xref: /openbsd-src/usr.sbin/nsd/packet.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
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