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