1 /* 2 * packet.c -- low-level DNS packet encoding and decoding functions. 3 * 4 * Copyright (c) 2001-2006, 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 int round_robin = 0; 19 20 static void 21 encode_dname(query_type *q, domain_type *domain) 22 { 23 while (domain->parent && query_get_dname_offset(q, domain) == 0) { 24 query_put_dname_offset(q, domain, buffer_position(q->packet)); 25 DEBUG(DEBUG_NAME_COMPRESSION, 2, 26 (LOG_INFO, "dname: %s, number: %lu, offset: %u\n", 27 domain_to_string(domain), 28 (unsigned long) domain->number, 29 query_get_dname_offset(q, domain))); 30 buffer_write(q->packet, dname_name(domain_dname(domain)), 31 label_length(dname_name(domain_dname(domain))) + 1U); 32 domain = domain->parent; 33 } 34 if (domain->parent) { 35 DEBUG(DEBUG_NAME_COMPRESSION, 2, 36 (LOG_INFO, "dname: %s, number: %lu, pointer: %u\n", 37 domain_to_string(domain), 38 (unsigned long) domain->number, 39 query_get_dname_offset(q, domain))); 40 assert(query_get_dname_offset(q, domain) <= MAX_COMPRESSION_OFFSET); 41 buffer_write_u16(q->packet, 42 0xc000 | query_get_dname_offset(q, domain)); 43 } else { 44 buffer_write_u8(q->packet, 0); 45 } 46 } 47 48 int 49 packet_encode_rr(query_type *q, domain_type *owner, rr_type *rr, uint32_t ttl) 50 { 51 size_t truncation_mark; 52 uint16_t rdlength = 0; 53 size_t rdlength_pos; 54 uint16_t j; 55 56 assert(q); 57 assert(owner); 58 assert(rr); 59 60 /* 61 * If the record does not in fit in the packet the packet size 62 * will be restored to the mark. 63 */ 64 truncation_mark = buffer_position(q->packet); 65 66 encode_dname(q, owner); 67 buffer_write_u16(q->packet, rr->type); 68 buffer_write_u16(q->packet, rr->klass); 69 buffer_write_u32(q->packet, ttl); 70 71 /* Reserve space for rdlength. */ 72 rdlength_pos = buffer_position(q->packet); 73 buffer_skip(q->packet, sizeof(rdlength)); 74 75 for (j = 0; j < rr->rdata_count; ++j) { 76 switch (rdata_atom_wireformat_type(rr->type, j)) { 77 case RDATA_WF_COMPRESSED_DNAME: 78 encode_dname(q, rdata_atom_domain(rr->rdatas[j])); 79 break; 80 case RDATA_WF_UNCOMPRESSED_DNAME: 81 { 82 const dname_type *dname = domain_dname( 83 rdata_atom_domain(rr->rdatas[j])); 84 buffer_write(q->packet, 85 dname_name(dname), dname->name_size); 86 break; 87 } 88 default: 89 buffer_write(q->packet, 90 rdata_atom_data(rr->rdatas[j]), 91 rdata_atom_size(rr->rdatas[j])); 92 break; 93 } 94 } 95 96 if (!query_overflow(q)) { 97 rdlength = (buffer_position(q->packet) - rdlength_pos 98 - sizeof(rdlength)); 99 buffer_write_u16_at(q->packet, rdlength_pos, rdlength); 100 return 1; 101 } else { 102 buffer_set_position(q->packet, truncation_mark); 103 query_clear_dname_offsets(q, truncation_mark); 104 assert(!query_overflow(q)); 105 return 0; 106 } 107 } 108 109 int 110 packet_encode_rrset(query_type *query, 111 domain_type *owner, 112 rrset_type *rrset, 113 int section, 114 #ifdef MINIMAL_RESPONSES 115 size_t minimal_respsize, 116 int* done) 117 #else 118 size_t ATTR_UNUSED(minimal_respsize), 119 int* ATTR_UNUSED(done)) 120 #endif 121 { 122 uint16_t i; 123 size_t truncation_mark; 124 uint16_t added = 0; 125 int all_added = 1; 126 #ifdef MINIMAL_RESPONSES 127 int minimize_response = (section >= OPTIONAL_AUTHORITY_SECTION); 128 int truncate_rrset = (section == ANSWER_SECTION || 129 section == AUTHORITY_SECTION); 130 #else 131 int truncate_rrset = (section == ANSWER_SECTION || 132 section == AUTHORITY_SECTION || 133 section == OPTIONAL_AUTHORITY_SECTION); 134 #endif 135 static int round_robin_off = 0; 136 int do_robin = (round_robin && section == ANSWER_SECTION && 137 query->qtype != TYPE_AXFR && query->qtype != TYPE_IXFR); 138 uint16_t start; 139 rrset_type *rrsig; 140 141 assert(rrset->rr_count > 0); 142 143 truncation_mark = buffer_position(query->packet); 144 145 if(do_robin && rrset->rr_count) 146 start = (uint16_t)(round_robin_off++ % rrset->rr_count); 147 else start = 0; 148 for (i = start; i < rrset->rr_count; ++i) { 149 if (packet_encode_rr(query, owner, &rrset->rrs[i], 150 rrset->rrs[i].ttl)) { 151 ++added; 152 } else { 153 all_added = 0; 154 start = 0; 155 break; 156 } 157 } 158 for (i = 0; i < start; ++i) { 159 if (packet_encode_rr(query, owner, &rrset->rrs[i], 160 rrset->rrs[i].ttl)) { 161 ++added; 162 } else { 163 all_added = 0; 164 break; 165 } 166 } 167 168 if (all_added && 169 query->edns.dnssec_ok && 170 zone_is_secure(rrset->zone) && 171 rrset_rrtype(rrset) != TYPE_RRSIG && 172 (rrsig = domain_find_rrset(owner, rrset->zone, TYPE_RRSIG))) 173 { 174 for (i = 0; i < rrsig->rr_count; ++i) { 175 if (rr_rrsig_type_covered(&rrsig->rrs[i]) 176 == rrset_rrtype(rrset)) 177 { 178 if (packet_encode_rr(query, owner, 179 &rrsig->rrs[i], 180 rrset_rrtype(rrset)==TYPE_SOA?rrset->rrs[0].ttl:rrsig->rrs[i].ttl)) 181 { 182 ++added; 183 } else { 184 all_added = 0; 185 break; 186 } 187 } 188 } 189 } 190 191 #ifdef MINIMAL_RESPONSES 192 if ((!all_added || buffer_position(query->packet) > minimal_respsize) 193 && !query->tcp && minimize_response) { 194 /* Truncate entire RRset. */ 195 buffer_set_position(query->packet, truncation_mark); 196 query_clear_dname_offsets(query, truncation_mark); 197 added = 0; 198 *done = 1; 199 } 200 #endif 201 202 if (!all_added && truncate_rrset) { 203 /* Truncate entire RRset and set truncate flag. */ 204 buffer_set_position(query->packet, truncation_mark); 205 query_clear_dname_offsets(query, truncation_mark); 206 TC_SET(query->packet); 207 added = 0; 208 } 209 210 return added; 211 } 212 213 int 214 packet_skip_dname(buffer_type *packet) 215 { 216 while (1) { 217 uint8_t label_size; 218 if (!buffer_available(packet, 1)) 219 return 0; 220 221 label_size = buffer_read_u8(packet); 222 if (label_size == 0) { 223 return 1; 224 } else if ((label_size & 0xc0) != 0) { 225 if (!buffer_available(packet, 1)) 226 return 0; 227 buffer_skip(packet, 1); 228 return 1; 229 } else if (!buffer_available(packet, label_size)) { 230 return 0; 231 } else { 232 buffer_skip(packet, label_size); 233 } 234 } 235 } 236 237 int 238 packet_skip_rr(buffer_type *packet, int question_section) 239 { 240 if (!packet_skip_dname(packet)) 241 return 0; 242 243 if (question_section) { 244 if (!buffer_available(packet, 4)) 245 return 0; 246 buffer_skip(packet, 4); 247 } else { 248 uint16_t rdata_size; 249 if (!buffer_available(packet, 10)) 250 return 0; 251 buffer_skip(packet, 8); 252 rdata_size = buffer_read_u16(packet); 253 if (!buffer_available(packet, rdata_size)) 254 return 0; 255 buffer_skip(packet, rdata_size); 256 } 257 258 return 1; 259 } 260 261 rr_type * 262 packet_read_rr(region_type *region, domain_table_type *owners, 263 buffer_type *packet, int question_section) 264 { 265 const dname_type *owner; 266 uint16_t rdlength; 267 ssize_t rdata_count; 268 rdata_atom_type *rdatas; 269 rr_type *result = (rr_type *) region_alloc(region, sizeof(rr_type)); 270 271 owner = dname_make_from_packet(region, packet, 1, 1); 272 if (!owner || !buffer_available(packet, 2*sizeof(uint16_t))) { 273 return NULL; 274 } 275 276 result->owner = domain_table_insert(owners, owner); 277 result->type = buffer_read_u16(packet); 278 result->klass = buffer_read_u16(packet); 279 280 if (question_section) { 281 result->ttl = 0; 282 result->rdata_count = 0; 283 result->rdatas = NULL; 284 return result; 285 } else if (!buffer_available(packet, sizeof(uint32_t) + sizeof(uint16_t))) { 286 return NULL; 287 } 288 289 result->ttl = buffer_read_u32(packet); 290 rdlength = buffer_read_u16(packet); 291 292 if (!buffer_available(packet, rdlength)) { 293 return NULL; 294 } 295 296 rdata_count = rdata_wireformat_to_rdata_atoms( 297 region, owners, result->type, rdlength, packet, &rdatas); 298 if (rdata_count == -1) { 299 return NULL; 300 } 301 result->rdata_count = rdata_count; 302 result->rdatas = rdatas; 303 304 return result; 305 } 306 307 int packet_read_query_section(buffer_type *packet, 308 uint8_t* dst, uint16_t* qtype, uint16_t* qclass) 309 { 310 uint8_t *query_name = buffer_current(packet); 311 uint8_t *src = query_name; 312 size_t len; 313 314 while (*src) { 315 /* 316 * If we are out of buffer limits or we have a pointer 317 * in question dname or the domain name is longer than 318 * MAXDOMAINLEN ... 319 */ 320 if ((*src & 0xc0) || 321 (src + *src + 2 > buffer_end(packet)) || 322 (src + *src + 2 > query_name + MAXDOMAINLEN)) 323 { 324 return 0; 325 } 326 memcpy(dst, src, *src + 1); 327 dst += *src + 1; 328 src += *src + 1; 329 } 330 *dst++ = *src++; 331 332 /* Make sure name is not too long or we have stripped packet... */ 333 len = src - query_name; 334 if (len > MAXDOMAINLEN || 335 (src + 2*sizeof(uint16_t) > buffer_end(packet))) 336 { 337 return 0; 338 } 339 buffer_set_position(packet, src - buffer_begin(packet)); 340 341 *qtype = buffer_read_u16(packet); 342 *qclass = buffer_read_u16(packet); 343 return 1; 344 } 345 346 int packet_find_notify_serial(buffer_type *packet, uint32_t* serial) 347 { 348 size_t saved_position = buffer_position(packet); 349 /* count of further RRs after question section */ 350 size_t rrcount = ANCOUNT(packet) + NSCOUNT(packet) + ARCOUNT(packet); 351 size_t i; 352 buffer_set_position(packet, QHEADERSZ); 353 354 /* skip all question RRs */ 355 for (i = 0; i < QDCOUNT(packet); ++i) { 356 if (!packet_skip_rr(packet, 1)) { 357 buffer_set_position(packet, saved_position); 358 return 0; 359 } 360 } 361 362 /* Find the SOA RR */ 363 for(i = 0; i < rrcount; i++) { 364 uint16_t rdata_size; 365 if (!packet_skip_dname(packet)) 366 break; 367 /* check length available for type,class,ttl,rdatalen */ 368 if (!buffer_available(packet, 10)) 369 break; 370 /* check type, class */ 371 if(buffer_read_u16(packet) == TYPE_SOA) { 372 if(buffer_read_u16(packet) != CLASS_IN) 373 break; 374 buffer_skip(packet, 4); /* skip ttl */ 375 rdata_size = buffer_read_u16(packet); 376 if (!buffer_available(packet, rdata_size)) 377 break; 378 /* skip two dnames, then serial */ 379 if (!packet_skip_dname(packet) || 380 !packet_skip_dname(packet)) 381 break; 382 if (!buffer_available(packet, 4)) 383 break; 384 *serial = buffer_read_u32(packet); 385 buffer_set_position(packet, saved_position); 386 return 1; 387 } 388 /* continue to next RR */ 389 buffer_skip(packet, 6); 390 rdata_size = buffer_read_u16(packet); 391 if (!buffer_available(packet, rdata_size)) 392 break; 393 buffer_skip(packet, rdata_size); 394 } 395 /* failed to find SOA */ 396 buffer_set_position(packet, saved_position); 397 return 0; 398 } 399