2 * Copyright (C) 2004-2016 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
27 #include <isc/buffer.h>
29 #include <isc/print.h>
30 #include <isc/string.h> /* Required for HP/UX (and others?) */
33 #include <dns/dnssec.h>
34 #include <dns/keyvalues.h>
36 #include <dns/masterdump.h>
37 #include <dns/message.h>
38 #include <dns/opcode.h>
39 #include <dns/rcode.h>
40 #include <dns/rdata.h>
41 #include <dns/rdatalist.h>
42 #include <dns/rdataset.h>
43 #include <dns/rdatastruct.h>
44 #include <dns/result.h>
51 hexdump(const char *msg, const char *msg2, void *base, size_t len) {
58 printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base);
63 else if (cnt % 8 == 0)
65 printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
78 #define DNS_MESSAGE_OPCODE_MASK 0x7800U
79 #define DNS_MESSAGE_OPCODE_SHIFT 11
80 #define DNS_MESSAGE_RCODE_MASK 0x000fU
81 #define DNS_MESSAGE_FLAG_MASK 0x8ff0U
82 #define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U
83 #define DNS_MESSAGE_EDNSRCODE_SHIFT 24
84 #define DNS_MESSAGE_EDNSVERSION_MASK 0x00ff0000U
85 #define DNS_MESSAGE_EDNSVERSION_SHIFT 16
87 #define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \
88 && ((s) < DNS_SECTION_MAX))
89 #define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \
90 && ((s) < DNS_SECTION_MAX))
91 #define ADD_STRING(b, s) {if (strlen(s) >= \
92 isc_buffer_availablelength(b)) \
93 return(ISC_R_NOSPACE); else \
94 isc_buffer_putstr(b, s);}
95 #define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \
96 && ((s) < DNS_PSEUDOSECTION_MAX))
98 #define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
101 * This is the size of each individual scratchpad buffer, and the numbers
102 * of various block allocations used within the server.
103 * XXXMLG These should come from a config setting.
105 #define SCRATCHPAD_SIZE 512
107 #define OFFSET_COUNT 4
108 #define RDATA_COUNT 8
109 #define RDATALIST_COUNT 8
110 #define RDATASET_COUNT RDATALIST_COUNT
113 * Text representation of the different items, for message_totext
116 static const char *sectiontext[] = {
123 static const char *updsectiontext[] = {
130 static const char *opcodetext[] = {
150 * "helper" type, which consists of a block of some type, and is linkable.
151 * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
152 * size, or the allocated elements will not be aligned correctly.
154 struct dns_msgblock {
156 unsigned int remaining;
157 ISC_LINK(dns_msgblock_t) link;
158 }; /* dynamically sized */
160 static inline dns_msgblock_t *
161 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
163 #define msgblock_get(block, type) \
164 ((type *)msgblock_internalget(block, sizeof(type)))
167 msgblock_internalget(dns_msgblock_t *, unsigned int);
170 msgblock_reset(dns_msgblock_t *);
173 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
176 * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory
177 * is free, return NULL.
179 static inline dns_msgblock_t *
180 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
183 dns_msgblock_t *block;
186 length = sizeof(dns_msgblock_t) + (sizeof_type * count);
188 block = isc_mem_get(mctx, length);
192 block->count = count;
193 block->remaining = count;
195 ISC_LINK_INIT(block, link);
201 * Return an element from the msgblock. If no more are available, return
205 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
208 if (block == NULL || block->remaining == 0)
213 ptr = (((unsigned char *)block)
214 + sizeof(dns_msgblock_t)
215 + (sizeof_type * block->remaining));
221 msgblock_reset(dns_msgblock_t *block) {
222 block->remaining = block->count;
226 * Release memory associated with a message block.
229 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
233 length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
235 isc_mem_put(mctx, block, length);
239 * Allocate a new dynamic buffer, and attach it to this message as the
240 * "current" buffer. (which is always the last on the list, for our
243 static inline isc_result_t
244 newbuffer(dns_message_t *msg, unsigned int size) {
246 isc_buffer_t *dynbuf;
249 result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
250 if (result != ISC_R_SUCCESS)
251 return (ISC_R_NOMEMORY);
253 ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
254 return (ISC_R_SUCCESS);
257 static inline isc_buffer_t *
258 currentbuffer(dns_message_t *msg) {
259 isc_buffer_t *dynbuf;
261 dynbuf = ISC_LIST_TAIL(msg->scratchpad);
262 INSIST(dynbuf != NULL);
268 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
269 ISC_LIST_PREPEND(msg->freerdata, rdata, link);
272 static inline dns_rdata_t *
273 newrdata(dns_message_t *msg) {
274 dns_msgblock_t *msgblock;
277 rdata = ISC_LIST_HEAD(msg->freerdata);
279 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
283 msgblock = ISC_LIST_TAIL(msg->rdatas);
284 rdata = msgblock_get(msgblock, dns_rdata_t);
286 msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
288 if (msgblock == NULL)
291 ISC_LIST_APPEND(msg->rdatas, msgblock, link);
293 rdata = msgblock_get(msgblock, dns_rdata_t);
296 dns_rdata_init(rdata);
301 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
302 ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
305 static inline dns_rdatalist_t *
306 newrdatalist(dns_message_t *msg) {
307 dns_msgblock_t *msgblock;
308 dns_rdatalist_t *rdatalist;
310 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
311 if (rdatalist != NULL) {
312 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
316 msgblock = ISC_LIST_TAIL(msg->rdatalists);
317 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
318 if (rdatalist == NULL) {
319 msgblock = msgblock_allocate(msg->mctx,
320 sizeof(dns_rdatalist_t),
322 if (msgblock == NULL)
325 ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
327 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
330 if (rdatalist != NULL)
331 dns_rdatalist_init(rdatalist);
336 static inline dns_offsets_t *
337 newoffsets(dns_message_t *msg) {
338 dns_msgblock_t *msgblock;
339 dns_offsets_t *offsets;
341 msgblock = ISC_LIST_TAIL(msg->offsets);
342 offsets = msgblock_get(msgblock, dns_offsets_t);
343 if (offsets == NULL) {
344 msgblock = msgblock_allocate(msg->mctx,
345 sizeof(dns_offsets_t),
347 if (msgblock == NULL)
350 ISC_LIST_APPEND(msg->offsets, msgblock, link);
352 offsets = msgblock_get(msgblock, dns_offsets_t);
359 msginitheader(dns_message_t *m) {
368 msginitprivate(dns_message_t *m) {
371 for (i = 0; i < DNS_SECTION_MAX; i++) {
372 m->cursors[i] = NULL;
380 m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */
388 msginittsig(dns_message_t *m) {
389 m->tsigstatus = dns_rcode_noerror;
390 m->querytsigstatus = dns_rcode_noerror;
395 m->sig0status = dns_rcode_noerror;
400 * Init elements to default state. Used both when allocating a new element
401 * and when resetting one.
404 msginit(dns_message_t *m) {
410 m->tcp_continuation = 0;
412 m->verify_attempted = 0;
415 m->query.base = NULL;
418 m->saved.base = NULL;
427 msgresetnames(dns_message_t *msg, unsigned int first_section) {
429 dns_name_t *name, *next_name;
430 dns_rdataset_t *rds, *next_rds;
433 * Clean up name lists by calling the rdataset disassociate function.
435 for (i = first_section; i < DNS_SECTION_MAX; i++) {
436 name = ISC_LIST_HEAD(msg->sections[i]);
437 while (name != NULL) {
438 next_name = ISC_LIST_NEXT(name, link);
439 ISC_LIST_UNLINK(msg->sections[i], name, link);
441 rds = ISC_LIST_HEAD(name->list);
442 while (rds != NULL) {
443 next_rds = ISC_LIST_NEXT(rds, link);
444 ISC_LIST_UNLINK(name->list, rds, link);
446 INSIST(dns_rdataset_isassociated(rds));
447 dns_rdataset_disassociate(rds);
448 isc_mempool_put(msg->rdspool, rds);
451 if (dns_name_dynamic(name))
452 dns_name_free(name, msg->mctx);
453 isc_mempool_put(msg->namepool, name);
460 msgresetopt(dns_message_t *msg)
462 if (msg->opt != NULL) {
463 if (msg->opt_reserved > 0) {
464 dns_message_renderrelease(msg, msg->opt_reserved);
465 msg->opt_reserved = 0;
467 INSIST(dns_rdataset_isassociated(msg->opt));
468 dns_rdataset_disassociate(msg->opt);
469 isc_mempool_put(msg->rdspool, msg->opt);
475 msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
476 if (msg->sig_reserved > 0) {
477 dns_message_renderrelease(msg, msg->sig_reserved);
478 msg->sig_reserved = 0;
480 if (msg->tsig != NULL) {
481 INSIST(dns_rdataset_isassociated(msg->tsig));
482 INSIST(msg->namepool != NULL);
484 INSIST(msg->querytsig == NULL);
485 msg->querytsig = msg->tsig;
487 dns_rdataset_disassociate(msg->tsig);
488 isc_mempool_put(msg->rdspool, msg->tsig);
489 if (msg->querytsig != NULL) {
490 dns_rdataset_disassociate(msg->querytsig);
491 isc_mempool_put(msg->rdspool, msg->querytsig);
494 if (dns_name_dynamic(msg->tsigname))
495 dns_name_free(msg->tsigname, msg->mctx);
496 isc_mempool_put(msg->namepool, msg->tsigname);
498 msg->tsigname = NULL;
499 } else if (msg->querytsig != NULL && !replying) {
500 dns_rdataset_disassociate(msg->querytsig);
501 isc_mempool_put(msg->rdspool, msg->querytsig);
502 msg->querytsig = NULL;
504 if (msg->sig0 != NULL) {
505 INSIST(dns_rdataset_isassociated(msg->sig0));
506 dns_rdataset_disassociate(msg->sig0);
507 isc_mempool_put(msg->rdspool, msg->sig0);
508 if (msg->sig0name != NULL) {
509 if (dns_name_dynamic(msg->sig0name))
510 dns_name_free(msg->sig0name, msg->mctx);
511 isc_mempool_put(msg->namepool, msg->sig0name);
514 msg->sig0name = NULL;
519 * Free all but one (or everything) for this message. This is used by
520 * both dns_message_reset() and dns_message_destroy().
523 msgreset(dns_message_t *msg, isc_boolean_t everything) {
524 dns_msgblock_t *msgblock, *next_msgblock;
525 isc_buffer_t *dynbuf, *next_dynbuf;
527 dns_rdatalist_t *rdatalist;
529 msgresetnames(msg, 0);
531 msgresetsigs(msg, ISC_FALSE);
534 * Clean up linked lists.
538 * Run through the free lists, and just unlink anything found there.
539 * The memory isn't lost since these are part of message blocks we
542 rdata = ISC_LIST_HEAD(msg->freerdata);
543 while (rdata != NULL) {
544 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
545 rdata = ISC_LIST_HEAD(msg->freerdata);
547 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
548 while (rdatalist != NULL) {
549 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
550 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
553 dynbuf = ISC_LIST_HEAD(msg->scratchpad);
554 INSIST(dynbuf != NULL);
556 isc_buffer_clear(dynbuf);
557 dynbuf = ISC_LIST_NEXT(dynbuf, link);
559 while (dynbuf != NULL) {
560 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
561 ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
562 isc_buffer_free(&dynbuf);
563 dynbuf = next_dynbuf;
566 msgblock = ISC_LIST_HEAD(msg->rdatas);
567 if (!everything && msgblock != NULL) {
568 msgblock_reset(msgblock);
569 msgblock = ISC_LIST_NEXT(msgblock, link);
571 while (msgblock != NULL) {
572 next_msgblock = ISC_LIST_NEXT(msgblock, link);
573 ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
574 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
575 msgblock = next_msgblock;
579 * rdatalists could be empty.
582 msgblock = ISC_LIST_HEAD(msg->rdatalists);
583 if (!everything && msgblock != NULL) {
584 msgblock_reset(msgblock);
585 msgblock = ISC_LIST_NEXT(msgblock, link);
587 while (msgblock != NULL) {
588 next_msgblock = ISC_LIST_NEXT(msgblock, link);
589 ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
590 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
591 msgblock = next_msgblock;
594 msgblock = ISC_LIST_HEAD(msg->offsets);
595 if (!everything && msgblock != NULL) {
596 msgblock_reset(msgblock);
597 msgblock = ISC_LIST_NEXT(msgblock, link);
599 while (msgblock != NULL) {
600 next_msgblock = ISC_LIST_NEXT(msgblock, link);
601 ISC_LIST_UNLINK(msg->offsets, msgblock, link);
602 msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
603 msgblock = next_msgblock;
606 if (msg->tsigkey != NULL) {
607 dns_tsigkey_detach(&msg->tsigkey);
611 if (msg->tsigctx != NULL)
612 dst_context_destroy(&msg->tsigctx);
614 if (msg->query.base != NULL) {
615 if (msg->free_query != 0)
616 isc_mem_put(msg->mctx, msg->query.base,
618 msg->query.base = NULL;
619 msg->query.length = 0;
622 if (msg->saved.base != NULL) {
623 if (msg->free_saved != 0)
624 isc_mem_put(msg->mctx, msg->saved.base,
626 msg->saved.base = NULL;
627 msg->saved.length = 0;
631 * cleanup the buffer cleanup list
633 dynbuf = ISC_LIST_HEAD(msg->cleanup);
634 while (dynbuf != NULL) {
635 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
636 ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
637 isc_buffer_free(&dynbuf);
638 dynbuf = next_dynbuf;
642 * Set other bits to normal default values.
647 ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
648 ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
652 spacefortsig(dns_tsigkey_t *key, int otherlen) {
658 * The space required for an TSIG record is:
660 * n1 bytes for the name
661 * 2 bytes for the type
662 * 2 bytes for the class
663 * 4 bytes for the ttl
664 * 2 bytes for the rdlength
665 * n2 bytes for the algorithm name
666 * 6 bytes for the time signed
667 * 2 bytes for the fudge
668 * 2 bytes for the MAC size
669 * x bytes for the MAC
670 * 2 bytes for the original id
671 * 2 bytes for the error
672 * 2 bytes for the other data length
673 * y bytes for the other data (at most)
674 * ---------------------------------
675 * 26 + n1 + n2 + x + y bytes
678 dns_name_toregion(&key->name, &r1);
679 dns_name_toregion(key->algorithm, &r2);
680 if (key->key == NULL)
683 result = dst_key_sigsize(key->key, &x);
684 if (result != ISC_R_SUCCESS)
687 return (26 + r1.length + r2.length + x + otherlen);
691 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
695 isc_buffer_t *dynbuf;
698 REQUIRE(mctx != NULL);
699 REQUIRE(msgp != NULL);
700 REQUIRE(*msgp == NULL);
701 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
702 || intent == DNS_MESSAGE_INTENTRENDER);
704 m = isc_mem_get(mctx, sizeof(dns_message_t));
706 return (ISC_R_NOMEMORY);
709 * No allocations until further notice. Just initialize all lists
710 * and other members that are freed in the cleanup phase here.
713 m->magic = DNS_MESSAGE_MAGIC;
714 m->from_to_wire = intent;
717 for (i = 0; i < DNS_SECTION_MAX; i++)
718 ISC_LIST_INIT(m->sections[i]);
721 isc_mem_attach(mctx, &m->mctx);
723 ISC_LIST_INIT(m->scratchpad);
724 ISC_LIST_INIT(m->cleanup);
727 ISC_LIST_INIT(m->rdatas);
728 ISC_LIST_INIT(m->rdatalists);
729 ISC_LIST_INIT(m->offsets);
730 ISC_LIST_INIT(m->freerdata);
731 ISC_LIST_INIT(m->freerdatalist);
734 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
737 result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
738 if (result != ISC_R_SUCCESS)
740 isc_mempool_setfreemax(m->namepool, NAME_COUNT);
741 isc_mempool_setname(m->namepool, "msg:names");
743 result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
745 if (result != ISC_R_SUCCESS)
747 isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
748 isc_mempool_setname(m->rdspool, "msg:rdataset");
751 result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
752 if (result != ISC_R_SUCCESS)
754 ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
759 return (ISC_R_SUCCESS);
762 * Cleanup for error returns.
765 dynbuf = ISC_LIST_HEAD(m->scratchpad);
766 if (dynbuf != NULL) {
767 ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
768 isc_buffer_free(&dynbuf);
770 if (m->namepool != NULL)
771 isc_mempool_destroy(&m->namepool);
772 if (m->rdspool != NULL)
773 isc_mempool_destroy(&m->rdspool);
775 isc_mem_putanddetach(&mctx, m, sizeof(dns_message_t));
777 return (ISC_R_NOMEMORY);
781 dns_message_reset(dns_message_t *msg, unsigned int intent) {
782 REQUIRE(DNS_MESSAGE_VALID(msg));
783 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
784 || intent == DNS_MESSAGE_INTENTRENDER);
786 msgreset(msg, ISC_FALSE);
787 msg->from_to_wire = intent;
791 dns_message_destroy(dns_message_t **msgp) {
794 REQUIRE(msgp != NULL);
795 REQUIRE(DNS_MESSAGE_VALID(*msgp));
800 msgreset(msg, ISC_TRUE);
801 isc_mempool_destroy(&msg->namepool);
802 isc_mempool_destroy(&msg->rdspool);
804 isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
808 findname(dns_name_t **foundname, dns_name_t *target,
809 dns_namelist_t *section)
813 for (curr = ISC_LIST_TAIL(*section);
815 curr = ISC_LIST_PREV(curr, link)) {
816 if (dns_name_equal(curr, target)) {
817 if (foundname != NULL)
819 return (ISC_R_SUCCESS);
823 return (ISC_R_NOTFOUND);
827 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
828 dns_rdatatype_t type, dns_rdatatype_t covers,
829 dns_rdataset_t **rdataset)
831 dns_rdataset_t *curr;
833 REQUIRE(name != NULL);
834 REQUIRE(rdataset == NULL || *rdataset == NULL);
836 for (curr = ISC_LIST_TAIL(name->list);
838 curr = ISC_LIST_PREV(curr, link)) {
839 if (curr->rdclass == rdclass &&
840 curr->type == type && curr->covers == covers) {
841 if (rdataset != NULL)
843 return (ISC_R_SUCCESS);
847 return (ISC_R_NOTFOUND);
851 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
852 dns_rdatatype_t covers, dns_rdataset_t **rdataset)
854 dns_rdataset_t *curr;
856 REQUIRE(name != NULL);
857 REQUIRE(rdataset == NULL || *rdataset == NULL);
859 for (curr = ISC_LIST_TAIL(name->list);
861 curr = ISC_LIST_PREV(curr, link)) {
862 if (curr->type == type && curr->covers == covers) {
863 if (ISC_UNLIKELY(rdataset != NULL))
865 return (ISC_R_SUCCESS);
869 return (ISC_R_NOTFOUND);
873 * Read a name from buffer "source".
876 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
877 dns_decompress_t *dctx)
879 isc_buffer_t *scratch;
883 scratch = currentbuffer(msg);
886 * First try: use current buffer.
887 * Second try: allocate a new buffer and use that.
891 result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
894 if (result == ISC_R_NOSPACE) {
897 result = newbuffer(msg, SCRATCHPAD_SIZE);
898 if (result != ISC_R_SUCCESS)
901 scratch = currentbuffer(msg);
902 dns_name_reset(name);
908 INSIST(0); /* Cannot get here... */
909 return (ISC_R_UNEXPECTED);
913 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
914 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
915 unsigned int rdatalen, dns_rdata_t *rdata)
917 isc_buffer_t *scratch;
920 unsigned int trysize;
922 scratch = currentbuffer(msg);
924 isc_buffer_setactive(source, rdatalen);
927 * First try: use current buffer.
928 * Second try: allocate a new buffer of size
929 * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
930 * (the data will fit if it was not more than 50% compressed)
931 * Subsequent tries: double buffer size on each try.
935 /* XXX possibly change this to a while (tries < 2) loop */
937 result = dns_rdata_fromwire(rdata, rdclass, rdtype,
941 if (result == ISC_R_NOSPACE) {
943 trysize = 2 * rdatalen;
944 if (trysize < SCRATCHPAD_SIZE)
945 trysize = SCRATCHPAD_SIZE;
947 INSIST(trysize != 0);
948 if (trysize >= 65535)
949 return (ISC_R_NOSPACE);
950 /* XXX DNS_R_RRTOOLONG? */
954 result = newbuffer(msg, trysize);
955 if (result != ISC_R_SUCCESS)
958 scratch = currentbuffer(msg);
968 seen_problem = ISC_TRUE; \
970 result = DNS_R_FORMERR; \
976 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
977 unsigned int options)
983 dns_offsets_t *offsets;
984 dns_rdataset_t *rdataset;
985 dns_rdatalist_t *rdatalist;
987 dns_rdatatype_t rdtype;
988 dns_rdataclass_t rdclass;
989 dns_namelist_t *section;
990 isc_boolean_t free_name;
991 isc_boolean_t best_effort;
992 isc_boolean_t seen_problem;
994 section = &msg->sections[DNS_SECTION_QUESTION];
996 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
997 seen_problem = ISC_FALSE;
1003 for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
1004 name = isc_mempool_get(msg->namepool);
1006 return (ISC_R_NOMEMORY);
1007 free_name = ISC_TRUE;
1009 offsets = newoffsets(msg);
1010 if (offsets == NULL) {
1011 result = ISC_R_NOMEMORY;
1014 dns_name_init(name, *offsets);
1017 * Parse the name out of this packet.
1019 isc_buffer_remainingregion(source, &r);
1020 isc_buffer_setactive(source, r.length);
1021 result = getname(name, source, msg, dctx);
1022 if (result != ISC_R_SUCCESS)
1026 * Run through the section, looking to see if this name
1027 * is already there. If it is found, put back the allocated
1028 * name since we no longer need it, and set our name pointer
1029 * to point to the name we found.
1031 result = findname(&name2, name, section);
1034 * If it is the first name in the section, accept it.
1036 * If it is not, but is not the same as the name already
1037 * in the question section, append to the section. Note that
1038 * here in the question section this is illegal, so return
1039 * FORMERR. In the future, check the opcode to see if
1040 * this should be legal or not. In either case we no longer
1041 * need this name pointer.
1043 if (result != ISC_R_SUCCESS) {
1044 if (!ISC_LIST_EMPTY(*section))
1046 ISC_LIST_APPEND(*section, name, link);
1047 free_name = ISC_FALSE;
1049 isc_mempool_put(msg->namepool, name);
1052 free_name = ISC_FALSE;
1056 * Get type and class.
1058 isc_buffer_remainingregion(source, &r);
1060 result = ISC_R_UNEXPECTEDEND;
1063 rdtype = isc_buffer_getuint16(source);
1064 rdclass = isc_buffer_getuint16(source);
1067 * If this class is different than the one we already read,
1070 if (msg->rdclass_set == 0) {
1071 msg->rdclass = rdclass;
1072 msg->rdclass_set = 1;
1073 } else if (msg->rdclass != rdclass)
1077 * Is this a TKEY query?
1079 if (rdtype == dns_rdatatype_tkey)
1083 * Can't ask the same question twice.
1085 result = dns_message_find(name, rdclass, rdtype, 0, NULL);
1086 if (result == ISC_R_SUCCESS)
1090 * Allocate a new rdatalist.
1092 rdatalist = newrdatalist(msg);
1093 if (rdatalist == NULL) {
1094 result = ISC_R_NOMEMORY;
1097 rdataset = isc_mempool_get(msg->rdspool);
1098 if (rdataset == NULL) {
1099 result = ISC_R_NOMEMORY;
1104 * Convert rdatalist to rdataset, and attach the latter to
1107 rdatalist->type = rdtype;
1108 rdatalist->covers = 0;
1109 rdatalist->rdclass = rdclass;
1111 ISC_LIST_INIT(rdatalist->rdata);
1113 dns_rdataset_init(rdataset);
1114 result = dns_rdatalist_tordataset(rdatalist, rdataset);
1115 if (result != ISC_R_SUCCESS)
1118 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1120 ISC_LIST_APPEND(name->list, rdataset, link);
1125 return (DNS_R_RECOVERABLE);
1126 return (ISC_R_SUCCESS);
1129 if (rdataset != NULL) {
1130 INSIST(!dns_rdataset_isassociated(rdataset));
1131 isc_mempool_put(msg->rdspool, rdataset);
1134 if (rdatalist != NULL)
1135 isc_mempool_put(msg->rdlpool, rdatalist);
1138 isc_mempool_put(msg->namepool, name);
1143 static isc_boolean_t
1144 update(dns_section_t section, dns_rdataclass_t rdclass) {
1145 if (section == DNS_SECTION_PREREQUISITE)
1146 return (ISC_TF(rdclass == dns_rdataclass_any ||
1147 rdclass == dns_rdataclass_none));
1148 if (section == DNS_SECTION_UPDATE)
1149 return (ISC_TF(rdclass == dns_rdataclass_any));
1154 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1155 dns_section_t sectionid, unsigned int options)
1158 unsigned int count, rdatalen;
1161 dns_offsets_t *offsets;
1162 dns_rdataset_t *rdataset;
1163 dns_rdatalist_t *rdatalist;
1164 isc_result_t result;
1165 dns_rdatatype_t rdtype, covers;
1166 dns_rdataclass_t rdclass;
1169 dns_namelist_t *section;
1170 isc_boolean_t free_name, free_rdataset;
1171 isc_boolean_t preserve_order, best_effort, seen_problem;
1172 isc_boolean_t issigzero;
1174 preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
1175 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1176 seen_problem = ISC_FALSE;
1178 for (count = 0; count < msg->counts[sectionid]; count++) {
1179 int recstart = source->current;
1180 isc_boolean_t skip_name_search, skip_type_search;
1182 section = &msg->sections[sectionid];
1184 skip_name_search = ISC_FALSE;
1185 skip_type_search = ISC_FALSE;
1186 free_rdataset = ISC_FALSE;
1188 name = isc_mempool_get(msg->namepool);
1190 return (ISC_R_NOMEMORY);
1191 free_name = ISC_TRUE;
1193 offsets = newoffsets(msg);
1194 if (offsets == NULL) {
1195 result = ISC_R_NOMEMORY;
1198 dns_name_init(name, *offsets);
1201 * Parse the name out of this packet.
1203 isc_buffer_remainingregion(source, &r);
1204 isc_buffer_setactive(source, r.length);
1205 result = getname(name, source, msg, dctx);
1206 if (result != ISC_R_SUCCESS)
1210 * Get type, class, ttl, and rdatalen. Verify that at least
1211 * rdatalen bytes remain. (Some of this is deferred to
1214 isc_buffer_remainingregion(source, &r);
1215 if (r.length < 2 + 2 + 4 + 2) {
1216 result = ISC_R_UNEXPECTEDEND;
1219 rdtype = isc_buffer_getuint16(source);
1220 rdclass = isc_buffer_getuint16(source);
1223 * If there was no question section, we may not yet have
1224 * established a class. Do so now.
1226 if (msg->rdclass_set == 0 &&
1227 rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
1228 rdtype != dns_rdatatype_tsig && /* class is ANY */
1229 rdtype != dns_rdatatype_tkey) { /* class is undefined */
1230 msg->rdclass = rdclass;
1231 msg->rdclass_set = 1;
1235 * If this class is different than the one in the question
1238 if (msg->opcode != dns_opcode_update
1239 && rdtype != dns_rdatatype_tsig
1240 && rdtype != dns_rdatatype_opt
1241 && rdtype != dns_rdatatype_key /* in a TKEY query */
1242 && rdtype != dns_rdatatype_sig /* SIG(0) */
1243 && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1244 && msg->rdclass != dns_rdataclass_any
1245 && msg->rdclass != rdclass)
1249 * If this is not a TKEY query/response then the KEY
1250 * record's class needs to match.
1252 if (msg->opcode != dns_opcode_update && !msg->tkey &&
1253 rdtype == dns_rdatatype_key &&
1254 msg->rdclass != dns_rdataclass_any &&
1255 msg->rdclass != rdclass)
1259 * Special type handling for TSIG, OPT, and TKEY.
1261 if (rdtype == dns_rdatatype_tsig) {
1263 * If it is a tsig, verify that it is in the
1264 * additional data section.
1266 if (sectionid != DNS_SECTION_ADDITIONAL ||
1267 rdclass != dns_rdataclass_any ||
1268 count != msg->counts[sectionid] - 1)
1270 msg->sigstart = recstart;
1271 skip_name_search = ISC_TRUE;
1272 skip_type_search = ISC_TRUE;
1273 } else if (rdtype == dns_rdatatype_opt) {
1275 * The name of an OPT record must be ".", it
1276 * must be in the additional data section, and
1277 * it must be the first OPT we've seen.
1279 if (!dns_name_equal(dns_rootname, name) ||
1280 sectionid != DNS_SECTION_ADDITIONAL ||
1283 skip_name_search = ISC_TRUE;
1284 skip_type_search = ISC_TRUE;
1285 } else if (rdtype == dns_rdatatype_tkey) {
1287 * A TKEY must be in the additional section if this
1288 * is a query, and the answer section if this is a
1289 * response. Unless it's a Win2000 client.
1291 * Its class is ignored.
1293 dns_section_t tkeysection;
1295 if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1296 tkeysection = DNS_SECTION_ADDITIONAL;
1298 tkeysection = DNS_SECTION_ANSWER;
1299 if (sectionid != tkeysection &&
1300 sectionid != DNS_SECTION_ANSWER)
1305 * ... now get ttl and rdatalen, and check buffer.
1307 ttl = isc_buffer_getuint32(source);
1308 rdatalen = isc_buffer_getuint16(source);
1309 r.length -= (2 + 2 + 4 + 2);
1310 if (r.length < rdatalen) {
1311 result = ISC_R_UNEXPECTEDEND;
1316 * Read the rdata from the wire format. Interpret the
1317 * rdata according to its actual class, even if it had a
1318 * DynDNS meta-class in the packet (unless this is a TSIG).
1319 * Then put the meta-class back into the finished rdata.
1321 rdata = newrdata(msg);
1322 if (rdata == NULL) {
1323 result = ISC_R_NOMEMORY;
1326 if (msg->opcode == dns_opcode_update &&
1327 update(sectionid, rdclass)) {
1328 if (rdatalen != 0) {
1329 result = DNS_R_FORMERR;
1333 * When the rdata is empty, the data pointer is
1334 * never dereferenced, but it must still be non-NULL.
1335 * Casting 1 rather than "" avoids warnings about
1336 * discarding the const attribute of a string,
1337 * for compilers that would warn about such things.
1339 rdata->data = (unsigned char *)1;
1341 rdata->rdclass = rdclass;
1342 rdata->type = rdtype;
1343 rdata->flags = DNS_RDATA_UPDATE;
1344 result = ISC_R_SUCCESS;
1345 } else if (rdclass == dns_rdataclass_none &&
1346 msg->opcode == dns_opcode_update &&
1347 sectionid == DNS_SECTION_UPDATE) {
1348 result = getrdata(source, msg, dctx, msg->rdclass,
1349 rdtype, rdatalen, rdata);
1351 result = getrdata(source, msg, dctx, rdclass,
1352 rdtype, rdatalen, rdata);
1353 if (result != ISC_R_SUCCESS)
1355 rdata->rdclass = rdclass;
1356 issigzero = ISC_FALSE;
1357 if (rdtype == dns_rdatatype_rrsig &&
1358 rdata->flags == 0) {
1359 covers = dns_rdata_covers(rdata);
1362 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1363 rdata->flags == 0) {
1364 covers = dns_rdata_covers(rdata);
1366 if (sectionid != DNS_SECTION_ADDITIONAL ||
1367 count != msg->counts[sectionid] - 1)
1369 msg->sigstart = recstart;
1370 skip_name_search = ISC_TRUE;
1371 skip_type_search = ISC_TRUE;
1372 issigzero = ISC_TRUE;
1374 if (msg->rdclass != dns_rdataclass_any &&
1375 msg->rdclass != rdclass)
1382 * Check the ownername of NSEC3 records
1384 if (rdtype == dns_rdatatype_nsec3 &&
1385 !dns_rdata_checkowner(name, msg->rdclass, rdtype,
1387 result = DNS_R_BADOWNERNAME;
1392 * If we are doing a dynamic update or this is a meta-type,
1393 * don't bother searching for a name, just append this one
1394 * to the end of the message.
1396 if (preserve_order || msg->opcode == dns_opcode_update ||
1398 if (rdtype != dns_rdatatype_opt &&
1399 rdtype != dns_rdatatype_tsig &&
1402 ISC_LIST_APPEND(*section, name, link);
1403 free_name = ISC_FALSE;
1407 * Run through the section, looking to see if this name
1408 * is already there. If it is found, put back the
1409 * allocated name since we no longer need it, and set
1410 * our name pointer to point to the name we found.
1412 result = findname(&name2, name, section);
1415 * If it is a new name, append to the section.
1417 if (result == ISC_R_SUCCESS) {
1418 isc_mempool_put(msg->namepool, name);
1421 ISC_LIST_APPEND(*section, name, link);
1423 free_name = ISC_FALSE;
1427 * Search name for the particular type and class.
1428 * Skip this stage if in update mode or this is a meta-type.
1430 if (preserve_order || msg->opcode == dns_opcode_update ||
1432 result = ISC_R_NOTFOUND;
1435 * If this is a type that can only occur in
1436 * the question section, fail.
1438 if (dns_rdatatype_questiononly(rdtype))
1442 result = dns_message_find(name, rdclass, rdtype,
1447 * If we found an rdataset that matches, we need to
1448 * append this rdata to that set. If we did not, we need
1449 * to create a new rdatalist, store the important bits there,
1450 * convert it to an rdataset, and link the latter to the name.
1451 * Yuck. When appending, make certain that the type isn't
1452 * a singleton type, such as SOA or CNAME.
1454 * Note that this check will be bypassed when preserving order,
1455 * the opcode is an update, or the type search is skipped.
1457 if (result == ISC_R_SUCCESS) {
1458 if (dns_rdatatype_issingleton(rdtype)) {
1460 dns_rdatalist_fromrdataset(rdataset,
1462 first = ISC_LIST_HEAD(rdatalist->rdata);
1463 INSIST(first != NULL);
1464 if (dns_rdata_compare(rdata, first) != 0)
1469 if (result == ISC_R_NOTFOUND) {
1470 rdataset = isc_mempool_get(msg->rdspool);
1471 if (rdataset == NULL) {
1472 result = ISC_R_NOMEMORY;
1475 free_rdataset = ISC_TRUE;
1477 rdatalist = newrdatalist(msg);
1478 if (rdatalist == NULL) {
1479 result = ISC_R_NOMEMORY;
1483 rdatalist->type = rdtype;
1484 rdatalist->covers = covers;
1485 rdatalist->rdclass = rdclass;
1486 rdatalist->ttl = ttl;
1487 ISC_LIST_INIT(rdatalist->rdata);
1489 dns_rdataset_init(rdataset);
1490 RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1494 if (rdtype != dns_rdatatype_opt &&
1495 rdtype != dns_rdatatype_tsig &&
1498 ISC_LIST_APPEND(name->list, rdataset, link);
1499 free_rdataset = ISC_FALSE;
1506 * Section 5.2 of RFC2181 says we should drop
1507 * nonauthoritative rrsets where the TTLs differ, but we
1508 * currently treat them the as if they were authoritative and
1511 if (ttl != rdataset->ttl) {
1512 rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1513 if (ttl < rdataset->ttl)
1514 rdataset->ttl = ttl;
1517 /* Append this rdata to the rdataset. */
1518 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1519 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1522 * If this is an OPT, SIG(0) or TSIG record, remember it.
1523 * Also, set the extended rcode for TSIG.
1525 * Note msg->opt, msg->sig0 and msg->tsig will only be
1526 * already set if best-effort parsing is enabled otherwise
1527 * there will only be at most one of each.
1529 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1532 msg->opt = rdataset;
1534 free_rdataset = ISC_FALSE;
1535 ercode = (dns_rcode_t)
1536 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1538 msg->rcode |= ercode;
1539 isc_mempool_put(msg->namepool, name);
1540 free_name = ISC_FALSE;
1541 } else if (issigzero && msg->sig0 == NULL) {
1542 msg->sig0 = rdataset;
1543 msg->sig0name = name;
1545 free_rdataset = ISC_FALSE;
1546 free_name = ISC_FALSE;
1547 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1548 msg->tsig = rdataset;
1549 msg->tsigname = name;
1550 /* Windows doesn't like TSIG names to be compressed. */
1551 msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1553 free_rdataset = ISC_FALSE;
1554 free_name = ISC_FALSE;
1559 isc_mempool_put(msg->namepool, name);
1561 isc_mempool_put(msg->rdspool, rdataset);
1562 free_name = free_rdataset = ISC_FALSE;
1564 INSIST(free_name == ISC_FALSE);
1565 INSIST(free_rdataset == ISC_FALSE);
1569 return (DNS_R_RECOVERABLE);
1570 return (ISC_R_SUCCESS);
1574 isc_mempool_put(msg->namepool, name);
1576 isc_mempool_put(msg->rdspool, rdataset);
1582 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1583 unsigned int options)
1586 dns_decompress_t dctx;
1588 isc_uint16_t tmpflags;
1589 isc_buffer_t origsource;
1590 isc_boolean_t seen_problem;
1591 isc_boolean_t ignore_tc;
1593 REQUIRE(DNS_MESSAGE_VALID(msg));
1594 REQUIRE(source != NULL);
1595 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1597 seen_problem = ISC_FALSE;
1598 ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1600 origsource = *source;
1603 msg->question_ok = 0;
1605 isc_buffer_remainingregion(source, &r);
1606 if (r.length < DNS_MESSAGE_HEADERLEN)
1607 return (ISC_R_UNEXPECTEDEND);
1609 msg->id = isc_buffer_getuint16(source);
1610 tmpflags = isc_buffer_getuint16(source);
1611 msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1612 >> DNS_MESSAGE_OPCODE_SHIFT);
1613 msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1614 msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1615 msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1616 msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1617 msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1618 msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1621 msg->state = DNS_SECTION_QUESTION;
1626 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1628 dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1630 ret = getquestions(source, msg, &dctx, options);
1631 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1633 if (ret == DNS_R_RECOVERABLE) {
1634 seen_problem = ISC_TRUE;
1635 ret = ISC_R_SUCCESS;
1637 if (ret != ISC_R_SUCCESS)
1639 msg->question_ok = 1;
1641 ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1642 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1644 if (ret == DNS_R_RECOVERABLE) {
1645 seen_problem = ISC_TRUE;
1646 ret = ISC_R_SUCCESS;
1648 if (ret != ISC_R_SUCCESS)
1651 ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1652 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1654 if (ret == DNS_R_RECOVERABLE) {
1655 seen_problem = ISC_TRUE;
1656 ret = ISC_R_SUCCESS;
1658 if (ret != ISC_R_SUCCESS)
1661 ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1662 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1664 if (ret == DNS_R_RECOVERABLE) {
1665 seen_problem = ISC_TRUE;
1666 ret = ISC_R_SUCCESS;
1668 if (ret != ISC_R_SUCCESS)
1671 isc_buffer_remainingregion(source, &r);
1672 if (r.length != 0) {
1673 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1674 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1675 "message has %u byte(s) of trailing garbage",
1680 if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1681 isc_buffer_usedregion(&origsource, &msg->saved);
1683 msg->saved.length = isc_buffer_usedlength(&origsource);
1684 msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1685 if (msg->saved.base == NULL)
1686 return (ISC_R_NOMEMORY);
1687 memmove(msg->saved.base, isc_buffer_base(&origsource),
1689 msg->free_saved = 1;
1692 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1693 return (DNS_R_RECOVERABLE);
1694 if (seen_problem == ISC_TRUE)
1695 return (DNS_R_RECOVERABLE);
1696 return (ISC_R_SUCCESS);
1700 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1701 isc_buffer_t *buffer)
1705 REQUIRE(DNS_MESSAGE_VALID(msg));
1706 REQUIRE(buffer != NULL);
1707 REQUIRE(msg->buffer == NULL);
1708 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1713 * Erase the contents of this buffer.
1715 isc_buffer_clear(buffer);
1718 * Make certain there is enough for at least the header in this
1721 isc_buffer_availableregion(buffer, &r);
1722 if (r.length < DNS_MESSAGE_HEADERLEN)
1723 return (ISC_R_NOSPACE);
1725 if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved)
1726 return (ISC_R_NOSPACE);
1729 * Reserve enough space for the header in this buffer.
1731 isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1733 msg->buffer = buffer;
1735 return (ISC_R_SUCCESS);
1739 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1742 REQUIRE(DNS_MESSAGE_VALID(msg));
1743 REQUIRE(buffer != NULL);
1744 REQUIRE(msg->buffer != NULL);
1747 * Ensure that the new buffer is empty, and has enough space to
1748 * hold the current contents.
1750 isc_buffer_clear(buffer);
1752 isc_buffer_availableregion(buffer, &rn);
1753 isc_buffer_usedregion(msg->buffer, &r);
1754 REQUIRE(rn.length > r.length);
1757 * Copy the contents from the old to the new buffer.
1759 isc_buffer_add(buffer, r.length);
1760 memmove(rn.base, r.base, r.length);
1762 msg->buffer = buffer;
1764 return (ISC_R_SUCCESS);
1768 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1769 REQUIRE(DNS_MESSAGE_VALID(msg));
1770 REQUIRE(space <= msg->reserved);
1772 msg->reserved -= space;
1776 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1779 REQUIRE(DNS_MESSAGE_VALID(msg));
1781 if (msg->buffer != NULL) {
1782 isc_buffer_availableregion(msg->buffer, &r);
1783 if (r.length < (space + msg->reserved))
1784 return (ISC_R_NOSPACE);
1787 msg->reserved += space;
1789 return (ISC_R_SUCCESS);
1792 static inline isc_boolean_t
1793 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1797 * If we are not rendering class IN, this ordering is bogus.
1799 if (rds->rdclass != dns_rdataclass_in)
1802 switch (rds->type) {
1803 case dns_rdatatype_a:
1804 case dns_rdatatype_aaaa:
1805 if (preferred_glue == rds->type)
1810 case dns_rdatatype_rrsig:
1811 case dns_rdatatype_dnskey:
1818 if (pass_needed >= pass)
1824 #ifdef ALLOW_FILTER_AAAA_ON_V4
1826 * Decide whether to not answer with an AAAA record and its RRSIG
1828 static inline isc_boolean_t
1829 norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options,
1830 dns_section_t sectionid)
1832 if (sectionid == DNS_SECTION_QUESTION)
1835 switch (rdataset->type) {
1836 case dns_rdatatype_ns:
1837 if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
1838 sectionid != DNS_SECTION_AUTHORITY)
1842 case dns_rdatatype_aaaa:
1843 if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
1847 case dns_rdatatype_rrsig:
1848 if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
1849 (rdataset->covers != dns_rdatatype_ns &&
1850 rdataset->covers != dns_rdatatype_aaaa))
1852 if ((rdataset->covers == dns_rdatatype_ns) &&
1853 (sectionid != DNS_SECTION_AUTHORITY))
1861 if (rdataset->rdclass != dns_rdataclass_in)
1869 renderset(dns_rdataset_t *rdataset, dns_name_t *owner_name,
1870 dns_compress_t *cctx, isc_buffer_t *target,
1871 unsigned int reserved, unsigned int options, unsigned int *countp)
1873 isc_result_t result;
1876 * Shrink the space in the buffer by the reserved amount.
1878 if (target->length - target->used < reserved)
1879 return (ISC_R_NOSPACE);
1881 target->length -= reserved;
1882 result = dns_rdataset_towire(rdataset, owner_name,
1883 cctx, target, options, countp);
1884 target->length += reserved;
1890 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1891 unsigned int options)
1893 dns_namelist_t *section;
1894 dns_name_t *name, *next_name;
1895 dns_rdataset_t *rdataset, *next_rdataset;
1896 unsigned int count, total;
1897 isc_result_t result;
1898 isc_buffer_t st; /* for rollbacks */
1900 isc_boolean_t partial = ISC_FALSE;
1901 unsigned int rd_options;
1902 dns_rdatatype_t preferred_glue = 0;
1904 REQUIRE(DNS_MESSAGE_VALID(msg));
1905 REQUIRE(msg->buffer != NULL);
1906 REQUIRE(VALID_NAMED_SECTION(sectionid));
1908 section = &msg->sections[sectionid];
1910 if ((sectionid == DNS_SECTION_ADDITIONAL)
1911 && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1912 if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1913 preferred_glue = dns_rdatatype_a;
1915 } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1916 preferred_glue = dns_rdatatype_aaaa;
1923 if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1926 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1929 * Shrink the space in the buffer by the reserved amount.
1931 if (msg->buffer->length - msg->buffer->used < msg->reserved)
1932 return (ISC_R_NOSPACE);
1933 msg->buffer->length -= msg->reserved;
1936 if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1940 * Render required glue first. Set TC if it won't fit.
1942 name = ISC_LIST_HEAD(*section);
1944 rdataset = ISC_LIST_HEAD(name->list);
1945 if (rdataset != NULL &&
1946 (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
1947 (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
1948 const void *order_arg = msg->order_arg;
1949 st = *(msg->buffer);
1952 result = dns_rdataset_towirepartial(rdataset,
1962 result = dns_rdataset_towiresorted(rdataset,
1971 if (partial && result == ISC_R_NOSPACE) {
1972 msg->flags |= DNS_MESSAGEFLAG_TC;
1973 msg->buffer->length += msg->reserved;
1974 msg->counts[sectionid] += total;
1977 if (result == ISC_R_NOSPACE)
1978 msg->flags |= DNS_MESSAGEFLAG_TC;
1979 if (result != ISC_R_SUCCESS) {
1980 INSIST(st.used < 65536);
1981 dns_compress_rollback(msg->cctx,
1982 (isc_uint16_t)st.used);
1983 *(msg->buffer) = st; /* rollback */
1984 msg->buffer->length += msg->reserved;
1985 msg->counts[sectionid] += total;
1988 rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
1993 name = ISC_LIST_HEAD(*section);
1995 msg->buffer->length += msg->reserved;
1996 msg->counts[sectionid] += total;
1997 return (ISC_R_SUCCESS);
2000 while (name != NULL) {
2001 next_name = ISC_LIST_NEXT(name, link);
2003 rdataset = ISC_LIST_HEAD(name->list);
2004 while (rdataset != NULL) {
2005 next_rdataset = ISC_LIST_NEXT(rdataset, link);
2007 if ((rdataset->attributes &
2008 DNS_RDATASETATTR_RENDERED) != 0)
2011 if (((options & DNS_MESSAGERENDER_ORDERED)
2013 && (sectionid == DNS_SECTION_ADDITIONAL)
2014 && wrong_priority(rdataset, pass,
2018 #ifdef ALLOW_FILTER_AAAA_ON_V4
2020 * Suppress AAAAs if asked and we are
2021 * not doing DNSSEC or are breaking DNSSEC.
2022 * Say so in the AD bit if we break DNSSEC.
2024 if (norender_rdataset(rdataset, options, sectionid)) {
2025 if (sectionid == DNS_SECTION_ANSWER ||
2026 sectionid == DNS_SECTION_AUTHORITY)
2027 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2028 if (OPTOUT(rdataset))
2029 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2034 st = *(msg->buffer);
2038 result = dns_rdataset_towirepartial(
2049 result = dns_rdataset_towiresorted(
2062 * If out of space, record stats on what we
2063 * rendered so far, and return that status.
2065 * XXXMLG Need to change this when
2066 * dns_rdataset_towire() can render partial
2067 * sets starting at some arbitrary point in the
2068 * set. This will include setting a bit in the
2069 * rdataset to indicate that a partial
2070 * rendering was done, and some state saved
2071 * somewhere (probably in the message struct)
2072 * to indicate where to continue from.
2074 if (partial && result == ISC_R_NOSPACE) {
2075 msg->buffer->length += msg->reserved;
2076 msg->counts[sectionid] += total;
2079 if (result != ISC_R_SUCCESS) {
2080 INSIST(st.used < 65536);
2081 dns_compress_rollback(msg->cctx,
2082 (isc_uint16_t)st.used);
2083 *(msg->buffer) = st; /* rollback */
2084 msg->buffer->length += msg->reserved;
2085 msg->counts[sectionid] += total;
2090 * If we have rendered non-validated data,
2091 * ensure that the AD bit is not set.
2093 if (rdataset->trust != dns_trust_secure &&
2094 (sectionid == DNS_SECTION_ANSWER ||
2095 sectionid == DNS_SECTION_AUTHORITY))
2096 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2097 if (OPTOUT(rdataset))
2098 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2100 rdataset->attributes |=
2101 DNS_RDATASETATTR_RENDERED;
2104 rdataset = next_rdataset;
2109 } while (--pass != 0);
2111 msg->buffer->length += msg->reserved;
2112 msg->counts[sectionid] += total;
2114 return (ISC_R_SUCCESS);
2118 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2122 REQUIRE(DNS_MESSAGE_VALID(msg));
2123 REQUIRE(target != NULL);
2125 isc_buffer_availableregion(target, &r);
2126 REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2128 isc_buffer_putuint16(target, msg->id);
2130 tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
2131 & DNS_MESSAGE_OPCODE_MASK);
2132 tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2133 tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2135 INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
2136 msg->counts[DNS_SECTION_ANSWER] < 65536 &&
2137 msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2138 msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2140 isc_buffer_putuint16(target, tmp);
2141 isc_buffer_putuint16(target,
2142 (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2143 isc_buffer_putuint16(target,
2144 (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2145 isc_buffer_putuint16(target,
2146 (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2147 isc_buffer_putuint16(target,
2148 (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2152 dns_message_renderend(dns_message_t *msg) {
2153 isc_buffer_t tmpbuf;
2158 REQUIRE(DNS_MESSAGE_VALID(msg));
2159 REQUIRE(msg->buffer != NULL);
2161 if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2163 * We have an extended rcode but are not using EDNS.
2165 return (DNS_R_FORMERR);
2169 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
2170 * clear all rdatasets from the message except for the question
2171 * before adding the OPT, TSIG or SIG(0). If the question doesn't
2172 * fit, don't include it.
2174 if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
2175 (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2179 msgresetnames(msg, DNS_SECTION_ANSWER);
2181 dns_message_renderreset(msg);
2183 isc_buffer_clear(msg->buffer);
2184 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2185 dns_compress_rollback(msg->cctx, 0);
2186 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2188 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2193 * If we've got an OPT record, render it.
2195 if (msg->opt != NULL) {
2196 dns_message_renderrelease(msg, msg->opt_reserved);
2197 msg->opt_reserved = 0;
2199 * Set the extended rcode.
2201 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2202 msg->opt->ttl |= ((msg->rcode << 20) &
2203 DNS_MESSAGE_EDNSRCODE_MASK);
2208 result = renderset(msg->opt, dns_rootname, msg->cctx,
2209 msg->buffer, msg->reserved, 0, &count);
2210 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2211 if (result != ISC_R_SUCCESS)
2216 * If we're adding a TSIG record, generate and render it.
2218 if (msg->tsigkey != NULL) {
2219 dns_message_renderrelease(msg, msg->sig_reserved);
2220 msg->sig_reserved = 0;
2221 result = dns_tsig_sign(msg);
2222 if (result != ISC_R_SUCCESS)
2225 result = renderset(msg->tsig, msg->tsigname, msg->cctx,
2226 msg->buffer, msg->reserved, 0, &count);
2227 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2228 if (result != ISC_R_SUCCESS)
2233 * If we're adding a SIG(0) record, generate and render it.
2235 if (msg->sig0key != NULL) {
2236 dns_message_renderrelease(msg, msg->sig_reserved);
2237 msg->sig_reserved = 0;
2238 result = dns_dnssec_signmessage(msg, msg->sig0key);
2239 if (result != ISC_R_SUCCESS)
2243 * Note: dns_rootname is used here, not msg->sig0name, since
2244 * the owner name of a SIG(0) is irrelevant, and will not
2245 * be set in a message being rendered.
2247 result = renderset(msg->sig0, dns_rootname, msg->cctx,
2248 msg->buffer, msg->reserved, 0, &count);
2249 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2250 if (result != ISC_R_SUCCESS)
2254 isc_buffer_usedregion(msg->buffer, &r);
2255 isc_buffer_init(&tmpbuf, r.base, r.length);
2257 dns_message_renderheader(msg, &tmpbuf);
2259 msg->buffer = NULL; /* forget about this buffer only on success XXX */
2261 return (ISC_R_SUCCESS);
2265 dns_message_renderreset(dns_message_t *msg) {
2268 dns_rdataset_t *rds;
2271 * Reset the message so that it may be rendered again.
2274 REQUIRE(DNS_MESSAGE_VALID(msg));
2275 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2279 for (i = 0; i < DNS_SECTION_MAX; i++) {
2280 msg->cursors[i] = NULL;
2282 for (name = ISC_LIST_HEAD(msg->sections[i]);
2284 name = ISC_LIST_NEXT(name, link)) {
2285 for (rds = ISC_LIST_HEAD(name->list);
2287 rds = ISC_LIST_NEXT(rds, link)) {
2288 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2292 if (msg->tsigname != NULL)
2293 dns_message_puttempname(msg, &msg->tsigname);
2294 if (msg->tsig != NULL) {
2295 dns_rdataset_disassociate(msg->tsig);
2296 dns_message_puttemprdataset(msg, &msg->tsig);
2298 if (msg->sig0 != NULL) {
2299 dns_rdataset_disassociate(msg->sig0);
2300 dns_message_puttemprdataset(msg, &msg->sig0);
2305 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2306 REQUIRE(DNS_MESSAGE_VALID(msg));
2307 REQUIRE(VALID_NAMED_SECTION(section));
2309 msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2311 if (msg->cursors[section] == NULL)
2312 return (ISC_R_NOMORE);
2314 return (ISC_R_SUCCESS);
2318 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2319 REQUIRE(DNS_MESSAGE_VALID(msg));
2320 REQUIRE(VALID_NAMED_SECTION(section));
2321 REQUIRE(msg->cursors[section] != NULL);
2323 msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2325 if (msg->cursors[section] == NULL)
2326 return (ISC_R_NOMORE);
2328 return (ISC_R_SUCCESS);
2332 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2335 REQUIRE(DNS_MESSAGE_VALID(msg));
2336 REQUIRE(VALID_NAMED_SECTION(section));
2337 REQUIRE(name != NULL && *name == NULL);
2338 REQUIRE(msg->cursors[section] != NULL);
2340 *name = msg->cursors[section];
2344 dns_message_findname(dns_message_t *msg, dns_section_t section,
2345 dns_name_t *target, dns_rdatatype_t type,
2346 dns_rdatatype_t covers, dns_name_t **name,
2347 dns_rdataset_t **rdataset)
2349 dns_name_t *foundname;
2350 isc_result_t result;
2353 * XXX These requirements are probably too intensive, especially
2354 * where things can be NULL, but as they are they ensure that if
2355 * something is NON-NULL, indicating that the caller expects it
2356 * to be filled in, that we can in fact fill it in.
2358 REQUIRE(msg != NULL);
2359 REQUIRE(VALID_SECTION(section));
2360 REQUIRE(target != NULL);
2361 REQUIRE(name == NULL || *name == NULL);
2363 if (type == dns_rdatatype_any) {
2364 REQUIRE(rdataset == NULL);
2366 REQUIRE(rdataset == NULL || *rdataset == NULL);
2369 result = findname(&foundname, target,
2370 &msg->sections[section]);
2372 if (result == ISC_R_NOTFOUND)
2373 return (DNS_R_NXDOMAIN);
2374 else if (result != ISC_R_SUCCESS)
2381 * And now look for the type.
2383 if (ISC_UNLIKELY(type == dns_rdatatype_any))
2384 return (ISC_R_SUCCESS);
2386 result = dns_message_findtype(foundname, type, covers, rdataset);
2387 if (result == ISC_R_NOTFOUND)
2388 return (DNS_R_NXRRSET);
2394 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2395 dns_section_t fromsection,
2396 dns_section_t tosection)
2398 REQUIRE(msg != NULL);
2399 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2400 REQUIRE(name != NULL);
2401 REQUIRE(VALID_NAMED_SECTION(fromsection));
2402 REQUIRE(VALID_NAMED_SECTION(tosection));
2405 * Unlink the name from the old section
2407 ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2408 ISC_LIST_APPEND(msg->sections[tosection], name, link);
2412 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2413 dns_section_t section)
2415 REQUIRE(msg != NULL);
2416 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2417 REQUIRE(name != NULL);
2418 REQUIRE(VALID_NAMED_SECTION(section));
2420 ISC_LIST_APPEND(msg->sections[section], name, link);
2424 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2425 dns_section_t section)
2427 REQUIRE(msg != NULL);
2428 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2429 REQUIRE(name != NULL);
2430 REQUIRE(VALID_NAMED_SECTION(section));
2432 ISC_LIST_UNLINK(msg->sections[section], name, link);
2436 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2437 REQUIRE(DNS_MESSAGE_VALID(msg));
2438 REQUIRE(item != NULL && *item == NULL);
2440 *item = isc_mempool_get(msg->namepool);
2442 return (ISC_R_NOMEMORY);
2443 dns_name_init(*item, NULL);
2445 return (ISC_R_SUCCESS);
2449 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2450 REQUIRE(DNS_MESSAGE_VALID(msg));
2451 REQUIRE(item != NULL && *item == NULL);
2453 *item = newoffsets(msg);
2455 return (ISC_R_NOMEMORY);
2457 return (ISC_R_SUCCESS);
2461 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2462 REQUIRE(DNS_MESSAGE_VALID(msg));
2463 REQUIRE(item != NULL && *item == NULL);
2465 *item = newrdata(msg);
2467 return (ISC_R_NOMEMORY);
2469 return (ISC_R_SUCCESS);
2473 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2474 REQUIRE(DNS_MESSAGE_VALID(msg));
2475 REQUIRE(item != NULL && *item == NULL);
2477 *item = isc_mempool_get(msg->rdspool);
2479 return (ISC_R_NOMEMORY);
2481 dns_rdataset_init(*item);
2483 return (ISC_R_SUCCESS);
2487 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2488 REQUIRE(DNS_MESSAGE_VALID(msg));
2489 REQUIRE(item != NULL && *item == NULL);
2491 *item = newrdatalist(msg);
2493 return (ISC_R_NOMEMORY);
2495 return (ISC_R_SUCCESS);
2499 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2500 REQUIRE(DNS_MESSAGE_VALID(msg));
2501 REQUIRE(item != NULL && *item != NULL);
2503 if (dns_name_dynamic(*item))
2504 dns_name_free(*item, msg->mctx);
2505 isc_mempool_put(msg->namepool, *item);
2510 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2511 REQUIRE(DNS_MESSAGE_VALID(msg));
2512 REQUIRE(item != NULL && *item != NULL);
2514 releaserdata(msg, *item);
2519 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2520 REQUIRE(DNS_MESSAGE_VALID(msg));
2521 REQUIRE(item != NULL && *item != NULL);
2523 REQUIRE(!dns_rdataset_isassociated(*item));
2524 isc_mempool_put(msg->rdspool, *item);
2529 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2530 REQUIRE(DNS_MESSAGE_VALID(msg));
2531 REQUIRE(item != NULL && *item != NULL);
2533 releaserdatalist(msg, *item);
2538 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2539 unsigned int *flagsp)
2542 isc_buffer_t buffer;
2546 REQUIRE(source != NULL);
2550 isc_buffer_remainingregion(&buffer, &r);
2551 if (r.length < DNS_MESSAGE_HEADERLEN)
2552 return (ISC_R_UNEXPECTEDEND);
2554 id = isc_buffer_getuint16(&buffer);
2555 flags = isc_buffer_getuint16(&buffer);
2556 flags &= DNS_MESSAGE_FLAG_MASK;
2563 return (ISC_R_SUCCESS);
2567 dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
2568 unsigned int clear_from;
2569 isc_result_t result;
2571 REQUIRE(DNS_MESSAGE_VALID(msg));
2572 REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2574 if (!msg->header_ok)
2575 return (DNS_R_FORMERR);
2576 if (msg->opcode != dns_opcode_query &&
2577 msg->opcode != dns_opcode_notify)
2578 want_question_section = ISC_FALSE;
2579 if (msg->opcode == dns_opcode_update)
2580 clear_from = DNS_SECTION_PREREQUISITE;
2581 else if (want_question_section) {
2582 if (!msg->question_ok)
2583 return (DNS_R_FORMERR);
2584 clear_from = DNS_SECTION_ANSWER;
2586 clear_from = DNS_SECTION_QUESTION;
2587 msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2588 msgresetnames(msg, clear_from);
2590 msgresetsigs(msg, ISC_TRUE);
2591 msginitprivate(msg);
2593 * We now clear most flags and then set QR, ensuring that the
2594 * reply's flags will be in a reasonable state.
2596 msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2597 msg->flags |= DNS_MESSAGEFLAG_QR;
2600 * This saves the query TSIG status, if the query was signed, and
2601 * reserves space in the reply for the TSIG.
2603 if (msg->tsigkey != NULL) {
2604 unsigned int otherlen = 0;
2605 msg->querytsigstatus = msg->tsigstatus;
2606 msg->tsigstatus = dns_rcode_noerror;
2607 if (msg->querytsigstatus == dns_tsigerror_badtime)
2609 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2610 result = dns_message_renderreserve(msg, msg->sig_reserved);
2611 if (result != ISC_R_SUCCESS) {
2612 msg->sig_reserved = 0;
2616 if (msg->saved.base != NULL) {
2617 msg->query.base = msg->saved.base;
2618 msg->query.length = msg->saved.length;
2619 msg->free_query = msg->free_saved;
2620 msg->saved.base = NULL;
2621 msg->saved.length = 0;
2622 msg->free_saved = 0;
2625 return (ISC_R_SUCCESS);
2629 dns_message_getopt(dns_message_t *msg) {
2632 * Get the OPT record for 'msg'.
2635 REQUIRE(DNS_MESSAGE_VALID(msg));
2641 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2642 isc_result_t result;
2643 dns_rdata_t rdata = DNS_RDATA_INIT;
2646 * Set the OPT record for 'msg'.
2650 * The space required for an OPT record is:
2652 * 1 byte for the name
2653 * 2 bytes for the type
2654 * 2 bytes for the class
2655 * 4 bytes for the ttl
2656 * 2 bytes for the rdata length
2657 * ---------------------------------
2660 * plus the length of the rdata.
2663 REQUIRE(DNS_MESSAGE_VALID(msg));
2664 REQUIRE(opt->type == dns_rdatatype_opt);
2665 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2666 REQUIRE(msg->state == DNS_SECTION_ANY);
2670 result = dns_rdataset_first(opt);
2671 if (result != ISC_R_SUCCESS)
2673 dns_rdataset_current(opt, &rdata);
2674 msg->opt_reserved = 11 + rdata.length;
2675 result = dns_message_renderreserve(msg, msg->opt_reserved);
2676 if (result != ISC_R_SUCCESS) {
2677 msg->opt_reserved = 0;
2683 return (ISC_R_SUCCESS);
2686 dns_rdataset_disassociate(opt);
2687 dns_message_puttemprdataset(msg, &opt);
2692 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2695 * Get the TSIG record and owner for 'msg'.
2698 REQUIRE(DNS_MESSAGE_VALID(msg));
2699 REQUIRE(owner == NULL || *owner == NULL);
2702 *owner = msg->tsigname;
2707 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2708 isc_result_t result;
2711 * Set the TSIG key for 'msg'
2714 REQUIRE(DNS_MESSAGE_VALID(msg));
2715 REQUIRE(msg->state == DNS_SECTION_ANY);
2717 if (key == NULL && msg->tsigkey != NULL) {
2718 if (msg->sig_reserved != 0) {
2719 dns_message_renderrelease(msg, msg->sig_reserved);
2720 msg->sig_reserved = 0;
2722 dns_tsigkey_detach(&msg->tsigkey);
2725 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2726 dns_tsigkey_attach(key, &msg->tsigkey);
2727 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2728 msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2729 result = dns_message_renderreserve(msg,
2731 if (result != ISC_R_SUCCESS) {
2732 dns_tsigkey_detach(&msg->tsigkey);
2733 msg->sig_reserved = 0;
2738 return (ISC_R_SUCCESS);
2742 dns_message_gettsigkey(dns_message_t *msg) {
2745 * Get the TSIG key for 'msg'
2748 REQUIRE(DNS_MESSAGE_VALID(msg));
2750 return (msg->tsigkey);
2754 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2755 dns_rdata_t *rdata = NULL;
2756 dns_rdatalist_t *list = NULL;
2757 dns_rdataset_t *set = NULL;
2758 isc_buffer_t *buf = NULL;
2760 isc_result_t result;
2762 REQUIRE(DNS_MESSAGE_VALID(msg));
2763 REQUIRE(msg->querytsig == NULL);
2765 if (querytsig == NULL)
2766 return (ISC_R_SUCCESS);
2768 result = dns_message_gettemprdata(msg, &rdata);
2769 if (result != ISC_R_SUCCESS)
2772 result = dns_message_gettemprdatalist(msg, &list);
2773 if (result != ISC_R_SUCCESS)
2775 result = dns_message_gettemprdataset(msg, &set);
2776 if (result != ISC_R_SUCCESS)
2779 isc_buffer_usedregion(querytsig, &r);
2780 result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2781 if (result != ISC_R_SUCCESS)
2783 isc_buffer_putmem(buf, r.base, r.length);
2784 isc_buffer_usedregion(buf, &r);
2785 dns_rdata_init(rdata);
2786 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2787 dns_message_takebuffer(msg, &buf);
2788 ISC_LIST_APPEND(list->rdata, rdata, link);
2789 result = dns_rdatalist_tordataset(list, set);
2790 if (result != ISC_R_SUCCESS)
2793 msg->querytsig = set;
2799 dns_message_puttemprdata(msg, &rdata);
2801 dns_message_puttemprdatalist(msg, &list);
2803 dns_message_puttemprdataset(msg, &set);
2804 return (ISC_R_NOMEMORY);
2808 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2809 isc_buffer_t **querytsig) {
2810 isc_result_t result;
2811 dns_rdata_t rdata = DNS_RDATA_INIT;
2814 REQUIRE(DNS_MESSAGE_VALID(msg));
2815 REQUIRE(mctx != NULL);
2816 REQUIRE(querytsig != NULL && *querytsig == NULL);
2818 if (msg->tsig == NULL)
2819 return (ISC_R_SUCCESS);
2821 result = dns_rdataset_first(msg->tsig);
2822 if (result != ISC_R_SUCCESS)
2824 dns_rdataset_current(msg->tsig, &rdata);
2825 dns_rdata_toregion(&rdata, &r);
2827 result = isc_buffer_allocate(mctx, querytsig, r.length);
2828 if (result != ISC_R_SUCCESS)
2830 isc_buffer_putmem(*querytsig, r.base, r.length);
2831 return (ISC_R_SUCCESS);
2835 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2838 * Get the SIG(0) record for 'msg'.
2841 REQUIRE(DNS_MESSAGE_VALID(msg));
2842 REQUIRE(owner == NULL || *owner == NULL);
2844 if (msg->sig0 != NULL && owner != NULL) {
2845 /* If dns_message_getsig0 is called on a rendered message
2846 * after the SIG(0) has been applied, we need to return the
2847 * root name, not NULL.
2849 if (msg->sig0name == NULL)
2850 *owner = dns_rootname;
2852 *owner = msg->sig0name;
2858 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2861 isc_result_t result;
2864 * Set the SIG(0) key for 'msg'
2868 * The space required for an SIG(0) record is:
2870 * 1 byte for the name
2871 * 2 bytes for the type
2872 * 2 bytes for the class
2873 * 4 bytes for the ttl
2874 * 2 bytes for the type covered
2875 * 1 byte for the algorithm
2876 * 1 bytes for the labels
2877 * 4 bytes for the original ttl
2878 * 4 bytes for the signature expiration
2879 * 4 bytes for the signature inception
2880 * 2 bytes for the key tag
2881 * n bytes for the signer's name
2882 * x bytes for the signature
2883 * ---------------------------------
2886 REQUIRE(DNS_MESSAGE_VALID(msg));
2887 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2888 REQUIRE(msg->state == DNS_SECTION_ANY);
2891 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2892 dns_name_toregion(dst_key_name(key), &r);
2893 result = dst_key_sigsize(key, &x);
2894 if (result != ISC_R_SUCCESS) {
2895 msg->sig_reserved = 0;
2898 msg->sig_reserved = 27 + r.length + x;
2899 result = dns_message_renderreserve(msg, msg->sig_reserved);
2900 if (result != ISC_R_SUCCESS) {
2901 msg->sig_reserved = 0;
2906 return (ISC_R_SUCCESS);
2910 dns_message_getsig0key(dns_message_t *msg) {
2913 * Get the SIG(0) key for 'msg'
2916 REQUIRE(DNS_MESSAGE_VALID(msg));
2918 return (msg->sig0key);
2922 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2923 REQUIRE(DNS_MESSAGE_VALID(msg));
2924 REQUIRE(buffer != NULL);
2925 REQUIRE(ISC_BUFFER_VALID(*buffer));
2927 ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2932 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
2933 isc_result_t result = ISC_R_SUCCESS;
2934 dns_rdata_t rdata = DNS_RDATA_INIT;
2936 REQUIRE(DNS_MESSAGE_VALID(msg));
2937 REQUIRE(signer != NULL);
2938 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2940 if (msg->tsig == NULL && msg->sig0 == NULL)
2941 return (ISC_R_NOTFOUND);
2943 if (msg->verify_attempted == 0)
2944 return (DNS_R_NOTVERIFIEDYET);
2946 if (!dns_name_hasbuffer(signer)) {
2947 isc_buffer_t *dynbuf = NULL;
2948 result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
2949 if (result != ISC_R_SUCCESS)
2951 dns_name_setbuffer(signer, dynbuf);
2952 dns_message_takebuffer(msg, &dynbuf);
2955 if (msg->sig0 != NULL) {
2956 dns_rdata_sig_t sig;
2958 result = dns_rdataset_first(msg->sig0);
2959 INSIST(result == ISC_R_SUCCESS);
2960 dns_rdataset_current(msg->sig0, &rdata);
2962 result = dns_rdata_tostruct(&rdata, &sig, NULL);
2963 if (result != ISC_R_SUCCESS)
2966 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
2967 result = ISC_R_SUCCESS;
2969 result = DNS_R_SIGINVALID;
2970 dns_name_clone(&sig.signer, signer);
2971 dns_rdata_freestruct(&sig);
2973 dns_name_t *identity;
2974 dns_rdata_any_tsig_t tsig;
2976 result = dns_rdataset_first(msg->tsig);
2977 INSIST(result == ISC_R_SUCCESS);
2978 dns_rdataset_current(msg->tsig, &rdata);
2980 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2981 INSIST(result == ISC_R_SUCCESS);
2982 if (msg->tsigstatus != dns_rcode_noerror)
2983 result = DNS_R_TSIGVERIFYFAILURE;
2984 else if (tsig.error != dns_rcode_noerror)
2985 result = DNS_R_TSIGERRORSET;
2987 result = ISC_R_SUCCESS;
2988 dns_rdata_freestruct(&tsig);
2990 if (msg->tsigkey == NULL) {
2992 * If msg->tsigstatus & tsig.error are both
2993 * dns_rcode_noerror, the message must have been
2994 * verified, which means msg->tsigkey will be
2997 INSIST(result != ISC_R_SUCCESS);
2999 identity = dns_tsigkey_identity(msg->tsigkey);
3000 if (identity == NULL) {
3001 if (result == ISC_R_SUCCESS)
3002 result = DNS_R_NOIDENTITY;
3003 identity = &msg->tsigkey->name;
3005 dns_name_clone(identity, signer);
3013 dns_message_resetsig(dns_message_t *msg) {
3014 REQUIRE(DNS_MESSAGE_VALID(msg));
3015 msg->verified_sig = 0;
3016 msg->verify_attempted = 0;
3017 msg->tsigstatus = dns_rcode_noerror;
3018 msg->sig0status = dns_rcode_noerror;
3019 msg->timeadjust = 0;
3020 if (msg->tsigkey != NULL) {
3021 dns_tsigkey_detach(&msg->tsigkey);
3022 msg->tsigkey = NULL;
3027 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
3028 dns_message_resetsig(msg);
3029 return (dns_message_checksig(msg, view));
3032 #ifdef SKAN_MSG_DEBUG
3034 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
3035 dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
3036 dns_rdata_any_tsig_t querytsig;
3037 isc_result_t result;
3039 if (msg->tsig != NULL) {
3040 result = dns_rdataset_first(msg->tsig);
3041 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3042 dns_rdataset_current(msg->tsig, &querytsigrdata);
3043 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3044 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3045 hexdump(txt1, "TSIG", querytsig.signature,
3049 if (msg->querytsig != NULL) {
3050 result = dns_rdataset_first(msg->querytsig);
3051 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3052 dns_rdataset_current(msg->querytsig, &querytsigrdata);
3053 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3054 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3055 hexdump(txt1, "QUERYTSIG", querytsig.signature,
3062 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
3063 isc_buffer_t b, msgb;
3065 REQUIRE(DNS_MESSAGE_VALID(msg));
3067 if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
3068 return (ISC_R_SUCCESS);
3070 INSIST(msg->saved.base != NULL);
3071 isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
3072 isc_buffer_add(&msgb, msg->saved.length);
3073 if (msg->tsigkey != NULL || msg->tsig != NULL) {
3074 #ifdef SKAN_MSG_DEBUG
3075 dns_message_dumpsig(msg, "dns_message_checksig#1");
3078 return (dns_view_checksig(view, &msgb, msg));
3080 return (dns_tsig_verify(&msgb, msg, NULL, NULL));
3082 dns_rdata_t rdata = DNS_RDATA_INIT;
3083 dns_rdata_sig_t sig;
3084 dns_rdataset_t keyset;
3085 isc_result_t result;
3087 result = dns_rdataset_first(msg->sig0);
3088 INSIST(result == ISC_R_SUCCESS);
3089 dns_rdataset_current(msg->sig0, &rdata);
3092 * This can occur when the message is a dynamic update, since
3093 * the rdata length checking is relaxed. This should not
3094 * happen in a well-formed message, since the SIG(0) is only
3095 * looked for in the additional section, and the dynamic update
3096 * meta-records are in the prerequisite and update sections.
3098 if (rdata.length == 0)
3099 return (ISC_R_UNEXPECTEDEND);
3101 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
3102 if (result != ISC_R_SUCCESS)
3105 dns_rdataset_init(&keyset);
3107 return (DNS_R_KEYUNAUTHORIZED);
3108 result = dns_view_simplefind(view, &sig.signer,
3109 dns_rdatatype_key /* SIG(0) */,
3110 0, 0, ISC_FALSE, &keyset, NULL);
3112 if (result != ISC_R_SUCCESS) {
3113 /* XXXBEW Should possibly create a fetch here */
3114 result = DNS_R_KEYUNAUTHORIZED;
3116 } else if (keyset.trust < dns_trust_secure) {
3117 /* XXXBEW Should call a validator here */
3118 result = DNS_R_KEYUNAUTHORIZED;
3121 result = dns_rdataset_first(&keyset);
3122 INSIST(result == ISC_R_SUCCESS);
3124 result == ISC_R_SUCCESS;
3125 result = dns_rdataset_next(&keyset))
3127 dst_key_t *key = NULL;
3129 dns_rdata_reset(&rdata);
3130 dns_rdataset_current(&keyset, &rdata);
3131 isc_buffer_init(&b, rdata.data, rdata.length);
3132 isc_buffer_add(&b, rdata.length);
3134 result = dst_key_fromdns(&sig.signer, rdata.rdclass,
3135 &b, view->mctx, &key);
3136 if (result != ISC_R_SUCCESS)
3138 if (dst_key_alg(key) != sig.algorithm ||
3139 dst_key_id(key) != sig.keyid ||
3140 !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3141 dst_key_proto(key) == DNS_KEYPROTO_ANY))
3146 result = dns_dnssec_verifymessage(&msgb, msg, key);
3148 if (result == ISC_R_SUCCESS)
3151 if (result == ISC_R_NOMORE)
3152 result = DNS_R_KEYUNAUTHORIZED;
3155 if (dns_rdataset_isassociated(&keyset))
3156 dns_rdataset_disassociate(&keyset);
3157 dns_rdata_freestruct(&sig);
3163 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3164 const dns_master_style_t *style,
3165 dns_messagetextflag_t flags,
3166 isc_buffer_t *target) {
3167 dns_name_t *name, empty_name;
3168 dns_rdataset_t *rdataset;
3169 isc_result_t result;
3170 isc_boolean_t seensoa = ISC_FALSE;
3172 REQUIRE(DNS_MESSAGE_VALID(msg));
3173 REQUIRE(target != NULL);
3174 REQUIRE(VALID_SECTION(section));
3176 if (ISC_LIST_EMPTY(msg->sections[section]))
3177 return (ISC_R_SUCCESS);
3179 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3180 ADD_STRING(target, ";; ");
3181 if (msg->opcode != dns_opcode_update) {
3182 ADD_STRING(target, sectiontext[section]);
3184 ADD_STRING(target, updsectiontext[section]);
3186 ADD_STRING(target, " SECTION:\n");
3189 dns_name_init(&empty_name, NULL);
3190 result = dns_message_firstname(msg, section);
3191 if (result != ISC_R_SUCCESS) {
3196 dns_message_currentname(msg, section, &name);
3197 for (rdataset = ISC_LIST_HEAD(name->list);
3199 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3200 if (section == DNS_SECTION_ANSWER &&
3201 rdataset->type == dns_rdatatype_soa) {
3202 if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
3205 (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
3209 if (section == DNS_SECTION_QUESTION) {
3210 ADD_STRING(target, ";");
3211 result = dns_master_questiontotext(name,
3216 result = dns_master_rdatasettotext(name,
3221 if (result != ISC_R_SUCCESS)
3224 result = dns_message_nextname(msg, section);
3225 } while (result == ISC_R_SUCCESS);
3226 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3227 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3228 ADD_STRING(target, "\n");
3229 if (result == ISC_R_NOMORE)
3230 result = ISC_R_SUCCESS;
3235 dns_message_pseudosectiontotext(dns_message_t *msg,
3236 dns_pseudosection_t section,
3237 const dns_master_style_t *style,
3238 dns_messagetextflag_t flags,
3239 isc_buffer_t *target)
3241 dns_rdataset_t *ps = NULL;
3242 dns_name_t *name = NULL;
3243 isc_result_t result;
3244 char buf[sizeof("1234567890")];
3247 isc_buffer_t optbuf;
3248 isc_uint16_t optcode, optlen;
3249 unsigned char *optdata;
3251 REQUIRE(DNS_MESSAGE_VALID(msg));
3252 REQUIRE(target != NULL);
3253 REQUIRE(VALID_PSEUDOSECTION(section));
3256 case DNS_PSEUDOSECTION_OPT:
3257 ps = dns_message_getopt(msg);
3259 return (ISC_R_SUCCESS);
3260 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3261 ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3262 ADD_STRING(target, "; EDNS: version: ");
3263 snprintf(buf, sizeof(buf), "%u",
3264 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3265 ADD_STRING(target, buf);
3266 ADD_STRING(target, ", flags:");
3267 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3268 ADD_STRING(target, " do");
3269 mbz = ps->ttl & 0xffff;
3270 mbz &= ~DNS_MESSAGEEXTFLAG_DO; /* Known Flags. */
3272 ADD_STRING(target, "; MBZ: ");
3273 snprintf(buf, sizeof(buf), "0x%.4x", mbz);
3274 ADD_STRING(target, buf);
3275 ADD_STRING(target, ", udp: ");
3277 ADD_STRING(target, "; udp: ");
3278 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3279 ADD_STRING(target, buf);
3281 result = dns_rdataset_first(ps);
3282 if (result != ISC_R_SUCCESS)
3283 return (ISC_R_SUCCESS);
3285 /* Print EDNS info, if any */
3286 dns_rdata_init(&rdata);
3287 dns_rdataset_current(ps, &rdata);
3289 isc_buffer_init(&optbuf, rdata.data, rdata.length);
3290 isc_buffer_add(&optbuf, rdata.length);
3291 while (isc_buffer_remaininglength(&optbuf) != 0) {
3292 INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3293 optcode = isc_buffer_getuint16(&optbuf);
3294 optlen = isc_buffer_getuint16(&optbuf);
3295 INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3297 if (optcode == DNS_OPT_NSID) {
3298 ADD_STRING(target, "; NSID");
3299 } else if (optcode == DNS_OPT_COOKIE) {
3300 ADD_STRING(target, "; COOKIE");
3301 } else if (optcode == DNS_OPT_EXPIRE) {
3304 secs = isc_buffer_getuint32(&optbuf);
3305 ADD_STRING(target, "; EXPIRE: ");
3306 snprintf(buf, sizeof(buf), "%u", secs);
3307 ADD_STRING(target, buf);
3308 ADD_STRING(target, " (");
3309 result = dns_ttl_totext(secs,
3312 if (result != ISC_R_SUCCESS)
3314 ADD_STRING(target, ")\n");
3317 ADD_STRING(target, "; EXPIRE");
3318 } else if (optcode == DNS_OPT_PAD) {
3319 ADD_STRING(target, "; PAD");
3321 ADD_STRING(target, "; OPT=");
3322 snprintf(buf, sizeof(buf), "%u", optcode);
3323 ADD_STRING(target, buf);
3328 ADD_STRING(target, ": ");
3330 optdata = isc_buffer_current(&optbuf);
3331 for (i = 0; i < optlen; i++) {
3334 case DNS_OPT_COOKIE:
3341 snprintf(buf, sizeof(buf), "%02x%s",
3343 ADD_STRING(target, buf);
3346 isc_buffer_forward(&optbuf, optlen);
3348 if (optcode == DNS_OPT_COOKIE) {
3349 ADD_STRING(target, "\n");
3354 * For non-COOKIE options, add a printable
3357 for (i = 0; i < optlen; i++) {
3358 ADD_STRING(target, " (");
3359 if (!isc_buffer_availablelength(target))
3360 return (ISC_R_NOSPACE);
3361 if (isprint(optdata[i]))
3362 isc_buffer_putmem(target,
3366 isc_buffer_putstr(target, ".");
3367 ADD_STRING(target, ")");
3370 ADD_STRING(target, "\n");
3372 return (ISC_R_SUCCESS);
3373 case DNS_PSEUDOSECTION_TSIG:
3374 ps = dns_message_gettsig(msg, &name);
3376 return (ISC_R_SUCCESS);
3377 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3378 ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
3379 result = dns_master_rdatasettotext(name, ps, style, target);
3380 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3381 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3382 ADD_STRING(target, "\n");
3384 case DNS_PSEUDOSECTION_SIG0:
3385 ps = dns_message_getsig0(msg, &name);
3387 return (ISC_R_SUCCESS);
3388 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3389 ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3390 result = dns_master_rdatasettotext(name, ps, style, target);
3391 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3392 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3393 ADD_STRING(target, "\n");
3396 return (ISC_R_UNEXPECTED);
3400 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3401 dns_messagetextflag_t flags, isc_buffer_t *target)
3403 char buf[sizeof("1234567890")];
3404 isc_result_t result;
3406 REQUIRE(DNS_MESSAGE_VALID(msg));
3407 REQUIRE(target != NULL);
3409 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
3410 ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
3411 ADD_STRING(target, opcodetext[msg->opcode]);
3412 ADD_STRING(target, ", status: ");
3413 result = dns_rcode_totext(msg->rcode, target);
3414 if (result != ISC_R_SUCCESS)
3416 ADD_STRING(target, ", id: ");
3417 snprintf(buf, sizeof(buf), "%6u", msg->id);
3418 ADD_STRING(target, buf);
3419 ADD_STRING(target, "\n;; flags:");
3420 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3421 ADD_STRING(target, " qr");
3422 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3423 ADD_STRING(target, " aa");
3424 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3425 ADD_STRING(target, " tc");
3426 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3427 ADD_STRING(target, " rd");
3428 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3429 ADD_STRING(target, " ra");
3430 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3431 ADD_STRING(target, " ad");
3432 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
3433 ADD_STRING(target, " cd");
3435 * The final unnamed flag must be zero.
3437 if ((msg->flags & 0x0040U) != 0)
3438 ADD_STRING(target, "; MBZ: 0x4");
3439 if (msg->opcode != dns_opcode_update) {
3440 ADD_STRING(target, "; QUESTION: ");
3442 ADD_STRING(target, "; ZONE: ");
3444 snprintf(buf, sizeof(buf), "%1u",
3445 msg->counts[DNS_SECTION_QUESTION]);
3446 ADD_STRING(target, buf);
3447 if (msg->opcode != dns_opcode_update) {
3448 ADD_STRING(target, ", ANSWER: ");
3450 ADD_STRING(target, ", PREREQ: ");
3452 snprintf(buf, sizeof(buf), "%1u",
3453 msg->counts[DNS_SECTION_ANSWER]);
3454 ADD_STRING(target, buf);
3455 if (msg->opcode != dns_opcode_update) {
3456 ADD_STRING(target, ", AUTHORITY: ");
3458 ADD_STRING(target, ", UPDATE: ");
3460 snprintf(buf, sizeof(buf), "%1u",
3461 msg->counts[DNS_SECTION_AUTHORITY]);
3462 ADD_STRING(target, buf);
3463 ADD_STRING(target, ", ADDITIONAL: ");
3464 snprintf(buf, sizeof(buf), "%1u",
3465 msg->counts[DNS_SECTION_ADDITIONAL]);
3466 ADD_STRING(target, buf);
3467 ADD_STRING(target, "\n");
3469 result = dns_message_pseudosectiontotext(msg,
3470 DNS_PSEUDOSECTION_OPT,
3471 style, flags, target);
3472 if (result != ISC_R_SUCCESS)
3475 result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
3476 style, flags, target);
3477 if (result != ISC_R_SUCCESS)
3479 result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
3480 style, flags, target);
3481 if (result != ISC_R_SUCCESS)
3483 result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
3484 style, flags, target);
3485 if (result != ISC_R_SUCCESS)
3487 result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
3488 style, flags, target);
3489 if (result != ISC_R_SUCCESS)
3492 result = dns_message_pseudosectiontotext(msg,
3493 DNS_PSEUDOSECTION_TSIG,
3494 style, flags, target);
3495 if (result != ISC_R_SUCCESS)
3498 result = dns_message_pseudosectiontotext(msg,
3499 DNS_PSEUDOSECTION_SIG0,
3500 style, flags, target);
3501 if (result != ISC_R_SUCCESS)
3504 return (ISC_R_SUCCESS);
3508 dns_message_getrawmessage(dns_message_t *msg) {
3509 REQUIRE(DNS_MESSAGE_VALID(msg));
3510 return (&msg->saved);
3514 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3515 const void *order_arg)
3517 REQUIRE(DNS_MESSAGE_VALID(msg));
3519 msg->order_arg = order_arg;
3523 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3524 REQUIRE(DNS_MESSAGE_VALID(msg));
3525 msg->timeadjust = timeadjust;
3529 dns_message_gettimeadjust(dns_message_t *msg) {
3530 REQUIRE(DNS_MESSAGE_VALID(msg));
3531 return (msg->timeadjust);
3535 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3537 REQUIRE(opcode < 16);
3539 if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
3540 return (ISC_R_NOSPACE);
3541 isc_buffer_putstr(target, opcodetext[opcode]);
3542 return (ISC_R_SUCCESS);
3546 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
3547 unsigned int version, isc_uint16_t udpsize,
3548 unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
3550 dns_rdataset_t *rdataset = NULL;
3551 dns_rdatalist_t *rdatalist = NULL;
3552 dns_rdata_t *rdata = NULL;
3553 isc_result_t result;
3554 unsigned int len = 0, i;
3556 REQUIRE(DNS_MESSAGE_VALID(message));
3557 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
3559 result = dns_message_gettemprdatalist(message, &rdatalist);
3560 if (result != ISC_R_SUCCESS)
3562 result = dns_message_gettemprdata(message, &rdata);
3563 if (result != ISC_R_SUCCESS)
3565 result = dns_message_gettemprdataset(message, &rdataset);
3566 if (result != ISC_R_SUCCESS)
3568 dns_rdataset_init(rdataset);
3570 rdatalist->type = dns_rdatatype_opt;
3573 * Set Maximum UDP buffer size.
3575 rdatalist->rdclass = udpsize;
3578 * Set EXTENDED-RCODE and Z to 0.
3580 rdatalist->ttl = (version << 16);
3581 rdatalist->ttl |= (flags & 0xffff);
3584 * Set EDNS options if applicable
3587 isc_buffer_t *buf = NULL;
3588 for (i = 0; i < count; i++)
3589 len += ednsopts[i].length + 4;
3591 if (len > 0xffffU) {
3592 result = ISC_R_NOSPACE;
3596 result = isc_buffer_allocate(message->mctx, &buf, len);
3597 if (result != ISC_R_SUCCESS)
3600 for (i = 0; i < count; i++) {
3601 isc_buffer_putuint16(buf, ednsopts[i].code);
3602 isc_buffer_putuint16(buf, ednsopts[i].length);
3603 isc_buffer_putmem(buf, ednsopts[i].value,
3604 ednsopts[i].length);
3606 rdata->data = isc_buffer_base(buf);
3607 rdata->length = len;
3608 dns_message_takebuffer(message, &buf);
3614 rdata->rdclass = rdatalist->rdclass;
3615 rdata->type = rdatalist->type;
3618 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
3619 result = dns_rdatalist_tordataset(rdatalist, rdataset);
3620 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3622 *rdatasetp = rdataset;
3623 return (ISC_R_SUCCESS);
3627 dns_message_puttemprdata(message, &rdata);
3628 if (rdataset != NULL)
3629 dns_message_puttemprdataset(message, &rdataset);
3630 if (rdatalist != NULL)
3631 dns_message_puttemprdatalist(message, &rdatalist);
3636 dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) {
3638 REQUIRE(DNS_MESSAGE_VALID(msg));
3639 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
3640 REQUIRE(msg->state == DNS_SECTION_ANY);
3641 REQUIRE(msg->rdclass_set == 0);
3643 msg->rdclass = rdclass;
3644 msg->rdclass_set = 1;