2 * Copyright (C) 2004-2014 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.
29 #include <isc/buffer.h>
31 #include <isc/print.h>
32 #include <isc/string.h> /* Required for HP/UX (and others?) */
35 #include <dns/dnssec.h>
36 #include <dns/keyvalues.h>
38 #include <dns/masterdump.h>
39 #include <dns/message.h>
40 #include <dns/opcode.h>
41 #include <dns/rdata.h>
42 #include <dns/rdatalist.h>
43 #include <dns/rdataset.h>
44 #include <dns/rdatastruct.h>
45 #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[] = {
149 static const char *rcodetext[] = {
171 * "helper" type, which consists of a block of some type, and is linkable.
172 * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
173 * size, or the allocated elements will not be aligned correctly.
175 struct dns_msgblock {
177 unsigned int remaining;
178 ISC_LINK(dns_msgblock_t) link;
179 }; /* dynamically sized */
181 static inline dns_msgblock_t *
182 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
184 #define msgblock_get(block, type) \
185 ((type *)msgblock_internalget(block, sizeof(type)))
188 msgblock_internalget(dns_msgblock_t *, unsigned int);
191 msgblock_reset(dns_msgblock_t *);
194 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
197 * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory
198 * is free, return NULL.
200 static inline dns_msgblock_t *
201 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
204 dns_msgblock_t *block;
207 length = sizeof(dns_msgblock_t) + (sizeof_type * count);
209 block = isc_mem_get(mctx, length);
213 block->count = count;
214 block->remaining = count;
216 ISC_LINK_INIT(block, link);
222 * Return an element from the msgblock. If no more are available, return
226 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
229 if (block == NULL || block->remaining == 0)
234 ptr = (((unsigned char *)block)
235 + sizeof(dns_msgblock_t)
236 + (sizeof_type * block->remaining));
242 msgblock_reset(dns_msgblock_t *block) {
243 block->remaining = block->count;
247 * Release memory associated with a message block.
250 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
254 length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
256 isc_mem_put(mctx, block, length);
260 * Allocate a new dynamic buffer, and attach it to this message as the
261 * "current" buffer. (which is always the last on the list, for our
264 static inline isc_result_t
265 newbuffer(dns_message_t *msg, unsigned int size) {
267 isc_buffer_t *dynbuf;
270 result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
271 if (result != ISC_R_SUCCESS)
272 return (ISC_R_NOMEMORY);
274 ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
275 return (ISC_R_SUCCESS);
278 static inline isc_buffer_t *
279 currentbuffer(dns_message_t *msg) {
280 isc_buffer_t *dynbuf;
282 dynbuf = ISC_LIST_TAIL(msg->scratchpad);
283 INSIST(dynbuf != NULL);
289 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
290 ISC_LIST_PREPEND(msg->freerdata, rdata, link);
293 static inline dns_rdata_t *
294 newrdata(dns_message_t *msg) {
295 dns_msgblock_t *msgblock;
298 rdata = ISC_LIST_HEAD(msg->freerdata);
300 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
304 msgblock = ISC_LIST_TAIL(msg->rdatas);
305 rdata = msgblock_get(msgblock, dns_rdata_t);
307 msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
309 if (msgblock == NULL)
312 ISC_LIST_APPEND(msg->rdatas, msgblock, link);
314 rdata = msgblock_get(msgblock, dns_rdata_t);
317 dns_rdata_init(rdata);
322 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
323 ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
326 static inline dns_rdatalist_t *
327 newrdatalist(dns_message_t *msg) {
328 dns_msgblock_t *msgblock;
329 dns_rdatalist_t *rdatalist;
331 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
332 if (rdatalist != NULL) {
333 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
337 msgblock = ISC_LIST_TAIL(msg->rdatalists);
338 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
339 if (rdatalist == NULL) {
340 msgblock = msgblock_allocate(msg->mctx,
341 sizeof(dns_rdatalist_t),
343 if (msgblock == NULL)
346 ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
348 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
354 static inline dns_offsets_t *
355 newoffsets(dns_message_t *msg) {
356 dns_msgblock_t *msgblock;
357 dns_offsets_t *offsets;
359 msgblock = ISC_LIST_TAIL(msg->offsets);
360 offsets = msgblock_get(msgblock, dns_offsets_t);
361 if (offsets == NULL) {
362 msgblock = msgblock_allocate(msg->mctx,
363 sizeof(dns_offsets_t),
365 if (msgblock == NULL)
368 ISC_LIST_APPEND(msg->offsets, msgblock, link);
370 offsets = msgblock_get(msgblock, dns_offsets_t);
377 msginitheader(dns_message_t *m) {
386 msginitprivate(dns_message_t *m) {
389 for (i = 0; i < DNS_SECTION_MAX; i++) {
390 m->cursors[i] = NULL;
398 m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */
406 msginittsig(dns_message_t *m) {
407 m->tsigstatus = dns_rcode_noerror;
408 m->querytsigstatus = dns_rcode_noerror;
413 m->sig0status = dns_rcode_noerror;
418 * Init elements to default state. Used both when allocating a new element
419 * and when resetting one.
422 msginit(dns_message_t *m) {
428 m->tcp_continuation = 0;
430 m->verify_attempted = 0;
433 m->query.base = NULL;
436 m->saved.base = NULL;
445 msgresetnames(dns_message_t *msg, unsigned int first_section) {
447 dns_name_t *name, *next_name;
448 dns_rdataset_t *rds, *next_rds;
451 * Clean up name lists by calling the rdataset disassociate function.
453 for (i = first_section; i < DNS_SECTION_MAX; i++) {
454 name = ISC_LIST_HEAD(msg->sections[i]);
455 while (name != NULL) {
456 next_name = ISC_LIST_NEXT(name, link);
457 ISC_LIST_UNLINK(msg->sections[i], name, link);
459 rds = ISC_LIST_HEAD(name->list);
460 while (rds != NULL) {
461 next_rds = ISC_LIST_NEXT(rds, link);
462 ISC_LIST_UNLINK(name->list, rds, link);
464 INSIST(dns_rdataset_isassociated(rds));
465 dns_rdataset_disassociate(rds);
466 isc_mempool_put(msg->rdspool, rds);
469 if (dns_name_dynamic(name))
470 dns_name_free(name, msg->mctx);
471 isc_mempool_put(msg->namepool, name);
478 msgresetopt(dns_message_t *msg)
480 if (msg->opt != NULL) {
481 if (msg->opt_reserved > 0) {
482 dns_message_renderrelease(msg, msg->opt_reserved);
483 msg->opt_reserved = 0;
485 INSIST(dns_rdataset_isassociated(msg->opt));
486 dns_rdataset_disassociate(msg->opt);
487 isc_mempool_put(msg->rdspool, msg->opt);
493 msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
494 if (msg->sig_reserved > 0) {
495 dns_message_renderrelease(msg, msg->sig_reserved);
496 msg->sig_reserved = 0;
498 if (msg->tsig != NULL) {
499 INSIST(dns_rdataset_isassociated(msg->tsig));
500 INSIST(msg->namepool != NULL);
502 INSIST(msg->querytsig == NULL);
503 msg->querytsig = msg->tsig;
505 dns_rdataset_disassociate(msg->tsig);
506 isc_mempool_put(msg->rdspool, msg->tsig);
507 if (msg->querytsig != NULL) {
508 dns_rdataset_disassociate(msg->querytsig);
509 isc_mempool_put(msg->rdspool, msg->querytsig);
512 if (dns_name_dynamic(msg->tsigname))
513 dns_name_free(msg->tsigname, msg->mctx);
514 isc_mempool_put(msg->namepool, msg->tsigname);
516 msg->tsigname = NULL;
517 } else if (msg->querytsig != NULL && !replying) {
518 dns_rdataset_disassociate(msg->querytsig);
519 isc_mempool_put(msg->rdspool, msg->querytsig);
520 msg->querytsig = NULL;
522 if (msg->sig0 != NULL) {
523 INSIST(dns_rdataset_isassociated(msg->sig0));
524 dns_rdataset_disassociate(msg->sig0);
525 isc_mempool_put(msg->rdspool, msg->sig0);
526 if (msg->sig0name != NULL) {
527 if (dns_name_dynamic(msg->sig0name))
528 dns_name_free(msg->sig0name, msg->mctx);
529 isc_mempool_put(msg->namepool, msg->sig0name);
532 msg->sig0name = NULL;
537 * Free all but one (or everything) for this message. This is used by
538 * both dns_message_reset() and dns_message_destroy().
541 msgreset(dns_message_t *msg, isc_boolean_t everything) {
542 dns_msgblock_t *msgblock, *next_msgblock;
543 isc_buffer_t *dynbuf, *next_dynbuf;
545 dns_rdatalist_t *rdatalist;
547 msgresetnames(msg, 0);
549 msgresetsigs(msg, ISC_FALSE);
552 * Clean up linked lists.
556 * Run through the free lists, and just unlink anything found there.
557 * The memory isn't lost since these are part of message blocks we
560 rdata = ISC_LIST_HEAD(msg->freerdata);
561 while (rdata != NULL) {
562 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
563 rdata = ISC_LIST_HEAD(msg->freerdata);
565 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
566 while (rdatalist != NULL) {
567 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
568 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
571 dynbuf = ISC_LIST_HEAD(msg->scratchpad);
572 INSIST(dynbuf != NULL);
574 isc_buffer_clear(dynbuf);
575 dynbuf = ISC_LIST_NEXT(dynbuf, link);
577 while (dynbuf != NULL) {
578 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
579 ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
580 isc_buffer_free(&dynbuf);
581 dynbuf = next_dynbuf;
584 msgblock = ISC_LIST_HEAD(msg->rdatas);
585 if (!everything && msgblock != NULL) {
586 msgblock_reset(msgblock);
587 msgblock = ISC_LIST_NEXT(msgblock, link);
589 while (msgblock != NULL) {
590 next_msgblock = ISC_LIST_NEXT(msgblock, link);
591 ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
592 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
593 msgblock = next_msgblock;
597 * rdatalists could be empty.
600 msgblock = ISC_LIST_HEAD(msg->rdatalists);
601 if (!everything && msgblock != NULL) {
602 msgblock_reset(msgblock);
603 msgblock = ISC_LIST_NEXT(msgblock, link);
605 while (msgblock != NULL) {
606 next_msgblock = ISC_LIST_NEXT(msgblock, link);
607 ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
608 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
609 msgblock = next_msgblock;
612 msgblock = ISC_LIST_HEAD(msg->offsets);
613 if (!everything && msgblock != NULL) {
614 msgblock_reset(msgblock);
615 msgblock = ISC_LIST_NEXT(msgblock, link);
617 while (msgblock != NULL) {
618 next_msgblock = ISC_LIST_NEXT(msgblock, link);
619 ISC_LIST_UNLINK(msg->offsets, msgblock, link);
620 msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
621 msgblock = next_msgblock;
624 if (msg->tsigkey != NULL) {
625 dns_tsigkey_detach(&msg->tsigkey);
629 if (msg->tsigctx != NULL)
630 dst_context_destroy(&msg->tsigctx);
632 if (msg->query.base != NULL) {
633 if (msg->free_query != 0)
634 isc_mem_put(msg->mctx, msg->query.base,
636 msg->query.base = NULL;
637 msg->query.length = 0;
640 if (msg->saved.base != NULL) {
641 if (msg->free_saved != 0)
642 isc_mem_put(msg->mctx, msg->saved.base,
644 msg->saved.base = NULL;
645 msg->saved.length = 0;
649 * cleanup the buffer cleanup list
651 dynbuf = ISC_LIST_HEAD(msg->cleanup);
652 while (dynbuf != NULL) {
653 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
654 ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
655 isc_buffer_free(&dynbuf);
656 dynbuf = next_dynbuf;
660 * Set other bits to normal default values.
665 ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
666 ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
670 spacefortsig(dns_tsigkey_t *key, int otherlen) {
676 * The space required for an TSIG record is:
678 * n1 bytes for the name
679 * 2 bytes for the type
680 * 2 bytes for the class
681 * 4 bytes for the ttl
682 * 2 bytes for the rdlength
683 * n2 bytes for the algorithm name
684 * 6 bytes for the time signed
685 * 2 bytes for the fudge
686 * 2 bytes for the MAC size
687 * x bytes for the MAC
688 * 2 bytes for the original id
689 * 2 bytes for the error
690 * 2 bytes for the other data length
691 * y bytes for the other data (at most)
692 * ---------------------------------
693 * 26 + n1 + n2 + x + y bytes
696 dns_name_toregion(&key->name, &r1);
697 dns_name_toregion(key->algorithm, &r2);
698 if (key->key == NULL)
701 result = dst_key_sigsize(key->key, &x);
702 if (result != ISC_R_SUCCESS)
705 return (26 + r1.length + r2.length + x + otherlen);
709 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
713 isc_buffer_t *dynbuf;
716 REQUIRE(mctx != NULL);
717 REQUIRE(msgp != NULL);
718 REQUIRE(*msgp == NULL);
719 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
720 || intent == DNS_MESSAGE_INTENTRENDER);
722 m = isc_mem_get(mctx, sizeof(dns_message_t));
724 return (ISC_R_NOMEMORY);
727 * No allocations until further notice. Just initialize all lists
728 * and other members that are freed in the cleanup phase here.
731 m->magic = DNS_MESSAGE_MAGIC;
732 m->from_to_wire = intent;
735 for (i = 0; i < DNS_SECTION_MAX; i++)
736 ISC_LIST_INIT(m->sections[i]);
739 isc_mem_attach(mctx, &m->mctx);
741 ISC_LIST_INIT(m->scratchpad);
742 ISC_LIST_INIT(m->cleanup);
745 ISC_LIST_INIT(m->rdatas);
746 ISC_LIST_INIT(m->rdatalists);
747 ISC_LIST_INIT(m->offsets);
748 ISC_LIST_INIT(m->freerdata);
749 ISC_LIST_INIT(m->freerdatalist);
752 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
755 result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
756 if (result != ISC_R_SUCCESS)
758 isc_mempool_setfreemax(m->namepool, NAME_COUNT);
759 isc_mempool_setname(m->namepool, "msg:names");
761 result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
763 if (result != ISC_R_SUCCESS)
765 isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
766 isc_mempool_setname(m->rdspool, "msg:rdataset");
769 result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
770 if (result != ISC_R_SUCCESS)
772 ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
777 return (ISC_R_SUCCESS);
780 * Cleanup for error returns.
783 dynbuf = ISC_LIST_HEAD(m->scratchpad);
784 if (dynbuf != NULL) {
785 ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
786 isc_buffer_free(&dynbuf);
788 if (m->namepool != NULL)
789 isc_mempool_destroy(&m->namepool);
790 if (m->rdspool != NULL)
791 isc_mempool_destroy(&m->rdspool);
793 isc_mem_putanddetach(&mctx, m, sizeof(dns_message_t));
795 return (ISC_R_NOMEMORY);
799 dns_message_reset(dns_message_t *msg, unsigned int intent) {
800 REQUIRE(DNS_MESSAGE_VALID(msg));
801 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
802 || intent == DNS_MESSAGE_INTENTRENDER);
804 msgreset(msg, ISC_FALSE);
805 msg->from_to_wire = intent;
809 dns_message_destroy(dns_message_t **msgp) {
812 REQUIRE(msgp != NULL);
813 REQUIRE(DNS_MESSAGE_VALID(*msgp));
818 msgreset(msg, ISC_TRUE);
819 isc_mempool_destroy(&msg->namepool);
820 isc_mempool_destroy(&msg->rdspool);
822 isc_mem_putanddetach(&msg->mctx, msg, sizeof(dns_message_t));
826 findname(dns_name_t **foundname, dns_name_t *target,
827 dns_namelist_t *section)
831 for (curr = ISC_LIST_TAIL(*section);
833 curr = ISC_LIST_PREV(curr, link)) {
834 if (dns_name_equal(curr, target)) {
835 if (foundname != NULL)
837 return (ISC_R_SUCCESS);
841 return (ISC_R_NOTFOUND);
845 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
846 dns_rdatatype_t type, dns_rdatatype_t covers,
847 dns_rdataset_t **rdataset)
849 dns_rdataset_t *curr;
851 if (rdataset != NULL) {
852 REQUIRE(*rdataset == NULL);
855 for (curr = ISC_LIST_TAIL(name->list);
857 curr = ISC_LIST_PREV(curr, link)) {
858 if (curr->rdclass == rdclass &&
859 curr->type == type && curr->covers == covers) {
860 if (rdataset != NULL)
862 return (ISC_R_SUCCESS);
866 return (ISC_R_NOTFOUND);
870 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
871 dns_rdatatype_t covers, dns_rdataset_t **rdataset)
873 dns_rdataset_t *curr;
875 REQUIRE(name != NULL);
876 if (rdataset != NULL) {
877 REQUIRE(*rdataset == NULL);
880 for (curr = ISC_LIST_TAIL(name->list);
882 curr = ISC_LIST_PREV(curr, link)) {
883 if (curr->type == type && curr->covers == covers) {
884 if (rdataset != NULL)
886 return (ISC_R_SUCCESS);
890 return (ISC_R_NOTFOUND);
894 * Read a name from buffer "source".
897 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
898 dns_decompress_t *dctx)
900 isc_buffer_t *scratch;
904 scratch = currentbuffer(msg);
907 * First try: use current buffer.
908 * Second try: allocate a new buffer and use that.
912 result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
915 if (result == ISC_R_NOSPACE) {
918 result = newbuffer(msg, SCRATCHPAD_SIZE);
919 if (result != ISC_R_SUCCESS)
922 scratch = currentbuffer(msg);
923 dns_name_reset(name);
929 INSIST(0); /* Cannot get here... */
930 return (ISC_R_UNEXPECTED);
934 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
935 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
936 unsigned int rdatalen, dns_rdata_t *rdata)
938 isc_buffer_t *scratch;
941 unsigned int trysize;
943 scratch = currentbuffer(msg);
945 isc_buffer_setactive(source, rdatalen);
948 * First try: use current buffer.
949 * Second try: allocate a new buffer of size
950 * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
951 * (the data will fit if it was not more than 50% compressed)
952 * Subsequent tries: double buffer size on each try.
956 /* XXX possibly change this to a while (tries < 2) loop */
958 result = dns_rdata_fromwire(rdata, rdclass, rdtype,
962 if (result == ISC_R_NOSPACE) {
964 trysize = 2 * rdatalen;
965 if (trysize < SCRATCHPAD_SIZE)
966 trysize = SCRATCHPAD_SIZE;
968 INSIST(trysize != 0);
969 if (trysize >= 65535)
970 return (ISC_R_NOSPACE);
971 /* XXX DNS_R_RRTOOLONG? */
975 result = newbuffer(msg, trysize);
976 if (result != ISC_R_SUCCESS)
979 scratch = currentbuffer(msg);
989 seen_problem = ISC_TRUE; \
991 result = DNS_R_FORMERR; \
997 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
998 unsigned int options)
1004 dns_offsets_t *offsets;
1005 dns_rdataset_t *rdataset;
1006 dns_rdatalist_t *rdatalist;
1007 isc_result_t result;
1008 dns_rdatatype_t rdtype;
1009 dns_rdataclass_t rdclass;
1010 dns_namelist_t *section;
1011 isc_boolean_t free_name;
1012 isc_boolean_t best_effort;
1013 isc_boolean_t seen_problem;
1015 section = &msg->sections[DNS_SECTION_QUESTION];
1017 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1018 seen_problem = ISC_FALSE;
1024 for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
1025 name = isc_mempool_get(msg->namepool);
1027 return (ISC_R_NOMEMORY);
1028 free_name = ISC_TRUE;
1030 offsets = newoffsets(msg);
1031 if (offsets == NULL) {
1032 result = ISC_R_NOMEMORY;
1035 dns_name_init(name, *offsets);
1038 * Parse the name out of this packet.
1040 isc_buffer_remainingregion(source, &r);
1041 isc_buffer_setactive(source, r.length);
1042 result = getname(name, source, msg, dctx);
1043 if (result != ISC_R_SUCCESS)
1047 * Run through the section, looking to see if this name
1048 * is already there. If it is found, put back the allocated
1049 * name since we no longer need it, and set our name pointer
1050 * to point to the name we found.
1052 result = findname(&name2, name, section);
1055 * If it is the first name in the section, accept it.
1057 * If it is not, but is not the same as the name already
1058 * in the question section, append to the section. Note that
1059 * here in the question section this is illegal, so return
1060 * FORMERR. In the future, check the opcode to see if
1061 * this should be legal or not. In either case we no longer
1062 * need this name pointer.
1064 if (result != ISC_R_SUCCESS) {
1065 if (!ISC_LIST_EMPTY(*section))
1067 ISC_LIST_APPEND(*section, name, link);
1068 free_name = ISC_FALSE;
1070 isc_mempool_put(msg->namepool, name);
1073 free_name = ISC_FALSE;
1077 * Get type and class.
1079 isc_buffer_remainingregion(source, &r);
1081 result = ISC_R_UNEXPECTEDEND;
1084 rdtype = isc_buffer_getuint16(source);
1085 rdclass = isc_buffer_getuint16(source);
1088 * If this class is different than the one we already read,
1091 if (msg->rdclass_set == 0) {
1092 msg->rdclass = rdclass;
1093 msg->rdclass_set = 1;
1094 } else if (msg->rdclass != rdclass)
1098 * Is this a TKEY query?
1100 if (rdtype == dns_rdatatype_tkey)
1104 * Can't ask the same question twice.
1106 result = dns_message_find(name, rdclass, rdtype, 0, NULL);
1107 if (result == ISC_R_SUCCESS)
1111 * Allocate a new rdatalist.
1113 rdatalist = newrdatalist(msg);
1114 if (rdatalist == NULL) {
1115 result = ISC_R_NOMEMORY;
1118 rdataset = isc_mempool_get(msg->rdspool);
1119 if (rdataset == NULL) {
1120 result = ISC_R_NOMEMORY;
1125 * Convert rdatalist to rdataset, and attach the latter to
1128 rdatalist->type = rdtype;
1129 rdatalist->covers = 0;
1130 rdatalist->rdclass = rdclass;
1132 ISC_LIST_INIT(rdatalist->rdata);
1134 dns_rdataset_init(rdataset);
1135 result = dns_rdatalist_tordataset(rdatalist, rdataset);
1136 if (result != ISC_R_SUCCESS)
1139 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1141 ISC_LIST_APPEND(name->list, rdataset, link);
1146 return (DNS_R_RECOVERABLE);
1147 return (ISC_R_SUCCESS);
1150 if (rdataset != NULL) {
1151 INSIST(!dns_rdataset_isassociated(rdataset));
1152 isc_mempool_put(msg->rdspool, rdataset);
1155 if (rdatalist != NULL)
1156 isc_mempool_put(msg->rdlpool, rdatalist);
1159 isc_mempool_put(msg->namepool, name);
1164 static isc_boolean_t
1165 update(dns_section_t section, dns_rdataclass_t rdclass) {
1166 if (section == DNS_SECTION_PREREQUISITE)
1167 return (ISC_TF(rdclass == dns_rdataclass_any ||
1168 rdclass == dns_rdataclass_none));
1169 if (section == DNS_SECTION_UPDATE)
1170 return (ISC_TF(rdclass == dns_rdataclass_any));
1175 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1176 dns_section_t sectionid, unsigned int options)
1179 unsigned int count, rdatalen;
1182 dns_offsets_t *offsets;
1183 dns_rdataset_t *rdataset;
1184 dns_rdatalist_t *rdatalist;
1185 isc_result_t result;
1186 dns_rdatatype_t rdtype, covers;
1187 dns_rdataclass_t rdclass;
1190 dns_namelist_t *section;
1191 isc_boolean_t free_name, free_rdataset;
1192 isc_boolean_t preserve_order, best_effort, seen_problem;
1193 isc_boolean_t issigzero;
1195 preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
1196 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1197 seen_problem = ISC_FALSE;
1199 for (count = 0; count < msg->counts[sectionid]; count++) {
1200 int recstart = source->current;
1201 isc_boolean_t skip_name_search, skip_type_search;
1203 section = &msg->sections[sectionid];
1205 skip_name_search = ISC_FALSE;
1206 skip_type_search = ISC_FALSE;
1207 free_rdataset = ISC_FALSE;
1209 name = isc_mempool_get(msg->namepool);
1211 return (ISC_R_NOMEMORY);
1212 free_name = ISC_TRUE;
1214 offsets = newoffsets(msg);
1215 if (offsets == NULL) {
1216 result = ISC_R_NOMEMORY;
1219 dns_name_init(name, *offsets);
1222 * Parse the name out of this packet.
1224 isc_buffer_remainingregion(source, &r);
1225 isc_buffer_setactive(source, r.length);
1226 result = getname(name, source, msg, dctx);
1227 if (result != ISC_R_SUCCESS)
1231 * Get type, class, ttl, and rdatalen. Verify that at least
1232 * rdatalen bytes remain. (Some of this is deferred to
1235 isc_buffer_remainingregion(source, &r);
1236 if (r.length < 2 + 2 + 4 + 2) {
1237 result = ISC_R_UNEXPECTEDEND;
1240 rdtype = isc_buffer_getuint16(source);
1241 rdclass = isc_buffer_getuint16(source);
1244 * If there was no question section, we may not yet have
1245 * established a class. Do so now.
1247 if (msg->rdclass_set == 0 &&
1248 rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
1249 rdtype != dns_rdatatype_tsig && /* class is ANY */
1250 rdtype != dns_rdatatype_tkey) { /* class is undefined */
1251 msg->rdclass = rdclass;
1252 msg->rdclass_set = 1;
1256 * If this class is different than the one in the question
1259 if (msg->opcode != dns_opcode_update
1260 && rdtype != dns_rdatatype_tsig
1261 && rdtype != dns_rdatatype_opt
1262 && rdtype != dns_rdatatype_key /* in a TKEY query */
1263 && rdtype != dns_rdatatype_sig /* SIG(0) */
1264 && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1265 && msg->rdclass != dns_rdataclass_any
1266 && msg->rdclass != rdclass)
1270 * If this is not a TKEY query/response then the KEY
1271 * record's class needs to match.
1273 if (msg->opcode != dns_opcode_update && !msg->tkey &&
1274 rdtype == dns_rdatatype_key &&
1275 msg->rdclass != dns_rdataclass_any &&
1276 msg->rdclass != rdclass)
1280 * Special type handling for TSIG, OPT, and TKEY.
1282 if (rdtype == dns_rdatatype_tsig) {
1284 * If it is a tsig, verify that it is in the
1285 * additional data section.
1287 if (sectionid != DNS_SECTION_ADDITIONAL ||
1288 rdclass != dns_rdataclass_any ||
1289 count != msg->counts[sectionid] - 1)
1291 msg->sigstart = recstart;
1292 skip_name_search = ISC_TRUE;
1293 skip_type_search = ISC_TRUE;
1294 } else if (rdtype == dns_rdatatype_opt) {
1296 * The name of an OPT record must be ".", it
1297 * must be in the additional data section, and
1298 * it must be the first OPT we've seen.
1300 if (!dns_name_equal(dns_rootname, name) ||
1303 skip_name_search = ISC_TRUE;
1304 skip_type_search = ISC_TRUE;
1305 } else if (rdtype == dns_rdatatype_tkey) {
1307 * A TKEY must be in the additional section if this
1308 * is a query, and the answer section if this is a
1309 * response. Unless it's a Win2000 client.
1311 * Its class is ignored.
1313 dns_section_t tkeysection;
1315 if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1316 tkeysection = DNS_SECTION_ADDITIONAL;
1318 tkeysection = DNS_SECTION_ANSWER;
1319 if (sectionid != tkeysection &&
1320 sectionid != DNS_SECTION_ANSWER)
1325 * ... now get ttl and rdatalen, and check buffer.
1327 ttl = isc_buffer_getuint32(source);
1328 rdatalen = isc_buffer_getuint16(source);
1329 r.length -= (2 + 2 + 4 + 2);
1330 if (r.length < rdatalen) {
1331 result = ISC_R_UNEXPECTEDEND;
1336 * Read the rdata from the wire format. Interpret the
1337 * rdata according to its actual class, even if it had a
1338 * DynDNS meta-class in the packet (unless this is a TSIG).
1339 * Then put the meta-class back into the finished rdata.
1341 rdata = newrdata(msg);
1342 if (rdata == NULL) {
1343 result = ISC_R_NOMEMORY;
1346 if (msg->opcode == dns_opcode_update &&
1347 update(sectionid, rdclass)) {
1348 if (rdatalen != 0) {
1349 result = DNS_R_FORMERR;
1353 * When the rdata is empty, the data pointer is
1354 * never dereferenced, but it must still be non-NULL.
1355 * Casting 1 rather than "" avoids warnings about
1356 * discarding the const attribute of a string,
1357 * for compilers that would warn about such things.
1359 rdata->data = (unsigned char *)1;
1361 rdata->rdclass = rdclass;
1362 rdata->type = rdtype;
1363 rdata->flags = DNS_RDATA_UPDATE;
1364 result = ISC_R_SUCCESS;
1365 } else if (rdclass == dns_rdataclass_none &&
1366 msg->opcode == dns_opcode_update &&
1367 sectionid == DNS_SECTION_UPDATE) {
1368 result = getrdata(source, msg, dctx, msg->rdclass,
1369 rdtype, rdatalen, rdata);
1371 result = getrdata(source, msg, dctx, rdclass,
1372 rdtype, rdatalen, rdata);
1373 if (result != ISC_R_SUCCESS)
1375 rdata->rdclass = rdclass;
1376 issigzero = ISC_FALSE;
1377 if (rdtype == dns_rdatatype_rrsig &&
1378 rdata->flags == 0) {
1379 covers = dns_rdata_covers(rdata);
1382 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1383 rdata->flags == 0) {
1384 covers = dns_rdata_covers(rdata);
1386 if (sectionid != DNS_SECTION_ADDITIONAL ||
1387 count != msg->counts[sectionid] - 1)
1389 msg->sigstart = recstart;
1390 skip_name_search = ISC_TRUE;
1391 skip_type_search = ISC_TRUE;
1392 issigzero = ISC_TRUE;
1394 if (msg->rdclass != dns_rdataclass_any &&
1395 msg->rdclass != rdclass)
1402 * If we are doing a dynamic update or this is a meta-type,
1403 * don't bother searching for a name, just append this one
1404 * to the end of the message.
1406 if (preserve_order || msg->opcode == dns_opcode_update ||
1408 if (rdtype != dns_rdatatype_opt &&
1409 rdtype != dns_rdatatype_tsig &&
1412 ISC_LIST_APPEND(*section, name, link);
1413 free_name = ISC_FALSE;
1417 * Run through the section, looking to see if this name
1418 * is already there. If it is found, put back the
1419 * allocated name since we no longer need it, and set
1420 * our name pointer to point to the name we found.
1422 result = findname(&name2, name, section);
1425 * If it is a new name, append to the section.
1427 if (result == ISC_R_SUCCESS) {
1428 isc_mempool_put(msg->namepool, name);
1431 ISC_LIST_APPEND(*section, name, link);
1433 free_name = ISC_FALSE;
1437 * Search name for the particular type and class.
1438 * Skip this stage if in update mode or this is a meta-type.
1440 if (preserve_order || msg->opcode == dns_opcode_update ||
1442 result = ISC_R_NOTFOUND;
1445 * If this is a type that can only occur in
1446 * the question section, fail.
1448 if (dns_rdatatype_questiononly(rdtype))
1452 result = dns_message_find(name, rdclass, rdtype,
1457 * If we found an rdataset that matches, we need to
1458 * append this rdata to that set. If we did not, we need
1459 * to create a new rdatalist, store the important bits there,
1460 * convert it to an rdataset, and link the latter to the name.
1461 * Yuck. When appending, make certain that the type isn't
1462 * a singleton type, such as SOA or CNAME.
1464 * Note that this check will be bypassed when preserving order,
1465 * the opcode is an update, or the type search is skipped.
1467 if (result == ISC_R_SUCCESS) {
1468 if (dns_rdatatype_issingleton(rdtype)) {
1470 dns_rdatalist_fromrdataset(rdataset,
1472 first = ISC_LIST_HEAD(rdatalist->rdata);
1473 INSIST(first != NULL);
1474 if (dns_rdata_compare(rdata, first) != 0)
1479 if (result == ISC_R_NOTFOUND) {
1480 rdataset = isc_mempool_get(msg->rdspool);
1481 if (rdataset == NULL) {
1482 result = ISC_R_NOMEMORY;
1485 free_rdataset = ISC_TRUE;
1487 rdatalist = newrdatalist(msg);
1488 if (rdatalist == NULL) {
1489 result = ISC_R_NOMEMORY;
1493 rdatalist->type = rdtype;
1494 rdatalist->covers = covers;
1495 rdatalist->rdclass = rdclass;
1496 rdatalist->ttl = ttl;
1497 ISC_LIST_INIT(rdatalist->rdata);
1499 dns_rdataset_init(rdataset);
1500 RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1504 if (rdtype != dns_rdatatype_opt &&
1505 rdtype != dns_rdatatype_tsig &&
1508 ISC_LIST_APPEND(name->list, rdataset, link);
1509 free_rdataset = ISC_FALSE;
1516 * Section 5.2 of RFC2181 says we should drop
1517 * nonauthoritative rrsets where the TTLs differ, but we
1518 * currently treat them the as if they were authoritative and
1521 if (ttl != rdataset->ttl) {
1522 rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1523 if (ttl < rdataset->ttl)
1524 rdataset->ttl = ttl;
1527 /* Append this rdata to the rdataset. */
1528 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1529 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1532 * If this is an OPT record, remember it. Also, set
1533 * the extended rcode. Note that msg->opt will only be set
1534 * if best-effort parsing is enabled.
1536 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1539 msg->opt = rdataset;
1541 free_rdataset = ISC_FALSE;
1542 ercode = (dns_rcode_t)
1543 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1545 msg->rcode |= ercode;
1546 isc_mempool_put(msg->namepool, name);
1547 free_name = ISC_FALSE;
1551 * If this is an SIG(0) or TSIG record, remember it. Note
1552 * that msg->sig0 or msg->tsig will only be set if best-effort
1553 * parsing is enabled.
1555 if (issigzero && msg->sig0 == NULL) {
1556 msg->sig0 = rdataset;
1557 msg->sig0name = name;
1559 free_rdataset = ISC_FALSE;
1560 free_name = ISC_FALSE;
1561 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1562 msg->tsig = rdataset;
1563 msg->tsigname = name;
1564 /* Windows doesn't like TSIG names to be compressed. */
1565 msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1567 free_rdataset = ISC_FALSE;
1568 free_name = ISC_FALSE;
1573 isc_mempool_put(msg->namepool, name);
1575 isc_mempool_put(msg->rdspool, rdataset);
1576 free_name = free_rdataset = ISC_FALSE;
1578 INSIST(free_name == ISC_FALSE);
1579 INSIST(free_rdataset == ISC_FALSE);
1583 return (DNS_R_RECOVERABLE);
1584 return (ISC_R_SUCCESS);
1588 isc_mempool_put(msg->namepool, name);
1590 isc_mempool_put(msg->rdspool, rdataset);
1596 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1597 unsigned int options)
1600 dns_decompress_t dctx;
1602 isc_uint16_t tmpflags;
1603 isc_buffer_t origsource;
1604 isc_boolean_t seen_problem;
1605 isc_boolean_t ignore_tc;
1607 REQUIRE(DNS_MESSAGE_VALID(msg));
1608 REQUIRE(source != NULL);
1609 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1611 seen_problem = ISC_FALSE;
1612 ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1614 origsource = *source;
1617 msg->question_ok = 0;
1619 isc_buffer_remainingregion(source, &r);
1620 if (r.length < DNS_MESSAGE_HEADERLEN)
1621 return (ISC_R_UNEXPECTEDEND);
1623 msg->id = isc_buffer_getuint16(source);
1624 tmpflags = isc_buffer_getuint16(source);
1625 msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1626 >> DNS_MESSAGE_OPCODE_SHIFT);
1627 msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1628 msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1629 msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1630 msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1631 msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1632 msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1635 msg->state = DNS_SECTION_QUESTION;
1640 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1642 dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1644 ret = getquestions(source, msg, &dctx, options);
1645 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1647 if (ret == DNS_R_RECOVERABLE) {
1648 seen_problem = ISC_TRUE;
1649 ret = ISC_R_SUCCESS;
1651 if (ret != ISC_R_SUCCESS)
1653 msg->question_ok = 1;
1655 ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1656 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1658 if (ret == DNS_R_RECOVERABLE) {
1659 seen_problem = ISC_TRUE;
1660 ret = ISC_R_SUCCESS;
1662 if (ret != ISC_R_SUCCESS)
1665 ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1666 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1668 if (ret == DNS_R_RECOVERABLE) {
1669 seen_problem = ISC_TRUE;
1670 ret = ISC_R_SUCCESS;
1672 if (ret != ISC_R_SUCCESS)
1675 ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1676 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1678 if (ret == DNS_R_RECOVERABLE) {
1679 seen_problem = ISC_TRUE;
1680 ret = ISC_R_SUCCESS;
1682 if (ret != ISC_R_SUCCESS)
1685 isc_buffer_remainingregion(source, &r);
1686 if (r.length != 0) {
1687 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1688 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1689 "message has %u byte(s) of trailing garbage",
1694 if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1695 isc_buffer_usedregion(&origsource, &msg->saved);
1697 msg->saved.length = isc_buffer_usedlength(&origsource);
1698 msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1699 if (msg->saved.base == NULL)
1700 return (ISC_R_NOMEMORY);
1701 memmove(msg->saved.base, isc_buffer_base(&origsource),
1703 msg->free_saved = 1;
1706 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1707 return (DNS_R_RECOVERABLE);
1708 if (seen_problem == ISC_TRUE)
1709 return (DNS_R_RECOVERABLE);
1710 return (ISC_R_SUCCESS);
1714 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1715 isc_buffer_t *buffer)
1719 REQUIRE(DNS_MESSAGE_VALID(msg));
1720 REQUIRE(buffer != NULL);
1721 REQUIRE(msg->buffer == NULL);
1722 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1727 * Erase the contents of this buffer.
1729 isc_buffer_clear(buffer);
1732 * Make certain there is enough for at least the header in this
1735 isc_buffer_availableregion(buffer, &r);
1736 if (r.length < DNS_MESSAGE_HEADERLEN)
1737 return (ISC_R_NOSPACE);
1739 if (r.length < msg->reserved)
1740 return (ISC_R_NOSPACE);
1743 * Reserve enough space for the header in this buffer.
1745 isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1747 msg->buffer = buffer;
1749 return (ISC_R_SUCCESS);
1753 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1756 REQUIRE(DNS_MESSAGE_VALID(msg));
1757 REQUIRE(buffer != NULL);
1758 REQUIRE(msg->buffer != NULL);
1761 * Ensure that the new buffer is empty, and has enough space to
1762 * hold the current contents.
1764 isc_buffer_clear(buffer);
1766 isc_buffer_availableregion(buffer, &rn);
1767 isc_buffer_usedregion(msg->buffer, &r);
1768 REQUIRE(rn.length > r.length);
1771 * Copy the contents from the old to the new buffer.
1773 isc_buffer_add(buffer, r.length);
1774 memmove(rn.base, r.base, r.length);
1776 msg->buffer = buffer;
1778 return (ISC_R_SUCCESS);
1782 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1783 REQUIRE(DNS_MESSAGE_VALID(msg));
1784 REQUIRE(space <= msg->reserved);
1786 msg->reserved -= space;
1790 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1793 REQUIRE(DNS_MESSAGE_VALID(msg));
1795 if (msg->buffer != NULL) {
1796 isc_buffer_availableregion(msg->buffer, &r);
1797 if (r.length < (space + msg->reserved))
1798 return (ISC_R_NOSPACE);
1801 msg->reserved += space;
1803 return (ISC_R_SUCCESS);
1806 static inline isc_boolean_t
1807 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1811 * If we are not rendering class IN, this ordering is bogus.
1813 if (rds->rdclass != dns_rdataclass_in)
1816 switch (rds->type) {
1817 case dns_rdatatype_a:
1818 case dns_rdatatype_aaaa:
1819 if (preferred_glue == rds->type)
1824 case dns_rdatatype_rrsig:
1825 case dns_rdatatype_dnskey:
1832 if (pass_needed >= pass)
1838 #ifdef ALLOW_FILTER_AAAA_ON_V4
1840 * Decide whether to not answer with an AAAA record and its RRSIG
1842 static inline isc_boolean_t
1843 norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options)
1845 switch (rdataset->type) {
1846 case dns_rdatatype_aaaa:
1847 if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
1851 case dns_rdatatype_rrsig:
1852 if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
1853 rdataset->covers != dns_rdatatype_aaaa)
1861 if (rdataset->rdclass != dns_rdataclass_in)
1869 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1870 unsigned int options)
1872 dns_namelist_t *section;
1873 dns_name_t *name, *next_name;
1874 dns_rdataset_t *rdataset, *next_rdataset;
1875 unsigned int count, total;
1876 isc_result_t result;
1877 isc_buffer_t st; /* for rollbacks */
1879 isc_boolean_t partial = ISC_FALSE;
1880 unsigned int rd_options;
1881 dns_rdatatype_t preferred_glue = 0;
1883 REQUIRE(DNS_MESSAGE_VALID(msg));
1884 REQUIRE(msg->buffer != NULL);
1885 REQUIRE(VALID_NAMED_SECTION(sectionid));
1887 section = &msg->sections[sectionid];
1889 if ((sectionid == DNS_SECTION_ADDITIONAL)
1890 && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1891 if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1892 preferred_glue = dns_rdatatype_a;
1894 } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1895 preferred_glue = dns_rdatatype_aaaa;
1902 if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1905 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1908 * Shrink the space in the buffer by the reserved amount.
1910 msg->buffer->length -= msg->reserved;
1913 if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1917 * Render required glue first. Set TC if it won't fit.
1919 name = ISC_LIST_HEAD(*section);
1921 rdataset = ISC_LIST_HEAD(name->list);
1922 if (rdataset != NULL &&
1923 (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
1924 (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
1925 const void *order_arg = msg->order_arg;
1926 st = *(msg->buffer);
1929 result = dns_rdataset_towirepartial(rdataset,
1939 result = dns_rdataset_towiresorted(rdataset,
1948 if (partial && result == ISC_R_NOSPACE) {
1949 msg->flags |= DNS_MESSAGEFLAG_TC;
1950 msg->buffer->length += msg->reserved;
1951 msg->counts[sectionid] += total;
1954 if (result == ISC_R_NOSPACE)
1955 msg->flags |= DNS_MESSAGEFLAG_TC;
1956 if (result != ISC_R_SUCCESS) {
1957 INSIST(st.used < 65536);
1958 dns_compress_rollback(msg->cctx,
1959 (isc_uint16_t)st.used);
1960 *(msg->buffer) = st; /* rollback */
1961 msg->buffer->length += msg->reserved;
1962 msg->counts[sectionid] += total;
1965 rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
1970 name = ISC_LIST_HEAD(*section);
1972 msg->buffer->length += msg->reserved;
1973 msg->counts[sectionid] += total;
1974 return (ISC_R_SUCCESS);
1977 while (name != NULL) {
1978 next_name = ISC_LIST_NEXT(name, link);
1980 rdataset = ISC_LIST_HEAD(name->list);
1981 while (rdataset != NULL) {
1982 next_rdataset = ISC_LIST_NEXT(rdataset, link);
1984 if ((rdataset->attributes &
1985 DNS_RDATASETATTR_RENDERED) != 0)
1988 if (((options & DNS_MESSAGERENDER_ORDERED)
1990 && (sectionid == DNS_SECTION_ADDITIONAL)
1991 && wrong_priority(rdataset, pass,
1995 #ifdef ALLOW_FILTER_AAAA_ON_V4
1997 * Suppress AAAAs if asked and we are
1998 * not doing DNSSEC or are breaking DNSSEC.
1999 * Say so in the AD bit if we break DNSSEC.
2001 if (norender_rdataset(rdataset, options) &&
2002 sectionid != DNS_SECTION_QUESTION) {
2003 if (sectionid == DNS_SECTION_ANSWER ||
2004 sectionid == DNS_SECTION_AUTHORITY)
2005 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2006 if (OPTOUT(rdataset))
2007 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2012 st = *(msg->buffer);
2016 result = dns_rdataset_towirepartial(
2027 result = dns_rdataset_towiresorted(
2040 * If out of space, record stats on what we
2041 * rendered so far, and return that status.
2043 * XXXMLG Need to change this when
2044 * dns_rdataset_towire() can render partial
2045 * sets starting at some arbitrary point in the
2046 * set. This will include setting a bit in the
2047 * rdataset to indicate that a partial
2048 * rendering was done, and some state saved
2049 * somewhere (probably in the message struct)
2050 * to indicate where to continue from.
2052 if (partial && result == ISC_R_NOSPACE) {
2053 msg->buffer->length += msg->reserved;
2054 msg->counts[sectionid] += total;
2057 if (result != ISC_R_SUCCESS) {
2058 INSIST(st.used < 65536);
2059 dns_compress_rollback(msg->cctx,
2060 (isc_uint16_t)st.used);
2061 *(msg->buffer) = st; /* rollback */
2062 msg->buffer->length += msg->reserved;
2063 msg->counts[sectionid] += total;
2068 * If we have rendered non-validated data,
2069 * ensure that the AD bit is not set.
2071 if (rdataset->trust != dns_trust_secure &&
2072 (sectionid == DNS_SECTION_ANSWER ||
2073 sectionid == DNS_SECTION_AUTHORITY))
2074 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2075 if (OPTOUT(rdataset))
2076 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2078 rdataset->attributes |=
2079 DNS_RDATASETATTR_RENDERED;
2082 rdataset = next_rdataset;
2087 } while (--pass != 0);
2089 msg->buffer->length += msg->reserved;
2090 msg->counts[sectionid] += total;
2092 return (ISC_R_SUCCESS);
2096 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2100 REQUIRE(DNS_MESSAGE_VALID(msg));
2101 REQUIRE(target != NULL);
2103 isc_buffer_availableregion(target, &r);
2104 REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2106 isc_buffer_putuint16(target, msg->id);
2108 tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
2109 & DNS_MESSAGE_OPCODE_MASK);
2110 tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2111 tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2113 INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
2114 msg->counts[DNS_SECTION_ANSWER] < 65536 &&
2115 msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2116 msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2118 isc_buffer_putuint16(target, tmp);
2119 isc_buffer_putuint16(target,
2120 (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2121 isc_buffer_putuint16(target,
2122 (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2123 isc_buffer_putuint16(target,
2124 (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2125 isc_buffer_putuint16(target,
2126 (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2130 dns_message_renderend(dns_message_t *msg) {
2131 isc_buffer_t tmpbuf;
2136 REQUIRE(DNS_MESSAGE_VALID(msg));
2137 REQUIRE(msg->buffer != NULL);
2139 if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2141 * We have an extended rcode but are not using EDNS.
2143 return (DNS_R_FORMERR);
2147 * If we're adding a OPT, TSIG or SIG(0) to a truncated message,
2148 * clear all rdatasets from the message except for the question
2149 * before adding the OPT, TSIG or SIG(0). If the question doesn't
2150 * fit, don't include it.
2152 if ((msg->tsigkey != NULL || msg->sig0key != NULL || msg->opt) &&
2153 (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2157 msgresetnames(msg, DNS_SECTION_ANSWER);
2159 dns_message_renderreset(msg);
2161 isc_buffer_clear(msg->buffer);
2162 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2163 dns_compress_rollback(msg->cctx, 0);
2164 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2166 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2171 * If we've got an OPT record, render it.
2173 if (msg->opt != NULL) {
2174 dns_message_renderrelease(msg, msg->opt_reserved);
2175 msg->opt_reserved = 0;
2177 * Set the extended rcode.
2179 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2180 msg->opt->ttl |= ((msg->rcode << 20) &
2181 DNS_MESSAGE_EDNSRCODE_MASK);
2186 result = dns_rdataset_towire(msg->opt, dns_rootname,
2187 msg->cctx, msg->buffer, 0,
2189 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2190 if (result != ISC_R_SUCCESS)
2195 * If we're adding a TSIG record, generate and render it.
2197 if (msg->tsigkey != NULL) {
2198 dns_message_renderrelease(msg, msg->sig_reserved);
2199 msg->sig_reserved = 0;
2200 result = dns_tsig_sign(msg);
2201 if (result != ISC_R_SUCCESS)
2204 result = dns_rdataset_towire(msg->tsig, msg->tsigname,
2205 msg->cctx, msg->buffer, 0,
2207 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2208 if (result != ISC_R_SUCCESS)
2213 * If we're adding a SIG(0) record, generate and render it.
2215 if (msg->sig0key != NULL) {
2216 dns_message_renderrelease(msg, msg->sig_reserved);
2217 msg->sig_reserved = 0;
2218 result = dns_dnssec_signmessage(msg, msg->sig0key);
2219 if (result != ISC_R_SUCCESS)
2223 * Note: dns_rootname is used here, not msg->sig0name, since
2224 * the owner name of a SIG(0) is irrelevant, and will not
2225 * be set in a message being rendered.
2227 result = dns_rdataset_towire(msg->sig0, dns_rootname,
2228 msg->cctx, msg->buffer, 0,
2230 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2231 if (result != ISC_R_SUCCESS)
2235 isc_buffer_usedregion(msg->buffer, &r);
2236 isc_buffer_init(&tmpbuf, r.base, r.length);
2238 dns_message_renderheader(msg, &tmpbuf);
2240 msg->buffer = NULL; /* forget about this buffer only on success XXX */
2242 return (ISC_R_SUCCESS);
2246 dns_message_renderreset(dns_message_t *msg) {
2249 dns_rdataset_t *rds;
2252 * Reset the message so that it may be rendered again.
2255 REQUIRE(DNS_MESSAGE_VALID(msg));
2256 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2260 for (i = 0; i < DNS_SECTION_MAX; i++) {
2261 msg->cursors[i] = NULL;
2263 for (name = ISC_LIST_HEAD(msg->sections[i]);
2265 name = ISC_LIST_NEXT(name, link)) {
2266 for (rds = ISC_LIST_HEAD(name->list);
2268 rds = ISC_LIST_NEXT(rds, link)) {
2269 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2273 if (msg->tsigname != NULL)
2274 dns_message_puttempname(msg, &msg->tsigname);
2275 if (msg->tsig != NULL) {
2276 dns_rdataset_disassociate(msg->tsig);
2277 dns_message_puttemprdataset(msg, &msg->tsig);
2279 if (msg->sig0 != NULL) {
2280 dns_rdataset_disassociate(msg->sig0);
2281 dns_message_puttemprdataset(msg, &msg->sig0);
2286 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2287 REQUIRE(DNS_MESSAGE_VALID(msg));
2288 REQUIRE(VALID_NAMED_SECTION(section));
2290 msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2292 if (msg->cursors[section] == NULL)
2293 return (ISC_R_NOMORE);
2295 return (ISC_R_SUCCESS);
2299 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2300 REQUIRE(DNS_MESSAGE_VALID(msg));
2301 REQUIRE(VALID_NAMED_SECTION(section));
2302 REQUIRE(msg->cursors[section] != NULL);
2304 msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2306 if (msg->cursors[section] == NULL)
2307 return (ISC_R_NOMORE);
2309 return (ISC_R_SUCCESS);
2313 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2316 REQUIRE(DNS_MESSAGE_VALID(msg));
2317 REQUIRE(VALID_NAMED_SECTION(section));
2318 REQUIRE(name != NULL && *name == NULL);
2319 REQUIRE(msg->cursors[section] != NULL);
2321 *name = msg->cursors[section];
2325 dns_message_findname(dns_message_t *msg, dns_section_t section,
2326 dns_name_t *target, dns_rdatatype_t type,
2327 dns_rdatatype_t covers, dns_name_t **name,
2328 dns_rdataset_t **rdataset)
2330 dns_name_t *foundname;
2331 isc_result_t result;
2334 * XXX These requirements are probably too intensive, especially
2335 * where things can be NULL, but as they are they ensure that if
2336 * something is NON-NULL, indicating that the caller expects it
2337 * to be filled in, that we can in fact fill it in.
2339 REQUIRE(msg != NULL);
2340 REQUIRE(VALID_SECTION(section));
2341 REQUIRE(target != NULL);
2343 REQUIRE(*name == NULL);
2344 if (type == dns_rdatatype_any) {
2345 REQUIRE(rdataset == NULL);
2347 if (rdataset != NULL)
2348 REQUIRE(*rdataset == NULL);
2351 result = findname(&foundname, target,
2352 &msg->sections[section]);
2354 if (result == ISC_R_NOTFOUND)
2355 return (DNS_R_NXDOMAIN);
2356 else if (result != ISC_R_SUCCESS)
2363 * And now look for the type.
2365 if (type == dns_rdatatype_any)
2366 return (ISC_R_SUCCESS);
2368 result = dns_message_findtype(foundname, type, covers, rdataset);
2369 if (result == ISC_R_NOTFOUND)
2370 return (DNS_R_NXRRSET);
2376 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2377 dns_section_t fromsection,
2378 dns_section_t tosection)
2380 REQUIRE(msg != NULL);
2381 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2382 REQUIRE(name != NULL);
2383 REQUIRE(VALID_NAMED_SECTION(fromsection));
2384 REQUIRE(VALID_NAMED_SECTION(tosection));
2387 * Unlink the name from the old section
2389 ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2390 ISC_LIST_APPEND(msg->sections[tosection], name, link);
2394 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2395 dns_section_t section)
2397 REQUIRE(msg != NULL);
2398 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2399 REQUIRE(name != NULL);
2400 REQUIRE(VALID_NAMED_SECTION(section));
2402 ISC_LIST_APPEND(msg->sections[section], name, link);
2406 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2407 dns_section_t section)
2409 REQUIRE(msg != NULL);
2410 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2411 REQUIRE(name != NULL);
2412 REQUIRE(VALID_NAMED_SECTION(section));
2414 ISC_LIST_UNLINK(msg->sections[section], name, link);
2418 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2419 REQUIRE(DNS_MESSAGE_VALID(msg));
2420 REQUIRE(item != NULL && *item == NULL);
2422 *item = isc_mempool_get(msg->namepool);
2424 return (ISC_R_NOMEMORY);
2425 dns_name_init(*item, NULL);
2427 return (ISC_R_SUCCESS);
2431 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2432 REQUIRE(DNS_MESSAGE_VALID(msg));
2433 REQUIRE(item != NULL && *item == NULL);
2435 *item = newoffsets(msg);
2437 return (ISC_R_NOMEMORY);
2439 return (ISC_R_SUCCESS);
2443 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2444 REQUIRE(DNS_MESSAGE_VALID(msg));
2445 REQUIRE(item != NULL && *item == NULL);
2447 *item = newrdata(msg);
2449 return (ISC_R_NOMEMORY);
2451 return (ISC_R_SUCCESS);
2455 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2456 REQUIRE(DNS_MESSAGE_VALID(msg));
2457 REQUIRE(item != NULL && *item == NULL);
2459 *item = isc_mempool_get(msg->rdspool);
2461 return (ISC_R_NOMEMORY);
2463 dns_rdataset_init(*item);
2465 return (ISC_R_SUCCESS);
2469 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2470 REQUIRE(DNS_MESSAGE_VALID(msg));
2471 REQUIRE(item != NULL && *item == NULL);
2473 *item = newrdatalist(msg);
2475 return (ISC_R_NOMEMORY);
2477 return (ISC_R_SUCCESS);
2481 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2482 REQUIRE(DNS_MESSAGE_VALID(msg));
2483 REQUIRE(item != NULL && *item != NULL);
2485 if (dns_name_dynamic(*item))
2486 dns_name_free(*item, msg->mctx);
2487 isc_mempool_put(msg->namepool, *item);
2492 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2493 REQUIRE(DNS_MESSAGE_VALID(msg));
2494 REQUIRE(item != NULL && *item != NULL);
2496 releaserdata(msg, *item);
2501 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2502 REQUIRE(DNS_MESSAGE_VALID(msg));
2503 REQUIRE(item != NULL && *item != NULL);
2505 REQUIRE(!dns_rdataset_isassociated(*item));
2506 isc_mempool_put(msg->rdspool, *item);
2511 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2512 REQUIRE(DNS_MESSAGE_VALID(msg));
2513 REQUIRE(item != NULL && *item != NULL);
2515 releaserdatalist(msg, *item);
2520 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2521 unsigned int *flagsp)
2524 isc_buffer_t buffer;
2528 REQUIRE(source != NULL);
2532 isc_buffer_remainingregion(&buffer, &r);
2533 if (r.length < DNS_MESSAGE_HEADERLEN)
2534 return (ISC_R_UNEXPECTEDEND);
2536 id = isc_buffer_getuint16(&buffer);
2537 flags = isc_buffer_getuint16(&buffer);
2538 flags &= DNS_MESSAGE_FLAG_MASK;
2545 return (ISC_R_SUCCESS);
2549 dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
2550 unsigned int clear_after;
2551 isc_result_t result;
2553 REQUIRE(DNS_MESSAGE_VALID(msg));
2554 REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2556 if (!msg->header_ok)
2557 return (DNS_R_FORMERR);
2558 if (msg->opcode != dns_opcode_query &&
2559 msg->opcode != dns_opcode_notify)
2560 want_question_section = ISC_FALSE;
2561 if (msg->opcode == dns_opcode_update)
2562 clear_after = DNS_SECTION_PREREQUISITE;
2563 else if (want_question_section) {
2564 if (!msg->question_ok)
2565 return (DNS_R_FORMERR);
2566 clear_after = DNS_SECTION_ANSWER;
2568 clear_after = DNS_SECTION_QUESTION;
2569 msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2570 msgresetnames(msg, clear_after);
2572 msgresetsigs(msg, ISC_TRUE);
2573 msginitprivate(msg);
2575 * We now clear most flags and then set QR, ensuring that the
2576 * reply's flags will be in a reasonable state.
2578 msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2579 msg->flags |= DNS_MESSAGEFLAG_QR;
2582 * This saves the query TSIG status, if the query was signed, and
2583 * reserves space in the reply for the TSIG.
2585 if (msg->tsigkey != NULL) {
2586 unsigned int otherlen = 0;
2587 msg->querytsigstatus = msg->tsigstatus;
2588 msg->tsigstatus = dns_rcode_noerror;
2589 if (msg->querytsigstatus == dns_tsigerror_badtime)
2591 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2592 result = dns_message_renderreserve(msg, msg->sig_reserved);
2593 if (result != ISC_R_SUCCESS) {
2594 msg->sig_reserved = 0;
2598 if (msg->saved.base != NULL) {
2599 msg->query.base = msg->saved.base;
2600 msg->query.length = msg->saved.length;
2601 msg->free_query = msg->free_saved;
2602 msg->saved.base = NULL;
2603 msg->saved.length = 0;
2604 msg->free_saved = 0;
2607 return (ISC_R_SUCCESS);
2611 dns_message_getopt(dns_message_t *msg) {
2614 * Get the OPT record for 'msg'.
2617 REQUIRE(DNS_MESSAGE_VALID(msg));
2623 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2624 isc_result_t result;
2625 dns_rdata_t rdata = DNS_RDATA_INIT;
2628 * Set the OPT record for 'msg'.
2632 * The space required for an OPT record is:
2634 * 1 byte for the name
2635 * 2 bytes for the type
2636 * 2 bytes for the class
2637 * 4 bytes for the ttl
2638 * 2 bytes for the rdata length
2639 * ---------------------------------
2642 * plus the length of the rdata.
2645 REQUIRE(DNS_MESSAGE_VALID(msg));
2646 REQUIRE(opt->type == dns_rdatatype_opt);
2647 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2648 REQUIRE(msg->state == DNS_SECTION_ANY);
2652 result = dns_rdataset_first(opt);
2653 if (result != ISC_R_SUCCESS)
2655 dns_rdataset_current(opt, &rdata);
2656 msg->opt_reserved = 11 + rdata.length;
2657 result = dns_message_renderreserve(msg, msg->opt_reserved);
2658 if (result != ISC_R_SUCCESS) {
2659 msg->opt_reserved = 0;
2665 return (ISC_R_SUCCESS);
2668 dns_rdataset_disassociate(opt);
2669 dns_message_puttemprdataset(msg, &opt);
2674 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2677 * Get the TSIG record and owner for 'msg'.
2680 REQUIRE(DNS_MESSAGE_VALID(msg));
2681 REQUIRE(owner == NULL || *owner == NULL);
2684 *owner = msg->tsigname;
2689 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2690 isc_result_t result;
2693 * Set the TSIG key for 'msg'
2696 REQUIRE(DNS_MESSAGE_VALID(msg));
2697 REQUIRE(msg->state == DNS_SECTION_ANY);
2699 if (key == NULL && msg->tsigkey != NULL) {
2700 if (msg->sig_reserved != 0) {
2701 dns_message_renderrelease(msg, msg->sig_reserved);
2702 msg->sig_reserved = 0;
2704 dns_tsigkey_detach(&msg->tsigkey);
2707 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2708 dns_tsigkey_attach(key, &msg->tsigkey);
2709 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2710 msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2711 result = dns_message_renderreserve(msg,
2713 if (result != ISC_R_SUCCESS) {
2714 dns_tsigkey_detach(&msg->tsigkey);
2715 msg->sig_reserved = 0;
2720 return (ISC_R_SUCCESS);
2724 dns_message_gettsigkey(dns_message_t *msg) {
2727 * Get the TSIG key for 'msg'
2730 REQUIRE(DNS_MESSAGE_VALID(msg));
2732 return (msg->tsigkey);
2736 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2737 dns_rdata_t *rdata = NULL;
2738 dns_rdatalist_t *list = NULL;
2739 dns_rdataset_t *set = NULL;
2740 isc_buffer_t *buf = NULL;
2742 isc_result_t result;
2744 REQUIRE(DNS_MESSAGE_VALID(msg));
2745 REQUIRE(msg->querytsig == NULL);
2747 if (querytsig == NULL)
2748 return (ISC_R_SUCCESS);
2750 result = dns_message_gettemprdata(msg, &rdata);
2751 if (result != ISC_R_SUCCESS)
2754 result = dns_message_gettemprdatalist(msg, &list);
2755 if (result != ISC_R_SUCCESS)
2757 result = dns_message_gettemprdataset(msg, &set);
2758 if (result != ISC_R_SUCCESS)
2761 isc_buffer_usedregion(querytsig, &r);
2762 result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2763 if (result != ISC_R_SUCCESS)
2765 isc_buffer_putmem(buf, r.base, r.length);
2766 isc_buffer_usedregion(buf, &r);
2767 dns_rdata_init(rdata);
2768 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2769 dns_message_takebuffer(msg, &buf);
2770 ISC_LIST_INIT(list->rdata);
2771 ISC_LIST_APPEND(list->rdata, rdata, link);
2772 result = dns_rdatalist_tordataset(list, set);
2773 if (result != ISC_R_SUCCESS)
2776 msg->querytsig = set;
2782 dns_message_puttemprdata(msg, &rdata);
2784 dns_message_puttemprdatalist(msg, &list);
2786 dns_message_puttemprdataset(msg, &set);
2787 return (ISC_R_NOMEMORY);
2791 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2792 isc_buffer_t **querytsig) {
2793 isc_result_t result;
2794 dns_rdata_t rdata = DNS_RDATA_INIT;
2797 REQUIRE(DNS_MESSAGE_VALID(msg));
2798 REQUIRE(mctx != NULL);
2799 REQUIRE(querytsig != NULL && *querytsig == NULL);
2801 if (msg->tsig == NULL)
2802 return (ISC_R_SUCCESS);
2804 result = dns_rdataset_first(msg->tsig);
2805 if (result != ISC_R_SUCCESS)
2807 dns_rdataset_current(msg->tsig, &rdata);
2808 dns_rdata_toregion(&rdata, &r);
2810 result = isc_buffer_allocate(mctx, querytsig, r.length);
2811 if (result != ISC_R_SUCCESS)
2813 isc_buffer_putmem(*querytsig, r.base, r.length);
2814 return (ISC_R_SUCCESS);
2818 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2821 * Get the SIG(0) record for 'msg'.
2824 REQUIRE(DNS_MESSAGE_VALID(msg));
2825 REQUIRE(owner == NULL || *owner == NULL);
2827 if (msg->sig0 != NULL && owner != NULL) {
2828 /* If dns_message_getsig0 is called on a rendered message
2829 * after the SIG(0) has been applied, we need to return the
2830 * root name, not NULL.
2832 if (msg->sig0name == NULL)
2833 *owner = dns_rootname;
2835 *owner = msg->sig0name;
2841 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2844 isc_result_t result;
2847 * Set the SIG(0) key for 'msg'
2851 * The space required for an SIG(0) record is:
2853 * 1 byte for the name
2854 * 2 bytes for the type
2855 * 2 bytes for the class
2856 * 4 bytes for the ttl
2857 * 2 bytes for the type covered
2858 * 1 byte for the algorithm
2859 * 1 bytes for the labels
2860 * 4 bytes for the original ttl
2861 * 4 bytes for the signature expiration
2862 * 4 bytes for the signature inception
2863 * 2 bytes for the key tag
2864 * n bytes for the signer's name
2865 * x bytes for the signature
2866 * ---------------------------------
2869 REQUIRE(DNS_MESSAGE_VALID(msg));
2870 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2871 REQUIRE(msg->state == DNS_SECTION_ANY);
2874 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2875 dns_name_toregion(dst_key_name(key), &r);
2876 result = dst_key_sigsize(key, &x);
2877 if (result != ISC_R_SUCCESS) {
2878 msg->sig_reserved = 0;
2881 msg->sig_reserved = 27 + r.length + x;
2882 result = dns_message_renderreserve(msg, msg->sig_reserved);
2883 if (result != ISC_R_SUCCESS) {
2884 msg->sig_reserved = 0;
2889 return (ISC_R_SUCCESS);
2893 dns_message_getsig0key(dns_message_t *msg) {
2896 * Get the SIG(0) key for 'msg'
2899 REQUIRE(DNS_MESSAGE_VALID(msg));
2901 return (msg->sig0key);
2905 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2906 REQUIRE(DNS_MESSAGE_VALID(msg));
2907 REQUIRE(buffer != NULL);
2908 REQUIRE(ISC_BUFFER_VALID(*buffer));
2910 ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2915 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
2916 isc_result_t result = ISC_R_SUCCESS;
2917 dns_rdata_t rdata = DNS_RDATA_INIT;
2919 REQUIRE(DNS_MESSAGE_VALID(msg));
2920 REQUIRE(signer != NULL);
2921 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2923 if (msg->tsig == NULL && msg->sig0 == NULL)
2924 return (ISC_R_NOTFOUND);
2926 if (msg->verify_attempted == 0)
2927 return (DNS_R_NOTVERIFIEDYET);
2929 if (!dns_name_hasbuffer(signer)) {
2930 isc_buffer_t *dynbuf = NULL;
2931 result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
2932 if (result != ISC_R_SUCCESS)
2934 dns_name_setbuffer(signer, dynbuf);
2935 dns_message_takebuffer(msg, &dynbuf);
2938 if (msg->sig0 != NULL) {
2939 dns_rdata_sig_t sig;
2941 result = dns_rdataset_first(msg->sig0);
2942 INSIST(result == ISC_R_SUCCESS);
2943 dns_rdataset_current(msg->sig0, &rdata);
2945 result = dns_rdata_tostruct(&rdata, &sig, NULL);
2946 if (result != ISC_R_SUCCESS)
2949 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
2950 result = ISC_R_SUCCESS;
2952 result = DNS_R_SIGINVALID;
2953 dns_name_clone(&sig.signer, signer);
2954 dns_rdata_freestruct(&sig);
2956 dns_name_t *identity;
2957 dns_rdata_any_tsig_t tsig;
2959 result = dns_rdataset_first(msg->tsig);
2960 INSIST(result == ISC_R_SUCCESS);
2961 dns_rdataset_current(msg->tsig, &rdata);
2963 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2964 INSIST(result == ISC_R_SUCCESS);
2965 if (msg->tsigstatus != dns_rcode_noerror)
2966 result = DNS_R_TSIGVERIFYFAILURE;
2967 else if (tsig.error != dns_rcode_noerror)
2968 result = DNS_R_TSIGERRORSET;
2970 result = ISC_R_SUCCESS;
2971 dns_rdata_freestruct(&tsig);
2973 if (msg->tsigkey == NULL) {
2975 * If msg->tsigstatus & tsig.error are both
2976 * dns_rcode_noerror, the message must have been
2977 * verified, which means msg->tsigkey will be
2980 INSIST(result != ISC_R_SUCCESS);
2982 identity = dns_tsigkey_identity(msg->tsigkey);
2983 if (identity == NULL) {
2984 if (result == ISC_R_SUCCESS)
2985 result = DNS_R_NOIDENTITY;
2986 identity = &msg->tsigkey->name;
2988 dns_name_clone(identity, signer);
2996 dns_message_resetsig(dns_message_t *msg) {
2997 REQUIRE(DNS_MESSAGE_VALID(msg));
2998 msg->verified_sig = 0;
2999 msg->verify_attempted = 0;
3000 msg->tsigstatus = dns_rcode_noerror;
3001 msg->sig0status = dns_rcode_noerror;
3002 msg->timeadjust = 0;
3003 if (msg->tsigkey != NULL) {
3004 dns_tsigkey_detach(&msg->tsigkey);
3005 msg->tsigkey = NULL;
3010 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
3011 dns_message_resetsig(msg);
3012 return (dns_message_checksig(msg, view));
3015 #ifdef SKAN_MSG_DEBUG
3017 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
3018 dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
3019 dns_rdata_any_tsig_t querytsig;
3020 isc_result_t result;
3022 if (msg->tsig != NULL) {
3023 result = dns_rdataset_first(msg->tsig);
3024 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3025 dns_rdataset_current(msg->tsig, &querytsigrdata);
3026 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3027 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3028 hexdump(txt1, "TSIG", querytsig.signature,
3032 if (msg->querytsig != NULL) {
3033 result = dns_rdataset_first(msg->querytsig);
3034 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3035 dns_rdataset_current(msg->querytsig, &querytsigrdata);
3036 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3037 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3038 hexdump(txt1, "QUERYTSIG", querytsig.signature,
3045 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
3046 isc_buffer_t b, msgb;
3048 REQUIRE(DNS_MESSAGE_VALID(msg));
3050 if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
3051 return (ISC_R_SUCCESS);
3053 INSIST(msg->saved.base != NULL);
3054 isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
3055 isc_buffer_add(&msgb, msg->saved.length);
3056 if (msg->tsigkey != NULL || msg->tsig != NULL) {
3057 #ifdef SKAN_MSG_DEBUG
3058 dns_message_dumpsig(msg, "dns_message_checksig#1");
3061 return (dns_view_checksig(view, &msgb, msg));
3063 return (dns_tsig_verify(&msgb, msg, NULL, NULL));
3065 dns_rdata_t rdata = DNS_RDATA_INIT;
3066 dns_rdata_sig_t sig;
3067 dns_rdataset_t keyset;
3068 isc_result_t result;
3070 result = dns_rdataset_first(msg->sig0);
3071 INSIST(result == ISC_R_SUCCESS);
3072 dns_rdataset_current(msg->sig0, &rdata);
3075 * This can occur when the message is a dynamic update, since
3076 * the rdata length checking is relaxed. This should not
3077 * happen in a well-formed message, since the SIG(0) is only
3078 * looked for in the additional section, and the dynamic update
3079 * meta-records are in the prerequisite and update sections.
3081 if (rdata.length == 0)
3082 return (ISC_R_UNEXPECTEDEND);
3084 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
3085 if (result != ISC_R_SUCCESS)
3088 dns_rdataset_init(&keyset);
3090 return (DNS_R_KEYUNAUTHORIZED);
3091 result = dns_view_simplefind(view, &sig.signer,
3092 dns_rdatatype_key /* SIG(0) */,
3093 0, 0, ISC_FALSE, &keyset, NULL);
3095 if (result != ISC_R_SUCCESS) {
3096 /* XXXBEW Should possibly create a fetch here */
3097 result = DNS_R_KEYUNAUTHORIZED;
3099 } else if (keyset.trust < dns_trust_secure) {
3100 /* XXXBEW Should call a validator here */
3101 result = DNS_R_KEYUNAUTHORIZED;
3104 result = dns_rdataset_first(&keyset);
3105 INSIST(result == ISC_R_SUCCESS);
3107 result == ISC_R_SUCCESS;
3108 result = dns_rdataset_next(&keyset))
3110 dst_key_t *key = NULL;
3112 dns_rdata_reset(&rdata);
3113 dns_rdataset_current(&keyset, &rdata);
3114 isc_buffer_init(&b, rdata.data, rdata.length);
3115 isc_buffer_add(&b, rdata.length);
3117 result = dst_key_fromdns(&sig.signer, rdata.rdclass,
3118 &b, view->mctx, &key);
3119 if (result != ISC_R_SUCCESS)
3121 if (dst_key_alg(key) != sig.algorithm ||
3122 dst_key_id(key) != sig.keyid ||
3123 !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3124 dst_key_proto(key) == DNS_KEYPROTO_ANY))
3129 result = dns_dnssec_verifymessage(&msgb, msg, key);
3131 if (result == ISC_R_SUCCESS)
3134 if (result == ISC_R_NOMORE)
3135 result = DNS_R_KEYUNAUTHORIZED;
3138 if (dns_rdataset_isassociated(&keyset))
3139 dns_rdataset_disassociate(&keyset);
3140 dns_rdata_freestruct(&sig);
3146 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3147 const dns_master_style_t *style,
3148 dns_messagetextflag_t flags,
3149 isc_buffer_t *target) {
3150 dns_name_t *name, empty_name;
3151 dns_rdataset_t *rdataset;
3152 isc_result_t result;
3153 isc_boolean_t seensoa = ISC_FALSE;
3155 REQUIRE(DNS_MESSAGE_VALID(msg));
3156 REQUIRE(target != NULL);
3157 REQUIRE(VALID_SECTION(section));
3159 if (ISC_LIST_EMPTY(msg->sections[section]))
3160 return (ISC_R_SUCCESS);
3162 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3163 ADD_STRING(target, ";; ");
3164 if (msg->opcode != dns_opcode_update) {
3165 ADD_STRING(target, sectiontext[section]);
3167 ADD_STRING(target, updsectiontext[section]);
3169 ADD_STRING(target, " SECTION:\n");
3172 dns_name_init(&empty_name, NULL);
3173 result = dns_message_firstname(msg, section);
3174 if (result != ISC_R_SUCCESS) {
3179 dns_message_currentname(msg, section, &name);
3180 for (rdataset = ISC_LIST_HEAD(name->list);
3182 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3183 if (section == DNS_SECTION_ANSWER &&
3184 rdataset->type == dns_rdatatype_soa) {
3185 if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
3188 (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
3192 if (section == DNS_SECTION_QUESTION) {
3193 ADD_STRING(target, ";");
3194 result = dns_master_questiontotext(name,
3199 result = dns_master_rdatasettotext(name,
3204 if (result != ISC_R_SUCCESS)
3207 result = dns_message_nextname(msg, section);
3208 } while (result == ISC_R_SUCCESS);
3209 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3210 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3211 ADD_STRING(target, "\n");
3212 if (result == ISC_R_NOMORE)
3213 result = ISC_R_SUCCESS;
3218 dns_message_pseudosectiontotext(dns_message_t *msg,
3219 dns_pseudosection_t section,
3220 const dns_master_style_t *style,
3221 dns_messagetextflag_t flags,
3222 isc_buffer_t *target) {
3223 dns_rdataset_t *ps = NULL;
3224 dns_name_t *name = NULL;
3225 isc_result_t result;
3226 char buf[sizeof("1234567890")];
3229 isc_buffer_t optbuf;
3230 isc_uint16_t optcode, optlen;
3231 unsigned char *optdata;
3233 REQUIRE(DNS_MESSAGE_VALID(msg));
3234 REQUIRE(target != NULL);
3235 REQUIRE(VALID_PSEUDOSECTION(section));
3238 case DNS_PSEUDOSECTION_OPT:
3239 ps = dns_message_getopt(msg);
3241 return (ISC_R_SUCCESS);
3242 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3243 ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3244 ADD_STRING(target, "; EDNS: version: ");
3245 snprintf(buf, sizeof(buf), "%u",
3246 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3247 ADD_STRING(target, buf);
3248 ADD_STRING(target, ", flags:");
3249 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3250 ADD_STRING(target, " do");
3251 mbz = ps->ttl & 0xffff;
3252 mbz &= ~DNS_MESSAGEEXTFLAG_DO; /* Known Flags. */
3254 ADD_STRING(target, "; MBZ: ");
3255 snprintf(buf, sizeof(buf), "%.4x ", mbz);
3256 ADD_STRING(target, buf);
3257 ADD_STRING(target, ", udp: ");
3259 ADD_STRING(target, "; udp: ");
3260 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3261 ADD_STRING(target, buf);
3263 result = dns_rdataset_first(ps);
3264 if (result != ISC_R_SUCCESS)
3265 return (ISC_R_SUCCESS);
3267 /* Print EDNS info, if any */
3268 dns_rdata_init(&rdata);
3269 dns_rdataset_current(ps, &rdata);
3271 isc_buffer_init(&optbuf, rdata.data, rdata.length);
3272 isc_buffer_add(&optbuf, rdata.length);
3273 while (isc_buffer_remaininglength(&optbuf) != 0) {
3274 INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3275 optcode = isc_buffer_getuint16(&optbuf);
3276 optlen = isc_buffer_getuint16(&optbuf);
3277 INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3279 if (optcode == DNS_OPT_NSID) {
3280 ADD_STRING(target, "; NSID");
3282 ADD_STRING(target, "; OPT=");
3283 sprintf(buf, "%u", optcode);
3284 ADD_STRING(target, buf);
3289 ADD_STRING(target, ": ");
3291 optdata = isc_buffer_current(&optbuf);
3292 for (i = 0; i < optlen; i++) {
3293 sprintf(buf, "%02x ", optdata[i]);
3294 ADD_STRING(target, buf);
3296 for (i = 0; i < optlen; i++) {
3297 ADD_STRING(target, " (");
3298 if (isprint(optdata[i]))
3299 isc_buffer_putmem(target,
3303 isc_buffer_putstr(target, ".");
3304 ADD_STRING(target, ")");
3306 isc_buffer_forward(&optbuf, optlen);
3308 ADD_STRING(target, "\n");
3310 return (ISC_R_SUCCESS);
3311 case DNS_PSEUDOSECTION_TSIG:
3312 ps = dns_message_gettsig(msg, &name);
3314 return (ISC_R_SUCCESS);
3315 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3316 ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
3317 result = dns_master_rdatasettotext(name, ps, style, target);
3318 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3319 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3320 ADD_STRING(target, "\n");
3322 case DNS_PSEUDOSECTION_SIG0:
3323 ps = dns_message_getsig0(msg, &name);
3325 return (ISC_R_SUCCESS);
3326 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3327 ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3328 result = dns_master_rdatasettotext(name, ps, style, target);
3329 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3330 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3331 ADD_STRING(target, "\n");
3334 return (ISC_R_UNEXPECTED);
3338 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3339 dns_messagetextflag_t flags, isc_buffer_t *target) {
3340 char buf[sizeof("1234567890")];
3341 isc_result_t result;
3343 REQUIRE(DNS_MESSAGE_VALID(msg));
3344 REQUIRE(target != NULL);
3346 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
3347 ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
3348 ADD_STRING(target, opcodetext[msg->opcode]);
3349 ADD_STRING(target, ", status: ");
3350 if (msg->rcode < (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
3351 ADD_STRING(target, rcodetext[msg->rcode]);
3353 snprintf(buf, sizeof(buf), "%4u", msg->rcode);
3354 ADD_STRING(target, buf);
3356 ADD_STRING(target, ", id: ");
3357 snprintf(buf, sizeof(buf), "%6u", msg->id);
3358 ADD_STRING(target, buf);
3359 ADD_STRING(target, "\n;; flags:");
3360 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3361 ADD_STRING(target, " qr");
3362 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3363 ADD_STRING(target, " aa");
3364 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3365 ADD_STRING(target, " tc");
3366 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3367 ADD_STRING(target, " rd");
3368 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3369 ADD_STRING(target, " ra");
3370 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3371 ADD_STRING(target, " ad");
3372 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
3373 ADD_STRING(target, " cd");
3375 * The final unnamed flag must be zero.
3377 if ((msg->flags & 0x0040U) != 0)
3378 ADD_STRING(target, "; MBZ: 0x4");
3379 if (msg->opcode != dns_opcode_update) {
3380 ADD_STRING(target, "; QUESTION: ");
3382 ADD_STRING(target, "; ZONE: ");
3384 snprintf(buf, sizeof(buf), "%1u",
3385 msg->counts[DNS_SECTION_QUESTION]);
3386 ADD_STRING(target, buf);
3387 if (msg->opcode != dns_opcode_update) {
3388 ADD_STRING(target, ", ANSWER: ");
3390 ADD_STRING(target, ", PREREQ: ");
3392 snprintf(buf, sizeof(buf), "%1u",
3393 msg->counts[DNS_SECTION_ANSWER]);
3394 ADD_STRING(target, buf);
3395 if (msg->opcode != dns_opcode_update) {
3396 ADD_STRING(target, ", AUTHORITY: ");
3398 ADD_STRING(target, ", UPDATE: ");
3400 snprintf(buf, sizeof(buf), "%1u",
3401 msg->counts[DNS_SECTION_AUTHORITY]);
3402 ADD_STRING(target, buf);
3403 ADD_STRING(target, ", ADDITIONAL: ");
3404 snprintf(buf, sizeof(buf), "%1u",
3405 msg->counts[DNS_SECTION_ADDITIONAL]);
3406 ADD_STRING(target, buf);
3407 ADD_STRING(target, "\n");
3409 result = dns_message_pseudosectiontotext(msg,
3410 DNS_PSEUDOSECTION_OPT,
3411 style, flags, target);
3412 if (result != ISC_R_SUCCESS)
3415 result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
3416 style, flags, target);
3417 if (result != ISC_R_SUCCESS)
3419 result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
3420 style, flags, target);
3421 if (result != ISC_R_SUCCESS)
3423 result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
3424 style, flags, target);
3425 if (result != ISC_R_SUCCESS)
3427 result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
3428 style, flags, target);
3429 if (result != ISC_R_SUCCESS)
3432 result = dns_message_pseudosectiontotext(msg,
3433 DNS_PSEUDOSECTION_TSIG,
3434 style, flags, target);
3435 if (result != ISC_R_SUCCESS)
3438 result = dns_message_pseudosectiontotext(msg,
3439 DNS_PSEUDOSECTION_SIG0,
3440 style, flags, target);
3441 if (result != ISC_R_SUCCESS)
3444 return (ISC_R_SUCCESS);
3448 dns_message_getrawmessage(dns_message_t *msg) {
3449 REQUIRE(DNS_MESSAGE_VALID(msg));
3450 return (&msg->saved);
3454 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3455 const void *order_arg)
3457 REQUIRE(DNS_MESSAGE_VALID(msg));
3459 msg->order_arg = order_arg;
3463 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3464 REQUIRE(DNS_MESSAGE_VALID(msg));
3465 msg->timeadjust = timeadjust;
3469 dns_message_gettimeadjust(dns_message_t *msg) {
3470 REQUIRE(DNS_MESSAGE_VALID(msg));
3471 return (msg->timeadjust);
3475 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3477 REQUIRE(opcode < 16);
3479 if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
3480 return (ISC_R_NOSPACE);
3481 isc_buffer_putstr(target, opcodetext[opcode]);
3482 return (ISC_R_SUCCESS);
3486 dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp,
3487 unsigned int version, isc_uint16_t udpsize,
3488 unsigned int flags, dns_ednsopt_t *ednsopts, size_t count)
3490 dns_rdataset_t *rdataset = NULL;
3491 dns_rdatalist_t *rdatalist = NULL;
3492 dns_rdata_t *rdata = NULL;
3493 isc_result_t result;
3494 unsigned int len = 0, i;
3496 REQUIRE(DNS_MESSAGE_VALID(message));
3497 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
3499 result = dns_message_gettemprdatalist(message, &rdatalist);
3500 if (result != ISC_R_SUCCESS)
3502 result = dns_message_gettemprdata(message, &rdata);
3503 if (result != ISC_R_SUCCESS)
3505 result = dns_message_gettemprdataset(message, &rdataset);
3506 if (result != ISC_R_SUCCESS)
3508 dns_rdataset_init(rdataset);
3510 rdatalist->type = dns_rdatatype_opt;
3511 rdatalist->covers = 0;
3514 * Set Maximum UDP buffer size.
3516 rdatalist->rdclass = udpsize;
3519 * Set EXTENDED-RCODE and Z to 0.
3521 rdatalist->ttl = (version << 16);
3522 rdatalist->ttl |= (flags & 0xffff);
3525 * Set EDNS options if applicable
3528 isc_buffer_t *buf = NULL;
3529 for (i = 0; i < count; i++)
3530 len += ednsopts[i].length + 4;
3532 if (len > 0xffffU) {
3533 result = ISC_R_NOSPACE;
3537 result = isc_buffer_allocate(message->mctx, &buf, len);
3538 if (result != ISC_R_SUCCESS)
3541 for (i = 0; i < count; i++) {
3542 isc_buffer_putuint16(buf, ednsopts[i].code);
3543 isc_buffer_putuint16(buf, ednsopts[i].length);
3544 isc_buffer_putmem(buf, ednsopts[i].value,
3545 ednsopts[i].length);
3547 rdata->data = isc_buffer_base(buf);
3548 rdata->length = len;
3549 dns_message_takebuffer(message, &buf);
3555 rdata->rdclass = rdatalist->rdclass;
3556 rdata->type = rdatalist->type;
3559 ISC_LIST_INIT(rdatalist->rdata);
3560 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
3561 result = dns_rdatalist_tordataset(rdatalist, rdataset);
3562 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3564 *rdatasetp = rdataset;
3565 return (ISC_R_SUCCESS);
3569 dns_message_puttemprdata(message, &rdata);
3570 if (rdataset != NULL)
3571 dns_message_puttemprdataset(message, &rdataset);
3572 if (rdatalist != NULL)
3573 dns_message_puttemprdatalist(message, &rdatalist);
3578 dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) {
3580 REQUIRE(DNS_MESSAGE_VALID(msg));
3581 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
3582 REQUIRE(msg->state == DNS_SECTION_ANY);
3583 REQUIRE(msg->rdclass_set == 0);
3585 msg->rdclass = rdclass;
3586 msg->rdclass_set = 1;