Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / dns / message.c
bloba06eb713647beba0376ed02f5e14ef4f461ad54d
1 /* $NetBSD: message.c,v 1.15 2015/07/08 17:28:58 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id */
22 /*! \file */
24 /***
25 *** Imports
26 ***/
28 #include <config.h>
29 #include <ctype.h>
31 #include <isc/buffer.h>
32 #include <isc/mem.h>
33 #include <isc/print.h>
34 #include <isc/string.h> /* Required for HP/UX (and others?) */
35 #include <isc/util.h>
37 #include <dns/dnssec.h>
38 #include <dns/keyvalues.h>
39 #include <dns/log.h>
40 #include <dns/masterdump.h>
41 #include <dns/message.h>
42 #include <dns/opcode.h>
43 #include <dns/rdata.h>
44 #include <dns/rdatalist.h>
45 #include <dns/rdataset.h>
46 #include <dns/rdatastruct.h>
47 #include <dns/result.h>
48 #include <dns/tsig.h>
49 #include <dns/ttl.h>
50 #include <dns/view.h>
52 #ifdef SKAN_MSG_DEBUG
53 static void
54 hexdump(const char *msg, const char *msg2, void *base, size_t len) {
55 unsigned char *p;
56 unsigned int cnt;
58 p = base;
59 cnt = 0;
61 printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base);
63 while (cnt < len) {
64 if (cnt % 16 == 0)
65 printf("%p: ", p);
66 else if (cnt % 8 == 0)
67 printf(" |");
68 printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
69 p++;
70 cnt++;
72 if (cnt % 16 == 0)
73 printf("\n");
76 if (cnt % 16 != 0)
77 printf("\n");
79 #endif
81 #define DNS_MESSAGE_OPCODE_MASK 0x7800U
82 #define DNS_MESSAGE_OPCODE_SHIFT 11
83 #define DNS_MESSAGE_RCODE_MASK 0x000fU
84 #define DNS_MESSAGE_FLAG_MASK 0x8ff0U
85 #define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U
86 #define DNS_MESSAGE_EDNSRCODE_SHIFT 24
87 #define DNS_MESSAGE_EDNSVERSION_MASK 0x00ff0000U
88 #define DNS_MESSAGE_EDNSVERSION_SHIFT 16
90 #define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \
91 && ((s) < DNS_SECTION_MAX))
92 #define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \
93 && ((s) < DNS_SECTION_MAX))
94 #define ADD_STRING(b, s) {if (strlen(s) >= \
95 isc_buffer_availablelength(b)) \
96 return(ISC_R_NOSPACE); else \
97 isc_buffer_putstr(b, s);}
98 #define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \
99 && ((s) < DNS_PSEUDOSECTION_MAX))
101 #define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
104 * This is the size of each individual scratchpad buffer, and the numbers
105 * of various block allocations used within the server.
106 * XXXMLG These should come from a config setting.
108 #define SCRATCHPAD_SIZE 512
109 #define NAME_COUNT 8
110 #define OFFSET_COUNT 4
111 #define RDATA_COUNT 8
112 #define RDATALIST_COUNT 8
113 #define RDATASET_COUNT RDATALIST_COUNT
116 * Text representation of the different items, for message_totext
117 * functions.
119 static const char *sectiontext[] = {
120 "QUESTION",
121 "ANSWER",
122 "AUTHORITY",
123 "ADDITIONAL"
126 static const char *updsectiontext[] = {
127 "ZONE",
128 "PREREQUISITE",
129 "UPDATE",
130 "ADDITIONAL"
133 static const char *opcodetext[] = {
134 "QUERY",
135 "IQUERY",
136 "STATUS",
137 "RESERVED3",
138 "NOTIFY",
139 "UPDATE",
140 "RESERVED6",
141 "RESERVED7",
142 "RESERVED8",
143 "RESERVED9",
144 "RESERVED10",
145 "RESERVED11",
146 "RESERVED12",
147 "RESERVED13",
148 "RESERVED14",
149 "RESERVED15"
152 static const char *rcodetext[] = {
153 "NOERROR",
154 "FORMERR",
155 "SERVFAIL",
156 "NXDOMAIN",
157 "NOTIMP",
158 "REFUSED",
159 "YXDOMAIN",
160 "YXRRSET",
161 "NXRRSET",
162 "NOTAUTH",
163 "NOTZONE",
164 "RESERVED11",
165 "RESERVED12",
166 "RESERVED13",
167 "RESERVED14",
168 "RESERVED15",
169 "BADVERS"
174 * "helper" type, which consists of a block of some type, and is linkable.
175 * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
176 * size, or the allocated elements will not be aligned correctly.
178 struct dns_msgblock {
179 unsigned int count;
180 unsigned int remaining;
181 ISC_LINK(dns_msgblock_t) link;
182 }; /* dynamically sized */
184 static inline dns_msgblock_t *
185 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
187 #define msgblock_get(block, type) \
188 ((type *)msgblock_internalget(block, sizeof(type)))
190 static inline void *
191 msgblock_internalget(dns_msgblock_t *, unsigned int);
193 static inline void
194 msgblock_reset(dns_msgblock_t *);
196 static inline void
197 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
200 * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory
201 * is free, return NULL.
203 static inline dns_msgblock_t *
204 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
205 unsigned int count)
207 dns_msgblock_t *block;
208 unsigned int length;
210 length = sizeof(dns_msgblock_t) + (sizeof_type * count);
212 block = isc_mem_get(mctx, length);
213 if (block == NULL)
214 return (NULL);
216 block->count = count;
217 block->remaining = count;
219 ISC_LINK_INIT(block, link);
221 return (block);
225 * Return an element from the msgblock. If no more are available, return
226 * NULL.
228 static inline void *
229 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
230 void *ptr;
232 if (block == NULL || block->remaining == 0)
233 return (NULL);
235 block->remaining--;
237 ptr = (((unsigned char *)block)
238 + sizeof(dns_msgblock_t)
239 + (sizeof_type * block->remaining));
241 return (ptr);
244 static inline void
245 msgblock_reset(dns_msgblock_t *block) {
246 block->remaining = block->count;
250 * Release memory associated with a message block.
252 static inline void
253 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
255 unsigned int length;
257 length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
259 isc_mem_put(mctx, block, length);
263 * Allocate a new dynamic buffer, and attach it to this message as the
264 * "current" buffer. (which is always the last on the list, for our
265 * uses)
267 static inline isc_result_t
268 newbuffer(dns_message_t *msg, unsigned int size) {
269 isc_result_t result;
270 isc_buffer_t *dynbuf;
272 dynbuf = NULL;
273 result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
274 if (result != ISC_R_SUCCESS)
275 return (ISC_R_NOMEMORY);
277 ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
278 return (ISC_R_SUCCESS);
281 static inline isc_buffer_t *
282 currentbuffer(dns_message_t *msg) {
283 isc_buffer_t *dynbuf;
285 dynbuf = ISC_LIST_TAIL(msg->scratchpad);
286 INSIST(dynbuf != NULL);
288 return (dynbuf);
291 static inline void
292 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
293 ISC_LIST_PREPEND(msg->freerdata, rdata, link);
296 static inline dns_rdata_t *
297 newrdata(dns_message_t *msg) {
298 dns_msgblock_t *msgblock;
299 dns_rdata_t *rdata;
301 rdata = ISC_LIST_HEAD(msg->freerdata);
302 if (rdata != NULL) {
303 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
304 return (rdata);
307 msgblock = ISC_LIST_TAIL(msg->rdatas);
308 rdata = msgblock_get(msgblock, dns_rdata_t);
309 if (rdata == NULL) {
310 msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
311 RDATA_COUNT);
312 if (msgblock == NULL)
313 return (NULL);
315 ISC_LIST_APPEND(msg->rdatas, msgblock, link);
317 rdata = msgblock_get(msgblock, dns_rdata_t);
320 dns_rdata_init(rdata);
321 return (rdata);
324 static inline void
325 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
326 ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
329 static inline dns_rdatalist_t *
330 newrdatalist(dns_message_t *msg) {
331 dns_msgblock_t *msgblock;
332 dns_rdatalist_t *rdatalist;
334 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
335 if (rdatalist != NULL) {
336 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
337 return (rdatalist);
340 msgblock = ISC_LIST_TAIL(msg->rdatalists);
341 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
342 if (rdatalist == NULL) {
343 msgblock = msgblock_allocate(msg->mctx,
344 sizeof(dns_rdatalist_t),
345 RDATALIST_COUNT);
346 if (msgblock == NULL)
347 return (NULL);
349 ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
351 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
354 return (rdatalist);
357 static inline dns_offsets_t *
358 newoffsets(dns_message_t *msg) {
359 dns_msgblock_t *msgblock;
360 dns_offsets_t *offsets;
362 msgblock = ISC_LIST_TAIL(msg->offsets);
363 offsets = msgblock_get(msgblock, dns_offsets_t);
364 if (offsets == NULL) {
365 msgblock = msgblock_allocate(msg->mctx,
366 sizeof(dns_offsets_t),
367 OFFSET_COUNT);
368 if (msgblock == NULL)
369 return (NULL);
371 ISC_LIST_APPEND(msg->offsets, msgblock, link);
373 offsets = msgblock_get(msgblock, dns_offsets_t);
376 return (offsets);
379 static inline void
380 msginitheader(dns_message_t *m) {
381 m->id = 0;
382 m->flags = 0;
383 m->rcode = 0;
384 m->opcode = 0;
385 m->rdclass = 0;
388 static inline void
389 msginitprivate(dns_message_t *m) {
390 unsigned int i;
392 for (i = 0; i < DNS_SECTION_MAX; i++) {
393 m->cursors[i] = NULL;
394 m->counts[i] = 0;
396 m->opt = NULL;
397 m->sig0 = NULL;
398 m->sig0name = NULL;
399 m->tsig = NULL;
400 m->tsigname = NULL;
401 m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */
402 m->opt_reserved = 0;
403 m->sig_reserved = 0;
404 m->reserved = 0;
405 m->buffer = NULL;
408 static inline void
409 msginittsig(dns_message_t *m) {
410 m->tsigstatus = dns_rcode_noerror;
411 m->querytsigstatus = dns_rcode_noerror;
412 m->tsigkey = NULL;
413 m->tsigctx = NULL;
414 m->sigstart = -1;
415 m->sig0key = NULL;
416 m->sig0status = dns_rcode_noerror;
417 m->timeadjust = 0;
421 * Init elements to default state. Used both when allocating a new element
422 * and when resetting one.
424 static inline void
425 msginit(dns_message_t *m) {
426 msginitheader(m);
427 msginitprivate(m);
428 msginittsig(m);
429 m->header_ok = 0;
430 m->question_ok = 0;
431 m->tcp_continuation = 0;
432 m->verified_sig = 0;
433 m->verify_attempted = 0;
434 m->order = NULL;
435 m->order_arg = NULL;
436 m->query.base = NULL;
437 m->query.length = 0;
438 m->free_query = 0;
439 m->saved.base = NULL;
440 m->saved.length = 0;
441 m->free_saved = 0;
442 m->sitok = 0;
443 m->sitbad = 0;
444 m->querytsig = NULL;
447 static inline void
448 msgresetnames(dns_message_t *msg, unsigned int first_section) {
449 unsigned int i;
450 dns_name_t *name, *next_name;
451 dns_rdataset_t *rds, *next_rds;
454 * Clean up name lists by calling the rdataset disassociate function.
456 for (i = first_section; i < DNS_SECTION_MAX; i++) {
457 name = ISC_LIST_HEAD(msg->sections[i]);
458 while (name != NULL) {
459 next_name = ISC_LIST_NEXT(name, link);
460 ISC_LIST_UNLINK(msg->sections[i], name, link);
462 rds = ISC_LIST_HEAD(name->list);
463 while (rds != NULL) {
464 next_rds = ISC_LIST_NEXT(rds, link);
465 ISC_LIST_UNLINK(name->list, rds, link);
467 INSIST(dns_rdataset_isassociated(rds));
468 dns_rdataset_disassociate(rds);
469 isc_mempool_put(msg->rdspool, rds);
470 rds = next_rds;
472 if (dns_name_dynamic(name))
473 dns_name_free(name, msg->mctx);
474 isc_mempool_put(msg->namepool, name);
475 name = next_name;
480 static void
481 msgresetopt(dns_message_t *msg)
483 if (msg->opt != NULL) {
484 if (msg->opt_reserved > 0) {
485 dns_message_renderrelease(msg, msg->opt_reserved);
486 msg->opt_reserved = 0;
488 INSIST(dns_rdataset_isassociated(msg->opt));
489 dns_rdataset_disassociate(msg->opt);
490 isc_mempool_put(msg->rdspool, msg->opt);
491 msg->opt = NULL;
492 msg->sitok = 0;
493 msg->sitbad = 0;
497 static void
498 msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
499 if (msg->sig_reserved > 0) {
500 dns_message_renderrelease(msg, msg->sig_reserved);
501 msg->sig_reserved = 0;
503 if (msg->tsig != NULL) {
504 INSIST(dns_rdataset_isassociated(msg->tsig));
505 INSIST(msg->namepool != NULL);
506 if (replying) {
507 INSIST(msg->querytsig == NULL);
508 msg->querytsig = msg->tsig;
509 } else {
510 dns_rdataset_disassociate(msg->tsig);
511 isc_mempool_put(msg->rdspool, msg->tsig);
512 if (msg->querytsig != NULL) {
513 dns_rdataset_disassociate(msg->querytsig);
514 isc_mempool_put(msg->rdspool, msg->querytsig);
517 if (dns_name_dynamic(msg->tsigname))
518 dns_name_free(msg->tsigname, msg->mctx);
519 isc_mempool_put(msg->namepool, msg->tsigname);
520 msg->tsig = NULL;
521 msg->tsigname = NULL;
522 } else if (msg->querytsig != NULL && !replying) {
523 dns_rdataset_disassociate(msg->querytsig);
524 isc_mempool_put(msg->rdspool, msg->querytsig);
525 msg->querytsig = NULL;
527 if (msg->sig0 != NULL) {
528 INSIST(dns_rdataset_isassociated(msg->sig0));
529 dns_rdataset_disassociate(msg->sig0);
530 isc_mempool_put(msg->rdspool, msg->sig0);
531 if (msg->sig0name != NULL) {
532 if (dns_name_dynamic(msg->sig0name))
533 dns_name_free(msg->sig0name, msg->mctx);
534 isc_mempool_put(msg->namepool, msg->sig0name);
536 msg->sig0 = NULL;
537 msg->sig0name = NULL;
542 * Free all but one (or everything) for this message. This is used by
543 * both dns_message_reset() and dns_message_destroy().
545 static void
546 msgreset(dns_message_t *msg, isc_boolean_t everything) {
547 dns_msgblock_t *msgblock, *next_msgblock;
548 isc_buffer_t *dynbuf, *next_dynbuf;
549 dns_rdata_t *rdata;
550 dns_rdatalist_t *rdatalist;
552 msgresetnames(msg, 0);
553 msgresetopt(msg);
554 msgresetsigs(msg, ISC_FALSE);
557 * Clean up linked lists.
561 * Run through the free lists, and just unlink anything found there.
562 * The memory isn't lost since these are part of message blocks we
563 * have allocated.
565 rdata = ISC_LIST_HEAD(msg->freerdata);
566 while (rdata != NULL) {
567 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
568 rdata = ISC_LIST_HEAD(msg->freerdata);
570 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
571 while (rdatalist != NULL) {
572 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
573 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
576 dynbuf = ISC_LIST_HEAD(msg->scratchpad);
577 INSIST(dynbuf != NULL);
578 if (!everything) {
579 isc_buffer_clear(dynbuf);
580 dynbuf = ISC_LIST_NEXT(dynbuf, link);
582 while (dynbuf != NULL) {
583 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
584 ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
585 isc_buffer_free(&dynbuf);
586 dynbuf = next_dynbuf;
589 msgblock = ISC_LIST_HEAD(msg->rdatas);
590 if (!everything && msgblock != NULL) {
591 msgblock_reset(msgblock);
592 msgblock = ISC_LIST_NEXT(msgblock, link);
594 while (msgblock != NULL) {
595 next_msgblock = ISC_LIST_NEXT(msgblock, link);
596 ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
597 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
598 msgblock = next_msgblock;
602 * rdatalists could be empty.
605 msgblock = ISC_LIST_HEAD(msg->rdatalists);
606 if (!everything && msgblock != NULL) {
607 msgblock_reset(msgblock);
608 msgblock = ISC_LIST_NEXT(msgblock, link);
610 while (msgblock != NULL) {
611 next_msgblock = ISC_LIST_NEXT(msgblock, link);
612 ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
613 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
614 msgblock = next_msgblock;
617 msgblock = ISC_LIST_HEAD(msg->offsets);
618 if (!everything && msgblock != NULL) {
619 msgblock_reset(msgblock);
620 msgblock = ISC_LIST_NEXT(msgblock, link);
622 while (msgblock != NULL) {
623 next_msgblock = ISC_LIST_NEXT(msgblock, link);
624 ISC_LIST_UNLINK(msg->offsets, msgblock, link);
625 msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
626 msgblock = next_msgblock;
629 if (msg->tsigkey != NULL) {
630 dns_tsigkey_detach(&msg->tsigkey);
631 msg->tsigkey = NULL;
634 if (msg->tsigctx != NULL)
635 dst_context_destroy(&msg->tsigctx);
637 if (msg->query.base != NULL) {
638 if (msg->free_query != 0)
639 isc_mem_put(msg->mctx, msg->query.base,
640 msg->query.length);
641 msg->query.base = NULL;
642 msg->query.length = 0;
645 if (msg->saved.base != NULL) {
646 if (msg->free_saved != 0)
647 isc_mem_put(msg->mctx, msg->saved.base,
648 msg->saved.length);
649 msg->saved.base = NULL;
650 msg->saved.length = 0;
654 * cleanup the buffer cleanup list
656 dynbuf = ISC_LIST_HEAD(msg->cleanup);
657 while (dynbuf != NULL) {
658 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
659 ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
660 isc_buffer_free(&dynbuf);
661 dynbuf = next_dynbuf;
665 * Set other bits to normal default values.
667 if (!everything)
668 msginit(msg);
670 ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
671 ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
674 static unsigned int
675 spacefortsig(dns_tsigkey_t *key, int otherlen) {
676 isc_region_t r1, r2;
677 unsigned int x;
678 isc_result_t result;
681 * The space required for an TSIG record is:
683 * n1 bytes for the name
684 * 2 bytes for the type
685 * 2 bytes for the class
686 * 4 bytes for the ttl
687 * 2 bytes for the rdlength
688 * n2 bytes for the algorithm name
689 * 6 bytes for the time signed
690 * 2 bytes for the fudge
691 * 2 bytes for the MAC size
692 * x bytes for the MAC
693 * 2 bytes for the original id
694 * 2 bytes for the error
695 * 2 bytes for the other data length
696 * y bytes for the other data (at most)
697 * ---------------------------------
698 * 26 + n1 + n2 + x + y bytes
701 dns_name_toregion(&key->name, &r1);
702 dns_name_toregion(key->algorithm, &r2);
703 if (key->key == NULL)
704 x = 0;
705 else {
706 result = dst_key_sigsize(key->key, &x);
707 if (result != ISC_R_SUCCESS)
708 x = 0;
710 return (26 + r1.length + r2.length + x + otherlen);
713 isc_result_t
714 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
716 dns_message_t *m;
717 isc_result_t result;
718 isc_buffer_t *dynbuf;
719 unsigned int i;
721 REQUIRE(mctx != NULL);
722 REQUIRE(msgp != NULL);
723 REQUIRE(*msgp == NULL);
724 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
725 || intent == DNS_MESSAGE_INTENTRENDER);
727 m = isc_mem_get(mctx, sizeof(dns_message_t));
728 if (m == NULL)
729 return (ISC_R_NOMEMORY);
732 * No allocations until further notice. Just initialize all lists
733 * and other members that are freed in the cleanup phase here.
736 m->magic = DNS_MESSAGE_MAGIC;
737 m->from_to_wire = intent;
738 msginit(m);
740 for (i = 0; i < DNS_SECTION_MAX; i++)
741 ISC_LIST_INIT(m->sections[i]);
743 m->mctx = NULL;
744 isc_mem_attach(mctx, &m->mctx);
746 ISC_LIST_INIT(m->scratchpad);
747 ISC_LIST_INIT(m->cleanup);
748 m->namepool = NULL;
749 m->rdspool = NULL;
750 ISC_LIST_INIT(m->rdatas);
751 ISC_LIST_INIT(m->rdatalists);
752 ISC_LIST_INIT(m->offsets);
753 ISC_LIST_INIT(m->freerdata);
754 ISC_LIST_INIT(m->freerdatalist);
757 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
760 result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
761 if (result != ISC_R_SUCCESS)
762 goto cleanup;
763 isc_mempool_setfreemax(m->namepool, NAME_COUNT);
764 isc_mempool_setname(m->namepool, "msg:names");
766 result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
767 &m->rdspool);
768 if (result != ISC_R_SUCCESS)
769 goto cleanup;
770 isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
771 isc_mempool_setname(m->rdspool, "msg:rdataset");
773 dynbuf = NULL;
774 result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
775 if (result != ISC_R_SUCCESS)
776 goto cleanup;
777 ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
779 m->cctx = NULL;
781 *msgp = m;
782 return (ISC_R_SUCCESS);
785 * Cleanup for error returns.
787 cleanup:
788 dynbuf = ISC_LIST_HEAD(m->scratchpad);
789 if (dynbuf != NULL) {
790 ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
791 isc_buffer_free(&dynbuf);
793 if (m->namepool != NULL)
794 isc_mempool_destroy(&m->namepool);
795 if (m->rdspool != NULL)
796 isc_mempool_destroy(&m->rdspool);
797 m->magic = 0;
798 isc_mem_putanddetach(&mctx, m, sizeof(dns_message_t));
800 return (ISC_R_NOMEMORY);
803 void
804 dns_message_reset(dns_message_t *msg, unsigned int intent) {
805 REQUIRE(DNS_MESSAGE_VALID(msg));
806 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
807 || intent == DNS_MESSAGE_INTENTRENDER);
809 msgreset(msg, ISC_FALSE);
810 msg->from_to_wire = intent;
813 void
814 dns_message_destroy(dns_message_t **msgp) {
815 dns_message_t *msg;
817 REQUIRE(msgp != NULL);
818 REQUIRE(DNS_MESSAGE_VALID(*msgp));
820 msg = *msgp;
821 *msgp = NULL;
823 msgreset(msg, ISC_TRUE);
824 isc_mempool_destroy(&msg->namepool);
825 isc_mempool_destroy(&msg->rdspool);
826 msg->magic = 0;
827 isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
830 static isc_result_t
831 findname(dns_name_t **foundname, dns_name_t *target,
832 dns_namelist_t *section)
834 dns_name_t *curr;
836 for (curr = ISC_LIST_TAIL(*section);
837 curr != NULL;
838 curr = ISC_LIST_PREV(curr, link)) {
839 if (dns_name_equal(curr, target)) {
840 if (foundname != NULL)
841 *foundname = curr;
842 return (ISC_R_SUCCESS);
846 return (ISC_R_NOTFOUND);
849 isc_result_t
850 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
851 dns_rdatatype_t type, dns_rdatatype_t covers,
852 dns_rdataset_t **rdataset)
854 dns_rdataset_t *curr;
856 if (rdataset != NULL) {
857 REQUIRE(*rdataset == NULL);
860 for (curr = ISC_LIST_TAIL(name->list);
861 curr != NULL;
862 curr = ISC_LIST_PREV(curr, link)) {
863 if (curr->rdclass == rdclass &&
864 curr->type == type && curr->covers == covers) {
865 if (rdataset != NULL)
866 *rdataset = curr;
867 return (ISC_R_SUCCESS);
871 return (ISC_R_NOTFOUND);
874 isc_result_t
875 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
876 dns_rdatatype_t covers, dns_rdataset_t **rdataset)
878 dns_rdataset_t *curr;
880 REQUIRE(name != NULL);
881 if (rdataset != NULL) {
882 REQUIRE(*rdataset == NULL);
885 for (curr = ISC_LIST_TAIL(name->list);
886 curr != NULL;
887 curr = ISC_LIST_PREV(curr, link)) {
888 if (curr->type == type && curr->covers == covers) {
889 if (rdataset != NULL)
890 *rdataset = curr;
891 return (ISC_R_SUCCESS);
895 return (ISC_R_NOTFOUND);
899 * Read a name from buffer "source".
901 static isc_result_t
902 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
903 dns_decompress_t *dctx)
905 isc_buffer_t *scratch;
906 isc_result_t result;
907 unsigned int tries;
909 scratch = currentbuffer(msg);
912 * First try: use current buffer.
913 * Second try: allocate a new buffer and use that.
915 tries = 0;
916 while (tries < 2) {
917 result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
918 scratch);
920 if (result == ISC_R_NOSPACE) {
921 tries++;
923 result = newbuffer(msg, SCRATCHPAD_SIZE);
924 if (result != ISC_R_SUCCESS)
925 return (result);
927 scratch = currentbuffer(msg);
928 dns_name_reset(name);
929 } else {
930 return (result);
934 INSIST(0); /* Cannot get here... */
935 return (ISC_R_UNEXPECTED);
938 static isc_result_t
939 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
940 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
941 unsigned int rdatalen, dns_rdata_t *rdata)
943 isc_buffer_t *scratch;
944 isc_result_t result;
945 unsigned int tries;
946 unsigned int trysize;
948 scratch = currentbuffer(msg);
950 isc_buffer_setactive(source, rdatalen);
953 * First try: use current buffer.
954 * Second try: allocate a new buffer of size
955 * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
956 * (the data will fit if it was not more than 50% compressed)
957 * Subsequent tries: double buffer size on each try.
959 tries = 0;
960 trysize = 0;
961 /* XXX possibly change this to a while (tries < 2) loop */
962 for (;;) {
963 result = dns_rdata_fromwire(rdata, rdclass, rdtype,
964 source, dctx, 0,
965 scratch);
967 if (result == ISC_R_NOSPACE) {
968 if (tries == 0) {
969 trysize = 2 * rdatalen;
970 if (trysize < SCRATCHPAD_SIZE)
971 trysize = SCRATCHPAD_SIZE;
972 } else {
973 INSIST(trysize != 0);
974 if (trysize >= 65535)
975 return (ISC_R_NOSPACE);
976 /* XXX DNS_R_RRTOOLONG? */
977 trysize *= 2;
979 tries++;
980 result = newbuffer(msg, trysize);
981 if (result != ISC_R_SUCCESS)
982 return (result);
984 scratch = currentbuffer(msg);
985 } else {
986 return (result);
991 #define DO_FORMERR \
992 do { \
993 if (best_effort) \
994 seen_problem = ISC_TRUE; \
995 else { \
996 result = DNS_R_FORMERR; \
997 goto cleanup; \
999 } while (/*CONSTCOND*/0)
1001 static isc_result_t
1002 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1003 unsigned int options)
1005 isc_region_t r;
1006 unsigned int count;
1007 dns_name_t *name;
1008 dns_name_t *name2;
1009 dns_offsets_t *offsets;
1010 dns_rdataset_t *rdataset;
1011 dns_rdatalist_t *rdatalist;
1012 isc_result_t result;
1013 dns_rdatatype_t rdtype;
1014 dns_rdataclass_t rdclass;
1015 dns_namelist_t *section;
1016 isc_boolean_t free_name;
1017 isc_boolean_t best_effort;
1018 isc_boolean_t seen_problem;
1020 section = &msg->sections[DNS_SECTION_QUESTION];
1022 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1023 seen_problem = ISC_FALSE;
1025 name = NULL;
1026 rdataset = NULL;
1027 rdatalist = NULL;
1029 for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
1030 name = isc_mempool_get(msg->namepool);
1031 if (name == NULL)
1032 return (ISC_R_NOMEMORY);
1033 free_name = ISC_TRUE;
1035 offsets = newoffsets(msg);
1036 if (offsets == NULL) {
1037 result = ISC_R_NOMEMORY;
1038 goto cleanup;
1040 dns_name_init(name, *offsets);
1043 * Parse the name out of this packet.
1045 isc_buffer_remainingregion(source, &r);
1046 isc_buffer_setactive(source, r.length);
1047 result = getname(name, source, msg, dctx);
1048 if (result != ISC_R_SUCCESS)
1049 goto cleanup;
1052 * Run through the section, looking to see if this name
1053 * is already there. If it is found, put back the allocated
1054 * name since we no longer need it, and set our name pointer
1055 * to point to the name we found.
1057 result = findname(&name2, name, section);
1060 * If it is the first name in the section, accept it.
1062 * If it is not, but is not the same as the name already
1063 * in the question section, append to the section. Note that
1064 * here in the question section this is illegal, so return
1065 * FORMERR. In the future, check the opcode to see if
1066 * this should be legal or not. In either case we no longer
1067 * need this name pointer.
1069 if (result != ISC_R_SUCCESS) {
1070 if (!ISC_LIST_EMPTY(*section))
1071 DO_FORMERR;
1072 ISC_LIST_APPEND(*section, name, link);
1073 free_name = ISC_FALSE;
1074 } else {
1075 isc_mempool_put(msg->namepool, name);
1076 name = name2;
1077 name2 = NULL;
1078 free_name = ISC_FALSE;
1082 * Get type and class.
1084 isc_buffer_remainingregion(source, &r);
1085 if (r.length < 4) {
1086 result = ISC_R_UNEXPECTEDEND;
1087 goto cleanup;
1089 rdtype = isc_buffer_getuint16(source);
1090 rdclass = isc_buffer_getuint16(source);
1093 * If this class is different than the one we already read,
1094 * this is an error.
1096 if (msg->state == DNS_SECTION_ANY) {
1097 msg->state = DNS_SECTION_QUESTION;
1098 msg->rdclass = rdclass;
1099 } else if (msg->rdclass != rdclass)
1100 DO_FORMERR;
1103 * Can't ask the same question twice.
1105 result = dns_message_find(name, rdclass, rdtype, 0, NULL);
1106 if (result == ISC_R_SUCCESS)
1107 DO_FORMERR;
1110 * Allocate a new rdatalist.
1112 rdatalist = newrdatalist(msg);
1113 if (rdatalist == NULL) {
1114 result = ISC_R_NOMEMORY;
1115 goto cleanup;
1117 rdataset = isc_mempool_get(msg->rdspool);
1118 if (rdataset == NULL) {
1119 result = ISC_R_NOMEMORY;
1120 goto cleanup;
1124 * Convert rdatalist to rdataset, and attach the latter to
1125 * the name.
1127 rdatalist->type = rdtype;
1128 rdatalist->covers = 0;
1129 rdatalist->rdclass = rdclass;
1130 rdatalist->ttl = 0;
1131 ISC_LIST_INIT(rdatalist->rdata);
1133 dns_rdataset_init(rdataset);
1134 result = dns_rdatalist_tordataset(rdatalist, rdataset);
1135 if (result != ISC_R_SUCCESS)
1136 goto cleanup;
1138 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1140 ISC_LIST_APPEND(name->list, rdataset, link);
1141 rdataset = NULL;
1144 if (seen_problem)
1145 return (DNS_R_RECOVERABLE);
1146 return (ISC_R_SUCCESS);
1148 cleanup:
1149 if (rdataset != NULL) {
1150 INSIST(!dns_rdataset_isassociated(rdataset));
1151 isc_mempool_put(msg->rdspool, rdataset);
1153 #if 0
1154 if (rdatalist != NULL)
1155 isc_mempool_put(msg->rdlpool, rdatalist);
1156 #endif
1157 if (free_name)
1158 isc_mempool_put(msg->namepool, name);
1160 return (result);
1163 static isc_boolean_t
1164 update(dns_section_t section, dns_rdataclass_t rdclass) {
1165 if (section == DNS_SECTION_PREREQUISITE)
1166 return (ISC_TF(rdclass == dns_rdataclass_any ||
1167 rdclass == dns_rdataclass_none));
1168 if (section == DNS_SECTION_UPDATE)
1169 return (ISC_TF(rdclass == dns_rdataclass_any));
1170 return (ISC_FALSE);
1173 static isc_result_t
1174 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1175 dns_section_t sectionid, unsigned int options)
1177 isc_region_t r;
1178 unsigned int count, rdatalen;
1179 dns_name_t *name;
1180 dns_name_t *name2;
1181 dns_offsets_t *offsets;
1182 dns_rdataset_t *rdataset = NULL;
1183 dns_rdatalist_t *rdatalist;
1184 isc_result_t result;
1185 dns_rdatatype_t rdtype, covers;
1186 dns_rdataclass_t rdclass;
1187 dns_rdata_t *rdata;
1188 dns_ttl_t ttl;
1189 dns_namelist_t *section;
1190 isc_boolean_t free_name, free_rdataset;
1191 isc_boolean_t preserve_order, best_effort, seen_problem;
1192 isc_boolean_t issigzero;
1194 preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
1195 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1196 seen_problem = ISC_FALSE;
1198 for (count = 0; count < msg->counts[sectionid]; count++) {
1199 int recstart = source->current;
1200 isc_boolean_t skip_name_search, skip_type_search;
1202 section = &msg->sections[sectionid];
1204 skip_name_search = ISC_FALSE;
1205 skip_type_search = ISC_FALSE;
1206 free_rdataset = ISC_FALSE;
1208 name = isc_mempool_get(msg->namepool);
1209 if (name == NULL)
1210 return (ISC_R_NOMEMORY);
1211 free_name = ISC_TRUE;
1213 offsets = newoffsets(msg);
1214 if (offsets == NULL) {
1215 result = ISC_R_NOMEMORY;
1216 goto cleanup;
1218 dns_name_init(name, *offsets);
1221 * Parse the name out of this packet.
1223 isc_buffer_remainingregion(source, &r);
1224 isc_buffer_setactive(source, r.length);
1225 result = getname(name, source, msg, dctx);
1226 if (result != ISC_R_SUCCESS)
1227 goto cleanup;
1230 * Get type, class, ttl, and rdatalen. Verify that at least
1231 * rdatalen bytes remain. (Some of this is deferred to
1232 * later.)
1234 isc_buffer_remainingregion(source, &r);
1235 if (r.length < 2 + 2 + 4 + 2) {
1236 result = ISC_R_UNEXPECTEDEND;
1237 goto cleanup;
1239 rdtype = isc_buffer_getuint16(source);
1240 rdclass = isc_buffer_getuint16(source);
1243 * If there was no question section, we may not yet have
1244 * established a class. Do so now.
1246 if (msg->state == DNS_SECTION_ANY &&
1247 rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
1248 rdtype != dns_rdatatype_tsig && /* class is ANY */
1249 rdtype != dns_rdatatype_tkey) { /* class is undefined */
1250 msg->rdclass = rdclass;
1251 msg->state = DNS_SECTION_QUESTION;
1255 * If this class is different than the one in the question
1256 * section, bail.
1258 if (msg->opcode != dns_opcode_update
1259 && rdtype != dns_rdatatype_tsig
1260 && rdtype != dns_rdatatype_opt
1261 && rdtype != dns_rdatatype_dnskey /* in a TKEY query */
1262 && rdtype != dns_rdatatype_sig /* SIG(0) */
1263 && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1264 && msg->rdclass != dns_rdataclass_any
1265 && msg->rdclass != rdclass)
1266 DO_FORMERR;
1269 * Special type handling for TSIG, OPT, and TKEY.
1271 if (rdtype == dns_rdatatype_tsig) {
1273 * If it is a tsig, verify that it is in the
1274 * additional data section.
1276 if (sectionid != DNS_SECTION_ADDITIONAL ||
1277 rdclass != dns_rdataclass_any ||
1278 count != msg->counts[sectionid] - 1)
1279 DO_FORMERR;
1280 msg->sigstart = recstart;
1281 skip_name_search = ISC_TRUE;
1282 skip_type_search = ISC_TRUE;
1283 } else if (rdtype == dns_rdatatype_opt) {
1285 * The name of an OPT record must be ".", it
1286 * must be in the additional data section, and
1287 * it must be the first OPT we've seen.
1289 if (!dns_name_equal(dns_rootname, name) ||
1290 msg->opt != NULL)
1291 DO_FORMERR;
1292 skip_name_search = ISC_TRUE;
1293 skip_type_search = ISC_TRUE;
1294 } else if (rdtype == dns_rdatatype_tkey) {
1296 * A TKEY must be in the additional section if this
1297 * is a query, and the answer section if this is a
1298 * response. Unless it's a Win2000 client.
1300 * Its class is ignored.
1302 dns_section_t tkeysection;
1304 if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1305 tkeysection = DNS_SECTION_ADDITIONAL;
1306 else
1307 tkeysection = DNS_SECTION_ANSWER;
1308 if (sectionid != tkeysection &&
1309 sectionid != DNS_SECTION_ANSWER)
1310 DO_FORMERR;
1314 * ... now get ttl and rdatalen, and check buffer.
1316 ttl = isc_buffer_getuint32(source);
1317 rdatalen = isc_buffer_getuint16(source);
1318 r.length -= (2 + 2 + 4 + 2);
1319 if (r.length < rdatalen) {
1320 result = ISC_R_UNEXPECTEDEND;
1321 goto cleanup;
1325 * Read the rdata from the wire format. Interpret the
1326 * rdata according to its actual class, even if it had a
1327 * DynDNS meta-class in the packet (unless this is a TSIG).
1328 * Then put the meta-class back into the finished rdata.
1330 rdata = newrdata(msg);
1331 if (rdata == NULL) {
1332 result = ISC_R_NOMEMORY;
1333 goto cleanup;
1335 if (msg->opcode == dns_opcode_update &&
1336 update(sectionid, rdclass)) {
1337 if (rdatalen != 0) {
1338 result = DNS_R_FORMERR;
1339 goto cleanup;
1342 * When the rdata is empty, the data pointer is
1343 * never dereferenced, but it must still be non-NULL.
1344 * Casting 1 rather than "" avoids warnings about
1345 * discarding the const attribute of a string,
1346 * for compilers that would warn about such things.
1348 rdata->data = (unsigned char *)1;
1349 rdata->length = 0;
1350 rdata->rdclass = rdclass;
1351 rdata->type = rdtype;
1352 rdata->flags = DNS_RDATA_UPDATE;
1353 result = ISC_R_SUCCESS;
1354 } else if (rdclass == dns_rdataclass_none &&
1355 msg->opcode == dns_opcode_update &&
1356 sectionid == DNS_SECTION_UPDATE) {
1357 result = getrdata(source, msg, dctx, msg->rdclass,
1358 rdtype, rdatalen, rdata);
1359 } else
1360 result = getrdata(source, msg, dctx, rdclass,
1361 rdtype, rdatalen, rdata);
1362 if (result != ISC_R_SUCCESS)
1363 goto cleanup;
1364 rdata->rdclass = rdclass;
1365 issigzero = ISC_FALSE;
1366 if (rdtype == dns_rdatatype_rrsig &&
1367 rdata->flags == 0) {
1368 covers = dns_rdata_covers(rdata);
1369 if (covers == 0)
1370 DO_FORMERR;
1371 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1372 rdata->flags == 0) {
1373 covers = dns_rdata_covers(rdata);
1374 if (covers == 0) {
1375 if (sectionid != DNS_SECTION_ADDITIONAL ||
1376 count != msg->counts[sectionid] - 1)
1377 DO_FORMERR;
1378 msg->sigstart = recstart;
1379 skip_name_search = ISC_TRUE;
1380 skip_type_search = ISC_TRUE;
1381 issigzero = ISC_TRUE;
1383 } else
1384 covers = 0;
1387 * Check the ownername of NSEC3 records
1389 if (rdtype == dns_rdatatype_nsec3 &&
1390 !dns_rdata_checkowner(name, msg->rdclass, rdtype,
1391 ISC_FALSE)) {
1392 result = DNS_R_BADOWNERNAME;
1393 goto cleanup;
1397 * If we are doing a dynamic update or this is a meta-type,
1398 * don't bother searching for a name, just append this one
1399 * to the end of the message.
1401 if (preserve_order || msg->opcode == dns_opcode_update ||
1402 skip_name_search) {
1403 if (rdtype != dns_rdatatype_opt &&
1404 rdtype != dns_rdatatype_tsig &&
1405 !issigzero)
1407 ISC_LIST_APPEND(*section, name, link);
1408 free_name = ISC_FALSE;
1410 } else {
1412 * Run through the section, looking to see if this name
1413 * is already there. If it is found, put back the
1414 * allocated name since we no longer need it, and set
1415 * our name pointer to point to the name we found.
1417 result = findname(&name2, name, section);
1420 * If it is a new name, append to the section.
1422 if (result == ISC_R_SUCCESS) {
1423 isc_mempool_put(msg->namepool, name);
1424 name = name2;
1425 } else {
1426 ISC_LIST_APPEND(*section, name, link);
1428 free_name = ISC_FALSE;
1432 * Search name for the particular type and class.
1433 * Skip this stage if in update mode or this is a meta-type.
1435 if (preserve_order || msg->opcode == dns_opcode_update ||
1436 skip_type_search)
1437 result = ISC_R_NOTFOUND;
1438 else {
1440 * If this is a type that can only occur in
1441 * the question section, fail.
1443 if (dns_rdatatype_questiononly(rdtype))
1444 DO_FORMERR;
1446 rdataset = NULL;
1447 result = dns_message_find(name, rdclass, rdtype,
1448 covers, &rdataset);
1452 * If we found an rdataset that matches, we need to
1453 * append this rdata to that set. If we did not, we need
1454 * to create a new rdatalist, store the important bits there,
1455 * convert it to an rdataset, and link the latter to the name.
1456 * Yuck. When appending, make certain that the type isn't
1457 * a singleton type, such as SOA or CNAME.
1459 * Note that this check will be bypassed when preserving order,
1460 * the opcode is an update, or the type search is skipped.
1462 if (result == ISC_R_SUCCESS) {
1463 if (dns_rdatatype_issingleton(rdtype)) {
1464 dns_rdata_t *first;
1465 dns_rdatalist_fromrdataset(rdataset,
1466 &rdatalist);
1467 first = ISC_LIST_HEAD(rdatalist->rdata);
1468 INSIST(first != NULL);
1469 if (dns_rdata_compare(rdata, first) != 0)
1470 DO_FORMERR;
1474 if (result == ISC_R_NOTFOUND) {
1475 rdataset = isc_mempool_get(msg->rdspool);
1476 if (rdataset == NULL) {
1477 result = ISC_R_NOMEMORY;
1478 goto cleanup;
1480 free_rdataset = ISC_TRUE;
1482 rdatalist = newrdatalist(msg);
1483 if (rdatalist == NULL) {
1484 result = ISC_R_NOMEMORY;
1485 goto cleanup;
1488 rdatalist->type = rdtype;
1489 rdatalist->covers = covers;
1490 rdatalist->rdclass = rdclass;
1491 rdatalist->ttl = ttl;
1492 ISC_LIST_INIT(rdatalist->rdata);
1494 dns_rdataset_init(rdataset);
1495 RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1496 rdataset)
1497 == ISC_R_SUCCESS);
1499 if (rdtype != dns_rdatatype_opt &&
1500 rdtype != dns_rdatatype_tsig &&
1501 !issigzero)
1503 ISC_LIST_APPEND(name->list, rdataset, link);
1504 free_rdataset = ISC_FALSE;
1509 * Minimize TTLs.
1511 * Section 5.2 of RFC2181 says we should drop
1512 * nonauthoritative rrsets where the TTLs differ, but we
1513 * currently treat them the as if they were authoritative and
1514 * minimize them.
1516 if (ttl != rdataset->ttl) {
1517 rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1518 if (ttl < rdataset->ttl)
1519 rdataset->ttl = ttl;
1522 /* Append this rdata to the rdataset. */
1523 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1524 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1527 * If this is an OPT record, remember it. Also, set
1528 * the extended rcode. Note that msg->opt will only be set
1529 * if best-effort parsing is enabled.
1531 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1532 dns_rcode_t ercode;
1534 msg->opt = rdataset;
1535 rdataset = NULL;
1536 free_rdataset = ISC_FALSE;
1537 ercode = (dns_rcode_t)
1538 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1539 >> 20);
1540 msg->rcode |= ercode;
1541 isc_mempool_put(msg->namepool, name);
1542 free_name = ISC_FALSE;
1546 * If this is an SIG(0) or TSIG record, remember it. Note
1547 * that msg->sig0 or msg->tsig will only be set if best-effort
1548 * parsing is enabled.
1550 if (issigzero && msg->sig0 == NULL) {
1551 msg->sig0 = rdataset;
1552 msg->sig0name = name;
1553 rdataset = NULL;
1554 free_rdataset = ISC_FALSE;
1555 free_name = ISC_FALSE;
1556 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1557 msg->tsig = rdataset;
1558 msg->tsigname = name;
1559 /* Windows doesn't like TSIG names to be compressed. */
1560 msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1561 rdataset = NULL;
1562 free_rdataset = ISC_FALSE;
1563 free_name = ISC_FALSE;
1566 if (seen_problem) {
1567 if (free_name)
1568 isc_mempool_put(msg->namepool, name);
1569 if (free_rdataset)
1570 isc_mempool_put(msg->rdspool, rdataset);
1571 free_name = free_rdataset = ISC_FALSE;
1573 INSIST(free_name == ISC_FALSE);
1574 INSIST(free_rdataset == ISC_FALSE);
1577 if (seen_problem)
1578 return (DNS_R_RECOVERABLE);
1579 return (ISC_R_SUCCESS);
1581 cleanup:
1582 if (free_name)
1583 isc_mempool_put(msg->namepool, name);
1584 if (free_rdataset)
1585 isc_mempool_put(msg->rdspool, rdataset);
1587 return (result);
1590 isc_result_t
1591 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1592 unsigned int options)
1594 isc_region_t r;
1595 dns_decompress_t dctx;
1596 isc_result_t ret;
1597 isc_uint16_t tmpflags;
1598 isc_buffer_t origsource;
1599 isc_boolean_t seen_problem;
1600 isc_boolean_t ignore_tc;
1602 REQUIRE(DNS_MESSAGE_VALID(msg));
1603 REQUIRE(source != NULL);
1604 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1606 seen_problem = ISC_FALSE;
1607 ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1609 origsource = *source;
1611 msg->header_ok = 0;
1612 msg->question_ok = 0;
1614 isc_buffer_remainingregion(source, &r);
1615 if (r.length < DNS_MESSAGE_HEADERLEN)
1616 return (ISC_R_UNEXPECTEDEND);
1618 msg->id = isc_buffer_getuint16(source);
1619 tmpflags = isc_buffer_getuint16(source);
1620 msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1621 >> DNS_MESSAGE_OPCODE_SHIFT);
1622 msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1623 msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1624 msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1625 msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1626 msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1627 msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1629 msg->header_ok = 1;
1632 * -1 means no EDNS.
1634 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1636 dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1638 ret = getquestions(source, msg, &dctx, options);
1639 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1640 goto truncated;
1641 if (ret == DNS_R_RECOVERABLE) {
1642 seen_problem = ISC_TRUE;
1643 ret = ISC_R_SUCCESS;
1645 if (ret != ISC_R_SUCCESS)
1646 return (ret);
1647 msg->question_ok = 1;
1649 ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1650 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1651 goto truncated;
1652 if (ret == DNS_R_RECOVERABLE) {
1653 seen_problem = ISC_TRUE;
1654 ret = ISC_R_SUCCESS;
1656 if (ret != ISC_R_SUCCESS)
1657 return (ret);
1659 ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1660 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1661 goto truncated;
1662 if (ret == DNS_R_RECOVERABLE) {
1663 seen_problem = ISC_TRUE;
1664 ret = ISC_R_SUCCESS;
1666 if (ret != ISC_R_SUCCESS)
1667 return (ret);
1669 ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1670 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1671 goto truncated;
1672 if (ret == DNS_R_RECOVERABLE) {
1673 seen_problem = ISC_TRUE;
1674 ret = ISC_R_SUCCESS;
1676 if (ret != ISC_R_SUCCESS)
1677 return (ret);
1679 isc_buffer_remainingregion(source, &r);
1680 if (r.length != 0) {
1681 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1682 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1683 "message has %u byte(s) of trailing garbage",
1684 r.length);
1687 truncated:
1688 if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1689 isc_buffer_usedregion(&origsource, &msg->saved);
1690 else {
1691 msg->saved.length = isc_buffer_usedlength(&origsource);
1692 msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1693 if (msg->saved.base == NULL)
1694 return (ISC_R_NOMEMORY);
1695 memmove(msg->saved.base, isc_buffer_base(&origsource),
1696 msg->saved.length);
1697 msg->free_saved = 1;
1700 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1701 return (DNS_R_RECOVERABLE);
1702 if (seen_problem == ISC_TRUE)
1703 return (DNS_R_RECOVERABLE);
1704 return (ISC_R_SUCCESS);
1707 isc_result_t
1708 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1709 isc_buffer_t *buffer)
1711 isc_region_t r;
1713 REQUIRE(DNS_MESSAGE_VALID(msg));
1714 REQUIRE(buffer != NULL);
1715 REQUIRE(msg->buffer == NULL);
1716 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1718 msg->cctx = cctx;
1721 * Erase the contents of this buffer.
1723 isc_buffer_clear(buffer);
1726 * Make certain there is enough for at least the header in this
1727 * buffer.
1729 isc_buffer_availableregion(buffer, &r);
1730 if (r.length < DNS_MESSAGE_HEADERLEN)
1731 return (ISC_R_NOSPACE);
1733 if (r.length < msg->reserved)
1734 return (ISC_R_NOSPACE);
1737 * Reserve enough space for the header in this buffer.
1739 isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1741 msg->buffer = buffer;
1743 return (ISC_R_SUCCESS);
1746 isc_result_t
1747 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1748 isc_region_t r, rn;
1750 REQUIRE(DNS_MESSAGE_VALID(msg));
1751 REQUIRE(buffer != NULL);
1752 REQUIRE(msg->buffer != NULL);
1755 * Ensure that the new buffer is empty, and has enough space to
1756 * hold the current contents.
1758 isc_buffer_clear(buffer);
1760 isc_buffer_availableregion(buffer, &rn);
1761 isc_buffer_usedregion(msg->buffer, &r);
1762 REQUIRE(rn.length > r.length);
1765 * Copy the contents from the old to the new buffer.
1767 isc_buffer_add(buffer, r.length);
1768 memmove(rn.base, r.base, r.length);
1770 msg->buffer = buffer;
1772 return (ISC_R_SUCCESS);
1775 void
1776 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1777 REQUIRE(DNS_MESSAGE_VALID(msg));
1778 REQUIRE(space <= msg->reserved);
1780 msg->reserved -= space;
1783 isc_result_t
1784 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1785 isc_region_t r;
1787 REQUIRE(DNS_MESSAGE_VALID(msg));
1789 if (msg->buffer != NULL) {
1790 isc_buffer_availableregion(msg->buffer, &r);
1791 if (r.length < (space + msg->reserved))
1792 return (ISC_R_NOSPACE);
1795 msg->reserved += space;
1797 return (ISC_R_SUCCESS);
1800 static inline isc_boolean_t
1801 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1802 int pass_needed;
1805 * If we are not rendering class IN, this ordering is bogus.
1807 if (rds->rdclass != dns_rdataclass_in)
1808 return (ISC_FALSE);
1810 switch (rds->type) {
1811 case dns_rdatatype_a:
1812 case dns_rdatatype_aaaa:
1813 if (preferred_glue == rds->type)
1814 pass_needed = 4;
1815 else
1816 pass_needed = 3;
1817 break;
1818 case dns_rdatatype_rrsig:
1819 case dns_rdatatype_dnskey:
1820 pass_needed = 2;
1821 break;
1822 default:
1823 pass_needed = 1;
1826 if (pass_needed >= pass)
1827 return (ISC_FALSE);
1829 return (ISC_TRUE);
1832 #ifdef ALLOW_FILTER_AAAA
1834 * Decide whether to not answer with an AAAA record and its RRSIG
1836 static inline isc_boolean_t
1837 norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options)
1839 switch (rdataset->type) {
1840 case dns_rdatatype_aaaa:
1841 if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
1842 return (ISC_FALSE);
1843 break;
1845 case dns_rdatatype_rrsig:
1846 if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
1847 rdataset->covers != dns_rdatatype_aaaa)
1848 return (ISC_FALSE);
1849 break;
1851 default:
1852 return (ISC_FALSE);
1855 if (rdataset->rdclass != dns_rdataclass_in)
1856 return (ISC_FALSE);
1858 return (ISC_TRUE);
1861 #endif
1862 isc_result_t
1863 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1864 unsigned int options)
1866 dns_namelist_t *section;
1867 dns_name_t *name, *next_name;
1868 dns_rdataset_t *rdataset, *next_rdataset;
1869 unsigned int count, total;
1870 isc_result_t result;
1871 isc_buffer_t st; /* for rollbacks */
1872 int pass;
1873 isc_boolean_t partial = ISC_FALSE;
1874 unsigned int rd_options;
1875 dns_rdatatype_t preferred_glue = 0;
1877 REQUIRE(DNS_MESSAGE_VALID(msg));
1878 REQUIRE(msg->buffer != NULL);
1879 REQUIRE(VALID_NAMED_SECTION(sectionid));
1881 section = &msg->sections[sectionid];
1883 if ((sectionid == DNS_SECTION_ADDITIONAL)
1884 && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1885 if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1886 preferred_glue = dns_rdatatype_a;
1887 pass = 4;
1888 } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1889 preferred_glue = dns_rdatatype_aaaa;
1890 pass = 4;
1891 } else
1892 pass = 3;
1893 } else
1894 pass = 1;
1896 if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1897 rd_options = 0;
1898 else
1899 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1902 * Shrink the space in the buffer by the reserved amount.
1904 msg->buffer->length -= msg->reserved;
1906 total = 0;
1907 if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1908 partial = ISC_TRUE;
1911 * Render required glue first. Set TC if it won't fit.
1913 name = ISC_LIST_HEAD(*section);
1914 if (name != NULL) {
1915 rdataset = ISC_LIST_HEAD(name->list);
1916 if (rdataset != NULL &&
1917 (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
1918 (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
1919 const void *order_arg = msg->order_arg;
1920 st = *(msg->buffer);
1921 count = 0;
1922 if (partial)
1923 result = dns_rdataset_towirepartial(rdataset,
1924 name,
1925 msg->cctx,
1926 msg->buffer,
1927 msg->order,
1928 order_arg,
1929 rd_options,
1930 &count,
1931 NULL);
1932 else
1933 result = dns_rdataset_towiresorted(rdataset,
1934 name,
1935 msg->cctx,
1936 msg->buffer,
1937 msg->order,
1938 order_arg,
1939 rd_options,
1940 &count);
1941 total += count;
1942 if (partial && result == ISC_R_NOSPACE) {
1943 msg->flags |= DNS_MESSAGEFLAG_TC;
1944 msg->buffer->length += msg->reserved;
1945 msg->counts[sectionid] += total;
1946 return (result);
1948 if (result == ISC_R_NOSPACE)
1949 msg->flags |= DNS_MESSAGEFLAG_TC;
1950 if (result != ISC_R_SUCCESS) {
1951 INSIST(st.used < 65536);
1952 dns_compress_rollback(msg->cctx,
1953 (isc_uint16_t)st.used);
1954 *(msg->buffer) = st; /* rollback */
1955 msg->buffer->length += msg->reserved;
1956 msg->counts[sectionid] += total;
1957 return (result);
1959 rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
1963 do {
1964 name = ISC_LIST_HEAD(*section);
1965 if (name == NULL) {
1966 msg->buffer->length += msg->reserved;
1967 msg->counts[sectionid] += total;
1968 return (ISC_R_SUCCESS);
1971 while (name != NULL) {
1972 next_name = ISC_LIST_NEXT(name, link);
1974 rdataset = ISC_LIST_HEAD(name->list);
1975 while (rdataset != NULL) {
1976 next_rdataset = ISC_LIST_NEXT(rdataset, link);
1978 if ((rdataset->attributes &
1979 DNS_RDATASETATTR_RENDERED) != 0)
1980 goto next;
1982 if (((options & DNS_MESSAGERENDER_ORDERED)
1983 == 0)
1984 && (sectionid == DNS_SECTION_ADDITIONAL)
1985 && wrong_priority(rdataset, pass,
1986 preferred_glue))
1987 goto next;
1989 #ifdef ALLOW_FILTER_AAAA
1991 * Suppress AAAAs if asked and we are
1992 * not doing DNSSEC or are breaking DNSSEC.
1993 * Say so in the AD bit if we break DNSSEC.
1995 if (norender_rdataset(rdataset, options) &&
1996 sectionid != DNS_SECTION_QUESTION) {
1997 if (sectionid == DNS_SECTION_ANSWER ||
1998 sectionid == DNS_SECTION_AUTHORITY)
1999 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2000 if (OPTOUT(rdataset))
2001 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2002 goto next;
2005 #endif
2006 st = *(msg->buffer);
2008 count = 0;
2009 if (partial)
2010 result = dns_rdataset_towirepartial(
2011 rdataset,
2012 name,
2013 msg->cctx,
2014 msg->buffer,
2015 msg->order,
2016 msg->order_arg,
2017 rd_options,
2018 &count,
2019 NULL);
2020 else
2021 result = dns_rdataset_towiresorted(
2022 rdataset,
2023 name,
2024 msg->cctx,
2025 msg->buffer,
2026 msg->order,
2027 msg->order_arg,
2028 rd_options,
2029 &count);
2031 total += count;
2034 * If out of space, record stats on what we
2035 * rendered so far, and return that status.
2037 * XXXMLG Need to change this when
2038 * dns_rdataset_towire() can render partial
2039 * sets starting at some arbitrary point in the
2040 * set. This will include setting a bit in the
2041 * rdataset to indicate that a partial
2042 * rendering was done, and some state saved
2043 * somewhere (probably in the message struct)
2044 * to indicate where to continue from.
2046 if (partial && result == ISC_R_NOSPACE) {
2047 msg->buffer->length += msg->reserved;
2048 msg->counts[sectionid] += total;
2049 return (result);
2051 if (result != ISC_R_SUCCESS) {
2052 INSIST(st.used < 65536);
2053 dns_compress_rollback(msg->cctx,
2054 (isc_uint16_t)st.used);
2055 *(msg->buffer) = st; /* rollback */
2056 msg->buffer->length += msg->reserved;
2057 msg->counts[sectionid] += total;
2058 return (result);
2062 * If we have rendered non-validated data,
2063 * ensure that the AD bit is not set.
2065 if (rdataset->trust != dns_trust_secure &&
2066 (sectionid == DNS_SECTION_ANSWER ||
2067 sectionid == DNS_SECTION_AUTHORITY))
2068 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2069 if (OPTOUT(rdataset))
2070 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2072 rdataset->attributes |=
2073 DNS_RDATASETATTR_RENDERED;
2075 next:
2076 rdataset = next_rdataset;
2079 name = next_name;
2081 } while (--pass != 0);
2083 msg->buffer->length += msg->reserved;
2084 msg->counts[sectionid] += total;
2086 return (ISC_R_SUCCESS);
2089 void
2090 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2091 isc_uint16_t tmp;
2092 isc_region_t r;
2094 REQUIRE(DNS_MESSAGE_VALID(msg));
2095 REQUIRE(target != NULL);
2097 isc_buffer_availableregion(target, &r);
2098 REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2100 isc_buffer_putuint16(target, msg->id);
2102 tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
2103 & DNS_MESSAGE_OPCODE_MASK);
2104 tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2105 tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2107 INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
2108 msg->counts[DNS_SECTION_ANSWER] < 65536 &&
2109 msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2110 msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2112 isc_buffer_putuint16(target, tmp);
2113 isc_buffer_putuint16(target,
2114 (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2115 isc_buffer_putuint16(target,
2116 (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2117 isc_buffer_putuint16(target,
2118 (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2119 isc_buffer_putuint16(target,
2120 (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2123 isc_result_t
2124 dns_message_renderend(dns_message_t *msg) {
2125 isc_buffer_t tmpbuf;
2126 isc_region_t r;
2127 int result;
2128 unsigned int count;
2130 REQUIRE(DNS_MESSAGE_VALID(msg));
2131 REQUIRE(msg->buffer != NULL);
2133 if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2135 * We have an extended rcode but are not using EDNS.
2137 return (DNS_R_FORMERR);
2141 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
2142 * clear all rdatasets from the message except for the question
2143 * before adding the OPT, TSIG or SIG(0). If the question doesn't
2144 * fit, don't include it.
2146 if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
2147 (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2149 isc_buffer_t *buf;
2151 msgresetnames(msg, DNS_SECTION_ANSWER);
2152 buf = msg->buffer;
2153 dns_message_renderreset(msg);
2154 msg->buffer = buf;
2155 isc_buffer_clear(msg->buffer);
2156 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2157 dns_compress_rollback(msg->cctx, 0);
2158 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2160 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2161 return (result);
2165 * If we've got an OPT record, render it.
2167 if (msg->opt != NULL) {
2168 dns_message_renderrelease(msg, msg->opt_reserved);
2169 msg->opt_reserved = 0;
2171 * Set the extended rcode.
2173 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2174 msg->opt->ttl |= ((msg->rcode << 20) &
2175 DNS_MESSAGE_EDNSRCODE_MASK);
2177 * Render.
2179 count = 0;
2180 result = dns_rdataset_towire(msg->opt, dns_rootname,
2181 msg->cctx, msg->buffer, 0,
2182 &count);
2183 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2184 if (result != ISC_R_SUCCESS)
2185 return (result);
2189 * If we're adding a TSIG record, generate and render it.
2191 if (msg->tsigkey != NULL) {
2192 dns_message_renderrelease(msg, msg->sig_reserved);
2193 msg->sig_reserved = 0;
2194 result = dns_tsig_sign(msg);
2195 if (result != ISC_R_SUCCESS)
2196 return (result);
2197 count = 0;
2198 result = dns_rdataset_towire(msg->tsig, msg->tsigname,
2199 msg->cctx, msg->buffer, 0,
2200 &count);
2201 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2202 if (result != ISC_R_SUCCESS)
2203 return (result);
2207 * If we're adding a SIG(0) record, generate and render it.
2209 if (msg->sig0key != NULL) {
2210 dns_message_renderrelease(msg, msg->sig_reserved);
2211 msg->sig_reserved = 0;
2212 result = dns_dnssec_signmessage(msg, msg->sig0key);
2213 if (result != ISC_R_SUCCESS)
2214 return (result);
2215 count = 0;
2217 * Note: dns_rootname is used here, not msg->sig0name, since
2218 * the owner name of a SIG(0) is irrelevant, and will not
2219 * be set in a message being rendered.
2221 result = dns_rdataset_towire(msg->sig0, dns_rootname,
2222 msg->cctx, msg->buffer, 0,
2223 &count);
2224 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2225 if (result != ISC_R_SUCCESS)
2226 return (result);
2229 isc_buffer_usedregion(msg->buffer, &r);
2230 isc_buffer_init(&tmpbuf, r.base, r.length);
2232 dns_message_renderheader(msg, &tmpbuf);
2234 msg->buffer = NULL; /* forget about this buffer only on success XXX */
2236 return (ISC_R_SUCCESS);
2239 void
2240 dns_message_renderreset(dns_message_t *msg) {
2241 unsigned int i;
2242 dns_name_t *name;
2243 dns_rdataset_t *rds;
2246 * Reset the message so that it may be rendered again.
2249 REQUIRE(DNS_MESSAGE_VALID(msg));
2250 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2252 msg->buffer = NULL;
2254 for (i = 0; i < DNS_SECTION_MAX; i++) {
2255 msg->cursors[i] = NULL;
2256 msg->counts[i] = 0;
2257 for (name = ISC_LIST_HEAD(msg->sections[i]);
2258 name != NULL;
2259 name = ISC_LIST_NEXT(name, link)) {
2260 for (rds = ISC_LIST_HEAD(name->list);
2261 rds != NULL;
2262 rds = ISC_LIST_NEXT(rds, link)) {
2263 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2267 if (msg->tsigname != NULL)
2268 dns_message_puttempname(msg, &msg->tsigname);
2269 if (msg->tsig != NULL) {
2270 dns_rdataset_disassociate(msg->tsig);
2271 dns_message_puttemprdataset(msg, &msg->tsig);
2273 if (msg->sig0 != NULL) {
2274 dns_rdataset_disassociate(msg->sig0);
2275 dns_message_puttemprdataset(msg, &msg->sig0);
2279 isc_result_t
2280 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2281 REQUIRE(DNS_MESSAGE_VALID(msg));
2282 REQUIRE(VALID_NAMED_SECTION(section));
2284 msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2286 if (msg->cursors[section] == NULL)
2287 return (ISC_R_NOMORE);
2289 return (ISC_R_SUCCESS);
2292 isc_result_t
2293 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2294 REQUIRE(DNS_MESSAGE_VALID(msg));
2295 REQUIRE(VALID_NAMED_SECTION(section));
2296 REQUIRE(msg->cursors[section] != NULL);
2298 msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2300 if (msg->cursors[section] == NULL)
2301 return (ISC_R_NOMORE);
2303 return (ISC_R_SUCCESS);
2306 void
2307 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2308 dns_name_t **name)
2310 REQUIRE(DNS_MESSAGE_VALID(msg));
2311 REQUIRE(VALID_NAMED_SECTION(section));
2312 REQUIRE(name != NULL && *name == NULL);
2313 REQUIRE(msg->cursors[section] != NULL);
2315 *name = msg->cursors[section];
2318 isc_result_t
2319 dns_message_findname(dns_message_t *msg, dns_section_t section,
2320 dns_name_t *target, dns_rdatatype_t type,
2321 dns_rdatatype_t covers, dns_name_t **name,
2322 dns_rdataset_t **rdataset)
2324 dns_name_t *foundname;
2325 isc_result_t result;
2328 * XXX These requirements are probably too intensive, especially
2329 * where things can be NULL, but as they are they ensure that if
2330 * something is NON-NULL, indicating that the caller expects it
2331 * to be filled in, that we can in fact fill it in.
2333 REQUIRE(msg != NULL);
2334 REQUIRE(VALID_SECTION(section));
2335 REQUIRE(target != NULL);
2336 if (name != NULL)
2337 REQUIRE(*name == NULL);
2338 if (type == dns_rdatatype_any) {
2339 REQUIRE(rdataset == NULL);
2340 } else {
2341 if (rdataset != NULL)
2342 REQUIRE(*rdataset == NULL);
2345 result = findname(&foundname, target,
2346 &msg->sections[section]);
2348 if (result == ISC_R_NOTFOUND)
2349 return (DNS_R_NXDOMAIN);
2350 else if (result != ISC_R_SUCCESS)
2351 return (result);
2353 if (name != NULL)
2354 *name = foundname;
2357 * And now look for the type.
2359 if (type == dns_rdatatype_any)
2360 return (ISC_R_SUCCESS);
2362 result = dns_message_findtype(foundname, type, covers, rdataset);
2363 if (result == ISC_R_NOTFOUND)
2364 return (DNS_R_NXRRSET);
2366 return (result);
2369 void
2370 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2371 dns_section_t fromsection,
2372 dns_section_t tosection)
2374 REQUIRE(msg != NULL);
2375 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2376 REQUIRE(name != NULL);
2377 REQUIRE(VALID_NAMED_SECTION(fromsection));
2378 REQUIRE(VALID_NAMED_SECTION(tosection));
2381 * Unlink the name from the old section
2383 ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2384 ISC_LIST_APPEND(msg->sections[tosection], name, link);
2387 void
2388 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2389 dns_section_t section)
2391 REQUIRE(msg != NULL);
2392 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2393 REQUIRE(name != NULL);
2394 REQUIRE(VALID_NAMED_SECTION(section));
2396 ISC_LIST_APPEND(msg->sections[section], name, link);
2399 void
2400 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2401 dns_section_t section)
2403 REQUIRE(msg != NULL);
2404 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2405 REQUIRE(name != NULL);
2406 REQUIRE(VALID_NAMED_SECTION(section));
2408 ISC_LIST_UNLINK(msg->sections[section], name, link);
2411 isc_result_t
2412 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2413 REQUIRE(DNS_MESSAGE_VALID(msg));
2414 REQUIRE(item != NULL && *item == NULL);
2416 *item = isc_mempool_get(msg->namepool);
2417 if (*item == NULL)
2418 return (ISC_R_NOMEMORY);
2419 dns_name_init(*item, NULL);
2421 return (ISC_R_SUCCESS);
2424 isc_result_t
2425 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2426 REQUIRE(DNS_MESSAGE_VALID(msg));
2427 REQUIRE(item != NULL && *item == NULL);
2429 *item = newoffsets(msg);
2430 if (*item == NULL)
2431 return (ISC_R_NOMEMORY);
2433 return (ISC_R_SUCCESS);
2436 isc_result_t
2437 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2438 REQUIRE(DNS_MESSAGE_VALID(msg));
2439 REQUIRE(item != NULL && *item == NULL);
2441 *item = newrdata(msg);
2442 if (*item == NULL)
2443 return (ISC_R_NOMEMORY);
2445 return (ISC_R_SUCCESS);
2448 isc_result_t
2449 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2450 REQUIRE(DNS_MESSAGE_VALID(msg));
2451 REQUIRE(item != NULL && *item == NULL);
2453 *item = isc_mempool_get(msg->rdspool);
2454 if (*item == NULL)
2455 return (ISC_R_NOMEMORY);
2457 dns_rdataset_init(*item);
2459 return (ISC_R_SUCCESS);
2462 isc_result_t
2463 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2464 REQUIRE(DNS_MESSAGE_VALID(msg));
2465 REQUIRE(item != NULL && *item == NULL);
2467 *item = newrdatalist(msg);
2468 if (*item == NULL)
2469 return (ISC_R_NOMEMORY);
2471 return (ISC_R_SUCCESS);
2474 void
2475 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2476 REQUIRE(DNS_MESSAGE_VALID(msg));
2477 REQUIRE(item != NULL && *item != NULL);
2479 if (dns_name_dynamic(*item))
2480 dns_name_free(*item, msg->mctx);
2481 isc_mempool_put(msg->namepool, *item);
2482 *item = NULL;
2485 void
2486 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2487 REQUIRE(DNS_MESSAGE_VALID(msg));
2488 REQUIRE(item != NULL && *item != NULL);
2490 releaserdata(msg, *item);
2491 *item = NULL;
2494 void
2495 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2496 REQUIRE(DNS_MESSAGE_VALID(msg));
2497 REQUIRE(item != NULL && *item != NULL);
2499 REQUIRE(!dns_rdataset_isassociated(*item));
2500 isc_mempool_put(msg->rdspool, *item);
2501 *item = NULL;
2504 void
2505 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2506 REQUIRE(DNS_MESSAGE_VALID(msg));
2507 REQUIRE(item != NULL && *item != NULL);
2509 releaserdatalist(msg, *item);
2510 *item = NULL;
2513 isc_result_t
2514 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2515 unsigned int *flagsp)
2517 isc_region_t r;
2518 isc_buffer_t buffer;
2519 dns_messageid_t id;
2520 unsigned int flags;
2522 REQUIRE(source != NULL);
2524 buffer = *source;
2526 isc_buffer_remainingregion(&buffer, &r);
2527 if (r.length < DNS_MESSAGE_HEADERLEN)
2528 return (ISC_R_UNEXPECTEDEND);
2530 id = isc_buffer_getuint16(&buffer);
2531 flags = isc_buffer_getuint16(&buffer);
2532 flags &= DNS_MESSAGE_FLAG_MASK;
2534 if (flagsp != NULL)
2535 *flagsp = flags;
2536 if (idp != NULL)
2537 *idp = id;
2539 return (ISC_R_SUCCESS);
2542 isc_result_t
2543 dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
2544 unsigned int clear_after;
2545 isc_result_t result;
2547 REQUIRE(DNS_MESSAGE_VALID(msg));
2548 REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2550 if (!msg->header_ok)
2551 return (DNS_R_FORMERR);
2552 if (msg->opcode != dns_opcode_query &&
2553 msg->opcode != dns_opcode_notify)
2554 want_question_section = ISC_FALSE;
2555 if (msg->opcode == dns_opcode_update)
2556 clear_after = DNS_SECTION_PREREQUISITE;
2557 else if (want_question_section) {
2558 if (!msg->question_ok)
2559 return (DNS_R_FORMERR);
2560 clear_after = DNS_SECTION_ANSWER;
2561 } else
2562 clear_after = DNS_SECTION_QUESTION;
2563 msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2564 msgresetnames(msg, clear_after);
2565 msgresetopt(msg);
2566 msgresetsigs(msg, ISC_TRUE);
2567 msginitprivate(msg);
2569 * We now clear most flags and then set QR, ensuring that the
2570 * reply's flags will be in a reasonable state.
2572 msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2573 msg->flags |= DNS_MESSAGEFLAG_QR;
2576 * This saves the query TSIG status, if the query was signed, and
2577 * reserves space in the reply for the TSIG.
2579 if (msg->tsigkey != NULL) {
2580 unsigned int otherlen = 0;
2581 msg->querytsigstatus = msg->tsigstatus;
2582 msg->tsigstatus = dns_rcode_noerror;
2583 if (msg->querytsigstatus == dns_tsigerror_badtime)
2584 otherlen = 6;
2585 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2586 result = dns_message_renderreserve(msg, msg->sig_reserved);
2587 if (result != ISC_R_SUCCESS) {
2588 msg->sig_reserved = 0;
2589 return (result);
2592 if (msg->saved.base != NULL) {
2593 msg->query.base = msg->saved.base;
2594 msg->query.length = msg->saved.length;
2595 msg->free_query = msg->free_saved;
2596 msg->saved.base = NULL;
2597 msg->saved.length = 0;
2598 msg->free_saved = 0;
2601 return (ISC_R_SUCCESS);
2604 dns_rdataset_t *
2605 dns_message_getopt(dns_message_t *msg) {
2608 * Get the OPT record for 'msg'.
2611 REQUIRE(DNS_MESSAGE_VALID(msg));
2613 return (msg->opt);
2616 isc_result_t
2617 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2618 isc_result_t result;
2619 dns_rdata_t rdata = DNS_RDATA_INIT;
2622 * Set the OPT record for 'msg'.
2626 * The space required for an OPT record is:
2628 * 1 byte for the name
2629 * 2 bytes for the type
2630 * 2 bytes for the class
2631 * 4 bytes for the ttl
2632 * 2 bytes for the rdata length
2633 * ---------------------------------
2634 * 11 bytes
2636 * plus the length of the rdata.
2639 REQUIRE(DNS_MESSAGE_VALID(msg));
2640 REQUIRE(opt->type == dns_rdatatype_opt);
2641 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2642 REQUIRE(msg->state == DNS_SECTION_ANY);
2644 msgresetopt(msg);
2646 result = dns_rdataset_first(opt);
2647 if (result != ISC_R_SUCCESS)
2648 goto cleanup;
2649 dns_rdataset_current(opt, &rdata);
2650 msg->opt_reserved = 11 + rdata.length;
2651 result = dns_message_renderreserve(msg, msg->opt_reserved);
2652 if (result != ISC_R_SUCCESS) {
2653 msg->opt_reserved = 0;
2654 goto cleanup;
2657 msg->opt = opt;
2659 return (ISC_R_SUCCESS);
2661 cleanup:
2662 dns_rdataset_disassociate(opt);
2663 dns_message_puttemprdataset(msg, &opt);
2664 return (result);
2667 dns_rdataset_t *
2668 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2671 * Get the TSIG record and owner for 'msg'.
2674 REQUIRE(DNS_MESSAGE_VALID(msg));
2675 REQUIRE(owner == NULL || *owner == NULL);
2677 if (owner != NULL)
2678 *owner = msg->tsigname;
2679 return (msg->tsig);
2682 isc_result_t
2683 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2684 isc_result_t result;
2687 * Set the TSIG key for 'msg'
2690 REQUIRE(DNS_MESSAGE_VALID(msg));
2691 REQUIRE(msg->state == DNS_SECTION_ANY);
2693 if (key == NULL && msg->tsigkey != NULL) {
2694 if (msg->sig_reserved != 0) {
2695 dns_message_renderrelease(msg, msg->sig_reserved);
2696 msg->sig_reserved = 0;
2698 dns_tsigkey_detach(&msg->tsigkey);
2700 if (key != NULL) {
2701 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2702 dns_tsigkey_attach(key, &msg->tsigkey);
2703 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2704 msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2705 result = dns_message_renderreserve(msg,
2706 msg->sig_reserved);
2707 if (result != ISC_R_SUCCESS) {
2708 dns_tsigkey_detach(&msg->tsigkey);
2709 msg->sig_reserved = 0;
2710 return (result);
2714 return (ISC_R_SUCCESS);
2717 dns_tsigkey_t *
2718 dns_message_gettsigkey(dns_message_t *msg) {
2721 * Get the TSIG key for 'msg'
2724 REQUIRE(DNS_MESSAGE_VALID(msg));
2726 return (msg->tsigkey);
2729 isc_result_t
2730 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2731 dns_rdata_t *rdata = NULL;
2732 dns_rdatalist_t *list = NULL;
2733 dns_rdataset_t *set = NULL;
2734 isc_buffer_t *buf = NULL;
2735 isc_region_t r;
2736 isc_result_t result;
2738 REQUIRE(DNS_MESSAGE_VALID(msg));
2739 REQUIRE(msg->querytsig == NULL);
2741 if (querytsig == NULL)
2742 return (ISC_R_SUCCESS);
2744 result = dns_message_gettemprdata(msg, &rdata);
2745 if (result != ISC_R_SUCCESS)
2746 goto cleanup;
2748 result = dns_message_gettemprdatalist(msg, &list);
2749 if (result != ISC_R_SUCCESS)
2750 goto cleanup;
2751 result = dns_message_gettemprdataset(msg, &set);
2752 if (result != ISC_R_SUCCESS)
2753 goto cleanup;
2755 isc_buffer_usedregion(querytsig, &r);
2756 result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2757 if (result != ISC_R_SUCCESS)
2758 goto cleanup;
2759 isc_buffer_putmem(buf, r.base, r.length);
2760 isc_buffer_usedregion(buf, &r);
2761 dns_rdata_init(rdata);
2762 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2763 dns_message_takebuffer(msg, &buf);
2764 ISC_LIST_INIT(list->rdata);
2765 ISC_LIST_APPEND(list->rdata, rdata, link);
2766 result = dns_rdatalist_tordataset(list, set);
2767 if (result != ISC_R_SUCCESS)
2768 goto cleanup;
2770 msg->querytsig = set;
2772 return (result);
2774 cleanup:
2775 if (rdata != NULL)
2776 dns_message_puttemprdata(msg, &rdata);
2777 if (list != NULL)
2778 dns_message_puttemprdatalist(msg, &list);
2779 if (set != NULL)
2780 dns_message_puttemprdataset(msg, &set);
2781 return (ISC_R_NOMEMORY);
2784 isc_result_t
2785 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2786 isc_buffer_t **querytsig) {
2787 isc_result_t result;
2788 dns_rdata_t rdata = DNS_RDATA_INIT;
2789 isc_region_t r;
2791 REQUIRE(DNS_MESSAGE_VALID(msg));
2792 REQUIRE(mctx != NULL);
2793 REQUIRE(querytsig != NULL && *querytsig == NULL);
2795 if (msg->tsig == NULL)
2796 return (ISC_R_SUCCESS);
2798 result = dns_rdataset_first(msg->tsig);
2799 if (result != ISC_R_SUCCESS)
2800 return (result);
2801 dns_rdataset_current(msg->tsig, &rdata);
2802 dns_rdata_toregion(&rdata, &r);
2804 result = isc_buffer_allocate(mctx, querytsig, r.length);
2805 if (result != ISC_R_SUCCESS)
2806 return (result);
2807 isc_buffer_putmem(*querytsig, r.base, r.length);
2808 return (ISC_R_SUCCESS);
2811 dns_rdataset_t *
2812 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2815 * Get the SIG(0) record for 'msg'.
2818 REQUIRE(DNS_MESSAGE_VALID(msg));
2819 REQUIRE(owner == NULL || *owner == NULL);
2821 if (msg->sig0 != NULL && owner != NULL) {
2822 /* If dns_message_getsig0 is called on a rendered message
2823 * after the SIG(0) has been applied, we need to return the
2824 * root name, not NULL.
2826 if (msg->sig0name == NULL)
2827 *owner = dns_rootname;
2828 else
2829 *owner = msg->sig0name;
2831 return (msg->sig0);
2834 isc_result_t
2835 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2836 isc_region_t r;
2837 unsigned int x;
2838 isc_result_t result;
2841 * Set the SIG(0) key for 'msg'
2845 * The space required for an SIG(0) record is:
2847 * 1 byte for the name
2848 * 2 bytes for the type
2849 * 2 bytes for the class
2850 * 4 bytes for the ttl
2851 * 2 bytes for the type covered
2852 * 1 byte for the algorithm
2853 * 1 bytes for the labels
2854 * 4 bytes for the original ttl
2855 * 4 bytes for the signature expiration
2856 * 4 bytes for the signature inception
2857 * 2 bytes for the key tag
2858 * n bytes for the signer's name
2859 * x bytes for the signature
2860 * ---------------------------------
2861 * 27 + n + x bytes
2863 REQUIRE(DNS_MESSAGE_VALID(msg));
2864 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2865 REQUIRE(msg->state == DNS_SECTION_ANY);
2867 if (key != NULL) {
2868 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2869 dns_name_toregion(dst_key_name(key), &r);
2870 result = dst_key_sigsize(key, &x);
2871 if (result != ISC_R_SUCCESS) {
2872 msg->sig_reserved = 0;
2873 return (result);
2875 msg->sig_reserved = 27 + r.length + x;
2876 result = dns_message_renderreserve(msg, msg->sig_reserved);
2877 if (result != ISC_R_SUCCESS) {
2878 msg->sig_reserved = 0;
2879 return (result);
2881 msg->sig0key = key;
2883 return (ISC_R_SUCCESS);
2886 dst_key_t *
2887 dns_message_getsig0key(dns_message_t *msg) {
2890 * Get the SIG(0) key for 'msg'
2893 REQUIRE(DNS_MESSAGE_VALID(msg));
2895 return (msg->sig0key);
2898 void
2899 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2900 REQUIRE(DNS_MESSAGE_VALID(msg));
2901 REQUIRE(buffer != NULL);
2902 REQUIRE(ISC_BUFFER_VALID(*buffer));
2904 ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2905 *buffer = NULL;
2908 isc_result_t
2909 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
2910 isc_result_t result = ISC_R_SUCCESS;
2911 dns_rdata_t rdata = DNS_RDATA_INIT;
2913 REQUIRE(DNS_MESSAGE_VALID(msg));
2914 REQUIRE(signer != NULL);
2915 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2917 if (msg->tsig == NULL && msg->sig0 == NULL)
2918 return (ISC_R_NOTFOUND);
2920 if (msg->verify_attempted == 0)
2921 return (DNS_R_NOTVERIFIEDYET);
2923 if (!dns_name_hasbuffer(signer)) {
2924 isc_buffer_t *dynbuf = NULL;
2925 result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
2926 if (result != ISC_R_SUCCESS)
2927 return (result);
2928 dns_name_setbuffer(signer, dynbuf);
2929 dns_message_takebuffer(msg, &dynbuf);
2932 if (msg->sig0 != NULL) {
2933 dns_rdata_sig_t sig;
2935 result = dns_rdataset_first(msg->sig0);
2936 INSIST(result == ISC_R_SUCCESS);
2937 dns_rdataset_current(msg->sig0, &rdata);
2939 result = dns_rdata_tostruct(&rdata, &sig, NULL);
2940 if (result != ISC_R_SUCCESS)
2941 return (result);
2943 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
2944 result = ISC_R_SUCCESS;
2945 else
2946 result = DNS_R_SIGINVALID;
2947 dns_name_clone(&sig.signer, signer);
2948 dns_rdata_freestruct(&sig);
2949 } else {
2950 dns_name_t *identity;
2951 dns_rdata_any_tsig_t tsig;
2953 result = dns_rdataset_first(msg->tsig);
2954 INSIST(result == ISC_R_SUCCESS);
2955 dns_rdataset_current(msg->tsig, &rdata);
2957 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2958 INSIST(result == ISC_R_SUCCESS);
2959 if (msg->tsigstatus != dns_rcode_noerror)
2960 result = DNS_R_TSIGVERIFYFAILURE;
2961 else if (tsig.error != dns_rcode_noerror)
2962 result = DNS_R_TSIGERRORSET;
2963 else
2964 result = ISC_R_SUCCESS;
2965 dns_rdata_freestruct(&tsig);
2967 if (msg->tsigkey == NULL) {
2969 * If msg->tsigstatus & tsig.error are both
2970 * dns_rcode_noerror, the message must have been
2971 * verified, which means msg->tsigkey will be
2972 * non-NULL.
2974 INSIST(result != ISC_R_SUCCESS);
2975 } else {
2976 identity = dns_tsigkey_identity(msg->tsigkey);
2977 if (identity == NULL) {
2978 if (result == ISC_R_SUCCESS)
2979 result = DNS_R_NOIDENTITY;
2980 identity = &msg->tsigkey->name;
2982 dns_name_clone(identity, signer);
2986 return (result);
2989 void
2990 dns_message_resetsig(dns_message_t *msg) {
2991 REQUIRE(DNS_MESSAGE_VALID(msg));
2992 msg->verified_sig = 0;
2993 msg->verify_attempted = 0;
2994 msg->tsigstatus = dns_rcode_noerror;
2995 msg->sig0status = dns_rcode_noerror;
2996 msg->timeadjust = 0;
2997 if (msg->tsigkey != NULL) {
2998 dns_tsigkey_detach(&msg->tsigkey);
2999 msg->tsigkey = NULL;
3003 isc_result_t
3004 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
3005 dns_message_resetsig(msg);
3006 return (dns_message_checksig(msg, view));
3009 #ifdef SKAN_MSG_DEBUG
3010 void
3011 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
3012 dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
3013 dns_rdata_any_tsig_t querytsig;
3014 isc_result_t result;
3016 if (msg->tsig != NULL) {
3017 result = dns_rdataset_first(msg->tsig);
3018 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3019 dns_rdataset_current(msg->tsig, &querytsigrdata);
3020 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3021 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3022 hexdump(txt1, "TSIG", querytsig.signature,
3023 querytsig.siglen);
3026 if (msg->querytsig != NULL) {
3027 result = dns_rdataset_first(msg->querytsig);
3028 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3029 dns_rdataset_current(msg->querytsig, &querytsigrdata);
3030 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3031 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3032 hexdump(txt1, "QUERYTSIG", querytsig.signature,
3033 querytsig.siglen);
3036 #endif
3038 isc_result_t
3039 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
3040 isc_buffer_t b, msgb;
3042 REQUIRE(DNS_MESSAGE_VALID(msg));
3044 if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
3045 return (ISC_R_SUCCESS);
3047 INSIST(msg->saved.base != NULL);
3048 isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
3049 isc_buffer_add(&msgb, msg->saved.length);
3050 if (msg->tsigkey != NULL || msg->tsig != NULL) {
3051 #ifdef SKAN_MSG_DEBUG
3052 dns_message_dumpsig(msg, "dns_message_checksig#1");
3053 #endif
3054 if (view != NULL)
3055 return (dns_view_checksig(view, &msgb, msg));
3056 else
3057 return (dns_tsig_verify(&msgb, msg, NULL, NULL));
3058 } else {
3059 dns_rdata_t rdata = DNS_RDATA_INIT;
3060 dns_rdata_sig_t sig;
3061 dns_rdataset_t keyset;
3062 isc_result_t result;
3064 result = dns_rdataset_first(msg->sig0);
3065 INSIST(result == ISC_R_SUCCESS);
3066 dns_rdataset_current(msg->sig0, &rdata);
3069 * This can occur when the message is a dynamic update, since
3070 * the rdata length checking is relaxed. This should not
3071 * happen in a well-formed message, since the SIG(0) is only
3072 * looked for in the additional section, and the dynamic update
3073 * meta-records are in the prerequisite and update sections.
3075 if (rdata.length == 0)
3076 return (ISC_R_UNEXPECTEDEND);
3078 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
3079 if (result != ISC_R_SUCCESS)
3080 return (result);
3082 dns_rdataset_init(&keyset);
3083 if (view == NULL)
3084 return (DNS_R_KEYUNAUTHORIZED);
3085 result = dns_view_simplefind(view, &sig.signer,
3086 dns_rdatatype_key /* SIG(0) */,
3087 0, 0, ISC_FALSE, &keyset, NULL);
3089 if (result != ISC_R_SUCCESS) {
3090 /* XXXBEW Should possibly create a fetch here */
3091 result = DNS_R_KEYUNAUTHORIZED;
3092 goto freesig;
3093 } else if (keyset.trust < dns_trust_secure) {
3094 /* XXXBEW Should call a validator here */
3095 result = DNS_R_KEYUNAUTHORIZED;
3096 goto freesig;
3098 result = dns_rdataset_first(&keyset);
3099 INSIST(result == ISC_R_SUCCESS);
3100 for (;
3101 result == ISC_R_SUCCESS;
3102 result = dns_rdataset_next(&keyset))
3104 dst_key_t *key = NULL;
3106 dns_rdata_reset(&rdata);
3107 dns_rdataset_current(&keyset, &rdata);
3108 isc_buffer_init(&b, rdata.data, rdata.length);
3109 isc_buffer_add(&b, rdata.length);
3111 result = dst_key_fromdns(&sig.signer, rdata.rdclass,
3112 &b, view->mctx, &key);
3113 if (result != ISC_R_SUCCESS)
3114 continue;
3115 if (dst_key_alg(key) != sig.algorithm ||
3116 dst_key_id(key) != sig.keyid ||
3117 !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3118 dst_key_proto(key) == DNS_KEYPROTO_ANY))
3120 dst_key_free(&key);
3121 continue;
3123 result = dns_dnssec_verifymessage(&msgb, msg, key);
3124 dst_key_free(&key);
3125 if (result == ISC_R_SUCCESS)
3126 break;
3128 if (result == ISC_R_NOMORE)
3129 result = DNS_R_KEYUNAUTHORIZED;
3131 freesig:
3132 if (dns_rdataset_isassociated(&keyset))
3133 dns_rdataset_disassociate(&keyset);
3134 dns_rdata_freestruct(&sig);
3135 return (result);
3139 isc_result_t
3140 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3141 const dns_master_style_t *style,
3142 dns_messagetextflag_t flags,
3143 isc_buffer_t *target) {
3144 dns_name_t *name, empty_name;
3145 dns_rdataset_t *rdataset;
3146 isc_result_t result;
3147 isc_boolean_t seensoa = ISC_FALSE;
3149 REQUIRE(DNS_MESSAGE_VALID(msg));
3150 REQUIRE(target != NULL);
3151 REQUIRE(VALID_SECTION(section));
3153 if (ISC_LIST_EMPTY(msg->sections[section]))
3154 return (ISC_R_SUCCESS);
3156 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3157 ADD_STRING(target, ";; ");
3158 if (msg->opcode != dns_opcode_update) {
3159 ADD_STRING(target, sectiontext[section]);
3160 } else {
3161 ADD_STRING(target, updsectiontext[section]);
3163 ADD_STRING(target, " SECTION:\n");
3166 dns_name_init(&empty_name, NULL);
3167 result = dns_message_firstname(msg, section);
3168 if (result != ISC_R_SUCCESS) {
3169 return (result);
3171 do {
3172 name = NULL;
3173 dns_message_currentname(msg, section, &name);
3174 for (rdataset = ISC_LIST_HEAD(name->list);
3175 rdataset != NULL;
3176 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3177 if (section == DNS_SECTION_ANSWER &&
3178 rdataset->type == dns_rdatatype_soa) {
3179 if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
3180 continue;
3181 if (seensoa &&
3182 (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
3183 continue;
3184 seensoa = ISC_TRUE;
3186 if (section == DNS_SECTION_QUESTION) {
3187 ADD_STRING(target, ";");
3188 result = dns_master_questiontotext(name,
3189 rdataset,
3190 style,
3191 target);
3192 } else {
3193 result = dns_master_rdatasettotext(name,
3194 rdataset,
3195 style,
3196 target);
3198 if (result != ISC_R_SUCCESS)
3199 return (result);
3201 result = dns_message_nextname(msg, section);
3202 } while (result == ISC_R_SUCCESS);
3203 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3204 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3205 ADD_STRING(target, "\n");
3206 if (result == ISC_R_NOMORE)
3207 result = ISC_R_SUCCESS;
3208 return (result);
3211 static isc_result_t
3212 render_ecs(isc_buffer_t *optbuf, isc_buffer_t *target) {
3213 int i;
3214 char addr[16], addr_text[64];
3215 isc_uint16_t family;
3216 isc_uint8_t addrlen, addrbytes, scopelen;
3218 INSIST(isc_buffer_remaininglength(optbuf) >= 4);
3219 family = isc_buffer_getuint16(optbuf);
3220 addrlen = isc_buffer_getuint8(optbuf);
3221 scopelen = isc_buffer_getuint8(optbuf);
3223 addrbytes = (addrlen + 7) / 8;
3224 INSIST(isc_buffer_remaininglength(optbuf) >= addrbytes);
3226 memset(addr, 0, sizeof(addr));
3227 for (i = 0; i < addrbytes; i ++)
3228 addr[i] = isc_buffer_getuint8(optbuf);
3230 if (family == 1)
3231 inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
3232 else if (family == 2)
3233 inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
3234 else {
3235 snprintf(addr_text, sizeof(addr_text),
3236 "Unsupported family %u", family);
3237 ADD_STRING(target, addr_text);
3238 return (ISC_R_SUCCESS);
3241 ADD_STRING(target, addr_text);
3242 snprintf(addr_text, sizeof(addr_text), "/%d/%d", addrlen, scopelen);
3243 ADD_STRING(target, addr_text);
3244 return (ISC_R_SUCCESS);
3247 isc_result_t
3248 dns_message_pseudosectiontotext(dns_message_t *msg,
3249 dns_pseudosection_t section,
3250 const dns_master_style_t *style,
3251 dns_messagetextflag_t flags,
3252 isc_buffer_t *target)
3254 dns_rdataset_t *ps = NULL;
3255 dns_name_t *name = NULL;
3256 isc_result_t result;
3257 char buf[sizeof("1234567890")];
3258 isc_uint32_t mbz;
3259 dns_rdata_t rdata;
3260 isc_buffer_t optbuf;
3261 isc_uint16_t optcode, optlen;
3262 unsigned char *optdata;
3264 REQUIRE(DNS_MESSAGE_VALID(msg));
3265 REQUIRE(target != NULL);
3266 REQUIRE(VALID_PSEUDOSECTION(section));
3268 switch (section) {
3269 case DNS_PSEUDOSECTION_OPT:
3270 ps = dns_message_getopt(msg);
3271 if (ps == NULL)
3272 return (ISC_R_SUCCESS);
3273 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3274 ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3275 ADD_STRING(target, "; EDNS: version: ");
3276 snprintf(buf, sizeof(buf), "%u",
3277 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3278 ADD_STRING(target, buf);
3279 ADD_STRING(target, ", flags:");
3280 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3281 ADD_STRING(target, " do");
3282 mbz = ps->ttl & 0xffff;
3283 mbz &= ~DNS_MESSAGEEXTFLAG_DO; /* Known Flags. */
3284 if (mbz != 0) {
3285 ADD_STRING(target, "; MBZ: ");
3286 snprintf(buf, sizeof(buf), "%.4x ", mbz);
3287 ADD_STRING(target, buf);
3288 ADD_STRING(target, ", udp: ");
3289 } else
3290 ADD_STRING(target, "; udp: ");
3291 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3292 ADD_STRING(target, buf);
3294 result = dns_rdataset_first(ps);
3295 if (result != ISC_R_SUCCESS)
3296 return (ISC_R_SUCCESS);
3298 /* Print EDNS info, if any */
3299 dns_rdata_init(&rdata);
3300 dns_rdataset_current(ps, &rdata);
3302 isc_buffer_init(&optbuf, rdata.data, rdata.length);
3303 isc_buffer_add(&optbuf, rdata.length);
3304 while (isc_buffer_remaininglength(&optbuf) != 0) {
3305 INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3306 optcode = isc_buffer_getuint16(&optbuf);
3307 optlen = isc_buffer_getuint16(&optbuf);
3308 INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3310 if (optcode == DNS_OPT_NSID) {
3311 ADD_STRING(target, "; NSID");
3312 } else if (optcode == DNS_OPT_SIT) {
3313 ADD_STRING(target, "; SIT");
3314 } else if (optcode == DNS_OPT_CLIENT_SUBNET) {
3315 ADD_STRING(target, "; CLIENT-SUBNET: ");
3316 render_ecs(&optbuf, target);
3317 ADD_STRING(target, "\n");
3318 continue;
3319 } else if (optcode == DNS_OPT_EXPIRE) {
3320 if (optlen == 4) {
3321 isc_uint32_t secs;
3322 secs = isc_buffer_getuint32(&optbuf);
3323 ADD_STRING(target, "; EXPIRE: ");
3324 snprintf(buf, sizeof(buf), "%u", secs);
3325 ADD_STRING(target, buf);
3326 ADD_STRING(target, " (");
3327 dns_ttl_totext(secs, ISC_TRUE, target);
3328 ADD_STRING(target, ")\n");
3329 continue;
3331 ADD_STRING(target, "; EXPIRE");
3332 } else {
3333 ADD_STRING(target, "; OPT=");
3334 snprintf(buf, sizeof(buf), "%u", optcode);
3335 ADD_STRING(target, buf);
3338 if (optlen != 0) {
3339 int i;
3340 ADD_STRING(target, ": ");
3342 optdata = isc_buffer_current(&optbuf);
3343 for (i = 0; i < optlen; i++) {
3344 const char *sep;
3345 switch (optcode) {
3346 case DNS_OPT_SIT:
3347 sep = "";
3348 break;
3349 default:
3350 sep = " ";
3351 break;
3353 snprintf(buf, sizeof(buf), "%02x%s",
3354 optdata[i], sep);
3355 ADD_STRING(target, buf);
3358 isc_buffer_forward(&optbuf, optlen);
3360 if (optcode == DNS_OPT_SIT) {
3361 if (msg->sitok)
3362 ADD_STRING(target, " (good)");
3363 if (msg->sitbad)
3364 ADD_STRING(target, " (bad)");
3365 ADD_STRING(target, "\n");
3366 continue;
3370 * For non-SIT options, add a printable
3371 * version
3373 ADD_STRING(target, "(\"");
3374 if (isc_buffer_availablelength(target) < optlen)
3375 return (ISC_R_NOSPACE);
3376 for (i = 0; i < optlen; i++) {
3377 if (isprint(optdata[i]))
3378 isc_buffer_putmem(target,
3379 &optdata[i],
3381 else
3382 isc_buffer_putstr(target, ".");
3384 ADD_STRING(target, "\")");
3386 ADD_STRING(target, "\n");
3388 return (ISC_R_SUCCESS);
3389 case DNS_PSEUDOSECTION_TSIG:
3390 ps = dns_message_gettsig(msg, &name);
3391 if (ps == NULL)
3392 return (ISC_R_SUCCESS);
3393 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3394 ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
3395 result = dns_master_rdatasettotext(name, ps, style, target);
3396 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3397 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3398 ADD_STRING(target, "\n");
3399 return (result);
3400 case DNS_PSEUDOSECTION_SIG0:
3401 ps = dns_message_getsig0(msg, &name);
3402 if (ps == NULL)
3403 return (ISC_R_SUCCESS);
3404 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3405 ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3406 result = dns_master_rdatasettotext(name, ps, style, target);
3407 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3408 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3409 ADD_STRING(target, "\n");
3410 return (result);
3412 return (ISC_R_UNEXPECTED);
3415 isc_result_t
3416 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3417 dns_messagetextflag_t flags, isc_buffer_t *target) {
3418 char buf[sizeof("1234567890")];
3419 isc_result_t result;
3421 REQUIRE(DNS_MESSAGE_VALID(msg));
3422 REQUIRE(target != NULL);
3424 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
3425 ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
3426 ADD_STRING(target, opcodetext[msg->opcode]);
3427 ADD_STRING(target, ", status: ");
3428 if (msg->rcode < (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
3429 ADD_STRING(target, rcodetext[msg->rcode]);
3430 } else {
3431 snprintf(buf, sizeof(buf), "%4u", msg->rcode);
3432 ADD_STRING(target, buf);
3434 ADD_STRING(target, ", id: ");
3435 snprintf(buf, sizeof(buf), "%6u", msg->id);
3436 ADD_STRING(target, buf);
3437 ADD_STRING(target, "\n;; flags:");
3438 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3439 ADD_STRING(target, " qr");
3440 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3441 ADD_STRING(target, " aa");
3442 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3443 ADD_STRING(target, " tc");
3444 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3445 ADD_STRING(target, " rd");
3446 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3447 ADD_STRING(target, " ra");
3448 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3449 ADD_STRING(target, " ad");
3450 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
3451 ADD_STRING(target, " cd");
3453 * The final unnamed flag must be zero.
3455 if ((msg->flags & 0x0040U) != 0)
3456 ADD_STRING(target, "; MBZ: 0x4");
3457 if (msg->opcode != dns_opcode_update) {
3458 ADD_STRING(target, "; QUESTION: ");
3459 } else {
3460 ADD_STRING(target, "; ZONE: ");
3462 snprintf(buf, sizeof(buf), "%1u",
3463 msg->counts[DNS_SECTION_QUESTION]);
3464 ADD_STRING(target, buf);
3465 if (msg->opcode != dns_opcode_update) {
3466 ADD_STRING(target, ", ANSWER: ");
3467 } else {
3468 ADD_STRING(target, ", PREREQ: ");
3470 snprintf(buf, sizeof(buf), "%1u",
3471 msg->counts[DNS_SECTION_ANSWER]);
3472 ADD_STRING(target, buf);
3473 if (msg->opcode != dns_opcode_update) {
3474 ADD_STRING(target, ", AUTHORITY: ");
3475 } else {
3476 ADD_STRING(target, ", UPDATE: ");
3478 snprintf(buf, sizeof(buf), "%1u",
3479 msg->counts[DNS_SECTION_AUTHORITY]);
3480 ADD_STRING(target, buf);
3481 ADD_STRING(target, ", ADDITIONAL: ");
3482 snprintf(buf, sizeof(buf), "%1u",
3483 msg->counts[DNS_SECTION_ADDITIONAL]);
3484 ADD_STRING(target, buf);
3485 ADD_STRING(target, "\n");
3487 result = dns_message_pseudosectiontotext(msg,
3488 DNS_PSEUDOSECTION_OPT,
3489 style, flags, target);
3490 if (result != ISC_R_SUCCESS)
3491 return (result);
3493 result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
3494 style, flags, target);
3495 if (result != ISC_R_SUCCESS)
3496 return (result);
3497 result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
3498 style, flags, target);
3499 if (result != ISC_R_SUCCESS)
3500 return (result);
3501 result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
3502 style, flags, target);
3503 if (result != ISC_R_SUCCESS)
3504 return (result);
3505 result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
3506 style, flags, target);
3507 if (result != ISC_R_SUCCESS)
3508 return (result);
3510 result = dns_message_pseudosectiontotext(msg,
3511 DNS_PSEUDOSECTION_TSIG,
3512 style, flags, target);
3513 if (result != ISC_R_SUCCESS)
3514 return (result);
3516 result = dns_message_pseudosectiontotext(msg,
3517 DNS_PSEUDOSECTION_SIG0,
3518 style, flags, target);
3519 if (result != ISC_R_SUCCESS)
3520 return (result);
3522 return (ISC_R_SUCCESS);
3525 isc_region_t *
3526 dns_message_getrawmessage(dns_message_t *msg) {
3527 REQUIRE(DNS_MESSAGE_VALID(msg));
3528 return (&msg->saved);
3531 void
3532 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3533 const void *order_arg)
3535 REQUIRE(DNS_MESSAGE_VALID(msg));
3536 msg->order = order;
3537 msg->order_arg = order_arg;
3540 void
3541 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3542 REQUIRE(DNS_MESSAGE_VALID(msg));
3543 msg->timeadjust = timeadjust;
3547 dns_message_gettimeadjust(dns_message_t *msg) {
3548 REQUIRE(DNS_MESSAGE_VALID(msg));
3549 return (msg->timeadjust);
3552 isc_result_t
3553 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3555 REQUIRE(opcode < 16);
3557 if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
3558 return (ISC_R_NOSPACE);
3559 isc_buffer_putstr(target, opcodetext[opcode]);
3560 return (ISC_R_SUCCESS);
3563 void
3564 dns_message_logpacket(dns_message_t *message, const char *description,
3565 isc_logcategory_t *category, isc_logmodule_t *module,
3566 int level, isc_mem_t *mctx)
3568 dns_message_logfmtpacket(message, description, category, module,
3569 &dns_master_style_debug, level, mctx);
3572 void
3573 dns_message_logfmtpacket(dns_message_t *message, const char *description,
3574 isc_logcategory_t *category, isc_logmodule_t *module,
3575 const dns_master_style_t *style, int level,
3576 isc_mem_t *mctx)
3578 isc_buffer_t buffer;
3579 char *buf = NULL;
3580 int len = 1024;
3581 isc_result_t result;
3583 if (! isc_log_wouldlog(dns_lctx, level))
3584 return;
3587 * Note that these are multiline debug messages. We want a newline
3588 * to appear in the log after each message.
3591 do {
3592 buf = isc_mem_get(mctx, len);
3593 if (buf == NULL)
3594 break;
3595 isc_buffer_init(&buffer, buf, len);
3596 result = dns_message_totext(message, style, 0, &buffer);
3597 if (result == ISC_R_NOSPACE) {
3598 isc_mem_put(mctx, buf, len);
3599 len += 1024;
3600 } else if (result == ISC_R_SUCCESS)
3601 isc_log_write(dns_lctx, category, module, level,
3602 "%s%.*s", description,
3603 (int)isc_buffer_usedlength(&buffer),
3604 buf);
3605 } while (result == ISC_R_NOSPACE);
3607 if (buf != NULL)
3608 isc_mem_put(mctx, buf, len);
3611 isc_result_t
3612 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
3613 unsigned int version, isc_uint16_t udpsize,
3614 unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
3616 dns_rdataset_t *rdataset = NULL;
3617 dns_rdatalist_t *rdatalist = NULL;
3618 dns_rdata_t *rdata = NULL;
3619 isc_result_t result;
3620 unsigned int len = 0, i;
3622 REQUIRE(DNS_MESSAGE_VALID(message));
3623 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
3625 result = dns_message_gettemprdatalist(message, &rdatalist);
3626 if (result != ISC_R_SUCCESS)
3627 return (result);
3628 result = dns_message_gettemprdata(message, &rdata);
3629 if (result != ISC_R_SUCCESS)
3630 goto cleanup;
3631 result = dns_message_gettemprdataset(message, &rdataset);
3632 if (result != ISC_R_SUCCESS)
3633 goto cleanup;
3635 rdatalist->type = dns_rdatatype_opt;
3636 rdatalist->covers = 0;
3639 * Set Maximum UDP buffer size.
3641 rdatalist->rdclass = udpsize;
3644 * Set EXTENDED-RCODE and Z to 0.
3646 rdatalist->ttl = (version << 16);
3647 rdatalist->ttl |= (flags & 0xffff);
3650 * Set EDNS options if applicable
3652 if (count != 0U) {
3653 isc_buffer_t *buf = NULL;
3654 for (i = 0; i < count; i++)
3655 len += ednsopts[i].length + 4;
3657 if (len > 0xffffU) {
3658 result = ISC_R_NOSPACE;
3659 goto cleanup;
3662 result = isc_buffer_allocate(message->mctx, &buf, len);
3663 if (result != ISC_R_SUCCESS)
3664 goto cleanup;
3666 for (i = 0; i < count; i++) {
3667 isc_buffer_putuint16(buf, ednsopts[i].code);
3668 isc_buffer_putuint16(buf, ednsopts[i].length);
3669 isc_buffer_putmem(buf, ednsopts[i].value,
3670 ednsopts[i].length);
3672 rdata->data = isc_buffer_base(buf);
3673 rdata->length = len;
3674 dns_message_takebuffer(message, &buf);
3675 } else {
3676 rdata->data = NULL;
3677 rdata->length = 0;
3680 rdata->rdclass = rdatalist->rdclass;
3681 rdata->type = rdatalist->type;
3682 rdata->flags = 0;
3684 ISC_LIST_INIT(rdatalist->rdata);
3685 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
3686 result = dns_rdatalist_tordataset(rdatalist, rdataset);
3687 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3689 *rdatasetp = rdataset;
3690 return (ISC_R_SUCCESS);
3692 cleanup:
3693 if (rdata != NULL)
3694 dns_message_puttemprdata(message, &rdata);
3695 if (rdataset != NULL)
3696 dns_message_puttemprdataset(message, &rdataset);
3697 if (rdatalist != NULL)
3698 dns_message_puttemprdatalist(message, &rdatalist);
3699 return (result);