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