1 /* 2 * packet.c -- low-level DNS packet encoding and decoding functions. 3 * 4 * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 */ 9 10 #include <config.h> 11 12 #include <string.h> 13 14 #include "packet.h" 15 #include "query.h" 16 #include "rdata.h" 17 18 static void 19 encode_dname(query_type *q, domain_type *domain) 20 { 21 while (domain->parent && query_get_dname_offset(q, domain) == 0) { 22 query_put_dname_offset(q, domain, buffer_position(q->packet)); 23 DEBUG(DEBUG_NAME_COMPRESSION, 2, 24 (LOG_INFO, "dname: %s, number: %lu, offset: %u\n", 25 dname_to_string(domain_dname(domain), NULL), 26 (unsigned long) domain->number, 27 query_get_dname_offset(q, domain))); 28 buffer_write(q->packet, dname_name(domain_dname(domain)), 29 label_length(dname_name(domain_dname(domain))) + 1U); 30 domain = domain->parent; 31 } 32 if (domain->parent) { 33 DEBUG(DEBUG_NAME_COMPRESSION, 2, 34 (LOG_INFO, "dname: %s, number: %lu, pointer: %u\n", 35 dname_to_string(domain_dname(domain), NULL), 36 (unsigned long) domain->number, 37 query_get_dname_offset(q, domain))); 38 assert(query_get_dname_offset(q, domain) <= MAX_COMPRESSION_OFFSET); 39 buffer_write_u16(q->packet, 40 0xc000 | query_get_dname_offset(q, domain)); 41 } else { 42 buffer_write_u8(q->packet, 0); 43 } 44 } 45 46 int 47 packet_encode_rr(query_type *q, domain_type *owner, rr_type *rr) 48 { 49 size_t truncation_mark; 50 uint16_t rdlength = 0; 51 size_t rdlength_pos; 52 uint16_t j; 53 54 assert(q); 55 assert(owner); 56 assert(rr); 57 58 /* 59 * If the record does not in fit in the packet the packet size 60 * will be restored to the mark. 61 */ 62 truncation_mark = buffer_position(q->packet); 63 64 encode_dname(q, owner); 65 buffer_write_u16(q->packet, rr->type); 66 buffer_write_u16(q->packet, rr->klass); 67 buffer_write_u32(q->packet, rr->ttl); 68 69 /* Reserve space for rdlength. */ 70 rdlength_pos = buffer_position(q->packet); 71 buffer_skip(q->packet, sizeof(rdlength)); 72 73 for (j = 0; j < rr->rdata_count; ++j) { 74 switch (rdata_atom_wireformat_type(rr->type, j)) { 75 case RDATA_WF_COMPRESSED_DNAME: 76 encode_dname(q, rdata_atom_domain(rr->rdatas[j])); 77 break; 78 case RDATA_WF_UNCOMPRESSED_DNAME: 79 { 80 const dname_type *dname = domain_dname( 81 rdata_atom_domain(rr->rdatas[j])); 82 buffer_write(q->packet, 83 dname_name(dname), dname->name_size); 84 break; 85 } 86 default: 87 buffer_write(q->packet, 88 rdata_atom_data(rr->rdatas[j]), 89 rdata_atom_size(rr->rdatas[j])); 90 break; 91 } 92 } 93 94 if (!query_overflow(q)) { 95 rdlength = (buffer_position(q->packet) - rdlength_pos 96 - sizeof(rdlength)); 97 buffer_write_u16_at(q->packet, rdlength_pos, rdlength); 98 return 1; 99 } else { 100 buffer_set_position(q->packet, truncation_mark); 101 query_clear_dname_offsets(q, truncation_mark); 102 assert(!query_overflow(q)); 103 return 0; 104 } 105 } 106 107 int 108 packet_encode_rrset(query_type *query, 109 domain_type *owner, 110 rrset_type *rrset, 111 int section, 112 #ifdef MINIMAL_RESPONSES 113 size_t minimal_respsize, 114 int* done) 115 #else 116 size_t ATTR_UNUSED(minimal_respsize), 117 int* ATTR_UNUSED(done)) 118 #endif 119 { 120 uint16_t i; 121 size_t truncation_mark; 122 uint16_t added = 0; 123 int all_added = 1; 124 #ifdef MINIMAL_RESPONSES 125 int minimize_response = (section >= OPTIONAL_AUTHORITY_SECTION); 126 int truncate_rrset = (section == ANSWER_SECTION || 127 section == AUTHORITY_SECTION); 128 #else 129 int truncate_rrset = (section == ANSWER_SECTION || 130 section == AUTHORITY_SECTION || 131 section == OPTIONAL_AUTHORITY_SECTION); 132 #endif 133 rrset_type *rrsig; 134 135 assert(rrset->rr_count > 0); 136 137 truncation_mark = buffer_position(query->packet); 138 139 for (i = 0; i < rrset->rr_count; ++i) { 140 if (packet_encode_rr(query, owner, &rrset->rrs[i])) { 141 ++added; 142 } else { 143 all_added = 0; 144 break; 145 } 146 } 147 148 if (all_added && 149 query->edns.dnssec_ok && 150 zone_is_secure(rrset->zone) && 151 rrset_rrtype(rrset) != TYPE_RRSIG && 152 (rrsig = domain_find_rrset(owner, rrset->zone, TYPE_RRSIG))) 153 { 154 for (i = 0; i < rrsig->rr_count; ++i) { 155 if (rr_rrsig_type_covered(&rrsig->rrs[i]) 156 == rrset_rrtype(rrset)) 157 { 158 if (packet_encode_rr(query, owner, 159 &rrsig->rrs[i])) 160 { 161 ++added; 162 } else { 163 all_added = 0; 164 break; 165 } 166 } 167 } 168 } 169 170 #ifdef MINIMAL_RESPONSES 171 if ((!all_added || buffer_position(query->packet) > minimal_respsize) 172 && !query->tcp && minimize_response) { 173 /* Truncate entire RRset. */ 174 buffer_set_position(query->packet, truncation_mark); 175 query_clear_dname_offsets(query, truncation_mark); 176 added = 0; 177 *done = 1; 178 } 179 #endif 180 181 if (!all_added && truncate_rrset) { 182 /* Truncate entire RRset and set truncate flag. */ 183 buffer_set_position(query->packet, truncation_mark); 184 query_clear_dname_offsets(query, truncation_mark); 185 TC_SET(query->packet); 186 added = 0; 187 } 188 189 return added; 190 } 191 192 int 193 packet_skip_dname(buffer_type *packet) 194 { 195 while (1) { 196 uint8_t label_size; 197 if (!buffer_available(packet, 1)) 198 return 0; 199 200 label_size = buffer_read_u8(packet); 201 if (label_size == 0) { 202 return 1; 203 } else if ((label_size & 0xc0) != 0) { 204 if (!buffer_available(packet, 1)) 205 return 0; 206 buffer_skip(packet, 1); 207 return 1; 208 } else if (!buffer_available(packet, label_size)) { 209 return 0; 210 } else { 211 buffer_skip(packet, label_size); 212 } 213 } 214 } 215 216 int 217 packet_skip_rr(buffer_type *packet, int question_section) 218 { 219 if (!packet_skip_dname(packet)) 220 return 0; 221 222 if (question_section) { 223 if (!buffer_available(packet, 4)) 224 return 0; 225 buffer_skip(packet, 4); 226 } else { 227 uint16_t rdata_size; 228 if (!buffer_available(packet, 10)) 229 return 0; 230 buffer_skip(packet, 8); 231 rdata_size = buffer_read_u16(packet); 232 if (!buffer_available(packet, rdata_size)) 233 return 0; 234 buffer_skip(packet, rdata_size); 235 } 236 237 return 1; 238 } 239 240 rr_type * 241 packet_read_rr(region_type *region, domain_table_type *owners, 242 buffer_type *packet, int question_section) 243 { 244 const dname_type *owner; 245 uint16_t rdlength; 246 ssize_t rdata_count; 247 rdata_atom_type *rdatas; 248 rr_type *result = (rr_type *) region_alloc(region, sizeof(rr_type)); 249 250 owner = dname_make_from_packet(region, packet, 1, 1); 251 if (!owner || !buffer_available(packet, 2*sizeof(uint16_t))) { 252 return NULL; 253 } 254 255 result->owner = domain_table_insert(owners, owner); 256 result->type = buffer_read_u16(packet); 257 result->klass = buffer_read_u16(packet); 258 259 if (question_section) { 260 result->ttl = 0; 261 result->rdata_count = 0; 262 result->rdatas = NULL; 263 return result; 264 } else if (!buffer_available(packet, sizeof(uint32_t) + sizeof(uint16_t))) { 265 return NULL; 266 } 267 268 result->ttl = buffer_read_u32(packet); 269 rdlength = buffer_read_u16(packet); 270 271 if (!buffer_available(packet, rdlength)) { 272 return NULL; 273 } 274 275 rdata_count = rdata_wireformat_to_rdata_atoms( 276 region, owners, result->type, rdlength, packet, &rdatas); 277 if (rdata_count == -1) { 278 return NULL; 279 } 280 result->rdata_count = rdata_count; 281 result->rdatas = rdatas; 282 283 return result; 284 } 285 286 int packet_read_query_section(buffer_type *packet, 287 uint8_t* dst, uint16_t* qtype, uint16_t* qclass) 288 { 289 uint8_t *query_name = buffer_current(packet); 290 uint8_t *src = query_name; 291 size_t len; 292 293 while (*src) { 294 /* 295 * If we are out of buffer limits or we have a pointer 296 * in question dname or the domain name is longer than 297 * MAXDOMAINLEN ... 298 */ 299 if ((*src & 0xc0) || 300 (src + *src + 2 > buffer_end(packet)) || 301 (src + *src + 2 > query_name + MAXDOMAINLEN)) 302 { 303 return 0; 304 } 305 memcpy(dst, src, *src + 1); 306 dst += *src + 1; 307 src += *src + 1; 308 } 309 *dst++ = *src++; 310 311 /* Make sure name is not too long or we have stripped packet... */ 312 len = src - query_name; 313 if (len > MAXDOMAINLEN || 314 (src + 2*sizeof(uint16_t) > buffer_end(packet))) 315 { 316 return 0; 317 } 318 buffer_set_position(packet, src - buffer_begin(packet)); 319 320 *qtype = buffer_read_u16(packet); 321 *qclass = buffer_read_u16(packet); 322 return 1; 323 } 324