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