1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /* $Id: message.c,v 1.22 2024/12/27 09:04:48 florian Exp $ */
18
19 /*! \file */
20
21 /***
22 *** Imports
23 ***/
24
25 #include <sys/socket.h>
26 #include <arpa/inet.h>
27
28 #include <ctype.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <isc/buffer.h>
33 #include <isc/util.h>
34
35 #include <dns/log.h>
36 #include <dns/masterdump.h>
37 #include <dns/message.h>
38 #include <dns/rdata.h>
39 #include <dns/rdatalist.h>
40 #include <dns/rdataset.h>
41 #include <dns/result.h>
42 #include <dns/tsig.h>
43 #include <dns/ttl.h>
44
45 #define DNS_MESSAGE_OPCODE_MASK 0x7800U
46 #define DNS_MESSAGE_OPCODE_SHIFT 11
47 #define DNS_MESSAGE_RCODE_MASK 0x000fU
48 #define DNS_MESSAGE_FLAG_MASK 0x8ff0U
49 #define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U
50
51 #define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \
52 && ((s) < DNS_SECTION_MAX))
53 #define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \
54 && ((s) < DNS_SECTION_MAX))
55 #define ADD_STRING(b, s) {if (strlen(s) >= \
56 isc_buffer_availablelength(b)) \
57 return(ISC_R_NOSPACE); else \
58 isc_buffer_putstr(b, s);}
59 #define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \
60 && ((s) < DNS_PSEUDOSECTION_MAX))
61
62 /*%
63 * This is the size of each individual scratchpad buffer, and the numbers
64 * of various block allocations used within the server.
65 * XXXMLG These should come from a config setting.
66 */
67 #define SCRATCHPAD_SIZE 512
68 #define OFFSET_COUNT 4
69 #define RDATA_COUNT 8
70 #define RDATALIST_COUNT 8
71
72 /*%
73 * Text representation of the different items, for message_totext
74 * functions.
75 */
76 static const char *sectiontext[] = {
77 "QUESTION",
78 "ANSWER",
79 "AUTHORITY",
80 "ADDITIONAL"
81 };
82
83 static const char *updsectiontext[] = {
84 "ZONE",
85 "PREREQUISITE",
86 "UPDATE",
87 "ADDITIONAL"
88 };
89
90 /*%
91 * "helper" type, which consists of a block of some type, and is linkable.
92 * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
93 * size, or the allocated elements will not be aligned correctly.
94 */
95 struct dns_msgblock {
96 unsigned int count;
97 unsigned int remaining;
98 ISC_LINK(dns_msgblock_t) link;
99 }; /* dynamically sized */
100
101 static inline dns_msgblock_t *
102 msgblock_allocate(unsigned int, unsigned int);
103
104 #define msgblock_get(block, type) \
105 ((type *)msgblock_internalget(block, sizeof(type)))
106
107 static inline void *
108 msgblock_internalget(dns_msgblock_t *, unsigned int);
109
110 static inline void
111 msgblock_reset(dns_msgblock_t *);
112
113 /*
114 * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory
115 * is free, return NULL.
116 */
117 static inline dns_msgblock_t *
msgblock_allocate(unsigned int sizeof_type,unsigned int count)118 msgblock_allocate(unsigned int sizeof_type,
119 unsigned int count)
120 {
121 dns_msgblock_t *block;
122 unsigned int length;
123
124 length = sizeof(dns_msgblock_t) + (sizeof_type * count);
125
126 block = malloc(length);
127 if (block == NULL)
128 return (NULL);
129
130 block->count = count;
131 block->remaining = count;
132
133 ISC_LINK_INIT(block, link);
134
135 return (block);
136 }
137
138 /*
139 * Return an element from the msgblock. If no more are available, return
140 * NULL.
141 */
142 static inline void *
msgblock_internalget(dns_msgblock_t * block,unsigned int sizeof_type)143 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
144 void *ptr;
145
146 if (block == NULL || block->remaining == 0)
147 return (NULL);
148
149 block->remaining--;
150
151 ptr = (((unsigned char *)block)
152 + sizeof(dns_msgblock_t)
153 + (sizeof_type * block->remaining));
154
155 return (ptr);
156 }
157
158 static inline void
msgblock_reset(dns_msgblock_t * block)159 msgblock_reset(dns_msgblock_t *block) {
160 block->remaining = block->count;
161 }
162
163 /*
164 * Allocate a new dynamic buffer, and attach it to this message as the
165 * "current" buffer. (which is always the last on the list, for our
166 * uses)
167 */
168 static inline isc_result_t
newbuffer(dns_message_t * msg,unsigned int size)169 newbuffer(dns_message_t *msg, unsigned int size) {
170 isc_result_t result;
171 isc_buffer_t *dynbuf;
172
173 dynbuf = NULL;
174 result = isc_buffer_allocate(&dynbuf, size);
175 if (result != ISC_R_SUCCESS)
176 return (ISC_R_NOMEMORY);
177
178 ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
179 return (ISC_R_SUCCESS);
180 }
181
182 static inline isc_buffer_t *
currentbuffer(dns_message_t * msg)183 currentbuffer(dns_message_t *msg) {
184 isc_buffer_t *dynbuf;
185
186 dynbuf = ISC_LIST_TAIL(msg->scratchpad);
187 INSIST(dynbuf != NULL);
188
189 return (dynbuf);
190 }
191
192 static inline void
releaserdata(dns_message_t * msg,dns_rdata_t * rdata)193 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
194 ISC_LIST_PREPEND(msg->freerdata, rdata, link);
195 }
196
197 static inline dns_rdata_t *
newrdata(dns_message_t * msg)198 newrdata(dns_message_t *msg) {
199 dns_msgblock_t *msgblock;
200 dns_rdata_t *rdata;
201
202 rdata = ISC_LIST_HEAD(msg->freerdata);
203 if (rdata != NULL) {
204 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
205 return (rdata);
206 }
207
208 msgblock = ISC_LIST_TAIL(msg->rdatas);
209 rdata = msgblock_get(msgblock, dns_rdata_t);
210 if (rdata == NULL) {
211 msgblock = msgblock_allocate(sizeof(dns_rdata_t), RDATA_COUNT);
212 if (msgblock == NULL)
213 return (NULL);
214
215 ISC_LIST_APPEND(msg->rdatas, msgblock, link);
216
217 rdata = msgblock_get(msgblock, dns_rdata_t);
218 }
219
220 dns_rdata_init(rdata);
221 return (rdata);
222 }
223
224 static inline void
releaserdatalist(dns_message_t * msg,dns_rdatalist_t * rdatalist)225 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
226 ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
227 }
228
229 static inline dns_rdatalist_t *
newrdatalist(dns_message_t * msg)230 newrdatalist(dns_message_t *msg) {
231 dns_msgblock_t *msgblock;
232 dns_rdatalist_t *rdatalist;
233
234 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
235 if (rdatalist != NULL) {
236 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
237 goto out;
238 }
239
240 msgblock = ISC_LIST_TAIL(msg->rdatalists);
241 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
242 if (rdatalist == NULL) {
243 msgblock = msgblock_allocate(sizeof(dns_rdatalist_t),
244 RDATALIST_COUNT);
245 if (msgblock == NULL)
246 return (NULL);
247
248 ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
249
250 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
251 }
252 out:
253 if (rdatalist != NULL)
254 dns_rdatalist_init(rdatalist);
255
256 return (rdatalist);
257 }
258
259 static inline dns_offsets_t *
newoffsets(dns_message_t * msg)260 newoffsets(dns_message_t *msg) {
261 dns_msgblock_t *msgblock;
262 dns_offsets_t *offsets;
263
264 msgblock = ISC_LIST_TAIL(msg->offsets);
265 offsets = msgblock_get(msgblock, dns_offsets_t);
266 if (offsets == NULL) {
267 msgblock = msgblock_allocate(sizeof(dns_offsets_t),
268 OFFSET_COUNT);
269 if (msgblock == NULL)
270 return (NULL);
271
272 ISC_LIST_APPEND(msg->offsets, msgblock, link);
273
274 offsets = msgblock_get(msgblock, dns_offsets_t);
275 }
276
277 return (offsets);
278 }
279
280 static inline void
msginitheader(dns_message_t * m)281 msginitheader(dns_message_t *m) {
282 m->id = 0;
283 m->flags = 0;
284 m->rcode = 0;
285 m->opcode = 0;
286 m->rdclass = 0;
287 }
288
289 static inline void
msginitprivate(dns_message_t * m)290 msginitprivate(dns_message_t *m) {
291 unsigned int i;
292
293 for (i = 0; i < DNS_SECTION_MAX; i++) {
294 m->cursors[i] = NULL;
295 m->counts[i] = 0;
296 }
297 m->opt = NULL;
298 m->sig0 = NULL;
299 m->sig0name = NULL;
300 m->tsig = NULL;
301 m->tsigname = NULL;
302 m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */
303 m->opt_reserved = 0;
304 m->sig_reserved = 0;
305 m->reserved = 0;
306 m->buffer = NULL;
307 }
308
309 static inline void
msginittsig(dns_message_t * m)310 msginittsig(dns_message_t *m) {
311 m->tsigstatus = dns_rcode_noerror;
312 m->querytsigstatus = dns_rcode_noerror;
313 m->tsigkey = NULL;
314 m->tsigctx = NULL;
315 m->sigstart = -1;
316 m->sig0status = dns_rcode_noerror;
317 m->timeadjust = 0;
318 }
319
320 /*
321 * Init elements to default state. Used both when allocating a new element
322 * and when resetting one.
323 */
324 static inline void
msginit(dns_message_t * m)325 msginit(dns_message_t *m) {
326 msginitheader(m);
327 msginitprivate(m);
328 msginittsig(m);
329 m->header_ok = 0;
330 m->question_ok = 0;
331 m->tcp_continuation = 0;
332 m->verified_sig = 0;
333 m->verify_attempted = 0;
334 m->query.base = NULL;
335 m->query.length = 0;
336 m->free_query = 0;
337 m->saved.base = NULL;
338 m->saved.length = 0;
339 m->free_saved = 0;
340 m->sitok = 0;
341 m->sitbad = 0;
342 m->tkey = 0;
343 m->rdclass_set = 0;
344 m->querytsig = NULL;
345 }
346
347 static inline void
msgresetnames(dns_message_t * msg,unsigned int first_section)348 msgresetnames(dns_message_t *msg, unsigned int first_section) {
349 unsigned int i;
350 dns_name_t *name, *next_name;
351 dns_rdataset_t *rds, *next_rds;
352
353 /*
354 * Clean up name lists by calling the rdataset disassociate function.
355 */
356 for (i = first_section; i < DNS_SECTION_MAX; i++) {
357 name = ISC_LIST_HEAD(msg->sections[i]);
358 while (name != NULL) {
359 next_name = ISC_LIST_NEXT(name, link);
360 ISC_LIST_UNLINK(msg->sections[i], name, link);
361
362 rds = ISC_LIST_HEAD(name->list);
363 while (rds != NULL) {
364 next_rds = ISC_LIST_NEXT(rds, link);
365 ISC_LIST_UNLINK(name->list, rds, link);
366
367 INSIST(dns_rdataset_isassociated(rds));
368 dns_rdataset_disassociate(rds);
369 free(rds);
370 rds = next_rds;
371 }
372 if (dns_name_dynamic(name))
373 dns_name_free(name);
374 free(name);
375 name = next_name;
376 }
377 }
378 }
379
380 static void
msgresetopt(dns_message_t * msg)381 msgresetopt(dns_message_t *msg)
382 {
383 if (msg->opt != NULL) {
384 if (msg->opt_reserved > 0) {
385 dns_message_renderrelease(msg, msg->opt_reserved);
386 msg->opt_reserved = 0;
387 }
388 INSIST(dns_rdataset_isassociated(msg->opt));
389 dns_rdataset_disassociate(msg->opt);
390 free(msg->opt);
391 msg->opt = NULL;
392 msg->sitok = 0;
393 msg->sitbad = 0;
394 }
395 }
396
397 static void
msgresetsigs(dns_message_t * msg,int replying)398 msgresetsigs(dns_message_t *msg, int replying) {
399 if (msg->sig_reserved > 0) {
400 dns_message_renderrelease(msg, msg->sig_reserved);
401 msg->sig_reserved = 0;
402 }
403 if (msg->tsig != NULL) {
404 INSIST(dns_rdataset_isassociated(msg->tsig));
405 if (replying) {
406 INSIST(msg->querytsig == NULL);
407 msg->querytsig = msg->tsig;
408 } else {
409 dns_rdataset_disassociate(msg->tsig);
410 free(msg->tsig);
411 if (msg->querytsig != NULL) {
412 dns_rdataset_disassociate(msg->querytsig);
413 free(msg->querytsig);
414 }
415 }
416 if (dns_name_dynamic(msg->tsigname))
417 dns_name_free(msg->tsigname);
418 free(msg->tsigname);
419 msg->tsig = NULL;
420 msg->tsigname = NULL;
421 } else if (msg->querytsig != NULL && !replying) {
422 dns_rdataset_disassociate(msg->querytsig);
423 free(msg->querytsig);
424 msg->querytsig = NULL;
425 }
426 if (msg->sig0 != NULL) {
427 INSIST(dns_rdataset_isassociated(msg->sig0));
428 dns_rdataset_disassociate(msg->sig0);
429 free(msg->sig0);
430 if (msg->sig0name != NULL) {
431 if (dns_name_dynamic(msg->sig0name))
432 dns_name_free(msg->sig0name);
433 free(msg->sig0name);
434 }
435 msg->sig0 = NULL;
436 msg->sig0name = NULL;
437 }
438 }
439
440 /*
441 * Free all but one (or everything) for this message. This is used by
442 * both dns_message_reset() and dns_message_destroy().
443 */
444 static void
msgreset(dns_message_t * msg,int everything)445 msgreset(dns_message_t *msg, int everything) {
446 dns_msgblock_t *msgblock, *next_msgblock;
447 isc_buffer_t *dynbuf, *next_dynbuf;
448 dns_rdata_t *rdata;
449 dns_rdatalist_t *rdatalist;
450
451 msgresetnames(msg, 0);
452 msgresetopt(msg);
453 msgresetsigs(msg, 0);
454
455 /*
456 * Clean up linked lists.
457 */
458
459 /*
460 * Run through the free lists, and just unlink anything found there.
461 * The memory isn't lost since these are part of message blocks we
462 * have allocated.
463 */
464 rdata = ISC_LIST_HEAD(msg->freerdata);
465 while (rdata != NULL) {
466 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
467 rdata = ISC_LIST_HEAD(msg->freerdata);
468 }
469 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
470 while (rdatalist != NULL) {
471 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
472 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
473 }
474
475 dynbuf = ISC_LIST_HEAD(msg->scratchpad);
476 INSIST(dynbuf != NULL);
477 if (!everything) {
478 isc_buffer_clear(dynbuf);
479 dynbuf = ISC_LIST_NEXT(dynbuf, link);
480 }
481 while (dynbuf != NULL) {
482 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
483 ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
484 isc_buffer_free(&dynbuf);
485 dynbuf = next_dynbuf;
486 }
487
488 msgblock = ISC_LIST_HEAD(msg->rdatas);
489 if (!everything && msgblock != NULL) {
490 msgblock_reset(msgblock);
491 msgblock = ISC_LIST_NEXT(msgblock, link);
492 }
493 while (msgblock != NULL) {
494 next_msgblock = ISC_LIST_NEXT(msgblock, link);
495 ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
496 free(msgblock);
497 msgblock = next_msgblock;
498 }
499
500 /*
501 * rdatalists could be empty.
502 */
503
504 msgblock = ISC_LIST_HEAD(msg->rdatalists);
505 if (!everything && msgblock != NULL) {
506 msgblock_reset(msgblock);
507 msgblock = ISC_LIST_NEXT(msgblock, link);
508 }
509 while (msgblock != NULL) {
510 next_msgblock = ISC_LIST_NEXT(msgblock, link);
511 ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
512 free(msgblock);
513 msgblock = next_msgblock;
514 }
515
516 msgblock = ISC_LIST_HEAD(msg->offsets);
517 if (!everything && msgblock != NULL) {
518 msgblock_reset(msgblock);
519 msgblock = ISC_LIST_NEXT(msgblock, link);
520 }
521 while (msgblock != NULL) {
522 next_msgblock = ISC_LIST_NEXT(msgblock, link);
523 ISC_LIST_UNLINK(msg->offsets, msgblock, link);
524 free(msgblock);
525 msgblock = next_msgblock;
526 }
527
528 if (msg->tsigkey != NULL) {
529 dns_tsigkey_detach(&msg->tsigkey);
530 msg->tsigkey = NULL;
531 }
532
533 if (msg->tsigctx != NULL)
534 dst_context_destroy(&msg->tsigctx);
535
536 if (msg->query.base != NULL) {
537 if (msg->free_query != 0)
538 free(msg->query.base);
539 msg->query.base = NULL;
540 msg->query.length = 0;
541 }
542
543 if (msg->saved.base != NULL) {
544 if (msg->free_saved != 0)
545 free(msg->saved.base);
546 msg->saved.base = NULL;
547 msg->saved.length = 0;
548 }
549
550 /*
551 * cleanup the buffer cleanup list
552 */
553 dynbuf = ISC_LIST_HEAD(msg->cleanup);
554 while (dynbuf != NULL) {
555 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
556 ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
557 isc_buffer_free(&dynbuf);
558 dynbuf = next_dynbuf;
559 }
560
561 /*
562 * Set other bits to normal default values.
563 */
564 if (!everything)
565 msginit(msg);
566 }
567
568 static unsigned int
spacefortsig(dns_tsigkey_t * key,int otherlen)569 spacefortsig(dns_tsigkey_t *key, int otherlen) {
570 isc_region_t r1, r2;
571 unsigned int x;
572 isc_result_t result;
573
574 /*
575 * The space required for an TSIG record is:
576 *
577 * n1 bytes for the name
578 * 2 bytes for the type
579 * 2 bytes for the class
580 * 4 bytes for the ttl
581 * 2 bytes for the rdlength
582 * n2 bytes for the algorithm name
583 * 6 bytes for the time signed
584 * 2 bytes for the fudge
585 * 2 bytes for the MAC size
586 * x bytes for the MAC
587 * 2 bytes for the original id
588 * 2 bytes for the error
589 * 2 bytes for the other data length
590 * y bytes for the other data (at most)
591 * ---------------------------------
592 * 26 + n1 + n2 + x + y bytes
593 */
594
595 dns_name_toregion(&key->name, &r1);
596 dns_name_toregion(key->algorithm, &r2);
597 if (key->key == NULL)
598 x = 0;
599 else {
600 result = dst_key_sigsize(key->key, &x);
601 if (result != ISC_R_SUCCESS)
602 x = 0;
603 }
604 return (26 + r1.length + r2.length + x + otherlen);
605 }
606
607 isc_result_t
dns_message_create(unsigned int intent,dns_message_t ** msgp)608 dns_message_create(unsigned int intent, dns_message_t **msgp)
609 {
610 dns_message_t *m;
611 isc_result_t result;
612 isc_buffer_t *dynbuf;
613 unsigned int i;
614
615 REQUIRE(msgp != NULL);
616 REQUIRE(*msgp == NULL);
617 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
618 || intent == DNS_MESSAGE_INTENTRENDER);
619
620 m = malloc(sizeof(dns_message_t));
621 if (m == NULL)
622 return (ISC_R_NOMEMORY);
623
624 /*
625 * No allocations until further notice. Just initialize all lists
626 * and other members that are freed in the cleanup phase here.
627 */
628
629 m->from_to_wire = intent;
630 msginit(m);
631
632 for (i = 0; i < DNS_SECTION_MAX; i++)
633 ISC_LIST_INIT(m->sections[i]);
634
635 ISC_LIST_INIT(m->scratchpad);
636 ISC_LIST_INIT(m->cleanup);
637 ISC_LIST_INIT(m->rdatas);
638 ISC_LIST_INIT(m->rdatalists);
639 ISC_LIST_INIT(m->offsets);
640 ISC_LIST_INIT(m->freerdata);
641 ISC_LIST_INIT(m->freerdatalist);
642
643 /*
644 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
645 */
646
647 dynbuf = NULL;
648 result = isc_buffer_allocate(&dynbuf, SCRATCHPAD_SIZE);
649 if (result != ISC_R_SUCCESS)
650 goto cleanup;
651 ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
652
653 m->cctx = NULL;
654
655 *msgp = m;
656 return (ISC_R_SUCCESS);
657
658 /*
659 * Cleanup for error returns.
660 */
661 cleanup:
662 dynbuf = ISC_LIST_HEAD(m->scratchpad);
663 if (dynbuf != NULL) {
664 ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
665 isc_buffer_free(&dynbuf);
666 }
667 free(m);
668
669 return (ISC_R_NOMEMORY);
670 }
671
672 void
dns_message_destroy(dns_message_t ** msgp)673 dns_message_destroy(dns_message_t **msgp) {
674 dns_message_t *msg;
675
676 REQUIRE(msgp != NULL);
677
678 msg = *msgp;
679 *msgp = NULL;
680
681 msgreset(msg, 1);
682 free(msg);
683 }
684
685 static isc_result_t
findname(dns_name_t ** foundname,dns_name_t * target,dns_namelist_t * section)686 findname(dns_name_t **foundname, dns_name_t *target,
687 dns_namelist_t *section)
688 {
689 dns_name_t *curr;
690
691 for (curr = ISC_LIST_TAIL(*section);
692 curr != NULL;
693 curr = ISC_LIST_PREV(curr, link)) {
694 if (dns_name_equal(curr, target)) {
695 if (foundname != NULL)
696 *foundname = curr;
697 return (ISC_R_SUCCESS);
698 }
699 }
700
701 return (ISC_R_NOTFOUND);
702 }
703
704 isc_result_t
dns_message_find(dns_name_t * name,dns_rdataclass_t rdclass,dns_rdatatype_t type,dns_rdatatype_t covers,dns_rdataset_t ** rdataset)705 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
706 dns_rdatatype_t type, dns_rdatatype_t covers,
707 dns_rdataset_t **rdataset)
708 {
709 dns_rdataset_t *curr;
710
711 REQUIRE(name != NULL);
712 REQUIRE(rdataset == NULL || *rdataset == NULL);
713
714 for (curr = ISC_LIST_TAIL(name->list);
715 curr != NULL;
716 curr = ISC_LIST_PREV(curr, link)) {
717 if (curr->rdclass == rdclass &&
718 curr->type == type && curr->covers == covers) {
719 if (rdataset != NULL)
720 *rdataset = curr;
721 return (ISC_R_SUCCESS);
722 }
723 }
724
725 return (ISC_R_NOTFOUND);
726 }
727
728 isc_result_t
dns_message_findtype(dns_name_t * name,dns_rdatatype_t type,dns_rdatatype_t covers,dns_rdataset_t ** rdataset)729 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
730 dns_rdatatype_t covers, dns_rdataset_t **rdataset)
731 {
732 dns_rdataset_t *curr;
733
734 REQUIRE(name != NULL);
735 REQUIRE(rdataset == NULL || *rdataset == NULL);
736
737 for (curr = ISC_LIST_TAIL(name->list);
738 curr != NULL;
739 curr = ISC_LIST_PREV(curr, link)) {
740 if (curr->type == type && curr->covers == covers) {
741 if (rdataset != NULL)
742 *rdataset = curr;
743 return (ISC_R_SUCCESS);
744 }
745 }
746
747 return (ISC_R_NOTFOUND);
748 }
749
750 /*
751 * Read a name from buffer "source".
752 */
753 static isc_result_t
getname(dns_name_t * name,isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx)754 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
755 dns_decompress_t *dctx)
756 {
757 isc_buffer_t *scratch;
758 isc_result_t result;
759 unsigned int tries;
760
761 scratch = currentbuffer(msg);
762
763 /*
764 * First try: use current buffer.
765 * Second try: allocate a new buffer and use that.
766 */
767 tries = 0;
768 while (tries < 2) {
769 result = dns_name_fromwire(name, source, dctx, 0,
770 scratch);
771
772 if (result == ISC_R_NOSPACE) {
773 tries++;
774
775 result = newbuffer(msg, SCRATCHPAD_SIZE);
776 if (result != ISC_R_SUCCESS)
777 return (result);
778
779 scratch = currentbuffer(msg);
780 dns_name_reset(name);
781 } else {
782 return (result);
783 }
784 }
785
786 INSIST(0); /* Cannot get here... */
787 return (ISC_R_UNEXPECTED);
788 }
789
790 static isc_result_t
getrdata(isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx,dns_rdataclass_t rdclass,dns_rdatatype_t rdtype,unsigned int rdatalen,dns_rdata_t * rdata)791 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
792 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
793 unsigned int rdatalen, dns_rdata_t *rdata)
794 {
795 isc_buffer_t *scratch;
796 isc_result_t result;
797 unsigned int tries;
798 unsigned int trysize;
799
800 scratch = currentbuffer(msg);
801
802 isc_buffer_setactive(source, rdatalen);
803
804 /*
805 * First try: use current buffer.
806 * Second try: allocate a new buffer of size
807 * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
808 * (the data will fit if it was not more than 50% compressed)
809 * Subsequent tries: double buffer size on each try.
810 */
811 tries = 0;
812 trysize = 0;
813 /* XXX possibly change this to a while (tries < 2) loop */
814 for (;;) {
815 result = dns_rdata_fromwire(rdata, rdclass, rdtype,
816 source, dctx, 0,
817 scratch);
818
819 if (result == ISC_R_NOSPACE) {
820 if (tries == 0) {
821 trysize = 2 * rdatalen;
822 if (trysize < SCRATCHPAD_SIZE)
823 trysize = SCRATCHPAD_SIZE;
824 } else {
825 INSIST(trysize != 0);
826 if (trysize >= 65535)
827 return (ISC_R_NOSPACE);
828 /* XXX DNS_R_RRTOOLONG? */
829 trysize *= 2;
830 }
831 tries++;
832 result = newbuffer(msg, trysize);
833 if (result != ISC_R_SUCCESS)
834 return (result);
835
836 scratch = currentbuffer(msg);
837 } else {
838 return (result);
839 }
840 }
841 }
842
843 #define DO_FORMERR \
844 do { \
845 if (best_effort) \
846 seen_problem = 1; \
847 else { \
848 result = DNS_R_FORMERR; \
849 goto cleanup; \
850 } \
851 } while (0)
852
853 static isc_result_t
getquestions(isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx,unsigned int options)854 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
855 unsigned int options)
856 {
857 isc_region_t r;
858 unsigned int count;
859 dns_name_t *name;
860 dns_name_t *name2;
861 dns_offsets_t *offsets;
862 dns_rdataset_t *rdataset;
863 dns_rdatalist_t *rdatalist;
864 isc_result_t result;
865 dns_rdatatype_t rdtype;
866 dns_rdataclass_t rdclass;
867 dns_namelist_t *section;
868 int free_name;
869 int best_effort;
870 int seen_problem;
871
872 section = &msg->sections[DNS_SECTION_QUESTION];
873
874 best_effort = options & DNS_MESSAGEPARSE_BESTEFFORT;
875 seen_problem = 0;
876
877 name = NULL;
878 rdataset = NULL;
879 rdatalist = NULL;
880
881 for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
882 name = malloc(sizeof(dns_name_t));
883 if (name == NULL)
884 return (ISC_R_NOMEMORY);
885 free_name = 1;
886
887 offsets = newoffsets(msg);
888 if (offsets == NULL) {
889 result = ISC_R_NOMEMORY;
890 goto cleanup;
891 }
892 dns_name_init(name, *offsets);
893
894 /*
895 * Parse the name out of this packet.
896 */
897 isc_buffer_remainingregion(source, &r);
898 isc_buffer_setactive(source, r.length);
899 result = getname(name, source, msg, dctx);
900 if (result != ISC_R_SUCCESS)
901 goto cleanup;
902
903 /*
904 * Run through the section, looking to see if this name
905 * is already there. If it is found, put back the allocated
906 * name since we no longer need it, and set our name pointer
907 * to point to the name we found.
908 */
909 result = findname(&name2, name, section);
910
911 /*
912 * If it is the first name in the section, accept it.
913 *
914 * If it is not, but is not the same as the name already
915 * in the question section, append to the section. Note that
916 * here in the question section this is illegal, so return
917 * FORMERR. In the future, check the opcode to see if
918 * this should be legal or not. In either case we no longer
919 * need this name pointer.
920 */
921 if (result != ISC_R_SUCCESS) {
922 if (!ISC_LIST_EMPTY(*section))
923 DO_FORMERR;
924 ISC_LIST_APPEND(*section, name, link);
925 free_name = 0;
926 } else {
927 free(name);
928 name = name2;
929 name2 = NULL;
930 free_name = 0;
931 }
932
933 /*
934 * Get type and class.
935 */
936 isc_buffer_remainingregion(source, &r);
937 if (r.length < 4) {
938 result = ISC_R_UNEXPECTEDEND;
939 goto cleanup;
940 }
941 rdtype = isc_buffer_getuint16(source);
942 rdclass = isc_buffer_getuint16(source);
943
944 /*
945 * If this class is different than the one we already read,
946 * this is an error.
947 */
948 if (msg->rdclass_set == 0) {
949 msg->rdclass = rdclass;
950 msg->rdclass_set = 1;
951 } else if (msg->rdclass != rdclass)
952 DO_FORMERR;
953
954 /*
955 * Is this a TKEY query?
956 */
957 if (rdtype == dns_rdatatype_tkey)
958 msg->tkey = 1;
959
960 /*
961 * Can't ask the same question twice.
962 */
963 result = dns_message_find(name, rdclass, rdtype, 0, NULL);
964 if (result == ISC_R_SUCCESS)
965 DO_FORMERR;
966
967 /*
968 * Allocate a new rdatalist.
969 */
970 rdatalist = newrdatalist(msg);
971 if (rdatalist == NULL) {
972 result = ISC_R_NOMEMORY;
973 goto cleanup;
974 }
975 rdataset = malloc(sizeof(dns_rdataset_t));
976 if (rdataset == NULL) {
977 result = ISC_R_NOMEMORY;
978 goto cleanup;
979 }
980
981 /*
982 * Convert rdatalist to rdataset, and attach the latter to
983 * the name.
984 */
985 rdatalist->type = rdtype;
986 rdatalist->covers = 0;
987 rdatalist->rdclass = rdclass;
988 rdatalist->ttl = 0;
989 ISC_LIST_INIT(rdatalist->rdata);
990
991 dns_rdataset_init(rdataset);
992 result = dns_rdatalist_tordataset(rdatalist, rdataset);
993 if (result != ISC_R_SUCCESS)
994 goto cleanup;
995
996 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
997
998 ISC_LIST_APPEND(name->list, rdataset, link);
999 rdataset = NULL;
1000 }
1001
1002 if (seen_problem)
1003 return (DNS_R_RECOVERABLE);
1004 return (ISC_R_SUCCESS);
1005
1006 cleanup:
1007 if (rdataset != NULL) {
1008 INSIST(!dns_rdataset_isassociated(rdataset));
1009 free(rdataset);
1010 }
1011 if (free_name)
1012 free(name);
1013
1014 return (result);
1015 }
1016
1017 static int
update(dns_section_t section,dns_rdataclass_t rdclass)1018 update(dns_section_t section, dns_rdataclass_t rdclass) {
1019 if (section == DNS_SECTION_PREREQUISITE)
1020 return (rdclass == dns_rdataclass_any ||
1021 rdclass == dns_rdataclass_none);
1022 if (section == DNS_SECTION_UPDATE)
1023 return (rdclass == dns_rdataclass_any);
1024 return (0);
1025 }
1026
1027 static isc_result_t
getsection(isc_buffer_t * source,dns_message_t * msg,dns_decompress_t * dctx,dns_section_t sectionid,unsigned int options)1028 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1029 dns_section_t sectionid, unsigned int options)
1030 {
1031 isc_region_t r;
1032 unsigned int count, rdatalen;
1033 dns_name_t *name = NULL;
1034 dns_offsets_t *offsets;
1035 dns_rdataset_t *rdataset;
1036 dns_rdatalist_t *rdatalist;
1037 isc_result_t result;
1038 dns_rdatatype_t rdtype, covers;
1039 dns_rdataclass_t rdclass;
1040 dns_rdata_t *rdata;
1041 dns_ttl_t ttl;
1042 dns_namelist_t *section;
1043 int free_name = 0, free_rdataset = 0;
1044 int best_effort, seen_problem;
1045 int issigzero;
1046
1047 best_effort = options & DNS_MESSAGEPARSE_BESTEFFORT;
1048 seen_problem = 0;
1049
1050 section = &msg->sections[sectionid];
1051
1052 for (count = 0; count < msg->counts[sectionid]; count++) {
1053 int recstart = source->current;
1054 free_rdataset = 0;
1055
1056 name = malloc(sizeof(dns_name_t));
1057 if (name == NULL)
1058 return (ISC_R_NOMEMORY);
1059 free_name = 1;
1060
1061 offsets = newoffsets(msg);
1062 if (offsets == NULL) {
1063 result = ISC_R_NOMEMORY;
1064 goto cleanup;
1065 }
1066 dns_name_init(name, *offsets);
1067
1068 /*
1069 * Parse the name out of this packet.
1070 */
1071 isc_buffer_remainingregion(source, &r);
1072 isc_buffer_setactive(source, r.length);
1073 result = getname(name, source, msg, dctx);
1074 if (result != ISC_R_SUCCESS)
1075 goto cleanup;
1076
1077 /*
1078 * Get type, class, ttl, and rdatalen. Verify that at least
1079 * rdatalen bytes remain. (Some of this is deferred to
1080 * later.)
1081 */
1082 isc_buffer_remainingregion(source, &r);
1083 if (r.length < 2 + 2 + 4 + 2) {
1084 result = ISC_R_UNEXPECTEDEND;
1085 goto cleanup;
1086 }
1087 rdtype = isc_buffer_getuint16(source);
1088 rdclass = isc_buffer_getuint16(source);
1089
1090 /*
1091 * If there was no question section, we may not yet have
1092 * established a class. Do so now.
1093 */
1094 if (msg->rdclass_set == 0 &&
1095 rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
1096 rdtype != dns_rdatatype_tsig && /* class is ANY */
1097 rdtype != dns_rdatatype_tkey) { /* class is undefined */
1098 msg->rdclass = rdclass;
1099 msg->rdclass_set = 1;
1100 }
1101
1102 /*
1103 * If this class is different than the one in the question
1104 * section, bail.
1105 */
1106 if (msg->opcode != dns_opcode_update
1107 && rdtype != dns_rdatatype_tsig
1108 && rdtype != dns_rdatatype_opt
1109 && rdtype != dns_rdatatype_key /* in a TKEY query */
1110 && rdtype != dns_rdatatype_sig /* SIG(0) */
1111 && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1112 && msg->rdclass != dns_rdataclass_any
1113 && msg->rdclass != rdclass)
1114 DO_FORMERR;
1115
1116 /*
1117 * If this is not a TKEY query/response then the KEY
1118 * record's class needs to match.
1119 */
1120 if (msg->opcode != dns_opcode_update && !msg->tkey &&
1121 rdtype == dns_rdatatype_key &&
1122 msg->rdclass != dns_rdataclass_any &&
1123 msg->rdclass != rdclass)
1124 DO_FORMERR;
1125
1126 /*
1127 * Special type handling for TSIG, OPT, and TKEY.
1128 */
1129 if (rdtype == dns_rdatatype_tsig) {
1130 /*
1131 * If it is a tsig, verify that it is in the
1132 * additional data section.
1133 */
1134 if (sectionid != DNS_SECTION_ADDITIONAL ||
1135 rdclass != dns_rdataclass_any ||
1136 count != msg->counts[sectionid] - 1)
1137 DO_FORMERR;
1138 msg->sigstart = recstart;
1139 } else if (rdtype == dns_rdatatype_opt) {
1140 /*
1141 * The name of an OPT record must be ".", it
1142 * must be in the additional data section, and
1143 * it must be the first OPT we've seen.
1144 */
1145 if (!dns_name_equal(dns_rootname, name) ||
1146 sectionid != DNS_SECTION_ADDITIONAL ||
1147 msg->opt != NULL)
1148 DO_FORMERR;
1149 } else if (rdtype == dns_rdatatype_tkey) {
1150 /*
1151 * A TKEY must be in the additional section if this
1152 * is a query, and the answer section if this is a
1153 * response. Unless it's a Win2000 client.
1154 *
1155 * Its class is ignored.
1156 */
1157 dns_section_t tkeysection;
1158
1159 if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1160 tkeysection = DNS_SECTION_ADDITIONAL;
1161 else
1162 tkeysection = DNS_SECTION_ANSWER;
1163 if (sectionid != tkeysection &&
1164 sectionid != DNS_SECTION_ANSWER)
1165 DO_FORMERR;
1166 }
1167
1168 /*
1169 * ... now get ttl and rdatalen, and check buffer.
1170 */
1171 ttl = isc_buffer_getuint32(source);
1172 rdatalen = isc_buffer_getuint16(source);
1173 r.length -= (2 + 2 + 4 + 2);
1174 if (r.length < rdatalen) {
1175 result = ISC_R_UNEXPECTEDEND;
1176 goto cleanup;
1177 }
1178
1179 /*
1180 * Read the rdata from the wire format. Interpret the
1181 * rdata according to its actual class, even if it had a
1182 * DynDNS meta-class in the packet (unless this is a TSIG).
1183 * Then put the meta-class back into the finished rdata.
1184 */
1185 rdata = newrdata(msg);
1186 if (rdata == NULL) {
1187 result = ISC_R_NOMEMORY;
1188 goto cleanup;
1189 }
1190 if (msg->opcode == dns_opcode_update &&
1191 update(sectionid, rdclass)) {
1192 if (rdatalen != 0) {
1193 result = DNS_R_FORMERR;
1194 goto cleanup;
1195 }
1196 /*
1197 * When the rdata is empty, the data pointer is
1198 * never dereferenced, but it must still be non-NULL.
1199 * Casting 1 rather than "" avoids warnings about
1200 * discarding the const attribute of a string,
1201 * for compilers that would warn about such things.
1202 */
1203 rdata->data = (unsigned char *)1;
1204 rdata->length = 0;
1205 rdata->rdclass = rdclass;
1206 rdata->type = rdtype;
1207 rdata->flags = DNS_RDATA_UPDATE;
1208 result = ISC_R_SUCCESS;
1209 } else if (rdclass == dns_rdataclass_none &&
1210 msg->opcode == dns_opcode_update &&
1211 sectionid == DNS_SECTION_UPDATE) {
1212 result = getrdata(source, msg, dctx, msg->rdclass,
1213 rdtype, rdatalen, rdata);
1214 } else
1215 result = getrdata(source, msg, dctx, rdclass,
1216 rdtype, rdatalen, rdata);
1217 if (result != ISC_R_SUCCESS)
1218 goto cleanup;
1219 rdata->rdclass = rdclass;
1220 issigzero = 0;
1221 if (rdtype == dns_rdatatype_rrsig &&
1222 rdata->flags == 0) {
1223 covers = dns_rdata_covers(rdata);
1224 if (covers == 0)
1225 DO_FORMERR;
1226 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1227 rdata->flags == 0) {
1228 covers = dns_rdata_covers(rdata);
1229 if (covers == 0) {
1230 if (sectionid != DNS_SECTION_ADDITIONAL ||
1231 count != msg->counts[sectionid] - 1)
1232 DO_FORMERR;
1233 msg->sigstart = recstart;
1234 issigzero = 1;
1235 } else {
1236 if (msg->rdclass != dns_rdataclass_any &&
1237 msg->rdclass != rdclass)
1238 DO_FORMERR;
1239 }
1240 } else
1241 covers = 0;
1242
1243 /*
1244 * Check the ownername of NSEC3 records
1245 */
1246 if (rdtype == dns_rdatatype_nsec3 &&
1247 !dns_rdata_checkowner_nsec3(name, msg->rdclass, rdtype,
1248 0)) {
1249 result = DNS_R_BADOWNERNAME;
1250 goto cleanup;
1251 }
1252
1253 if (rdtype != dns_rdatatype_opt &&
1254 rdtype != dns_rdatatype_tsig && !issigzero) {
1255 ISC_LIST_APPEND(*section, name, link);
1256 free_name = 0;
1257 }
1258
1259 rdataset = malloc(sizeof(dns_rdataset_t));
1260 if (rdataset == NULL) {
1261 result = ISC_R_NOMEMORY;
1262 goto cleanup;
1263 }
1264 free_rdataset = 1;
1265
1266 rdatalist = newrdatalist(msg);
1267 if (rdatalist == NULL) {
1268 result = ISC_R_NOMEMORY;
1269 goto cleanup;
1270 }
1271
1272 rdatalist->type = rdtype;
1273 rdatalist->covers = covers;
1274 rdatalist->rdclass = rdclass;
1275 rdatalist->ttl = ttl;
1276 ISC_LIST_INIT(rdatalist->rdata);
1277
1278 dns_rdataset_init(rdataset);
1279 RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1280 rdataset)
1281 == ISC_R_SUCCESS);
1282
1283 if (rdtype != dns_rdatatype_opt &&
1284 rdtype != dns_rdatatype_tsig &&
1285 !issigzero)
1286 {
1287 ISC_LIST_APPEND(name->list, rdataset, link);
1288 free_rdataset = 0;
1289 }
1290
1291 /*
1292 * Minimize TTLs.
1293 *
1294 * Section 5.2 of RFC2181 says we should drop
1295 * nonauthoritative rrsets where the TTLs differ, but we
1296 * currently treat them the as if they were authoritative and
1297 * minimize them.
1298 */
1299 if (ttl < rdataset->ttl)
1300 rdataset->ttl = ttl;
1301
1302 /* Append this rdata to the rdataset. */
1303 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1304 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1305
1306 /*
1307 * If this is an OPT, SIG(0) or TSIG record, remember it.
1308 * Also, set the extended rcode for TSIG.
1309 *
1310 * Note msg->opt, msg->sig0 and msg->tsig will only be
1311 * already set if best-effort parsing is enabled otherwise
1312 * there will only be at most one of each.
1313 */
1314 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1315 dns_rcode_t ercode;
1316
1317 msg->opt = rdataset;
1318 rdataset = NULL;
1319 free_rdataset = 0;
1320 ercode = (dns_rcode_t)
1321 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1322 >> 20);
1323 msg->rcode |= ercode;
1324 free(name);
1325 free_name = 0;
1326 } else if (issigzero && msg->sig0 == NULL) {
1327 msg->sig0 = rdataset;
1328 msg->sig0name = name;
1329 rdataset = NULL;
1330 free_rdataset = 0;
1331 free_name = 0;
1332 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1333 msg->tsig = rdataset;
1334 msg->tsigname = name;
1335 /* Windows doesn't like TSIG names to be compressed. */
1336 msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1337 rdataset = NULL;
1338 free_rdataset = 0;
1339 free_name = 0;
1340 }
1341
1342 if (seen_problem) {
1343 if (free_name)
1344 free(name);
1345 if (free_rdataset)
1346 free(rdataset);
1347 free_name = free_rdataset = 0;
1348 }
1349 INSIST(!free_name);
1350 INSIST(!free_rdataset);
1351 }
1352
1353 if (seen_problem)
1354 return (DNS_R_RECOVERABLE);
1355 return (ISC_R_SUCCESS);
1356
1357 cleanup:
1358 if (free_name)
1359 free(name);
1360 if (free_rdataset)
1361 free(rdataset);
1362
1363 return (result);
1364 }
1365
1366 isc_result_t
dns_message_parse(dns_message_t * msg,isc_buffer_t * source,unsigned int options)1367 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1368 unsigned int options)
1369 {
1370 isc_region_t r;
1371 dns_decompress_t dctx;
1372 isc_result_t ret;
1373 uint16_t tmpflags;
1374 isc_buffer_t origsource;
1375 int seen_problem;
1376 int ignore_tc;
1377
1378 REQUIRE(source != NULL);
1379 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1380
1381 seen_problem = 0;
1382 ignore_tc = options & DNS_MESSAGEPARSE_IGNORETRUNCATION;
1383
1384 origsource = *source;
1385
1386 msg->header_ok = 0;
1387 msg->question_ok = 0;
1388
1389 isc_buffer_remainingregion(source, &r);
1390 if (r.length < DNS_MESSAGE_HEADERLEN)
1391 return (ISC_R_UNEXPECTEDEND);
1392
1393 msg->id = isc_buffer_getuint16(source);
1394 tmpflags = isc_buffer_getuint16(source);
1395 msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1396 >> DNS_MESSAGE_OPCODE_SHIFT);
1397 msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1398 msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1399 msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1400 msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1401 msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1402 msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1403
1404 msg->header_ok = 1;
1405 msg->state = DNS_SECTION_QUESTION;
1406
1407 /*
1408 * -1 means no EDNS.
1409 */
1410 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1411
1412 dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1413
1414 ret = getquestions(source, msg, &dctx, options);
1415 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1416 goto truncated;
1417 if (ret == DNS_R_RECOVERABLE) {
1418 seen_problem = 1;
1419 ret = ISC_R_SUCCESS;
1420 }
1421 if (ret != ISC_R_SUCCESS)
1422 return (ret);
1423 msg->question_ok = 1;
1424
1425 ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1426 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1427 goto truncated;
1428 if (ret == DNS_R_RECOVERABLE) {
1429 seen_problem = 1;
1430 ret = ISC_R_SUCCESS;
1431 }
1432 if (ret != ISC_R_SUCCESS)
1433 return (ret);
1434
1435 ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1436 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1437 goto truncated;
1438 if (ret == DNS_R_RECOVERABLE) {
1439 seen_problem = 1;
1440 ret = ISC_R_SUCCESS;
1441 }
1442 if (ret != ISC_R_SUCCESS)
1443 return (ret);
1444
1445 ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1446 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1447 goto truncated;
1448 if (ret == DNS_R_RECOVERABLE) {
1449 seen_problem = 1;
1450 ret = ISC_R_SUCCESS;
1451 }
1452 if (ret != ISC_R_SUCCESS)
1453 return (ret);
1454
1455 isc_buffer_remainingregion(source, &r);
1456 if (r.length != 0) {
1457 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1458 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1459 "message has %u byte(s) of trailing garbage",
1460 r.length);
1461 }
1462
1463 truncated:
1464 isc_buffer_usedregion(&origsource, &msg->saved);
1465
1466 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1467 return (DNS_R_RECOVERABLE);
1468 if (seen_problem)
1469 return (DNS_R_RECOVERABLE);
1470 return (ISC_R_SUCCESS);
1471 }
1472
1473 isc_result_t
dns_message_renderbegin(dns_message_t * msg,dns_compress_t * cctx,isc_buffer_t * buffer)1474 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1475 isc_buffer_t *buffer)
1476 {
1477 isc_region_t r;
1478
1479 REQUIRE(buffer != NULL);
1480 REQUIRE(msg->buffer == NULL);
1481 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1482
1483 msg->cctx = cctx;
1484
1485 /*
1486 * Erase the contents of this buffer.
1487 */
1488 isc_buffer_clear(buffer);
1489
1490 /*
1491 * Make certain there is enough for at least the header in this
1492 * buffer.
1493 */
1494 isc_buffer_availableregion(buffer, &r);
1495 if (r.length < DNS_MESSAGE_HEADERLEN)
1496 return (ISC_R_NOSPACE);
1497
1498 if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved)
1499 return (ISC_R_NOSPACE);
1500
1501 /*
1502 * Reserve enough space for the header in this buffer.
1503 */
1504 isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1505
1506 msg->buffer = buffer;
1507
1508 return (ISC_R_SUCCESS);
1509 }
1510
1511 void
dns_message_renderrelease(dns_message_t * msg,unsigned int space)1512 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1513 REQUIRE(space <= msg->reserved);
1514
1515 msg->reserved -= space;
1516 }
1517
1518 isc_result_t
dns_message_renderreserve(dns_message_t * msg,unsigned int space)1519 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1520 isc_region_t r;
1521
1522 if (msg->buffer != NULL) {
1523 isc_buffer_availableregion(msg->buffer, &r);
1524 if (r.length < (space + msg->reserved))
1525 return (ISC_R_NOSPACE);
1526 }
1527
1528 msg->reserved += space;
1529
1530 return (ISC_R_SUCCESS);
1531 }
1532
1533 static inline int
wrong_priority(dns_rdataset_t * rds,int pass)1534 wrong_priority(dns_rdataset_t *rds, int pass) {
1535 int pass_needed;
1536
1537 /*
1538 * If we are not rendering class IN, this ordering is bogus.
1539 */
1540 if (rds->rdclass != dns_rdataclass_in)
1541 return (0);
1542
1543 switch (rds->type) {
1544 case dns_rdatatype_a:
1545 case dns_rdatatype_aaaa:
1546 pass_needed = 3;
1547 break;
1548 case dns_rdatatype_rrsig:
1549 case dns_rdatatype_dnskey:
1550 pass_needed = 2;
1551 break;
1552 default:
1553 pass_needed = 1;
1554 }
1555
1556 if (pass_needed >= pass)
1557 return (0);
1558
1559 return (1);
1560 }
1561
1562 static isc_result_t
renderset(dns_rdataset_t * rdataset,dns_name_t * owner_name,dns_compress_t * cctx,isc_buffer_t * target,unsigned int reserved,unsigned int * countp)1563 renderset(dns_rdataset_t *rdataset, dns_name_t *owner_name,
1564 dns_compress_t *cctx, isc_buffer_t *target,
1565 unsigned int reserved, unsigned int *countp)
1566 {
1567 isc_result_t result;
1568
1569 /*
1570 * Shrink the space in the buffer by the reserved amount.
1571 */
1572 if (target->length - target->used < reserved)
1573 return (ISC_R_NOSPACE);
1574
1575 target->length -= reserved;
1576 result = dns_rdataset_towire(rdataset, owner_name,
1577 cctx, target, countp);
1578 target->length += reserved;
1579
1580 return (result);
1581 }
1582
1583 static void
maybe_clear_ad(dns_message_t * msg,dns_section_t sectionid)1584 maybe_clear_ad(dns_message_t *msg, dns_section_t sectionid) {
1585 if (msg->counts[sectionid] == 0 &&
1586 (sectionid == DNS_SECTION_ANSWER ||
1587 (sectionid == DNS_SECTION_AUTHORITY &&
1588 msg->counts[DNS_SECTION_ANSWER] == 0)))
1589 msg->flags &= ~DNS_MESSAGEFLAG_AD;
1590 }
1591
1592 isc_result_t
dns_message_rendersection(dns_message_t * msg,dns_section_t sectionid)1593 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid)
1594 {
1595 dns_namelist_t *section;
1596 dns_name_t *name, *next_name;
1597 dns_rdataset_t *rdataset, *next_rdataset;
1598 unsigned int count, total;
1599 isc_result_t result;
1600 isc_buffer_t st; /* for rollbacks */
1601 int pass;
1602
1603 REQUIRE(msg->buffer != NULL);
1604 REQUIRE(VALID_NAMED_SECTION(sectionid));
1605
1606 section = &msg->sections[sectionid];
1607
1608 if (sectionid == DNS_SECTION_ADDITIONAL)
1609 pass = 3;
1610 else
1611 pass = 1;
1612
1613 /*
1614 * Shrink the space in the buffer by the reserved amount.
1615 */
1616 if (msg->buffer->length - msg->buffer->used < msg->reserved)
1617 return (ISC_R_NOSPACE);
1618 msg->buffer->length -= msg->reserved;
1619
1620 total = 0;
1621
1622 do {
1623 name = ISC_LIST_HEAD(*section);
1624 if (name == NULL) {
1625 msg->buffer->length += msg->reserved;
1626 msg->counts[sectionid] += total;
1627 return (ISC_R_SUCCESS);
1628 }
1629
1630 while (name != NULL) {
1631 next_name = ISC_LIST_NEXT(name, link);
1632
1633 rdataset = ISC_LIST_HEAD(name->list);
1634 while (rdataset != NULL) {
1635 next_rdataset = ISC_LIST_NEXT(rdataset, link);
1636
1637 if ((rdataset->attributes &
1638 DNS_RDATASETATTR_RENDERED) != 0)
1639 goto next;
1640
1641 if ((sectionid == DNS_SECTION_ADDITIONAL)
1642 && wrong_priority(rdataset, pass))
1643 goto next;
1644
1645 st = *(msg->buffer);
1646
1647 count = 0;
1648 result = dns_rdataset_towiresorted(
1649 rdataset,
1650 name,
1651 msg->cctx,
1652 msg->buffer,
1653 &count);
1654
1655 total += count;
1656
1657 /*
1658 * If out of space, record stats on what we
1659 * rendered so far, and return that status.
1660 *
1661 */
1662 if (result != ISC_R_SUCCESS) {
1663 INSIST(st.used < 65536);
1664 dns_compress_rollback(msg->cctx,
1665 (uint16_t)st.used);
1666 *(msg->buffer) = st; /* rollback */
1667 msg->buffer->length += msg->reserved;
1668 msg->counts[sectionid] += total;
1669 maybe_clear_ad(msg, sectionid);
1670 return (result);
1671 }
1672
1673 /*
1674 * If we have rendered non-validated data,
1675 * ensure that the AD bit is not set.
1676 */
1677 if ((sectionid == DNS_SECTION_ANSWER ||
1678 sectionid == DNS_SECTION_AUTHORITY))
1679 msg->flags &= ~DNS_MESSAGEFLAG_AD;
1680
1681 rdataset->attributes |=
1682 DNS_RDATASETATTR_RENDERED;
1683
1684 next:
1685 rdataset = next_rdataset;
1686 }
1687
1688 name = next_name;
1689 }
1690 } while (--pass != 0);
1691
1692 msg->buffer->length += msg->reserved;
1693 msg->counts[sectionid] += total;
1694
1695 return (ISC_R_SUCCESS);
1696 }
1697
1698 void
dns_message_renderheader(dns_message_t * msg,isc_buffer_t * target)1699 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
1700 uint16_t tmp;
1701 isc_region_t r;
1702
1703 REQUIRE(target != NULL);
1704
1705 isc_buffer_availableregion(target, &r);
1706 REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
1707
1708 isc_buffer_putuint16(target, msg->id);
1709
1710 tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
1711 & DNS_MESSAGE_OPCODE_MASK);
1712 tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
1713 tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
1714
1715 INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
1716 msg->counts[DNS_SECTION_ANSWER] < 65536 &&
1717 msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
1718 msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
1719
1720 isc_buffer_putuint16(target, tmp);
1721 isc_buffer_putuint16(target,
1722 (uint16_t)msg->counts[DNS_SECTION_QUESTION]);
1723 isc_buffer_putuint16(target,
1724 (uint16_t)msg->counts[DNS_SECTION_ANSWER]);
1725 isc_buffer_putuint16(target,
1726 (uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
1727 isc_buffer_putuint16(target,
1728 (uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
1729 }
1730
1731 isc_result_t
dns_message_renderend(dns_message_t * msg)1732 dns_message_renderend(dns_message_t *msg) {
1733 isc_buffer_t tmpbuf;
1734 isc_region_t r;
1735 int result;
1736 unsigned int count;
1737
1738 REQUIRE(msg->buffer != NULL);
1739
1740 if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
1741 /*
1742 * We have an extended rcode but are not using EDNS.
1743 */
1744 return (DNS_R_FORMERR);
1745 }
1746
1747 /*
1748 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
1749 * clear all rdatasets from the message except for the question
1750 * before adding the OPT, TSIG or SIG(0). If the question doesn't
1751 * fit, don't include it.
1752 */
1753 if ((msg->tsigkey != NULL || msg->opt) &&
1754 (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
1755 {
1756 isc_buffer_t *buf;
1757
1758 msgresetnames(msg, DNS_SECTION_ANSWER);
1759 buf = msg->buffer;
1760 dns_message_renderreset(msg);
1761 msg->buffer = buf;
1762 isc_buffer_clear(msg->buffer);
1763 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
1764 dns_compress_rollback(msg->cctx, 0);
1765 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION);
1766 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
1767 return (result);
1768 }
1769
1770 /*
1771 * If we've got an OPT record, render it.
1772 */
1773 if (msg->opt != NULL) {
1774 dns_message_renderrelease(msg, msg->opt_reserved);
1775 msg->opt_reserved = 0;
1776 /*
1777 * Set the extended rcode.
1778 */
1779 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
1780 msg->opt->ttl |= ((msg->rcode << 20) &
1781 DNS_MESSAGE_EDNSRCODE_MASK);
1782 /*
1783 * Render.
1784 */
1785 count = 0;
1786 result = renderset(msg->opt, dns_rootname, msg->cctx,
1787 msg->buffer, msg->reserved, &count);
1788 msg->counts[DNS_SECTION_ADDITIONAL] += count;
1789 if (result != ISC_R_SUCCESS)
1790 return (result);
1791 }
1792
1793 /*
1794 * If we're adding a TSIG record, generate and render it.
1795 */
1796 if (msg->tsigkey != NULL) {
1797 dns_message_renderrelease(msg, msg->sig_reserved);
1798 msg->sig_reserved = 0;
1799 result = dns_tsig_sign(msg);
1800 if (result != ISC_R_SUCCESS)
1801 return (result);
1802 count = 0;
1803 result = renderset(msg->tsig, msg->tsigname, msg->cctx,
1804 msg->buffer, msg->reserved, &count);
1805 msg->counts[DNS_SECTION_ADDITIONAL] += count;
1806 if (result != ISC_R_SUCCESS)
1807 return (result);
1808 }
1809
1810 isc_buffer_usedregion(msg->buffer, &r);
1811 isc_buffer_init(&tmpbuf, r.base, r.length);
1812
1813 dns_message_renderheader(msg, &tmpbuf);
1814
1815 msg->buffer = NULL; /* forget about this buffer only on success XXX */
1816
1817 return (ISC_R_SUCCESS);
1818 }
1819
1820 void
dns_message_renderreset(dns_message_t * msg)1821 dns_message_renderreset(dns_message_t *msg) {
1822 unsigned int i;
1823 dns_name_t *name;
1824 dns_rdataset_t *rds;
1825
1826 /*
1827 * Reset the message so that it may be rendered again.
1828 */
1829
1830 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1831
1832 msg->buffer = NULL;
1833
1834 for (i = 0; i < DNS_SECTION_MAX; i++) {
1835 msg->cursors[i] = NULL;
1836 msg->counts[i] = 0;
1837 for (name = ISC_LIST_HEAD(msg->sections[i]);
1838 name != NULL;
1839 name = ISC_LIST_NEXT(name, link)) {
1840 for (rds = ISC_LIST_HEAD(name->list);
1841 rds != NULL;
1842 rds = ISC_LIST_NEXT(rds, link)) {
1843 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
1844 }
1845 }
1846 }
1847 if (msg->tsigname != NULL)
1848 dns_message_puttempname(msg, &msg->tsigname);
1849 if (msg->tsig != NULL) {
1850 dns_rdataset_disassociate(msg->tsig);
1851 dns_message_puttemprdataset(msg, &msg->tsig);
1852 }
1853 if (msg->sig0 != NULL) {
1854 dns_rdataset_disassociate(msg->sig0);
1855 dns_message_puttemprdataset(msg, &msg->sig0);
1856 }
1857 }
1858
1859 isc_result_t
dns_message_firstname(dns_message_t * msg,dns_section_t section)1860 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
1861 REQUIRE(VALID_NAMED_SECTION(section));
1862
1863 msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
1864
1865 if (msg->cursors[section] == NULL)
1866 return (ISC_R_NOMORE);
1867
1868 return (ISC_R_SUCCESS);
1869 }
1870
1871 isc_result_t
dns_message_nextname(dns_message_t * msg,dns_section_t section)1872 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
1873 REQUIRE(VALID_NAMED_SECTION(section));
1874 REQUIRE(msg->cursors[section] != NULL);
1875
1876 msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
1877
1878 if (msg->cursors[section] == NULL)
1879 return (ISC_R_NOMORE);
1880
1881 return (ISC_R_SUCCESS);
1882 }
1883
1884 void
dns_message_currentname(dns_message_t * msg,dns_section_t section,dns_name_t ** name)1885 dns_message_currentname(dns_message_t *msg, dns_section_t section,
1886 dns_name_t **name)
1887 {
1888 REQUIRE(VALID_NAMED_SECTION(section));
1889 REQUIRE(name != NULL && *name == NULL);
1890 REQUIRE(msg->cursors[section] != NULL);
1891
1892 *name = msg->cursors[section];
1893 }
1894
1895 isc_result_t
dns_message_findname(dns_message_t * msg,dns_section_t section,dns_name_t * target,dns_rdatatype_t type,dns_rdatatype_t covers,dns_name_t ** name,dns_rdataset_t ** rdataset)1896 dns_message_findname(dns_message_t *msg, dns_section_t section,
1897 dns_name_t *target, dns_rdatatype_t type,
1898 dns_rdatatype_t covers, dns_name_t **name,
1899 dns_rdataset_t **rdataset)
1900 {
1901 dns_name_t *foundname;
1902 isc_result_t result;
1903
1904 /*
1905 * XXX These requirements are probably too intensive, especially
1906 * where things can be NULL, but as they are they ensure that if
1907 * something is NON-NULL, indicating that the caller expects it
1908 * to be filled in, that we can in fact fill it in.
1909 */
1910 REQUIRE(msg != NULL);
1911 REQUIRE(VALID_SECTION(section));
1912 REQUIRE(target != NULL);
1913 REQUIRE(name == NULL || *name == NULL);
1914
1915 if (type == dns_rdatatype_any) {
1916 REQUIRE(rdataset == NULL);
1917 } else {
1918 REQUIRE(rdataset == NULL || *rdataset == NULL);
1919 }
1920
1921 result = findname(&foundname, target,
1922 &msg->sections[section]);
1923
1924 if (result == ISC_R_NOTFOUND)
1925 return (DNS_R_NXDOMAIN);
1926 else if (result != ISC_R_SUCCESS)
1927 return (result);
1928
1929 if (name != NULL)
1930 *name = foundname;
1931
1932 /*
1933 * And now look for the type.
1934 */
1935 if (type == dns_rdatatype_any)
1936 return (ISC_R_SUCCESS);
1937
1938 result = dns_message_findtype(foundname, type, covers, rdataset);
1939 if (result == ISC_R_NOTFOUND)
1940 return (DNS_R_NXRRSET);
1941
1942 return (result);
1943 }
1944
1945 void
dns_message_addname(dns_message_t * msg,dns_name_t * name,dns_section_t section)1946 dns_message_addname(dns_message_t *msg, dns_name_t *name,
1947 dns_section_t section)
1948 {
1949 REQUIRE(msg != NULL);
1950 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1951 REQUIRE(name != NULL);
1952 REQUIRE(VALID_NAMED_SECTION(section));
1953
1954 ISC_LIST_APPEND(msg->sections[section], name, link);
1955 }
1956
1957 isc_result_t
dns_message_gettempname(dns_message_t * msg,dns_name_t ** item)1958 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
1959 REQUIRE(item != NULL && *item == NULL);
1960
1961 UNUSED(msg);
1962
1963 *item = malloc(sizeof(dns_name_t));
1964 if (*item == NULL)
1965 return (ISC_R_NOMEMORY);
1966 dns_name_init(*item, NULL);
1967
1968 return (ISC_R_SUCCESS);
1969 }
1970
1971 isc_result_t
dns_message_gettemprdata(dns_message_t * msg,dns_rdata_t ** item)1972 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
1973 REQUIRE(item != NULL && *item == NULL);
1974
1975 *item = newrdata(msg);
1976 if (*item == NULL)
1977 return (ISC_R_NOMEMORY);
1978
1979 return (ISC_R_SUCCESS);
1980 }
1981
1982 isc_result_t
dns_message_gettemprdataset(dns_message_t * msg,dns_rdataset_t ** item)1983 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
1984 REQUIRE(item != NULL && *item == NULL);
1985
1986 UNUSED(msg);
1987
1988 *item = malloc(sizeof(dns_rdataset_t));
1989 if (*item == NULL)
1990 return (ISC_R_NOMEMORY);
1991
1992 dns_rdataset_init(*item);
1993
1994 return (ISC_R_SUCCESS);
1995 }
1996
1997 isc_result_t
dns_message_gettemprdatalist(dns_message_t * msg,dns_rdatalist_t ** item)1998 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
1999 REQUIRE(item != NULL && *item == NULL);
2000
2001 *item = newrdatalist(msg);
2002 if (*item == NULL)
2003 return (ISC_R_NOMEMORY);
2004
2005 return (ISC_R_SUCCESS);
2006 }
2007
2008 void
dns_message_puttempname(dns_message_t * msg,dns_name_t ** item)2009 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2010 REQUIRE(item != NULL && *item != NULL);
2011
2012 UNUSED(msg);
2013
2014 if (dns_name_dynamic(*item))
2015 dns_name_free(*item);
2016 free(*item);
2017 *item = NULL;
2018 }
2019
2020 void
dns_message_puttemprdata(dns_message_t * msg,dns_rdata_t ** item)2021 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2022 REQUIRE(item != NULL && *item != NULL);
2023
2024 releaserdata(msg, *item);
2025 *item = NULL;
2026 }
2027
2028 void
dns_message_puttemprdataset(dns_message_t * msg,dns_rdataset_t ** item)2029 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2030 REQUIRE(item != NULL && *item != NULL);
2031 REQUIRE(!dns_rdataset_isassociated(*item));
2032
2033 UNUSED(msg);
2034
2035 free(*item);
2036 *item = NULL;
2037 }
2038
2039 void
dns_message_puttemprdatalist(dns_message_t * msg,dns_rdatalist_t ** item)2040 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2041 REQUIRE(item != NULL && *item != NULL);
2042
2043 releaserdatalist(msg, *item);
2044 *item = NULL;
2045 }
2046
2047 isc_result_t
dns_message_peekheader(isc_buffer_t * source,dns_messageid_t * idp,unsigned int * flagsp)2048 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2049 unsigned int *flagsp)
2050 {
2051 isc_region_t r;
2052 isc_buffer_t buffer;
2053 dns_messageid_t id;
2054 unsigned int flags;
2055
2056 REQUIRE(source != NULL);
2057
2058 buffer = *source;
2059
2060 isc_buffer_remainingregion(&buffer, &r);
2061 if (r.length < DNS_MESSAGE_HEADERLEN)
2062 return (ISC_R_UNEXPECTEDEND);
2063
2064 id = isc_buffer_getuint16(&buffer);
2065 flags = isc_buffer_getuint16(&buffer);
2066 flags &= DNS_MESSAGE_FLAG_MASK;
2067
2068 if (flagsp != NULL)
2069 *flagsp = flags;
2070 if (idp != NULL)
2071 *idp = id;
2072
2073 return (ISC_R_SUCCESS);
2074 }
2075
2076 dns_rdataset_t *
dns_message_getopt(dns_message_t * msg)2077 dns_message_getopt(dns_message_t *msg) {
2078
2079 /*
2080 * Get the OPT record for 'msg'.
2081 */
2082 return (msg->opt);
2083 }
2084
2085 isc_result_t
dns_message_setopt(dns_message_t * msg,dns_rdataset_t * opt)2086 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2087 isc_result_t result;
2088 dns_rdata_t rdata = DNS_RDATA_INIT;
2089
2090 /*
2091 * Set the OPT record for 'msg'.
2092 */
2093
2094 /*
2095 * The space required for an OPT record is:
2096 *
2097 * 1 byte for the name
2098 * 2 bytes for the type
2099 * 2 bytes for the class
2100 * 4 bytes for the ttl
2101 * 2 bytes for the rdata length
2102 * ---------------------------------
2103 * 11 bytes
2104 *
2105 * plus the length of the rdata.
2106 */
2107
2108 REQUIRE(opt->type == dns_rdatatype_opt);
2109 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2110 REQUIRE(msg->state == DNS_SECTION_ANY);
2111
2112 msgresetopt(msg);
2113
2114 result = dns_rdataset_first(opt);
2115 if (result != ISC_R_SUCCESS)
2116 goto cleanup;
2117 dns_rdataset_current(opt, &rdata);
2118 msg->opt_reserved = 11 + rdata.length;
2119 result = dns_message_renderreserve(msg, msg->opt_reserved);
2120 if (result != ISC_R_SUCCESS) {
2121 msg->opt_reserved = 0;
2122 goto cleanup;
2123 }
2124
2125 msg->opt = opt;
2126
2127 return (ISC_R_SUCCESS);
2128
2129 cleanup:
2130 dns_rdataset_disassociate(opt);
2131 dns_message_puttemprdataset(msg, &opt);
2132 return (result);
2133 }
2134
2135 dns_rdataset_t *
dns_message_gettsig(dns_message_t * msg,dns_name_t ** owner)2136 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2137
2138 /*
2139 * Get the TSIG record and owner for 'msg'.
2140 */
2141
2142 REQUIRE(owner == NULL || *owner == NULL);
2143
2144 if (owner != NULL)
2145 *owner = msg->tsigname;
2146 return (msg->tsig);
2147 }
2148
2149 isc_result_t
dns_message_settsigkey(dns_message_t * msg,dns_tsigkey_t * key)2150 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2151 isc_result_t result;
2152
2153 /*
2154 * Set the TSIG key for 'msg'
2155 */
2156
2157 REQUIRE(msg->state == DNS_SECTION_ANY);
2158
2159 if (key == NULL && msg->tsigkey != NULL) {
2160 if (msg->sig_reserved != 0) {
2161 dns_message_renderrelease(msg, msg->sig_reserved);
2162 msg->sig_reserved = 0;
2163 }
2164 dns_tsigkey_detach(&msg->tsigkey);
2165 }
2166 if (key != NULL) {
2167 REQUIRE(msg->tsigkey == NULL);
2168 dns_tsigkey_attach(key, &msg->tsigkey);
2169 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2170 msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2171 result = dns_message_renderreserve(msg,
2172 msg->sig_reserved);
2173 if (result != ISC_R_SUCCESS) {
2174 dns_tsigkey_detach(&msg->tsigkey);
2175 msg->sig_reserved = 0;
2176 return (result);
2177 }
2178 }
2179 }
2180 return (ISC_R_SUCCESS);
2181 }
2182
2183 dns_tsigkey_t *
dns_message_gettsigkey(dns_message_t * msg)2184 dns_message_gettsigkey(dns_message_t *msg) {
2185
2186 /*
2187 * Get the TSIG key for 'msg'
2188 */
2189 return (msg->tsigkey);
2190 }
2191
2192 isc_result_t
dns_message_setquerytsig(dns_message_t * msg,isc_buffer_t * querytsig)2193 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2194 dns_rdata_t *rdata = NULL;
2195 dns_rdatalist_t *list = NULL;
2196 dns_rdataset_t *set = NULL;
2197 isc_buffer_t *buf = NULL;
2198 isc_region_t r;
2199 isc_result_t result;
2200
2201 REQUIRE(msg->querytsig == NULL);
2202
2203 if (querytsig == NULL)
2204 return (ISC_R_SUCCESS);
2205
2206 result = dns_message_gettemprdata(msg, &rdata);
2207 if (result != ISC_R_SUCCESS)
2208 goto cleanup;
2209
2210 result = dns_message_gettemprdatalist(msg, &list);
2211 if (result != ISC_R_SUCCESS)
2212 goto cleanup;
2213 result = dns_message_gettemprdataset(msg, &set);
2214 if (result != ISC_R_SUCCESS)
2215 goto cleanup;
2216
2217 isc_buffer_usedregion(querytsig, &r);
2218 result = isc_buffer_allocate(&buf, r.length);
2219 if (result != ISC_R_SUCCESS)
2220 goto cleanup;
2221 isc_buffer_putmem(buf, r.base, r.length);
2222 isc_buffer_usedregion(buf, &r);
2223 dns_rdata_init(rdata);
2224 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2225 dns_message_takebuffer(msg, &buf);
2226 ISC_LIST_APPEND(list->rdata, rdata, link);
2227 result = dns_rdatalist_tordataset(list, set);
2228 if (result != ISC_R_SUCCESS)
2229 goto cleanup;
2230
2231 msg->querytsig = set;
2232
2233 return (result);
2234
2235 cleanup:
2236 if (rdata != NULL)
2237 dns_message_puttemprdata(msg, &rdata);
2238 if (list != NULL)
2239 dns_message_puttemprdatalist(msg, &list);
2240 if (set != NULL)
2241 dns_message_puttemprdataset(msg, &set);
2242 return (ISC_R_NOMEMORY);
2243 }
2244
2245 isc_result_t
dns_message_getquerytsig(dns_message_t * msg,isc_buffer_t ** querytsig)2246 dns_message_getquerytsig(dns_message_t *msg, isc_buffer_t **querytsig) {
2247 isc_result_t result;
2248 dns_rdata_t rdata = DNS_RDATA_INIT;
2249 isc_region_t r;
2250
2251 REQUIRE(querytsig != NULL && *querytsig == NULL);
2252
2253 if (msg->tsig == NULL)
2254 return (ISC_R_SUCCESS);
2255
2256 result = dns_rdataset_first(msg->tsig);
2257 if (result != ISC_R_SUCCESS)
2258 return (result);
2259 dns_rdataset_current(msg->tsig, &rdata);
2260 dns_rdata_toregion(&rdata, &r);
2261
2262 result = isc_buffer_allocate(querytsig, r.length);
2263 if (result != ISC_R_SUCCESS)
2264 return (result);
2265 isc_buffer_putmem(*querytsig, r.base, r.length);
2266 return (ISC_R_SUCCESS);
2267 }
2268
2269 dns_rdataset_t *
dns_message_getsig0(dns_message_t * msg,dns_name_t ** owner)2270 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2271
2272 /*
2273 * Get the SIG(0) record for 'msg'.
2274 */
2275
2276 REQUIRE(owner == NULL || *owner == NULL);
2277
2278 if (msg->sig0 != NULL && owner != NULL) {
2279 /* If dns_message_getsig0 is called on a rendered message
2280 * after the SIG(0) has been applied, we need to return the
2281 * root name, not NULL.
2282 */
2283 if (msg->sig0name == NULL)
2284 *owner = dns_rootname;
2285 else
2286 *owner = msg->sig0name;
2287 }
2288 return (msg->sig0);
2289 }
2290
2291 void
dns_message_takebuffer(dns_message_t * msg,isc_buffer_t ** buffer)2292 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2293 REQUIRE(buffer != NULL);
2294
2295 ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2296 *buffer = NULL;
2297 }
2298
2299 isc_result_t
dns_message_sectiontotext(dns_message_t * msg,dns_section_t section,const dns_master_style_t * style,dns_messagetextflag_t flags,isc_buffer_t * target)2300 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
2301 const dns_master_style_t *style,
2302 dns_messagetextflag_t flags,
2303 isc_buffer_t *target) {
2304 dns_name_t *name, empty_name;
2305 dns_rdataset_t *rdataset;
2306 isc_result_t result;
2307 int seensoa = 0;
2308
2309 REQUIRE(target != NULL);
2310 REQUIRE(VALID_SECTION(section));
2311
2312 if (ISC_LIST_EMPTY(msg->sections[section]))
2313 return (ISC_R_SUCCESS);
2314
2315 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
2316 ADD_STRING(target, ";; ");
2317 if (msg->opcode != dns_opcode_update) {
2318 ADD_STRING(target, sectiontext[section]);
2319 } else {
2320 ADD_STRING(target, updsectiontext[section]);
2321 }
2322 ADD_STRING(target, " SECTION:\n");
2323 }
2324
2325 dns_name_init(&empty_name, NULL);
2326 result = dns_message_firstname(msg, section);
2327 if (result != ISC_R_SUCCESS) {
2328 return (result);
2329 }
2330 do {
2331 name = NULL;
2332 dns_message_currentname(msg, section, &name);
2333 for (rdataset = ISC_LIST_HEAD(name->list);
2334 rdataset != NULL;
2335 rdataset = ISC_LIST_NEXT(rdataset, link)) {
2336 if (section == DNS_SECTION_ANSWER &&
2337 rdataset->type == dns_rdatatype_soa) {
2338 if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
2339 continue;
2340 if (seensoa &&
2341 (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
2342 continue;
2343 seensoa = 1;
2344 }
2345 if (section == DNS_SECTION_QUESTION) {
2346 ADD_STRING(target, ";");
2347 result = dns_master_questiontotext(name,
2348 rdataset,
2349 style,
2350 target);
2351 } else {
2352 result = dns_master_rdatasettotext(name,
2353 rdataset,
2354 style,
2355 target);
2356 }
2357 if (result != ISC_R_SUCCESS)
2358 return (result);
2359 }
2360 result = dns_message_nextname(msg, section);
2361 } while (result == ISC_R_SUCCESS);
2362 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
2363 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2364 ADD_STRING(target, "\n");
2365 if (result == ISC_R_NOMORE)
2366 result = ISC_R_SUCCESS;
2367 return (result);
2368 }
2369
2370 static isc_result_t
render_ecs(isc_buffer_t * ecsbuf,isc_buffer_t * target)2371 render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
2372 int i;
2373 char addr[16], addr_text[64];
2374 uint16_t family;
2375 uint8_t addrlen, addrbytes, scopelen;
2376
2377 /*
2378 * Note: This routine needs to handle malformed ECS options.
2379 */
2380
2381 if (isc_buffer_remaininglength(ecsbuf) < 4)
2382 return (DNS_R_OPTERR);
2383 family = isc_buffer_getuint16(ecsbuf);
2384 addrlen = isc_buffer_getuint8(ecsbuf);
2385 scopelen = isc_buffer_getuint8(ecsbuf);
2386
2387 addrbytes = (addrlen + 7) / 8;
2388 if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
2389 return (DNS_R_OPTERR);
2390
2391 if (addrbytes > sizeof(addr))
2392 return (DNS_R_OPTERR);
2393
2394 memset(addr, 0, sizeof(addr));
2395 for (i = 0; i < addrbytes; i ++)
2396 addr[i] = isc_buffer_getuint8(ecsbuf);
2397
2398 switch (family) {
2399 case 0:
2400 if (addrlen != 0U || scopelen != 0U)
2401 return (DNS_R_OPTERR);
2402 strlcpy(addr_text, "0", sizeof(addr_text));
2403 break;
2404 case 1:
2405 if (addrlen > 32 || scopelen > 32)
2406 return (DNS_R_OPTERR);
2407 inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
2408 break;
2409 case 2:
2410 if (addrlen > 128 || scopelen > 128)
2411 return (DNS_R_OPTERR);
2412 inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
2413 break;
2414 default:
2415 return (DNS_R_OPTERR);
2416 }
2417
2418 ADD_STRING(target, ": ");
2419 ADD_STRING(target, addr_text);
2420 snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
2421 ADD_STRING(target, addr_text);
2422 return (ISC_R_SUCCESS);
2423 }
2424
2425 static const char *
ede_info_code2str(uint16_t info_code)2426 ede_info_code2str(uint16_t info_code)
2427 {
2428 if (info_code > 49151)
2429 return "Private Use";
2430
2431 switch (info_code) {
2432 case 0:
2433 return "Other Error";
2434 case 1:
2435 return "Unsupported DNSKEY Algorithm";
2436 case 2:
2437 return "Unsupported DS Digest Type";
2438 case 3:
2439 return "Stale Answer";
2440 case 4:
2441 return "Forged Answer";
2442 case 5:
2443 return "DNSSEC Indeterminate";
2444 case 6:
2445 return "DNSSEC Bogus";
2446 case 7:
2447 return "Signature Expired";
2448 case 8:
2449 return "Signature Not Yet Valid";
2450 case 9:
2451 return "DNSKEY Missing";
2452 case 10:
2453 return "RRSIGs Missing";
2454 case 11:
2455 return "No Zone Key Bit Set";
2456 case 12:
2457 return "NSEC Missing";
2458 case 13:
2459 return "Cached Error";
2460 case 14:
2461 return "Not Ready";
2462 case 15:
2463 return "Blocked";
2464 case 16:
2465 return "Censored";
2466 case 17:
2467 return "Filtered";
2468 case 18:
2469 return "Prohibited";
2470 case 19:
2471 return "Stale NXDomain Answer";
2472 case 20:
2473 return "Not Authoritative";
2474 case 21:
2475 return "Not Supported";
2476 case 22:
2477 return "No Reachable Authority";
2478 case 23:
2479 return "Network Error";
2480 case 24:
2481 return "Invalid Data";
2482 default:
2483 return "Unassigned";
2484 }
2485 }
2486
2487 static const char *
zoneversion_zone(const char * zone,int labelcount)2488 zoneversion_zone(const char *zone, int labelcount)
2489 {
2490 size_t pos;
2491
2492 if (zone == NULL || labelcount == 0)
2493 return ".";
2494
2495 pos = strlen(zone);
2496 if (pos == 0)
2497 return ".";
2498
2499 pos--; /* go to last char in string */
2500 if (zone[pos] == '.')
2501 pos--; /* the labelcount does not count the empty root label */
2502
2503 for (; pos > 0; pos--) {
2504 if (zone[pos] == '.') {
2505 labelcount--;
2506
2507 if (labelcount == 0) {
2508 pos++;
2509 break;
2510 }
2511 }
2512 }
2513
2514 return (zone + pos);
2515 }
2516
2517 isc_result_t
dns_message_pseudosectiontotext(dns_message_t * msg,dns_pseudosection_t section,const dns_master_style_t * style,dns_messagetextflag_t flags,const char * textname,isc_buffer_t * target)2518 dns_message_pseudosectiontotext(dns_message_t *msg,
2519 dns_pseudosection_t section,
2520 const dns_master_style_t *style,
2521 dns_messagetextflag_t flags,
2522 const char *textname,
2523 isc_buffer_t *target)
2524 {
2525 dns_rdataset_t *ps = NULL;
2526 dns_name_t *name = NULL;
2527 isc_result_t result;
2528 char buf[sizeof("1234567890")];
2529 uint32_t mbz;
2530 dns_rdata_t rdata;
2531 isc_buffer_t optbuf;
2532 uint16_t optcode, optlen;
2533 unsigned char *optdata;
2534
2535 REQUIRE(target != NULL);
2536 REQUIRE(VALID_PSEUDOSECTION(section));
2537
2538 switch (section) {
2539 case DNS_PSEUDOSECTION_OPT:
2540 ps = dns_message_getopt(msg);
2541 if (ps == NULL)
2542 return (ISC_R_SUCCESS);
2543 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2544 ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
2545 ADD_STRING(target, "; EDNS: version: ");
2546 snprintf(buf, sizeof(buf), "%u",
2547 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
2548 ADD_STRING(target, buf);
2549 ADD_STRING(target, ", flags:");
2550 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
2551 ADD_STRING(target, " do");
2552 mbz = ps->ttl & 0xffff;
2553 mbz &= ~DNS_MESSAGEEXTFLAG_DO; /* Known Flags. */
2554 if (mbz != 0) {
2555 ADD_STRING(target, "; MBZ: ");
2556 snprintf(buf, sizeof(buf), "0x%.4x", mbz);
2557 ADD_STRING(target, buf);
2558 ADD_STRING(target, ", udp: ");
2559 } else
2560 ADD_STRING(target, "; udp: ");
2561 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
2562 ADD_STRING(target, buf);
2563
2564 result = dns_rdataset_first(ps);
2565 if (result != ISC_R_SUCCESS)
2566 return (ISC_R_SUCCESS);
2567
2568 /*
2569 * Print EDNS info, if any.
2570 *
2571 * WARNING: The option contents may be malformed as
2572 * dig +ednsopt=value:<content> does not validity
2573 * checking.
2574 */
2575 dns_rdata_init(&rdata);
2576 dns_rdataset_current(ps, &rdata);
2577
2578 isc_buffer_init(&optbuf, rdata.data, rdata.length);
2579 isc_buffer_add(&optbuf, rdata.length);
2580 while (isc_buffer_remaininglength(&optbuf) != 0) {
2581 INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
2582 optcode = isc_buffer_getuint16(&optbuf);
2583 optlen = isc_buffer_getuint16(&optbuf);
2584 INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
2585
2586 if (optcode == DNS_OPT_NSID) {
2587 ADD_STRING(target, "; NSID");
2588 } else if (optcode == DNS_OPT_COOKIE) {
2589 ADD_STRING(target, "; COOKIE");
2590 } else if (optcode == DNS_OPT_CLIENT_SUBNET) {
2591 isc_buffer_t ecsbuf;
2592
2593 ADD_STRING(target, "; CLIENT-SUBNET");
2594 isc_buffer_init(&ecsbuf,
2595 isc_buffer_current(&optbuf),
2596 optlen);
2597 isc_buffer_add(&ecsbuf, optlen);
2598 result = render_ecs(&ecsbuf, target);
2599 if (result == ISC_R_NOSPACE)
2600 return (result);
2601 if (result == ISC_R_SUCCESS) {
2602 isc_buffer_forward(&optbuf, optlen);
2603 ADD_STRING(target, "\n");
2604 continue;
2605 }
2606 } else if (optcode == DNS_OPT_EXPIRE) {
2607 if (optlen == 4) {
2608 uint32_t secs;
2609 secs = isc_buffer_getuint32(&optbuf);
2610 ADD_STRING(target, "; EXPIRE: ");
2611 snprintf(buf, sizeof(buf), "%u", secs);
2612 ADD_STRING(target, buf);
2613 ADD_STRING(target, " (");
2614 result = dns_ttl_totext(secs,
2615 1,
2616 target);
2617 if (result != ISC_R_SUCCESS)
2618 return (result);
2619 ADD_STRING(target, ")\n");
2620 continue;
2621 }
2622 ADD_STRING(target, "; EXPIRE");
2623 } else if (optcode == DNS_OPT_PAD) {
2624 ADD_STRING(target, "; PAD");
2625 } else if (optcode == DNS_OPT_KEY_TAG) {
2626 ADD_STRING(target, "; KEY-TAG");
2627 if (optlen > 0U && (optlen % 2U) == 0U) {
2628 const char *sep = ": ";
2629 uint16_t id;
2630 while (optlen > 0U) {
2631 id = isc_buffer_getuint16(&optbuf);
2632 snprintf(buf, sizeof(buf), "%s%u",
2633 sep, id);
2634 ADD_STRING(target, buf);
2635 sep = ", ";
2636 optlen -= 2;
2637 }
2638 ADD_STRING(target, "\n");
2639 continue;
2640 }
2641 } else if (optcode == DNS_OPT_EDE) {
2642 uint16_t info_code;
2643 ADD_STRING(target, "; EDE");
2644 if (optlen >= 2) {
2645 info_code =
2646 isc_buffer_getuint16(&optbuf);
2647 optlen -= 2;
2648 snprintf(buf, sizeof(buf), ": %u (",
2649 info_code);
2650 ADD_STRING(target, buf);
2651 ADD_STRING(target,
2652 ede_info_code2str(info_code));
2653 ADD_STRING(target, ")");
2654 }
2655 } else if (optcode == DNS_OPT_ZONEVERSION) {
2656 int i;
2657
2658 ADD_STRING(target, "; ZONEVERSION: ");
2659 optdata = isc_buffer_current(&optbuf);
2660 for (i = 0; i < optlen; i++) {
2661 snprintf(buf, sizeof(buf), "%02x ",
2662 optdata[i]);
2663 ADD_STRING(target, buf);
2664 }
2665
2666 if (optlen >= 2) {
2667 uint8_t labelcount, type;
2668 const char *zone;
2669
2670 labelcount =
2671 isc_buffer_getuint8(&optbuf);
2672 optlen -= 1;
2673 type = isc_buffer_getuint8(&optbuf);
2674 optlen -= 1;
2675 zone = zoneversion_zone(textname,
2676 labelcount);
2677
2678 if (type == 0 && optlen == 4) {
2679 uint32_t serial;
2680
2681 serial = isc_buffer_getuint32(
2682 &optbuf);
2683 optlen -= 4;
2684 ADD_STRING(target,
2685 "(\"SOA-SERIAL: ");
2686 snprintf(buf, sizeof(buf), "%u",
2687 serial);
2688 ADD_STRING(target, buf);
2689 ADD_STRING(target, " (");
2690 ADD_STRING(target, zone);
2691 ADD_STRING(target, ")");
2692 ADD_STRING(target, "\")");
2693 }
2694 }
2695 } else {
2696 ADD_STRING(target, "; OPT=");
2697 snprintf(buf, sizeof(buf), "%u", optcode);
2698 ADD_STRING(target, buf);
2699 }
2700
2701 if (optlen != 0) {
2702 int i;
2703 ADD_STRING(target, ": ");
2704
2705 optdata = isc_buffer_current(&optbuf);
2706 for (i = 0; i < optlen; i++) {
2707 const char *sep;
2708 switch (optcode) {
2709 case DNS_OPT_COOKIE:
2710 sep = "";
2711 break;
2712 default:
2713 sep = " ";
2714 break;
2715 }
2716 snprintf(buf, sizeof(buf), "%02x%s",
2717 optdata[i], sep);
2718 ADD_STRING(target, buf);
2719 }
2720
2721 isc_buffer_forward(&optbuf, optlen);
2722
2723 if (optcode == DNS_OPT_COOKIE) {
2724 if (msg->sitok)
2725 ADD_STRING(target, " (good)");
2726 if (msg->sitbad)
2727 ADD_STRING(target, " (bad)");
2728 ADD_STRING(target, "\n");
2729 continue;
2730 }
2731
2732 if (optcode == DNS_OPT_CLIENT_SUBNET) {
2733 ADD_STRING(target, "\n");
2734 continue;
2735 }
2736
2737 /*
2738 * For non-SIT options, add a printable
2739 * version
2740 */
2741 ADD_STRING(target, "(\"");
2742 if (isc_buffer_availablelength(target) < optlen)
2743 return (ISC_R_NOSPACE);
2744 for (i = 0; i < optlen; i++) {
2745 if (isprint(optdata[i]))
2746 isc_buffer_putmem(target,
2747 &optdata[i],
2748 1);
2749 else
2750 isc_buffer_putstr(target, ".");
2751 }
2752 ADD_STRING(target, "\")");
2753 }
2754 ADD_STRING(target, "\n");
2755 }
2756 return (ISC_R_SUCCESS);
2757 case DNS_PSEUDOSECTION_TSIG:
2758 ps = dns_message_gettsig(msg, &name);
2759 if (ps == NULL)
2760 return (ISC_R_SUCCESS);
2761 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2762 ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
2763 result = dns_master_rdatasettotext(name, ps, style, target);
2764 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
2765 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2766 ADD_STRING(target, "\n");
2767 return (result);
2768 case DNS_PSEUDOSECTION_SIG0:
2769 ps = dns_message_getsig0(msg, &name);
2770 if (ps == NULL)
2771 return (ISC_R_SUCCESS);
2772 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2773 ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
2774 result = dns_master_rdatasettotext(name, ps, style, target);
2775 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
2776 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2777 ADD_STRING(target, "\n");
2778 return (result);
2779 }
2780 return (ISC_R_UNEXPECTED);
2781 }
2782
2783 isc_result_t
dns_message_buildopt(dns_message_t * message,dns_rdataset_t ** rdatasetp,unsigned int version,uint16_t udpsize,unsigned int flags,dns_ednsopt_t * ednsopts,size_t count)2784 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
2785 unsigned int version, uint16_t udpsize,
2786 unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
2787 {
2788 dns_rdataset_t *rdataset = NULL;
2789 dns_rdatalist_t *rdatalist = NULL;
2790 dns_rdata_t *rdata = NULL;
2791 isc_result_t result;
2792 unsigned int len = 0, i;
2793
2794 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
2795
2796 result = dns_message_gettemprdatalist(message, &rdatalist);
2797 if (result != ISC_R_SUCCESS)
2798 return (result);
2799 result = dns_message_gettemprdata(message, &rdata);
2800 if (result != ISC_R_SUCCESS)
2801 goto cleanup;
2802 result = dns_message_gettemprdataset(message, &rdataset);
2803 if (result != ISC_R_SUCCESS)
2804 goto cleanup;
2805
2806 rdatalist->type = dns_rdatatype_opt;
2807
2808 /*
2809 * Set Maximum UDP buffer size.
2810 */
2811 rdatalist->rdclass = udpsize;
2812
2813 /*
2814 * Set EXTENDED-RCODE and Z to 0.
2815 */
2816 rdatalist->ttl = (version << 16);
2817 rdatalist->ttl |= (flags & 0xffff);
2818
2819 /*
2820 * Set EDNS options if applicable
2821 */
2822 if (count != 0U) {
2823 isc_buffer_t *buf = NULL;
2824 for (i = 0; i < count; i++)
2825 len += ednsopts[i].length + 4;
2826
2827 if (len > 0xffffU) {
2828 result = ISC_R_NOSPACE;
2829 goto cleanup;
2830 }
2831
2832 result = isc_buffer_allocate(&buf, len);
2833 if (result != ISC_R_SUCCESS)
2834 goto cleanup;
2835
2836 for (i = 0; i < count; i++) {
2837 isc_buffer_putuint16(buf, ednsopts[i].code);
2838 isc_buffer_putuint16(buf, ednsopts[i].length);
2839 if (ednsopts[i].length != 0) {
2840 isc_buffer_putmem(buf, ednsopts[i].value,
2841 ednsopts[i].length);
2842 }
2843 }
2844 rdata->data = isc_buffer_base(buf);
2845 rdata->length = len;
2846 dns_message_takebuffer(message, &buf);
2847 } else {
2848 rdata->data = NULL;
2849 rdata->length = 0;
2850 }
2851
2852 rdata->rdclass = rdatalist->rdclass;
2853 rdata->type = rdatalist->type;
2854 rdata->flags = 0;
2855
2856 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
2857 result = dns_rdatalist_tordataset(rdatalist, rdataset);
2858 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2859
2860 *rdatasetp = rdataset;
2861 return (ISC_R_SUCCESS);
2862
2863 cleanup:
2864 if (rdata != NULL)
2865 dns_message_puttemprdata(message, &rdata);
2866 if (rdataset != NULL)
2867 dns_message_puttemprdataset(message, &rdataset);
2868 if (rdatalist != NULL)
2869 dns_message_puttemprdatalist(message, &rdatalist);
2870 return (result);
2871 }
2872