Import bind-9.3.4
[dragonfly.git] / contrib / bind-9.3 / lib / dns / message.c
blob33875433f6aa05f6ecdb19a053af0c8a8fb80608
1 /*
2 * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.
18 /* $Id: message.c,v 1.194.2.10.2.24 2006/02/28 06:32:54 marka Exp $ */
20 /***
21 *** Imports
22 ***/
24 #include <config.h>
26 #include <isc/buffer.h>
27 #include <isc/mem.h>
28 #include <isc/print.h>
29 #include <isc/string.h> /* Required for HP/UX (and others?) */
30 #include <isc/util.h>
32 #include <dns/dnssec.h>
33 #include <dns/keyvalues.h>
34 #include <dns/log.h>
35 #include <dns/masterdump.h>
36 #include <dns/message.h>
37 #include <dns/opcode.h>
38 #include <dns/rdata.h>
39 #include <dns/rdatalist.h>
40 #include <dns/rdataset.h>
41 #include <dns/rdatastruct.h>
42 #include <dns/result.h>
43 #include <dns/tsig.h>
44 #include <dns/view.h>
46 #define DNS_MESSAGE_OPCODE_MASK 0x7800U
47 #define DNS_MESSAGE_OPCODE_SHIFT 11
48 #define DNS_MESSAGE_RCODE_MASK 0x000fU
49 #define DNS_MESSAGE_FLAG_MASK 0x8ff0U
50 #define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U
51 #define DNS_MESSAGE_EDNSRCODE_SHIFT 24
52 #define DNS_MESSAGE_EDNSVERSION_MASK 0x00ff0000U
53 #define DNS_MESSAGE_EDNSVERSION_SHIFT 16
55 #define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \
56 && ((s) < DNS_SECTION_MAX))
57 #define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \
58 && ((s) < DNS_SECTION_MAX))
59 #define ADD_STRING(b, s) {if (strlen(s) >= \
60 isc_buffer_availablelength(b)) \
61 return(ISC_R_NOSPACE); else \
62 isc_buffer_putstr(b, s);}
63 #define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \
64 && ((s) < DNS_PSEUDOSECTION_MAX))
67 * This is the size of each individual scratchpad buffer, and the numbers
68 * of various block allocations used within the server.
69 * XXXMLG These should come from a config setting.
71 #define SCRATCHPAD_SIZE 512
72 #define NAME_COUNT 8
73 #define OFFSET_COUNT 4
74 #define RDATA_COUNT 8
75 #define RDATALIST_COUNT 8
76 #define RDATASET_COUNT RDATALIST_COUNT
79 * Text representation of the different items, for message_totext
80 * functions.
82 static const char *sectiontext[] = {
83 "QUESTION",
84 "ANSWER",
85 "AUTHORITY",
86 "ADDITIONAL"
89 static const char *updsectiontext[] = {
90 "ZONE",
91 "PREREQUISITE",
92 "UPDATE",
93 "ADDITIONAL"
96 static const char *opcodetext[] = {
97 "QUERY",
98 "IQUERY",
99 "STATUS",
100 "RESERVED3",
101 "NOTIFY",
102 "UPDATE",
103 "RESERVED6",
104 "RESERVED7",
105 "RESERVED8",
106 "RESERVED9",
107 "RESERVED10",
108 "RESERVED11",
109 "RESERVED12",
110 "RESERVED13",
111 "RESERVED14",
112 "RESERVED15"
115 static const char *rcodetext[] = {
116 "NOERROR",
117 "FORMERR",
118 "SERVFAIL",
119 "NXDOMAIN",
120 "NOTIMP",
121 "REFUSED",
122 "YXDOMAIN",
123 "YXRRSET",
124 "NXRRSET",
125 "NOTAUTH",
126 "NOTZONE",
127 "RESERVED11",
128 "RESERVED12",
129 "RESERVED13",
130 "RESERVED14",
131 "RESERVED15",
132 "BADVERS"
137 * "helper" type, which consists of a block of some type, and is linkable.
138 * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
139 * size, or the allocated elements will not be alligned correctly.
141 struct dns_msgblock {
142 unsigned int count;
143 unsigned int remaining;
144 ISC_LINK(dns_msgblock_t) link;
145 }; /* dynamically sized */
147 static inline dns_msgblock_t *
148 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
150 #define msgblock_get(block, type) \
151 ((type *)msgblock_internalget(block, sizeof(type)))
153 static inline void *
154 msgblock_internalget(dns_msgblock_t *, unsigned int);
156 static inline void
157 msgblock_reset(dns_msgblock_t *);
159 static inline void
160 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
163 * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory
164 * is free, return NULL.
166 static inline dns_msgblock_t *
167 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
168 unsigned int count)
170 dns_msgblock_t *block;
171 unsigned int length;
173 length = sizeof(dns_msgblock_t) + (sizeof_type * count);
175 block = isc_mem_get(mctx, length);
176 if (block == NULL)
177 return (NULL);
179 block->count = count;
180 block->remaining = count;
182 ISC_LINK_INIT(block, link);
184 return (block);
188 * Return an element from the msgblock. If no more are available, return
189 * NULL.
191 static inline void *
192 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
193 void *ptr;
195 if (block == NULL || block->remaining == 0)
196 return (NULL);
198 block->remaining--;
200 ptr = (((unsigned char *)block)
201 + sizeof(dns_msgblock_t)
202 + (sizeof_type * block->remaining));
204 return (ptr);
207 static inline void
208 msgblock_reset(dns_msgblock_t *block) {
209 block->remaining = block->count;
213 * Release memory associated with a message block.
215 static inline void
216 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
218 unsigned int length;
220 length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
222 isc_mem_put(mctx, block, length);
226 * Allocate a new dynamic buffer, and attach it to this message as the
227 * "current" buffer. (which is always the last on the list, for our
228 * uses)
230 static inline isc_result_t
231 newbuffer(dns_message_t *msg, unsigned int size) {
232 isc_result_t result;
233 isc_buffer_t *dynbuf;
235 dynbuf = NULL;
236 result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
237 if (result != ISC_R_SUCCESS)
238 return (ISC_R_NOMEMORY);
240 ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
241 return (ISC_R_SUCCESS);
244 static inline isc_buffer_t *
245 currentbuffer(dns_message_t *msg) {
246 isc_buffer_t *dynbuf;
248 dynbuf = ISC_LIST_TAIL(msg->scratchpad);
249 INSIST(dynbuf != NULL);
251 return (dynbuf);
254 static inline void
255 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
256 ISC_LIST_PREPEND(msg->freerdata, rdata, link);
259 static inline dns_rdata_t *
260 newrdata(dns_message_t *msg) {
261 dns_msgblock_t *msgblock;
262 dns_rdata_t *rdata;
264 rdata = ISC_LIST_HEAD(msg->freerdata);
265 if (rdata != NULL) {
266 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
267 return (rdata);
270 msgblock = ISC_LIST_TAIL(msg->rdatas);
271 rdata = msgblock_get(msgblock, dns_rdata_t);
272 if (rdata == NULL) {
273 msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
274 RDATA_COUNT);
275 if (msgblock == NULL)
276 return (NULL);
278 ISC_LIST_APPEND(msg->rdatas, msgblock, link);
280 rdata = msgblock_get(msgblock, dns_rdata_t);
283 dns_rdata_init(rdata);
284 return (rdata);
287 static inline void
288 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
289 ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
292 static inline dns_rdatalist_t *
293 newrdatalist(dns_message_t *msg) {
294 dns_msgblock_t *msgblock;
295 dns_rdatalist_t *rdatalist;
297 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
298 if (rdatalist != NULL) {
299 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
300 return (rdatalist);
303 msgblock = ISC_LIST_TAIL(msg->rdatalists);
304 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
305 if (rdatalist == NULL) {
306 msgblock = msgblock_allocate(msg->mctx,
307 sizeof(dns_rdatalist_t),
308 RDATALIST_COUNT);
309 if (msgblock == NULL)
310 return (NULL);
312 ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
314 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
317 return (rdatalist);
320 static inline dns_offsets_t *
321 newoffsets(dns_message_t *msg) {
322 dns_msgblock_t *msgblock;
323 dns_offsets_t *offsets;
325 msgblock = ISC_LIST_TAIL(msg->offsets);
326 offsets = msgblock_get(msgblock, dns_offsets_t);
327 if (offsets == NULL) {
328 msgblock = msgblock_allocate(msg->mctx,
329 sizeof(dns_offsets_t),
330 OFFSET_COUNT);
331 if (msgblock == NULL)
332 return (NULL);
334 ISC_LIST_APPEND(msg->offsets, msgblock, link);
336 offsets = msgblock_get(msgblock, dns_offsets_t);
339 return (offsets);
342 static inline void
343 msginitheader(dns_message_t *m) {
344 m->id = 0;
345 m->flags = 0;
346 m->rcode = 0;
347 m->opcode = 0;
348 m->rdclass = 0;
351 static inline void
352 msginitprivate(dns_message_t *m) {
353 unsigned int i;
355 for (i = 0; i < DNS_SECTION_MAX; i++) {
356 m->cursors[i] = NULL;
357 m->counts[i] = 0;
359 m->opt = NULL;
360 m->sig0 = NULL;
361 m->sig0name = NULL;
362 m->tsig = NULL;
363 m->tsigname = NULL;
364 m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */
365 m->opt_reserved = 0;
366 m->sig_reserved = 0;
367 m->reserved = 0;
368 m->buffer = NULL;
371 static inline void
372 msginittsig(dns_message_t *m) {
373 m->tsigstatus = dns_rcode_noerror;
374 m->querytsigstatus = dns_rcode_noerror;
375 m->tsigkey = NULL;
376 m->tsigctx = NULL;
377 m->sigstart = -1;
378 m->sig0key = NULL;
379 m->sig0status = dns_rcode_noerror;
380 m->timeadjust = 0;
384 * Init elements to default state. Used both when allocating a new element
385 * and when resetting one.
387 static inline void
388 msginit(dns_message_t *m) {
389 msginitheader(m);
390 msginitprivate(m);
391 msginittsig(m);
392 m->header_ok = 0;
393 m->question_ok = 0;
394 m->tcp_continuation = 0;
395 m->verified_sig = 0;
396 m->verify_attempted = 0;
397 m->order = NULL;
398 m->order_arg = NULL;
399 m->query.base = NULL;
400 m->query.length = 0;
401 m->free_query = 0;
402 m->saved.base = NULL;
403 m->saved.length = 0;
404 m->free_saved = 0;
405 m->querytsig = NULL;
408 static inline void
409 msgresetnames(dns_message_t *msg, unsigned int first_section) {
410 unsigned int i;
411 dns_name_t *name, *next_name;
412 dns_rdataset_t *rds, *next_rds;
415 * Clean up name lists by calling the rdataset disassociate function.
417 for (i = first_section; i < DNS_SECTION_MAX; i++) {
418 name = ISC_LIST_HEAD(msg->sections[i]);
419 while (name != NULL) {
420 next_name = ISC_LIST_NEXT(name, link);
421 ISC_LIST_UNLINK(msg->sections[i], name, link);
423 rds = ISC_LIST_HEAD(name->list);
424 while (rds != NULL) {
425 next_rds = ISC_LIST_NEXT(rds, link);
426 ISC_LIST_UNLINK(name->list, rds, link);
428 INSIST(dns_rdataset_isassociated(rds));
429 dns_rdataset_disassociate(rds);
430 isc_mempool_put(msg->rdspool, rds);
431 rds = next_rds;
433 if (dns_name_dynamic(name))
434 dns_name_free(name, msg->mctx);
435 isc_mempool_put(msg->namepool, name);
436 name = next_name;
441 static void
442 msgresetopt(dns_message_t *msg)
444 if (msg->opt != NULL) {
445 if (msg->opt_reserved > 0) {
446 dns_message_renderrelease(msg, msg->opt_reserved);
447 msg->opt_reserved = 0;
449 INSIST(dns_rdataset_isassociated(msg->opt));
450 dns_rdataset_disassociate(msg->opt);
451 isc_mempool_put(msg->rdspool, msg->opt);
452 msg->opt = NULL;
456 static void
457 msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
458 if (msg->sig_reserved > 0) {
459 dns_message_renderrelease(msg, msg->sig_reserved);
460 msg->sig_reserved = 0;
462 if (msg->tsig != NULL) {
463 INSIST(dns_rdataset_isassociated(msg->tsig));
464 INSIST(msg->namepool != NULL);
465 if (replying) {
466 INSIST(msg->querytsig == NULL);
467 msg->querytsig = msg->tsig;
468 } else {
469 dns_rdataset_disassociate(msg->tsig);
470 isc_mempool_put(msg->rdspool, msg->tsig);
471 if (msg->querytsig != NULL) {
472 dns_rdataset_disassociate(msg->querytsig);
473 isc_mempool_put(msg->rdspool, msg->querytsig);
476 if (dns_name_dynamic(msg->tsigname))
477 dns_name_free(msg->tsigname, msg->mctx);
478 isc_mempool_put(msg->namepool, msg->tsigname);
479 msg->tsig = NULL;
480 msg->tsigname = NULL;
481 } else if (msg->querytsig != NULL && !replying) {
482 dns_rdataset_disassociate(msg->querytsig);
483 isc_mempool_put(msg->rdspool, msg->querytsig);
484 msg->querytsig = NULL;
486 if (msg->sig0 != NULL) {
487 INSIST(dns_rdataset_isassociated(msg->sig0));
488 dns_rdataset_disassociate(msg->sig0);
489 isc_mempool_put(msg->rdspool, msg->sig0);
490 if (msg->sig0name != NULL) {
491 if (dns_name_dynamic(msg->sig0name))
492 dns_name_free(msg->sig0name, msg->mctx);
493 isc_mempool_put(msg->namepool, msg->sig0name);
495 msg->sig0 = NULL;
496 msg->sig0name = NULL;
501 * Free all but one (or everything) for this message. This is used by
502 * both dns_message_reset() and dns_message_destroy().
504 static void
505 msgreset(dns_message_t *msg, isc_boolean_t everything) {
506 dns_msgblock_t *msgblock, *next_msgblock;
507 isc_buffer_t *dynbuf, *next_dynbuf;
508 dns_rdata_t *rdata;
509 dns_rdatalist_t *rdatalist;
511 msgresetnames(msg, 0);
512 msgresetopt(msg);
513 msgresetsigs(msg, ISC_FALSE);
516 * Clean up linked lists.
520 * Run through the free lists, and just unlink anything found there.
521 * The memory isn't lost since these are part of message blocks we
522 * have allocated.
524 rdata = ISC_LIST_HEAD(msg->freerdata);
525 while (rdata != NULL) {
526 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
527 rdata = ISC_LIST_HEAD(msg->freerdata);
529 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
530 while (rdatalist != NULL) {
531 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
532 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
535 dynbuf = ISC_LIST_HEAD(msg->scratchpad);
536 INSIST(dynbuf != NULL);
537 if (!everything) {
538 isc_buffer_clear(dynbuf);
539 dynbuf = ISC_LIST_NEXT(dynbuf, link);
541 while (dynbuf != NULL) {
542 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
543 ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
544 isc_buffer_free(&dynbuf);
545 dynbuf = next_dynbuf;
548 msgblock = ISC_LIST_HEAD(msg->rdatas);
549 if (!everything && msgblock != NULL) {
550 msgblock_reset(msgblock);
551 msgblock = ISC_LIST_NEXT(msgblock, link);
553 while (msgblock != NULL) {
554 next_msgblock = ISC_LIST_NEXT(msgblock, link);
555 ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
556 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
557 msgblock = next_msgblock;
561 * rdatalists could be empty.
564 msgblock = ISC_LIST_HEAD(msg->rdatalists);
565 if (!everything && msgblock != NULL) {
566 msgblock_reset(msgblock);
567 msgblock = ISC_LIST_NEXT(msgblock, link);
569 while (msgblock != NULL) {
570 next_msgblock = ISC_LIST_NEXT(msgblock, link);
571 ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
572 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
573 msgblock = next_msgblock;
576 msgblock = ISC_LIST_HEAD(msg->offsets);
577 if (!everything && msgblock != NULL) {
578 msgblock_reset(msgblock);
579 msgblock = ISC_LIST_NEXT(msgblock, link);
581 while (msgblock != NULL) {
582 next_msgblock = ISC_LIST_NEXT(msgblock, link);
583 ISC_LIST_UNLINK(msg->offsets, msgblock, link);
584 msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
585 msgblock = next_msgblock;
588 if (msg->tsigkey != NULL) {
589 dns_tsigkey_detach(&msg->tsigkey);
590 msg->tsigkey = NULL;
593 if (msg->query.base != NULL) {
594 if (msg->free_query != 0)
595 isc_mem_put(msg->mctx, msg->query.base,
596 msg->query.length);
597 msg->query.base = NULL;
598 msg->query.length = 0;
601 if (msg->saved.base != NULL) {
602 if (msg->free_saved != 0)
603 isc_mem_put(msg->mctx, msg->saved.base,
604 msg->saved.length);
605 msg->saved.base = NULL;
606 msg->saved.length = 0;
610 * cleanup the buffer cleanup list
612 dynbuf = ISC_LIST_HEAD(msg->cleanup);
613 while (dynbuf != NULL) {
614 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
615 ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
616 isc_buffer_free(&dynbuf);
617 dynbuf = next_dynbuf;
621 * Set other bits to normal default values.
623 if (!everything)
624 msginit(msg);
626 ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
627 ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
630 static unsigned int
631 spacefortsig(dns_tsigkey_t *key, int otherlen) {
632 isc_region_t r1, r2;
633 unsigned int x;
634 isc_result_t result;
637 * The space required for an TSIG record is:
639 * n1 bytes for the name
640 * 2 bytes for the type
641 * 2 bytes for the class
642 * 4 bytes for the ttl
643 * 2 bytes for the rdlength
644 * n2 bytes for the algorithm name
645 * 6 bytes for the time signed
646 * 2 bytes for the fudge
647 * 2 bytes for the MAC size
648 * x bytes for the MAC
649 * 2 bytes for the original id
650 * 2 bytes for the error
651 * 2 bytes for the other data length
652 * y bytes for the other data (at most)
653 * ---------------------------------
654 * 26 + n1 + n2 + x + y bytes
657 dns_name_toregion(&key->name, &r1);
658 dns_name_toregion(key->algorithm, &r2);
659 if (key->key == NULL)
660 x = 0;
661 else {
662 result = dst_key_sigsize(key->key, &x);
663 if (result != ISC_R_SUCCESS)
664 x = 0;
666 return (26 + r1.length + r2.length + x + otherlen);
669 isc_result_t
670 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
672 dns_message_t *m;
673 isc_result_t result;
674 isc_buffer_t *dynbuf;
675 unsigned int i;
677 REQUIRE(mctx != NULL);
678 REQUIRE(msgp != NULL);
679 REQUIRE(*msgp == NULL);
680 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
681 || intent == DNS_MESSAGE_INTENTRENDER);
683 m = isc_mem_get(mctx, sizeof(dns_message_t));
684 if (m == NULL)
685 return (ISC_R_NOMEMORY);
688 * No allocations until further notice. Just initialize all lists
689 * and other members that are freed in the cleanup phase here.
692 m->magic = DNS_MESSAGE_MAGIC;
693 m->from_to_wire = intent;
694 msginit(m);
696 for (i = 0; i < DNS_SECTION_MAX; i++)
697 ISC_LIST_INIT(m->sections[i]);
698 m->mctx = mctx;
700 ISC_LIST_INIT(m->scratchpad);
701 ISC_LIST_INIT(m->cleanup);
702 m->namepool = NULL;
703 m->rdspool = NULL;
704 ISC_LIST_INIT(m->rdatas);
705 ISC_LIST_INIT(m->rdatalists);
706 ISC_LIST_INIT(m->offsets);
707 ISC_LIST_INIT(m->freerdata);
708 ISC_LIST_INIT(m->freerdatalist);
711 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
714 result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
715 if (result != ISC_R_SUCCESS)
716 goto cleanup;
717 isc_mempool_setfreemax(m->namepool, NAME_COUNT);
718 isc_mempool_setname(m->namepool, "msg:names");
720 result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
721 &m->rdspool);
722 if (result != ISC_R_SUCCESS)
723 goto cleanup;
724 isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
725 isc_mempool_setname(m->rdspool, "msg:rdataset");
727 dynbuf = NULL;
728 result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
729 if (result != ISC_R_SUCCESS)
730 goto cleanup;
731 ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
733 m->cctx = NULL;
735 *msgp = m;
736 return (ISC_R_SUCCESS);
739 * Cleanup for error returns.
741 cleanup:
742 dynbuf = ISC_LIST_HEAD(m->scratchpad);
743 if (dynbuf != NULL) {
744 ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
745 isc_buffer_free(&dynbuf);
747 if (m->namepool != NULL)
748 isc_mempool_destroy(&m->namepool);
749 if (m->rdspool != NULL)
750 isc_mempool_destroy(&m->rdspool);
751 m->magic = 0;
752 isc_mem_put(mctx, m, sizeof(dns_message_t));
754 return (ISC_R_NOMEMORY);
757 void
758 dns_message_reset(dns_message_t *msg, unsigned int intent) {
759 REQUIRE(DNS_MESSAGE_VALID(msg));
760 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
761 || intent == DNS_MESSAGE_INTENTRENDER);
763 msgreset(msg, ISC_FALSE);
764 msg->from_to_wire = intent;
767 void
768 dns_message_destroy(dns_message_t **msgp) {
769 dns_message_t *msg;
771 REQUIRE(msgp != NULL);
772 REQUIRE(DNS_MESSAGE_VALID(*msgp));
774 msg = *msgp;
775 *msgp = NULL;
777 msgreset(msg, ISC_TRUE);
778 isc_mempool_destroy(&msg->namepool);
779 isc_mempool_destroy(&msg->rdspool);
780 msg->magic = 0;
781 isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
784 static isc_result_t
785 findname(dns_name_t **foundname, dns_name_t *target,
786 dns_namelist_t *section)
788 dns_name_t *curr;
790 for (curr = ISC_LIST_TAIL(*section);
791 curr != NULL;
792 curr = ISC_LIST_PREV(curr, link)) {
793 if (dns_name_equal(curr, target)) {
794 if (foundname != NULL)
795 *foundname = curr;
796 return (ISC_R_SUCCESS);
800 return (ISC_R_NOTFOUND);
803 isc_result_t
804 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
805 dns_rdatatype_t type, dns_rdatatype_t covers,
806 dns_rdataset_t **rdataset)
808 dns_rdataset_t *curr;
810 if (rdataset != NULL) {
811 REQUIRE(*rdataset == NULL);
814 for (curr = ISC_LIST_TAIL(name->list);
815 curr != NULL;
816 curr = ISC_LIST_PREV(curr, link)) {
817 if (curr->rdclass == rdclass &&
818 curr->type == type && curr->covers == covers) {
819 if (rdataset != NULL)
820 *rdataset = curr;
821 return (ISC_R_SUCCESS);
825 return (ISC_R_NOTFOUND);
828 isc_result_t
829 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
830 dns_rdatatype_t covers, dns_rdataset_t **rdataset)
832 dns_rdataset_t *curr;
834 REQUIRE(name != NULL);
835 if (rdataset != NULL) {
836 REQUIRE(*rdataset == NULL);
839 for (curr = ISC_LIST_TAIL(name->list);
840 curr != NULL;
841 curr = ISC_LIST_PREV(curr, link)) {
842 if (curr->type == type && curr->covers == covers) {
843 if (rdataset != NULL)
844 *rdataset = curr;
845 return (ISC_R_SUCCESS);
849 return (ISC_R_NOTFOUND);
853 * Read a name from buffer "source".
855 static isc_result_t
856 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
857 dns_decompress_t *dctx)
859 isc_buffer_t *scratch;
860 isc_result_t result;
861 unsigned int tries;
863 scratch = currentbuffer(msg);
866 * First try: use current buffer.
867 * Second try: allocate a new buffer and use that.
869 tries = 0;
870 while (tries < 2) {
871 result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
872 scratch);
874 if (result == ISC_R_NOSPACE) {
875 tries++;
877 result = newbuffer(msg, SCRATCHPAD_SIZE);
878 if (result != ISC_R_SUCCESS)
879 return (result);
881 scratch = currentbuffer(msg);
882 dns_name_reset(name);
883 } else {
884 return (result);
888 INSIST(0); /* Cannot get here... */
889 return (ISC_R_UNEXPECTED);
892 static isc_result_t
893 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
894 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
895 unsigned int rdatalen, dns_rdata_t *rdata)
897 isc_buffer_t *scratch;
898 isc_result_t result;
899 unsigned int tries;
900 unsigned int trysize;
902 scratch = currentbuffer(msg);
904 isc_buffer_setactive(source, rdatalen);
907 * First try: use current buffer.
908 * Second try: allocate a new buffer of size
909 * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
910 * (the data will fit if it was not more than 50% compressed)
911 * Subsequent tries: double buffer size on each try.
913 tries = 0;
914 trysize = 0;
915 /* XXX possibly change this to a while (tries < 2) loop */
916 for (;;) {
917 result = dns_rdata_fromwire(rdata, rdclass, rdtype,
918 source, dctx, 0,
919 scratch);
921 if (result == ISC_R_NOSPACE) {
922 if (tries == 0) {
923 trysize = 2 * rdatalen;
924 if (trysize < SCRATCHPAD_SIZE)
925 trysize = SCRATCHPAD_SIZE;
926 } else {
927 INSIST(trysize != 0);
928 if (trysize >= 65535)
929 return (ISC_R_NOSPACE);
930 /* XXX DNS_R_RRTOOLONG? */
931 trysize *= 2;
933 tries++;
934 result = newbuffer(msg, trysize);
935 if (result != ISC_R_SUCCESS)
936 return (result);
938 scratch = currentbuffer(msg);
939 } else {
940 return (result);
945 #define DO_FORMERR \
946 do { \
947 if (best_effort) \
948 seen_problem = ISC_TRUE; \
949 else { \
950 result = DNS_R_FORMERR; \
951 goto cleanup; \
953 } while (0)
955 static isc_result_t
956 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
957 unsigned int options)
959 isc_region_t r;
960 unsigned int count;
961 dns_name_t *name;
962 dns_name_t *name2;
963 dns_offsets_t *offsets;
964 dns_rdataset_t *rdataset;
965 dns_rdatalist_t *rdatalist;
966 isc_result_t result;
967 dns_rdatatype_t rdtype;
968 dns_rdataclass_t rdclass;
969 dns_namelist_t *section;
970 isc_boolean_t free_name;
971 isc_boolean_t best_effort;
972 isc_boolean_t seen_problem;
974 section = &msg->sections[DNS_SECTION_QUESTION];
976 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
977 seen_problem = ISC_FALSE;
979 name = NULL;
980 rdataset = NULL;
981 rdatalist = NULL;
983 for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
984 name = isc_mempool_get(msg->namepool);
985 if (name == NULL)
986 return (ISC_R_NOMEMORY);
987 free_name = ISC_TRUE;
989 offsets = newoffsets(msg);
990 if (offsets == NULL) {
991 result = ISC_R_NOMEMORY;
992 goto cleanup;
994 dns_name_init(name, *offsets);
997 * Parse the name out of this packet.
999 isc_buffer_remainingregion(source, &r);
1000 isc_buffer_setactive(source, r.length);
1001 result = getname(name, source, msg, dctx);
1002 if (result != ISC_R_SUCCESS)
1003 goto cleanup;
1006 * Run through the section, looking to see if this name
1007 * is already there. If it is found, put back the allocated
1008 * name since we no longer need it, and set our name pointer
1009 * to point to the name we found.
1011 result = findname(&name2, name, section);
1014 * If it is the first name in the section, accept it.
1016 * If it is not, but is not the same as the name already
1017 * in the question section, append to the section. Note that
1018 * here in the question section this is illegal, so return
1019 * FORMERR. In the future, check the opcode to see if
1020 * this should be legal or not. In either case we no longer
1021 * need this name pointer.
1023 if (result != ISC_R_SUCCESS) {
1024 if (!ISC_LIST_EMPTY(*section))
1025 DO_FORMERR;
1026 ISC_LIST_APPEND(*section, name, link);
1027 free_name = ISC_FALSE;
1028 } else {
1029 isc_mempool_put(msg->namepool, name);
1030 name = name2;
1031 name2 = NULL;
1032 free_name = ISC_FALSE;
1036 * Get type and class.
1038 isc_buffer_remainingregion(source, &r);
1039 if (r.length < 4) {
1040 result = ISC_R_UNEXPECTEDEND;
1041 goto cleanup;
1043 rdtype = isc_buffer_getuint16(source);
1044 rdclass = isc_buffer_getuint16(source);
1047 * If this class is different than the one we already read,
1048 * this is an error.
1050 if (msg->state == DNS_SECTION_ANY) {
1051 msg->state = DNS_SECTION_QUESTION;
1052 msg->rdclass = rdclass;
1053 } else if (msg->rdclass != rdclass)
1054 DO_FORMERR;
1057 * Can't ask the same question twice.
1059 result = dns_message_find(name, rdclass, rdtype, 0, NULL);
1060 if (result == ISC_R_SUCCESS)
1061 DO_FORMERR;
1064 * Allocate a new rdatalist.
1066 rdatalist = newrdatalist(msg);
1067 if (rdatalist == NULL) {
1068 result = ISC_R_NOMEMORY;
1069 goto cleanup;
1071 rdataset = isc_mempool_get(msg->rdspool);
1072 if (rdataset == NULL) {
1073 result = ISC_R_NOMEMORY;
1074 goto cleanup;
1078 * Convert rdatalist to rdataset, and attach the latter to
1079 * the name.
1081 rdatalist->type = rdtype;
1082 rdatalist->covers = 0;
1083 rdatalist->rdclass = rdclass;
1084 rdatalist->ttl = 0;
1085 ISC_LIST_INIT(rdatalist->rdata);
1087 dns_rdataset_init(rdataset);
1088 result = dns_rdatalist_tordataset(rdatalist, rdataset);
1089 if (result != ISC_R_SUCCESS)
1090 goto cleanup;
1092 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1094 ISC_LIST_APPEND(name->list, rdataset, link);
1095 rdataset = NULL;
1098 if (seen_problem)
1099 return (DNS_R_RECOVERABLE);
1100 return (ISC_R_SUCCESS);
1102 cleanup:
1103 if (rdataset != NULL) {
1104 INSIST(!dns_rdataset_isassociated(rdataset));
1105 isc_mempool_put(msg->rdspool, rdataset);
1107 #if 0
1108 if (rdatalist != NULL)
1109 isc_mempool_put(msg->rdlpool, rdatalist);
1110 #endif
1111 if (free_name)
1112 isc_mempool_put(msg->namepool, name);
1114 return (result);
1117 static isc_boolean_t
1118 update(dns_section_t section, dns_rdataclass_t rdclass) {
1119 if (section == DNS_SECTION_PREREQUISITE)
1120 return (ISC_TF(rdclass == dns_rdataclass_any ||
1121 rdclass == dns_rdataclass_none));
1122 if (section == DNS_SECTION_UPDATE)
1123 return (ISC_TF(rdclass == dns_rdataclass_any));
1124 return (ISC_FALSE);
1127 static isc_result_t
1128 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1129 dns_section_t sectionid, unsigned int options)
1131 isc_region_t r;
1132 unsigned int count, rdatalen;
1133 dns_name_t *name;
1134 dns_name_t *name2;
1135 dns_offsets_t *offsets;
1136 dns_rdataset_t *rdataset;
1137 dns_rdatalist_t *rdatalist;
1138 isc_result_t result;
1139 dns_rdatatype_t rdtype, covers;
1140 dns_rdataclass_t rdclass;
1141 dns_rdata_t *rdata;
1142 dns_ttl_t ttl;
1143 dns_namelist_t *section;
1144 isc_boolean_t free_name, free_rdataset;
1145 isc_boolean_t preserve_order, best_effort, seen_problem;
1146 isc_boolean_t issigzero;
1148 preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
1149 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1150 seen_problem = ISC_FALSE;
1152 for (count = 0; count < msg->counts[sectionid]; count++) {
1153 int recstart = source->current;
1154 isc_boolean_t skip_name_search, skip_type_search;
1156 section = &msg->sections[sectionid];
1158 skip_name_search = ISC_FALSE;
1159 skip_type_search = ISC_FALSE;
1160 free_name = ISC_FALSE;
1161 free_rdataset = ISC_FALSE;
1163 name = isc_mempool_get(msg->namepool);
1164 if (name == NULL)
1165 return (ISC_R_NOMEMORY);
1166 free_name = ISC_TRUE;
1168 offsets = newoffsets(msg);
1169 if (offsets == NULL) {
1170 result = ISC_R_NOMEMORY;
1171 goto cleanup;
1173 dns_name_init(name, *offsets);
1176 * Parse the name out of this packet.
1178 isc_buffer_remainingregion(source, &r);
1179 isc_buffer_setactive(source, r.length);
1180 result = getname(name, source, msg, dctx);
1181 if (result != ISC_R_SUCCESS)
1182 goto cleanup;
1185 * Get type, class, ttl, and rdatalen. Verify that at least
1186 * rdatalen bytes remain. (Some of this is deferred to
1187 * later.)
1189 isc_buffer_remainingregion(source, &r);
1190 if (r.length < 2 + 2 + 4 + 2) {
1191 result = ISC_R_UNEXPECTEDEND;
1192 goto cleanup;
1194 rdtype = isc_buffer_getuint16(source);
1195 rdclass = isc_buffer_getuint16(source);
1198 * If there was no question section, we may not yet have
1199 * established a class. Do so now.
1201 if (msg->state == DNS_SECTION_ANY &&
1202 rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
1203 rdtype != dns_rdatatype_tsig && /* class is ANY */
1204 rdtype != dns_rdatatype_tkey) { /* class is undefined */
1205 msg->rdclass = rdclass;
1206 msg->state = DNS_SECTION_QUESTION;
1210 * If this class is different than the one in the question
1211 * section, bail.
1213 if (msg->opcode != dns_opcode_update
1214 && rdtype != dns_rdatatype_tsig
1215 && rdtype != dns_rdatatype_opt
1216 && rdtype != dns_rdatatype_dnskey /* in a TKEY query */
1217 && rdtype != dns_rdatatype_sig /* SIG(0) */
1218 && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1219 && msg->rdclass != dns_rdataclass_any
1220 && msg->rdclass != rdclass)
1221 DO_FORMERR;
1224 * Special type handling for TSIG, OPT, and TKEY.
1226 if (rdtype == dns_rdatatype_tsig) {
1228 * If it is a tsig, verify that it is in the
1229 * additional data section.
1231 if (sectionid != DNS_SECTION_ADDITIONAL ||
1232 rdclass != dns_rdataclass_any ||
1233 count != msg->counts[sectionid] - 1)
1234 DO_FORMERR;
1235 msg->sigstart = recstart;
1236 skip_name_search = ISC_TRUE;
1237 skip_type_search = ISC_TRUE;
1238 } else if (rdtype == dns_rdatatype_opt) {
1240 * The name of an OPT record must be ".", it
1241 * must be in the additional data section, and
1242 * it must be the first OPT we've seen.
1244 if (!dns_name_equal(dns_rootname, name) ||
1245 msg->opt != NULL)
1246 DO_FORMERR;
1247 skip_name_search = ISC_TRUE;
1248 skip_type_search = ISC_TRUE;
1249 } else if (rdtype == dns_rdatatype_tkey) {
1251 * A TKEY must be in the additional section if this
1252 * is a query, and the answer section if this is a
1253 * response. Unless it's a Win2000 client.
1255 * Its class is ignored.
1257 dns_section_t tkeysection;
1259 if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1260 tkeysection = DNS_SECTION_ADDITIONAL;
1261 else
1262 tkeysection = DNS_SECTION_ANSWER;
1263 if (sectionid != tkeysection &&
1264 sectionid != DNS_SECTION_ANSWER)
1265 DO_FORMERR;
1269 * ... now get ttl and rdatalen, and check buffer.
1271 ttl = isc_buffer_getuint32(source);
1272 rdatalen = isc_buffer_getuint16(source);
1273 r.length -= (2 + 2 + 4 + 2);
1274 if (r.length < rdatalen) {
1275 result = ISC_R_UNEXPECTEDEND;
1276 goto cleanup;
1280 * Read the rdata from the wire format. Interpret the
1281 * rdata according to its actual class, even if it had a
1282 * DynDNS meta-class in the packet (unless this is a TSIG).
1283 * Then put the meta-class back into the finished rdata.
1285 rdata = newrdata(msg);
1286 if (rdata == NULL) {
1287 result = ISC_R_NOMEMORY;
1288 goto cleanup;
1290 if (msg->opcode == dns_opcode_update &&
1291 update(sectionid, rdclass)) {
1292 if (rdatalen != 0) {
1293 result = DNS_R_FORMERR;
1294 goto cleanup;
1297 * When the rdata is empty, the data pointer is
1298 * never dereferenced, but it must still be non-NULL.
1299 * Casting 1 rather than "" avoids warnings about
1300 * discarding the const attribute of a string,
1301 * for compilers that would warn about such things.
1303 rdata->data = (unsigned char *)1;
1304 rdata->length = 0;
1305 rdata->rdclass = rdclass;
1306 rdata->type = rdtype;
1307 rdata->flags = DNS_RDATA_UPDATE;
1308 result = ISC_R_SUCCESS;
1309 } else
1310 result = getrdata(source, msg, dctx, rdclass,
1311 rdtype, rdatalen, rdata);
1312 if (result != ISC_R_SUCCESS)
1313 goto cleanup;
1314 rdata->rdclass = rdclass;
1315 issigzero = ISC_FALSE;
1316 if (rdtype == dns_rdatatype_rrsig &&
1317 rdata->flags == 0) {
1318 covers = dns_rdata_covers(rdata);
1319 if (covers == 0)
1320 DO_FORMERR;
1321 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1322 rdata->flags == 0) {
1323 covers = dns_rdata_covers(rdata);
1324 if (covers == 0) {
1325 if (sectionid != DNS_SECTION_ADDITIONAL ||
1326 count != msg->counts[sectionid] - 1)
1327 DO_FORMERR;
1328 msg->sigstart = recstart;
1329 skip_name_search = ISC_TRUE;
1330 skip_type_search = ISC_TRUE;
1331 issigzero = ISC_TRUE;
1333 } else
1334 covers = 0;
1337 * If we are doing a dynamic update or this is a meta-type,
1338 * don't bother searching for a name, just append this one
1339 * to the end of the message.
1341 if (preserve_order || msg->opcode == dns_opcode_update ||
1342 skip_name_search) {
1343 if (rdtype != dns_rdatatype_opt &&
1344 rdtype != dns_rdatatype_tsig &&
1345 !issigzero)
1347 ISC_LIST_APPEND(*section, name, link);
1348 free_name = ISC_FALSE;
1350 } else {
1352 * Run through the section, looking to see if this name
1353 * is already there. If it is found, put back the
1354 * allocated name since we no longer need it, and set
1355 * our name pointer to point to the name we found.
1357 result = findname(&name2, name, section);
1360 * If it is a new name, append to the section.
1362 if (result == ISC_R_SUCCESS) {
1363 isc_mempool_put(msg->namepool, name);
1364 name = name2;
1365 } else {
1366 ISC_LIST_APPEND(*section, name, link);
1368 free_name = ISC_FALSE;
1372 * Search name for the particular type and class.
1373 * Skip this stage if in update mode or this is a meta-type.
1375 if (preserve_order || msg->opcode == dns_opcode_update ||
1376 skip_type_search)
1377 result = ISC_R_NOTFOUND;
1378 else {
1380 * If this is a type that can only occur in
1381 * the question section, fail.
1383 if (dns_rdatatype_questiononly(rdtype))
1384 DO_FORMERR;
1386 rdataset = NULL;
1387 result = dns_message_find(name, rdclass, rdtype,
1388 covers, &rdataset);
1392 * If we found an rdataset that matches, we need to
1393 * append this rdata to that set. If we did not, we need
1394 * to create a new rdatalist, store the important bits there,
1395 * convert it to an rdataset, and link the latter to the name.
1396 * Yuck. When appending, make certain that the type isn't
1397 * a singleton type, such as SOA or CNAME.
1399 * Note that this check will be bypassed when preserving order,
1400 * the opcode is an update, or the type search is skipped.
1402 if (result == ISC_R_SUCCESS) {
1403 if (dns_rdatatype_issingleton(rdtype))
1404 DO_FORMERR;
1407 if (result == ISC_R_NOTFOUND) {
1408 rdataset = isc_mempool_get(msg->rdspool);
1409 if (rdataset == NULL) {
1410 result = ISC_R_NOMEMORY;
1411 goto cleanup;
1413 free_rdataset = ISC_TRUE;
1415 rdatalist = newrdatalist(msg);
1416 if (rdatalist == NULL) {
1417 result = ISC_R_NOMEMORY;
1418 goto cleanup;
1421 rdatalist->type = rdtype;
1422 rdatalist->covers = covers;
1423 rdatalist->rdclass = rdclass;
1424 rdatalist->ttl = ttl;
1425 ISC_LIST_INIT(rdatalist->rdata);
1427 dns_rdataset_init(rdataset);
1428 RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1429 rdataset)
1430 == ISC_R_SUCCESS);
1432 if (rdtype != dns_rdatatype_opt &&
1433 rdtype != dns_rdatatype_tsig &&
1434 !issigzero)
1436 ISC_LIST_APPEND(name->list, rdataset, link);
1437 free_rdataset = ISC_FALSE;
1442 * Minimize TTLs.
1444 * Section 5.2 of RFC 2181 says we should drop
1445 * nonauthoritative rrsets where the TTLs differ, but we
1446 * currently treat them the as if they were authoritative and
1447 * minimize them.
1449 if (ttl != rdataset->ttl) {
1450 rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1451 if (ttl < rdataset->ttl)
1452 rdataset->ttl = ttl;
1456 * XXXMLG Perform a totally ugly hack here to pull
1457 * the rdatalist out of the private field in the rdataset,
1458 * and append this rdata to the rdatalist's linked list
1459 * of rdata.
1461 rdatalist = (dns_rdatalist_t *)(rdataset->private1);
1463 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1466 * If this is an OPT record, remember it. Also, set
1467 * the extended rcode. Note that msg->opt will only be set
1468 * if best-effort parsing is enabled.
1470 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1471 dns_rcode_t ercode;
1473 msg->opt = rdataset;
1474 rdataset = NULL;
1475 free_rdataset = ISC_FALSE;
1476 ercode = (dns_rcode_t)
1477 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1478 >> 20);
1479 msg->rcode |= ercode;
1480 isc_mempool_put(msg->namepool, name);
1481 free_name = ISC_FALSE;
1485 * If this is an SIG(0) or TSIG record, remember it. Note
1486 * that msg->sig0 or msg->tsig will only be set if best-effort
1487 * parsing is enabled.
1489 if (issigzero && msg->sig0 == NULL) {
1490 msg->sig0 = rdataset;
1491 msg->sig0name = name;
1492 rdataset = NULL;
1493 free_rdataset = ISC_FALSE;
1494 free_name = ISC_FALSE;
1495 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1496 msg->tsig = rdataset;
1497 msg->tsigname = name;
1498 rdataset = NULL;
1499 free_rdataset = ISC_FALSE;
1500 free_name = ISC_FALSE;
1503 if (seen_problem) {
1504 if (free_name)
1505 isc_mempool_put(msg->namepool, name);
1506 if (free_rdataset)
1507 isc_mempool_put(msg->rdspool, rdataset);
1508 free_name = free_rdataset = ISC_FALSE;
1510 INSIST(free_name == ISC_FALSE);
1511 INSIST(free_rdataset == ISC_FALSE);
1514 if (seen_problem)
1515 return (DNS_R_RECOVERABLE);
1516 return (ISC_R_SUCCESS);
1518 cleanup:
1519 if (free_name)
1520 isc_mempool_put(msg->namepool, name);
1521 if (free_rdataset)
1522 isc_mempool_put(msg->rdspool, rdataset);
1524 return (result);
1527 isc_result_t
1528 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1529 unsigned int options)
1531 isc_region_t r;
1532 dns_decompress_t dctx;
1533 isc_result_t ret;
1534 isc_uint16_t tmpflags;
1535 isc_buffer_t origsource;
1536 isc_boolean_t seen_problem;
1537 isc_boolean_t ignore_tc;
1539 REQUIRE(DNS_MESSAGE_VALID(msg));
1540 REQUIRE(source != NULL);
1541 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1543 seen_problem = ISC_FALSE;
1544 ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1546 origsource = *source;
1548 msg->header_ok = 0;
1549 msg->question_ok = 0;
1551 isc_buffer_remainingregion(source, &r);
1552 if (r.length < DNS_MESSAGE_HEADERLEN)
1553 return (ISC_R_UNEXPECTEDEND);
1555 msg->id = isc_buffer_getuint16(source);
1556 tmpflags = isc_buffer_getuint16(source);
1557 msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1558 >> DNS_MESSAGE_OPCODE_SHIFT);
1559 msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1560 msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1561 msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1562 msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1563 msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1564 msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1566 msg->header_ok = 1;
1569 * -1 means no EDNS.
1571 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1573 dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1575 ret = getquestions(source, msg, &dctx, options);
1576 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1577 goto truncated;
1578 if (ret == DNS_R_RECOVERABLE) {
1579 seen_problem = ISC_TRUE;
1580 ret = ISC_R_SUCCESS;
1582 if (ret != ISC_R_SUCCESS)
1583 return (ret);
1584 msg->question_ok = 1;
1586 ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1587 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1588 goto truncated;
1589 if (ret == DNS_R_RECOVERABLE) {
1590 seen_problem = ISC_TRUE;
1591 ret = ISC_R_SUCCESS;
1593 if (ret != ISC_R_SUCCESS)
1594 return (ret);
1596 ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1597 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1598 goto truncated;
1599 if (ret == DNS_R_RECOVERABLE) {
1600 seen_problem = ISC_TRUE;
1601 ret = ISC_R_SUCCESS;
1603 if (ret != ISC_R_SUCCESS)
1604 return (ret);
1606 ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1607 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1608 goto truncated;
1609 if (ret == DNS_R_RECOVERABLE) {
1610 seen_problem = ISC_TRUE;
1611 ret = ISC_R_SUCCESS;
1613 if (ret != ISC_R_SUCCESS)
1614 return (ret);
1616 isc_buffer_remainingregion(source, &r);
1617 if (r.length != 0) {
1618 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1619 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1620 "message has %u byte(s) of trailing garbage",
1621 r.length);
1624 truncated:
1625 if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1626 isc_buffer_usedregion(&origsource, &msg->saved);
1627 else {
1628 msg->saved.length = isc_buffer_usedlength(&origsource);
1629 msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1630 if (msg->saved.base == NULL)
1631 return (ISC_R_NOMEMORY);
1632 memcpy(msg->saved.base, isc_buffer_base(&origsource),
1633 msg->saved.length);
1634 msg->free_saved = 1;
1637 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1638 return (DNS_R_RECOVERABLE);
1639 if (seen_problem == ISC_TRUE)
1640 return (DNS_R_RECOVERABLE);
1641 return (ISC_R_SUCCESS);
1644 isc_result_t
1645 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1646 isc_buffer_t *buffer)
1648 isc_region_t r;
1650 REQUIRE(DNS_MESSAGE_VALID(msg));
1651 REQUIRE(buffer != NULL);
1652 REQUIRE(msg->buffer == NULL);
1653 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1655 msg->cctx = cctx;
1658 * Erase the contents of this buffer.
1660 isc_buffer_clear(buffer);
1663 * Make certain there is enough for at least the header in this
1664 * buffer.
1666 isc_buffer_availableregion(buffer, &r);
1667 if (r.length < DNS_MESSAGE_HEADERLEN)
1668 return (ISC_R_NOSPACE);
1670 if (r.length < msg->reserved)
1671 return (ISC_R_NOSPACE);
1674 * Reserve enough space for the header in this buffer.
1676 isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1678 msg->buffer = buffer;
1680 return (ISC_R_SUCCESS);
1683 isc_result_t
1684 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1685 isc_region_t r, rn;
1687 REQUIRE(DNS_MESSAGE_VALID(msg));
1688 REQUIRE(buffer != NULL);
1689 REQUIRE(msg->buffer != NULL);
1692 * Ensure that the new buffer is empty, and has enough space to
1693 * hold the current contents.
1695 isc_buffer_clear(buffer);
1697 isc_buffer_availableregion(buffer, &rn);
1698 isc_buffer_usedregion(msg->buffer, &r);
1699 REQUIRE(rn.length > r.length);
1702 * Copy the contents from the old to the new buffer.
1704 isc_buffer_add(buffer, r.length);
1705 memcpy(rn.base, r.base, r.length);
1707 msg->buffer = buffer;
1709 return (ISC_R_SUCCESS);
1712 void
1713 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1714 REQUIRE(DNS_MESSAGE_VALID(msg));
1715 REQUIRE(space <= msg->reserved);
1717 msg->reserved -= space;
1720 isc_result_t
1721 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1722 isc_region_t r;
1724 REQUIRE(DNS_MESSAGE_VALID(msg));
1726 if (msg->buffer != NULL) {
1727 isc_buffer_availableregion(msg->buffer, &r);
1728 if (r.length < (space + msg->reserved))
1729 return (ISC_R_NOSPACE);
1732 msg->reserved += space;
1734 return (ISC_R_SUCCESS);
1737 static inline isc_boolean_t
1738 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1739 int pass_needed;
1742 * If we are not rendering class IN, this ordering is bogus.
1744 if (rds->rdclass != dns_rdataclass_in)
1745 return (ISC_FALSE);
1747 switch (rds->type) {
1748 case dns_rdatatype_a:
1749 case dns_rdatatype_aaaa:
1750 if (preferred_glue == rds->type)
1751 pass_needed = 4;
1752 else
1753 pass_needed = 3;
1754 break;
1755 case dns_rdatatype_rrsig:
1756 case dns_rdatatype_dnskey:
1757 pass_needed = 2;
1758 break;
1759 default:
1760 pass_needed = 1;
1763 if (pass_needed >= pass)
1764 return (ISC_FALSE);
1766 return (ISC_TRUE);
1769 isc_result_t
1770 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1771 unsigned int options)
1773 dns_namelist_t *section;
1774 dns_name_t *name, *next_name;
1775 dns_rdataset_t *rdataset, *next_rdataset;
1776 unsigned int count, total;
1777 isc_result_t result;
1778 isc_buffer_t st; /* for rollbacks */
1779 int pass;
1780 isc_boolean_t partial = ISC_FALSE;
1781 unsigned int rd_options;
1782 dns_rdatatype_t preferred_glue = 0;
1784 REQUIRE(DNS_MESSAGE_VALID(msg));
1785 REQUIRE(msg->buffer != NULL);
1786 REQUIRE(VALID_NAMED_SECTION(sectionid));
1788 section = &msg->sections[sectionid];
1790 if ((sectionid == DNS_SECTION_ADDITIONAL)
1791 && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1792 if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1793 preferred_glue = dns_rdatatype_a;
1794 pass = 4;
1795 } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1796 preferred_glue = dns_rdatatype_aaaa;
1797 pass = 4;
1798 } else
1799 pass = 3;
1800 } else
1801 pass = 1;
1803 if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1804 rd_options = 0;
1805 else
1806 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1809 * Shrink the space in the buffer by the reserved amount.
1811 msg->buffer->length -= msg->reserved;
1813 total = 0;
1814 if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1815 partial = ISC_TRUE;
1818 * Render required glue first. Set TC if it won't fit.
1820 name = ISC_LIST_HEAD(*section);
1821 if (name != NULL) {
1822 rdataset = ISC_LIST_HEAD(name->list);
1823 if (rdataset != NULL &&
1824 (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
1825 (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
1826 const void *order_arg = msg->order_arg;
1827 st = *(msg->buffer);
1828 count = 0;
1829 if (partial)
1830 result = dns_rdataset_towirepartial(rdataset,
1831 name,
1832 msg->cctx,
1833 msg->buffer,
1834 msg->order,
1835 order_arg,
1836 rd_options,
1837 &count,
1838 NULL);
1839 else
1840 result = dns_rdataset_towiresorted(rdataset,
1841 name,
1842 msg->cctx,
1843 msg->buffer,
1844 msg->order,
1845 order_arg,
1846 rd_options,
1847 &count);
1848 total += count;
1849 if (partial && result == ISC_R_NOSPACE) {
1850 msg->flags |= DNS_MESSAGEFLAG_TC;
1851 msg->buffer->length += msg->reserved;
1852 msg->counts[sectionid] += total;
1853 return (result);
1855 if (result != ISC_R_SUCCESS) {
1856 INSIST(st.used < 65536);
1857 dns_compress_rollback(msg->cctx,
1858 (isc_uint16_t)st.used);
1859 *(msg->buffer) = st; /* rollback */
1860 msg->buffer->length += msg->reserved;
1861 msg->counts[sectionid] += total;
1862 return (result);
1864 rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
1868 do {
1869 name = ISC_LIST_HEAD(*section);
1870 if (name == NULL) {
1871 msg->buffer->length += msg->reserved;
1872 msg->counts[sectionid] += total;
1873 return (ISC_R_SUCCESS);
1876 while (name != NULL) {
1877 next_name = ISC_LIST_NEXT(name, link);
1879 rdataset = ISC_LIST_HEAD(name->list);
1880 while (rdataset != NULL) {
1881 next_rdataset = ISC_LIST_NEXT(rdataset, link);
1883 if ((rdataset->attributes &
1884 DNS_RDATASETATTR_RENDERED) != 0)
1885 goto next;
1887 if (((options & DNS_MESSAGERENDER_ORDERED)
1888 == 0)
1889 && (sectionid == DNS_SECTION_ADDITIONAL)
1890 && wrong_priority(rdataset, pass,
1891 preferred_glue))
1892 goto next;
1894 st = *(msg->buffer);
1896 count = 0;
1897 if (partial)
1898 result = dns_rdataset_towirepartial(
1899 rdataset,
1900 name,
1901 msg->cctx,
1902 msg->buffer,
1903 msg->order,
1904 msg->order_arg,
1905 rd_options,
1906 &count,
1907 NULL);
1908 else
1909 result = dns_rdataset_towiresorted(
1910 rdataset,
1911 name,
1912 msg->cctx,
1913 msg->buffer,
1914 msg->order,
1915 msg->order_arg,
1916 rd_options,
1917 &count);
1919 total += count;
1922 * If out of space, record stats on what we
1923 * rendered so far, and return that status.
1925 * XXXMLG Need to change this when
1926 * dns_rdataset_towire() can render partial
1927 * sets starting at some arbitary point in the
1928 * set. This will include setting a bit in the
1929 * rdataset to indicate that a partial
1930 * rendering was done, and some state saved
1931 * somewhere (probably in the message struct)
1932 * to indicate where to continue from.
1934 if (partial && result == ISC_R_NOSPACE) {
1935 msg->buffer->length += msg->reserved;
1936 msg->counts[sectionid] += total;
1937 return (result);
1939 if (result != ISC_R_SUCCESS) {
1940 INSIST(st.used < 65536);
1941 dns_compress_rollback(msg->cctx,
1942 (isc_uint16_t)st.used);
1943 *(msg->buffer) = st; /* rollback */
1944 msg->buffer->length += msg->reserved;
1945 msg->counts[sectionid] += total;
1946 return (result);
1950 * If we have rendered non-validated data,
1951 * ensure that the AD bit is not set.
1953 if (rdataset->trust != dns_trust_secure &&
1954 (sectionid == DNS_SECTION_ANSWER ||
1955 sectionid == DNS_SECTION_AUTHORITY))
1956 msg->flags &= ~DNS_MESSAGEFLAG_AD;
1958 rdataset->attributes |=
1959 DNS_RDATASETATTR_RENDERED;
1961 next:
1962 rdataset = next_rdataset;
1965 name = next_name;
1967 } while (--pass != 0);
1969 msg->buffer->length += msg->reserved;
1970 msg->counts[sectionid] += total;
1972 return (ISC_R_SUCCESS);
1975 void
1976 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
1977 isc_uint16_t tmp;
1978 isc_region_t r;
1980 REQUIRE(DNS_MESSAGE_VALID(msg));
1981 REQUIRE(target != NULL);
1983 isc_buffer_availableregion(target, &r);
1984 REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
1986 isc_buffer_putuint16(target, msg->id);
1988 tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
1989 & DNS_MESSAGE_OPCODE_MASK);
1990 tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
1991 tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
1993 INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
1994 msg->counts[DNS_SECTION_ANSWER] < 65536 &&
1995 msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
1996 msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
1998 isc_buffer_putuint16(target, tmp);
1999 isc_buffer_putuint16(target,
2000 (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2001 isc_buffer_putuint16(target,
2002 (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2003 isc_buffer_putuint16(target,
2004 (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2005 isc_buffer_putuint16(target,
2006 (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2009 isc_result_t
2010 dns_message_renderend(dns_message_t *msg) {
2011 isc_buffer_t tmpbuf;
2012 isc_region_t r;
2013 int result;
2014 unsigned int count;
2016 REQUIRE(DNS_MESSAGE_VALID(msg));
2017 REQUIRE(msg->buffer != NULL);
2019 if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2021 * We have an extended rcode but are not using EDNS.
2023 return (DNS_R_FORMERR);
2027 * If we've got an OPT record, render it.
2029 if (msg->opt != NULL) {
2030 dns_message_renderrelease(msg, msg->opt_reserved);
2031 msg->opt_reserved = 0;
2033 * Set the extended rcode.
2035 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2036 msg->opt->ttl |= ((msg->rcode << 20) &
2037 DNS_MESSAGE_EDNSRCODE_MASK);
2039 * Render.
2041 count = 0;
2042 result = dns_rdataset_towire(msg->opt, dns_rootname,
2043 msg->cctx, msg->buffer, 0,
2044 &count);
2045 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2046 if (result != ISC_R_SUCCESS)
2047 return (result);
2051 * If we're adding a TSIG or SIG(0) to a truncated message,
2052 * clear all rdatasets from the message except for the question
2053 * before adding the TSIG or SIG(0). If the question doesn't fit,
2054 * don't include it.
2056 if ((msg->tsigkey != NULL || msg->sig0key != NULL) &&
2057 (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2059 isc_buffer_t *buf;
2061 msgresetnames(msg, DNS_SECTION_ANSWER);
2062 buf = msg->buffer;
2063 dns_message_renderreset(msg);
2064 msg->buffer = buf;
2065 isc_buffer_clear(msg->buffer);
2066 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2067 dns_compress_rollback(msg->cctx, 0);
2068 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2070 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2071 return (result);
2075 * If we're adding a TSIG record, generate and render it.
2077 if (msg->tsigkey != NULL) {
2078 dns_message_renderrelease(msg, msg->sig_reserved);
2079 msg->sig_reserved = 0;
2080 result = dns_tsig_sign(msg);
2081 if (result != ISC_R_SUCCESS)
2082 return (result);
2083 count = 0;
2084 result = dns_rdataset_towire(msg->tsig, msg->tsigname,
2085 msg->cctx, msg->buffer, 0,
2086 &count);
2087 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2088 if (result != ISC_R_SUCCESS)
2089 return (result);
2093 * If we're adding a SIG(0) record, generate and render it.
2095 if (msg->sig0key != NULL) {
2096 dns_message_renderrelease(msg, msg->sig_reserved);
2097 msg->sig_reserved = 0;
2098 result = dns_dnssec_signmessage(msg, msg->sig0key);
2099 if (result != ISC_R_SUCCESS)
2100 return (result);
2101 count = 0;
2103 * Note: dns_rootname is used here, not msg->sig0name, since
2104 * the owner name of a SIG(0) is irrelevant, and will not
2105 * be set in a message being rendered.
2107 result = dns_rdataset_towire(msg->sig0, dns_rootname,
2108 msg->cctx, msg->buffer, 0,
2109 &count);
2110 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2111 if (result != ISC_R_SUCCESS)
2112 return (result);
2115 isc_buffer_usedregion(msg->buffer, &r);
2116 isc_buffer_init(&tmpbuf, r.base, r.length);
2118 dns_message_renderheader(msg, &tmpbuf);
2120 msg->buffer = NULL; /* forget about this buffer only on success XXX */
2122 return (ISC_R_SUCCESS);
2125 void
2126 dns_message_renderreset(dns_message_t *msg) {
2127 unsigned int i;
2128 dns_name_t *name;
2129 dns_rdataset_t *rds;
2132 * Reset the message so that it may be rendered again.
2135 REQUIRE(DNS_MESSAGE_VALID(msg));
2136 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2138 msg->buffer = NULL;
2140 for (i = 0; i < DNS_SECTION_MAX; i++) {
2141 msg->cursors[i] = NULL;
2142 msg->counts[i] = 0;
2143 for (name = ISC_LIST_HEAD(msg->sections[i]);
2144 name != NULL;
2145 name = ISC_LIST_NEXT(name, link)) {
2146 for (rds = ISC_LIST_HEAD(name->list);
2147 rds != NULL;
2148 rds = ISC_LIST_NEXT(rds, link)) {
2149 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2153 if (msg->tsigname != NULL)
2154 dns_message_puttempname(msg, &msg->tsigname);
2155 if (msg->tsig != NULL) {
2156 dns_rdataset_disassociate(msg->tsig);
2157 dns_message_puttemprdataset(msg, &msg->tsig);
2159 if (msg->sig0 != NULL) {
2160 dns_rdataset_disassociate(msg->sig0);
2161 dns_message_puttemprdataset(msg, &msg->sig0);
2165 isc_result_t
2166 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2167 REQUIRE(DNS_MESSAGE_VALID(msg));
2168 REQUIRE(VALID_NAMED_SECTION(section));
2170 msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2172 if (msg->cursors[section] == NULL)
2173 return (ISC_R_NOMORE);
2175 return (ISC_R_SUCCESS);
2178 isc_result_t
2179 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2180 REQUIRE(DNS_MESSAGE_VALID(msg));
2181 REQUIRE(VALID_NAMED_SECTION(section));
2182 REQUIRE(msg->cursors[section] != NULL);
2184 msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2186 if (msg->cursors[section] == NULL)
2187 return (ISC_R_NOMORE);
2189 return (ISC_R_SUCCESS);
2192 void
2193 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2194 dns_name_t **name)
2196 REQUIRE(DNS_MESSAGE_VALID(msg));
2197 REQUIRE(VALID_NAMED_SECTION(section));
2198 REQUIRE(name != NULL && *name == NULL);
2199 REQUIRE(msg->cursors[section] != NULL);
2201 *name = msg->cursors[section];
2204 isc_result_t
2205 dns_message_findname(dns_message_t *msg, dns_section_t section,
2206 dns_name_t *target, dns_rdatatype_t type,
2207 dns_rdatatype_t covers, dns_name_t **name,
2208 dns_rdataset_t **rdataset)
2210 dns_name_t *foundname;
2211 isc_result_t result;
2214 * XXX These requirements are probably too intensive, especially
2215 * where things can be NULL, but as they are they ensure that if
2216 * something is NON-NULL, indicating that the caller expects it
2217 * to be filled in, that we can in fact fill it in.
2219 REQUIRE(msg != NULL);
2220 REQUIRE(VALID_SECTION(section));
2221 REQUIRE(target != NULL);
2222 if (name != NULL)
2223 REQUIRE(*name == NULL);
2224 if (type == dns_rdatatype_any) {
2225 REQUIRE(rdataset == NULL);
2226 } else {
2227 if (rdataset != NULL)
2228 REQUIRE(*rdataset == NULL);
2231 result = findname(&foundname, target,
2232 &msg->sections[section]);
2234 if (result == ISC_R_NOTFOUND)
2235 return (DNS_R_NXDOMAIN);
2236 else if (result != ISC_R_SUCCESS)
2237 return (result);
2239 if (name != NULL)
2240 *name = foundname;
2243 * And now look for the type.
2245 if (type == dns_rdatatype_any)
2246 return (ISC_R_SUCCESS);
2248 result = dns_message_findtype(foundname, type, covers, rdataset);
2249 if (result == ISC_R_NOTFOUND)
2250 return (DNS_R_NXRRSET);
2252 return (result);
2255 void
2256 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2257 dns_section_t fromsection,
2258 dns_section_t tosection)
2260 REQUIRE(msg != NULL);
2261 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2262 REQUIRE(name != NULL);
2263 REQUIRE(VALID_NAMED_SECTION(fromsection));
2264 REQUIRE(VALID_NAMED_SECTION(tosection));
2267 * Unlink the name from the old section
2269 ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2270 ISC_LIST_APPEND(msg->sections[tosection], name, link);
2273 void
2274 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2275 dns_section_t section)
2277 REQUIRE(msg != NULL);
2278 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2279 REQUIRE(name != NULL);
2280 REQUIRE(VALID_NAMED_SECTION(section));
2282 ISC_LIST_APPEND(msg->sections[section], name, link);
2285 isc_result_t
2286 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2287 REQUIRE(DNS_MESSAGE_VALID(msg));
2288 REQUIRE(item != NULL && *item == NULL);
2290 *item = isc_mempool_get(msg->namepool);
2291 if (*item == NULL)
2292 return (ISC_R_NOMEMORY);
2293 dns_name_init(*item, NULL);
2295 return (ISC_R_SUCCESS);
2298 isc_result_t
2299 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2300 REQUIRE(DNS_MESSAGE_VALID(msg));
2301 REQUIRE(item != NULL && *item == NULL);
2303 *item = newoffsets(msg);
2304 if (*item == NULL)
2305 return (ISC_R_NOMEMORY);
2307 return (ISC_R_SUCCESS);
2310 isc_result_t
2311 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2312 REQUIRE(DNS_MESSAGE_VALID(msg));
2313 REQUIRE(item != NULL && *item == NULL);
2315 *item = newrdata(msg);
2316 if (*item == NULL)
2317 return (ISC_R_NOMEMORY);
2319 return (ISC_R_SUCCESS);
2322 isc_result_t
2323 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2324 REQUIRE(DNS_MESSAGE_VALID(msg));
2325 REQUIRE(item != NULL && *item == NULL);
2327 *item = isc_mempool_get(msg->rdspool);
2328 if (*item == NULL)
2329 return (ISC_R_NOMEMORY);
2331 dns_rdataset_init(*item);
2333 return (ISC_R_SUCCESS);
2336 isc_result_t
2337 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2338 REQUIRE(DNS_MESSAGE_VALID(msg));
2339 REQUIRE(item != NULL && *item == NULL);
2341 *item = newrdatalist(msg);
2342 if (*item == NULL)
2343 return (ISC_R_NOMEMORY);
2345 return (ISC_R_SUCCESS);
2348 void
2349 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2350 REQUIRE(DNS_MESSAGE_VALID(msg));
2351 REQUIRE(item != NULL && *item != NULL);
2353 if (dns_name_dynamic(*item))
2354 dns_name_free(*item, msg->mctx);
2355 isc_mempool_put(msg->namepool, *item);
2356 *item = NULL;
2359 void
2360 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2361 REQUIRE(DNS_MESSAGE_VALID(msg));
2362 REQUIRE(item != NULL && *item != NULL);
2364 releaserdata(msg, *item);
2365 *item = NULL;
2368 void
2369 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2370 REQUIRE(DNS_MESSAGE_VALID(msg));
2371 REQUIRE(item != NULL && *item != NULL);
2373 REQUIRE(!dns_rdataset_isassociated(*item));
2374 isc_mempool_put(msg->rdspool, *item);
2375 *item = NULL;
2378 void
2379 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2380 REQUIRE(DNS_MESSAGE_VALID(msg));
2381 REQUIRE(item != NULL && *item != NULL);
2383 releaserdatalist(msg, *item);
2384 *item = NULL;
2387 isc_result_t
2388 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2389 unsigned int *flagsp)
2391 isc_region_t r;
2392 isc_buffer_t buffer;
2393 dns_messageid_t id;
2394 unsigned int flags;
2396 REQUIRE(source != NULL);
2398 buffer = *source;
2400 isc_buffer_remainingregion(&buffer, &r);
2401 if (r.length < DNS_MESSAGE_HEADERLEN)
2402 return (ISC_R_UNEXPECTEDEND);
2404 id = isc_buffer_getuint16(&buffer);
2405 flags = isc_buffer_getuint16(&buffer);
2406 flags &= DNS_MESSAGE_FLAG_MASK;
2408 if (flagsp != NULL)
2409 *flagsp = flags;
2410 if (idp != NULL)
2411 *idp = id;
2413 return (ISC_R_SUCCESS);
2416 isc_result_t
2417 dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
2418 unsigned int first_section;
2419 isc_result_t result;
2421 REQUIRE(DNS_MESSAGE_VALID(msg));
2422 REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2424 if (!msg->header_ok)
2425 return (DNS_R_FORMERR);
2426 if (msg->opcode != dns_opcode_query &&
2427 msg->opcode != dns_opcode_notify)
2428 want_question_section = ISC_FALSE;
2429 if (want_question_section) {
2430 if (!msg->question_ok)
2431 return (DNS_R_FORMERR);
2432 first_section = DNS_SECTION_ANSWER;
2433 } else
2434 first_section = DNS_SECTION_QUESTION;
2435 msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2436 msgresetnames(msg, first_section);
2437 msgresetopt(msg);
2438 msgresetsigs(msg, ISC_TRUE);
2439 msginitprivate(msg);
2441 * We now clear most flags and then set QR, ensuring that the
2442 * reply's flags will be in a reasonable state.
2444 msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2445 msg->flags |= DNS_MESSAGEFLAG_QR;
2448 * This saves the query TSIG status, if the query was signed, and
2449 * reserves space in the reply for the TSIG.
2451 if (msg->tsigkey != NULL) {
2452 unsigned int otherlen = 0;
2453 msg->querytsigstatus = msg->tsigstatus;
2454 msg->tsigstatus = dns_rcode_noerror;
2455 if (msg->querytsigstatus == dns_tsigerror_badtime)
2456 otherlen = 6;
2457 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2458 result = dns_message_renderreserve(msg, msg->sig_reserved);
2459 if (result != ISC_R_SUCCESS) {
2460 msg->sig_reserved = 0;
2461 return (result);
2464 if (msg->saved.base != NULL) {
2465 msg->query.base = msg->saved.base;
2466 msg->query.length = msg->saved.length;
2467 msg->free_query = msg->free_saved;
2468 msg->saved.base = NULL;
2469 msg->saved.length = 0;
2470 msg->free_saved = 0;
2473 return (ISC_R_SUCCESS);
2476 dns_rdataset_t *
2477 dns_message_getopt(dns_message_t *msg) {
2480 * Get the OPT record for 'msg'.
2483 REQUIRE(DNS_MESSAGE_VALID(msg));
2485 return (msg->opt);
2488 isc_result_t
2489 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2490 isc_result_t result;
2491 dns_rdata_t rdata = DNS_RDATA_INIT;
2494 * Set the OPT record for 'msg'.
2498 * The space required for an OPT record is:
2500 * 1 byte for the name
2501 * 2 bytes for the type
2502 * 2 bytes for the class
2503 * 4 bytes for the ttl
2504 * 2 bytes for the rdata length
2505 * ---------------------------------
2506 * 11 bytes
2508 * plus the length of the rdata.
2511 REQUIRE(DNS_MESSAGE_VALID(msg));
2512 REQUIRE(opt->type == dns_rdatatype_opt);
2513 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2514 REQUIRE(msg->state == DNS_SECTION_ANY);
2516 msgresetopt(msg);
2518 result = dns_rdataset_first(opt);
2519 if (result != ISC_R_SUCCESS)
2520 goto cleanup;
2521 dns_rdataset_current(opt, &rdata);
2522 msg->opt_reserved = 11 + rdata.length;
2523 result = dns_message_renderreserve(msg, msg->opt_reserved);
2524 if (result != ISC_R_SUCCESS) {
2525 msg->opt_reserved = 0;
2526 goto cleanup;
2529 msg->opt = opt;
2531 return (ISC_R_SUCCESS);
2533 cleanup:
2534 dns_message_puttemprdataset(msg, &opt);
2535 return (result);
2539 dns_rdataset_t *
2540 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2543 * Get the TSIG record and owner for 'msg'.
2546 REQUIRE(DNS_MESSAGE_VALID(msg));
2547 REQUIRE(owner == NULL || *owner == NULL);
2549 if (owner != NULL)
2550 *owner = msg->tsigname;
2551 return (msg->tsig);
2554 isc_result_t
2555 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2556 isc_result_t result;
2559 * Set the TSIG key for 'msg'
2562 REQUIRE(DNS_MESSAGE_VALID(msg));
2563 REQUIRE(msg->state == DNS_SECTION_ANY);
2565 if (key == NULL && msg->tsigkey != NULL) {
2566 if (msg->sig_reserved != 0) {
2567 dns_message_renderrelease(msg, msg->sig_reserved);
2568 msg->sig_reserved = 0;
2570 dns_tsigkey_detach(&msg->tsigkey);
2572 if (key != NULL) {
2573 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2574 dns_tsigkey_attach(key, &msg->tsigkey);
2575 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2576 msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2577 result = dns_message_renderreserve(msg,
2578 msg->sig_reserved);
2579 if (result != ISC_R_SUCCESS) {
2580 dns_tsigkey_detach(&msg->tsigkey);
2581 msg->sig_reserved = 0;
2582 return (result);
2586 return (ISC_R_SUCCESS);
2589 dns_tsigkey_t *
2590 dns_message_gettsigkey(dns_message_t *msg) {
2593 * Get the TSIG key for 'msg'
2596 REQUIRE(DNS_MESSAGE_VALID(msg));
2598 return (msg->tsigkey);
2601 isc_result_t
2602 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2603 dns_rdata_t *rdata = NULL;
2604 dns_rdatalist_t *list = NULL;
2605 dns_rdataset_t *set = NULL;
2606 isc_buffer_t *buf = NULL;
2607 isc_region_t r;
2608 isc_result_t result;
2610 REQUIRE(DNS_MESSAGE_VALID(msg));
2611 REQUIRE(msg->querytsig == NULL);
2613 if (querytsig == NULL)
2614 return (ISC_R_SUCCESS);
2616 result = dns_message_gettemprdata(msg, &rdata);
2617 if (result != ISC_R_SUCCESS)
2618 goto cleanup;
2620 result = dns_message_gettemprdatalist(msg, &list);
2621 if (result != ISC_R_SUCCESS)
2622 goto cleanup;
2623 result = dns_message_gettemprdataset(msg, &set);
2624 if (result != ISC_R_SUCCESS)
2625 goto cleanup;
2627 isc_buffer_usedregion(querytsig, &r);
2628 result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2629 if (result != ISC_R_SUCCESS)
2630 goto cleanup;
2631 isc_buffer_putmem(buf, r.base, r.length);
2632 isc_buffer_usedregion(buf, &r);
2633 dns_rdata_init(rdata);
2634 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2635 dns_message_takebuffer(msg, &buf);
2636 ISC_LIST_INIT(list->rdata);
2637 ISC_LIST_APPEND(list->rdata, rdata, link);
2638 result = dns_rdatalist_tordataset(list, set);
2639 if (result != ISC_R_SUCCESS)
2640 goto cleanup;
2642 msg->querytsig = set;
2644 return (result);
2646 cleanup:
2647 if (rdata != NULL)
2648 dns_message_puttemprdata(msg, &rdata);
2649 if (list != NULL)
2650 dns_message_puttemprdatalist(msg, &list);
2651 if (set != NULL)
2652 dns_message_puttemprdataset(msg, &set);
2653 return (ISC_R_NOMEMORY);
2656 isc_result_t
2657 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2658 isc_buffer_t **querytsig) {
2659 isc_result_t result;
2660 dns_rdata_t rdata = DNS_RDATA_INIT;
2661 isc_region_t r;
2663 REQUIRE(DNS_MESSAGE_VALID(msg));
2664 REQUIRE(mctx != NULL);
2665 REQUIRE(querytsig != NULL && *querytsig == NULL);
2667 if (msg->tsig == NULL)
2668 return (ISC_R_SUCCESS);
2670 result = dns_rdataset_first(msg->tsig);
2671 if (result != ISC_R_SUCCESS)
2672 return (result);
2673 dns_rdataset_current(msg->tsig, &rdata);
2674 dns_rdata_toregion(&rdata, &r);
2676 result = isc_buffer_allocate(mctx, querytsig, r.length);
2677 if (result != ISC_R_SUCCESS)
2678 return (result);
2679 isc_buffer_putmem(*querytsig, r.base, r.length);
2680 return (ISC_R_SUCCESS);
2683 dns_rdataset_t *
2684 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2687 * Get the SIG(0) record for 'msg'.
2690 REQUIRE(DNS_MESSAGE_VALID(msg));
2691 REQUIRE(owner == NULL || *owner == NULL);
2693 if (msg->sig0 != NULL && owner != NULL) {
2694 /* If dns_message_getsig0 is called on a rendered message
2695 * after the SIG(0) has been applied, we need to return the
2696 * root name, not NULL.
2698 if (msg->sig0name == NULL)
2699 *owner = dns_rootname;
2700 else
2701 *owner = msg->sig0name;
2703 return (msg->sig0);
2706 isc_result_t
2707 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2708 isc_region_t r;
2709 unsigned int x;
2710 isc_result_t result;
2713 * Set the SIG(0) key for 'msg'
2717 * The space required for an SIG(0) record is:
2719 * 1 byte for the name
2720 * 2 bytes for the type
2721 * 2 bytes for the class
2722 * 4 bytes for the ttl
2723 * 2 bytes for the type covered
2724 * 1 byte for the algorithm
2725 * 1 bytes for the labels
2726 * 4 bytes for the original ttl
2727 * 4 bytes for the signature expiration
2728 * 4 bytes for the signature inception
2729 * 2 bytes for the key tag
2730 * n bytes for the signer's name
2731 * x bytes for the signature
2732 * ---------------------------------
2733 * 27 + n + x bytes
2735 REQUIRE(DNS_MESSAGE_VALID(msg));
2736 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2737 REQUIRE(msg->state == DNS_SECTION_ANY);
2739 if (key != NULL) {
2740 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2741 dns_name_toregion(dst_key_name(key), &r);
2742 result = dst_key_sigsize(key, &x);
2743 if (result != ISC_R_SUCCESS) {
2744 msg->sig_reserved = 0;
2745 return (result);
2747 msg->sig_reserved = 27 + r.length + x;
2748 result = dns_message_renderreserve(msg, msg->sig_reserved);
2749 if (result != ISC_R_SUCCESS) {
2750 msg->sig_reserved = 0;
2751 return (result);
2753 msg->sig0key = key;
2755 return (ISC_R_SUCCESS);
2758 dst_key_t *
2759 dns_message_getsig0key(dns_message_t *msg) {
2762 * Get the SIG(0) key for 'msg'
2765 REQUIRE(DNS_MESSAGE_VALID(msg));
2767 return (msg->sig0key);
2770 void
2771 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2772 REQUIRE(DNS_MESSAGE_VALID(msg));
2773 REQUIRE(buffer != NULL);
2774 REQUIRE(ISC_BUFFER_VALID(*buffer));
2776 ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2777 *buffer = NULL;
2780 isc_result_t
2781 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
2782 isc_result_t result = ISC_R_SUCCESS;
2783 dns_rdata_t rdata = DNS_RDATA_INIT;
2785 REQUIRE(DNS_MESSAGE_VALID(msg));
2786 REQUIRE(signer != NULL);
2787 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2789 if (msg->tsig == NULL && msg->sig0 == NULL)
2790 return (ISC_R_NOTFOUND);
2792 if (msg->verify_attempted == 0)
2793 return (DNS_R_NOTVERIFIEDYET);
2795 if (!dns_name_hasbuffer(signer)) {
2796 isc_buffer_t *dynbuf = NULL;
2797 result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
2798 if (result != ISC_R_SUCCESS)
2799 return (result);
2800 dns_name_setbuffer(signer, dynbuf);
2801 dns_message_takebuffer(msg, &dynbuf);
2804 if (msg->sig0 != NULL) {
2805 dns_rdata_sig_t sig;
2807 result = dns_rdataset_first(msg->sig0);
2808 INSIST(result == ISC_R_SUCCESS);
2809 dns_rdataset_current(msg->sig0, &rdata);
2811 result = dns_rdata_tostruct(&rdata, &sig, NULL);
2812 if (result != ISC_R_SUCCESS)
2813 return (result);
2815 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
2816 result = ISC_R_SUCCESS;
2817 else
2818 result = DNS_R_SIGINVALID;
2819 dns_name_clone(&sig.signer, signer);
2820 dns_rdata_freestruct(&sig);
2821 } else {
2822 dns_name_t *identity;
2823 dns_rdata_any_tsig_t tsig;
2825 result = dns_rdataset_first(msg->tsig);
2826 INSIST(result == ISC_R_SUCCESS);
2827 dns_rdataset_current(msg->tsig, &rdata);
2829 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2830 if (msg->tsigstatus != dns_rcode_noerror)
2831 result = DNS_R_TSIGVERIFYFAILURE;
2832 else if (tsig.error != dns_rcode_noerror)
2833 result = DNS_R_TSIGERRORSET;
2834 else
2835 result = ISC_R_SUCCESS;
2836 dns_rdata_freestruct(&tsig);
2838 if (msg->tsigkey == NULL) {
2840 * If msg->tsigstatus & tsig.error are both
2841 * dns_rcode_noerror, the message must have been
2842 * verified, which means msg->tsigkey will be
2843 * non-NULL.
2845 INSIST(result != ISC_R_SUCCESS);
2846 } else {
2847 identity = dns_tsigkey_identity(msg->tsigkey);
2848 if (identity == NULL) {
2849 if (result == ISC_R_SUCCESS)
2850 result = DNS_R_NOIDENTITY;
2851 identity = &msg->tsigkey->name;
2853 dns_name_clone(identity, signer);
2857 return (result);
2860 void
2861 dns_message_resetsig(dns_message_t *msg) {
2862 REQUIRE(DNS_MESSAGE_VALID(msg));
2863 msg->verified_sig = 0;
2864 msg->verify_attempted = 0;
2865 msg->tsigstatus = dns_rcode_noerror;
2866 msg->sig0status = dns_rcode_noerror;
2867 msg->timeadjust = 0;
2868 if (msg->tsigkey != NULL) {
2869 dns_tsigkey_detach(&msg->tsigkey);
2870 msg->tsigkey = NULL;
2874 isc_result_t
2875 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
2876 dns_message_resetsig(msg);
2877 return (dns_message_checksig(msg, view));
2880 isc_result_t
2881 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
2882 isc_buffer_t b, msgb;
2884 REQUIRE(DNS_MESSAGE_VALID(msg));
2886 if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
2887 return (ISC_R_SUCCESS);
2888 INSIST(msg->saved.base != NULL);
2889 isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
2890 isc_buffer_add(&msgb, msg->saved.length);
2891 if (msg->tsigkey != NULL || msg->tsig != NULL) {
2892 if (view != NULL)
2893 return (dns_view_checksig(view, &msgb, msg));
2894 else
2895 return (dns_tsig_verify(&msgb, msg, NULL, NULL));
2896 } else {
2897 dns_rdata_t rdata = DNS_RDATA_INIT;
2898 dns_rdata_sig_t sig;
2899 dns_rdataset_t keyset;
2900 isc_result_t result;
2902 result = dns_rdataset_first(msg->sig0);
2903 INSIST(result == ISC_R_SUCCESS);
2904 dns_rdataset_current(msg->sig0, &rdata);
2907 * This can occur when the message is a dynamic update, since
2908 * the rdata length checking is relaxed. This should not
2909 * happen in a well-formed message, since the SIG(0) is only
2910 * looked for in the additional section, and the dynamic update
2911 * meta-records are in the prerequisite and update sections.
2913 if (rdata.length == 0)
2914 return (ISC_R_UNEXPECTEDEND);
2916 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
2917 if (result != ISC_R_SUCCESS)
2918 return (result);
2920 dns_rdataset_init(&keyset);
2921 if (view == NULL)
2922 return (DNS_R_KEYUNAUTHORIZED);
2923 result = dns_view_simplefind(view, &sig.signer,
2924 dns_rdatatype_key /* SIG(0) */,
2925 0, 0, ISC_FALSE, &keyset, NULL);
2927 if (result != ISC_R_SUCCESS) {
2928 /* XXXBEW Should possibly create a fetch here */
2929 result = DNS_R_KEYUNAUTHORIZED;
2930 goto freesig;
2931 } else if (keyset.trust < dns_trust_secure) {
2932 /* XXXBEW Should call a validator here */
2933 result = DNS_R_KEYUNAUTHORIZED;
2934 goto freesig;
2936 result = dns_rdataset_first(&keyset);
2937 INSIST(result == ISC_R_SUCCESS);
2938 for (;
2939 result == ISC_R_SUCCESS;
2940 result = dns_rdataset_next(&keyset))
2942 dst_key_t *key = NULL;
2944 dns_rdataset_current(&keyset, &rdata);
2945 isc_buffer_init(&b, rdata.data, rdata.length);
2946 isc_buffer_add(&b, rdata.length);
2948 result = dst_key_fromdns(&sig.signer, rdata.rdclass,
2949 &b, view->mctx, &key);
2950 if (result != ISC_R_SUCCESS)
2951 continue;
2952 if (dst_key_alg(key) != sig.algorithm ||
2953 dst_key_id(key) != sig.keyid ||
2954 !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
2955 dst_key_proto(key) == DNS_KEYPROTO_ANY))
2957 dst_key_free(&key);
2958 continue;
2960 result = dns_dnssec_verifymessage(&msgb, msg, key);
2961 dst_key_free(&key);
2962 if (result == ISC_R_SUCCESS)
2963 break;
2965 if (result == ISC_R_NOMORE)
2966 result = DNS_R_KEYUNAUTHORIZED;
2968 freesig:
2969 if (dns_rdataset_isassociated(&keyset))
2970 dns_rdataset_disassociate(&keyset);
2971 dns_rdata_freestruct(&sig);
2972 return (result);
2976 isc_result_t
2977 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
2978 const dns_master_style_t *style,
2979 dns_messagetextflag_t flags,
2980 isc_buffer_t *target) {
2981 dns_name_t *name, empty_name;
2982 dns_rdataset_t *rdataset;
2983 isc_result_t result;
2985 REQUIRE(DNS_MESSAGE_VALID(msg));
2986 REQUIRE(target != NULL);
2987 REQUIRE(VALID_SECTION(section));
2989 if (ISC_LIST_EMPTY(msg->sections[section]))
2990 return (ISC_R_SUCCESS);
2992 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
2993 ADD_STRING(target, ";; ");
2994 if (msg->opcode != dns_opcode_update) {
2995 ADD_STRING(target, sectiontext[section]);
2997 else {
2998 ADD_STRING(target, updsectiontext[section]);
3000 ADD_STRING(target, " SECTION:\n");
3003 dns_name_init(&empty_name, NULL);
3004 result = dns_message_firstname(msg, section);
3005 if (result != ISC_R_SUCCESS) {
3006 return (result);
3008 do {
3009 name = NULL;
3010 dns_message_currentname(msg, section, &name);
3011 for (rdataset = ISC_LIST_HEAD(name->list);
3012 rdataset != NULL;
3013 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3014 if (section == DNS_SECTION_QUESTION) {
3015 ADD_STRING(target, ";");
3016 result = dns_master_questiontotext(name,
3017 rdataset,
3018 style,
3019 target);
3020 } else {
3021 result = dns_master_rdatasettotext(name,
3022 rdataset,
3023 style,
3024 target);
3026 if (result != ISC_R_SUCCESS)
3027 return (result);
3029 result = dns_message_nextname(msg, section);
3030 } while (result == ISC_R_SUCCESS);
3031 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3032 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3033 ADD_STRING(target, "\n");
3034 if (result == ISC_R_NOMORE)
3035 result = ISC_R_SUCCESS;
3036 return (result);
3039 isc_result_t
3040 dns_message_pseudosectiontotext(dns_message_t *msg,
3041 dns_pseudosection_t section,
3042 const dns_master_style_t *style,
3043 dns_messagetextflag_t flags,
3044 isc_buffer_t *target) {
3045 dns_rdataset_t *ps = NULL;
3046 dns_name_t *name = NULL;
3047 isc_result_t result;
3048 char buf[sizeof("1234567890")];
3049 isc_uint32_t mbz;
3051 REQUIRE(DNS_MESSAGE_VALID(msg));
3052 REQUIRE(target != NULL);
3053 REQUIRE(VALID_PSEUDOSECTION(section));
3055 switch (section) {
3056 case DNS_PSEUDOSECTION_OPT:
3057 ps = dns_message_getopt(msg);
3058 if (ps == NULL)
3059 return (ISC_R_SUCCESS);
3060 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3061 ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3062 ADD_STRING(target, "; EDNS: version: ");
3063 snprintf(buf, sizeof(buf), "%u",
3064 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3065 ADD_STRING(target, buf);
3066 ADD_STRING(target, ", flags:");
3067 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3068 ADD_STRING(target, " do");
3069 mbz = ps->ttl & ~DNS_MESSAGEEXTFLAG_DO & 0xffff;
3070 if (mbz != 0) {
3071 ADD_STRING(target, "; MBZ: ");
3072 snprintf(buf, sizeof(buf), "%.4x ", mbz);
3073 ADD_STRING(target, buf);
3074 ADD_STRING(target, ", udp: ");
3075 } else
3076 ADD_STRING(target, "; udp: ");
3077 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3078 ADD_STRING(target, buf);
3079 return (ISC_R_SUCCESS);
3080 case DNS_PSEUDOSECTION_TSIG:
3081 ps = dns_message_gettsig(msg, &name);
3082 if (ps == NULL)
3083 return (ISC_R_SUCCESS);
3084 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3085 ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
3086 result = dns_master_rdatasettotext(name, ps, style, target);
3087 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3088 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3089 ADD_STRING(target, "\n");
3090 return (result);
3091 case DNS_PSEUDOSECTION_SIG0:
3092 ps = dns_message_getsig0(msg, &name);
3093 if (ps == NULL)
3094 return (ISC_R_SUCCESS);
3095 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3096 ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3097 result = dns_master_rdatasettotext(name, ps, style, target);
3098 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3099 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3100 ADD_STRING(target, "\n");
3101 return (result);
3103 return (ISC_R_UNEXPECTED);
3106 isc_result_t
3107 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3108 dns_messagetextflag_t flags, isc_buffer_t *target) {
3109 char buf[sizeof("1234567890")];
3110 isc_result_t result;
3112 REQUIRE(DNS_MESSAGE_VALID(msg));
3113 REQUIRE(target != NULL);
3115 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
3116 ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
3117 ADD_STRING(target, opcodetext[msg->opcode]);
3118 ADD_STRING(target, ", status: ");
3119 ADD_STRING(target, rcodetext[msg->rcode]);
3120 ADD_STRING(target, ", id: ");
3121 snprintf(buf, sizeof(buf), "%6u", msg->id);
3122 ADD_STRING(target, buf);
3123 ADD_STRING(target, "\n;; flags: ");
3124 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3125 ADD_STRING(target, "qr ");
3126 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3127 ADD_STRING(target, "aa ");
3128 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3129 ADD_STRING(target, "tc ");
3130 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3131 ADD_STRING(target, "rd ");
3132 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3133 ADD_STRING(target, "ra ");
3134 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3135 ADD_STRING(target, "ad ");
3136 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
3137 ADD_STRING(target, "cd ");
3138 if (msg->opcode != dns_opcode_update) {
3139 ADD_STRING(target, "; QUESTION: ");
3140 } else {
3141 ADD_STRING(target, "; ZONE: ");
3143 snprintf(buf, sizeof(buf), "%1u",
3144 msg->counts[DNS_SECTION_QUESTION]);
3145 ADD_STRING(target, buf);
3146 if (msg->opcode != dns_opcode_update) {
3147 ADD_STRING(target, ", ANSWER: ");
3148 } else {
3149 ADD_STRING(target, ", PREREQ: ");
3151 snprintf(buf, sizeof(buf), "%1u",
3152 msg->counts[DNS_SECTION_ANSWER]);
3153 ADD_STRING(target, buf);
3154 if (msg->opcode != dns_opcode_update) {
3155 ADD_STRING(target, ", AUTHORITY: ");
3156 } else {
3157 ADD_STRING(target, ", UPDATE: ");
3159 snprintf(buf, sizeof(buf), "%1u",
3160 msg->counts[DNS_SECTION_AUTHORITY]);
3161 ADD_STRING(target, buf);
3162 ADD_STRING(target, ", ADDITIONAL: ");
3163 snprintf(buf, sizeof(buf), "%1u",
3164 msg->counts[DNS_SECTION_ADDITIONAL]);
3165 ADD_STRING(target, buf);
3166 ADD_STRING(target, "\n");
3168 result = dns_message_pseudosectiontotext(msg,
3169 DNS_PSEUDOSECTION_OPT,
3170 style, flags, target);
3171 if (result != ISC_R_SUCCESS)
3172 return (result);
3174 result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
3175 style, flags, target);
3176 if (result != ISC_R_SUCCESS)
3177 return (result);
3178 result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
3179 style, flags, target);
3180 if (result != ISC_R_SUCCESS)
3181 return (result);
3182 result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
3183 style, flags, target);
3184 if (result != ISC_R_SUCCESS)
3185 return (result);
3186 result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
3187 style, flags, target);
3188 if (result != ISC_R_SUCCESS)
3189 return (result);
3191 result = dns_message_pseudosectiontotext(msg,
3192 DNS_PSEUDOSECTION_TSIG,
3193 style, flags, target);
3194 if (result != ISC_R_SUCCESS)
3195 return (result);
3197 result = dns_message_pseudosectiontotext(msg,
3198 DNS_PSEUDOSECTION_SIG0,
3199 style, flags, target);
3200 if (result != ISC_R_SUCCESS)
3201 return (result);
3203 return (ISC_R_SUCCESS);
3206 isc_region_t *
3207 dns_message_getrawmessage(dns_message_t *msg) {
3208 REQUIRE(DNS_MESSAGE_VALID(msg));
3209 return (&msg->saved);
3212 void
3213 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3214 const void *order_arg)
3216 REQUIRE(DNS_MESSAGE_VALID(msg));
3217 msg->order = order;
3218 msg->order_arg = order_arg;
3221 void
3222 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3223 REQUIRE(DNS_MESSAGE_VALID(msg));
3224 msg->timeadjust = timeadjust;
3228 dns_message_gettimeadjust(dns_message_t *msg) {
3229 REQUIRE(DNS_MESSAGE_VALID(msg));
3230 return (msg->timeadjust);
3233 isc_result_t
3234 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3236 REQUIRE(opcode < 16);
3238 if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
3239 return (ISC_R_NOSPACE);
3240 isc_buffer_putstr(target, opcodetext[opcode]);
3241 return (ISC_R_SUCCESS);