Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / dns / message.c
blobbad2c2b075a644f09f644d97e745461175409849
1 /* $NetBSD: message.c,v 1.1.1.3 2009/12/26 22:24:41 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: message.c,v 1.249 2009/11/24 03:20:02 marka Exp */
22 /*! \file */
24 /***
25 *** Imports
26 ***/
28 #include <config.h>
29 #include <ctype.h>
31 #include <isc/buffer.h>
32 #include <isc/mem.h>
33 #include <isc/print.h>
34 #include <isc/string.h> /* Required for HP/UX (and others?) */
35 #include <isc/util.h>
37 #include <dns/dnssec.h>
38 #include <dns/keyvalues.h>
39 #include <dns/log.h>
40 #include <dns/masterdump.h>
41 #include <dns/message.h>
42 #include <dns/opcode.h>
43 #include <dns/rdata.h>
44 #include <dns/rdatalist.h>
45 #include <dns/rdataset.h>
46 #include <dns/rdatastruct.h>
47 #include <dns/result.h>
48 #include <dns/tsig.h>
49 #include <dns/view.h>
51 #ifdef SKAN_MSG_DEBUG
52 static void
53 hexdump(const char *msg, const char *msg2, void *base, size_t len) {
54 unsigned char *p;
55 unsigned int cnt;
57 p = base;
58 cnt = 0;
60 printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base);
62 while (cnt < len) {
63 if (cnt % 16 == 0)
64 printf("%p: ", p);
65 else if (cnt % 8 == 0)
66 printf(" |");
67 printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
68 p++;
69 cnt++;
71 if (cnt % 16 == 0)
72 printf("\n");
75 if (cnt % 16 != 0)
76 printf("\n");
78 #endif
80 #define DNS_MESSAGE_OPCODE_MASK 0x7800U
81 #define DNS_MESSAGE_OPCODE_SHIFT 11
82 #define DNS_MESSAGE_RCODE_MASK 0x000fU
83 #define DNS_MESSAGE_FLAG_MASK 0x8ff0U
84 #define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U
85 #define DNS_MESSAGE_EDNSRCODE_SHIFT 24
86 #define DNS_MESSAGE_EDNSVERSION_MASK 0x00ff0000U
87 #define DNS_MESSAGE_EDNSVERSION_SHIFT 16
89 #define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \
90 && ((s) < DNS_SECTION_MAX))
91 #define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \
92 && ((s) < DNS_SECTION_MAX))
93 #define ADD_STRING(b, s) {if (strlen(s) >= \
94 isc_buffer_availablelength(b)) \
95 return(ISC_R_NOSPACE); else \
96 isc_buffer_putstr(b, s);}
97 #define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \
98 && ((s) < DNS_PSEUDOSECTION_MAX))
100 #define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
103 * This is the size of each individual scratchpad buffer, and the numbers
104 * of various block allocations used within the server.
105 * XXXMLG These should come from a config setting.
107 #define SCRATCHPAD_SIZE 512
108 #define NAME_COUNT 8
109 #define OFFSET_COUNT 4
110 #define RDATA_COUNT 8
111 #define RDATALIST_COUNT 8
112 #define RDATASET_COUNT RDATALIST_COUNT
115 * Text representation of the different items, for message_totext
116 * functions.
118 static const char *sectiontext[] = {
119 "QUESTION",
120 "ANSWER",
121 "AUTHORITY",
122 "ADDITIONAL"
125 static const char *updsectiontext[] = {
126 "ZONE",
127 "PREREQUISITE",
128 "UPDATE",
129 "ADDITIONAL"
132 static const char *opcodetext[] = {
133 "QUERY",
134 "IQUERY",
135 "STATUS",
136 "RESERVED3",
137 "NOTIFY",
138 "UPDATE",
139 "RESERVED6",
140 "RESERVED7",
141 "RESERVED8",
142 "RESERVED9",
143 "RESERVED10",
144 "RESERVED11",
145 "RESERVED12",
146 "RESERVED13",
147 "RESERVED14",
148 "RESERVED15"
151 static const char *rcodetext[] = {
152 "NOERROR",
153 "FORMERR",
154 "SERVFAIL",
155 "NXDOMAIN",
156 "NOTIMP",
157 "REFUSED",
158 "YXDOMAIN",
159 "YXRRSET",
160 "NXRRSET",
161 "NOTAUTH",
162 "NOTZONE",
163 "RESERVED11",
164 "RESERVED12",
165 "RESERVED13",
166 "RESERVED14",
167 "RESERVED15",
168 "BADVERS"
173 * "helper" type, which consists of a block of some type, and is linkable.
174 * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
175 * size, or the allocated elements will not be aligned correctly.
177 struct dns_msgblock {
178 unsigned int count;
179 unsigned int remaining;
180 ISC_LINK(dns_msgblock_t) link;
181 }; /* dynamically sized */
183 static inline dns_msgblock_t *
184 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
186 #define msgblock_get(block, type) \
187 ((type *)msgblock_internalget(block, sizeof(type)))
189 static inline void *
190 msgblock_internalget(dns_msgblock_t *, unsigned int);
192 static inline void
193 msgblock_reset(dns_msgblock_t *);
195 static inline void
196 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
199 * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory
200 * is free, return NULL.
202 static inline dns_msgblock_t *
203 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
204 unsigned int count)
206 dns_msgblock_t *block;
207 unsigned int length;
209 length = sizeof(dns_msgblock_t) + (sizeof_type * count);
211 block = isc_mem_get(mctx, length);
212 if (block == NULL)
213 return (NULL);
215 block->count = count;
216 block->remaining = count;
218 ISC_LINK_INIT(block, link);
220 return (block);
224 * Return an element from the msgblock. If no more are available, return
225 * NULL.
227 static inline void *
228 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
229 void *ptr;
231 if (block == NULL || block->remaining == 0)
232 return (NULL);
234 block->remaining--;
236 ptr = (((unsigned char *)block)
237 + sizeof(dns_msgblock_t)
238 + (sizeof_type * block->remaining));
240 return (ptr);
243 static inline void
244 msgblock_reset(dns_msgblock_t *block) {
245 block->remaining = block->count;
249 * Release memory associated with a message block.
251 static inline void
252 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
254 unsigned int length;
256 length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
258 isc_mem_put(mctx, block, length);
262 * Allocate a new dynamic buffer, and attach it to this message as the
263 * "current" buffer. (which is always the last on the list, for our
264 * uses)
266 static inline isc_result_t
267 newbuffer(dns_message_t *msg, unsigned int size) {
268 isc_result_t result;
269 isc_buffer_t *dynbuf;
271 dynbuf = NULL;
272 result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
273 if (result != ISC_R_SUCCESS)
274 return (ISC_R_NOMEMORY);
276 ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
277 return (ISC_R_SUCCESS);
280 static inline isc_buffer_t *
281 currentbuffer(dns_message_t *msg) {
282 isc_buffer_t *dynbuf;
284 dynbuf = ISC_LIST_TAIL(msg->scratchpad);
285 INSIST(dynbuf != NULL);
287 return (dynbuf);
290 static inline void
291 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
292 ISC_LIST_PREPEND(msg->freerdata, rdata, link);
295 static inline dns_rdata_t *
296 newrdata(dns_message_t *msg) {
297 dns_msgblock_t *msgblock;
298 dns_rdata_t *rdata;
300 rdata = ISC_LIST_HEAD(msg->freerdata);
301 if (rdata != NULL) {
302 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
303 return (rdata);
306 msgblock = ISC_LIST_TAIL(msg->rdatas);
307 rdata = msgblock_get(msgblock, dns_rdata_t);
308 if (rdata == NULL) {
309 msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
310 RDATA_COUNT);
311 if (msgblock == NULL)
312 return (NULL);
314 ISC_LIST_APPEND(msg->rdatas, msgblock, link);
316 rdata = msgblock_get(msgblock, dns_rdata_t);
319 dns_rdata_init(rdata);
320 return (rdata);
323 static inline void
324 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
325 ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
328 static inline dns_rdatalist_t *
329 newrdatalist(dns_message_t *msg) {
330 dns_msgblock_t *msgblock;
331 dns_rdatalist_t *rdatalist;
333 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
334 if (rdatalist != NULL) {
335 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
336 return (rdatalist);
339 msgblock = ISC_LIST_TAIL(msg->rdatalists);
340 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
341 if (rdatalist == NULL) {
342 msgblock = msgblock_allocate(msg->mctx,
343 sizeof(dns_rdatalist_t),
344 RDATALIST_COUNT);
345 if (msgblock == NULL)
346 return (NULL);
348 ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
350 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
353 return (rdatalist);
356 static inline dns_offsets_t *
357 newoffsets(dns_message_t *msg) {
358 dns_msgblock_t *msgblock;
359 dns_offsets_t *offsets;
361 msgblock = ISC_LIST_TAIL(msg->offsets);
362 offsets = msgblock_get(msgblock, dns_offsets_t);
363 if (offsets == NULL) {
364 msgblock = msgblock_allocate(msg->mctx,
365 sizeof(dns_offsets_t),
366 OFFSET_COUNT);
367 if (msgblock == NULL)
368 return (NULL);
370 ISC_LIST_APPEND(msg->offsets, msgblock, link);
372 offsets = msgblock_get(msgblock, dns_offsets_t);
375 return (offsets);
378 static inline void
379 msginitheader(dns_message_t *m) {
380 m->id = 0;
381 m->flags = 0;
382 m->rcode = 0;
383 m->opcode = 0;
384 m->rdclass = 0;
387 static inline void
388 msginitprivate(dns_message_t *m) {
389 unsigned int i;
391 for (i = 0; i < DNS_SECTION_MAX; i++) {
392 m->cursors[i] = NULL;
393 m->counts[i] = 0;
395 m->opt = NULL;
396 m->sig0 = NULL;
397 m->sig0name = NULL;
398 m->tsig = NULL;
399 m->tsigname = NULL;
400 m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */
401 m->opt_reserved = 0;
402 m->sig_reserved = 0;
403 m->reserved = 0;
404 m->buffer = NULL;
407 static inline void
408 msginittsig(dns_message_t *m) {
409 m->tsigstatus = dns_rcode_noerror;
410 m->querytsigstatus = dns_rcode_noerror;
411 m->tsigkey = NULL;
412 m->tsigctx = NULL;
413 m->sigstart = -1;
414 m->sig0key = NULL;
415 m->sig0status = dns_rcode_noerror;
416 m->timeadjust = 0;
420 * Init elements to default state. Used both when allocating a new element
421 * and when resetting one.
423 static inline void
424 msginit(dns_message_t *m) {
425 msginitheader(m);
426 msginitprivate(m);
427 msginittsig(m);
428 m->header_ok = 0;
429 m->question_ok = 0;
430 m->tcp_continuation = 0;
431 m->verified_sig = 0;
432 m->verify_attempted = 0;
433 m->order = NULL;
434 m->order_arg = NULL;
435 m->query.base = NULL;
436 m->query.length = 0;
437 m->free_query = 0;
438 m->saved.base = NULL;
439 m->saved.length = 0;
440 m->free_saved = 0;
441 m->querytsig = NULL;
444 static inline void
445 msgresetnames(dns_message_t *msg, unsigned int first_section) {
446 unsigned int i;
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);
467 rds = next_rds;
469 if (dns_name_dynamic(name))
470 dns_name_free(name, msg->mctx);
471 isc_mempool_put(msg->namepool, name);
472 name = next_name;
477 static void
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);
488 msg->opt = NULL;
492 static void
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);
501 if (replying) {
502 INSIST(msg->querytsig == NULL);
503 msg->querytsig = msg->tsig;
504 } else {
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);
515 msg->tsig = NULL;
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);
531 msg->sig0 = NULL;
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().
540 static void
541 msgreset(dns_message_t *msg, isc_boolean_t everything) {
542 dns_msgblock_t *msgblock, *next_msgblock;
543 isc_buffer_t *dynbuf, *next_dynbuf;
544 dns_rdata_t *rdata;
545 dns_rdatalist_t *rdatalist;
547 msgresetnames(msg, 0);
548 msgresetopt(msg);
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
558 * have allocated.
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);
573 if (!everything) {
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);
626 msg->tsigkey = NULL;
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,
635 msg->query.length);
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,
643 msg->saved.length);
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.
662 if (!everything)
663 msginit(msg);
665 ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
666 ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
669 static unsigned int
670 spacefortsig(dns_tsigkey_t *key, int otherlen) {
671 isc_region_t r1, r2;
672 unsigned int x;
673 isc_result_t result;
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)
699 x = 0;
700 else {
701 result = dst_key_sigsize(key->key, &x);
702 if (result != ISC_R_SUCCESS)
703 x = 0;
705 return (26 + r1.length + r2.length + x + otherlen);
708 isc_result_t
709 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
711 dns_message_t *m;
712 isc_result_t result;
713 isc_buffer_t *dynbuf;
714 unsigned int i;
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));
723 if (m == NULL)
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;
733 msginit(m);
735 for (i = 0; i < DNS_SECTION_MAX; i++)
736 ISC_LIST_INIT(m->sections[i]);
737 m->mctx = mctx;
739 ISC_LIST_INIT(m->scratchpad);
740 ISC_LIST_INIT(m->cleanup);
741 m->namepool = NULL;
742 m->rdspool = NULL;
743 ISC_LIST_INIT(m->rdatas);
744 ISC_LIST_INIT(m->rdatalists);
745 ISC_LIST_INIT(m->offsets);
746 ISC_LIST_INIT(m->freerdata);
747 ISC_LIST_INIT(m->freerdatalist);
750 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
753 result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
754 if (result != ISC_R_SUCCESS)
755 goto cleanup;
756 isc_mempool_setfreemax(m->namepool, NAME_COUNT);
757 isc_mempool_setname(m->namepool, "msg:names");
759 result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
760 &m->rdspool);
761 if (result != ISC_R_SUCCESS)
762 goto cleanup;
763 isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
764 isc_mempool_setname(m->rdspool, "msg:rdataset");
766 dynbuf = NULL;
767 result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
768 if (result != ISC_R_SUCCESS)
769 goto cleanup;
770 ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
772 m->cctx = NULL;
774 *msgp = m;
775 return (ISC_R_SUCCESS);
778 * Cleanup for error returns.
780 cleanup:
781 dynbuf = ISC_LIST_HEAD(m->scratchpad);
782 if (dynbuf != NULL) {
783 ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
784 isc_buffer_free(&dynbuf);
786 if (m->namepool != NULL)
787 isc_mempool_destroy(&m->namepool);
788 if (m->rdspool != NULL)
789 isc_mempool_destroy(&m->rdspool);
790 m->magic = 0;
791 isc_mem_put(mctx, m, sizeof(dns_message_t));
793 return (ISC_R_NOMEMORY);
796 void
797 dns_message_reset(dns_message_t *msg, unsigned int intent) {
798 REQUIRE(DNS_MESSAGE_VALID(msg));
799 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
800 || intent == DNS_MESSAGE_INTENTRENDER);
802 msgreset(msg, ISC_FALSE);
803 msg->from_to_wire = intent;
806 void
807 dns_message_destroy(dns_message_t **msgp) {
808 dns_message_t *msg;
810 REQUIRE(msgp != NULL);
811 REQUIRE(DNS_MESSAGE_VALID(*msgp));
813 msg = *msgp;
814 *msgp = NULL;
816 msgreset(msg, ISC_TRUE);
817 isc_mempool_destroy(&msg->namepool);
818 isc_mempool_destroy(&msg->rdspool);
819 msg->magic = 0;
820 isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
823 static isc_result_t
824 findname(dns_name_t **foundname, dns_name_t *target,
825 dns_namelist_t *section)
827 dns_name_t *curr;
829 for (curr = ISC_LIST_TAIL(*section);
830 curr != NULL;
831 curr = ISC_LIST_PREV(curr, link)) {
832 if (dns_name_equal(curr, target)) {
833 if (foundname != NULL)
834 *foundname = curr;
835 return (ISC_R_SUCCESS);
839 return (ISC_R_NOTFOUND);
842 isc_result_t
843 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
844 dns_rdatatype_t type, dns_rdatatype_t covers,
845 dns_rdataset_t **rdataset)
847 dns_rdataset_t *curr;
849 if (rdataset != NULL) {
850 REQUIRE(*rdataset == NULL);
853 for (curr = ISC_LIST_TAIL(name->list);
854 curr != NULL;
855 curr = ISC_LIST_PREV(curr, link)) {
856 if (curr->rdclass == rdclass &&
857 curr->type == type && curr->covers == covers) {
858 if (rdataset != NULL)
859 *rdataset = curr;
860 return (ISC_R_SUCCESS);
864 return (ISC_R_NOTFOUND);
867 isc_result_t
868 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
869 dns_rdatatype_t covers, dns_rdataset_t **rdataset)
871 dns_rdataset_t *curr;
873 REQUIRE(name != NULL);
874 if (rdataset != NULL) {
875 REQUIRE(*rdataset == NULL);
878 for (curr = ISC_LIST_TAIL(name->list);
879 curr != NULL;
880 curr = ISC_LIST_PREV(curr, link)) {
881 if (curr->type == type && curr->covers == covers) {
882 if (rdataset != NULL)
883 *rdataset = curr;
884 return (ISC_R_SUCCESS);
888 return (ISC_R_NOTFOUND);
892 * Read a name from buffer "source".
894 static isc_result_t
895 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
896 dns_decompress_t *dctx)
898 isc_buffer_t *scratch;
899 isc_result_t result;
900 unsigned int tries;
902 scratch = currentbuffer(msg);
905 * First try: use current buffer.
906 * Second try: allocate a new buffer and use that.
908 tries = 0;
909 while (tries < 2) {
910 result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
911 scratch);
913 if (result == ISC_R_NOSPACE) {
914 tries++;
916 result = newbuffer(msg, SCRATCHPAD_SIZE);
917 if (result != ISC_R_SUCCESS)
918 return (result);
920 scratch = currentbuffer(msg);
921 dns_name_reset(name);
922 } else {
923 return (result);
927 INSIST(0); /* Cannot get here... */
928 return (ISC_R_UNEXPECTED);
931 static isc_result_t
932 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
933 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
934 unsigned int rdatalen, dns_rdata_t *rdata)
936 isc_buffer_t *scratch;
937 isc_result_t result;
938 unsigned int tries;
939 unsigned int trysize;
941 scratch = currentbuffer(msg);
943 isc_buffer_setactive(source, rdatalen);
946 * First try: use current buffer.
947 * Second try: allocate a new buffer of size
948 * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
949 * (the data will fit if it was not more than 50% compressed)
950 * Subsequent tries: double buffer size on each try.
952 tries = 0;
953 trysize = 0;
954 /* XXX possibly change this to a while (tries < 2) loop */
955 for (;;) {
956 result = dns_rdata_fromwire(rdata, rdclass, rdtype,
957 source, dctx, 0,
958 scratch);
960 if (result == ISC_R_NOSPACE) {
961 if (tries == 0) {
962 trysize = 2 * rdatalen;
963 if (trysize < SCRATCHPAD_SIZE)
964 trysize = SCRATCHPAD_SIZE;
965 } else {
966 INSIST(trysize != 0);
967 if (trysize >= 65535)
968 return (ISC_R_NOSPACE);
969 /* XXX DNS_R_RRTOOLONG? */
970 trysize *= 2;
972 tries++;
973 result = newbuffer(msg, trysize);
974 if (result != ISC_R_SUCCESS)
975 return (result);
977 scratch = currentbuffer(msg);
978 } else {
979 return (result);
984 #define DO_FORMERR \
985 do { \
986 if (best_effort) \
987 seen_problem = ISC_TRUE; \
988 else { \
989 result = DNS_R_FORMERR; \
990 goto cleanup; \
992 } while (0)
994 static isc_result_t
995 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
996 unsigned int options)
998 isc_region_t r;
999 unsigned int count;
1000 dns_name_t *name;
1001 dns_name_t *name2;
1002 dns_offsets_t *offsets;
1003 dns_rdataset_t *rdataset;
1004 dns_rdatalist_t *rdatalist;
1005 isc_result_t result;
1006 dns_rdatatype_t rdtype;
1007 dns_rdataclass_t rdclass;
1008 dns_namelist_t *section;
1009 isc_boolean_t free_name;
1010 isc_boolean_t best_effort;
1011 isc_boolean_t seen_problem;
1013 section = &msg->sections[DNS_SECTION_QUESTION];
1015 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1016 seen_problem = ISC_FALSE;
1018 name = NULL;
1019 rdataset = NULL;
1020 rdatalist = NULL;
1022 for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
1023 name = isc_mempool_get(msg->namepool);
1024 if (name == NULL)
1025 return (ISC_R_NOMEMORY);
1026 free_name = ISC_TRUE;
1028 offsets = newoffsets(msg);
1029 if (offsets == NULL) {
1030 result = ISC_R_NOMEMORY;
1031 goto cleanup;
1033 dns_name_init(name, *offsets);
1036 * Parse the name out of this packet.
1038 isc_buffer_remainingregion(source, &r);
1039 isc_buffer_setactive(source, r.length);
1040 result = getname(name, source, msg, dctx);
1041 if (result != ISC_R_SUCCESS)
1042 goto cleanup;
1045 * Run through the section, looking to see if this name
1046 * is already there. If it is found, put back the allocated
1047 * name since we no longer need it, and set our name pointer
1048 * to point to the name we found.
1050 result = findname(&name2, name, section);
1053 * If it is the first name in the section, accept it.
1055 * If it is not, but is not the same as the name already
1056 * in the question section, append to the section. Note that
1057 * here in the question section this is illegal, so return
1058 * FORMERR. In the future, check the opcode to see if
1059 * this should be legal or not. In either case we no longer
1060 * need this name pointer.
1062 if (result != ISC_R_SUCCESS) {
1063 if (!ISC_LIST_EMPTY(*section))
1064 DO_FORMERR;
1065 ISC_LIST_APPEND(*section, name, link);
1066 free_name = ISC_FALSE;
1067 } else {
1068 isc_mempool_put(msg->namepool, name);
1069 name = name2;
1070 name2 = NULL;
1071 free_name = ISC_FALSE;
1075 * Get type and class.
1077 isc_buffer_remainingregion(source, &r);
1078 if (r.length < 4) {
1079 result = ISC_R_UNEXPECTEDEND;
1080 goto cleanup;
1082 rdtype = isc_buffer_getuint16(source);
1083 rdclass = isc_buffer_getuint16(source);
1086 * If this class is different than the one we already read,
1087 * this is an error.
1089 if (msg->state == DNS_SECTION_ANY) {
1090 msg->state = DNS_SECTION_QUESTION;
1091 msg->rdclass = rdclass;
1092 } else if (msg->rdclass != rdclass)
1093 DO_FORMERR;
1096 * Can't ask the same question twice.
1098 result = dns_message_find(name, rdclass, rdtype, 0, NULL);
1099 if (result == ISC_R_SUCCESS)
1100 DO_FORMERR;
1103 * Allocate a new rdatalist.
1105 rdatalist = newrdatalist(msg);
1106 if (rdatalist == NULL) {
1107 result = ISC_R_NOMEMORY;
1108 goto cleanup;
1110 rdataset = isc_mempool_get(msg->rdspool);
1111 if (rdataset == NULL) {
1112 result = ISC_R_NOMEMORY;
1113 goto cleanup;
1117 * Convert rdatalist to rdataset, and attach the latter to
1118 * the name.
1120 rdatalist->type = rdtype;
1121 rdatalist->covers = 0;
1122 rdatalist->rdclass = rdclass;
1123 rdatalist->ttl = 0;
1124 ISC_LIST_INIT(rdatalist->rdata);
1126 dns_rdataset_init(rdataset);
1127 result = dns_rdatalist_tordataset(rdatalist, rdataset);
1128 if (result != ISC_R_SUCCESS)
1129 goto cleanup;
1131 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1133 ISC_LIST_APPEND(name->list, rdataset, link);
1134 rdataset = NULL;
1137 if (seen_problem)
1138 return (DNS_R_RECOVERABLE);
1139 return (ISC_R_SUCCESS);
1141 cleanup:
1142 if (rdataset != NULL) {
1143 INSIST(!dns_rdataset_isassociated(rdataset));
1144 isc_mempool_put(msg->rdspool, rdataset);
1146 #if 0
1147 if (rdatalist != NULL)
1148 isc_mempool_put(msg->rdlpool, rdatalist);
1149 #endif
1150 if (free_name)
1151 isc_mempool_put(msg->namepool, name);
1153 return (result);
1156 static isc_boolean_t
1157 update(dns_section_t section, dns_rdataclass_t rdclass) {
1158 if (section == DNS_SECTION_PREREQUISITE)
1159 return (ISC_TF(rdclass == dns_rdataclass_any ||
1160 rdclass == dns_rdataclass_none));
1161 if (section == DNS_SECTION_UPDATE)
1162 return (ISC_TF(rdclass == dns_rdataclass_any));
1163 return (ISC_FALSE);
1166 static isc_result_t
1167 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1168 dns_section_t sectionid, unsigned int options)
1170 isc_region_t r;
1171 unsigned int count, rdatalen;
1172 dns_name_t *name;
1173 dns_name_t *name2;
1174 dns_offsets_t *offsets;
1175 dns_rdataset_t *rdataset = NULL;
1176 dns_rdatalist_t *rdatalist;
1177 isc_result_t result;
1178 dns_rdatatype_t rdtype, covers;
1179 dns_rdataclass_t rdclass;
1180 dns_rdata_t *rdata;
1181 dns_ttl_t ttl;
1182 dns_namelist_t *section;
1183 isc_boolean_t free_name, free_rdataset;
1184 isc_boolean_t preserve_order, best_effort, seen_problem;
1185 isc_boolean_t issigzero;
1187 preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
1188 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1189 seen_problem = ISC_FALSE;
1191 for (count = 0; count < msg->counts[sectionid]; count++) {
1192 int recstart = source->current;
1193 isc_boolean_t skip_name_search, skip_type_search;
1195 section = &msg->sections[sectionid];
1197 skip_name_search = ISC_FALSE;
1198 skip_type_search = ISC_FALSE;
1199 free_name = ISC_FALSE;
1200 free_rdataset = ISC_FALSE;
1202 name = isc_mempool_get(msg->namepool);
1203 if (name == NULL)
1204 return (ISC_R_NOMEMORY);
1205 free_name = ISC_TRUE;
1207 offsets = newoffsets(msg);
1208 if (offsets == NULL) {
1209 result = ISC_R_NOMEMORY;
1210 goto cleanup;
1212 dns_name_init(name, *offsets);
1215 * Parse the name out of this packet.
1217 isc_buffer_remainingregion(source, &r);
1218 isc_buffer_setactive(source, r.length);
1219 result = getname(name, source, msg, dctx);
1220 if (result != ISC_R_SUCCESS)
1221 goto cleanup;
1224 * Get type, class, ttl, and rdatalen. Verify that at least
1225 * rdatalen bytes remain. (Some of this is deferred to
1226 * later.)
1228 isc_buffer_remainingregion(source, &r);
1229 if (r.length < 2 + 2 + 4 + 2) {
1230 result = ISC_R_UNEXPECTEDEND;
1231 goto cleanup;
1233 rdtype = isc_buffer_getuint16(source);
1234 rdclass = isc_buffer_getuint16(source);
1237 * If there was no question section, we may not yet have
1238 * established a class. Do so now.
1240 if (msg->state == DNS_SECTION_ANY &&
1241 rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
1242 rdtype != dns_rdatatype_tsig && /* class is ANY */
1243 rdtype != dns_rdatatype_tkey) { /* class is undefined */
1244 msg->rdclass = rdclass;
1245 msg->state = DNS_SECTION_QUESTION;
1249 * If this class is different than the one in the question
1250 * section, bail.
1252 if (msg->opcode != dns_opcode_update
1253 && rdtype != dns_rdatatype_tsig
1254 && rdtype != dns_rdatatype_opt
1255 && rdtype != dns_rdatatype_dnskey /* in a TKEY query */
1256 && rdtype != dns_rdatatype_sig /* SIG(0) */
1257 && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1258 && msg->rdclass != dns_rdataclass_any
1259 && msg->rdclass != rdclass)
1260 DO_FORMERR;
1263 * Special type handling for TSIG, OPT, and TKEY.
1265 if (rdtype == dns_rdatatype_tsig) {
1267 * If it is a tsig, verify that it is in the
1268 * additional data section.
1270 if (sectionid != DNS_SECTION_ADDITIONAL ||
1271 rdclass != dns_rdataclass_any ||
1272 count != msg->counts[sectionid] - 1)
1273 DO_FORMERR;
1274 msg->sigstart = recstart;
1275 skip_name_search = ISC_TRUE;
1276 skip_type_search = ISC_TRUE;
1277 } else if (rdtype == dns_rdatatype_opt) {
1279 * The name of an OPT record must be ".", it
1280 * must be in the additional data section, and
1281 * it must be the first OPT we've seen.
1283 if (!dns_name_equal(dns_rootname, name) ||
1284 msg->opt != NULL)
1285 DO_FORMERR;
1286 skip_name_search = ISC_TRUE;
1287 skip_type_search = ISC_TRUE;
1288 } else if (rdtype == dns_rdatatype_tkey) {
1290 * A TKEY must be in the additional section if this
1291 * is a query, and the answer section if this is a
1292 * response. Unless it's a Win2000 client.
1294 * Its class is ignored.
1296 dns_section_t tkeysection;
1298 if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1299 tkeysection = DNS_SECTION_ADDITIONAL;
1300 else
1301 tkeysection = DNS_SECTION_ANSWER;
1302 if (sectionid != tkeysection &&
1303 sectionid != DNS_SECTION_ANSWER)
1304 DO_FORMERR;
1308 * ... now get ttl and rdatalen, and check buffer.
1310 ttl = isc_buffer_getuint32(source);
1311 rdatalen = isc_buffer_getuint16(source);
1312 r.length -= (2 + 2 + 4 + 2);
1313 if (r.length < rdatalen) {
1314 result = ISC_R_UNEXPECTEDEND;
1315 goto cleanup;
1319 * Read the rdata from the wire format. Interpret the
1320 * rdata according to its actual class, even if it had a
1321 * DynDNS meta-class in the packet (unless this is a TSIG).
1322 * Then put the meta-class back into the finished rdata.
1324 rdata = newrdata(msg);
1325 if (rdata == NULL) {
1326 result = ISC_R_NOMEMORY;
1327 goto cleanup;
1329 if (msg->opcode == dns_opcode_update &&
1330 update(sectionid, rdclass)) {
1331 if (rdatalen != 0) {
1332 result = DNS_R_FORMERR;
1333 goto cleanup;
1336 * When the rdata is empty, the data pointer is
1337 * never dereferenced, but it must still be non-NULL.
1338 * Casting 1 rather than "" avoids warnings about
1339 * discarding the const attribute of a string,
1340 * for compilers that would warn about such things.
1342 rdata->data = (unsigned char *)1;
1343 rdata->length = 0;
1344 rdata->rdclass = rdclass;
1345 rdata->type = rdtype;
1346 rdata->flags = DNS_RDATA_UPDATE;
1347 result = ISC_R_SUCCESS;
1348 } else if (rdclass == dns_rdataclass_none &&
1349 msg->opcode == dns_opcode_update &&
1350 sectionid == DNS_SECTION_UPDATE) {
1351 result = getrdata(source, msg, dctx, msg->rdclass,
1352 rdtype, rdatalen, rdata);
1353 } else
1354 result = getrdata(source, msg, dctx, rdclass,
1355 rdtype, rdatalen, rdata);
1356 if (result != ISC_R_SUCCESS)
1357 goto cleanup;
1358 rdata->rdclass = rdclass;
1359 issigzero = ISC_FALSE;
1360 if (rdtype == dns_rdatatype_rrsig &&
1361 rdata->flags == 0) {
1362 covers = dns_rdata_covers(rdata);
1363 if (covers == 0)
1364 DO_FORMERR;
1365 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1366 rdata->flags == 0) {
1367 covers = dns_rdata_covers(rdata);
1368 if (covers == 0) {
1369 if (sectionid != DNS_SECTION_ADDITIONAL ||
1370 count != msg->counts[sectionid] - 1)
1371 DO_FORMERR;
1372 msg->sigstart = recstart;
1373 skip_name_search = ISC_TRUE;
1374 skip_type_search = ISC_TRUE;
1375 issigzero = ISC_TRUE;
1377 } else
1378 covers = 0;
1381 * If we are doing a dynamic update or this is a meta-type,
1382 * don't bother searching for a name, just append this one
1383 * to the end of the message.
1385 if (preserve_order || msg->opcode == dns_opcode_update ||
1386 skip_name_search) {
1387 if (rdtype != dns_rdatatype_opt &&
1388 rdtype != dns_rdatatype_tsig &&
1389 !issigzero)
1391 ISC_LIST_APPEND(*section, name, link);
1392 free_name = ISC_FALSE;
1394 } else {
1396 * Run through the section, looking to see if this name
1397 * is already there. If it is found, put back the
1398 * allocated name since we no longer need it, and set
1399 * our name pointer to point to the name we found.
1401 result = findname(&name2, name, section);
1404 * If it is a new name, append to the section.
1406 if (result == ISC_R_SUCCESS) {
1407 isc_mempool_put(msg->namepool, name);
1408 name = name2;
1409 } else {
1410 ISC_LIST_APPEND(*section, name, link);
1412 free_name = ISC_FALSE;
1416 * Search name for the particular type and class.
1417 * Skip this stage if in update mode or this is a meta-type.
1419 if (preserve_order || msg->opcode == dns_opcode_update ||
1420 skip_type_search)
1421 result = ISC_R_NOTFOUND;
1422 else {
1424 * If this is a type that can only occur in
1425 * the question section, fail.
1427 if (dns_rdatatype_questiononly(rdtype))
1428 DO_FORMERR;
1430 rdataset = NULL;
1431 result = dns_message_find(name, rdclass, rdtype,
1432 covers, &rdataset);
1436 * If we found an rdataset that matches, we need to
1437 * append this rdata to that set. If we did not, we need
1438 * to create a new rdatalist, store the important bits there,
1439 * convert it to an rdataset, and link the latter to the name.
1440 * Yuck. When appending, make certain that the type isn't
1441 * a singleton type, such as SOA or CNAME.
1443 * Note that this check will be bypassed when preserving order,
1444 * the opcode is an update, or the type search is skipped.
1446 if (result == ISC_R_SUCCESS) {
1447 if (dns_rdatatype_issingleton(rdtype))
1448 DO_FORMERR;
1451 if (result == ISC_R_NOTFOUND) {
1452 rdataset = isc_mempool_get(msg->rdspool);
1453 if (rdataset == NULL) {
1454 result = ISC_R_NOMEMORY;
1455 goto cleanup;
1457 free_rdataset = ISC_TRUE;
1459 rdatalist = newrdatalist(msg);
1460 if (rdatalist == NULL) {
1461 result = ISC_R_NOMEMORY;
1462 goto cleanup;
1465 rdatalist->type = rdtype;
1466 rdatalist->covers = covers;
1467 rdatalist->rdclass = rdclass;
1468 rdatalist->ttl = ttl;
1469 ISC_LIST_INIT(rdatalist->rdata);
1471 dns_rdataset_init(rdataset);
1472 RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1473 rdataset)
1474 == ISC_R_SUCCESS);
1476 if (rdtype != dns_rdatatype_opt &&
1477 rdtype != dns_rdatatype_tsig &&
1478 !issigzero)
1480 ISC_LIST_APPEND(name->list, rdataset, link);
1481 free_rdataset = ISC_FALSE;
1486 * Minimize TTLs.
1488 * Section 5.2 of RFC2181 says we should drop
1489 * nonauthoritative rrsets where the TTLs differ, but we
1490 * currently treat them the as if they were authoritative and
1491 * minimize them.
1493 if (ttl != rdataset->ttl) {
1494 rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1495 if (ttl < rdataset->ttl)
1496 rdataset->ttl = ttl;
1499 /* Append this rdata to the rdataset. */
1500 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1501 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1504 * If this is an OPT record, remember it. Also, set
1505 * the extended rcode. Note that msg->opt will only be set
1506 * if best-effort parsing is enabled.
1508 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1509 dns_rcode_t ercode;
1511 msg->opt = rdataset;
1512 rdataset = NULL;
1513 free_rdataset = ISC_FALSE;
1514 ercode = (dns_rcode_t)
1515 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1516 >> 20);
1517 msg->rcode |= ercode;
1518 isc_mempool_put(msg->namepool, name);
1519 free_name = ISC_FALSE;
1523 * If this is an SIG(0) or TSIG record, remember it. Note
1524 * that msg->sig0 or msg->tsig will only be set if best-effort
1525 * parsing is enabled.
1527 if (issigzero && msg->sig0 == NULL) {
1528 msg->sig0 = rdataset;
1529 msg->sig0name = name;
1530 rdataset = NULL;
1531 free_rdataset = ISC_FALSE;
1532 free_name = ISC_FALSE;
1533 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1534 msg->tsig = rdataset;
1535 msg->tsigname = name;
1536 rdataset = NULL;
1537 free_rdataset = ISC_FALSE;
1538 free_name = ISC_FALSE;
1541 if (seen_problem) {
1542 if (free_name)
1543 isc_mempool_put(msg->namepool, name);
1544 if (free_rdataset)
1545 isc_mempool_put(msg->rdspool, rdataset);
1546 free_name = free_rdataset = ISC_FALSE;
1548 INSIST(free_name == ISC_FALSE);
1549 INSIST(free_rdataset == ISC_FALSE);
1552 if (seen_problem)
1553 return (DNS_R_RECOVERABLE);
1554 return (ISC_R_SUCCESS);
1556 cleanup:
1557 if (free_name)
1558 isc_mempool_put(msg->namepool, name);
1559 if (free_rdataset)
1560 isc_mempool_put(msg->rdspool, rdataset);
1562 return (result);
1565 isc_result_t
1566 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1567 unsigned int options)
1569 isc_region_t r;
1570 dns_decompress_t dctx;
1571 isc_result_t ret;
1572 isc_uint16_t tmpflags;
1573 isc_buffer_t origsource;
1574 isc_boolean_t seen_problem;
1575 isc_boolean_t ignore_tc;
1577 REQUIRE(DNS_MESSAGE_VALID(msg));
1578 REQUIRE(source != NULL);
1579 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1581 seen_problem = ISC_FALSE;
1582 ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1584 origsource = *source;
1586 msg->header_ok = 0;
1587 msg->question_ok = 0;
1589 isc_buffer_remainingregion(source, &r);
1590 if (r.length < DNS_MESSAGE_HEADERLEN)
1591 return (ISC_R_UNEXPECTEDEND);
1593 msg->id = isc_buffer_getuint16(source);
1594 tmpflags = isc_buffer_getuint16(source);
1595 msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1596 >> DNS_MESSAGE_OPCODE_SHIFT);
1597 msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1598 msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1599 msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1600 msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1601 msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1602 msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1604 msg->header_ok = 1;
1607 * -1 means no EDNS.
1609 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1611 dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1613 ret = getquestions(source, msg, &dctx, options);
1614 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1615 goto truncated;
1616 if (ret == DNS_R_RECOVERABLE) {
1617 seen_problem = ISC_TRUE;
1618 ret = ISC_R_SUCCESS;
1620 if (ret != ISC_R_SUCCESS)
1621 return (ret);
1622 msg->question_ok = 1;
1624 ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1625 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1626 goto truncated;
1627 if (ret == DNS_R_RECOVERABLE) {
1628 seen_problem = ISC_TRUE;
1629 ret = ISC_R_SUCCESS;
1631 if (ret != ISC_R_SUCCESS)
1632 return (ret);
1634 ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1635 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1636 goto truncated;
1637 if (ret == DNS_R_RECOVERABLE) {
1638 seen_problem = ISC_TRUE;
1639 ret = ISC_R_SUCCESS;
1641 if (ret != ISC_R_SUCCESS)
1642 return (ret);
1644 ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1645 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1646 goto truncated;
1647 if (ret == DNS_R_RECOVERABLE) {
1648 seen_problem = ISC_TRUE;
1649 ret = ISC_R_SUCCESS;
1651 if (ret != ISC_R_SUCCESS)
1652 return (ret);
1654 isc_buffer_remainingregion(source, &r);
1655 if (r.length != 0) {
1656 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1657 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1658 "message has %u byte(s) of trailing garbage",
1659 r.length);
1662 truncated:
1663 if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1664 isc_buffer_usedregion(&origsource, &msg->saved);
1665 else {
1666 msg->saved.length = isc_buffer_usedlength(&origsource);
1667 msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1668 if (msg->saved.base == NULL)
1669 return (ISC_R_NOMEMORY);
1670 memcpy(msg->saved.base, isc_buffer_base(&origsource),
1671 msg->saved.length);
1672 msg->free_saved = 1;
1675 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1676 return (DNS_R_RECOVERABLE);
1677 if (seen_problem == ISC_TRUE)
1678 return (DNS_R_RECOVERABLE);
1679 return (ISC_R_SUCCESS);
1682 isc_result_t
1683 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1684 isc_buffer_t *buffer)
1686 isc_region_t r;
1688 REQUIRE(DNS_MESSAGE_VALID(msg));
1689 REQUIRE(buffer != NULL);
1690 REQUIRE(msg->buffer == NULL);
1691 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1693 msg->cctx = cctx;
1696 * Erase the contents of this buffer.
1698 isc_buffer_clear(buffer);
1701 * Make certain there is enough for at least the header in this
1702 * buffer.
1704 isc_buffer_availableregion(buffer, &r);
1705 if (r.length < DNS_MESSAGE_HEADERLEN)
1706 return (ISC_R_NOSPACE);
1708 if (r.length < msg->reserved)
1709 return (ISC_R_NOSPACE);
1712 * Reserve enough space for the header in this buffer.
1714 isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1716 msg->buffer = buffer;
1718 return (ISC_R_SUCCESS);
1721 isc_result_t
1722 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1723 isc_region_t r, rn;
1725 REQUIRE(DNS_MESSAGE_VALID(msg));
1726 REQUIRE(buffer != NULL);
1727 REQUIRE(msg->buffer != NULL);
1730 * Ensure that the new buffer is empty, and has enough space to
1731 * hold the current contents.
1733 isc_buffer_clear(buffer);
1735 isc_buffer_availableregion(buffer, &rn);
1736 isc_buffer_usedregion(msg->buffer, &r);
1737 REQUIRE(rn.length > r.length);
1740 * Copy the contents from the old to the new buffer.
1742 isc_buffer_add(buffer, r.length);
1743 memcpy(rn.base, r.base, r.length);
1745 msg->buffer = buffer;
1747 return (ISC_R_SUCCESS);
1750 void
1751 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1752 REQUIRE(DNS_MESSAGE_VALID(msg));
1753 REQUIRE(space <= msg->reserved);
1755 msg->reserved -= space;
1758 isc_result_t
1759 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1760 isc_region_t r;
1762 REQUIRE(DNS_MESSAGE_VALID(msg));
1764 if (msg->buffer != NULL) {
1765 isc_buffer_availableregion(msg->buffer, &r);
1766 if (r.length < (space + msg->reserved))
1767 return (ISC_R_NOSPACE);
1770 msg->reserved += space;
1772 return (ISC_R_SUCCESS);
1775 static inline isc_boolean_t
1776 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1777 int pass_needed;
1780 * If we are not rendering class IN, this ordering is bogus.
1782 if (rds->rdclass != dns_rdataclass_in)
1783 return (ISC_FALSE);
1785 switch (rds->type) {
1786 case dns_rdatatype_a:
1787 case dns_rdatatype_aaaa:
1788 if (preferred_glue == rds->type)
1789 pass_needed = 4;
1790 else
1791 pass_needed = 3;
1792 break;
1793 case dns_rdatatype_rrsig:
1794 case dns_rdatatype_dnskey:
1795 pass_needed = 2;
1796 break;
1797 default:
1798 pass_needed = 1;
1801 if (pass_needed >= pass)
1802 return (ISC_FALSE);
1804 return (ISC_TRUE);
1807 #ifdef ALLOW_FILTER_AAAA_ON_V4
1809 * Decide whether to not answer with an AAAA record and its RRSIG
1811 static inline isc_boolean_t
1812 norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options)
1814 switch (rdataset->type) {
1815 case dns_rdatatype_aaaa:
1816 if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
1817 return (ISC_FALSE);
1818 break;
1820 case dns_rdatatype_rrsig:
1821 if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
1822 rdataset->covers != dns_rdatatype_aaaa)
1823 return (ISC_FALSE);
1824 break;
1826 default:
1827 return (ISC_FALSE);
1830 if (rdataset->rdclass != dns_rdataclass_in)
1831 return (ISC_FALSE);
1833 return (ISC_TRUE);
1836 #endif
1837 isc_result_t
1838 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1839 unsigned int options)
1841 dns_namelist_t *section;
1842 dns_name_t *name, *next_name;
1843 dns_rdataset_t *rdataset, *next_rdataset;
1844 unsigned int count, total;
1845 isc_result_t result;
1846 isc_buffer_t st; /* for rollbacks */
1847 int pass;
1848 isc_boolean_t partial = ISC_FALSE;
1849 unsigned int rd_options;
1850 dns_rdatatype_t preferred_glue = 0;
1852 REQUIRE(DNS_MESSAGE_VALID(msg));
1853 REQUIRE(msg->buffer != NULL);
1854 REQUIRE(VALID_NAMED_SECTION(sectionid));
1856 section = &msg->sections[sectionid];
1858 if ((sectionid == DNS_SECTION_ADDITIONAL)
1859 && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1860 if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1861 preferred_glue = dns_rdatatype_a;
1862 pass = 4;
1863 } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1864 preferred_glue = dns_rdatatype_aaaa;
1865 pass = 4;
1866 } else
1867 pass = 3;
1868 } else
1869 pass = 1;
1871 if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1872 rd_options = 0;
1873 else
1874 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1877 * Shrink the space in the buffer by the reserved amount.
1879 msg->buffer->length -= msg->reserved;
1881 total = 0;
1882 if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1883 partial = ISC_TRUE;
1886 * Render required glue first. Set TC if it won't fit.
1888 name = ISC_LIST_HEAD(*section);
1889 if (name != NULL) {
1890 rdataset = ISC_LIST_HEAD(name->list);
1891 if (rdataset != NULL &&
1892 (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
1893 (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
1894 const void *order_arg = msg->order_arg;
1895 st = *(msg->buffer);
1896 count = 0;
1897 if (partial)
1898 result = dns_rdataset_towirepartial(rdataset,
1899 name,
1900 msg->cctx,
1901 msg->buffer,
1902 msg->order,
1903 order_arg,
1904 rd_options,
1905 &count,
1906 NULL);
1907 else
1908 result = dns_rdataset_towiresorted(rdataset,
1909 name,
1910 msg->cctx,
1911 msg->buffer,
1912 msg->order,
1913 order_arg,
1914 rd_options,
1915 &count);
1916 total += count;
1917 if (partial && result == ISC_R_NOSPACE) {
1918 msg->flags |= DNS_MESSAGEFLAG_TC;
1919 msg->buffer->length += msg->reserved;
1920 msg->counts[sectionid] += total;
1921 return (result);
1923 if (result == ISC_R_NOSPACE)
1924 msg->flags |= DNS_MESSAGEFLAG_TC;
1925 if (result != ISC_R_SUCCESS) {
1926 INSIST(st.used < 65536);
1927 dns_compress_rollback(msg->cctx,
1928 (isc_uint16_t)st.used);
1929 *(msg->buffer) = st; /* rollback */
1930 msg->buffer->length += msg->reserved;
1931 msg->counts[sectionid] += total;
1932 return (result);
1934 rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
1938 do {
1939 name = ISC_LIST_HEAD(*section);
1940 if (name == NULL) {
1941 msg->buffer->length += msg->reserved;
1942 msg->counts[sectionid] += total;
1943 return (ISC_R_SUCCESS);
1946 while (name != NULL) {
1947 next_name = ISC_LIST_NEXT(name, link);
1949 rdataset = ISC_LIST_HEAD(name->list);
1950 while (rdataset != NULL) {
1951 next_rdataset = ISC_LIST_NEXT(rdataset, link);
1953 if ((rdataset->attributes &
1954 DNS_RDATASETATTR_RENDERED) != 0)
1955 goto next;
1957 if (((options & DNS_MESSAGERENDER_ORDERED)
1958 == 0)
1959 && (sectionid == DNS_SECTION_ADDITIONAL)
1960 && wrong_priority(rdataset, pass,
1961 preferred_glue))
1962 goto next;
1964 #ifdef ALLOW_FILTER_AAAA_ON_V4
1966 * Suppress AAAAs if asked and we are
1967 * not doing DNSSEC or are breaking DNSSEC.
1968 * Say so in the AD bit if we break DNSSEC.
1970 if (norender_rdataset(rdataset, options) &&
1971 sectionid != DNS_SECTION_QUESTION) {
1972 if (sectionid == DNS_SECTION_ANSWER ||
1973 sectionid == DNS_SECTION_AUTHORITY)
1974 msg->flags &= ~DNS_MESSAGEFLAG_AD;
1975 if (OPTOUT(rdataset))
1976 msg->flags &= ~DNS_MESSAGEFLAG_AD;
1977 goto next;
1980 #endif
1981 st = *(msg->buffer);
1983 count = 0;
1984 if (partial)
1985 result = dns_rdataset_towirepartial(
1986 rdataset,
1987 name,
1988 msg->cctx,
1989 msg->buffer,
1990 msg->order,
1991 msg->order_arg,
1992 rd_options,
1993 &count,
1994 NULL);
1995 else
1996 result = dns_rdataset_towiresorted(
1997 rdataset,
1998 name,
1999 msg->cctx,
2000 msg->buffer,
2001 msg->order,
2002 msg->order_arg,
2003 rd_options,
2004 &count);
2006 total += count;
2009 * If out of space, record stats on what we
2010 * rendered so far, and return that status.
2012 * XXXMLG Need to change this when
2013 * dns_rdataset_towire() can render partial
2014 * sets starting at some arbitrary point in the
2015 * set. This will include setting a bit in the
2016 * rdataset to indicate that a partial
2017 * rendering was done, and some state saved
2018 * somewhere (probably in the message struct)
2019 * to indicate where to continue from.
2021 if (partial && result == ISC_R_NOSPACE) {
2022 msg->buffer->length += msg->reserved;
2023 msg->counts[sectionid] += total;
2024 return (result);
2026 if (result != ISC_R_SUCCESS) {
2027 INSIST(st.used < 65536);
2028 dns_compress_rollback(msg->cctx,
2029 (isc_uint16_t)st.used);
2030 *(msg->buffer) = st; /* rollback */
2031 msg->buffer->length += msg->reserved;
2032 msg->counts[sectionid] += total;
2033 return (result);
2037 * If we have rendered non-validated data,
2038 * ensure that the AD bit is not set.
2040 if (rdataset->trust != dns_trust_secure &&
2041 (sectionid == DNS_SECTION_ANSWER ||
2042 sectionid == DNS_SECTION_AUTHORITY))
2043 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2044 if (OPTOUT(rdataset))
2045 msg->flags &= ~DNS_MESSAGEFLAG_AD;
2047 rdataset->attributes |=
2048 DNS_RDATASETATTR_RENDERED;
2050 next:
2051 rdataset = next_rdataset;
2054 name = next_name;
2056 } while (--pass != 0);
2058 msg->buffer->length += msg->reserved;
2059 msg->counts[sectionid] += total;
2061 return (ISC_R_SUCCESS);
2064 void
2065 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2066 isc_uint16_t tmp;
2067 isc_region_t r;
2069 REQUIRE(DNS_MESSAGE_VALID(msg));
2070 REQUIRE(target != NULL);
2072 isc_buffer_availableregion(target, &r);
2073 REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2075 isc_buffer_putuint16(target, msg->id);
2077 tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
2078 & DNS_MESSAGE_OPCODE_MASK);
2079 tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2080 tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2082 INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
2083 msg->counts[DNS_SECTION_ANSWER] < 65536 &&
2084 msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2085 msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2087 isc_buffer_putuint16(target, tmp);
2088 isc_buffer_putuint16(target,
2089 (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2090 isc_buffer_putuint16(target,
2091 (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2092 isc_buffer_putuint16(target,
2093 (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2094 isc_buffer_putuint16(target,
2095 (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2098 isc_result_t
2099 dns_message_renderend(dns_message_t *msg) {
2100 isc_buffer_t tmpbuf;
2101 isc_region_t r;
2102 int result;
2103 unsigned int count;
2105 REQUIRE(DNS_MESSAGE_VALID(msg));
2106 REQUIRE(msg->buffer != NULL);
2108 if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2110 * We have an extended rcode but are not using EDNS.
2112 return (DNS_R_FORMERR);
2116 * If we've got an OPT record, render it.
2118 if (msg->opt != NULL) {
2119 dns_message_renderrelease(msg, msg->opt_reserved);
2120 msg->opt_reserved = 0;
2122 * Set the extended rcode.
2124 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2125 msg->opt->ttl |= ((msg->rcode << 20) &
2126 DNS_MESSAGE_EDNSRCODE_MASK);
2128 * Render.
2130 count = 0;
2131 result = dns_rdataset_towire(msg->opt, dns_rootname,
2132 msg->cctx, msg->buffer, 0,
2133 &count);
2134 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2135 if (result != ISC_R_SUCCESS)
2136 return (result);
2140 * If we're adding a TSIG or SIG(0) to a truncated message,
2141 * clear all rdatasets from the message except for the question
2142 * before adding the TSIG or SIG(0). If the question doesn't fit,
2143 * don't include it.
2145 if ((msg->tsigkey != NULL || msg->sig0key != NULL) &&
2146 (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2148 isc_buffer_t *buf;
2150 msgresetnames(msg, DNS_SECTION_ANSWER);
2151 buf = msg->buffer;
2152 dns_message_renderreset(msg);
2153 msg->buffer = buf;
2154 isc_buffer_clear(msg->buffer);
2155 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2156 dns_compress_rollback(msg->cctx, 0);
2157 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2159 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2160 return (result);
2164 * If we're adding a TSIG record, generate and render it.
2166 if (msg->tsigkey != NULL) {
2167 dns_message_renderrelease(msg, msg->sig_reserved);
2168 msg->sig_reserved = 0;
2169 result = dns_tsig_sign(msg);
2170 if (result != ISC_R_SUCCESS)
2171 return (result);
2172 count = 0;
2173 result = dns_rdataset_towire(msg->tsig, msg->tsigname,
2174 msg->cctx, msg->buffer, 0,
2175 &count);
2176 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2177 if (result != ISC_R_SUCCESS)
2178 return (result);
2182 * If we're adding a SIG(0) record, generate and render it.
2184 if (msg->sig0key != NULL) {
2185 dns_message_renderrelease(msg, msg->sig_reserved);
2186 msg->sig_reserved = 0;
2187 result = dns_dnssec_signmessage(msg, msg->sig0key);
2188 if (result != ISC_R_SUCCESS)
2189 return (result);
2190 count = 0;
2192 * Note: dns_rootname is used here, not msg->sig0name, since
2193 * the owner name of a SIG(0) is irrelevant, and will not
2194 * be set in a message being rendered.
2196 result = dns_rdataset_towire(msg->sig0, dns_rootname,
2197 msg->cctx, msg->buffer, 0,
2198 &count);
2199 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2200 if (result != ISC_R_SUCCESS)
2201 return (result);
2204 isc_buffer_usedregion(msg->buffer, &r);
2205 isc_buffer_init(&tmpbuf, r.base, r.length);
2207 dns_message_renderheader(msg, &tmpbuf);
2209 msg->buffer = NULL; /* forget about this buffer only on success XXX */
2211 return (ISC_R_SUCCESS);
2214 void
2215 dns_message_renderreset(dns_message_t *msg) {
2216 unsigned int i;
2217 dns_name_t *name;
2218 dns_rdataset_t *rds;
2221 * Reset the message so that it may be rendered again.
2224 REQUIRE(DNS_MESSAGE_VALID(msg));
2225 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2227 msg->buffer = NULL;
2229 for (i = 0; i < DNS_SECTION_MAX; i++) {
2230 msg->cursors[i] = NULL;
2231 msg->counts[i] = 0;
2232 for (name = ISC_LIST_HEAD(msg->sections[i]);
2233 name != NULL;
2234 name = ISC_LIST_NEXT(name, link)) {
2235 for (rds = ISC_LIST_HEAD(name->list);
2236 rds != NULL;
2237 rds = ISC_LIST_NEXT(rds, link)) {
2238 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2242 if (msg->tsigname != NULL)
2243 dns_message_puttempname(msg, &msg->tsigname);
2244 if (msg->tsig != NULL) {
2245 dns_rdataset_disassociate(msg->tsig);
2246 dns_message_puttemprdataset(msg, &msg->tsig);
2248 if (msg->sig0 != NULL) {
2249 dns_rdataset_disassociate(msg->sig0);
2250 dns_message_puttemprdataset(msg, &msg->sig0);
2254 isc_result_t
2255 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2256 REQUIRE(DNS_MESSAGE_VALID(msg));
2257 REQUIRE(VALID_NAMED_SECTION(section));
2259 msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2261 if (msg->cursors[section] == NULL)
2262 return (ISC_R_NOMORE);
2264 return (ISC_R_SUCCESS);
2267 isc_result_t
2268 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2269 REQUIRE(DNS_MESSAGE_VALID(msg));
2270 REQUIRE(VALID_NAMED_SECTION(section));
2271 REQUIRE(msg->cursors[section] != NULL);
2273 msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2275 if (msg->cursors[section] == NULL)
2276 return (ISC_R_NOMORE);
2278 return (ISC_R_SUCCESS);
2281 void
2282 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2283 dns_name_t **name)
2285 REQUIRE(DNS_MESSAGE_VALID(msg));
2286 REQUIRE(VALID_NAMED_SECTION(section));
2287 REQUIRE(name != NULL && *name == NULL);
2288 REQUIRE(msg->cursors[section] != NULL);
2290 *name = msg->cursors[section];
2293 isc_result_t
2294 dns_message_findname(dns_message_t *msg, dns_section_t section,
2295 dns_name_t *target, dns_rdatatype_t type,
2296 dns_rdatatype_t covers, dns_name_t **name,
2297 dns_rdataset_t **rdataset)
2299 dns_name_t *foundname;
2300 isc_result_t result;
2303 * XXX These requirements are probably too intensive, especially
2304 * where things can be NULL, but as they are they ensure that if
2305 * something is NON-NULL, indicating that the caller expects it
2306 * to be filled in, that we can in fact fill it in.
2308 REQUIRE(msg != NULL);
2309 REQUIRE(VALID_SECTION(section));
2310 REQUIRE(target != NULL);
2311 if (name != NULL)
2312 REQUIRE(*name == NULL);
2313 if (type == dns_rdatatype_any) {
2314 REQUIRE(rdataset == NULL);
2315 } else {
2316 if (rdataset != NULL)
2317 REQUIRE(*rdataset == NULL);
2320 result = findname(&foundname, target,
2321 &msg->sections[section]);
2323 if (result == ISC_R_NOTFOUND)
2324 return (DNS_R_NXDOMAIN);
2325 else if (result != ISC_R_SUCCESS)
2326 return (result);
2328 if (name != NULL)
2329 *name = foundname;
2332 * And now look for the type.
2334 if (type == dns_rdatatype_any)
2335 return (ISC_R_SUCCESS);
2337 result = dns_message_findtype(foundname, type, covers, rdataset);
2338 if (result == ISC_R_NOTFOUND)
2339 return (DNS_R_NXRRSET);
2341 return (result);
2344 void
2345 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2346 dns_section_t fromsection,
2347 dns_section_t tosection)
2349 REQUIRE(msg != NULL);
2350 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2351 REQUIRE(name != NULL);
2352 REQUIRE(VALID_NAMED_SECTION(fromsection));
2353 REQUIRE(VALID_NAMED_SECTION(tosection));
2356 * Unlink the name from the old section
2358 ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2359 ISC_LIST_APPEND(msg->sections[tosection], name, link);
2362 void
2363 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2364 dns_section_t section)
2366 REQUIRE(msg != NULL);
2367 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2368 REQUIRE(name != NULL);
2369 REQUIRE(VALID_NAMED_SECTION(section));
2371 ISC_LIST_APPEND(msg->sections[section], name, link);
2374 void
2375 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2376 dns_section_t section)
2378 REQUIRE(msg != NULL);
2379 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2380 REQUIRE(name != NULL);
2381 REQUIRE(VALID_NAMED_SECTION(section));
2383 ISC_LIST_UNLINK(msg->sections[section], name, link);
2386 isc_result_t
2387 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2388 REQUIRE(DNS_MESSAGE_VALID(msg));
2389 REQUIRE(item != NULL && *item == NULL);
2391 *item = isc_mempool_get(msg->namepool);
2392 if (*item == NULL)
2393 return (ISC_R_NOMEMORY);
2394 dns_name_init(*item, NULL);
2396 return (ISC_R_SUCCESS);
2399 isc_result_t
2400 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2401 REQUIRE(DNS_MESSAGE_VALID(msg));
2402 REQUIRE(item != NULL && *item == NULL);
2404 *item = newoffsets(msg);
2405 if (*item == NULL)
2406 return (ISC_R_NOMEMORY);
2408 return (ISC_R_SUCCESS);
2411 isc_result_t
2412 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2413 REQUIRE(DNS_MESSAGE_VALID(msg));
2414 REQUIRE(item != NULL && *item == NULL);
2416 *item = newrdata(msg);
2417 if (*item == NULL)
2418 return (ISC_R_NOMEMORY);
2420 return (ISC_R_SUCCESS);
2423 isc_result_t
2424 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2425 REQUIRE(DNS_MESSAGE_VALID(msg));
2426 REQUIRE(item != NULL && *item == NULL);
2428 *item = isc_mempool_get(msg->rdspool);
2429 if (*item == NULL)
2430 return (ISC_R_NOMEMORY);
2432 dns_rdataset_init(*item);
2434 return (ISC_R_SUCCESS);
2437 isc_result_t
2438 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2439 REQUIRE(DNS_MESSAGE_VALID(msg));
2440 REQUIRE(item != NULL && *item == NULL);
2442 *item = newrdatalist(msg);
2443 if (*item == NULL)
2444 return (ISC_R_NOMEMORY);
2446 return (ISC_R_SUCCESS);
2449 void
2450 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2451 REQUIRE(DNS_MESSAGE_VALID(msg));
2452 REQUIRE(item != NULL && *item != NULL);
2454 if (dns_name_dynamic(*item))
2455 dns_name_free(*item, msg->mctx);
2456 isc_mempool_put(msg->namepool, *item);
2457 *item = NULL;
2460 void
2461 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2462 REQUIRE(DNS_MESSAGE_VALID(msg));
2463 REQUIRE(item != NULL && *item != NULL);
2465 releaserdata(msg, *item);
2466 *item = NULL;
2469 void
2470 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2471 REQUIRE(DNS_MESSAGE_VALID(msg));
2472 REQUIRE(item != NULL && *item != NULL);
2474 REQUIRE(!dns_rdataset_isassociated(*item));
2475 isc_mempool_put(msg->rdspool, *item);
2476 *item = NULL;
2479 void
2480 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2481 REQUIRE(DNS_MESSAGE_VALID(msg));
2482 REQUIRE(item != NULL && *item != NULL);
2484 releaserdatalist(msg, *item);
2485 *item = NULL;
2488 isc_result_t
2489 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2490 unsigned int *flagsp)
2492 isc_region_t r;
2493 isc_buffer_t buffer;
2494 dns_messageid_t id;
2495 unsigned int flags;
2497 REQUIRE(source != NULL);
2499 buffer = *source;
2501 isc_buffer_remainingregion(&buffer, &r);
2502 if (r.length < DNS_MESSAGE_HEADERLEN)
2503 return (ISC_R_UNEXPECTEDEND);
2505 id = isc_buffer_getuint16(&buffer);
2506 flags = isc_buffer_getuint16(&buffer);
2507 flags &= DNS_MESSAGE_FLAG_MASK;
2509 if (flagsp != NULL)
2510 *flagsp = flags;
2511 if (idp != NULL)
2512 *idp = id;
2514 return (ISC_R_SUCCESS);
2517 isc_result_t
2518 dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
2519 unsigned int first_section;
2520 isc_result_t result;
2522 REQUIRE(DNS_MESSAGE_VALID(msg));
2523 REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2525 if (!msg->header_ok)
2526 return (DNS_R_FORMERR);
2527 if (msg->opcode != dns_opcode_query &&
2528 msg->opcode != dns_opcode_notify)
2529 want_question_section = ISC_FALSE;
2530 if (want_question_section) {
2531 if (!msg->question_ok)
2532 return (DNS_R_FORMERR);
2533 first_section = DNS_SECTION_ANSWER;
2534 } else
2535 first_section = DNS_SECTION_QUESTION;
2536 msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2537 msgresetnames(msg, first_section);
2538 msgresetopt(msg);
2539 msgresetsigs(msg, ISC_TRUE);
2540 msginitprivate(msg);
2542 * We now clear most flags and then set QR, ensuring that the
2543 * reply's flags will be in a reasonable state.
2545 msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2546 msg->flags |= DNS_MESSAGEFLAG_QR;
2549 * This saves the query TSIG status, if the query was signed, and
2550 * reserves space in the reply for the TSIG.
2552 if (msg->tsigkey != NULL) {
2553 unsigned int otherlen = 0;
2554 msg->querytsigstatus = msg->tsigstatus;
2555 msg->tsigstatus = dns_rcode_noerror;
2556 if (msg->querytsigstatus == dns_tsigerror_badtime)
2557 otherlen = 6;
2558 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2559 result = dns_message_renderreserve(msg, msg->sig_reserved);
2560 if (result != ISC_R_SUCCESS) {
2561 msg->sig_reserved = 0;
2562 return (result);
2565 if (msg->saved.base != NULL) {
2566 msg->query.base = msg->saved.base;
2567 msg->query.length = msg->saved.length;
2568 msg->free_query = msg->free_saved;
2569 msg->saved.base = NULL;
2570 msg->saved.length = 0;
2571 msg->free_saved = 0;
2574 return (ISC_R_SUCCESS);
2577 dns_rdataset_t *
2578 dns_message_getopt(dns_message_t *msg) {
2581 * Get the OPT record for 'msg'.
2584 REQUIRE(DNS_MESSAGE_VALID(msg));
2586 return (msg->opt);
2589 isc_result_t
2590 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2591 isc_result_t result;
2592 dns_rdata_t rdata = DNS_RDATA_INIT;
2595 * Set the OPT record for 'msg'.
2599 * The space required for an OPT record is:
2601 * 1 byte for the name
2602 * 2 bytes for the type
2603 * 2 bytes for the class
2604 * 4 bytes for the ttl
2605 * 2 bytes for the rdata length
2606 * ---------------------------------
2607 * 11 bytes
2609 * plus the length of the rdata.
2612 REQUIRE(DNS_MESSAGE_VALID(msg));
2613 REQUIRE(opt->type == dns_rdatatype_opt);
2614 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2615 REQUIRE(msg->state == DNS_SECTION_ANY);
2617 msgresetopt(msg);
2619 result = dns_rdataset_first(opt);
2620 if (result != ISC_R_SUCCESS)
2621 goto cleanup;
2622 dns_rdataset_current(opt, &rdata);
2623 msg->opt_reserved = 11 + rdata.length;
2624 result = dns_message_renderreserve(msg, msg->opt_reserved);
2625 if (result != ISC_R_SUCCESS) {
2626 msg->opt_reserved = 0;
2627 goto cleanup;
2630 msg->opt = opt;
2632 return (ISC_R_SUCCESS);
2634 cleanup:
2635 dns_message_puttemprdataset(msg, &opt);
2636 return (result);
2640 dns_rdataset_t *
2641 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2644 * Get the TSIG record and owner for 'msg'.
2647 REQUIRE(DNS_MESSAGE_VALID(msg));
2648 REQUIRE(owner == NULL || *owner == NULL);
2650 if (owner != NULL)
2651 *owner = msg->tsigname;
2652 return (msg->tsig);
2655 isc_result_t
2656 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2657 isc_result_t result;
2660 * Set the TSIG key for 'msg'
2663 REQUIRE(DNS_MESSAGE_VALID(msg));
2664 REQUIRE(msg->state == DNS_SECTION_ANY);
2666 if (key == NULL && msg->tsigkey != NULL) {
2667 if (msg->sig_reserved != 0) {
2668 dns_message_renderrelease(msg, msg->sig_reserved);
2669 msg->sig_reserved = 0;
2671 dns_tsigkey_detach(&msg->tsigkey);
2673 if (key != NULL) {
2674 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2675 dns_tsigkey_attach(key, &msg->tsigkey);
2676 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2677 msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2678 result = dns_message_renderreserve(msg,
2679 msg->sig_reserved);
2680 if (result != ISC_R_SUCCESS) {
2681 dns_tsigkey_detach(&msg->tsigkey);
2682 msg->sig_reserved = 0;
2683 return (result);
2687 return (ISC_R_SUCCESS);
2690 dns_tsigkey_t *
2691 dns_message_gettsigkey(dns_message_t *msg) {
2694 * Get the TSIG key for 'msg'
2697 REQUIRE(DNS_MESSAGE_VALID(msg));
2699 return (msg->tsigkey);
2702 isc_result_t
2703 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2704 dns_rdata_t *rdata = NULL;
2705 dns_rdatalist_t *list = NULL;
2706 dns_rdataset_t *set = NULL;
2707 isc_buffer_t *buf = NULL;
2708 isc_region_t r;
2709 isc_result_t result;
2711 REQUIRE(DNS_MESSAGE_VALID(msg));
2712 REQUIRE(msg->querytsig == NULL);
2714 if (querytsig == NULL)
2715 return (ISC_R_SUCCESS);
2717 result = dns_message_gettemprdata(msg, &rdata);
2718 if (result != ISC_R_SUCCESS)
2719 goto cleanup;
2721 result = dns_message_gettemprdatalist(msg, &list);
2722 if (result != ISC_R_SUCCESS)
2723 goto cleanup;
2724 result = dns_message_gettemprdataset(msg, &set);
2725 if (result != ISC_R_SUCCESS)
2726 goto cleanup;
2728 isc_buffer_usedregion(querytsig, &r);
2729 result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2730 if (result != ISC_R_SUCCESS)
2731 goto cleanup;
2732 isc_buffer_putmem(buf, r.base, r.length);
2733 isc_buffer_usedregion(buf, &r);
2734 dns_rdata_init(rdata);
2735 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2736 dns_message_takebuffer(msg, &buf);
2737 ISC_LIST_INIT(list->rdata);
2738 ISC_LIST_APPEND(list->rdata, rdata, link);
2739 result = dns_rdatalist_tordataset(list, set);
2740 if (result != ISC_R_SUCCESS)
2741 goto cleanup;
2743 msg->querytsig = set;
2745 return (result);
2747 cleanup:
2748 if (rdata != NULL)
2749 dns_message_puttemprdata(msg, &rdata);
2750 if (list != NULL)
2751 dns_message_puttemprdatalist(msg, &list);
2752 if (set != NULL)
2753 dns_message_puttemprdataset(msg, &set);
2754 return (ISC_R_NOMEMORY);
2757 isc_result_t
2758 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2759 isc_buffer_t **querytsig) {
2760 isc_result_t result;
2761 dns_rdata_t rdata = DNS_RDATA_INIT;
2762 isc_region_t r;
2764 REQUIRE(DNS_MESSAGE_VALID(msg));
2765 REQUIRE(mctx != NULL);
2766 REQUIRE(querytsig != NULL && *querytsig == NULL);
2768 if (msg->tsig == NULL)
2769 return (ISC_R_SUCCESS);
2771 result = dns_rdataset_first(msg->tsig);
2772 if (result != ISC_R_SUCCESS)
2773 return (result);
2774 dns_rdataset_current(msg->tsig, &rdata);
2775 dns_rdata_toregion(&rdata, &r);
2777 result = isc_buffer_allocate(mctx, querytsig, r.length);
2778 if (result != ISC_R_SUCCESS)
2779 return (result);
2780 isc_buffer_putmem(*querytsig, r.base, r.length);
2781 return (ISC_R_SUCCESS);
2784 dns_rdataset_t *
2785 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2788 * Get the SIG(0) record for 'msg'.
2791 REQUIRE(DNS_MESSAGE_VALID(msg));
2792 REQUIRE(owner == NULL || *owner == NULL);
2794 if (msg->sig0 != NULL && owner != NULL) {
2795 /* If dns_message_getsig0 is called on a rendered message
2796 * after the SIG(0) has been applied, we need to return the
2797 * root name, not NULL.
2799 if (msg->sig0name == NULL)
2800 *owner = dns_rootname;
2801 else
2802 *owner = msg->sig0name;
2804 return (msg->sig0);
2807 isc_result_t
2808 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2809 isc_region_t r;
2810 unsigned int x;
2811 isc_result_t result;
2814 * Set the SIG(0) key for 'msg'
2818 * The space required for an SIG(0) record is:
2820 * 1 byte for the name
2821 * 2 bytes for the type
2822 * 2 bytes for the class
2823 * 4 bytes for the ttl
2824 * 2 bytes for the type covered
2825 * 1 byte for the algorithm
2826 * 1 bytes for the labels
2827 * 4 bytes for the original ttl
2828 * 4 bytes for the signature expiration
2829 * 4 bytes for the signature inception
2830 * 2 bytes for the key tag
2831 * n bytes for the signer's name
2832 * x bytes for the signature
2833 * ---------------------------------
2834 * 27 + n + x bytes
2836 REQUIRE(DNS_MESSAGE_VALID(msg));
2837 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2838 REQUIRE(msg->state == DNS_SECTION_ANY);
2840 if (key != NULL) {
2841 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2842 dns_name_toregion(dst_key_name(key), &r);
2843 result = dst_key_sigsize(key, &x);
2844 if (result != ISC_R_SUCCESS) {
2845 msg->sig_reserved = 0;
2846 return (result);
2848 msg->sig_reserved = 27 + r.length + x;
2849 result = dns_message_renderreserve(msg, msg->sig_reserved);
2850 if (result != ISC_R_SUCCESS) {
2851 msg->sig_reserved = 0;
2852 return (result);
2854 msg->sig0key = key;
2856 return (ISC_R_SUCCESS);
2859 dst_key_t *
2860 dns_message_getsig0key(dns_message_t *msg) {
2863 * Get the SIG(0) key for 'msg'
2866 REQUIRE(DNS_MESSAGE_VALID(msg));
2868 return (msg->sig0key);
2871 void
2872 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2873 REQUIRE(DNS_MESSAGE_VALID(msg));
2874 REQUIRE(buffer != NULL);
2875 REQUIRE(ISC_BUFFER_VALID(*buffer));
2877 ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2878 *buffer = NULL;
2881 isc_result_t
2882 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
2883 isc_result_t result = ISC_R_SUCCESS;
2884 dns_rdata_t rdata = DNS_RDATA_INIT;
2886 REQUIRE(DNS_MESSAGE_VALID(msg));
2887 REQUIRE(signer != NULL);
2888 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2890 if (msg->tsig == NULL && msg->sig0 == NULL)
2891 return (ISC_R_NOTFOUND);
2893 if (msg->verify_attempted == 0)
2894 return (DNS_R_NOTVERIFIEDYET);
2896 if (!dns_name_hasbuffer(signer)) {
2897 isc_buffer_t *dynbuf = NULL;
2898 result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
2899 if (result != ISC_R_SUCCESS)
2900 return (result);
2901 dns_name_setbuffer(signer, dynbuf);
2902 dns_message_takebuffer(msg, &dynbuf);
2905 if (msg->sig0 != NULL) {
2906 dns_rdata_sig_t sig;
2908 result = dns_rdataset_first(msg->sig0);
2909 INSIST(result == ISC_R_SUCCESS);
2910 dns_rdataset_current(msg->sig0, &rdata);
2912 result = dns_rdata_tostruct(&rdata, &sig, NULL);
2913 if (result != ISC_R_SUCCESS)
2914 return (result);
2916 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
2917 result = ISC_R_SUCCESS;
2918 else
2919 result = DNS_R_SIGINVALID;
2920 dns_name_clone(&sig.signer, signer);
2921 dns_rdata_freestruct(&sig);
2922 } else {
2923 dns_name_t *identity;
2924 dns_rdata_any_tsig_t tsig;
2926 result = dns_rdataset_first(msg->tsig);
2927 INSIST(result == ISC_R_SUCCESS);
2928 dns_rdataset_current(msg->tsig, &rdata);
2930 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2931 if (msg->tsigstatus != dns_rcode_noerror)
2932 result = DNS_R_TSIGVERIFYFAILURE;
2933 else if (tsig.error != dns_rcode_noerror)
2934 result = DNS_R_TSIGERRORSET;
2935 else
2936 result = ISC_R_SUCCESS;
2937 dns_rdata_freestruct(&tsig);
2939 if (msg->tsigkey == NULL) {
2941 * If msg->tsigstatus & tsig.error are both
2942 * dns_rcode_noerror, the message must have been
2943 * verified, which means msg->tsigkey will be
2944 * non-NULL.
2946 INSIST(result != ISC_R_SUCCESS);
2947 } else {
2948 identity = dns_tsigkey_identity(msg->tsigkey);
2949 if (identity == NULL) {
2950 if (result == ISC_R_SUCCESS)
2951 result = DNS_R_NOIDENTITY;
2952 identity = &msg->tsigkey->name;
2954 dns_name_clone(identity, signer);
2958 return (result);
2961 void
2962 dns_message_resetsig(dns_message_t *msg) {
2963 REQUIRE(DNS_MESSAGE_VALID(msg));
2964 msg->verified_sig = 0;
2965 msg->verify_attempted = 0;
2966 msg->tsigstatus = dns_rcode_noerror;
2967 msg->sig0status = dns_rcode_noerror;
2968 msg->timeadjust = 0;
2969 if (msg->tsigkey != NULL) {
2970 dns_tsigkey_detach(&msg->tsigkey);
2971 msg->tsigkey = NULL;
2975 isc_result_t
2976 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
2977 dns_message_resetsig(msg);
2978 return (dns_message_checksig(msg, view));
2981 #ifdef SKAN_MSG_DEBUG
2982 void
2983 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
2984 dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
2985 dns_rdata_any_tsig_t querytsig;
2986 isc_result_t result;
2988 if (msg->tsig != NULL) {
2989 result = dns_rdataset_first(msg->tsig);
2990 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2991 dns_rdataset_current(msg->tsig, &querytsigrdata);
2992 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
2993 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2994 hexdump(txt1, "TSIG", querytsig.signature,
2995 querytsig.siglen);
2998 if (msg->querytsig != NULL) {
2999 result = dns_rdataset_first(msg->querytsig);
3000 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3001 dns_rdataset_current(msg->querytsig, &querytsigrdata);
3002 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3003 RUNTIME_CHECK(result == ISC_R_SUCCESS);
3004 hexdump(txt1, "QUERYTSIG", querytsig.signature,
3005 querytsig.siglen);
3008 #endif
3010 isc_result_t
3011 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
3012 isc_buffer_t b, msgb;
3014 REQUIRE(DNS_MESSAGE_VALID(msg));
3016 if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
3017 return (ISC_R_SUCCESS);
3019 INSIST(msg->saved.base != NULL);
3020 isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
3021 isc_buffer_add(&msgb, msg->saved.length);
3022 if (msg->tsigkey != NULL || msg->tsig != NULL) {
3023 #ifdef SKAN_MSG_DEBUG
3024 dns_message_dumpsig(msg, "dns_message_checksig#1");
3025 #endif
3026 if (view != NULL)
3027 return (dns_view_checksig(view, &msgb, msg));
3028 else
3029 return (dns_tsig_verify(&msgb, msg, NULL, NULL));
3030 } else {
3031 dns_rdata_t rdata = DNS_RDATA_INIT;
3032 dns_rdata_sig_t sig;
3033 dns_rdataset_t keyset;
3034 isc_result_t result;
3036 result = dns_rdataset_first(msg->sig0);
3037 INSIST(result == ISC_R_SUCCESS);
3038 dns_rdataset_current(msg->sig0, &rdata);
3041 * This can occur when the message is a dynamic update, since
3042 * the rdata length checking is relaxed. This should not
3043 * happen in a well-formed message, since the SIG(0) is only
3044 * looked for in the additional section, and the dynamic update
3045 * meta-records are in the prerequisite and update sections.
3047 if (rdata.length == 0)
3048 return (ISC_R_UNEXPECTEDEND);
3050 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
3051 if (result != ISC_R_SUCCESS)
3052 return (result);
3054 dns_rdataset_init(&keyset);
3055 if (view == NULL)
3056 return (DNS_R_KEYUNAUTHORIZED);
3057 result = dns_view_simplefind(view, &sig.signer,
3058 dns_rdatatype_key /* SIG(0) */,
3059 0, 0, ISC_FALSE, &keyset, NULL);
3061 if (result != ISC_R_SUCCESS) {
3062 /* XXXBEW Should possibly create a fetch here */
3063 result = DNS_R_KEYUNAUTHORIZED;
3064 goto freesig;
3065 } else if (keyset.trust < dns_trust_secure) {
3066 /* XXXBEW Should call a validator here */
3067 result = DNS_R_KEYUNAUTHORIZED;
3068 goto freesig;
3070 result = dns_rdataset_first(&keyset);
3071 INSIST(result == ISC_R_SUCCESS);
3072 for (;
3073 result == ISC_R_SUCCESS;
3074 result = dns_rdataset_next(&keyset))
3076 dst_key_t *key = NULL;
3078 dns_rdata_reset(&rdata);
3079 dns_rdataset_current(&keyset, &rdata);
3080 isc_buffer_init(&b, rdata.data, rdata.length);
3081 isc_buffer_add(&b, rdata.length);
3083 result = dst_key_fromdns(&sig.signer, rdata.rdclass,
3084 &b, view->mctx, &key);
3085 if (result != ISC_R_SUCCESS)
3086 continue;
3087 if (dst_key_alg(key) != sig.algorithm ||
3088 dst_key_id(key) != sig.keyid ||
3089 !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3090 dst_key_proto(key) == DNS_KEYPROTO_ANY))
3092 dst_key_free(&key);
3093 continue;
3095 result = dns_dnssec_verifymessage(&msgb, msg, key);
3096 dst_key_free(&key);
3097 if (result == ISC_R_SUCCESS)
3098 break;
3100 if (result == ISC_R_NOMORE)
3101 result = DNS_R_KEYUNAUTHORIZED;
3103 freesig:
3104 if (dns_rdataset_isassociated(&keyset))
3105 dns_rdataset_disassociate(&keyset);
3106 dns_rdata_freestruct(&sig);
3107 return (result);
3111 isc_result_t
3112 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3113 const dns_master_style_t *style,
3114 dns_messagetextflag_t flags,
3115 isc_buffer_t *target) {
3116 dns_name_t *name, empty_name;
3117 dns_rdataset_t *rdataset;
3118 isc_result_t result;
3120 REQUIRE(DNS_MESSAGE_VALID(msg));
3121 REQUIRE(target != NULL);
3122 REQUIRE(VALID_SECTION(section));
3124 if (ISC_LIST_EMPTY(msg->sections[section]))
3125 return (ISC_R_SUCCESS);
3127 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3128 ADD_STRING(target, ";; ");
3129 if (msg->opcode != dns_opcode_update) {
3130 ADD_STRING(target, sectiontext[section]);
3131 } else {
3132 ADD_STRING(target, updsectiontext[section]);
3134 ADD_STRING(target, " SECTION:\n");
3137 dns_name_init(&empty_name, NULL);
3138 result = dns_message_firstname(msg, section);
3139 if (result != ISC_R_SUCCESS) {
3140 return (result);
3142 do {
3143 name = NULL;
3144 dns_message_currentname(msg, section, &name);
3145 for (rdataset = ISC_LIST_HEAD(name->list);
3146 rdataset != NULL;
3147 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3148 if (section == DNS_SECTION_QUESTION) {
3149 ADD_STRING(target, ";");
3150 result = dns_master_questiontotext(name,
3151 rdataset,
3152 style,
3153 target);
3154 } else {
3155 result = dns_master_rdatasettotext(name,
3156 rdataset,
3157 style,
3158 target);
3160 if (result != ISC_R_SUCCESS)
3161 return (result);
3163 result = dns_message_nextname(msg, section);
3164 } while (result == ISC_R_SUCCESS);
3165 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3166 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3167 ADD_STRING(target, "\n");
3168 if (result == ISC_R_NOMORE)
3169 result = ISC_R_SUCCESS;
3170 return (result);
3173 isc_result_t
3174 dns_message_pseudosectiontotext(dns_message_t *msg,
3175 dns_pseudosection_t section,
3176 const dns_master_style_t *style,
3177 dns_messagetextflag_t flags,
3178 isc_buffer_t *target) {
3179 dns_rdataset_t *ps = NULL;
3180 dns_name_t *name = NULL;
3181 isc_result_t result;
3182 char buf[sizeof("1234567890")];
3183 isc_uint32_t mbz;
3184 dns_rdata_t rdata;
3185 isc_buffer_t optbuf;
3186 isc_uint16_t optcode, optlen;
3187 unsigned char *optdata;
3189 REQUIRE(DNS_MESSAGE_VALID(msg));
3190 REQUIRE(target != NULL);
3191 REQUIRE(VALID_PSEUDOSECTION(section));
3193 switch (section) {
3194 case DNS_PSEUDOSECTION_OPT:
3195 ps = dns_message_getopt(msg);
3196 if (ps == NULL)
3197 return (ISC_R_SUCCESS);
3198 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3199 ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3200 ADD_STRING(target, "; EDNS: version: ");
3201 snprintf(buf, sizeof(buf), "%u",
3202 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3203 ADD_STRING(target, buf);
3204 ADD_STRING(target, ", flags:");
3205 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3206 ADD_STRING(target, " do");
3207 mbz = ps->ttl & ~DNS_MESSAGEEXTFLAG_DO & 0xffff;
3208 if (mbz != 0) {
3209 ADD_STRING(target, "; MBZ: ");
3210 snprintf(buf, sizeof(buf), "%.4x ", mbz);
3211 ADD_STRING(target, buf);
3212 ADD_STRING(target, ", udp: ");
3213 } else
3214 ADD_STRING(target, "; udp: ");
3215 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3216 ADD_STRING(target, buf);
3218 result = dns_rdataset_first(ps);
3219 if (result != ISC_R_SUCCESS)
3220 return (ISC_R_SUCCESS);
3222 /* Print EDNS info, if any */
3223 dns_rdata_init(&rdata);
3224 dns_rdataset_current(ps, &rdata);
3225 if (rdata.length < 4)
3226 return (ISC_R_SUCCESS);
3228 isc_buffer_init(&optbuf, rdata.data, rdata.length);
3229 isc_buffer_add(&optbuf, rdata.length);
3230 optcode = isc_buffer_getuint16(&optbuf);
3231 optlen = isc_buffer_getuint16(&optbuf);
3233 if (optcode == DNS_OPT_NSID) {
3234 ADD_STRING(target, "; NSID");
3235 } else {
3236 ADD_STRING(target, "; OPT=");
3237 sprintf(buf, "%u", optcode);
3238 ADD_STRING(target, buf);
3241 if (optlen != 0) {
3242 int i;
3243 ADD_STRING(target, ": ");
3245 optdata = rdata.data + 4;
3246 for (i = 0; i < optlen; i++) {
3247 sprintf(buf, "%02x ", optdata[i]);
3248 ADD_STRING(target, buf);
3250 for (i = 0; i < optlen; i++) {
3251 ADD_STRING(target, " (");
3252 if (isprint(optdata[i]))
3253 isc_buffer_putmem(target, &optdata[i],
3255 else
3256 isc_buffer_putstr(target, ".");
3257 ADD_STRING(target, ")");
3260 ADD_STRING(target, "\n");
3261 return (ISC_R_SUCCESS);
3262 case DNS_PSEUDOSECTION_TSIG:
3263 ps = dns_message_gettsig(msg, &name);
3264 if (ps == NULL)
3265 return (ISC_R_SUCCESS);
3266 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3267 ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
3268 result = dns_master_rdatasettotext(name, ps, style, target);
3269 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3270 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3271 ADD_STRING(target, "\n");
3272 return (result);
3273 case DNS_PSEUDOSECTION_SIG0:
3274 ps = dns_message_getsig0(msg, &name);
3275 if (ps == NULL)
3276 return (ISC_R_SUCCESS);
3277 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3278 ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3279 result = dns_master_rdatasettotext(name, ps, style, target);
3280 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3281 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3282 ADD_STRING(target, "\n");
3283 return (result);
3285 return (ISC_R_UNEXPECTED);
3288 isc_result_t
3289 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3290 dns_messagetextflag_t flags, isc_buffer_t *target) {
3291 char buf[sizeof("1234567890")];
3292 isc_result_t result;
3294 REQUIRE(DNS_MESSAGE_VALID(msg));
3295 REQUIRE(target != NULL);
3297 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
3298 ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
3299 ADD_STRING(target, opcodetext[msg->opcode]);
3300 ADD_STRING(target, ", status: ");
3301 if (msg->rcode < (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
3302 ADD_STRING(target, rcodetext[msg->rcode]);
3303 } else {
3304 snprintf(buf, sizeof(buf), "%4u", msg->rcode);
3305 ADD_STRING(target, buf);
3307 ADD_STRING(target, ", id: ");
3308 snprintf(buf, sizeof(buf), "%6u", msg->id);
3309 ADD_STRING(target, buf);
3310 ADD_STRING(target, "\n;; flags: ");
3311 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3312 ADD_STRING(target, "qr ");
3313 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3314 ADD_STRING(target, "aa ");
3315 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3316 ADD_STRING(target, "tc ");
3317 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3318 ADD_STRING(target, "rd ");
3319 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3320 ADD_STRING(target, "ra ");
3321 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3322 ADD_STRING(target, "ad ");
3323 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
3324 ADD_STRING(target, "cd ");
3325 if (msg->opcode != dns_opcode_update) {
3326 ADD_STRING(target, "; QUESTION: ");
3327 } else {
3328 ADD_STRING(target, "; ZONE: ");
3330 snprintf(buf, sizeof(buf), "%1u",
3331 msg->counts[DNS_SECTION_QUESTION]);
3332 ADD_STRING(target, buf);
3333 if (msg->opcode != dns_opcode_update) {
3334 ADD_STRING(target, ", ANSWER: ");
3335 } else {
3336 ADD_STRING(target, ", PREREQ: ");
3338 snprintf(buf, sizeof(buf), "%1u",
3339 msg->counts[DNS_SECTION_ANSWER]);
3340 ADD_STRING(target, buf);
3341 if (msg->opcode != dns_opcode_update) {
3342 ADD_STRING(target, ", AUTHORITY: ");
3343 } else {
3344 ADD_STRING(target, ", UPDATE: ");
3346 snprintf(buf, sizeof(buf), "%1u",
3347 msg->counts[DNS_SECTION_AUTHORITY]);
3348 ADD_STRING(target, buf);
3349 ADD_STRING(target, ", ADDITIONAL: ");
3350 snprintf(buf, sizeof(buf), "%1u",
3351 msg->counts[DNS_SECTION_ADDITIONAL]);
3352 ADD_STRING(target, buf);
3353 ADD_STRING(target, "\n");
3355 result = dns_message_pseudosectiontotext(msg,
3356 DNS_PSEUDOSECTION_OPT,
3357 style, flags, target);
3358 if (result != ISC_R_SUCCESS)
3359 return (result);
3361 result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
3362 style, flags, target);
3363 if (result != ISC_R_SUCCESS)
3364 return (result);
3365 result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
3366 style, flags, target);
3367 if (result != ISC_R_SUCCESS)
3368 return (result);
3369 result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
3370 style, flags, target);
3371 if (result != ISC_R_SUCCESS)
3372 return (result);
3373 result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
3374 style, flags, target);
3375 if (result != ISC_R_SUCCESS)
3376 return (result);
3378 result = dns_message_pseudosectiontotext(msg,
3379 DNS_PSEUDOSECTION_TSIG,
3380 style, flags, target);
3381 if (result != ISC_R_SUCCESS)
3382 return (result);
3384 result = dns_message_pseudosectiontotext(msg,
3385 DNS_PSEUDOSECTION_SIG0,
3386 style, flags, target);
3387 if (result != ISC_R_SUCCESS)
3388 return (result);
3390 return (ISC_R_SUCCESS);
3393 isc_region_t *
3394 dns_message_getrawmessage(dns_message_t *msg) {
3395 REQUIRE(DNS_MESSAGE_VALID(msg));
3396 return (&msg->saved);
3399 void
3400 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3401 const void *order_arg)
3403 REQUIRE(DNS_MESSAGE_VALID(msg));
3404 msg->order = order;
3405 msg->order_arg = order_arg;
3408 void
3409 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3410 REQUIRE(DNS_MESSAGE_VALID(msg));
3411 msg->timeadjust = timeadjust;
3415 dns_message_gettimeadjust(dns_message_t *msg) {
3416 REQUIRE(DNS_MESSAGE_VALID(msg));
3417 return (msg->timeadjust);
3420 isc_result_t
3421 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3423 REQUIRE(opcode < 16);
3425 if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
3426 return (ISC_R_NOSPACE);
3427 isc_buffer_putstr(target, opcodetext[opcode]);
3428 return (ISC_R_SUCCESS);