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