Detect FPU by checking CPUID features.
[dragonfly.git] / contrib / bind-9.5.2 / lib / dns / message.c
blob7c2ab35948c68ad0bc94d942badc607cf5c7bf45
1 /*
2 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: message.c,v 1.237.110.8 2009/01/19 23:47:02 tbox Exp $ */
20 /*! \file */
22 /***
23 *** Imports
24 ***/
26 #include <config.h>
27 #include <ctype.h>
29 #include <isc/buffer.h>
30 #include <isc/mem.h>
31 #include <isc/print.h>
32 #include <isc/string.h> /* Required for HP/UX (and others?) */
33 #include <isc/util.h>
35 #include <dns/dnssec.h>
36 #include <dns/keyvalues.h>
37 #include <dns/log.h>
38 #include <dns/masterdump.h>
39 #include <dns/message.h>
40 #include <dns/opcode.h>
41 #include <dns/rdata.h>
42 #include <dns/rdatalist.h>
43 #include <dns/rdataset.h>
44 #include <dns/rdatastruct.h>
45 #include <dns/result.h>
46 #include <dns/tsig.h>
47 #include <dns/view.h>
49 #ifdef SKAN_MSG_DEBUG
50 static void
51 hexdump(const char *msg, const char *msg2, void *base, size_t len) {
52 unsigned char *p;
53 unsigned int cnt;
55 p = base;
56 cnt = 0;
58 printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base);
60 while (cnt < len) {
61 if (cnt % 16 == 0)
62 printf("%p: ", p);
63 else if (cnt % 8 == 0)
64 printf(" |");
65 printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
66 p++;
67 cnt++;
69 if (cnt % 16 == 0)
70 printf("\n");
73 if (cnt % 16 != 0)
74 printf("\n");
76 #endif
78 #define DNS_MESSAGE_OPCODE_MASK 0x7800U
79 #define DNS_MESSAGE_OPCODE_SHIFT 11
80 #define DNS_MESSAGE_RCODE_MASK 0x000fU
81 #define DNS_MESSAGE_FLAG_MASK 0x8ff0U
82 #define DNS_MESSAGE_EDNSRCODE_MASK 0xff000000U
83 #define DNS_MESSAGE_EDNSRCODE_SHIFT 24
84 #define DNS_MESSAGE_EDNSVERSION_MASK 0x00ff0000U
85 #define DNS_MESSAGE_EDNSVERSION_SHIFT 16
87 #define VALID_NAMED_SECTION(s) (((s) > DNS_SECTION_ANY) \
88 && ((s) < DNS_SECTION_MAX))
89 #define VALID_SECTION(s) (((s) >= DNS_SECTION_ANY) \
90 && ((s) < DNS_SECTION_MAX))
91 #define ADD_STRING(b, s) {if (strlen(s) >= \
92 isc_buffer_availablelength(b)) \
93 return(ISC_R_NOSPACE); else \
94 isc_buffer_putstr(b, s);}
95 #define VALID_PSEUDOSECTION(s) (((s) >= DNS_PSEUDOSECTION_ANY) \
96 && ((s) < DNS_PSEUDOSECTION_MAX))
98 /*%
99 * This is the size of each individual scratchpad buffer, and the numbers
100 * of various block allocations used within the server.
101 * XXXMLG These should come from a config setting.
103 #define SCRATCHPAD_SIZE 512
104 #define NAME_COUNT 8
105 #define OFFSET_COUNT 4
106 #define RDATA_COUNT 8
107 #define RDATALIST_COUNT 8
108 #define RDATASET_COUNT RDATALIST_COUNT
111 * Text representation of the different items, for message_totext
112 * functions.
114 static const char *sectiontext[] = {
115 "QUESTION",
116 "ANSWER",
117 "AUTHORITY",
118 "ADDITIONAL"
121 static const char *updsectiontext[] = {
122 "ZONE",
123 "PREREQUISITE",
124 "UPDATE",
125 "ADDITIONAL"
128 static const char *opcodetext[] = {
129 "QUERY",
130 "IQUERY",
131 "STATUS",
132 "RESERVED3",
133 "NOTIFY",
134 "UPDATE",
135 "RESERVED6",
136 "RESERVED7",
137 "RESERVED8",
138 "RESERVED9",
139 "RESERVED10",
140 "RESERVED11",
141 "RESERVED12",
142 "RESERVED13",
143 "RESERVED14",
144 "RESERVED15"
147 static const char *rcodetext[] = {
148 "NOERROR",
149 "FORMERR",
150 "SERVFAIL",
151 "NXDOMAIN",
152 "NOTIMP",
153 "REFUSED",
154 "YXDOMAIN",
155 "YXRRSET",
156 "NXRRSET",
157 "NOTAUTH",
158 "NOTZONE",
159 "RESERVED11",
160 "RESERVED12",
161 "RESERVED13",
162 "RESERVED14",
163 "RESERVED15",
164 "BADVERS"
169 * "helper" type, which consists of a block of some type, and is linkable.
170 * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
171 * size, or the allocated elements will not be aligned correctly.
173 struct dns_msgblock {
174 unsigned int count;
175 unsigned int remaining;
176 ISC_LINK(dns_msgblock_t) link;
177 }; /* dynamically sized */
179 static inline dns_msgblock_t *
180 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
182 #define msgblock_get(block, type) \
183 ((type *)msgblock_internalget(block, sizeof(type)))
185 static inline void *
186 msgblock_internalget(dns_msgblock_t *, unsigned int);
188 static inline void
189 msgblock_reset(dns_msgblock_t *);
191 static inline void
192 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
195 * Allocate a new dns_msgblock_t, and return a pointer to it. If no memory
196 * is free, return NULL.
198 static inline dns_msgblock_t *
199 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
200 unsigned int count)
202 dns_msgblock_t *block;
203 unsigned int length;
205 length = sizeof(dns_msgblock_t) + (sizeof_type * count);
207 block = isc_mem_get(mctx, length);
208 if (block == NULL)
209 return (NULL);
211 block->count = count;
212 block->remaining = count;
214 ISC_LINK_INIT(block, link);
216 return (block);
220 * Return an element from the msgblock. If no more are available, return
221 * NULL.
223 static inline void *
224 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
225 void *ptr;
227 if (block == NULL || block->remaining == 0)
228 return (NULL);
230 block->remaining--;
232 ptr = (((unsigned char *)block)
233 + sizeof(dns_msgblock_t)
234 + (sizeof_type * block->remaining));
236 return (ptr);
239 static inline void
240 msgblock_reset(dns_msgblock_t *block) {
241 block->remaining = block->count;
245 * Release memory associated with a message block.
247 static inline void
248 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
250 unsigned int length;
252 length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
254 isc_mem_put(mctx, block, length);
258 * Allocate a new dynamic buffer, and attach it to this message as the
259 * "current" buffer. (which is always the last on the list, for our
260 * uses)
262 static inline isc_result_t
263 newbuffer(dns_message_t *msg, unsigned int size) {
264 isc_result_t result;
265 isc_buffer_t *dynbuf;
267 dynbuf = NULL;
268 result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
269 if (result != ISC_R_SUCCESS)
270 return (ISC_R_NOMEMORY);
272 ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
273 return (ISC_R_SUCCESS);
276 static inline isc_buffer_t *
277 currentbuffer(dns_message_t *msg) {
278 isc_buffer_t *dynbuf;
280 dynbuf = ISC_LIST_TAIL(msg->scratchpad);
281 INSIST(dynbuf != NULL);
283 return (dynbuf);
286 static inline void
287 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
288 ISC_LIST_PREPEND(msg->freerdata, rdata, link);
291 static inline dns_rdata_t *
292 newrdata(dns_message_t *msg) {
293 dns_msgblock_t *msgblock;
294 dns_rdata_t *rdata;
296 rdata = ISC_LIST_HEAD(msg->freerdata);
297 if (rdata != NULL) {
298 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
299 return (rdata);
302 msgblock = ISC_LIST_TAIL(msg->rdatas);
303 rdata = msgblock_get(msgblock, dns_rdata_t);
304 if (rdata == NULL) {
305 msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
306 RDATA_COUNT);
307 if (msgblock == NULL)
308 return (NULL);
310 ISC_LIST_APPEND(msg->rdatas, msgblock, link);
312 rdata = msgblock_get(msgblock, dns_rdata_t);
315 dns_rdata_init(rdata);
316 return (rdata);
319 static inline void
320 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
321 ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
324 static inline dns_rdatalist_t *
325 newrdatalist(dns_message_t *msg) {
326 dns_msgblock_t *msgblock;
327 dns_rdatalist_t *rdatalist;
329 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
330 if (rdatalist != NULL) {
331 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
332 return (rdatalist);
335 msgblock = ISC_LIST_TAIL(msg->rdatalists);
336 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
337 if (rdatalist == NULL) {
338 msgblock = msgblock_allocate(msg->mctx,
339 sizeof(dns_rdatalist_t),
340 RDATALIST_COUNT);
341 if (msgblock == NULL)
342 return (NULL);
344 ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
346 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
349 return (rdatalist);
352 static inline dns_offsets_t *
353 newoffsets(dns_message_t *msg) {
354 dns_msgblock_t *msgblock;
355 dns_offsets_t *offsets;
357 msgblock = ISC_LIST_TAIL(msg->offsets);
358 offsets = msgblock_get(msgblock, dns_offsets_t);
359 if (offsets == NULL) {
360 msgblock = msgblock_allocate(msg->mctx,
361 sizeof(dns_offsets_t),
362 OFFSET_COUNT);
363 if (msgblock == NULL)
364 return (NULL);
366 ISC_LIST_APPEND(msg->offsets, msgblock, link);
368 offsets = msgblock_get(msgblock, dns_offsets_t);
371 return (offsets);
374 static inline void
375 msginitheader(dns_message_t *m) {
376 m->id = 0;
377 m->flags = 0;
378 m->rcode = 0;
379 m->opcode = 0;
380 m->rdclass = 0;
383 static inline void
384 msginitprivate(dns_message_t *m) {
385 unsigned int i;
387 for (i = 0; i < DNS_SECTION_MAX; i++) {
388 m->cursors[i] = NULL;
389 m->counts[i] = 0;
391 m->opt = NULL;
392 m->sig0 = NULL;
393 m->sig0name = NULL;
394 m->tsig = NULL;
395 m->tsigname = NULL;
396 m->state = DNS_SECTION_ANY; /* indicate nothing parsed or rendered */
397 m->opt_reserved = 0;
398 m->sig_reserved = 0;
399 m->reserved = 0;
400 m->buffer = NULL;
403 static inline void
404 msginittsig(dns_message_t *m) {
405 m->tsigstatus = dns_rcode_noerror;
406 m->querytsigstatus = dns_rcode_noerror;
407 m->tsigkey = NULL;
408 m->tsigctx = NULL;
409 m->sigstart = -1;
410 m->sig0key = NULL;
411 m->sig0status = dns_rcode_noerror;
412 m->timeadjust = 0;
416 * Init elements to default state. Used both when allocating a new element
417 * and when resetting one.
419 static inline void
420 msginit(dns_message_t *m) {
421 msginitheader(m);
422 msginitprivate(m);
423 msginittsig(m);
424 m->header_ok = 0;
425 m->question_ok = 0;
426 m->tcp_continuation = 0;
427 m->verified_sig = 0;
428 m->verify_attempted = 0;
429 m->order = NULL;
430 m->order_arg = NULL;
431 m->query.base = NULL;
432 m->query.length = 0;
433 m->free_query = 0;
434 m->saved.base = NULL;
435 m->saved.length = 0;
436 m->free_saved = 0;
437 m->querytsig = NULL;
440 static inline void
441 msgresetnames(dns_message_t *msg, unsigned int first_section) {
442 unsigned int i;
443 dns_name_t *name, *next_name;
444 dns_rdataset_t *rds, *next_rds;
447 * Clean up name lists by calling the rdataset disassociate function.
449 for (i = first_section; i < DNS_SECTION_MAX; i++) {
450 name = ISC_LIST_HEAD(msg->sections[i]);
451 while (name != NULL) {
452 next_name = ISC_LIST_NEXT(name, link);
453 ISC_LIST_UNLINK(msg->sections[i], name, link);
455 rds = ISC_LIST_HEAD(name->list);
456 while (rds != NULL) {
457 next_rds = ISC_LIST_NEXT(rds, link);
458 ISC_LIST_UNLINK(name->list, rds, link);
460 INSIST(dns_rdataset_isassociated(rds));
461 dns_rdataset_disassociate(rds);
462 isc_mempool_put(msg->rdspool, rds);
463 rds = next_rds;
465 if (dns_name_dynamic(name))
466 dns_name_free(name, msg->mctx);
467 isc_mempool_put(msg->namepool, name);
468 name = next_name;
473 static void
474 msgresetopt(dns_message_t *msg)
476 if (msg->opt != NULL) {
477 if (msg->opt_reserved > 0) {
478 dns_message_renderrelease(msg, msg->opt_reserved);
479 msg->opt_reserved = 0;
481 INSIST(dns_rdataset_isassociated(msg->opt));
482 dns_rdataset_disassociate(msg->opt);
483 isc_mempool_put(msg->rdspool, msg->opt);
484 msg->opt = NULL;
488 static void
489 msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
490 if (msg->sig_reserved > 0) {
491 dns_message_renderrelease(msg, msg->sig_reserved);
492 msg->sig_reserved = 0;
494 if (msg->tsig != NULL) {
495 INSIST(dns_rdataset_isassociated(msg->tsig));
496 INSIST(msg->namepool != NULL);
497 if (replying) {
498 INSIST(msg->querytsig == NULL);
499 msg->querytsig = msg->tsig;
500 } else {
501 dns_rdataset_disassociate(msg->tsig);
502 isc_mempool_put(msg->rdspool, msg->tsig);
503 if (msg->querytsig != NULL) {
504 dns_rdataset_disassociate(msg->querytsig);
505 isc_mempool_put(msg->rdspool, msg->querytsig);
508 if (dns_name_dynamic(msg->tsigname))
509 dns_name_free(msg->tsigname, msg->mctx);
510 isc_mempool_put(msg->namepool, msg->tsigname);
511 msg->tsig = NULL;
512 msg->tsigname = NULL;
513 } else if (msg->querytsig != NULL && !replying) {
514 dns_rdataset_disassociate(msg->querytsig);
515 isc_mempool_put(msg->rdspool, msg->querytsig);
516 msg->querytsig = NULL;
518 if (msg->sig0 != NULL) {
519 INSIST(dns_rdataset_isassociated(msg->sig0));
520 dns_rdataset_disassociate(msg->sig0);
521 isc_mempool_put(msg->rdspool, msg->sig0);
522 if (msg->sig0name != NULL) {
523 if (dns_name_dynamic(msg->sig0name))
524 dns_name_free(msg->sig0name, msg->mctx);
525 isc_mempool_put(msg->namepool, msg->sig0name);
527 msg->sig0 = NULL;
528 msg->sig0name = NULL;
533 * Free all but one (or everything) for this message. This is used by
534 * both dns_message_reset() and dns_message_destroy().
536 static void
537 msgreset(dns_message_t *msg, isc_boolean_t everything) {
538 dns_msgblock_t *msgblock, *next_msgblock;
539 isc_buffer_t *dynbuf, *next_dynbuf;
540 dns_rdata_t *rdata;
541 dns_rdatalist_t *rdatalist;
543 msgresetnames(msg, 0);
544 msgresetopt(msg);
545 msgresetsigs(msg, ISC_FALSE);
548 * Clean up linked lists.
552 * Run through the free lists, and just unlink anything found there.
553 * The memory isn't lost since these are part of message blocks we
554 * have allocated.
556 rdata = ISC_LIST_HEAD(msg->freerdata);
557 while (rdata != NULL) {
558 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
559 rdata = ISC_LIST_HEAD(msg->freerdata);
561 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
562 while (rdatalist != NULL) {
563 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
564 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
567 dynbuf = ISC_LIST_HEAD(msg->scratchpad);
568 INSIST(dynbuf != NULL);
569 if (!everything) {
570 isc_buffer_clear(dynbuf);
571 dynbuf = ISC_LIST_NEXT(dynbuf, link);
573 while (dynbuf != NULL) {
574 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
575 ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
576 isc_buffer_free(&dynbuf);
577 dynbuf = next_dynbuf;
580 msgblock = ISC_LIST_HEAD(msg->rdatas);
581 if (!everything && msgblock != NULL) {
582 msgblock_reset(msgblock);
583 msgblock = ISC_LIST_NEXT(msgblock, link);
585 while (msgblock != NULL) {
586 next_msgblock = ISC_LIST_NEXT(msgblock, link);
587 ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
588 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
589 msgblock = next_msgblock;
593 * rdatalists could be empty.
596 msgblock = ISC_LIST_HEAD(msg->rdatalists);
597 if (!everything && msgblock != NULL) {
598 msgblock_reset(msgblock);
599 msgblock = ISC_LIST_NEXT(msgblock, link);
601 while (msgblock != NULL) {
602 next_msgblock = ISC_LIST_NEXT(msgblock, link);
603 ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
604 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
605 msgblock = next_msgblock;
608 msgblock = ISC_LIST_HEAD(msg->offsets);
609 if (!everything && msgblock != NULL) {
610 msgblock_reset(msgblock);
611 msgblock = ISC_LIST_NEXT(msgblock, link);
613 while (msgblock != NULL) {
614 next_msgblock = ISC_LIST_NEXT(msgblock, link);
615 ISC_LIST_UNLINK(msg->offsets, msgblock, link);
616 msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
617 msgblock = next_msgblock;
620 if (msg->tsigkey != NULL) {
621 dns_tsigkey_detach(&msg->tsigkey);
622 msg->tsigkey = NULL;
625 if (msg->tsigctx != NULL)
626 dst_context_destroy(&msg->tsigctx);
628 if (msg->query.base != NULL) {
629 if (msg->free_query != 0)
630 isc_mem_put(msg->mctx, msg->query.base,
631 msg->query.length);
632 msg->query.base = NULL;
633 msg->query.length = 0;
636 if (msg->saved.base != NULL) {
637 if (msg->free_saved != 0)
638 isc_mem_put(msg->mctx, msg->saved.base,
639 msg->saved.length);
640 msg->saved.base = NULL;
641 msg->saved.length = 0;
645 * cleanup the buffer cleanup list
647 dynbuf = ISC_LIST_HEAD(msg->cleanup);
648 while (dynbuf != NULL) {
649 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
650 ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
651 isc_buffer_free(&dynbuf);
652 dynbuf = next_dynbuf;
656 * Set other bits to normal default values.
658 if (!everything)
659 msginit(msg);
661 ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
662 ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
665 static unsigned int
666 spacefortsig(dns_tsigkey_t *key, int otherlen) {
667 isc_region_t r1, r2;
668 unsigned int x;
669 isc_result_t result;
672 * The space required for an TSIG record is:
674 * n1 bytes for the name
675 * 2 bytes for the type
676 * 2 bytes for the class
677 * 4 bytes for the ttl
678 * 2 bytes for the rdlength
679 * n2 bytes for the algorithm name
680 * 6 bytes for the time signed
681 * 2 bytes for the fudge
682 * 2 bytes for the MAC size
683 * x bytes for the MAC
684 * 2 bytes for the original id
685 * 2 bytes for the error
686 * 2 bytes for the other data length
687 * y bytes for the other data (at most)
688 * ---------------------------------
689 * 26 + n1 + n2 + x + y bytes
692 dns_name_toregion(&key->name, &r1);
693 dns_name_toregion(key->algorithm, &r2);
694 if (key->key == NULL)
695 x = 0;
696 else {
697 result = dst_key_sigsize(key->key, &x);
698 if (result != ISC_R_SUCCESS)
699 x = 0;
701 return (26 + r1.length + r2.length + x + otherlen);
704 isc_result_t
705 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
707 dns_message_t *m;
708 isc_result_t result;
709 isc_buffer_t *dynbuf;
710 unsigned int i;
712 REQUIRE(mctx != NULL);
713 REQUIRE(msgp != NULL);
714 REQUIRE(*msgp == NULL);
715 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
716 || intent == DNS_MESSAGE_INTENTRENDER);
718 m = isc_mem_get(mctx, sizeof(dns_message_t));
719 if (m == NULL)
720 return (ISC_R_NOMEMORY);
723 * No allocations until further notice. Just initialize all lists
724 * and other members that are freed in the cleanup phase here.
727 m->magic = DNS_MESSAGE_MAGIC;
728 m->from_to_wire = intent;
729 msginit(m);
731 for (i = 0; i < DNS_SECTION_MAX; i++)
732 ISC_LIST_INIT(m->sections[i]);
733 m->mctx = mctx;
735 ISC_LIST_INIT(m->scratchpad);
736 ISC_LIST_INIT(m->cleanup);
737 m->namepool = NULL;
738 m->rdspool = NULL;
739 ISC_LIST_INIT(m->rdatas);
740 ISC_LIST_INIT(m->rdatalists);
741 ISC_LIST_INIT(m->offsets);
742 ISC_LIST_INIT(m->freerdata);
743 ISC_LIST_INIT(m->freerdatalist);
746 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
749 result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
750 if (result != ISC_R_SUCCESS)
751 goto cleanup;
752 isc_mempool_setfreemax(m->namepool, NAME_COUNT);
753 isc_mempool_setname(m->namepool, "msg:names");
755 result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
756 &m->rdspool);
757 if (result != ISC_R_SUCCESS)
758 goto cleanup;
759 isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
760 isc_mempool_setname(m->rdspool, "msg:rdataset");
762 dynbuf = NULL;
763 result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
764 if (result != ISC_R_SUCCESS)
765 goto cleanup;
766 ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
768 m->cctx = NULL;
770 *msgp = m;
771 return (ISC_R_SUCCESS);
774 * Cleanup for error returns.
776 cleanup:
777 dynbuf = ISC_LIST_HEAD(m->scratchpad);
778 if (dynbuf != NULL) {
779 ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
780 isc_buffer_free(&dynbuf);
782 if (m->namepool != NULL)
783 isc_mempool_destroy(&m->namepool);
784 if (m->rdspool != NULL)
785 isc_mempool_destroy(&m->rdspool);
786 m->magic = 0;
787 isc_mem_put(mctx, m, sizeof(dns_message_t));
789 return (ISC_R_NOMEMORY);
792 void
793 dns_message_reset(dns_message_t *msg, unsigned int intent) {
794 REQUIRE(DNS_MESSAGE_VALID(msg));
795 REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
796 || intent == DNS_MESSAGE_INTENTRENDER);
798 msgreset(msg, ISC_FALSE);
799 msg->from_to_wire = intent;
802 void
803 dns_message_destroy(dns_message_t **msgp) {
804 dns_message_t *msg;
806 REQUIRE(msgp != NULL);
807 REQUIRE(DNS_MESSAGE_VALID(*msgp));
809 msg = *msgp;
810 *msgp = NULL;
812 msgreset(msg, ISC_TRUE);
813 isc_mempool_destroy(&msg->namepool);
814 isc_mempool_destroy(&msg->rdspool);
815 msg->magic = 0;
816 isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
819 static isc_result_t
820 findname(dns_name_t **foundname, dns_name_t *target,
821 dns_namelist_t *section)
823 dns_name_t *curr;
825 for (curr = ISC_LIST_TAIL(*section);
826 curr != NULL;
827 curr = ISC_LIST_PREV(curr, link)) {
828 if (dns_name_equal(curr, target)) {
829 if (foundname != NULL)
830 *foundname = curr;
831 return (ISC_R_SUCCESS);
835 return (ISC_R_NOTFOUND);
838 isc_result_t
839 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
840 dns_rdatatype_t type, dns_rdatatype_t covers,
841 dns_rdataset_t **rdataset)
843 dns_rdataset_t *curr;
845 if (rdataset != NULL) {
846 REQUIRE(*rdataset == NULL);
849 for (curr = ISC_LIST_TAIL(name->list);
850 curr != NULL;
851 curr = ISC_LIST_PREV(curr, link)) {
852 if (curr->rdclass == rdclass &&
853 curr->type == type && curr->covers == covers) {
854 if (rdataset != NULL)
855 *rdataset = curr;
856 return (ISC_R_SUCCESS);
860 return (ISC_R_NOTFOUND);
863 isc_result_t
864 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
865 dns_rdatatype_t covers, dns_rdataset_t **rdataset)
867 dns_rdataset_t *curr;
869 REQUIRE(name != NULL);
870 if (rdataset != NULL) {
871 REQUIRE(*rdataset == NULL);
874 for (curr = ISC_LIST_TAIL(name->list);
875 curr != NULL;
876 curr = ISC_LIST_PREV(curr, link)) {
877 if (curr->type == type && curr->covers == covers) {
878 if (rdataset != NULL)
879 *rdataset = curr;
880 return (ISC_R_SUCCESS);
884 return (ISC_R_NOTFOUND);
888 * Read a name from buffer "source".
890 static isc_result_t
891 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
892 dns_decompress_t *dctx)
894 isc_buffer_t *scratch;
895 isc_result_t result;
896 unsigned int tries;
898 scratch = currentbuffer(msg);
901 * First try: use current buffer.
902 * Second try: allocate a new buffer and use that.
904 tries = 0;
905 while (tries < 2) {
906 result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
907 scratch);
909 if (result == ISC_R_NOSPACE) {
910 tries++;
912 result = newbuffer(msg, SCRATCHPAD_SIZE);
913 if (result != ISC_R_SUCCESS)
914 return (result);
916 scratch = currentbuffer(msg);
917 dns_name_reset(name);
918 } else {
919 return (result);
923 INSIST(0); /* Cannot get here... */
924 return (ISC_R_UNEXPECTED);
927 static isc_result_t
928 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
929 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
930 unsigned int rdatalen, dns_rdata_t *rdata)
932 isc_buffer_t *scratch;
933 isc_result_t result;
934 unsigned int tries;
935 unsigned int trysize;
937 scratch = currentbuffer(msg);
939 isc_buffer_setactive(source, rdatalen);
942 * First try: use current buffer.
943 * Second try: allocate a new buffer of size
944 * max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
945 * (the data will fit if it was not more than 50% compressed)
946 * Subsequent tries: double buffer size on each try.
948 tries = 0;
949 trysize = 0;
950 /* XXX possibly change this to a while (tries < 2) loop */
951 for (;;) {
952 result = dns_rdata_fromwire(rdata, rdclass, rdtype,
953 source, dctx, 0,
954 scratch);
956 if (result == ISC_R_NOSPACE) {
957 if (tries == 0) {
958 trysize = 2 * rdatalen;
959 if (trysize < SCRATCHPAD_SIZE)
960 trysize = SCRATCHPAD_SIZE;
961 } else {
962 INSIST(trysize != 0);
963 if (trysize >= 65535)
964 return (ISC_R_NOSPACE);
965 /* XXX DNS_R_RRTOOLONG? */
966 trysize *= 2;
968 tries++;
969 result = newbuffer(msg, trysize);
970 if (result != ISC_R_SUCCESS)
971 return (result);
973 scratch = currentbuffer(msg);
974 } else {
975 return (result);
980 #define DO_FORMERR \
981 do { \
982 if (best_effort) \
983 seen_problem = ISC_TRUE; \
984 else { \
985 result = DNS_R_FORMERR; \
986 goto cleanup; \
988 } while (0)
990 static isc_result_t
991 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
992 unsigned int options)
994 isc_region_t r;
995 unsigned int count;
996 dns_name_t *name;
997 dns_name_t *name2;
998 dns_offsets_t *offsets;
999 dns_rdataset_t *rdataset;
1000 dns_rdatalist_t *rdatalist;
1001 isc_result_t result;
1002 dns_rdatatype_t rdtype;
1003 dns_rdataclass_t rdclass;
1004 dns_namelist_t *section;
1005 isc_boolean_t free_name;
1006 isc_boolean_t best_effort;
1007 isc_boolean_t seen_problem;
1009 section = &msg->sections[DNS_SECTION_QUESTION];
1011 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1012 seen_problem = ISC_FALSE;
1014 name = NULL;
1015 rdataset = NULL;
1016 rdatalist = NULL;
1018 for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
1019 name = isc_mempool_get(msg->namepool);
1020 if (name == NULL)
1021 return (ISC_R_NOMEMORY);
1022 free_name = ISC_TRUE;
1024 offsets = newoffsets(msg);
1025 if (offsets == NULL) {
1026 result = ISC_R_NOMEMORY;
1027 goto cleanup;
1029 dns_name_init(name, *offsets);
1032 * Parse the name out of this packet.
1034 isc_buffer_remainingregion(source, &r);
1035 isc_buffer_setactive(source, r.length);
1036 result = getname(name, source, msg, dctx);
1037 if (result != ISC_R_SUCCESS)
1038 goto cleanup;
1041 * Run through the section, looking to see if this name
1042 * is already there. If it is found, put back the allocated
1043 * name since we no longer need it, and set our name pointer
1044 * to point to the name we found.
1046 result = findname(&name2, name, section);
1049 * If it is the first name in the section, accept it.
1051 * If it is not, but is not the same as the name already
1052 * in the question section, append to the section. Note that
1053 * here in the question section this is illegal, so return
1054 * FORMERR. In the future, check the opcode to see if
1055 * this should be legal or not. In either case we no longer
1056 * need this name pointer.
1058 if (result != ISC_R_SUCCESS) {
1059 if (!ISC_LIST_EMPTY(*section))
1060 DO_FORMERR;
1061 ISC_LIST_APPEND(*section, name, link);
1062 free_name = ISC_FALSE;
1063 } else {
1064 isc_mempool_put(msg->namepool, name);
1065 name = name2;
1066 name2 = NULL;
1067 free_name = ISC_FALSE;
1071 * Get type and class.
1073 isc_buffer_remainingregion(source, &r);
1074 if (r.length < 4) {
1075 result = ISC_R_UNEXPECTEDEND;
1076 goto cleanup;
1078 rdtype = isc_buffer_getuint16(source);
1079 rdclass = isc_buffer_getuint16(source);
1082 * If this class is different than the one we already read,
1083 * this is an error.
1085 if (msg->state == DNS_SECTION_ANY) {
1086 msg->state = DNS_SECTION_QUESTION;
1087 msg->rdclass = rdclass;
1088 } else if (msg->rdclass != rdclass)
1089 DO_FORMERR;
1092 * Can't ask the same question twice.
1094 result = dns_message_find(name, rdclass, rdtype, 0, NULL);
1095 if (result == ISC_R_SUCCESS)
1096 DO_FORMERR;
1099 * Allocate a new rdatalist.
1101 rdatalist = newrdatalist(msg);
1102 if (rdatalist == NULL) {
1103 result = ISC_R_NOMEMORY;
1104 goto cleanup;
1106 rdataset = isc_mempool_get(msg->rdspool);
1107 if (rdataset == NULL) {
1108 result = ISC_R_NOMEMORY;
1109 goto cleanup;
1113 * Convert rdatalist to rdataset, and attach the latter to
1114 * the name.
1116 rdatalist->type = rdtype;
1117 rdatalist->covers = 0;
1118 rdatalist->rdclass = rdclass;
1119 rdatalist->ttl = 0;
1120 ISC_LIST_INIT(rdatalist->rdata);
1122 dns_rdataset_init(rdataset);
1123 result = dns_rdatalist_tordataset(rdatalist, rdataset);
1124 if (result != ISC_R_SUCCESS)
1125 goto cleanup;
1127 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1129 ISC_LIST_APPEND(name->list, rdataset, link);
1130 rdataset = NULL;
1133 if (seen_problem)
1134 return (DNS_R_RECOVERABLE);
1135 return (ISC_R_SUCCESS);
1137 cleanup:
1138 if (rdataset != NULL) {
1139 INSIST(!dns_rdataset_isassociated(rdataset));
1140 isc_mempool_put(msg->rdspool, rdataset);
1142 #if 0
1143 if (rdatalist != NULL)
1144 isc_mempool_put(msg->rdlpool, rdatalist);
1145 #endif
1146 if (free_name)
1147 isc_mempool_put(msg->namepool, name);
1149 return (result);
1152 static isc_boolean_t
1153 update(dns_section_t section, dns_rdataclass_t rdclass) {
1154 if (section == DNS_SECTION_PREREQUISITE)
1155 return (ISC_TF(rdclass == dns_rdataclass_any ||
1156 rdclass == dns_rdataclass_none));
1157 if (section == DNS_SECTION_UPDATE)
1158 return (ISC_TF(rdclass == dns_rdataclass_any));
1159 return (ISC_FALSE);
1162 static isc_result_t
1163 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1164 dns_section_t sectionid, unsigned int options)
1166 isc_region_t r;
1167 unsigned int count, rdatalen;
1168 dns_name_t *name;
1169 dns_name_t *name2;
1170 dns_offsets_t *offsets;
1171 dns_rdataset_t *rdataset;
1172 dns_rdatalist_t *rdatalist;
1173 isc_result_t result;
1174 dns_rdatatype_t rdtype, covers;
1175 dns_rdataclass_t rdclass;
1176 dns_rdata_t *rdata;
1177 dns_ttl_t ttl;
1178 dns_namelist_t *section;
1179 isc_boolean_t free_name, free_rdataset;
1180 isc_boolean_t preserve_order, best_effort, seen_problem;
1181 isc_boolean_t issigzero;
1183 preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
1184 best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1185 seen_problem = ISC_FALSE;
1187 for (count = 0; count < msg->counts[sectionid]; count++) {
1188 int recstart = source->current;
1189 isc_boolean_t skip_name_search, skip_type_search;
1191 section = &msg->sections[sectionid];
1193 skip_name_search = ISC_FALSE;
1194 skip_type_search = ISC_FALSE;
1195 free_name = ISC_FALSE;
1196 free_rdataset = ISC_FALSE;
1198 name = isc_mempool_get(msg->namepool);
1199 if (name == NULL)
1200 return (ISC_R_NOMEMORY);
1201 free_name = ISC_TRUE;
1203 offsets = newoffsets(msg);
1204 if (offsets == NULL) {
1205 result = ISC_R_NOMEMORY;
1206 goto cleanup;
1208 dns_name_init(name, *offsets);
1211 * Parse the name out of this packet.
1213 isc_buffer_remainingregion(source, &r);
1214 isc_buffer_setactive(source, r.length);
1215 result = getname(name, source, msg, dctx);
1216 if (result != ISC_R_SUCCESS)
1217 goto cleanup;
1220 * Get type, class, ttl, and rdatalen. Verify that at least
1221 * rdatalen bytes remain. (Some of this is deferred to
1222 * later.)
1224 isc_buffer_remainingregion(source, &r);
1225 if (r.length < 2 + 2 + 4 + 2) {
1226 result = ISC_R_UNEXPECTEDEND;
1227 goto cleanup;
1229 rdtype = isc_buffer_getuint16(source);
1230 rdclass = isc_buffer_getuint16(source);
1233 * If there was no question section, we may not yet have
1234 * established a class. Do so now.
1236 if (msg->state == DNS_SECTION_ANY &&
1237 rdtype != dns_rdatatype_opt && /* class is UDP SIZE */
1238 rdtype != dns_rdatatype_tsig && /* class is ANY */
1239 rdtype != dns_rdatatype_tkey) { /* class is undefined */
1240 msg->rdclass = rdclass;
1241 msg->state = DNS_SECTION_QUESTION;
1245 * If this class is different than the one in the question
1246 * section, bail.
1248 if (msg->opcode != dns_opcode_update
1249 && rdtype != dns_rdatatype_tsig
1250 && rdtype != dns_rdatatype_opt
1251 && rdtype != dns_rdatatype_dnskey /* in a TKEY query */
1252 && rdtype != dns_rdatatype_sig /* SIG(0) */
1253 && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1254 && msg->rdclass != dns_rdataclass_any
1255 && msg->rdclass != rdclass)
1256 DO_FORMERR;
1259 * Special type handling for TSIG, OPT, and TKEY.
1261 if (rdtype == dns_rdatatype_tsig) {
1263 * If it is a tsig, verify that it is in the
1264 * additional data section.
1266 if (sectionid != DNS_SECTION_ADDITIONAL ||
1267 rdclass != dns_rdataclass_any ||
1268 count != msg->counts[sectionid] - 1)
1269 DO_FORMERR;
1270 msg->sigstart = recstart;
1271 skip_name_search = ISC_TRUE;
1272 skip_type_search = ISC_TRUE;
1273 } else if (rdtype == dns_rdatatype_opt) {
1275 * The name of an OPT record must be ".", it
1276 * must be in the additional data section, and
1277 * it must be the first OPT we've seen.
1279 if (!dns_name_equal(dns_rootname, name) ||
1280 msg->opt != NULL)
1281 DO_FORMERR;
1282 skip_name_search = ISC_TRUE;
1283 skip_type_search = ISC_TRUE;
1284 } else if (rdtype == dns_rdatatype_tkey) {
1286 * A TKEY must be in the additional section if this
1287 * is a query, and the answer section if this is a
1288 * response. Unless it's a Win2000 client.
1290 * Its class is ignored.
1292 dns_section_t tkeysection;
1294 if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1295 tkeysection = DNS_SECTION_ADDITIONAL;
1296 else
1297 tkeysection = DNS_SECTION_ANSWER;
1298 if (sectionid != tkeysection &&
1299 sectionid != DNS_SECTION_ANSWER)
1300 DO_FORMERR;
1304 * ... now get ttl and rdatalen, and check buffer.
1306 ttl = isc_buffer_getuint32(source);
1307 rdatalen = isc_buffer_getuint16(source);
1308 r.length -= (2 + 2 + 4 + 2);
1309 if (r.length < rdatalen) {
1310 result = ISC_R_UNEXPECTEDEND;
1311 goto cleanup;
1315 * Read the rdata from the wire format. Interpret the
1316 * rdata according to its actual class, even if it had a
1317 * DynDNS meta-class in the packet (unless this is a TSIG).
1318 * Then put the meta-class back into the finished rdata.
1320 rdata = newrdata(msg);
1321 if (rdata == NULL) {
1322 result = ISC_R_NOMEMORY;
1323 goto cleanup;
1325 if (msg->opcode == dns_opcode_update &&
1326 update(sectionid, rdclass)) {
1327 if (rdatalen != 0) {
1328 result = DNS_R_FORMERR;
1329 goto cleanup;
1332 * When the rdata is empty, the data pointer is
1333 * never dereferenced, but it must still be non-NULL.
1334 * Casting 1 rather than "" avoids warnings about
1335 * discarding the const attribute of a string,
1336 * for compilers that would warn about such things.
1338 rdata->data = (unsigned char *)1;
1339 rdata->length = 0;
1340 rdata->rdclass = rdclass;
1341 rdata->type = rdtype;
1342 rdata->flags = DNS_RDATA_UPDATE;
1343 result = ISC_R_SUCCESS;
1344 } else if (rdclass == dns_rdataclass_none &&
1345 msg->opcode == dns_opcode_update &&
1346 sectionid == DNS_SECTION_UPDATE) {
1347 result = getrdata(source, msg, dctx, msg->rdclass,
1348 rdtype, rdatalen, rdata);
1349 } else
1350 result = getrdata(source, msg, dctx, rdclass,
1351 rdtype, rdatalen, rdata);
1352 if (result != ISC_R_SUCCESS)
1353 goto cleanup;
1354 rdata->rdclass = rdclass;
1355 issigzero = ISC_FALSE;
1356 if (rdtype == dns_rdatatype_rrsig &&
1357 rdata->flags == 0) {
1358 covers = dns_rdata_covers(rdata);
1359 if (covers == 0)
1360 DO_FORMERR;
1361 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1362 rdata->flags == 0) {
1363 covers = dns_rdata_covers(rdata);
1364 if (covers == 0) {
1365 if (sectionid != DNS_SECTION_ADDITIONAL ||
1366 count != msg->counts[sectionid] - 1)
1367 DO_FORMERR;
1368 msg->sigstart = recstart;
1369 skip_name_search = ISC_TRUE;
1370 skip_type_search = ISC_TRUE;
1371 issigzero = ISC_TRUE;
1373 } else
1374 covers = 0;
1377 * If we are doing a dynamic update or this is a meta-type,
1378 * don't bother searching for a name, just append this one
1379 * to the end of the message.
1381 if (preserve_order || msg->opcode == dns_opcode_update ||
1382 skip_name_search) {
1383 if (rdtype != dns_rdatatype_opt &&
1384 rdtype != dns_rdatatype_tsig &&
1385 !issigzero)
1387 ISC_LIST_APPEND(*section, name, link);
1388 free_name = ISC_FALSE;
1390 } else {
1392 * Run through the section, looking to see if this name
1393 * is already there. If it is found, put back the
1394 * allocated name since we no longer need it, and set
1395 * our name pointer to point to the name we found.
1397 result = findname(&name2, name, section);
1400 * If it is a new name, append to the section.
1402 if (result == ISC_R_SUCCESS) {
1403 isc_mempool_put(msg->namepool, name);
1404 name = name2;
1405 } else {
1406 ISC_LIST_APPEND(*section, name, link);
1408 free_name = ISC_FALSE;
1412 * Search name for the particular type and class.
1413 * Skip this stage if in update mode or this is a meta-type.
1415 if (preserve_order || msg->opcode == dns_opcode_update ||
1416 skip_type_search)
1417 result = ISC_R_NOTFOUND;
1418 else {
1420 * If this is a type that can only occur in
1421 * the question section, fail.
1423 if (dns_rdatatype_questiononly(rdtype))
1424 DO_FORMERR;
1426 rdataset = NULL;
1427 result = dns_message_find(name, rdclass, rdtype,
1428 covers, &rdataset);
1432 * If we found an rdataset that matches, we need to
1433 * append this rdata to that set. If we did not, we need
1434 * to create a new rdatalist, store the important bits there,
1435 * convert it to an rdataset, and link the latter to the name.
1436 * Yuck. When appending, make certain that the type isn't
1437 * a singleton type, such as SOA or CNAME.
1439 * Note that this check will be bypassed when preserving order,
1440 * the opcode is an update, or the type search is skipped.
1442 if (result == ISC_R_SUCCESS) {
1443 if (dns_rdatatype_issingleton(rdtype))
1444 DO_FORMERR;
1447 if (result == ISC_R_NOTFOUND) {
1448 rdataset = isc_mempool_get(msg->rdspool);
1449 if (rdataset == NULL) {
1450 result = ISC_R_NOMEMORY;
1451 goto cleanup;
1453 free_rdataset = ISC_TRUE;
1455 rdatalist = newrdatalist(msg);
1456 if (rdatalist == NULL) {
1457 result = ISC_R_NOMEMORY;
1458 goto cleanup;
1461 rdatalist->type = rdtype;
1462 rdatalist->covers = covers;
1463 rdatalist->rdclass = rdclass;
1464 rdatalist->ttl = ttl;
1465 ISC_LIST_INIT(rdatalist->rdata);
1467 dns_rdataset_init(rdataset);
1468 RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1469 rdataset)
1470 == ISC_R_SUCCESS);
1472 if (rdtype != dns_rdatatype_opt &&
1473 rdtype != dns_rdatatype_tsig &&
1474 !issigzero)
1476 ISC_LIST_APPEND(name->list, rdataset, link);
1477 free_rdataset = ISC_FALSE;
1482 * Minimize TTLs.
1484 * Section 5.2 of RFC2181 says we should drop
1485 * nonauthoritative rrsets where the TTLs differ, but we
1486 * currently treat them the as if they were authoritative and
1487 * minimize them.
1489 if (ttl != rdataset->ttl) {
1490 rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1491 if (ttl < rdataset->ttl)
1492 rdataset->ttl = ttl;
1495 /* Append this rdata to the rdataset. */
1496 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1497 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1500 * If this is an OPT record, remember it. Also, set
1501 * the extended rcode. Note that msg->opt will only be set
1502 * if best-effort parsing is enabled.
1504 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1505 dns_rcode_t ercode;
1507 msg->opt = rdataset;
1508 rdataset = NULL;
1509 free_rdataset = ISC_FALSE;
1510 ercode = (dns_rcode_t)
1511 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1512 >> 20);
1513 msg->rcode |= ercode;
1514 isc_mempool_put(msg->namepool, name);
1515 free_name = ISC_FALSE;
1519 * If this is an SIG(0) or TSIG record, remember it. Note
1520 * that msg->sig0 or msg->tsig will only be set if best-effort
1521 * parsing is enabled.
1523 if (issigzero && msg->sig0 == NULL) {
1524 msg->sig0 = rdataset;
1525 msg->sig0name = name;
1526 rdataset = NULL;
1527 free_rdataset = ISC_FALSE;
1528 free_name = ISC_FALSE;
1529 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1530 msg->tsig = rdataset;
1531 msg->tsigname = name;
1532 rdataset = NULL;
1533 free_rdataset = ISC_FALSE;
1534 free_name = ISC_FALSE;
1537 if (seen_problem) {
1538 if (free_name)
1539 isc_mempool_put(msg->namepool, name);
1540 if (free_rdataset)
1541 isc_mempool_put(msg->rdspool, rdataset);
1542 free_name = free_rdataset = ISC_FALSE;
1544 INSIST(free_name == ISC_FALSE);
1545 INSIST(free_rdataset == ISC_FALSE);
1548 if (seen_problem)
1549 return (DNS_R_RECOVERABLE);
1550 return (ISC_R_SUCCESS);
1552 cleanup:
1553 if (free_name)
1554 isc_mempool_put(msg->namepool, name);
1555 if (free_rdataset)
1556 isc_mempool_put(msg->rdspool, rdataset);
1558 return (result);
1561 isc_result_t
1562 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1563 unsigned int options)
1565 isc_region_t r;
1566 dns_decompress_t dctx;
1567 isc_result_t ret;
1568 isc_uint16_t tmpflags;
1569 isc_buffer_t origsource;
1570 isc_boolean_t seen_problem;
1571 isc_boolean_t ignore_tc;
1573 REQUIRE(DNS_MESSAGE_VALID(msg));
1574 REQUIRE(source != NULL);
1575 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1577 seen_problem = ISC_FALSE;
1578 ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1580 origsource = *source;
1582 msg->header_ok = 0;
1583 msg->question_ok = 0;
1585 isc_buffer_remainingregion(source, &r);
1586 if (r.length < DNS_MESSAGE_HEADERLEN)
1587 return (ISC_R_UNEXPECTEDEND);
1589 msg->id = isc_buffer_getuint16(source);
1590 tmpflags = isc_buffer_getuint16(source);
1591 msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1592 >> DNS_MESSAGE_OPCODE_SHIFT);
1593 msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1594 msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1595 msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1596 msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1597 msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1598 msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1600 msg->header_ok = 1;
1603 * -1 means no EDNS.
1605 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1607 dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1609 ret = getquestions(source, msg, &dctx, options);
1610 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1611 goto truncated;
1612 if (ret == DNS_R_RECOVERABLE) {
1613 seen_problem = ISC_TRUE;
1614 ret = ISC_R_SUCCESS;
1616 if (ret != ISC_R_SUCCESS)
1617 return (ret);
1618 msg->question_ok = 1;
1620 ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1621 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1622 goto truncated;
1623 if (ret == DNS_R_RECOVERABLE) {
1624 seen_problem = ISC_TRUE;
1625 ret = ISC_R_SUCCESS;
1627 if (ret != ISC_R_SUCCESS)
1628 return (ret);
1630 ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1631 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1632 goto truncated;
1633 if (ret == DNS_R_RECOVERABLE) {
1634 seen_problem = ISC_TRUE;
1635 ret = ISC_R_SUCCESS;
1637 if (ret != ISC_R_SUCCESS)
1638 return (ret);
1640 ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1641 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1642 goto truncated;
1643 if (ret == DNS_R_RECOVERABLE) {
1644 seen_problem = ISC_TRUE;
1645 ret = ISC_R_SUCCESS;
1647 if (ret != ISC_R_SUCCESS)
1648 return (ret);
1650 isc_buffer_remainingregion(source, &r);
1651 if (r.length != 0) {
1652 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1653 DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1654 "message has %u byte(s) of trailing garbage",
1655 r.length);
1658 truncated:
1659 if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1660 isc_buffer_usedregion(&origsource, &msg->saved);
1661 else {
1662 msg->saved.length = isc_buffer_usedlength(&origsource);
1663 msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1664 if (msg->saved.base == NULL)
1665 return (ISC_R_NOMEMORY);
1666 memcpy(msg->saved.base, isc_buffer_base(&origsource),
1667 msg->saved.length);
1668 msg->free_saved = 1;
1671 if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1672 return (DNS_R_RECOVERABLE);
1673 if (seen_problem == ISC_TRUE)
1674 return (DNS_R_RECOVERABLE);
1675 return (ISC_R_SUCCESS);
1678 isc_result_t
1679 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1680 isc_buffer_t *buffer)
1682 isc_region_t r;
1684 REQUIRE(DNS_MESSAGE_VALID(msg));
1685 REQUIRE(buffer != NULL);
1686 REQUIRE(msg->buffer == NULL);
1687 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1689 msg->cctx = cctx;
1692 * Erase the contents of this buffer.
1694 isc_buffer_clear(buffer);
1697 * Make certain there is enough for at least the header in this
1698 * buffer.
1700 isc_buffer_availableregion(buffer, &r);
1701 if (r.length < DNS_MESSAGE_HEADERLEN)
1702 return (ISC_R_NOSPACE);
1704 if (r.length < msg->reserved)
1705 return (ISC_R_NOSPACE);
1708 * Reserve enough space for the header in this buffer.
1710 isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1712 msg->buffer = buffer;
1714 return (ISC_R_SUCCESS);
1717 isc_result_t
1718 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1719 isc_region_t r, rn;
1721 REQUIRE(DNS_MESSAGE_VALID(msg));
1722 REQUIRE(buffer != NULL);
1723 REQUIRE(msg->buffer != NULL);
1726 * Ensure that the new buffer is empty, and has enough space to
1727 * hold the current contents.
1729 isc_buffer_clear(buffer);
1731 isc_buffer_availableregion(buffer, &rn);
1732 isc_buffer_usedregion(msg->buffer, &r);
1733 REQUIRE(rn.length > r.length);
1736 * Copy the contents from the old to the new buffer.
1738 isc_buffer_add(buffer, r.length);
1739 memcpy(rn.base, r.base, r.length);
1741 msg->buffer = buffer;
1743 return (ISC_R_SUCCESS);
1746 void
1747 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1748 REQUIRE(DNS_MESSAGE_VALID(msg));
1749 REQUIRE(space <= msg->reserved);
1751 msg->reserved -= space;
1754 isc_result_t
1755 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1756 isc_region_t r;
1758 REQUIRE(DNS_MESSAGE_VALID(msg));
1760 if (msg->buffer != NULL) {
1761 isc_buffer_availableregion(msg->buffer, &r);
1762 if (r.length < (space + msg->reserved))
1763 return (ISC_R_NOSPACE);
1766 msg->reserved += space;
1768 return (ISC_R_SUCCESS);
1771 static inline isc_boolean_t
1772 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1773 int pass_needed;
1776 * If we are not rendering class IN, this ordering is bogus.
1778 if (rds->rdclass != dns_rdataclass_in)
1779 return (ISC_FALSE);
1781 switch (rds->type) {
1782 case dns_rdatatype_a:
1783 case dns_rdatatype_aaaa:
1784 if (preferred_glue == rds->type)
1785 pass_needed = 4;
1786 else
1787 pass_needed = 3;
1788 break;
1789 case dns_rdatatype_rrsig:
1790 case dns_rdatatype_dnskey:
1791 pass_needed = 2;
1792 break;
1793 default:
1794 pass_needed = 1;
1797 if (pass_needed >= pass)
1798 return (ISC_FALSE);
1800 return (ISC_TRUE);
1803 isc_result_t
1804 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1805 unsigned int options)
1807 dns_namelist_t *section;
1808 dns_name_t *name, *next_name;
1809 dns_rdataset_t *rdataset, *next_rdataset;
1810 unsigned int count, total;
1811 isc_result_t result;
1812 isc_buffer_t st; /* for rollbacks */
1813 int pass;
1814 isc_boolean_t partial = ISC_FALSE;
1815 unsigned int rd_options;
1816 dns_rdatatype_t preferred_glue = 0;
1818 REQUIRE(DNS_MESSAGE_VALID(msg));
1819 REQUIRE(msg->buffer != NULL);
1820 REQUIRE(VALID_NAMED_SECTION(sectionid));
1822 section = &msg->sections[sectionid];
1824 if ((sectionid == DNS_SECTION_ADDITIONAL)
1825 && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1826 if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1827 preferred_glue = dns_rdatatype_a;
1828 pass = 4;
1829 } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1830 preferred_glue = dns_rdatatype_aaaa;
1831 pass = 4;
1832 } else
1833 pass = 3;
1834 } else
1835 pass = 1;
1837 if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1838 rd_options = 0;
1839 else
1840 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1843 * Shrink the space in the buffer by the reserved amount.
1845 msg->buffer->length -= msg->reserved;
1847 total = 0;
1848 if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1849 partial = ISC_TRUE;
1852 * Render required glue first. Set TC if it won't fit.
1854 name = ISC_LIST_HEAD(*section);
1855 if (name != NULL) {
1856 rdataset = ISC_LIST_HEAD(name->list);
1857 if (rdataset != NULL &&
1858 (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
1859 (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
1860 const void *order_arg = msg->order_arg;
1861 st = *(msg->buffer);
1862 count = 0;
1863 if (partial)
1864 result = dns_rdataset_towirepartial(rdataset,
1865 name,
1866 msg->cctx,
1867 msg->buffer,
1868 msg->order,
1869 order_arg,
1870 rd_options,
1871 &count,
1872 NULL);
1873 else
1874 result = dns_rdataset_towiresorted(rdataset,
1875 name,
1876 msg->cctx,
1877 msg->buffer,
1878 msg->order,
1879 order_arg,
1880 rd_options,
1881 &count);
1882 total += count;
1883 if (partial && result == ISC_R_NOSPACE) {
1884 msg->flags |= DNS_MESSAGEFLAG_TC;
1885 msg->buffer->length += msg->reserved;
1886 msg->counts[sectionid] += total;
1887 return (result);
1889 if (result != ISC_R_SUCCESS) {
1890 INSIST(st.used < 65536);
1891 dns_compress_rollback(msg->cctx,
1892 (isc_uint16_t)st.used);
1893 *(msg->buffer) = st; /* rollback */
1894 msg->buffer->length += msg->reserved;
1895 msg->counts[sectionid] += total;
1896 return (result);
1898 rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
1902 do {
1903 name = ISC_LIST_HEAD(*section);
1904 if (name == NULL) {
1905 msg->buffer->length += msg->reserved;
1906 msg->counts[sectionid] += total;
1907 return (ISC_R_SUCCESS);
1910 while (name != NULL) {
1911 next_name = ISC_LIST_NEXT(name, link);
1913 rdataset = ISC_LIST_HEAD(name->list);
1914 while (rdataset != NULL) {
1915 next_rdataset = ISC_LIST_NEXT(rdataset, link);
1917 if ((rdataset->attributes &
1918 DNS_RDATASETATTR_RENDERED) != 0)
1919 goto next;
1921 if (((options & DNS_MESSAGERENDER_ORDERED)
1922 == 0)
1923 && (sectionid == DNS_SECTION_ADDITIONAL)
1924 && wrong_priority(rdataset, pass,
1925 preferred_glue))
1926 goto next;
1928 st = *(msg->buffer);
1930 count = 0;
1931 if (partial)
1932 result = dns_rdataset_towirepartial(
1933 rdataset,
1934 name,
1935 msg->cctx,
1936 msg->buffer,
1937 msg->order,
1938 msg->order_arg,
1939 rd_options,
1940 &count,
1941 NULL);
1942 else
1943 result = dns_rdataset_towiresorted(
1944 rdataset,
1945 name,
1946 msg->cctx,
1947 msg->buffer,
1948 msg->order,
1949 msg->order_arg,
1950 rd_options,
1951 &count);
1953 total += count;
1956 * If out of space, record stats on what we
1957 * rendered so far, and return that status.
1959 * XXXMLG Need to change this when
1960 * dns_rdataset_towire() can render partial
1961 * sets starting at some arbitrary point in the
1962 * set. This will include setting a bit in the
1963 * rdataset to indicate that a partial
1964 * rendering was done, and some state saved
1965 * somewhere (probably in the message struct)
1966 * to indicate where to continue from.
1968 if (partial && result == ISC_R_NOSPACE) {
1969 msg->buffer->length += msg->reserved;
1970 msg->counts[sectionid] += total;
1971 return (result);
1973 if (result != ISC_R_SUCCESS) {
1974 INSIST(st.used < 65536);
1975 dns_compress_rollback(msg->cctx,
1976 (isc_uint16_t)st.used);
1977 *(msg->buffer) = st; /* rollback */
1978 msg->buffer->length += msg->reserved;
1979 msg->counts[sectionid] += total;
1980 return (result);
1984 * If we have rendered non-validated data,
1985 * ensure that the AD bit is not set.
1987 if (rdataset->trust != dns_trust_secure &&
1988 (sectionid == DNS_SECTION_ANSWER ||
1989 sectionid == DNS_SECTION_AUTHORITY))
1990 msg->flags &= ~DNS_MESSAGEFLAG_AD;
1992 rdataset->attributes |=
1993 DNS_RDATASETATTR_RENDERED;
1995 next:
1996 rdataset = next_rdataset;
1999 name = next_name;
2001 } while (--pass != 0);
2003 msg->buffer->length += msg->reserved;
2004 msg->counts[sectionid] += total;
2006 return (ISC_R_SUCCESS);
2009 void
2010 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2011 isc_uint16_t tmp;
2012 isc_region_t r;
2014 REQUIRE(DNS_MESSAGE_VALID(msg));
2015 REQUIRE(target != NULL);
2017 isc_buffer_availableregion(target, &r);
2018 REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2020 isc_buffer_putuint16(target, msg->id);
2022 tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
2023 & DNS_MESSAGE_OPCODE_MASK);
2024 tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2025 tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2027 INSIST(msg->counts[DNS_SECTION_QUESTION] < 65536 &&
2028 msg->counts[DNS_SECTION_ANSWER] < 65536 &&
2029 msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2030 msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2032 isc_buffer_putuint16(target, tmp);
2033 isc_buffer_putuint16(target,
2034 (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2035 isc_buffer_putuint16(target,
2036 (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2037 isc_buffer_putuint16(target,
2038 (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2039 isc_buffer_putuint16(target,
2040 (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2043 isc_result_t
2044 dns_message_renderend(dns_message_t *msg) {
2045 isc_buffer_t tmpbuf;
2046 isc_region_t r;
2047 int result;
2048 unsigned int count;
2050 REQUIRE(DNS_MESSAGE_VALID(msg));
2051 REQUIRE(msg->buffer != NULL);
2053 if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2055 * We have an extended rcode but are not using EDNS.
2057 return (DNS_R_FORMERR);
2061 * If we've got an OPT record, render it.
2063 if (msg->opt != NULL) {
2064 dns_message_renderrelease(msg, msg->opt_reserved);
2065 msg->opt_reserved = 0;
2067 * Set the extended rcode.
2069 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2070 msg->opt->ttl |= ((msg->rcode << 20) &
2071 DNS_MESSAGE_EDNSRCODE_MASK);
2073 * Render.
2075 count = 0;
2076 result = dns_rdataset_towire(msg->opt, dns_rootname,
2077 msg->cctx, msg->buffer, 0,
2078 &count);
2079 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2080 if (result != ISC_R_SUCCESS)
2081 return (result);
2085 * If we're adding a TSIG or SIG(0) to a truncated message,
2086 * clear all rdatasets from the message except for the question
2087 * before adding the TSIG or SIG(0). If the question doesn't fit,
2088 * don't include it.
2090 if ((msg->tsigkey != NULL || msg->sig0key != NULL) &&
2091 (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2093 isc_buffer_t *buf;
2095 msgresetnames(msg, DNS_SECTION_ANSWER);
2096 buf = msg->buffer;
2097 dns_message_renderreset(msg);
2098 msg->buffer = buf;
2099 isc_buffer_clear(msg->buffer);
2100 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2101 dns_compress_rollback(msg->cctx, 0);
2102 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2104 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2105 return (result);
2109 * If we're adding a TSIG record, generate and render it.
2111 if (msg->tsigkey != NULL) {
2112 dns_message_renderrelease(msg, msg->sig_reserved);
2113 msg->sig_reserved = 0;
2114 result = dns_tsig_sign(msg);
2115 if (result != ISC_R_SUCCESS)
2116 return (result);
2117 count = 0;
2118 result = dns_rdataset_towire(msg->tsig, msg->tsigname,
2119 msg->cctx, msg->buffer, 0,
2120 &count);
2121 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2122 if (result != ISC_R_SUCCESS)
2123 return (result);
2127 * If we're adding a SIG(0) record, generate and render it.
2129 if (msg->sig0key != NULL) {
2130 dns_message_renderrelease(msg, msg->sig_reserved);
2131 msg->sig_reserved = 0;
2132 result = dns_dnssec_signmessage(msg, msg->sig0key);
2133 if (result != ISC_R_SUCCESS)
2134 return (result);
2135 count = 0;
2137 * Note: dns_rootname is used here, not msg->sig0name, since
2138 * the owner name of a SIG(0) is irrelevant, and will not
2139 * be set in a message being rendered.
2141 result = dns_rdataset_towire(msg->sig0, dns_rootname,
2142 msg->cctx, msg->buffer, 0,
2143 &count);
2144 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2145 if (result != ISC_R_SUCCESS)
2146 return (result);
2149 isc_buffer_usedregion(msg->buffer, &r);
2150 isc_buffer_init(&tmpbuf, r.base, r.length);
2152 dns_message_renderheader(msg, &tmpbuf);
2154 msg->buffer = NULL; /* forget about this buffer only on success XXX */
2156 return (ISC_R_SUCCESS);
2159 void
2160 dns_message_renderreset(dns_message_t *msg) {
2161 unsigned int i;
2162 dns_name_t *name;
2163 dns_rdataset_t *rds;
2166 * Reset the message so that it may be rendered again.
2169 REQUIRE(DNS_MESSAGE_VALID(msg));
2170 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2172 msg->buffer = NULL;
2174 for (i = 0; i < DNS_SECTION_MAX; i++) {
2175 msg->cursors[i] = NULL;
2176 msg->counts[i] = 0;
2177 for (name = ISC_LIST_HEAD(msg->sections[i]);
2178 name != NULL;
2179 name = ISC_LIST_NEXT(name, link)) {
2180 for (rds = ISC_LIST_HEAD(name->list);
2181 rds != NULL;
2182 rds = ISC_LIST_NEXT(rds, link)) {
2183 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2187 if (msg->tsigname != NULL)
2188 dns_message_puttempname(msg, &msg->tsigname);
2189 if (msg->tsig != NULL) {
2190 dns_rdataset_disassociate(msg->tsig);
2191 dns_message_puttemprdataset(msg, &msg->tsig);
2193 if (msg->sig0 != NULL) {
2194 dns_rdataset_disassociate(msg->sig0);
2195 dns_message_puttemprdataset(msg, &msg->sig0);
2199 isc_result_t
2200 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2201 REQUIRE(DNS_MESSAGE_VALID(msg));
2202 REQUIRE(VALID_NAMED_SECTION(section));
2204 msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2206 if (msg->cursors[section] == NULL)
2207 return (ISC_R_NOMORE);
2209 return (ISC_R_SUCCESS);
2212 isc_result_t
2213 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2214 REQUIRE(DNS_MESSAGE_VALID(msg));
2215 REQUIRE(VALID_NAMED_SECTION(section));
2216 REQUIRE(msg->cursors[section] != NULL);
2218 msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2220 if (msg->cursors[section] == NULL)
2221 return (ISC_R_NOMORE);
2223 return (ISC_R_SUCCESS);
2226 void
2227 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2228 dns_name_t **name)
2230 REQUIRE(DNS_MESSAGE_VALID(msg));
2231 REQUIRE(VALID_NAMED_SECTION(section));
2232 REQUIRE(name != NULL && *name == NULL);
2233 REQUIRE(msg->cursors[section] != NULL);
2235 *name = msg->cursors[section];
2238 isc_result_t
2239 dns_message_findname(dns_message_t *msg, dns_section_t section,
2240 dns_name_t *target, dns_rdatatype_t type,
2241 dns_rdatatype_t covers, dns_name_t **name,
2242 dns_rdataset_t **rdataset)
2244 dns_name_t *foundname;
2245 isc_result_t result;
2248 * XXX These requirements are probably too intensive, especially
2249 * where things can be NULL, but as they are they ensure that if
2250 * something is NON-NULL, indicating that the caller expects it
2251 * to be filled in, that we can in fact fill it in.
2253 REQUIRE(msg != NULL);
2254 REQUIRE(VALID_SECTION(section));
2255 REQUIRE(target != NULL);
2256 if (name != NULL)
2257 REQUIRE(*name == NULL);
2258 if (type == dns_rdatatype_any) {
2259 REQUIRE(rdataset == NULL);
2260 } else {
2261 if (rdataset != NULL)
2262 REQUIRE(*rdataset == NULL);
2265 result = findname(&foundname, target,
2266 &msg->sections[section]);
2268 if (result == ISC_R_NOTFOUND)
2269 return (DNS_R_NXDOMAIN);
2270 else if (result != ISC_R_SUCCESS)
2271 return (result);
2273 if (name != NULL)
2274 *name = foundname;
2277 * And now look for the type.
2279 if (type == dns_rdatatype_any)
2280 return (ISC_R_SUCCESS);
2282 result = dns_message_findtype(foundname, type, covers, rdataset);
2283 if (result == ISC_R_NOTFOUND)
2284 return (DNS_R_NXRRSET);
2286 return (result);
2289 void
2290 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2291 dns_section_t fromsection,
2292 dns_section_t tosection)
2294 REQUIRE(msg != NULL);
2295 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2296 REQUIRE(name != NULL);
2297 REQUIRE(VALID_NAMED_SECTION(fromsection));
2298 REQUIRE(VALID_NAMED_SECTION(tosection));
2301 * Unlink the name from the old section
2303 ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2304 ISC_LIST_APPEND(msg->sections[tosection], name, link);
2307 void
2308 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2309 dns_section_t section)
2311 REQUIRE(msg != NULL);
2312 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2313 REQUIRE(name != NULL);
2314 REQUIRE(VALID_NAMED_SECTION(section));
2316 ISC_LIST_APPEND(msg->sections[section], name, link);
2319 void
2320 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2321 dns_section_t section)
2323 REQUIRE(msg != NULL);
2324 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2325 REQUIRE(name != NULL);
2326 REQUIRE(VALID_NAMED_SECTION(section));
2328 ISC_LIST_UNLINK(msg->sections[section], name, link);
2331 isc_result_t
2332 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2333 REQUIRE(DNS_MESSAGE_VALID(msg));
2334 REQUIRE(item != NULL && *item == NULL);
2336 *item = isc_mempool_get(msg->namepool);
2337 if (*item == NULL)
2338 return (ISC_R_NOMEMORY);
2339 dns_name_init(*item, NULL);
2341 return (ISC_R_SUCCESS);
2344 isc_result_t
2345 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2346 REQUIRE(DNS_MESSAGE_VALID(msg));
2347 REQUIRE(item != NULL && *item == NULL);
2349 *item = newoffsets(msg);
2350 if (*item == NULL)
2351 return (ISC_R_NOMEMORY);
2353 return (ISC_R_SUCCESS);
2356 isc_result_t
2357 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2358 REQUIRE(DNS_MESSAGE_VALID(msg));
2359 REQUIRE(item != NULL && *item == NULL);
2361 *item = newrdata(msg);
2362 if (*item == NULL)
2363 return (ISC_R_NOMEMORY);
2365 return (ISC_R_SUCCESS);
2368 isc_result_t
2369 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2370 REQUIRE(DNS_MESSAGE_VALID(msg));
2371 REQUIRE(item != NULL && *item == NULL);
2373 *item = isc_mempool_get(msg->rdspool);
2374 if (*item == NULL)
2375 return (ISC_R_NOMEMORY);
2377 dns_rdataset_init(*item);
2379 return (ISC_R_SUCCESS);
2382 isc_result_t
2383 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2384 REQUIRE(DNS_MESSAGE_VALID(msg));
2385 REQUIRE(item != NULL && *item == NULL);
2387 *item = newrdatalist(msg);
2388 if (*item == NULL)
2389 return (ISC_R_NOMEMORY);
2391 return (ISC_R_SUCCESS);
2394 void
2395 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2396 REQUIRE(DNS_MESSAGE_VALID(msg));
2397 REQUIRE(item != NULL && *item != NULL);
2399 if (dns_name_dynamic(*item))
2400 dns_name_free(*item, msg->mctx);
2401 isc_mempool_put(msg->namepool, *item);
2402 *item = NULL;
2405 void
2406 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2407 REQUIRE(DNS_MESSAGE_VALID(msg));
2408 REQUIRE(item != NULL && *item != NULL);
2410 releaserdata(msg, *item);
2411 *item = NULL;
2414 void
2415 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2416 REQUIRE(DNS_MESSAGE_VALID(msg));
2417 REQUIRE(item != NULL && *item != NULL);
2419 REQUIRE(!dns_rdataset_isassociated(*item));
2420 isc_mempool_put(msg->rdspool, *item);
2421 *item = NULL;
2424 void
2425 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2426 REQUIRE(DNS_MESSAGE_VALID(msg));
2427 REQUIRE(item != NULL && *item != NULL);
2429 releaserdatalist(msg, *item);
2430 *item = NULL;
2433 isc_result_t
2434 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2435 unsigned int *flagsp)
2437 isc_region_t r;
2438 isc_buffer_t buffer;
2439 dns_messageid_t id;
2440 unsigned int flags;
2442 REQUIRE(source != NULL);
2444 buffer = *source;
2446 isc_buffer_remainingregion(&buffer, &r);
2447 if (r.length < DNS_MESSAGE_HEADERLEN)
2448 return (ISC_R_UNEXPECTEDEND);
2450 id = isc_buffer_getuint16(&buffer);
2451 flags = isc_buffer_getuint16(&buffer);
2452 flags &= DNS_MESSAGE_FLAG_MASK;
2454 if (flagsp != NULL)
2455 *flagsp = flags;
2456 if (idp != NULL)
2457 *idp = id;
2459 return (ISC_R_SUCCESS);
2462 isc_result_t
2463 dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
2464 unsigned int first_section;
2465 isc_result_t result;
2467 REQUIRE(DNS_MESSAGE_VALID(msg));
2468 REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2470 if (!msg->header_ok)
2471 return (DNS_R_FORMERR);
2472 if (msg->opcode != dns_opcode_query &&
2473 msg->opcode != dns_opcode_notify)
2474 want_question_section = ISC_FALSE;
2475 if (want_question_section) {
2476 if (!msg->question_ok)
2477 return (DNS_R_FORMERR);
2478 first_section = DNS_SECTION_ANSWER;
2479 } else
2480 first_section = DNS_SECTION_QUESTION;
2481 msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2482 msgresetnames(msg, first_section);
2483 msgresetopt(msg);
2484 msgresetsigs(msg, ISC_TRUE);
2485 msginitprivate(msg);
2487 * We now clear most flags and then set QR, ensuring that the
2488 * reply's flags will be in a reasonable state.
2490 msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2491 msg->flags |= DNS_MESSAGEFLAG_QR;
2494 * This saves the query TSIG status, if the query was signed, and
2495 * reserves space in the reply for the TSIG.
2497 if (msg->tsigkey != NULL) {
2498 unsigned int otherlen = 0;
2499 msg->querytsigstatus = msg->tsigstatus;
2500 msg->tsigstatus = dns_rcode_noerror;
2501 if (msg->querytsigstatus == dns_tsigerror_badtime)
2502 otherlen = 6;
2503 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2504 result = dns_message_renderreserve(msg, msg->sig_reserved);
2505 if (result != ISC_R_SUCCESS) {
2506 msg->sig_reserved = 0;
2507 return (result);
2510 if (msg->saved.base != NULL) {
2511 msg->query.base = msg->saved.base;
2512 msg->query.length = msg->saved.length;
2513 msg->free_query = msg->free_saved;
2514 msg->saved.base = NULL;
2515 msg->saved.length = 0;
2516 msg->free_saved = 0;
2519 return (ISC_R_SUCCESS);
2522 dns_rdataset_t *
2523 dns_message_getopt(dns_message_t *msg) {
2526 * Get the OPT record for 'msg'.
2529 REQUIRE(DNS_MESSAGE_VALID(msg));
2531 return (msg->opt);
2534 isc_result_t
2535 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2536 isc_result_t result;
2537 dns_rdata_t rdata = DNS_RDATA_INIT;
2540 * Set the OPT record for 'msg'.
2544 * The space required for an OPT record is:
2546 * 1 byte for the name
2547 * 2 bytes for the type
2548 * 2 bytes for the class
2549 * 4 bytes for the ttl
2550 * 2 bytes for the rdata length
2551 * ---------------------------------
2552 * 11 bytes
2554 * plus the length of the rdata.
2557 REQUIRE(DNS_MESSAGE_VALID(msg));
2558 REQUIRE(opt->type == dns_rdatatype_opt);
2559 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2560 REQUIRE(msg->state == DNS_SECTION_ANY);
2562 msgresetopt(msg);
2564 result = dns_rdataset_first(opt);
2565 if (result != ISC_R_SUCCESS)
2566 goto cleanup;
2567 dns_rdataset_current(opt, &rdata);
2568 msg->opt_reserved = 11 + rdata.length;
2569 result = dns_message_renderreserve(msg, msg->opt_reserved);
2570 if (result != ISC_R_SUCCESS) {
2571 msg->opt_reserved = 0;
2572 goto cleanup;
2575 msg->opt = opt;
2577 return (ISC_R_SUCCESS);
2579 cleanup:
2580 dns_message_puttemprdataset(msg, &opt);
2581 return (result);
2585 dns_rdataset_t *
2586 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2589 * Get the TSIG record and owner for 'msg'.
2592 REQUIRE(DNS_MESSAGE_VALID(msg));
2593 REQUIRE(owner == NULL || *owner == NULL);
2595 if (owner != NULL)
2596 *owner = msg->tsigname;
2597 return (msg->tsig);
2600 isc_result_t
2601 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2602 isc_result_t result;
2605 * Set the TSIG key for 'msg'
2608 REQUIRE(DNS_MESSAGE_VALID(msg));
2609 REQUIRE(msg->state == DNS_SECTION_ANY);
2611 if (key == NULL && msg->tsigkey != NULL) {
2612 if (msg->sig_reserved != 0) {
2613 dns_message_renderrelease(msg, msg->sig_reserved);
2614 msg->sig_reserved = 0;
2616 dns_tsigkey_detach(&msg->tsigkey);
2618 if (key != NULL) {
2619 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2620 dns_tsigkey_attach(key, &msg->tsigkey);
2621 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2622 msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2623 result = dns_message_renderreserve(msg,
2624 msg->sig_reserved);
2625 if (result != ISC_R_SUCCESS) {
2626 dns_tsigkey_detach(&msg->tsigkey);
2627 msg->sig_reserved = 0;
2628 return (result);
2632 return (ISC_R_SUCCESS);
2635 dns_tsigkey_t *
2636 dns_message_gettsigkey(dns_message_t *msg) {
2639 * Get the TSIG key for 'msg'
2642 REQUIRE(DNS_MESSAGE_VALID(msg));
2644 return (msg->tsigkey);
2647 isc_result_t
2648 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2649 dns_rdata_t *rdata = NULL;
2650 dns_rdatalist_t *list = NULL;
2651 dns_rdataset_t *set = NULL;
2652 isc_buffer_t *buf = NULL;
2653 isc_region_t r;
2654 isc_result_t result;
2656 REQUIRE(DNS_MESSAGE_VALID(msg));
2657 REQUIRE(msg->querytsig == NULL);
2659 if (querytsig == NULL)
2660 return (ISC_R_SUCCESS);
2662 result = dns_message_gettemprdata(msg, &rdata);
2663 if (result != ISC_R_SUCCESS)
2664 goto cleanup;
2666 result = dns_message_gettemprdatalist(msg, &list);
2667 if (result != ISC_R_SUCCESS)
2668 goto cleanup;
2669 result = dns_message_gettemprdataset(msg, &set);
2670 if (result != ISC_R_SUCCESS)
2671 goto cleanup;
2673 isc_buffer_usedregion(querytsig, &r);
2674 result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2675 if (result != ISC_R_SUCCESS)
2676 goto cleanup;
2677 isc_buffer_putmem(buf, r.base, r.length);
2678 isc_buffer_usedregion(buf, &r);
2679 dns_rdata_init(rdata);
2680 dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2681 dns_message_takebuffer(msg, &buf);
2682 ISC_LIST_INIT(list->rdata);
2683 ISC_LIST_APPEND(list->rdata, rdata, link);
2684 result = dns_rdatalist_tordataset(list, set);
2685 if (result != ISC_R_SUCCESS)
2686 goto cleanup;
2688 msg->querytsig = set;
2690 return (result);
2692 cleanup:
2693 if (rdata != NULL)
2694 dns_message_puttemprdata(msg, &rdata);
2695 if (list != NULL)
2696 dns_message_puttemprdatalist(msg, &list);
2697 if (set != NULL)
2698 dns_message_puttemprdataset(msg, &set);
2699 return (ISC_R_NOMEMORY);
2702 isc_result_t
2703 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2704 isc_buffer_t **querytsig) {
2705 isc_result_t result;
2706 dns_rdata_t rdata = DNS_RDATA_INIT;
2707 isc_region_t r;
2709 REQUIRE(DNS_MESSAGE_VALID(msg));
2710 REQUIRE(mctx != NULL);
2711 REQUIRE(querytsig != NULL && *querytsig == NULL);
2713 if (msg->tsig == NULL)
2714 return (ISC_R_SUCCESS);
2716 result = dns_rdataset_first(msg->tsig);
2717 if (result != ISC_R_SUCCESS)
2718 return (result);
2719 dns_rdataset_current(msg->tsig, &rdata);
2720 dns_rdata_toregion(&rdata, &r);
2722 result = isc_buffer_allocate(mctx, querytsig, r.length);
2723 if (result != ISC_R_SUCCESS)
2724 return (result);
2725 isc_buffer_putmem(*querytsig, r.base, r.length);
2726 return (ISC_R_SUCCESS);
2729 dns_rdataset_t *
2730 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2733 * Get the SIG(0) record for 'msg'.
2736 REQUIRE(DNS_MESSAGE_VALID(msg));
2737 REQUIRE(owner == NULL || *owner == NULL);
2739 if (msg->sig0 != NULL && owner != NULL) {
2740 /* If dns_message_getsig0 is called on a rendered message
2741 * after the SIG(0) has been applied, we need to return the
2742 * root name, not NULL.
2744 if (msg->sig0name == NULL)
2745 *owner = dns_rootname;
2746 else
2747 *owner = msg->sig0name;
2749 return (msg->sig0);
2752 isc_result_t
2753 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2754 isc_region_t r;
2755 unsigned int x;
2756 isc_result_t result;
2759 * Set the SIG(0) key for 'msg'
2763 * The space required for an SIG(0) record is:
2765 * 1 byte for the name
2766 * 2 bytes for the type
2767 * 2 bytes for the class
2768 * 4 bytes for the ttl
2769 * 2 bytes for the type covered
2770 * 1 byte for the algorithm
2771 * 1 bytes for the labels
2772 * 4 bytes for the original ttl
2773 * 4 bytes for the signature expiration
2774 * 4 bytes for the signature inception
2775 * 2 bytes for the key tag
2776 * n bytes for the signer's name
2777 * x bytes for the signature
2778 * ---------------------------------
2779 * 27 + n + x bytes
2781 REQUIRE(DNS_MESSAGE_VALID(msg));
2782 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2783 REQUIRE(msg->state == DNS_SECTION_ANY);
2785 if (key != NULL) {
2786 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2787 dns_name_toregion(dst_key_name(key), &r);
2788 result = dst_key_sigsize(key, &x);
2789 if (result != ISC_R_SUCCESS) {
2790 msg->sig_reserved = 0;
2791 return (result);
2793 msg->sig_reserved = 27 + r.length + x;
2794 result = dns_message_renderreserve(msg, msg->sig_reserved);
2795 if (result != ISC_R_SUCCESS) {
2796 msg->sig_reserved = 0;
2797 return (result);
2799 msg->sig0key = key;
2801 return (ISC_R_SUCCESS);
2804 dst_key_t *
2805 dns_message_getsig0key(dns_message_t *msg) {
2808 * Get the SIG(0) key for 'msg'
2811 REQUIRE(DNS_MESSAGE_VALID(msg));
2813 return (msg->sig0key);
2816 void
2817 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2818 REQUIRE(DNS_MESSAGE_VALID(msg));
2819 REQUIRE(buffer != NULL);
2820 REQUIRE(ISC_BUFFER_VALID(*buffer));
2822 ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2823 *buffer = NULL;
2826 isc_result_t
2827 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
2828 isc_result_t result = ISC_R_SUCCESS;
2829 dns_rdata_t rdata = DNS_RDATA_INIT;
2831 REQUIRE(DNS_MESSAGE_VALID(msg));
2832 REQUIRE(signer != NULL);
2833 REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2835 if (msg->tsig == NULL && msg->sig0 == NULL)
2836 return (ISC_R_NOTFOUND);
2838 if (msg->verify_attempted == 0)
2839 return (DNS_R_NOTVERIFIEDYET);
2841 if (!dns_name_hasbuffer(signer)) {
2842 isc_buffer_t *dynbuf = NULL;
2843 result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
2844 if (result != ISC_R_SUCCESS)
2845 return (result);
2846 dns_name_setbuffer(signer, dynbuf);
2847 dns_message_takebuffer(msg, &dynbuf);
2850 if (msg->sig0 != NULL) {
2851 dns_rdata_sig_t sig;
2853 result = dns_rdataset_first(msg->sig0);
2854 INSIST(result == ISC_R_SUCCESS);
2855 dns_rdataset_current(msg->sig0, &rdata);
2857 result = dns_rdata_tostruct(&rdata, &sig, NULL);
2858 if (result != ISC_R_SUCCESS)
2859 return (result);
2861 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
2862 result = ISC_R_SUCCESS;
2863 else
2864 result = DNS_R_SIGINVALID;
2865 dns_name_clone(&sig.signer, signer);
2866 dns_rdata_freestruct(&sig);
2867 } else {
2868 dns_name_t *identity;
2869 dns_rdata_any_tsig_t tsig;
2871 result = dns_rdataset_first(msg->tsig);
2872 INSIST(result == ISC_R_SUCCESS);
2873 dns_rdataset_current(msg->tsig, &rdata);
2875 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2876 if (msg->tsigstatus != dns_rcode_noerror)
2877 result = DNS_R_TSIGVERIFYFAILURE;
2878 else if (tsig.error != dns_rcode_noerror)
2879 result = DNS_R_TSIGERRORSET;
2880 else
2881 result = ISC_R_SUCCESS;
2882 dns_rdata_freestruct(&tsig);
2884 if (msg->tsigkey == NULL) {
2886 * If msg->tsigstatus & tsig.error are both
2887 * dns_rcode_noerror, the message must have been
2888 * verified, which means msg->tsigkey will be
2889 * non-NULL.
2891 INSIST(result != ISC_R_SUCCESS);
2892 } else {
2893 identity = dns_tsigkey_identity(msg->tsigkey);
2894 if (identity == NULL) {
2895 if (result == ISC_R_SUCCESS)
2896 result = DNS_R_NOIDENTITY;
2897 identity = &msg->tsigkey->name;
2899 dns_name_clone(identity, signer);
2903 return (result);
2906 void
2907 dns_message_resetsig(dns_message_t *msg) {
2908 REQUIRE(DNS_MESSAGE_VALID(msg));
2909 msg->verified_sig = 0;
2910 msg->verify_attempted = 0;
2911 msg->tsigstatus = dns_rcode_noerror;
2912 msg->sig0status = dns_rcode_noerror;
2913 msg->timeadjust = 0;
2914 if (msg->tsigkey != NULL) {
2915 dns_tsigkey_detach(&msg->tsigkey);
2916 msg->tsigkey = NULL;
2920 isc_result_t
2921 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
2922 dns_message_resetsig(msg);
2923 return (dns_message_checksig(msg, view));
2926 #ifdef SKAN_MSG_DEBUG
2927 void
2928 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
2929 dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
2930 dns_rdata_any_tsig_t querytsig;
2931 isc_result_t result;
2933 if (msg->tsig != NULL) {
2934 result = dns_rdataset_first(msg->tsig);
2935 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2936 dns_rdataset_current(msg->tsig, &querytsigrdata);
2937 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
2938 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2939 hexdump(txt1, "TSIG", querytsig.signature,
2940 querytsig.siglen);
2943 if (msg->querytsig != NULL) {
2944 result = dns_rdataset_first(msg->querytsig);
2945 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2946 dns_rdataset_current(msg->querytsig, &querytsigrdata);
2947 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
2948 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2949 hexdump(txt1, "QUERYTSIG", querytsig.signature,
2950 querytsig.siglen);
2953 #endif
2955 isc_result_t
2956 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
2957 isc_buffer_t b, msgb;
2959 REQUIRE(DNS_MESSAGE_VALID(msg));
2961 if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
2962 return (ISC_R_SUCCESS);
2964 INSIST(msg->saved.base != NULL);
2965 isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
2966 isc_buffer_add(&msgb, msg->saved.length);
2967 if (msg->tsigkey != NULL || msg->tsig != NULL) {
2968 #ifdef SKAN_MSG_DEBUG
2969 dns_message_dumpsig(msg, "dns_message_checksig#1");
2970 #endif
2971 if (view != NULL)
2972 return (dns_view_checksig(view, &msgb, msg));
2973 else
2974 return (dns_tsig_verify(&msgb, msg, NULL, NULL));
2975 } else {
2976 dns_rdata_t rdata = DNS_RDATA_INIT;
2977 dns_rdata_sig_t sig;
2978 dns_rdataset_t keyset;
2979 isc_result_t result;
2981 result = dns_rdataset_first(msg->sig0);
2982 INSIST(result == ISC_R_SUCCESS);
2983 dns_rdataset_current(msg->sig0, &rdata);
2986 * This can occur when the message is a dynamic update, since
2987 * the rdata length checking is relaxed. This should not
2988 * happen in a well-formed message, since the SIG(0) is only
2989 * looked for in the additional section, and the dynamic update
2990 * meta-records are in the prerequisite and update sections.
2992 if (rdata.length == 0)
2993 return (ISC_R_UNEXPECTEDEND);
2995 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
2996 if (result != ISC_R_SUCCESS)
2997 return (result);
2999 dns_rdataset_init(&keyset);
3000 if (view == NULL)
3001 return (DNS_R_KEYUNAUTHORIZED);
3002 result = dns_view_simplefind(view, &sig.signer,
3003 dns_rdatatype_key /* SIG(0) */,
3004 0, 0, ISC_FALSE, &keyset, NULL);
3006 if (result != ISC_R_SUCCESS) {
3007 /* XXXBEW Should possibly create a fetch here */
3008 result = DNS_R_KEYUNAUTHORIZED;
3009 goto freesig;
3010 } else if (keyset.trust < dns_trust_secure) {
3011 /* XXXBEW Should call a validator here */
3012 result = DNS_R_KEYUNAUTHORIZED;
3013 goto freesig;
3015 result = dns_rdataset_first(&keyset);
3016 INSIST(result == ISC_R_SUCCESS);
3017 for (;
3018 result == ISC_R_SUCCESS;
3019 result = dns_rdataset_next(&keyset))
3021 dst_key_t *key = NULL;
3023 dns_rdataset_current(&keyset, &rdata);
3024 isc_buffer_init(&b, rdata.data, rdata.length);
3025 isc_buffer_add(&b, rdata.length);
3027 result = dst_key_fromdns(&sig.signer, rdata.rdclass,
3028 &b, view->mctx, &key);
3029 if (result != ISC_R_SUCCESS)
3030 continue;
3031 if (dst_key_alg(key) != sig.algorithm ||
3032 dst_key_id(key) != sig.keyid ||
3033 !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3034 dst_key_proto(key) == DNS_KEYPROTO_ANY))
3036 dst_key_free(&key);
3037 continue;
3039 result = dns_dnssec_verifymessage(&msgb, msg, key);
3040 dst_key_free(&key);
3041 if (result == ISC_R_SUCCESS)
3042 break;
3044 if (result == ISC_R_NOMORE)
3045 result = DNS_R_KEYUNAUTHORIZED;
3047 freesig:
3048 if (dns_rdataset_isassociated(&keyset))
3049 dns_rdataset_disassociate(&keyset);
3050 dns_rdata_freestruct(&sig);
3051 return (result);
3055 isc_result_t
3056 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3057 const dns_master_style_t *style,
3058 dns_messagetextflag_t flags,
3059 isc_buffer_t *target) {
3060 dns_name_t *name, empty_name;
3061 dns_rdataset_t *rdataset;
3062 isc_result_t result;
3064 REQUIRE(DNS_MESSAGE_VALID(msg));
3065 REQUIRE(target != NULL);
3066 REQUIRE(VALID_SECTION(section));
3068 if (ISC_LIST_EMPTY(msg->sections[section]))
3069 return (ISC_R_SUCCESS);
3071 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3072 ADD_STRING(target, ";; ");
3073 if (msg->opcode != dns_opcode_update) {
3074 ADD_STRING(target, sectiontext[section]);
3075 } else {
3076 ADD_STRING(target, updsectiontext[section]);
3078 ADD_STRING(target, " SECTION:\n");
3081 dns_name_init(&empty_name, NULL);
3082 result = dns_message_firstname(msg, section);
3083 if (result != ISC_R_SUCCESS) {
3084 return (result);
3086 do {
3087 name = NULL;
3088 dns_message_currentname(msg, section, &name);
3089 for (rdataset = ISC_LIST_HEAD(name->list);
3090 rdataset != NULL;
3091 rdataset = ISC_LIST_NEXT(rdataset, link)) {
3092 if (section == DNS_SECTION_QUESTION) {
3093 ADD_STRING(target, ";");
3094 result = dns_master_questiontotext(name,
3095 rdataset,
3096 style,
3097 target);
3098 } else {
3099 result = dns_master_rdatasettotext(name,
3100 rdataset,
3101 style,
3102 target);
3104 if (result != ISC_R_SUCCESS)
3105 return (result);
3107 result = dns_message_nextname(msg, section);
3108 } while (result == ISC_R_SUCCESS);
3109 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3110 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3111 ADD_STRING(target, "\n");
3112 if (result == ISC_R_NOMORE)
3113 result = ISC_R_SUCCESS;
3114 return (result);
3117 isc_result_t
3118 dns_message_pseudosectiontotext(dns_message_t *msg,
3119 dns_pseudosection_t section,
3120 const dns_master_style_t *style,
3121 dns_messagetextflag_t flags,
3122 isc_buffer_t *target) {
3123 dns_rdataset_t *ps = NULL;
3124 dns_name_t *name = NULL;
3125 isc_result_t result;
3126 char buf[sizeof("1234567890")];
3127 isc_uint32_t mbz;
3128 dns_rdata_t rdata;
3129 isc_buffer_t optbuf;
3130 isc_uint16_t optcode, optlen;
3131 unsigned char *optdata;
3133 REQUIRE(DNS_MESSAGE_VALID(msg));
3134 REQUIRE(target != NULL);
3135 REQUIRE(VALID_PSEUDOSECTION(section));
3137 switch (section) {
3138 case DNS_PSEUDOSECTION_OPT:
3139 ps = dns_message_getopt(msg);
3140 if (ps == NULL)
3141 return (ISC_R_SUCCESS);
3142 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3143 ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3144 ADD_STRING(target, "; EDNS: version: ");
3145 snprintf(buf, sizeof(buf), "%u",
3146 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3147 ADD_STRING(target, buf);
3148 ADD_STRING(target, ", flags:");
3149 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3150 ADD_STRING(target, " do");
3151 mbz = ps->ttl & ~DNS_MESSAGEEXTFLAG_DO & 0xffff;
3152 if (mbz != 0) {
3153 ADD_STRING(target, "; MBZ: ");
3154 snprintf(buf, sizeof(buf), "%.4x ", mbz);
3155 ADD_STRING(target, buf);
3156 ADD_STRING(target, ", udp: ");
3157 } else
3158 ADD_STRING(target, "; udp: ");
3159 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3160 ADD_STRING(target, buf);
3162 result = dns_rdataset_first(ps);
3163 if (result != ISC_R_SUCCESS)
3164 return (ISC_R_SUCCESS);
3166 /* Print EDNS info, if any */
3167 dns_rdata_init(&rdata);
3168 dns_rdataset_current(ps, &rdata);
3169 if (rdata.length < 4)
3170 return (ISC_R_SUCCESS);
3172 isc_buffer_init(&optbuf, rdata.data, rdata.length);
3173 isc_buffer_add(&optbuf, rdata.length);
3174 optcode = isc_buffer_getuint16(&optbuf);
3175 optlen = isc_buffer_getuint16(&optbuf);
3177 if (optcode == DNS_OPT_NSID) {
3178 ADD_STRING(target, "; NSID");
3179 } else {
3180 ADD_STRING(target, "; OPT=");
3181 sprintf(buf, "%u", optcode);
3182 ADD_STRING(target, buf);
3185 if (optlen != 0) {
3186 int i;
3187 ADD_STRING(target, ": ");
3189 optdata = rdata.data + 4;
3190 for (i = 0; i < optlen; i++) {
3191 sprintf(buf, "%02x ", optdata[i]);
3192 ADD_STRING(target, buf);
3194 for (i = 0; i < optlen; i++) {
3195 ADD_STRING(target, " (");
3196 if (isprint(optdata[i]))
3197 isc_buffer_putmem(target, &optdata[i],
3199 else
3200 isc_buffer_putstr(target, ".");
3201 ADD_STRING(target, ")");
3204 ADD_STRING(target, "\n");
3205 return (ISC_R_SUCCESS);
3206 case DNS_PSEUDOSECTION_TSIG:
3207 ps = dns_message_gettsig(msg, &name);
3208 if (ps == NULL)
3209 return (ISC_R_SUCCESS);
3210 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3211 ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
3212 result = dns_master_rdatasettotext(name, ps, style, target);
3213 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3214 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3215 ADD_STRING(target, "\n");
3216 return (result);
3217 case DNS_PSEUDOSECTION_SIG0:
3218 ps = dns_message_getsig0(msg, &name);
3219 if (ps == NULL)
3220 return (ISC_R_SUCCESS);
3221 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3222 ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3223 result = dns_master_rdatasettotext(name, ps, style, target);
3224 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3225 (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3226 ADD_STRING(target, "\n");
3227 return (result);
3229 return (ISC_R_UNEXPECTED);
3232 isc_result_t
3233 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3234 dns_messagetextflag_t flags, isc_buffer_t *target) {
3235 char buf[sizeof("1234567890")];
3236 isc_result_t result;
3238 REQUIRE(DNS_MESSAGE_VALID(msg));
3239 REQUIRE(target != NULL);
3241 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
3242 ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
3243 ADD_STRING(target, opcodetext[msg->opcode]);
3244 ADD_STRING(target, ", status: ");
3245 if (msg->rcode < (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
3246 ADD_STRING(target, rcodetext[msg->rcode]);
3247 } else {
3248 snprintf(buf, sizeof(buf), "%4u", msg->rcode);
3249 ADD_STRING(target, buf);
3251 ADD_STRING(target, ", id: ");
3252 snprintf(buf, sizeof(buf), "%6u", msg->id);
3253 ADD_STRING(target, buf);
3254 ADD_STRING(target, "\n;; flags: ");
3255 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3256 ADD_STRING(target, "qr ");
3257 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3258 ADD_STRING(target, "aa ");
3259 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3260 ADD_STRING(target, "tc ");
3261 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3262 ADD_STRING(target, "rd ");
3263 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3264 ADD_STRING(target, "ra ");
3265 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3266 ADD_STRING(target, "ad ");
3267 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
3268 ADD_STRING(target, "cd ");
3269 if (msg->opcode != dns_opcode_update) {
3270 ADD_STRING(target, "; QUESTION: ");
3271 } else {
3272 ADD_STRING(target, "; ZONE: ");
3274 snprintf(buf, sizeof(buf), "%1u",
3275 msg->counts[DNS_SECTION_QUESTION]);
3276 ADD_STRING(target, buf);
3277 if (msg->opcode != dns_opcode_update) {
3278 ADD_STRING(target, ", ANSWER: ");
3279 } else {
3280 ADD_STRING(target, ", PREREQ: ");
3282 snprintf(buf, sizeof(buf), "%1u",
3283 msg->counts[DNS_SECTION_ANSWER]);
3284 ADD_STRING(target, buf);
3285 if (msg->opcode != dns_opcode_update) {
3286 ADD_STRING(target, ", AUTHORITY: ");
3287 } else {
3288 ADD_STRING(target, ", UPDATE: ");
3290 snprintf(buf, sizeof(buf), "%1u",
3291 msg->counts[DNS_SECTION_AUTHORITY]);
3292 ADD_STRING(target, buf);
3293 ADD_STRING(target, ", ADDITIONAL: ");
3294 snprintf(buf, sizeof(buf), "%1u",
3295 msg->counts[DNS_SECTION_ADDITIONAL]);
3296 ADD_STRING(target, buf);
3297 ADD_STRING(target, "\n");
3299 result = dns_message_pseudosectiontotext(msg,
3300 DNS_PSEUDOSECTION_OPT,
3301 style, flags, target);
3302 if (result != ISC_R_SUCCESS)
3303 return (result);
3305 result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
3306 style, flags, target);
3307 if (result != ISC_R_SUCCESS)
3308 return (result);
3309 result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
3310 style, flags, target);
3311 if (result != ISC_R_SUCCESS)
3312 return (result);
3313 result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
3314 style, flags, target);
3315 if (result != ISC_R_SUCCESS)
3316 return (result);
3317 result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
3318 style, flags, target);
3319 if (result != ISC_R_SUCCESS)
3320 return (result);
3322 result = dns_message_pseudosectiontotext(msg,
3323 DNS_PSEUDOSECTION_TSIG,
3324 style, flags, target);
3325 if (result != ISC_R_SUCCESS)
3326 return (result);
3328 result = dns_message_pseudosectiontotext(msg,
3329 DNS_PSEUDOSECTION_SIG0,
3330 style, flags, target);
3331 if (result != ISC_R_SUCCESS)
3332 return (result);
3334 return (ISC_R_SUCCESS);
3337 isc_region_t *
3338 dns_message_getrawmessage(dns_message_t *msg) {
3339 REQUIRE(DNS_MESSAGE_VALID(msg));
3340 return (&msg->saved);
3343 void
3344 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3345 const void *order_arg)
3347 REQUIRE(DNS_MESSAGE_VALID(msg));
3348 msg->order = order;
3349 msg->order_arg = order_arg;
3352 void
3353 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3354 REQUIRE(DNS_MESSAGE_VALID(msg));
3355 msg->timeadjust = timeadjust;
3359 dns_message_gettimeadjust(dns_message_t *msg) {
3360 REQUIRE(DNS_MESSAGE_VALID(msg));
3361 return (msg->timeadjust);
3364 isc_result_t
3365 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3367 REQUIRE(opcode < 16);
3369 if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
3370 return (ISC_R_NOSPACE);
3371 isc_buffer_putstr(target, opcodetext[opcode]);
3372 return (ISC_R_SUCCESS);