Home | History | Annotate | Line # | Download | only in dist
      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