Import bind 9.5.2 vendor sources.
[dragonfly.git] / contrib / bind-9.5.2 / lib / dns / message.c
1 /*
2  * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
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.
8  *
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.
16  */
17
18 /* $Id: message.c,v 1.237.110.8 2009/01/19 23:47:02 tbox Exp $ */
19
20 /*! \file */
21
22 /***
23  *** Imports
24  ***/
25
26 #include <config.h>
27 #include <ctype.h>
28
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>
34
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>
48
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;
54
55         p = base;
56         cnt = 0;
57
58         printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base);
59
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++;
68
69                 if (cnt % 16 == 0)
70                         printf("\n");
71         }
72
73         if (cnt % 16 != 0)
74                 printf("\n");
75 }
76 #endif
77
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
86
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))
97
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.
102  */
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
109
110 /*%
111  * Text representation of the different items, for message_totext
112  * functions.
113  */
114 static const char *sectiontext[] = {
115         "QUESTION",
116         "ANSWER",
117         "AUTHORITY",
118         "ADDITIONAL"
119 };
120
121 static const char *updsectiontext[] = {
122         "ZONE",
123         "PREREQUISITE",
124         "UPDATE",
125         "ADDITIONAL"
126 };
127
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"
145 };
146
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"
165 };
166
167
168 /*%
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.
172  */
173 struct dns_msgblock {
174         unsigned int                    count;
175         unsigned int                    remaining;
176         ISC_LINK(dns_msgblock_t)        link;
177 }; /* dynamically sized */
178
179 static inline dns_msgblock_t *
180 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
181
182 #define msgblock_get(block, type) \
183         ((type *)msgblock_internalget(block, sizeof(type)))
184
185 static inline void *
186 msgblock_internalget(dns_msgblock_t *, unsigned int);
187
188 static inline void
189 msgblock_reset(dns_msgblock_t *);
190
191 static inline void
192 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
193
194 /*
195  * Allocate a new dns_msgblock_t, and return a pointer to it.  If no memory
196  * is free, return NULL.
197  */
198 static inline dns_msgblock_t *
199 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
200                   unsigned int count)
201 {
202         dns_msgblock_t *block;
203         unsigned int length;
204
205         length = sizeof(dns_msgblock_t) + (sizeof_type * count);
206
207         block = isc_mem_get(mctx, length);
208         if (block == NULL)
209                 return (NULL);
210
211         block->count = count;
212         block->remaining = count;
213
214         ISC_LINK_INIT(block, link);
215
216         return (block);
217 }
218
219 /*
220  * Return an element from the msgblock.  If no more are available, return
221  * NULL.
222  */
223 static inline void *
224 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
225         void *ptr;
226
227         if (block == NULL || block->remaining == 0)
228                 return (NULL);
229
230         block->remaining--;
231
232         ptr = (((unsigned char *)block)
233                + sizeof(dns_msgblock_t)
234                + (sizeof_type * block->remaining));
235
236         return (ptr);
237 }
238
239 static inline void
240 msgblock_reset(dns_msgblock_t *block) {
241         block->remaining = block->count;
242 }
243
244 /*
245  * Release memory associated with a message block.
246  */
247 static inline void
248 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
249 {
250         unsigned int length;
251
252         length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
253
254         isc_mem_put(mctx, block, length);
255 }
256
257 /*
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)
261  */
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;
266
267         dynbuf = NULL;
268         result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
269         if (result != ISC_R_SUCCESS)
270                 return (ISC_R_NOMEMORY);
271
272         ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
273         return (ISC_R_SUCCESS);
274 }
275
276 static inline isc_buffer_t *
277 currentbuffer(dns_message_t *msg) {
278         isc_buffer_t *dynbuf;
279
280         dynbuf = ISC_LIST_TAIL(msg->scratchpad);
281         INSIST(dynbuf != NULL);
282
283         return (dynbuf);
284 }
285
286 static inline void
287 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
288         ISC_LIST_PREPEND(msg->freerdata, rdata, link);
289 }
290
291 static inline dns_rdata_t *
292 newrdata(dns_message_t *msg) {
293         dns_msgblock_t *msgblock;
294         dns_rdata_t *rdata;
295
296         rdata = ISC_LIST_HEAD(msg->freerdata);
297         if (rdata != NULL) {
298                 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
299                 return (rdata);
300         }
301
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);
309
310                 ISC_LIST_APPEND(msg->rdatas, msgblock, link);
311
312                 rdata = msgblock_get(msgblock, dns_rdata_t);
313         }
314
315         dns_rdata_init(rdata);
316         return (rdata);
317 }
318
319 static inline void
320 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
321         ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
322 }
323
324 static inline dns_rdatalist_t *
325 newrdatalist(dns_message_t *msg) {
326         dns_msgblock_t *msgblock;
327         dns_rdatalist_t *rdatalist;
328
329         rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
330         if (rdatalist != NULL) {
331                 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
332                 return (rdatalist);
333         }
334
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);
343
344                 ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
345
346                 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
347         }
348
349         return (rdatalist);
350 }
351
352 static inline dns_offsets_t *
353 newoffsets(dns_message_t *msg) {
354         dns_msgblock_t *msgblock;
355         dns_offsets_t *offsets;
356
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);
365
366                 ISC_LIST_APPEND(msg->offsets, msgblock, link);
367
368                 offsets = msgblock_get(msgblock, dns_offsets_t);
369         }
370
371         return (offsets);
372 }
373
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;
381 }
382
383 static inline void
384 msginitprivate(dns_message_t *m) {
385         unsigned int i;
386
387         for (i = 0; i < DNS_SECTION_MAX; i++) {
388                 m->cursors[i] = NULL;
389                 m->counts[i] = 0;
390         }
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;
401 }
402
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;
413 }
414
415 /*
416  * Init elements to default state.  Used both when allocating a new element
417  * and when resetting one.
418  */
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;
438 }
439
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;
445
446         /*
447          * Clean up name lists by calling the rdataset disassociate function.
448          */
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);
454
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);
459
460                                 INSIST(dns_rdataset_isassociated(rds));
461                                 dns_rdataset_disassociate(rds);
462                                 isc_mempool_put(msg->rdspool, rds);
463                                 rds = next_rds;
464                         }
465                         if (dns_name_dynamic(name))
466                                 dns_name_free(name, msg->mctx);
467                         isc_mempool_put(msg->namepool, name);
468                         name = next_name;
469                 }
470         }
471 }
472
473 static void
474 msgresetopt(dns_message_t *msg)
475 {
476         if (msg->opt != NULL) {
477                 if (msg->opt_reserved > 0) {
478                         dns_message_renderrelease(msg, msg->opt_reserved);
479                         msg->opt_reserved = 0;
480                 }
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;
485         }
486 }
487
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;
493         }
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);
506                         }
507                 }
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;
517         }
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);
526                 }
527                 msg->sig0 = NULL;
528                 msg->sig0name = NULL;
529         }
530 }
531
532 /*
533  * Free all but one (or everything) for this message.  This is used by
534  * both dns_message_reset() and dns_message_destroy().
535  */
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;
542
543         msgresetnames(msg, 0);
544         msgresetopt(msg);
545         msgresetsigs(msg, ISC_FALSE);
546
547         /*
548          * Clean up linked lists.
549          */
550
551         /*
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.
555          */
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);
560         }
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);
565         }
566
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);
572         }
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;
578         }
579
580         msgblock = ISC_LIST_HEAD(msg->rdatas);
581         if (!everything && msgblock != NULL) {
582                 msgblock_reset(msgblock);
583                 msgblock = ISC_LIST_NEXT(msgblock, link);
584         }
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;
590         }
591
592         /*
593          * rdatalists could be empty.
594          */
595
596         msgblock = ISC_LIST_HEAD(msg->rdatalists);
597         if (!everything && msgblock != NULL) {
598                 msgblock_reset(msgblock);
599                 msgblock = ISC_LIST_NEXT(msgblock, link);
600         }
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;
606         }
607
608         msgblock = ISC_LIST_HEAD(msg->offsets);
609         if (!everything && msgblock != NULL) {
610                 msgblock_reset(msgblock);
611                 msgblock = ISC_LIST_NEXT(msgblock, link);
612         }
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;
618         }
619
620         if (msg->tsigkey != NULL) {
621                 dns_tsigkey_detach(&msg->tsigkey);
622                 msg->tsigkey = NULL;
623         }
624
625         if (msg->tsigctx != NULL)
626                 dst_context_destroy(&msg->tsigctx);
627
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;
634         }
635
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;
642         }
643
644         /*
645          * cleanup the buffer cleanup list
646          */
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;
653         }
654
655         /*
656          * Set other bits to normal default values.
657          */
658         if (!everything)
659                 msginit(msg);
660
661         ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
662         ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
663 }
664
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;
670
671         /*
672          * The space required for an TSIG record is:
673          *
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
690          */
691
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;
700         }
701         return (26 + r1.length + r2.length + x + otherlen);
702 }
703
704 isc_result_t
705 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
706 {
707         dns_message_t *m;
708         isc_result_t result;
709         isc_buffer_t *dynbuf;
710         unsigned int i;
711
712         REQUIRE(mctx != NULL);
713         REQUIRE(msgp != NULL);
714         REQUIRE(*msgp == NULL);
715         REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
716                 || intent == DNS_MESSAGE_INTENTRENDER);
717
718         m = isc_mem_get(mctx, sizeof(dns_message_t));
719         if (m == NULL)
720                 return (ISC_R_NOMEMORY);
721
722         /*
723          * No allocations until further notice.  Just initialize all lists
724          * and other members that are freed in the cleanup phase here.
725          */
726
727         m->magic = DNS_MESSAGE_MAGIC;
728         m->from_to_wire = intent;
729         msginit(m);
730
731         for (i = 0; i < DNS_SECTION_MAX; i++)
732                 ISC_LIST_INIT(m->sections[i]);
733         m->mctx = mctx;
734
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);
744
745         /*
746          * Ok, it is safe to allocate (and then "goto cleanup" if failure)
747          */
748
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");
754
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");
761
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);
767
768         m->cctx = NULL;
769
770         *msgp = m;
771         return (ISC_R_SUCCESS);
772
773         /*
774          * Cleanup for error returns.
775          */
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);
781         }
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));
788
789         return (ISC_R_NOMEMORY);
790 }
791
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);
797
798         msgreset(msg, ISC_FALSE);
799         msg->from_to_wire = intent;
800 }
801
802 void
803 dns_message_destroy(dns_message_t **msgp) {
804         dns_message_t *msg;
805
806         REQUIRE(msgp != NULL);
807         REQUIRE(DNS_MESSAGE_VALID(*msgp));
808
809         msg = *msgp;
810         *msgp = NULL;
811
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));
817 }
818
819 static isc_result_t
820 findname(dns_name_t **foundname, dns_name_t *target,
821          dns_namelist_t *section)
822 {
823         dns_name_t *curr;
824
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);
832                 }
833         }
834
835         return (ISC_R_NOTFOUND);
836 }
837
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)
842 {
843         dns_rdataset_t *curr;
844
845         if (rdataset != NULL) {
846                 REQUIRE(*rdataset == NULL);
847         }
848
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);
857                 }
858         }
859
860         return (ISC_R_NOTFOUND);
861 }
862
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)
866 {
867         dns_rdataset_t *curr;
868
869         REQUIRE(name != NULL);
870         if (rdataset != NULL) {
871                 REQUIRE(*rdataset == NULL);
872         }
873
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);
881                 }
882         }
883
884         return (ISC_R_NOTFOUND);
885 }
886
887 /*
888  * Read a name from buffer "source".
889  */
890 static isc_result_t
891 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
892         dns_decompress_t *dctx)
893 {
894         isc_buffer_t *scratch;
895         isc_result_t result;
896         unsigned int tries;
897
898         scratch = currentbuffer(msg);
899
900         /*
901          * First try:  use current buffer.
902          * Second try:  allocate a new buffer and use that.
903          */
904         tries = 0;
905         while (tries < 2) {
906                 result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
907                                            scratch);
908
909                 if (result == ISC_R_NOSPACE) {
910                         tries++;
911
912                         result = newbuffer(msg, SCRATCHPAD_SIZE);
913                         if (result != ISC_R_SUCCESS)
914                                 return (result);
915
916                         scratch = currentbuffer(msg);
917                         dns_name_reset(name);
918                 } else {
919                         return (result);
920                 }
921         }
922
923         INSIST(0);  /* Cannot get here... */
924         return (ISC_R_UNEXPECTED);
925 }
926
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)
931 {
932         isc_buffer_t *scratch;
933         isc_result_t result;
934         unsigned int tries;
935         unsigned int trysize;
936
937         scratch = currentbuffer(msg);
938
939         isc_buffer_setactive(source, rdatalen);
940
941         /*
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.
947          */
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);
955
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;
967                         }
968                         tries++;
969                         result = newbuffer(msg, trysize);
970                         if (result != ISC_R_SUCCESS)
971                                 return (result);
972
973                         scratch = currentbuffer(msg);
974                 } else {
975                         return (result);
976                 }
977         }
978 }
979
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;                   \
987                 }                                       \
988         } while (0)
989
990 static isc_result_t
991 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
992              unsigned int options)
993 {
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;
1008
1009         section = &msg->sections[DNS_SECTION_QUESTION];
1010
1011         best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1012         seen_problem = ISC_FALSE;
1013
1014         name = NULL;
1015         rdataset = NULL;
1016         rdatalist = NULL;
1017
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;
1023
1024                 offsets = newoffsets(msg);
1025                 if (offsets == NULL) {
1026                         result = ISC_R_NOMEMORY;
1027                         goto cleanup;
1028                 }
1029                 dns_name_init(name, *offsets);
1030
1031                 /*
1032                  * Parse the name out of this packet.
1033                  */
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;
1039
1040                 /*
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.
1045                  */
1046                 result = findname(&name2, name, section);
1047
1048                 /*
1049                  * If it is the first name in the section, accept it.
1050                  *
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.
1057                  */
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;
1068                 }
1069
1070                 /*
1071                  * Get type and class.
1072                  */
1073                 isc_buffer_remainingregion(source, &r);
1074                 if (r.length < 4) {
1075                         result = ISC_R_UNEXPECTEDEND;
1076                         goto cleanup;
1077                 }
1078                 rdtype = isc_buffer_getuint16(source);
1079                 rdclass = isc_buffer_getuint16(source);
1080
1081                 /*
1082                  * If this class is different than the one we already read,
1083                  * this is an error.
1084                  */
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;
1090
1091                 /*
1092                  * Can't ask the same question twice.
1093                  */
1094                 result = dns_message_find(name, rdclass, rdtype, 0, NULL);
1095                 if (result == ISC_R_SUCCESS)
1096                         DO_FORMERR;
1097
1098                 /*
1099                  * Allocate a new rdatalist.
1100                  */
1101                 rdatalist = newrdatalist(msg);
1102                 if (rdatalist == NULL) {
1103                         result = ISC_R_NOMEMORY;
1104                         goto cleanup;
1105                 }
1106                 rdataset =  isc_mempool_get(msg->rdspool);
1107                 if (rdataset == NULL) {
1108                         result = ISC_R_NOMEMORY;
1109                         goto cleanup;
1110                 }
1111
1112                 /*
1113                  * Convert rdatalist to rdataset, and attach the latter to
1114                  * the name.
1115                  */
1116                 rdatalist->type = rdtype;
1117                 rdatalist->covers = 0;
1118                 rdatalist->rdclass = rdclass;
1119                 rdatalist->ttl = 0;
1120                 ISC_LIST_INIT(rdatalist->rdata);
1121
1122                 dns_rdataset_init(rdataset);
1123                 result = dns_rdatalist_tordataset(rdatalist, rdataset);
1124                 if (result != ISC_R_SUCCESS)
1125                         goto cleanup;
1126
1127                 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1128
1129                 ISC_LIST_APPEND(name->list, rdataset, link);
1130                 rdataset = NULL;
1131         }
1132
1133         if (seen_problem)
1134                 return (DNS_R_RECOVERABLE);
1135         return (ISC_R_SUCCESS);
1136
1137  cleanup:
1138         if (rdataset != NULL) {
1139                 INSIST(!dns_rdataset_isassociated(rdataset));
1140                 isc_mempool_put(msg->rdspool, rdataset);
1141         }
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);
1148
1149         return (result);
1150 }
1151
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);
1160 }
1161
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)
1165 {
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;
1182
1183         preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
1184         best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1185         seen_problem = ISC_FALSE;
1186
1187         for (count = 0; count < msg->counts[sectionid]; count++) {
1188                 int recstart = source->current;
1189                 isc_boolean_t skip_name_search, skip_type_search;
1190
1191                 section = &msg->sections[sectionid];
1192
1193                 skip_name_search = ISC_FALSE;
1194                 skip_type_search = ISC_FALSE;
1195                 free_name = ISC_FALSE;
1196                 free_rdataset = ISC_FALSE;
1197
1198                 name = isc_mempool_get(msg->namepool);
1199                 if (name == NULL)
1200                         return (ISC_R_NOMEMORY);
1201                 free_name = ISC_TRUE;
1202
1203                 offsets = newoffsets(msg);
1204                 if (offsets == NULL) {
1205                         result = ISC_R_NOMEMORY;
1206                         goto cleanup;
1207                 }
1208                 dns_name_init(name, *offsets);
1209
1210                 /*
1211                  * Parse the name out of this packet.
1212                  */
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;
1218
1219                 /*
1220                  * Get type, class, ttl, and rdatalen.  Verify that at least
1221                  * rdatalen bytes remain.  (Some of this is deferred to
1222                  * later.)
1223                  */
1224                 isc_buffer_remainingregion(source, &r);
1225                 if (r.length < 2 + 2 + 4 + 2) {
1226                         result = ISC_R_UNEXPECTEDEND;
1227                         goto cleanup;
1228                 }
1229                 rdtype = isc_buffer_getuint16(source);
1230                 rdclass = isc_buffer_getuint16(source);
1231
1232                 /*
1233                  * If there was no question section, we may not yet have
1234                  * established a class.  Do so now.
1235                  */
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;
1242                 }
1243
1244                 /*
1245                  * If this class is different than the one in the question
1246                  * section, bail.
1247                  */
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;
1257
1258                 /*
1259                  * Special type handling for TSIG, OPT, and TKEY.
1260                  */
1261                 if (rdtype == dns_rdatatype_tsig) {
1262                         /*
1263                          * If it is a tsig, verify that it is in the
1264                          * additional data section.
1265                          */
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) {
1274                         /*
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.
1278                          */
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) {
1285                         /*
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.
1289                          *
1290                          * Its class is ignored.
1291                          */
1292                         dns_section_t tkeysection;
1293
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;
1301                 }
1302
1303                 /*
1304                  * ... now get ttl and rdatalen, and check buffer.
1305                  */
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;
1312                 }
1313
1314                 /*
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.
1319                  */
1320                 rdata = newrdata(msg);
1321                 if (rdata == NULL) {
1322                         result = ISC_R_NOMEMORY;
1323                         goto cleanup;
1324                 }
1325                 if (msg->opcode == dns_opcode_update &&
1326                     update(sectionid, rdclass)) {
1327                         if (rdatalen != 0) {
1328                                 result = DNS_R_FORMERR;
1329                                 goto cleanup;
1330                         }
1331                         /*
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.
1337                          */
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;
1372                         }
1373                 } else
1374                         covers = 0;
1375
1376                 /*
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.
1380                  */
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)
1386                         {
1387                                 ISC_LIST_APPEND(*section, name, link);
1388                                 free_name = ISC_FALSE;
1389                         }
1390                 } else {
1391                         /*
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.
1396                          */
1397                         result = findname(&name2, name, section);
1398
1399                         /*
1400                          * If it is a new name, append to the section.
1401                          */
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);
1407                         }
1408                         free_name = ISC_FALSE;
1409                 }
1410
1411                 /*
1412                  * Search name for the particular type and class.
1413                  * Skip this stage if in update mode or this is a meta-type.
1414                  */
1415                 if (preserve_order || msg->opcode == dns_opcode_update ||
1416                     skip_type_search)
1417                         result = ISC_R_NOTFOUND;
1418                 else {
1419                         /*
1420                          * If this is a type that can only occur in
1421                          * the question section, fail.
1422                          */
1423                         if (dns_rdatatype_questiononly(rdtype))
1424                                 DO_FORMERR;
1425
1426                         rdataset = NULL;
1427                         result = dns_message_find(name, rdclass, rdtype,
1428                                                    covers, &rdataset);
1429                 }
1430
1431                 /*
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.
1438                  *
1439                  * Note that this check will be bypassed when preserving order,
1440                  * the opcode is an update, or the type search is skipped.
1441                  */
1442                 if (result == ISC_R_SUCCESS) {
1443                         if (dns_rdatatype_issingleton(rdtype))
1444                                 DO_FORMERR;
1445                 }
1446
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;
1452                         }
1453                         free_rdataset = ISC_TRUE;
1454
1455                         rdatalist = newrdatalist(msg);
1456                         if (rdatalist == NULL) {
1457                                 result = ISC_R_NOMEMORY;
1458                                 goto cleanup;
1459                         }
1460
1461                         rdatalist->type = rdtype;
1462                         rdatalist->covers = covers;
1463                         rdatalist->rdclass = rdclass;
1464                         rdatalist->ttl = ttl;
1465                         ISC_LIST_INIT(rdatalist->rdata);
1466
1467                         dns_rdataset_init(rdataset);
1468                         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1469                                                                rdataset)
1470                                       == ISC_R_SUCCESS);
1471
1472                         if (rdtype != dns_rdatatype_opt &&
1473                             rdtype != dns_rdatatype_tsig &&
1474                             !issigzero)
1475                         {
1476                                 ISC_LIST_APPEND(name->list, rdataset, link);
1477                                 free_rdataset = ISC_FALSE;
1478                         }
1479                 }
1480
1481                 /*
1482                  * Minimize TTLs.
1483                  *
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.
1488                  */
1489                 if (ttl != rdataset->ttl) {
1490                         rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1491                         if (ttl < rdataset->ttl)
1492                                 rdataset->ttl = ttl;
1493                 }
1494
1495                 /* Append this rdata to the rdataset. */
1496                 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1497                 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1498
1499                 /*
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.
1503                  */
1504                 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1505                         dns_rcode_t ercode;
1506
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;
1516                 }
1517
1518                 /*
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.
1522                  */
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;
1535                 }
1536
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;
1543                 }
1544                 INSIST(free_name == ISC_FALSE);
1545                 INSIST(free_rdataset == ISC_FALSE);
1546         }
1547
1548         if (seen_problem)
1549                 return (DNS_R_RECOVERABLE);
1550         return (ISC_R_SUCCESS);
1551
1552  cleanup:
1553         if (free_name)
1554                 isc_mempool_put(msg->namepool, name);
1555         if (free_rdataset)
1556                 isc_mempool_put(msg->rdspool, rdataset);
1557
1558         return (result);
1559 }
1560
1561 isc_result_t
1562 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1563                   unsigned int options)
1564 {
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;
1572
1573         REQUIRE(DNS_MESSAGE_VALID(msg));
1574         REQUIRE(source != NULL);
1575         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1576
1577         seen_problem = ISC_FALSE;
1578         ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1579
1580         origsource = *source;
1581
1582         msg->header_ok = 0;
1583         msg->question_ok = 0;
1584
1585         isc_buffer_remainingregion(source, &r);
1586         if (r.length < DNS_MESSAGE_HEADERLEN)
1587                 return (ISC_R_UNEXPECTEDEND);
1588
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);
1599
1600         msg->header_ok = 1;
1601
1602         /*
1603          * -1 means no EDNS.
1604          */
1605         dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1606
1607         dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1608
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;
1615         }
1616         if (ret != ISC_R_SUCCESS)
1617                 return (ret);
1618         msg->question_ok = 1;
1619
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;
1626         }
1627         if (ret != ISC_R_SUCCESS)
1628                 return (ret);
1629
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;
1636         }
1637         if (ret != ISC_R_SUCCESS)
1638                 return (ret);
1639
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;
1646         }
1647         if (ret != ISC_R_SUCCESS)
1648                 return (ret);
1649
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);
1656         }
1657
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;
1669         }
1670
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);
1676 }
1677
1678 isc_result_t
1679 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1680                         isc_buffer_t *buffer)
1681 {
1682         isc_region_t r;
1683
1684         REQUIRE(DNS_MESSAGE_VALID(msg));
1685         REQUIRE(buffer != NULL);
1686         REQUIRE(msg->buffer == NULL);
1687         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1688
1689         msg->cctx = cctx;
1690
1691         /*
1692          * Erase the contents of this buffer.
1693          */
1694         isc_buffer_clear(buffer);
1695
1696         /*
1697          * Make certain there is enough for at least the header in this
1698          * buffer.
1699          */
1700         isc_buffer_availableregion(buffer, &r);
1701         if (r.length < DNS_MESSAGE_HEADERLEN)
1702                 return (ISC_R_NOSPACE);
1703
1704         if (r.length < msg->reserved)
1705                 return (ISC_R_NOSPACE);
1706
1707         /*
1708          * Reserve enough space for the header in this buffer.
1709          */
1710         isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1711
1712         msg->buffer = buffer;
1713
1714         return (ISC_R_SUCCESS);
1715 }
1716
1717 isc_result_t
1718 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1719         isc_region_t r, rn;
1720
1721         REQUIRE(DNS_MESSAGE_VALID(msg));
1722         REQUIRE(buffer != NULL);
1723         REQUIRE(msg->buffer != NULL);
1724
1725         /*
1726          * Ensure that the new buffer is empty, and has enough space to
1727          * hold the current contents.
1728          */
1729         isc_buffer_clear(buffer);
1730
1731         isc_buffer_availableregion(buffer, &rn);
1732         isc_buffer_usedregion(msg->buffer, &r);
1733         REQUIRE(rn.length > r.length);
1734
1735         /*
1736          * Copy the contents from the old to the new buffer.
1737          */
1738         isc_buffer_add(buffer, r.length);
1739         memcpy(rn.base, r.base, r.length);
1740
1741         msg->buffer = buffer;
1742
1743         return (ISC_R_SUCCESS);
1744 }
1745
1746 void
1747 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1748         REQUIRE(DNS_MESSAGE_VALID(msg));
1749         REQUIRE(space <= msg->reserved);
1750
1751         msg->reserved -= space;
1752 }
1753
1754 isc_result_t
1755 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1756         isc_region_t r;
1757
1758         REQUIRE(DNS_MESSAGE_VALID(msg));
1759
1760         if (msg->buffer != NULL) {
1761                 isc_buffer_availableregion(msg->buffer, &r);
1762                 if (r.length < (space + msg->reserved))
1763                         return (ISC_R_NOSPACE);
1764         }
1765
1766         msg->reserved += space;
1767
1768         return (ISC_R_SUCCESS);
1769 }
1770
1771 static inline isc_boolean_t
1772 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1773         int pass_needed;
1774
1775         /*
1776          * If we are not rendering class IN, this ordering is bogus.
1777          */
1778         if (rds->rdclass != dns_rdataclass_in)
1779                 return (ISC_FALSE);
1780
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;
1795         }
1796
1797         if (pass_needed >= pass)
1798                 return (ISC_FALSE);
1799
1800         return (ISC_TRUE);
1801 }
1802
1803 isc_result_t
1804 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1805                           unsigned int options)
1806 {
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;
1817
1818         REQUIRE(DNS_MESSAGE_VALID(msg));
1819         REQUIRE(msg->buffer != NULL);
1820         REQUIRE(VALID_NAMED_SECTION(sectionid));
1821
1822         section = &msg->sections[sectionid];
1823
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;
1836
1837         if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1838                 rd_options = 0;
1839         else
1840                 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1841
1842         /*
1843          * Shrink the space in the buffer by the reserved amount.
1844          */
1845         msg->buffer->length -= msg->reserved;
1846
1847         total = 0;
1848         if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1849                 partial = ISC_TRUE;
1850
1851         /*
1852          * Render required glue first.  Set TC if it won't fit.
1853          */
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);
1888                         }
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);
1897                         }
1898                         rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
1899                 }
1900         }
1901
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);
1908                 }
1909
1910                 while (name != NULL) {
1911                         next_name = ISC_LIST_NEXT(name, link);
1912
1913                         rdataset = ISC_LIST_HEAD(name->list);
1914                         while (rdataset != NULL) {
1915                                 next_rdataset = ISC_LIST_NEXT(rdataset, link);
1916
1917                                 if ((rdataset->attributes &
1918                                      DNS_RDATASETATTR_RENDERED) != 0)
1919                                         goto next;
1920
1921                                 if (((options & DNS_MESSAGERENDER_ORDERED)
1922                                      == 0)
1923                                     && (sectionid == DNS_SECTION_ADDITIONAL)
1924                                     && wrong_priority(rdataset, pass,
1925                                                       preferred_glue))
1926                                         goto next;
1927
1928                                 st = *(msg->buffer);
1929
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);
1952
1953                                 total += count;
1954
1955                                 /*
1956                                  * If out of space, record stats on what we
1957                                  * rendered so far, and return that status.
1958                                  *
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.
1967                                  */
1968                                 if (partial && result == ISC_R_NOSPACE) {
1969                                         msg->buffer->length += msg->reserved;
1970                                         msg->counts[sectionid] += total;
1971                                         return (result);
1972                                 }
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);
1981                                 }
1982
1983                                 /*
1984                                  * If we have rendered non-validated data,
1985                                  * ensure that the AD bit is not set.
1986                                  */
1987                                 if (rdataset->trust != dns_trust_secure &&
1988                                     (sectionid == DNS_SECTION_ANSWER ||
1989                                      sectionid == DNS_SECTION_AUTHORITY))
1990                                         msg->flags &= ~DNS_MESSAGEFLAG_AD;
1991
1992                                 rdataset->attributes |=
1993                                         DNS_RDATASETATTR_RENDERED;
1994
1995                         next:
1996                                 rdataset = next_rdataset;
1997                         }
1998
1999                         name = next_name;
2000                 }
2001         } while (--pass != 0);
2002
2003         msg->buffer->length += msg->reserved;
2004         msg->counts[sectionid] += total;
2005
2006         return (ISC_R_SUCCESS);
2007 }
2008
2009 void
2010 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2011         isc_uint16_t tmp;
2012         isc_region_t r;
2013
2014         REQUIRE(DNS_MESSAGE_VALID(msg));
2015         REQUIRE(target != NULL);
2016
2017         isc_buffer_availableregion(target, &r);
2018         REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2019
2020         isc_buffer_putuint16(target, msg->id);
2021
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);
2026
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);
2031
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]);
2041 }
2042
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;
2049
2050         REQUIRE(DNS_MESSAGE_VALID(msg));
2051         REQUIRE(msg->buffer != NULL);
2052
2053         if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2054                 /*
2055                  * We have an extended rcode but are not using EDNS.
2056                  */
2057                 return (DNS_R_FORMERR);
2058         }
2059
2060         /*
2061          * If we've got an OPT record, render it.
2062          */
2063         if (msg->opt != NULL) {
2064                 dns_message_renderrelease(msg, msg->opt_reserved);
2065                 msg->opt_reserved = 0;
2066                 /*
2067                  * Set the extended rcode.
2068                  */
2069                 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2070                 msg->opt->ttl |= ((msg->rcode << 20) &
2071                                   DNS_MESSAGE_EDNSRCODE_MASK);
2072                 /*
2073                  * Render.
2074                  */
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);
2082         }
2083
2084         /*
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.
2089          */
2090         if ((msg->tsigkey != NULL || msg->sig0key != NULL) &&
2091             (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2092         {
2093                 isc_buffer_t *buf;
2094
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,
2103                                                    0);
2104                 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2105                         return (result);
2106         }
2107
2108         /*
2109          * If we're adding a TSIG record, generate and render it.
2110          */
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);
2124         }
2125
2126         /*
2127          * If we're adding a SIG(0) record, generate and render it.
2128          */
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;
2136                 /*
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.
2140                  */
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);
2147         }
2148
2149         isc_buffer_usedregion(msg->buffer, &r);
2150         isc_buffer_init(&tmpbuf, r.base, r.length);
2151
2152         dns_message_renderheader(msg, &tmpbuf);
2153
2154         msg->buffer = NULL;  /* forget about this buffer only on success XXX */
2155
2156         return (ISC_R_SUCCESS);
2157 }
2158
2159 void
2160 dns_message_renderreset(dns_message_t *msg) {
2161         unsigned int i;
2162         dns_name_t *name;
2163         dns_rdataset_t *rds;
2164
2165         /*
2166          * Reset the message so that it may be rendered again.
2167          */
2168
2169         REQUIRE(DNS_MESSAGE_VALID(msg));
2170         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2171
2172         msg->buffer = NULL;
2173
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;
2184                         }
2185                 }
2186         }
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);
2192         }
2193         if (msg->sig0 != NULL) {
2194                 dns_rdataset_disassociate(msg->sig0);
2195                 dns_message_puttemprdataset(msg, &msg->sig0);
2196         }
2197 }
2198
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));
2203
2204         msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2205
2206         if (msg->cursors[section] == NULL)
2207                 return (ISC_R_NOMORE);
2208
2209         return (ISC_R_SUCCESS);
2210 }
2211
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);
2217
2218         msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2219
2220         if (msg->cursors[section] == NULL)
2221                 return (ISC_R_NOMORE);
2222
2223         return (ISC_R_SUCCESS);
2224 }
2225
2226 void
2227 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2228                         dns_name_t **name)
2229 {
2230         REQUIRE(DNS_MESSAGE_VALID(msg));
2231         REQUIRE(VALID_NAMED_SECTION(section));
2232         REQUIRE(name != NULL && *name == NULL);
2233         REQUIRE(msg->cursors[section] != NULL);
2234
2235         *name = msg->cursors[section];
2236 }
2237
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)
2243 {
2244         dns_name_t *foundname;
2245         isc_result_t result;
2246
2247         /*
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.
2252          */
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);
2263         }
2264
2265         result = findname(&foundname, target,
2266                           &msg->sections[section]);
2267
2268         if (result == ISC_R_NOTFOUND)
2269                 return (DNS_R_NXDOMAIN);
2270         else if (result != ISC_R_SUCCESS)
2271                 return (result);
2272
2273         if (name != NULL)
2274                 *name = foundname;
2275
2276         /*
2277          * And now look for the type.
2278          */
2279         if (type == dns_rdatatype_any)
2280                 return (ISC_R_SUCCESS);
2281
2282         result = dns_message_findtype(foundname, type, covers, rdataset);
2283         if (result == ISC_R_NOTFOUND)
2284                 return (DNS_R_NXRRSET);
2285
2286         return (result);
2287 }
2288
2289 void
2290 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2291                      dns_section_t fromsection,
2292                      dns_section_t tosection)
2293 {
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));
2299
2300         /*
2301          * Unlink the name from the old section
2302          */
2303         ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2304         ISC_LIST_APPEND(msg->sections[tosection], name, link);
2305 }
2306
2307 void
2308 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2309                     dns_section_t section)
2310 {
2311         REQUIRE(msg != NULL);
2312         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2313         REQUIRE(name != NULL);
2314         REQUIRE(VALID_NAMED_SECTION(section));
2315
2316         ISC_LIST_APPEND(msg->sections[section], name, link);
2317 }
2318
2319 void
2320 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2321                        dns_section_t section)
2322 {
2323         REQUIRE(msg != NULL);
2324         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2325         REQUIRE(name != NULL);
2326         REQUIRE(VALID_NAMED_SECTION(section));
2327
2328         ISC_LIST_UNLINK(msg->sections[section], name, link);
2329 }
2330
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);
2335
2336         *item = isc_mempool_get(msg->namepool);
2337         if (*item == NULL)
2338                 return (ISC_R_NOMEMORY);
2339         dns_name_init(*item, NULL);
2340
2341         return (ISC_R_SUCCESS);
2342 }
2343
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);
2348
2349         *item = newoffsets(msg);
2350         if (*item == NULL)
2351                 return (ISC_R_NOMEMORY);
2352
2353         return (ISC_R_SUCCESS);
2354 }
2355
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);
2360
2361         *item = newrdata(msg);
2362         if (*item == NULL)
2363                 return (ISC_R_NOMEMORY);
2364
2365         return (ISC_R_SUCCESS);
2366 }
2367
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);
2372
2373         *item = isc_mempool_get(msg->rdspool);
2374         if (*item == NULL)
2375                 return (ISC_R_NOMEMORY);
2376
2377         dns_rdataset_init(*item);
2378
2379         return (ISC_R_SUCCESS);
2380 }
2381
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);
2386
2387         *item = newrdatalist(msg);
2388         if (*item == NULL)
2389                 return (ISC_R_NOMEMORY);
2390
2391         return (ISC_R_SUCCESS);
2392 }
2393
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);
2398
2399         if (dns_name_dynamic(*item))
2400                 dns_name_free(*item, msg->mctx);
2401         isc_mempool_put(msg->namepool, *item);
2402         *item = NULL;
2403 }
2404
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);
2409
2410         releaserdata(msg, *item);
2411         *item = NULL;
2412 }
2413
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);
2418
2419         REQUIRE(!dns_rdataset_isassociated(*item));
2420         isc_mempool_put(msg->rdspool, *item);
2421         *item = NULL;
2422 }
2423
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);
2428
2429         releaserdatalist(msg, *item);
2430         *item = NULL;
2431 }
2432
2433 isc_result_t
2434 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2435                        unsigned int *flagsp)
2436 {
2437         isc_region_t r;
2438         isc_buffer_t buffer;
2439         dns_messageid_t id;
2440         unsigned int flags;
2441
2442         REQUIRE(source != NULL);
2443
2444         buffer = *source;
2445
2446         isc_buffer_remainingregion(&buffer, &r);
2447         if (r.length < DNS_MESSAGE_HEADERLEN)
2448                 return (ISC_R_UNEXPECTEDEND);
2449
2450         id = isc_buffer_getuint16(&buffer);
2451         flags = isc_buffer_getuint16(&buffer);
2452         flags &= DNS_MESSAGE_FLAG_MASK;
2453
2454         if (flagsp != NULL)
2455                 *flagsp = flags;
2456         if (idp != NULL)
2457                 *idp = id;
2458
2459         return (ISC_R_SUCCESS);
2460 }
2461
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;
2466
2467         REQUIRE(DNS_MESSAGE_VALID(msg));
2468         REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2469
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);
2486         /*
2487          * We now clear most flags and then set QR, ensuring that the
2488          * reply's flags will be in a reasonable state.
2489          */
2490         msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2491         msg->flags |= DNS_MESSAGEFLAG_QR;
2492
2493         /*
2494          * This saves the query TSIG status, if the query was signed, and
2495          * reserves space in the reply for the TSIG.
2496          */
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);
2508                 }
2509         }
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;
2517         }
2518
2519         return (ISC_R_SUCCESS);
2520 }
2521
2522 dns_rdataset_t *
2523 dns_message_getopt(dns_message_t *msg) {
2524
2525         /*
2526          * Get the OPT record for 'msg'.
2527          */
2528
2529         REQUIRE(DNS_MESSAGE_VALID(msg));
2530
2531         return (msg->opt);
2532 }
2533
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;
2538
2539         /*
2540          * Set the OPT record for 'msg'.
2541          */
2542
2543         /*
2544          * The space required for an OPT record is:
2545          *
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
2553          *
2554          * plus the length of the rdata.
2555          */
2556
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);
2561
2562         msgresetopt(msg);
2563
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;
2573         }
2574
2575         msg->opt = opt;
2576
2577         return (ISC_R_SUCCESS);
2578
2579  cleanup:
2580         dns_message_puttemprdataset(msg, &opt);
2581         return (result);
2582
2583 }
2584
2585 dns_rdataset_t *
2586 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2587
2588         /*
2589          * Get the TSIG record and owner for 'msg'.
2590          */
2591
2592         REQUIRE(DNS_MESSAGE_VALID(msg));
2593         REQUIRE(owner == NULL || *owner == NULL);
2594
2595         if (owner != NULL)
2596                 *owner = msg->tsigname;
2597         return (msg->tsig);
2598 }
2599
2600 isc_result_t
2601 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2602         isc_result_t result;
2603
2604         /*
2605          * Set the TSIG key for 'msg'
2606          */
2607
2608         REQUIRE(DNS_MESSAGE_VALID(msg));
2609         REQUIRE(msg->state == DNS_SECTION_ANY);
2610
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;
2615                 }
2616                 dns_tsigkey_detach(&msg->tsigkey);
2617         }
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);
2629                         }
2630                 }
2631         }
2632         return (ISC_R_SUCCESS);
2633 }
2634
2635 dns_tsigkey_t *
2636 dns_message_gettsigkey(dns_message_t *msg) {
2637
2638         /*
2639          * Get the TSIG key for 'msg'
2640          */
2641
2642         REQUIRE(DNS_MESSAGE_VALID(msg));
2643
2644         return (msg->tsigkey);
2645 }
2646
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;
2655
2656         REQUIRE(DNS_MESSAGE_VALID(msg));
2657         REQUIRE(msg->querytsig == NULL);
2658
2659         if (querytsig == NULL)
2660                 return (ISC_R_SUCCESS);
2661
2662         result = dns_message_gettemprdata(msg, &rdata);
2663         if (result != ISC_R_SUCCESS)
2664                 goto cleanup;
2665
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;
2672
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;
2687
2688         msg->querytsig = set;
2689
2690         return (result);
2691
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);
2700 }
2701
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;
2708
2709         REQUIRE(DNS_MESSAGE_VALID(msg));
2710         REQUIRE(mctx != NULL);
2711         REQUIRE(querytsig != NULL && *querytsig == NULL);
2712
2713         if (msg->tsig == NULL)
2714                 return (ISC_R_SUCCESS);
2715
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);
2721
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);
2727 }
2728
2729 dns_rdataset_t *
2730 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2731
2732         /*
2733          * Get the SIG(0) record for 'msg'.
2734          */
2735
2736         REQUIRE(DNS_MESSAGE_VALID(msg));
2737         REQUIRE(owner == NULL || *owner == NULL);
2738
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.
2743                  */
2744                 if (msg->sig0name == NULL)
2745                         *owner = dns_rootname;
2746                 else
2747                         *owner = msg->sig0name;
2748         }
2749         return (msg->sig0);
2750 }
2751
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;
2757
2758         /*
2759          * Set the SIG(0) key for 'msg'
2760          */
2761
2762         /*
2763          * The space required for an SIG(0) record is:
2764          *
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
2780          */
2781         REQUIRE(DNS_MESSAGE_VALID(msg));
2782         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2783         REQUIRE(msg->state == DNS_SECTION_ANY);
2784
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);
2792                 }
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);
2798                 }
2799                 msg->sig0key = key;
2800         }
2801         return (ISC_R_SUCCESS);
2802 }
2803
2804 dst_key_t *
2805 dns_message_getsig0key(dns_message_t *msg) {
2806
2807         /*
2808          * Get the SIG(0) key for 'msg'
2809          */
2810
2811         REQUIRE(DNS_MESSAGE_VALID(msg));
2812
2813         return (msg->sig0key);
2814 }
2815
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));
2821
2822         ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2823         *buffer = NULL;
2824 }
2825
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;
2830
2831         REQUIRE(DNS_MESSAGE_VALID(msg));
2832         REQUIRE(signer != NULL);
2833         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2834
2835         if (msg->tsig == NULL && msg->sig0 == NULL)
2836                 return (ISC_R_NOTFOUND);
2837
2838         if (msg->verify_attempted == 0)
2839                 return (DNS_R_NOTVERIFIEDYET);
2840
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);
2848         }
2849
2850         if (msg->sig0 != NULL) {
2851                 dns_rdata_sig_t sig;
2852
2853                 result = dns_rdataset_first(msg->sig0);
2854                 INSIST(result == ISC_R_SUCCESS);
2855                 dns_rdataset_current(msg->sig0, &rdata);
2856
2857                 result = dns_rdata_tostruct(&rdata, &sig, NULL);
2858                 if (result != ISC_R_SUCCESS)
2859                         return (result);
2860
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;
2870
2871                 result = dns_rdataset_first(msg->tsig);
2872                 INSIST(result == ISC_R_SUCCESS);
2873                 dns_rdataset_current(msg->tsig, &rdata);
2874
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);
2883
2884                 if (msg->tsigkey == NULL) {
2885                         /*
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.
2890                          */
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;
2898                         }
2899                         dns_name_clone(identity, signer);
2900                 }
2901         }
2902
2903         return (result);
2904 }
2905
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;
2917         }
2918 }
2919
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));
2924 }
2925
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;
2932
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);
2941         }
2942
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);
2951         }
2952 }
2953 #endif
2954
2955 isc_result_t
2956 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
2957         isc_buffer_t b, msgb;
2958
2959         REQUIRE(DNS_MESSAGE_VALID(msg));
2960
2961         if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
2962                 return (ISC_R_SUCCESS);
2963
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;
2980
2981                 result = dns_rdataset_first(msg->sig0);
2982                 INSIST(result == ISC_R_SUCCESS);
2983                 dns_rdataset_current(msg->sig0, &rdata);
2984
2985                 /*
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.
2991                  */
2992                 if (rdata.length == 0)
2993                         return (ISC_R_UNEXPECTEDEND);
2994
2995                 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
2996                 if (result != ISC_R_SUCCESS)
2997                         return (result);
2998
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);
3005
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;
3014                 }
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))
3020                 {
3021                         dst_key_t *key = NULL;
3022
3023                         dns_rdataset_current(&keyset, &rdata);
3024                         isc_buffer_init(&b, rdata.data, rdata.length);
3025                         isc_buffer_add(&b, rdata.length);
3026
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))
3035                         {
3036                                 dst_key_free(&key);
3037                                 continue;
3038                         }
3039                         result = dns_dnssec_verifymessage(&msgb, msg, key);
3040                         dst_key_free(&key);
3041                         if (result == ISC_R_SUCCESS)
3042                                 break;
3043                 }
3044                 if (result == ISC_R_NOMORE)
3045                         result = DNS_R_KEYUNAUTHORIZED;
3046
3047  freesig:
3048                 if (dns_rdataset_isassociated(&keyset))
3049                         dns_rdataset_disassociate(&keyset);
3050                 dns_rdata_freestruct(&sig);
3051                 return (result);
3052         }
3053 }
3054
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;
3063
3064         REQUIRE(DNS_MESSAGE_VALID(msg));
3065         REQUIRE(target != NULL);
3066         REQUIRE(VALID_SECTION(section));
3067
3068         if (ISC_LIST_EMPTY(msg->sections[section]))
3069                 return (ISC_R_SUCCESS);
3070
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]);
3077                 }
3078                 ADD_STRING(target, " SECTION:\n");
3079         }
3080
3081         dns_name_init(&empty_name, NULL);
3082         result = dns_message_firstname(msg, section);
3083         if (result != ISC_R_SUCCESS) {
3084                 return (result);
3085         }
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);
3103                         }
3104                         if (result != ISC_R_SUCCESS)
3105                                 return (result);
3106                 }
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);
3115 }
3116
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;
3132
3133         REQUIRE(DNS_MESSAGE_VALID(msg));
3134         REQUIRE(target != NULL);
3135         REQUIRE(VALID_PSEUDOSECTION(section));
3136
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);
3161
3162                 result = dns_rdataset_first(ps);
3163                 if (result != ISC_R_SUCCESS)
3164                         return (ISC_R_SUCCESS);
3165
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);
3171
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);
3176
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);
3183                 }
3184
3185                 if (optlen != 0) {
3186                         int i;
3187                         ADD_STRING(target, ": ");
3188
3189                         optdata = rdata.data + 4;
3190                         for (i = 0; i < optlen; i++) {
3191                                 sprintf(buf, "%02x ", optdata[i]);
3192                                 ADD_STRING(target, buf);
3193                         }
3194                         for (i = 0; i < optlen; i++) {
3195                                 ADD_STRING(target, " (");
3196                                 if (isprint(optdata[i]))
3197                                         isc_buffer_putmem(target, &optdata[i],
3198                                                           1);
3199                                 else
3200                                         isc_buffer_putstr(target, ".");
3201                                 ADD_STRING(target, ")");
3202                         }
3203                 }
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);
3228         }
3229         return (ISC_R_UNEXPECTED);
3230 }
3231
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;
3237
3238         REQUIRE(DNS_MESSAGE_VALID(msg));
3239         REQUIRE(target != NULL);
3240
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);
3250                 }
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: ");
3273                 }
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: ");
3281                 }
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: ");
3289                 }
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");
3298         }
3299         result = dns_message_pseudosectiontotext(msg,
3300                                                  DNS_PSEUDOSECTION_OPT,
3301                                                  style, flags, target);
3302         if (result != ISC_R_SUCCESS)
3303                 return (result);
3304
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);
3321
3322         result = dns_message_pseudosectiontotext(msg,
3323                                                  DNS_PSEUDOSECTION_TSIG,
3324                                                  style, flags, target);
3325         if (result != ISC_R_SUCCESS)
3326                 return (result);
3327
3328         result = dns_message_pseudosectiontotext(msg,
3329                                                  DNS_PSEUDOSECTION_SIG0,
3330                                                  style, flags, target);
3331         if (result != ISC_R_SUCCESS)
3332                 return (result);
3333
3334         return (ISC_R_SUCCESS);
3335 }
3336
3337 isc_region_t *
3338 dns_message_getrawmessage(dns_message_t *msg) {
3339         REQUIRE(DNS_MESSAGE_VALID(msg));
3340         return (&msg->saved);
3341 }
3342
3343 void
3344 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3345                          const void *order_arg)
3346 {
3347         REQUIRE(DNS_MESSAGE_VALID(msg));
3348         msg->order = order;
3349         msg->order_arg = order_arg;
3350 }
3351
3352 void
3353 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3354         REQUIRE(DNS_MESSAGE_VALID(msg));
3355         msg->timeadjust = timeadjust;
3356 }
3357
3358 int
3359 dns_message_gettimeadjust(dns_message_t *msg) {
3360         REQUIRE(DNS_MESSAGE_VALID(msg));
3361         return (msg->timeadjust);
3362 }
3363
3364 isc_result_t
3365 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3366
3367         REQUIRE(opcode < 16);
3368
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);
3373 }