]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - contrib/bind9/lib/dns/message.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / contrib / bind9 / 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.245.50.2 2009/01/18 23:47:40 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 #define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
99
100 /*%
101  * This is the size of each individual scratchpad buffer, and the numbers
102  * of various block allocations used within the server.
103  * XXXMLG These should come from a config setting.
104  */
105 #define SCRATCHPAD_SIZE         512
106 #define NAME_COUNT                8
107 #define OFFSET_COUNT              4
108 #define RDATA_COUNT               8
109 #define RDATALIST_COUNT           8
110 #define RDATASET_COUNT           RDATALIST_COUNT
111
112 /*%
113  * Text representation of the different items, for message_totext
114  * functions.
115  */
116 static const char *sectiontext[] = {
117         "QUESTION",
118         "ANSWER",
119         "AUTHORITY",
120         "ADDITIONAL"
121 };
122
123 static const char *updsectiontext[] = {
124         "ZONE",
125         "PREREQUISITE",
126         "UPDATE",
127         "ADDITIONAL"
128 };
129
130 static const char *opcodetext[] = {
131         "QUERY",
132         "IQUERY",
133         "STATUS",
134         "RESERVED3",
135         "NOTIFY",
136         "UPDATE",
137         "RESERVED6",
138         "RESERVED7",
139         "RESERVED8",
140         "RESERVED9",
141         "RESERVED10",
142         "RESERVED11",
143         "RESERVED12",
144         "RESERVED13",
145         "RESERVED14",
146         "RESERVED15"
147 };
148
149 static const char *rcodetext[] = {
150         "NOERROR",
151         "FORMERR",
152         "SERVFAIL",
153         "NXDOMAIN",
154         "NOTIMP",
155         "REFUSED",
156         "YXDOMAIN",
157         "YXRRSET",
158         "NXRRSET",
159         "NOTAUTH",
160         "NOTZONE",
161         "RESERVED11",
162         "RESERVED12",
163         "RESERVED13",
164         "RESERVED14",
165         "RESERVED15",
166         "BADVERS"
167 };
168
169
170 /*%
171  * "helper" type, which consists of a block of some type, and is linkable.
172  * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
173  * size, or the allocated elements will not be aligned correctly.
174  */
175 struct dns_msgblock {
176         unsigned int                    count;
177         unsigned int                    remaining;
178         ISC_LINK(dns_msgblock_t)        link;
179 }; /* dynamically sized */
180
181 static inline dns_msgblock_t *
182 msgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
183
184 #define msgblock_get(block, type) \
185         ((type *)msgblock_internalget(block, sizeof(type)))
186
187 static inline void *
188 msgblock_internalget(dns_msgblock_t *, unsigned int);
189
190 static inline void
191 msgblock_reset(dns_msgblock_t *);
192
193 static inline void
194 msgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
195
196 /*
197  * Allocate a new dns_msgblock_t, and return a pointer to it.  If no memory
198  * is free, return NULL.
199  */
200 static inline dns_msgblock_t *
201 msgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
202                   unsigned int count)
203 {
204         dns_msgblock_t *block;
205         unsigned int length;
206
207         length = sizeof(dns_msgblock_t) + (sizeof_type * count);
208
209         block = isc_mem_get(mctx, length);
210         if (block == NULL)
211                 return (NULL);
212
213         block->count = count;
214         block->remaining = count;
215
216         ISC_LINK_INIT(block, link);
217
218         return (block);
219 }
220
221 /*
222  * Return an element from the msgblock.  If no more are available, return
223  * NULL.
224  */
225 static inline void *
226 msgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
227         void *ptr;
228
229         if (block == NULL || block->remaining == 0)
230                 return (NULL);
231
232         block->remaining--;
233
234         ptr = (((unsigned char *)block)
235                + sizeof(dns_msgblock_t)
236                + (sizeof_type * block->remaining));
237
238         return (ptr);
239 }
240
241 static inline void
242 msgblock_reset(dns_msgblock_t *block) {
243         block->remaining = block->count;
244 }
245
246 /*
247  * Release memory associated with a message block.
248  */
249 static inline void
250 msgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
251 {
252         unsigned int length;
253
254         length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
255
256         isc_mem_put(mctx, block, length);
257 }
258
259 /*
260  * Allocate a new dynamic buffer, and attach it to this message as the
261  * "current" buffer.  (which is always the last on the list, for our
262  * uses)
263  */
264 static inline isc_result_t
265 newbuffer(dns_message_t *msg, unsigned int size) {
266         isc_result_t result;
267         isc_buffer_t *dynbuf;
268
269         dynbuf = NULL;
270         result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
271         if (result != ISC_R_SUCCESS)
272                 return (ISC_R_NOMEMORY);
273
274         ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
275         return (ISC_R_SUCCESS);
276 }
277
278 static inline isc_buffer_t *
279 currentbuffer(dns_message_t *msg) {
280         isc_buffer_t *dynbuf;
281
282         dynbuf = ISC_LIST_TAIL(msg->scratchpad);
283         INSIST(dynbuf != NULL);
284
285         return (dynbuf);
286 }
287
288 static inline void
289 releaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
290         ISC_LIST_PREPEND(msg->freerdata, rdata, link);
291 }
292
293 static inline dns_rdata_t *
294 newrdata(dns_message_t *msg) {
295         dns_msgblock_t *msgblock;
296         dns_rdata_t *rdata;
297
298         rdata = ISC_LIST_HEAD(msg->freerdata);
299         if (rdata != NULL) {
300                 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
301                 return (rdata);
302         }
303
304         msgblock = ISC_LIST_TAIL(msg->rdatas);
305         rdata = msgblock_get(msgblock, dns_rdata_t);
306         if (rdata == NULL) {
307                 msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
308                                              RDATA_COUNT);
309                 if (msgblock == NULL)
310                         return (NULL);
311
312                 ISC_LIST_APPEND(msg->rdatas, msgblock, link);
313
314                 rdata = msgblock_get(msgblock, dns_rdata_t);
315         }
316
317         dns_rdata_init(rdata);
318         return (rdata);
319 }
320
321 static inline void
322 releaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
323         ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
324 }
325
326 static inline dns_rdatalist_t *
327 newrdatalist(dns_message_t *msg) {
328         dns_msgblock_t *msgblock;
329         dns_rdatalist_t *rdatalist;
330
331         rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
332         if (rdatalist != NULL) {
333                 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
334                 return (rdatalist);
335         }
336
337         msgblock = ISC_LIST_TAIL(msg->rdatalists);
338         rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
339         if (rdatalist == NULL) {
340                 msgblock = msgblock_allocate(msg->mctx,
341                                              sizeof(dns_rdatalist_t),
342                                              RDATALIST_COUNT);
343                 if (msgblock == NULL)
344                         return (NULL);
345
346                 ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
347
348                 rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
349         }
350
351         return (rdatalist);
352 }
353
354 static inline dns_offsets_t *
355 newoffsets(dns_message_t *msg) {
356         dns_msgblock_t *msgblock;
357         dns_offsets_t *offsets;
358
359         msgblock = ISC_LIST_TAIL(msg->offsets);
360         offsets = msgblock_get(msgblock, dns_offsets_t);
361         if (offsets == NULL) {
362                 msgblock = msgblock_allocate(msg->mctx,
363                                              sizeof(dns_offsets_t),
364                                              OFFSET_COUNT);
365                 if (msgblock == NULL)
366                         return (NULL);
367
368                 ISC_LIST_APPEND(msg->offsets, msgblock, link);
369
370                 offsets = msgblock_get(msgblock, dns_offsets_t);
371         }
372
373         return (offsets);
374 }
375
376 static inline void
377 msginitheader(dns_message_t *m) {
378         m->id = 0;
379         m->flags = 0;
380         m->rcode = 0;
381         m->opcode = 0;
382         m->rdclass = 0;
383 }
384
385 static inline void
386 msginitprivate(dns_message_t *m) {
387         unsigned int i;
388
389         for (i = 0; i < DNS_SECTION_MAX; i++) {
390                 m->cursors[i] = NULL;
391                 m->counts[i] = 0;
392         }
393         m->opt = NULL;
394         m->sig0 = NULL;
395         m->sig0name = NULL;
396         m->tsig = NULL;
397         m->tsigname = NULL;
398         m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
399         m->opt_reserved = 0;
400         m->sig_reserved = 0;
401         m->reserved = 0;
402         m->buffer = NULL;
403 }
404
405 static inline void
406 msginittsig(dns_message_t *m) {
407         m->tsigstatus = dns_rcode_noerror;
408         m->querytsigstatus = dns_rcode_noerror;
409         m->tsigkey = NULL;
410         m->tsigctx = NULL;
411         m->sigstart = -1;
412         m->sig0key = NULL;
413         m->sig0status = dns_rcode_noerror;
414         m->timeadjust = 0;
415 }
416
417 /*
418  * Init elements to default state.  Used both when allocating a new element
419  * and when resetting one.
420  */
421 static inline void
422 msginit(dns_message_t *m) {
423         msginitheader(m);
424         msginitprivate(m);
425         msginittsig(m);
426         m->header_ok = 0;
427         m->question_ok = 0;
428         m->tcp_continuation = 0;
429         m->verified_sig = 0;
430         m->verify_attempted = 0;
431         m->order = NULL;
432         m->order_arg = NULL;
433         m->query.base = NULL;
434         m->query.length = 0;
435         m->free_query = 0;
436         m->saved.base = NULL;
437         m->saved.length = 0;
438         m->free_saved = 0;
439         m->querytsig = NULL;
440 }
441
442 static inline void
443 msgresetnames(dns_message_t *msg, unsigned int first_section) {
444         unsigned int i;
445         dns_name_t *name, *next_name;
446         dns_rdataset_t *rds, *next_rds;
447
448         /*
449          * Clean up name lists by calling the rdataset disassociate function.
450          */
451         for (i = first_section; i < DNS_SECTION_MAX; i++) {
452                 name = ISC_LIST_HEAD(msg->sections[i]);
453                 while (name != NULL) {
454                         next_name = ISC_LIST_NEXT(name, link);
455                         ISC_LIST_UNLINK(msg->sections[i], name, link);
456
457                         rds = ISC_LIST_HEAD(name->list);
458                         while (rds != NULL) {
459                                 next_rds = ISC_LIST_NEXT(rds, link);
460                                 ISC_LIST_UNLINK(name->list, rds, link);
461
462                                 INSIST(dns_rdataset_isassociated(rds));
463                                 dns_rdataset_disassociate(rds);
464                                 isc_mempool_put(msg->rdspool, rds);
465                                 rds = next_rds;
466                         }
467                         if (dns_name_dynamic(name))
468                                 dns_name_free(name, msg->mctx);
469                         isc_mempool_put(msg->namepool, name);
470                         name = next_name;
471                 }
472         }
473 }
474
475 static void
476 msgresetopt(dns_message_t *msg)
477 {
478         if (msg->opt != NULL) {
479                 if (msg->opt_reserved > 0) {
480                         dns_message_renderrelease(msg, msg->opt_reserved);
481                         msg->opt_reserved = 0;
482                 }
483                 INSIST(dns_rdataset_isassociated(msg->opt));
484                 dns_rdataset_disassociate(msg->opt);
485                 isc_mempool_put(msg->rdspool, msg->opt);
486                 msg->opt = NULL;
487         }
488 }
489
490 static void
491 msgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
492         if (msg->sig_reserved > 0) {
493                 dns_message_renderrelease(msg, msg->sig_reserved);
494                 msg->sig_reserved = 0;
495         }
496         if (msg->tsig != NULL) {
497                 INSIST(dns_rdataset_isassociated(msg->tsig));
498                 INSIST(msg->namepool != NULL);
499                 if (replying) {
500                         INSIST(msg->querytsig == NULL);
501                         msg->querytsig = msg->tsig;
502                 } else {
503                         dns_rdataset_disassociate(msg->tsig);
504                         isc_mempool_put(msg->rdspool, msg->tsig);
505                         if (msg->querytsig != NULL) {
506                                 dns_rdataset_disassociate(msg->querytsig);
507                                 isc_mempool_put(msg->rdspool, msg->querytsig);
508                         }
509                 }
510                 if (dns_name_dynamic(msg->tsigname))
511                         dns_name_free(msg->tsigname, msg->mctx);
512                 isc_mempool_put(msg->namepool, msg->tsigname);
513                 msg->tsig = NULL;
514                 msg->tsigname = NULL;
515         } else if (msg->querytsig != NULL && !replying) {
516                 dns_rdataset_disassociate(msg->querytsig);
517                 isc_mempool_put(msg->rdspool, msg->querytsig);
518                 msg->querytsig = NULL;
519         }
520         if (msg->sig0 != NULL) {
521                 INSIST(dns_rdataset_isassociated(msg->sig0));
522                 dns_rdataset_disassociate(msg->sig0);
523                 isc_mempool_put(msg->rdspool, msg->sig0);
524                 if (msg->sig0name != NULL) {
525                         if (dns_name_dynamic(msg->sig0name))
526                                 dns_name_free(msg->sig0name, msg->mctx);
527                         isc_mempool_put(msg->namepool, msg->sig0name);
528                 }
529                 msg->sig0 = NULL;
530                 msg->sig0name = NULL;
531         }
532 }
533
534 /*
535  * Free all but one (or everything) for this message.  This is used by
536  * both dns_message_reset() and dns_message_destroy().
537  */
538 static void
539 msgreset(dns_message_t *msg, isc_boolean_t everything) {
540         dns_msgblock_t *msgblock, *next_msgblock;
541         isc_buffer_t *dynbuf, *next_dynbuf;
542         dns_rdata_t *rdata;
543         dns_rdatalist_t *rdatalist;
544
545         msgresetnames(msg, 0);
546         msgresetopt(msg);
547         msgresetsigs(msg, ISC_FALSE);
548
549         /*
550          * Clean up linked lists.
551          */
552
553         /*
554          * Run through the free lists, and just unlink anything found there.
555          * The memory isn't lost since these are part of message blocks we
556          * have allocated.
557          */
558         rdata = ISC_LIST_HEAD(msg->freerdata);
559         while (rdata != NULL) {
560                 ISC_LIST_UNLINK(msg->freerdata, rdata, link);
561                 rdata = ISC_LIST_HEAD(msg->freerdata);
562         }
563         rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
564         while (rdatalist != NULL) {
565                 ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
566                 rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
567         }
568
569         dynbuf = ISC_LIST_HEAD(msg->scratchpad);
570         INSIST(dynbuf != NULL);
571         if (!everything) {
572                 isc_buffer_clear(dynbuf);
573                 dynbuf = ISC_LIST_NEXT(dynbuf, link);
574         }
575         while (dynbuf != NULL) {
576                 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
577                 ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
578                 isc_buffer_free(&dynbuf);
579                 dynbuf = next_dynbuf;
580         }
581
582         msgblock = ISC_LIST_HEAD(msg->rdatas);
583         if (!everything && msgblock != NULL) {
584                 msgblock_reset(msgblock);
585                 msgblock = ISC_LIST_NEXT(msgblock, link);
586         }
587         while (msgblock != NULL) {
588                 next_msgblock = ISC_LIST_NEXT(msgblock, link);
589                 ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
590                 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
591                 msgblock = next_msgblock;
592         }
593
594         /*
595          * rdatalists could be empty.
596          */
597
598         msgblock = ISC_LIST_HEAD(msg->rdatalists);
599         if (!everything && msgblock != NULL) {
600                 msgblock_reset(msgblock);
601                 msgblock = ISC_LIST_NEXT(msgblock, link);
602         }
603         while (msgblock != NULL) {
604                 next_msgblock = ISC_LIST_NEXT(msgblock, link);
605                 ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
606                 msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
607                 msgblock = next_msgblock;
608         }
609
610         msgblock = ISC_LIST_HEAD(msg->offsets);
611         if (!everything && msgblock != NULL) {
612                 msgblock_reset(msgblock);
613                 msgblock = ISC_LIST_NEXT(msgblock, link);
614         }
615         while (msgblock != NULL) {
616                 next_msgblock = ISC_LIST_NEXT(msgblock, link);
617                 ISC_LIST_UNLINK(msg->offsets, msgblock, link);
618                 msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
619                 msgblock = next_msgblock;
620         }
621
622         if (msg->tsigkey != NULL) {
623                 dns_tsigkey_detach(&msg->tsigkey);
624                 msg->tsigkey = NULL;
625         }
626
627         if (msg->tsigctx != NULL)
628                 dst_context_destroy(&msg->tsigctx);
629
630         if (msg->query.base != NULL) {
631                 if (msg->free_query != 0)
632                         isc_mem_put(msg->mctx, msg->query.base,
633                                     msg->query.length);
634                 msg->query.base = NULL;
635                 msg->query.length = 0;
636         }
637
638         if (msg->saved.base != NULL) {
639                 if (msg->free_saved != 0)
640                         isc_mem_put(msg->mctx, msg->saved.base,
641                                     msg->saved.length);
642                 msg->saved.base = NULL;
643                 msg->saved.length = 0;
644         }
645
646         /*
647          * cleanup the buffer cleanup list
648          */
649         dynbuf = ISC_LIST_HEAD(msg->cleanup);
650         while (dynbuf != NULL) {
651                 next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
652                 ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
653                 isc_buffer_free(&dynbuf);
654                 dynbuf = next_dynbuf;
655         }
656
657         /*
658          * Set other bits to normal default values.
659          */
660         if (!everything)
661                 msginit(msg);
662
663         ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
664         ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
665 }
666
667 static unsigned int
668 spacefortsig(dns_tsigkey_t *key, int otherlen) {
669         isc_region_t r1, r2;
670         unsigned int x;
671         isc_result_t result;
672
673         /*
674          * The space required for an TSIG record is:
675          *
676          *      n1 bytes for the name
677          *      2 bytes for the type
678          *      2 bytes for the class
679          *      4 bytes for the ttl
680          *      2 bytes for the rdlength
681          *      n2 bytes for the algorithm name
682          *      6 bytes for the time signed
683          *      2 bytes for the fudge
684          *      2 bytes for the MAC size
685          *      x bytes for the MAC
686          *      2 bytes for the original id
687          *      2 bytes for the error
688          *      2 bytes for the other data length
689          *      y bytes for the other data (at most)
690          * ---------------------------------
691          *     26 + n1 + n2 + x + y bytes
692          */
693
694         dns_name_toregion(&key->name, &r1);
695         dns_name_toregion(key->algorithm, &r2);
696         if (key->key == NULL)
697                 x = 0;
698         else {
699                 result = dst_key_sigsize(key->key, &x);
700                 if (result != ISC_R_SUCCESS)
701                         x = 0;
702         }
703         return (26 + r1.length + r2.length + x + otherlen);
704 }
705
706 isc_result_t
707 dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
708 {
709         dns_message_t *m;
710         isc_result_t result;
711         isc_buffer_t *dynbuf;
712         unsigned int i;
713
714         REQUIRE(mctx != NULL);
715         REQUIRE(msgp != NULL);
716         REQUIRE(*msgp == NULL);
717         REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
718                 || intent == DNS_MESSAGE_INTENTRENDER);
719
720         m = isc_mem_get(mctx, sizeof(dns_message_t));
721         if (m == NULL)
722                 return (ISC_R_NOMEMORY);
723
724         /*
725          * No allocations until further notice.  Just initialize all lists
726          * and other members that are freed in the cleanup phase here.
727          */
728
729         m->magic = DNS_MESSAGE_MAGIC;
730         m->from_to_wire = intent;
731         msginit(m);
732
733         for (i = 0; i < DNS_SECTION_MAX; i++)
734                 ISC_LIST_INIT(m->sections[i]);
735         m->mctx = mctx;
736
737         ISC_LIST_INIT(m->scratchpad);
738         ISC_LIST_INIT(m->cleanup);
739         m->namepool = NULL;
740         m->rdspool = NULL;
741         ISC_LIST_INIT(m->rdatas);
742         ISC_LIST_INIT(m->rdatalists);
743         ISC_LIST_INIT(m->offsets);
744         ISC_LIST_INIT(m->freerdata);
745         ISC_LIST_INIT(m->freerdatalist);
746
747         /*
748          * Ok, it is safe to allocate (and then "goto cleanup" if failure)
749          */
750
751         result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
752         if (result != ISC_R_SUCCESS)
753                 goto cleanup;
754         isc_mempool_setfreemax(m->namepool, NAME_COUNT);
755         isc_mempool_setname(m->namepool, "msg:names");
756
757         result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
758                                     &m->rdspool);
759         if (result != ISC_R_SUCCESS)
760                 goto cleanup;
761         isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
762         isc_mempool_setname(m->rdspool, "msg:rdataset");
763
764         dynbuf = NULL;
765         result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
766         if (result != ISC_R_SUCCESS)
767                 goto cleanup;
768         ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
769
770         m->cctx = NULL;
771
772         *msgp = m;
773         return (ISC_R_SUCCESS);
774
775         /*
776          * Cleanup for error returns.
777          */
778  cleanup:
779         dynbuf = ISC_LIST_HEAD(m->scratchpad);
780         if (dynbuf != NULL) {
781                 ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
782                 isc_buffer_free(&dynbuf);
783         }
784         if (m->namepool != NULL)
785                 isc_mempool_destroy(&m->namepool);
786         if (m->rdspool != NULL)
787                 isc_mempool_destroy(&m->rdspool);
788         m->magic = 0;
789         isc_mem_put(mctx, m, sizeof(dns_message_t));
790
791         return (ISC_R_NOMEMORY);
792 }
793
794 void
795 dns_message_reset(dns_message_t *msg, unsigned int intent) {
796         REQUIRE(DNS_MESSAGE_VALID(msg));
797         REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
798                 || intent == DNS_MESSAGE_INTENTRENDER);
799
800         msgreset(msg, ISC_FALSE);
801         msg->from_to_wire = intent;
802 }
803
804 void
805 dns_message_destroy(dns_message_t **msgp) {
806         dns_message_t *msg;
807
808         REQUIRE(msgp != NULL);
809         REQUIRE(DNS_MESSAGE_VALID(*msgp));
810
811         msg = *msgp;
812         *msgp = NULL;
813
814         msgreset(msg, ISC_TRUE);
815         isc_mempool_destroy(&msg->namepool);
816         isc_mempool_destroy(&msg->rdspool);
817         msg->magic = 0;
818         isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
819 }
820
821 static isc_result_t
822 findname(dns_name_t **foundname, dns_name_t *target,
823          dns_namelist_t *section)
824 {
825         dns_name_t *curr;
826
827         for (curr = ISC_LIST_TAIL(*section);
828              curr != NULL;
829              curr = ISC_LIST_PREV(curr, link)) {
830                 if (dns_name_equal(curr, target)) {
831                         if (foundname != NULL)
832                                 *foundname = curr;
833                         return (ISC_R_SUCCESS);
834                 }
835         }
836
837         return (ISC_R_NOTFOUND);
838 }
839
840 isc_result_t
841 dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
842                  dns_rdatatype_t type, dns_rdatatype_t covers,
843                  dns_rdataset_t **rdataset)
844 {
845         dns_rdataset_t *curr;
846
847         if (rdataset != NULL) {
848                 REQUIRE(*rdataset == NULL);
849         }
850
851         for (curr = ISC_LIST_TAIL(name->list);
852              curr != NULL;
853              curr = ISC_LIST_PREV(curr, link)) {
854                 if (curr->rdclass == rdclass &&
855                     curr->type == type && curr->covers == covers) {
856                         if (rdataset != NULL)
857                                 *rdataset = curr;
858                         return (ISC_R_SUCCESS);
859                 }
860         }
861
862         return (ISC_R_NOTFOUND);
863 }
864
865 isc_result_t
866 dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
867                      dns_rdatatype_t covers, dns_rdataset_t **rdataset)
868 {
869         dns_rdataset_t *curr;
870
871         REQUIRE(name != NULL);
872         if (rdataset != NULL) {
873                 REQUIRE(*rdataset == NULL);
874         }
875
876         for (curr = ISC_LIST_TAIL(name->list);
877              curr != NULL;
878              curr = ISC_LIST_PREV(curr, link)) {
879                 if (curr->type == type && curr->covers == covers) {
880                         if (rdataset != NULL)
881                                 *rdataset = curr;
882                         return (ISC_R_SUCCESS);
883                 }
884         }
885
886         return (ISC_R_NOTFOUND);
887 }
888
889 /*
890  * Read a name from buffer "source".
891  */
892 static isc_result_t
893 getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
894         dns_decompress_t *dctx)
895 {
896         isc_buffer_t *scratch;
897         isc_result_t result;
898         unsigned int tries;
899
900         scratch = currentbuffer(msg);
901
902         /*
903          * First try:  use current buffer.
904          * Second try:  allocate a new buffer and use that.
905          */
906         tries = 0;
907         while (tries < 2) {
908                 result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
909                                            scratch);
910
911                 if (result == ISC_R_NOSPACE) {
912                         tries++;
913
914                         result = newbuffer(msg, SCRATCHPAD_SIZE);
915                         if (result != ISC_R_SUCCESS)
916                                 return (result);
917
918                         scratch = currentbuffer(msg);
919                         dns_name_reset(name);
920                 } else {
921                         return (result);
922                 }
923         }
924
925         INSIST(0);  /* Cannot get here... */
926         return (ISC_R_UNEXPECTED);
927 }
928
929 static isc_result_t
930 getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
931          dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
932          unsigned int rdatalen, dns_rdata_t *rdata)
933 {
934         isc_buffer_t *scratch;
935         isc_result_t result;
936         unsigned int tries;
937         unsigned int trysize;
938
939         scratch = currentbuffer(msg);
940
941         isc_buffer_setactive(source, rdatalen);
942
943         /*
944          * First try:  use current buffer.
945          * Second try:  allocate a new buffer of size
946          *     max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
947          *     (the data will fit if it was not more than 50% compressed)
948          * Subsequent tries: double buffer size on each try.
949          */
950         tries = 0;
951         trysize = 0;
952         /* XXX possibly change this to a while (tries < 2) loop */
953         for (;;) {
954                 result = dns_rdata_fromwire(rdata, rdclass, rdtype,
955                                             source, dctx, 0,
956                                             scratch);
957
958                 if (result == ISC_R_NOSPACE) {
959                         if (tries == 0) {
960                                 trysize = 2 * rdatalen;
961                                 if (trysize < SCRATCHPAD_SIZE)
962                                         trysize = SCRATCHPAD_SIZE;
963                         } else {
964                                 INSIST(trysize != 0);
965                                 if (trysize >= 65535)
966                                         return (ISC_R_NOSPACE);
967                                         /* XXX DNS_R_RRTOOLONG? */
968                                 trysize *= 2;
969                         }
970                         tries++;
971                         result = newbuffer(msg, trysize);
972                         if (result != ISC_R_SUCCESS)
973                                 return (result);
974
975                         scratch = currentbuffer(msg);
976                 } else {
977                         return (result);
978                 }
979         }
980 }
981
982 #define DO_FORMERR                                      \
983         do {                                            \
984                 if (best_effort)                        \
985                         seen_problem = ISC_TRUE;        \
986                 else {                                  \
987                         result = DNS_R_FORMERR;         \
988                         goto cleanup;                   \
989                 }                                       \
990         } while (0)
991
992 static isc_result_t
993 getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
994              unsigned int options)
995 {
996         isc_region_t r;
997         unsigned int count;
998         dns_name_t *name;
999         dns_name_t *name2;
1000         dns_offsets_t *offsets;
1001         dns_rdataset_t *rdataset;
1002         dns_rdatalist_t *rdatalist;
1003         isc_result_t result;
1004         dns_rdatatype_t rdtype;
1005         dns_rdataclass_t rdclass;
1006         dns_namelist_t *section;
1007         isc_boolean_t free_name;
1008         isc_boolean_t best_effort;
1009         isc_boolean_t seen_problem;
1010
1011         section = &msg->sections[DNS_SECTION_QUESTION];
1012
1013         best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1014         seen_problem = ISC_FALSE;
1015
1016         name = NULL;
1017         rdataset = NULL;
1018         rdatalist = NULL;
1019
1020         for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
1021                 name = isc_mempool_get(msg->namepool);
1022                 if (name == NULL)
1023                         return (ISC_R_NOMEMORY);
1024                 free_name = ISC_TRUE;
1025
1026                 offsets = newoffsets(msg);
1027                 if (offsets == NULL) {
1028                         result = ISC_R_NOMEMORY;
1029                         goto cleanup;
1030                 }
1031                 dns_name_init(name, *offsets);
1032
1033                 /*
1034                  * Parse the name out of this packet.
1035                  */
1036                 isc_buffer_remainingregion(source, &r);
1037                 isc_buffer_setactive(source, r.length);
1038                 result = getname(name, source, msg, dctx);
1039                 if (result != ISC_R_SUCCESS)
1040                         goto cleanup;
1041
1042                 /*
1043                  * Run through the section, looking to see if this name
1044                  * is already there.  If it is found, put back the allocated
1045                  * name since we no longer need it, and set our name pointer
1046                  * to point to the name we found.
1047                  */
1048                 result = findname(&name2, name, section);
1049
1050                 /*
1051                  * If it is the first name in the section, accept it.
1052                  *
1053                  * If it is not, but is not the same as the name already
1054                  * in the question section, append to the section.  Note that
1055                  * here in the question section this is illegal, so return
1056                  * FORMERR.  In the future, check the opcode to see if
1057                  * this should be legal or not.  In either case we no longer
1058                  * need this name pointer.
1059                  */
1060                 if (result != ISC_R_SUCCESS) {
1061                         if (!ISC_LIST_EMPTY(*section))
1062                                 DO_FORMERR;
1063                         ISC_LIST_APPEND(*section, name, link);
1064                         free_name = ISC_FALSE;
1065                 } else {
1066                         isc_mempool_put(msg->namepool, name);
1067                         name = name2;
1068                         name2 = NULL;
1069                         free_name = ISC_FALSE;
1070                 }
1071
1072                 /*
1073                  * Get type and class.
1074                  */
1075                 isc_buffer_remainingregion(source, &r);
1076                 if (r.length < 4) {
1077                         result = ISC_R_UNEXPECTEDEND;
1078                         goto cleanup;
1079                 }
1080                 rdtype = isc_buffer_getuint16(source);
1081                 rdclass = isc_buffer_getuint16(source);
1082
1083                 /*
1084                  * If this class is different than the one we already read,
1085                  * this is an error.
1086                  */
1087                 if (msg->state == DNS_SECTION_ANY) {
1088                         msg->state = DNS_SECTION_QUESTION;
1089                         msg->rdclass = rdclass;
1090                 } else if (msg->rdclass != rdclass)
1091                         DO_FORMERR;
1092
1093                 /*
1094                  * Can't ask the same question twice.
1095                  */
1096                 result = dns_message_find(name, rdclass, rdtype, 0, NULL);
1097                 if (result == ISC_R_SUCCESS)
1098                         DO_FORMERR;
1099
1100                 /*
1101                  * Allocate a new rdatalist.
1102                  */
1103                 rdatalist = newrdatalist(msg);
1104                 if (rdatalist == NULL) {
1105                         result = ISC_R_NOMEMORY;
1106                         goto cleanup;
1107                 }
1108                 rdataset =  isc_mempool_get(msg->rdspool);
1109                 if (rdataset == NULL) {
1110                         result = ISC_R_NOMEMORY;
1111                         goto cleanup;
1112                 }
1113
1114                 /*
1115                  * Convert rdatalist to rdataset, and attach the latter to
1116                  * the name.
1117                  */
1118                 rdatalist->type = rdtype;
1119                 rdatalist->covers = 0;
1120                 rdatalist->rdclass = rdclass;
1121                 rdatalist->ttl = 0;
1122                 ISC_LIST_INIT(rdatalist->rdata);
1123
1124                 dns_rdataset_init(rdataset);
1125                 result = dns_rdatalist_tordataset(rdatalist, rdataset);
1126                 if (result != ISC_R_SUCCESS)
1127                         goto cleanup;
1128
1129                 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1130
1131                 ISC_LIST_APPEND(name->list, rdataset, link);
1132                 rdataset = NULL;
1133         }
1134
1135         if (seen_problem)
1136                 return (DNS_R_RECOVERABLE);
1137         return (ISC_R_SUCCESS);
1138
1139  cleanup:
1140         if (rdataset != NULL) {
1141                 INSIST(!dns_rdataset_isassociated(rdataset));
1142                 isc_mempool_put(msg->rdspool, rdataset);
1143         }
1144 #if 0
1145         if (rdatalist != NULL)
1146                 isc_mempool_put(msg->rdlpool, rdatalist);
1147 #endif
1148         if (free_name)
1149                 isc_mempool_put(msg->namepool, name);
1150
1151         return (result);
1152 }
1153
1154 static isc_boolean_t
1155 update(dns_section_t section, dns_rdataclass_t rdclass) {
1156         if (section == DNS_SECTION_PREREQUISITE)
1157                 return (ISC_TF(rdclass == dns_rdataclass_any ||
1158                                rdclass == dns_rdataclass_none));
1159         if (section == DNS_SECTION_UPDATE)
1160                 return (ISC_TF(rdclass == dns_rdataclass_any));
1161         return (ISC_FALSE);
1162 }
1163
1164 static isc_result_t
1165 getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1166            dns_section_t sectionid, unsigned int options)
1167 {
1168         isc_region_t r;
1169         unsigned int count, rdatalen;
1170         dns_name_t *name;
1171         dns_name_t *name2;
1172         dns_offsets_t *offsets;
1173         dns_rdataset_t *rdataset;
1174         dns_rdatalist_t *rdatalist;
1175         isc_result_t result;
1176         dns_rdatatype_t rdtype, covers;
1177         dns_rdataclass_t rdclass;
1178         dns_rdata_t *rdata;
1179         dns_ttl_t ttl;
1180         dns_namelist_t *section;
1181         isc_boolean_t free_name, free_rdataset;
1182         isc_boolean_t preserve_order, best_effort, seen_problem;
1183         isc_boolean_t issigzero;
1184
1185         preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
1186         best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1187         seen_problem = ISC_FALSE;
1188
1189         for (count = 0; count < msg->counts[sectionid]; count++) {
1190                 int recstart = source->current;
1191                 isc_boolean_t skip_name_search, skip_type_search;
1192
1193                 section = &msg->sections[sectionid];
1194
1195                 skip_name_search = ISC_FALSE;
1196                 skip_type_search = ISC_FALSE;
1197                 free_name = ISC_FALSE;
1198                 free_rdataset = ISC_FALSE;
1199
1200                 name = isc_mempool_get(msg->namepool);
1201                 if (name == NULL)
1202                         return (ISC_R_NOMEMORY);
1203                 free_name = ISC_TRUE;
1204
1205                 offsets = newoffsets(msg);
1206                 if (offsets == NULL) {
1207                         result = ISC_R_NOMEMORY;
1208                         goto cleanup;
1209                 }
1210                 dns_name_init(name, *offsets);
1211
1212                 /*
1213                  * Parse the name out of this packet.
1214                  */
1215                 isc_buffer_remainingregion(source, &r);
1216                 isc_buffer_setactive(source, r.length);
1217                 result = getname(name, source, msg, dctx);
1218                 if (result != ISC_R_SUCCESS)
1219                         goto cleanup;
1220
1221                 /*
1222                  * Get type, class, ttl, and rdatalen.  Verify that at least
1223                  * rdatalen bytes remain.  (Some of this is deferred to
1224                  * later.)
1225                  */
1226                 isc_buffer_remainingregion(source, &r);
1227                 if (r.length < 2 + 2 + 4 + 2) {
1228                         result = ISC_R_UNEXPECTEDEND;
1229                         goto cleanup;
1230                 }
1231                 rdtype = isc_buffer_getuint16(source);
1232                 rdclass = isc_buffer_getuint16(source);
1233
1234                 /*
1235                  * If there was no question section, we may not yet have
1236                  * established a class.  Do so now.
1237                  */
1238                 if (msg->state == DNS_SECTION_ANY &&
1239                     rdtype != dns_rdatatype_opt &&      /* class is UDP SIZE */
1240                     rdtype != dns_rdatatype_tsig &&     /* class is ANY */
1241                     rdtype != dns_rdatatype_tkey) {     /* class is undefined */
1242                         msg->rdclass = rdclass;
1243                         msg->state = DNS_SECTION_QUESTION;
1244                 }
1245
1246                 /*
1247                  * If this class is different than the one in the question
1248                  * section, bail.
1249                  */
1250                 if (msg->opcode != dns_opcode_update
1251                     && rdtype != dns_rdatatype_tsig
1252                     && rdtype != dns_rdatatype_opt
1253                     && rdtype != dns_rdatatype_dnskey /* in a TKEY query */
1254                     && rdtype != dns_rdatatype_sig /* SIG(0) */
1255                     && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1256                     && msg->rdclass != dns_rdataclass_any
1257                     && msg->rdclass != rdclass)
1258                         DO_FORMERR;
1259
1260                 /*
1261                  * Special type handling for TSIG, OPT, and TKEY.
1262                  */
1263                 if (rdtype == dns_rdatatype_tsig) {
1264                         /*
1265                          * If it is a tsig, verify that it is in the
1266                          * additional data section.
1267                          */
1268                         if (sectionid != DNS_SECTION_ADDITIONAL ||
1269                             rdclass != dns_rdataclass_any ||
1270                             count != msg->counts[sectionid]  - 1)
1271                                 DO_FORMERR;
1272                         msg->sigstart = recstart;
1273                         skip_name_search = ISC_TRUE;
1274                         skip_type_search = ISC_TRUE;
1275                 } else if (rdtype == dns_rdatatype_opt) {
1276                         /*
1277                          * The name of an OPT record must be ".", it
1278                          * must be in the additional data section, and
1279                          * it must be the first OPT we've seen.
1280                          */
1281                         if (!dns_name_equal(dns_rootname, name) ||
1282                             msg->opt != NULL)
1283                                 DO_FORMERR;
1284                         skip_name_search = ISC_TRUE;
1285                         skip_type_search = ISC_TRUE;
1286                 } else if (rdtype == dns_rdatatype_tkey) {
1287                         /*
1288                          * A TKEY must be in the additional section if this
1289                          * is a query, and the answer section if this is a
1290                          * response.  Unless it's a Win2000 client.
1291                          *
1292                          * Its class is ignored.
1293                          */
1294                         dns_section_t tkeysection;
1295
1296                         if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1297                                 tkeysection = DNS_SECTION_ADDITIONAL;
1298                         else
1299                                 tkeysection = DNS_SECTION_ANSWER;
1300                         if (sectionid != tkeysection &&
1301                             sectionid != DNS_SECTION_ANSWER)
1302                                 DO_FORMERR;
1303                 }
1304
1305                 /*
1306                  * ... now get ttl and rdatalen, and check buffer.
1307                  */
1308                 ttl = isc_buffer_getuint32(source);
1309                 rdatalen = isc_buffer_getuint16(source);
1310                 r.length -= (2 + 2 + 4 + 2);
1311                 if (r.length < rdatalen) {
1312                         result = ISC_R_UNEXPECTEDEND;
1313                         goto cleanup;
1314                 }
1315
1316                 /*
1317                  * Read the rdata from the wire format.  Interpret the
1318                  * rdata according to its actual class, even if it had a
1319                  * DynDNS meta-class in the packet (unless this is a TSIG).
1320                  * Then put the meta-class back into the finished rdata.
1321                  */
1322                 rdata = newrdata(msg);
1323                 if (rdata == NULL) {
1324                         result = ISC_R_NOMEMORY;
1325                         goto cleanup;
1326                 }
1327                 if (msg->opcode == dns_opcode_update &&
1328                     update(sectionid, rdclass)) {
1329                         if (rdatalen != 0) {
1330                                 result = DNS_R_FORMERR;
1331                                 goto cleanup;
1332                         }
1333                         /*
1334                          * When the rdata is empty, the data pointer is
1335                          * never dereferenced, but it must still be non-NULL.
1336                          * Casting 1 rather than "" avoids warnings about
1337                          * discarding the const attribute of a string,
1338                          * for compilers that would warn about such things.
1339                          */
1340                         rdata->data = (unsigned char *)1;
1341                         rdata->length = 0;
1342                         rdata->rdclass = rdclass;
1343                         rdata->type = rdtype;
1344                         rdata->flags = DNS_RDATA_UPDATE;
1345                         result = ISC_R_SUCCESS;
1346                 } else if (rdclass == dns_rdataclass_none &&
1347                            msg->opcode == dns_opcode_update &&
1348                            sectionid == DNS_SECTION_UPDATE) {
1349                         result = getrdata(source, msg, dctx, msg->rdclass,
1350                                           rdtype, rdatalen, rdata);
1351                 } else
1352                         result = getrdata(source, msg, dctx, rdclass,
1353                                           rdtype, rdatalen, rdata);
1354                 if (result != ISC_R_SUCCESS)
1355                         goto cleanup;
1356                 rdata->rdclass = rdclass;
1357                 issigzero = ISC_FALSE;
1358                 if (rdtype == dns_rdatatype_rrsig  &&
1359                     rdata->flags == 0) {
1360                         covers = dns_rdata_covers(rdata);
1361                         if (covers == 0)
1362                                 DO_FORMERR;
1363                 } else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1364                            rdata->flags == 0) {
1365                         covers = dns_rdata_covers(rdata);
1366                         if (covers == 0) {
1367                                 if (sectionid != DNS_SECTION_ADDITIONAL ||
1368                                     count != msg->counts[sectionid]  - 1)
1369                                         DO_FORMERR;
1370                                 msg->sigstart = recstart;
1371                                 skip_name_search = ISC_TRUE;
1372                                 skip_type_search = ISC_TRUE;
1373                                 issigzero = ISC_TRUE;
1374                         }
1375                 } else
1376                         covers = 0;
1377
1378                 /*
1379                  * If we are doing a dynamic update or this is a meta-type,
1380                  * don't bother searching for a name, just append this one
1381                  * to the end of the message.
1382                  */
1383                 if (preserve_order || msg->opcode == dns_opcode_update ||
1384                     skip_name_search) {
1385                         if (rdtype != dns_rdatatype_opt &&
1386                             rdtype != dns_rdatatype_tsig &&
1387                             !issigzero)
1388                         {
1389                                 ISC_LIST_APPEND(*section, name, link);
1390                                 free_name = ISC_FALSE;
1391                         }
1392                 } else {
1393                         /*
1394                          * Run through the section, looking to see if this name
1395                          * is already there.  If it is found, put back the
1396                          * allocated name since we no longer need it, and set
1397                          * our name pointer to point to the name we found.
1398                          */
1399                         result = findname(&name2, name, section);
1400
1401                         /*
1402                          * If it is a new name, append to the section.
1403                          */
1404                         if (result == ISC_R_SUCCESS) {
1405                                 isc_mempool_put(msg->namepool, name);
1406                                 name = name2;
1407                         } else {
1408                                 ISC_LIST_APPEND(*section, name, link);
1409                         }
1410                         free_name = ISC_FALSE;
1411                 }
1412
1413                 /*
1414                  * Search name for the particular type and class.
1415                  * Skip this stage if in update mode or this is a meta-type.
1416                  */
1417                 if (preserve_order || msg->opcode == dns_opcode_update ||
1418                     skip_type_search)
1419                         result = ISC_R_NOTFOUND;
1420                 else {
1421                         /*
1422                          * If this is a type that can only occur in
1423                          * the question section, fail.
1424                          */
1425                         if (dns_rdatatype_questiononly(rdtype))
1426                                 DO_FORMERR;
1427
1428                         rdataset = NULL;
1429                         result = dns_message_find(name, rdclass, rdtype,
1430                                                    covers, &rdataset);
1431                 }
1432
1433                 /*
1434                  * If we found an rdataset that matches, we need to
1435                  * append this rdata to that set.  If we did not, we need
1436                  * to create a new rdatalist, store the important bits there,
1437                  * convert it to an rdataset, and link the latter to the name.
1438                  * Yuck.  When appending, make certain that the type isn't
1439                  * a singleton type, such as SOA or CNAME.
1440                  *
1441                  * Note that this check will be bypassed when preserving order,
1442                  * the opcode is an update, or the type search is skipped.
1443                  */
1444                 if (result == ISC_R_SUCCESS) {
1445                         if (dns_rdatatype_issingleton(rdtype))
1446                                 DO_FORMERR;
1447                 }
1448
1449                 if (result == ISC_R_NOTFOUND) {
1450                         rdataset = isc_mempool_get(msg->rdspool);
1451                         if (rdataset == NULL) {
1452                                 result = ISC_R_NOMEMORY;
1453                                 goto cleanup;
1454                         }
1455                         free_rdataset = ISC_TRUE;
1456
1457                         rdatalist = newrdatalist(msg);
1458                         if (rdatalist == NULL) {
1459                                 result = ISC_R_NOMEMORY;
1460                                 goto cleanup;
1461                         }
1462
1463                         rdatalist->type = rdtype;
1464                         rdatalist->covers = covers;
1465                         rdatalist->rdclass = rdclass;
1466                         rdatalist->ttl = ttl;
1467                         ISC_LIST_INIT(rdatalist->rdata);
1468
1469                         dns_rdataset_init(rdataset);
1470                         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1471                                                                rdataset)
1472                                       == ISC_R_SUCCESS);
1473
1474                         if (rdtype != dns_rdatatype_opt &&
1475                             rdtype != dns_rdatatype_tsig &&
1476                             !issigzero)
1477                         {
1478                                 ISC_LIST_APPEND(name->list, rdataset, link);
1479                                 free_rdataset = ISC_FALSE;
1480                         }
1481                 }
1482
1483                 /*
1484                  * Minimize TTLs.
1485                  *
1486                  * Section 5.2 of RFC2181 says we should drop
1487                  * nonauthoritative rrsets where the TTLs differ, but we
1488                  * currently treat them the as if they were authoritative and
1489                  * minimize them.
1490                  */
1491                 if (ttl != rdataset->ttl) {
1492                         rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1493                         if (ttl < rdataset->ttl)
1494                                 rdataset->ttl = ttl;
1495                 }
1496
1497                 /* Append this rdata to the rdataset. */
1498                 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1499                 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1500
1501                 /*
1502                  * If this is an OPT record, remember it.  Also, set
1503                  * the extended rcode.  Note that msg->opt will only be set
1504                  * if best-effort parsing is enabled.
1505                  */
1506                 if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1507                         dns_rcode_t ercode;
1508
1509                         msg->opt = rdataset;
1510                         rdataset = NULL;
1511                         free_rdataset = ISC_FALSE;
1512                         ercode = (dns_rcode_t)
1513                                 ((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1514                                  >> 20);
1515                         msg->rcode |= ercode;
1516                         isc_mempool_put(msg->namepool, name);
1517                         free_name = ISC_FALSE;
1518                 }
1519
1520                 /*
1521                  * If this is an SIG(0) or TSIG record, remember it.  Note
1522                  * that msg->sig0 or msg->tsig will only be set if best-effort
1523                  * parsing is enabled.
1524                  */
1525                 if (issigzero && msg->sig0 == NULL) {
1526                         msg->sig0 = rdataset;
1527                         msg->sig0name = name;
1528                         rdataset = NULL;
1529                         free_rdataset = ISC_FALSE;
1530                         free_name = ISC_FALSE;
1531                 } else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1532                         msg->tsig = rdataset;
1533                         msg->tsigname = name;
1534                         rdataset = NULL;
1535                         free_rdataset = ISC_FALSE;
1536                         free_name = ISC_FALSE;
1537                 }
1538
1539                 if (seen_problem) {
1540                         if (free_name)
1541                                 isc_mempool_put(msg->namepool, name);
1542                         if (free_rdataset)
1543                                 isc_mempool_put(msg->rdspool, rdataset);
1544                         free_name = free_rdataset = ISC_FALSE;
1545                 }
1546                 INSIST(free_name == ISC_FALSE);
1547                 INSIST(free_rdataset == ISC_FALSE);
1548         }
1549
1550         if (seen_problem)
1551                 return (DNS_R_RECOVERABLE);
1552         return (ISC_R_SUCCESS);
1553
1554  cleanup:
1555         if (free_name)
1556                 isc_mempool_put(msg->namepool, name);
1557         if (free_rdataset)
1558                 isc_mempool_put(msg->rdspool, rdataset);
1559
1560         return (result);
1561 }
1562
1563 isc_result_t
1564 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1565                   unsigned int options)
1566 {
1567         isc_region_t r;
1568         dns_decompress_t dctx;
1569         isc_result_t ret;
1570         isc_uint16_t tmpflags;
1571         isc_buffer_t origsource;
1572         isc_boolean_t seen_problem;
1573         isc_boolean_t ignore_tc;
1574
1575         REQUIRE(DNS_MESSAGE_VALID(msg));
1576         REQUIRE(source != NULL);
1577         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1578
1579         seen_problem = ISC_FALSE;
1580         ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1581
1582         origsource = *source;
1583
1584         msg->header_ok = 0;
1585         msg->question_ok = 0;
1586
1587         isc_buffer_remainingregion(source, &r);
1588         if (r.length < DNS_MESSAGE_HEADERLEN)
1589                 return (ISC_R_UNEXPECTEDEND);
1590
1591         msg->id = isc_buffer_getuint16(source);
1592         tmpflags = isc_buffer_getuint16(source);
1593         msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1594                        >> DNS_MESSAGE_OPCODE_SHIFT);
1595         msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1596         msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1597         msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1598         msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1599         msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1600         msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1601
1602         msg->header_ok = 1;
1603
1604         /*
1605          * -1 means no EDNS.
1606          */
1607         dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1608
1609         dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1610
1611         ret = getquestions(source, msg, &dctx, options);
1612         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1613                 goto truncated;
1614         if (ret == DNS_R_RECOVERABLE) {
1615                 seen_problem = ISC_TRUE;
1616                 ret = ISC_R_SUCCESS;
1617         }
1618         if (ret != ISC_R_SUCCESS)
1619                 return (ret);
1620         msg->question_ok = 1;
1621
1622         ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1623         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1624                 goto truncated;
1625         if (ret == DNS_R_RECOVERABLE) {
1626                 seen_problem = ISC_TRUE;
1627                 ret = ISC_R_SUCCESS;
1628         }
1629         if (ret != ISC_R_SUCCESS)
1630                 return (ret);
1631
1632         ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1633         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1634                 goto truncated;
1635         if (ret == DNS_R_RECOVERABLE) {
1636                 seen_problem = ISC_TRUE;
1637                 ret = ISC_R_SUCCESS;
1638         }
1639         if (ret != ISC_R_SUCCESS)
1640                 return (ret);
1641
1642         ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1643         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1644                 goto truncated;
1645         if (ret == DNS_R_RECOVERABLE) {
1646                 seen_problem = ISC_TRUE;
1647                 ret = ISC_R_SUCCESS;
1648         }
1649         if (ret != ISC_R_SUCCESS)
1650                 return (ret);
1651
1652         isc_buffer_remainingregion(source, &r);
1653         if (r.length != 0) {
1654                 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1655                               DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1656                               "message has %u byte(s) of trailing garbage",
1657                               r.length);
1658         }
1659
1660  truncated:
1661         if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1662                 isc_buffer_usedregion(&origsource, &msg->saved);
1663         else {
1664                 msg->saved.length = isc_buffer_usedlength(&origsource);
1665                 msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1666                 if (msg->saved.base == NULL)
1667                         return (ISC_R_NOMEMORY);
1668                 memcpy(msg->saved.base, isc_buffer_base(&origsource),
1669                        msg->saved.length);
1670                 msg->free_saved = 1;
1671         }
1672
1673         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1674                 return (DNS_R_RECOVERABLE);
1675         if (seen_problem == ISC_TRUE)
1676                 return (DNS_R_RECOVERABLE);
1677         return (ISC_R_SUCCESS);
1678 }
1679
1680 isc_result_t
1681 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1682                         isc_buffer_t *buffer)
1683 {
1684         isc_region_t r;
1685
1686         REQUIRE(DNS_MESSAGE_VALID(msg));
1687         REQUIRE(buffer != NULL);
1688         REQUIRE(msg->buffer == NULL);
1689         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1690
1691         msg->cctx = cctx;
1692
1693         /*
1694          * Erase the contents of this buffer.
1695          */
1696         isc_buffer_clear(buffer);
1697
1698         /*
1699          * Make certain there is enough for at least the header in this
1700          * buffer.
1701          */
1702         isc_buffer_availableregion(buffer, &r);
1703         if (r.length < DNS_MESSAGE_HEADERLEN)
1704                 return (ISC_R_NOSPACE);
1705
1706         if (r.length < msg->reserved)
1707                 return (ISC_R_NOSPACE);
1708
1709         /*
1710          * Reserve enough space for the header in this buffer.
1711          */
1712         isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1713
1714         msg->buffer = buffer;
1715
1716         return (ISC_R_SUCCESS);
1717 }
1718
1719 isc_result_t
1720 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1721         isc_region_t r, rn;
1722
1723         REQUIRE(DNS_MESSAGE_VALID(msg));
1724         REQUIRE(buffer != NULL);
1725         REQUIRE(msg->buffer != NULL);
1726
1727         /*
1728          * Ensure that the new buffer is empty, and has enough space to
1729          * hold the current contents.
1730          */
1731         isc_buffer_clear(buffer);
1732
1733         isc_buffer_availableregion(buffer, &rn);
1734         isc_buffer_usedregion(msg->buffer, &r);
1735         REQUIRE(rn.length > r.length);
1736
1737         /*
1738          * Copy the contents from the old to the new buffer.
1739          */
1740         isc_buffer_add(buffer, r.length);
1741         memcpy(rn.base, r.base, r.length);
1742
1743         msg->buffer = buffer;
1744
1745         return (ISC_R_SUCCESS);
1746 }
1747
1748 void
1749 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1750         REQUIRE(DNS_MESSAGE_VALID(msg));
1751         REQUIRE(space <= msg->reserved);
1752
1753         msg->reserved -= space;
1754 }
1755
1756 isc_result_t
1757 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1758         isc_region_t r;
1759
1760         REQUIRE(DNS_MESSAGE_VALID(msg));
1761
1762         if (msg->buffer != NULL) {
1763                 isc_buffer_availableregion(msg->buffer, &r);
1764                 if (r.length < (space + msg->reserved))
1765                         return (ISC_R_NOSPACE);
1766         }
1767
1768         msg->reserved += space;
1769
1770         return (ISC_R_SUCCESS);
1771 }
1772
1773 static inline isc_boolean_t
1774 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1775         int pass_needed;
1776
1777         /*
1778          * If we are not rendering class IN, this ordering is bogus.
1779          */
1780         if (rds->rdclass != dns_rdataclass_in)
1781                 return (ISC_FALSE);
1782
1783         switch (rds->type) {
1784         case dns_rdatatype_a:
1785         case dns_rdatatype_aaaa:
1786                 if (preferred_glue == rds->type)
1787                         pass_needed = 4;
1788                 else
1789                         pass_needed = 3;
1790                 break;
1791         case dns_rdatatype_rrsig:
1792         case dns_rdatatype_dnskey:
1793                 pass_needed = 2;
1794                 break;
1795         default:
1796                 pass_needed = 1;
1797         }
1798
1799         if (pass_needed >= pass)
1800                 return (ISC_FALSE);
1801
1802         return (ISC_TRUE);
1803 }
1804
1805 isc_result_t
1806 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1807                           unsigned int options)
1808 {
1809         dns_namelist_t *section;
1810         dns_name_t *name, *next_name;
1811         dns_rdataset_t *rdataset, *next_rdataset;
1812         unsigned int count, total;
1813         isc_result_t result;
1814         isc_buffer_t st; /* for rollbacks */
1815         int pass;
1816         isc_boolean_t partial = ISC_FALSE;
1817         unsigned int rd_options;
1818         dns_rdatatype_t preferred_glue = 0;
1819
1820         REQUIRE(DNS_MESSAGE_VALID(msg));
1821         REQUIRE(msg->buffer != NULL);
1822         REQUIRE(VALID_NAMED_SECTION(sectionid));
1823
1824         section = &msg->sections[sectionid];
1825
1826         if ((sectionid == DNS_SECTION_ADDITIONAL)
1827             && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1828                 if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1829                         preferred_glue = dns_rdatatype_a;
1830                         pass = 4;
1831                 } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1832                         preferred_glue = dns_rdatatype_aaaa;
1833                         pass = 4;
1834                 } else
1835                         pass = 3;
1836         } else
1837                 pass = 1;
1838
1839         if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1840                 rd_options = 0;
1841         else
1842                 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1843
1844         /*
1845          * Shrink the space in the buffer by the reserved amount.
1846          */
1847         msg->buffer->length -= msg->reserved;
1848
1849         total = 0;
1850         if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1851                 partial = ISC_TRUE;
1852
1853         /*
1854          * Render required glue first.  Set TC if it won't fit.
1855          */
1856         name = ISC_LIST_HEAD(*section);
1857         if (name != NULL) {
1858                 rdataset = ISC_LIST_HEAD(name->list);
1859                 if (rdataset != NULL &&
1860                     (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
1861                     (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
1862                         const void *order_arg = msg->order_arg;
1863                         st = *(msg->buffer);
1864                         count = 0;
1865                         if (partial)
1866                                 result = dns_rdataset_towirepartial(rdataset,
1867                                                                     name,
1868                                                                     msg->cctx,
1869                                                                     msg->buffer,
1870                                                                     msg->order,
1871                                                                     order_arg,
1872                                                                     rd_options,
1873                                                                     &count,
1874                                                                     NULL);
1875                         else
1876                                 result = dns_rdataset_towiresorted(rdataset,
1877                                                                    name,
1878                                                                    msg->cctx,
1879                                                                    msg->buffer,
1880                                                                    msg->order,
1881                                                                    order_arg,
1882                                                                    rd_options,
1883                                                                    &count);
1884                         total += count;
1885                         if (partial && result == ISC_R_NOSPACE) {
1886                                 msg->flags |= DNS_MESSAGEFLAG_TC;
1887                                 msg->buffer->length += msg->reserved;
1888                                 msg->counts[sectionid] += total;
1889                                 return (result);
1890                         }
1891                         if (result != ISC_R_SUCCESS) {
1892                                 INSIST(st.used < 65536);
1893                                 dns_compress_rollback(msg->cctx,
1894                                                       (isc_uint16_t)st.used);
1895                                 *(msg->buffer) = st;  /* rollback */
1896                                 msg->buffer->length += msg->reserved;
1897                                 msg->counts[sectionid] += total;
1898                                 return (result);
1899                         }
1900                         rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
1901                 }
1902         }
1903
1904         do {
1905                 name = ISC_LIST_HEAD(*section);
1906                 if (name == NULL) {
1907                         msg->buffer->length += msg->reserved;
1908                         msg->counts[sectionid] += total;
1909                         return (ISC_R_SUCCESS);
1910                 }
1911
1912                 while (name != NULL) {
1913                         next_name = ISC_LIST_NEXT(name, link);
1914
1915                         rdataset = ISC_LIST_HEAD(name->list);
1916                         while (rdataset != NULL) {
1917                                 next_rdataset = ISC_LIST_NEXT(rdataset, link);
1918
1919                                 if ((rdataset->attributes &
1920                                      DNS_RDATASETATTR_RENDERED) != 0)
1921                                         goto next;
1922
1923                                 if (((options & DNS_MESSAGERENDER_ORDERED)
1924                                      == 0)
1925                                     && (sectionid == DNS_SECTION_ADDITIONAL)
1926                                     && wrong_priority(rdataset, pass,
1927                                                       preferred_glue))
1928                                         goto next;
1929
1930                                 st = *(msg->buffer);
1931
1932                                 count = 0;
1933                                 if (partial)
1934                                         result = dns_rdataset_towirepartial(
1935                                                           rdataset,
1936                                                           name,
1937                                                           msg->cctx,
1938                                                           msg->buffer,
1939                                                           msg->order,
1940                                                           msg->order_arg,
1941                                                           rd_options,
1942                                                           &count,
1943                                                           NULL);
1944                                 else
1945                                         result = dns_rdataset_towiresorted(
1946                                                           rdataset,
1947                                                           name,
1948                                                           msg->cctx,
1949                                                           msg->buffer,
1950                                                           msg->order,
1951                                                           msg->order_arg,
1952                                                           rd_options,
1953                                                           &count);
1954
1955                                 total += count;
1956
1957                                 /*
1958                                  * If out of space, record stats on what we
1959                                  * rendered so far, and return that status.
1960                                  *
1961                                  * XXXMLG Need to change this when
1962                                  * dns_rdataset_towire() can render partial
1963                                  * sets starting at some arbitrary point in the
1964                                  * set.  This will include setting a bit in the
1965                                  * rdataset to indicate that a partial
1966                                  * rendering was done, and some state saved
1967                                  * somewhere (probably in the message struct)
1968                                  * to indicate where to continue from.
1969                                  */
1970                                 if (partial && result == ISC_R_NOSPACE) {
1971                                         msg->buffer->length += msg->reserved;
1972                                         msg->counts[sectionid] += total;
1973                                         return (result);
1974                                 }
1975                                 if (result != ISC_R_SUCCESS) {
1976                                         INSIST(st.used < 65536);
1977                                         dns_compress_rollback(msg->cctx,
1978                                                         (isc_uint16_t)st.used);
1979                                         *(msg->buffer) = st;  /* rollback */
1980                                         msg->buffer->length += msg->reserved;
1981                                         msg->counts[sectionid] += total;
1982                                         return (result);
1983                                 }
1984
1985                                 /*
1986                                  * If we have rendered non-validated data,
1987                                  * ensure that the AD bit is not set.
1988                                  */
1989                                 if (rdataset->trust != dns_trust_secure &&
1990                                     (sectionid == DNS_SECTION_ANSWER ||
1991                                      sectionid == DNS_SECTION_AUTHORITY))
1992                                         msg->flags &= ~DNS_MESSAGEFLAG_AD;
1993                                 if (OPTOUT(rdataset))
1994                                         msg->flags &= ~DNS_MESSAGEFLAG_AD;
1995
1996                                 rdataset->attributes |=
1997                                         DNS_RDATASETATTR_RENDERED;
1998
1999                         next:
2000                                 rdataset = next_rdataset;
2001                         }
2002
2003                         name = next_name;
2004                 }
2005         } while (--pass != 0);
2006
2007         msg->buffer->length += msg->reserved;
2008         msg->counts[sectionid] += total;
2009
2010         return (ISC_R_SUCCESS);
2011 }
2012
2013 void
2014 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2015         isc_uint16_t tmp;
2016         isc_region_t r;
2017
2018         REQUIRE(DNS_MESSAGE_VALID(msg));
2019         REQUIRE(target != NULL);
2020
2021         isc_buffer_availableregion(target, &r);
2022         REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2023
2024         isc_buffer_putuint16(target, msg->id);
2025
2026         tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
2027                & DNS_MESSAGE_OPCODE_MASK);
2028         tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2029         tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2030
2031         INSIST(msg->counts[DNS_SECTION_QUESTION]  < 65536 &&
2032                msg->counts[DNS_SECTION_ANSWER]    < 65536 &&
2033                msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2034                msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2035
2036         isc_buffer_putuint16(target, tmp);
2037         isc_buffer_putuint16(target,
2038                             (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2039         isc_buffer_putuint16(target,
2040                             (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2041         isc_buffer_putuint16(target,
2042                             (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2043         isc_buffer_putuint16(target,
2044                             (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2045 }
2046
2047 isc_result_t
2048 dns_message_renderend(dns_message_t *msg) {
2049         isc_buffer_t tmpbuf;
2050         isc_region_t r;
2051         int result;
2052         unsigned int count;
2053
2054         REQUIRE(DNS_MESSAGE_VALID(msg));
2055         REQUIRE(msg->buffer != NULL);
2056
2057         if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2058                 /*
2059                  * We have an extended rcode but are not using EDNS.
2060                  */
2061                 return (DNS_R_FORMERR);
2062         }
2063
2064         /*
2065          * If we've got an OPT record, render it.
2066          */
2067         if (msg->opt != NULL) {
2068                 dns_message_renderrelease(msg, msg->opt_reserved);
2069                 msg->opt_reserved = 0;
2070                 /*
2071                  * Set the extended rcode.
2072                  */
2073                 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2074                 msg->opt->ttl |= ((msg->rcode << 20) &
2075                                   DNS_MESSAGE_EDNSRCODE_MASK);
2076                 /*
2077                  * Render.
2078                  */
2079                 count = 0;
2080                 result = dns_rdataset_towire(msg->opt, dns_rootname,
2081                                              msg->cctx, msg->buffer, 0,
2082                                              &count);
2083                 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2084                 if (result != ISC_R_SUCCESS)
2085                         return (result);
2086         }
2087
2088         /*
2089          * If we're adding a TSIG or SIG(0) to a truncated message,
2090          * clear all rdatasets from the message except for the question
2091          * before adding the TSIG or SIG(0).  If the question doesn't fit,
2092          * don't include it.
2093          */
2094         if ((msg->tsigkey != NULL || msg->sig0key != NULL) &&
2095             (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2096         {
2097                 isc_buffer_t *buf;
2098
2099                 msgresetnames(msg, DNS_SECTION_ANSWER);
2100                 buf = msg->buffer;
2101                 dns_message_renderreset(msg);
2102                 msg->buffer = buf;
2103                 isc_buffer_clear(msg->buffer);
2104                 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2105                 dns_compress_rollback(msg->cctx, 0);
2106                 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2107                                                    0);
2108                 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2109                         return (result);
2110         }
2111
2112         /*
2113          * If we're adding a TSIG record, generate and render it.
2114          */
2115         if (msg->tsigkey != NULL) {
2116                 dns_message_renderrelease(msg, msg->sig_reserved);
2117                 msg->sig_reserved = 0;
2118                 result = dns_tsig_sign(msg);
2119                 if (result != ISC_R_SUCCESS)
2120                         return (result);
2121                 count = 0;
2122                 result = dns_rdataset_towire(msg->tsig, msg->tsigname,
2123                                              msg->cctx, msg->buffer, 0,
2124                                              &count);
2125                 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2126                 if (result != ISC_R_SUCCESS)
2127                         return (result);
2128         }
2129
2130         /*
2131          * If we're adding a SIG(0) record, generate and render it.
2132          */
2133         if (msg->sig0key != NULL) {
2134                 dns_message_renderrelease(msg, msg->sig_reserved);
2135                 msg->sig_reserved = 0;
2136                 result = dns_dnssec_signmessage(msg, msg->sig0key);
2137                 if (result != ISC_R_SUCCESS)
2138                         return (result);
2139                 count = 0;
2140                 /*
2141                  * Note: dns_rootname is used here, not msg->sig0name, since
2142                  * the owner name of a SIG(0) is irrelevant, and will not
2143                  * be set in a message being rendered.
2144                  */
2145                 result = dns_rdataset_towire(msg->sig0, dns_rootname,
2146                                              msg->cctx, msg->buffer, 0,
2147                                              &count);
2148                 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2149                 if (result != ISC_R_SUCCESS)
2150                         return (result);
2151         }
2152
2153         isc_buffer_usedregion(msg->buffer, &r);
2154         isc_buffer_init(&tmpbuf, r.base, r.length);
2155
2156         dns_message_renderheader(msg, &tmpbuf);
2157
2158         msg->buffer = NULL;  /* forget about this buffer only on success XXX */
2159
2160         return (ISC_R_SUCCESS);
2161 }
2162
2163 void
2164 dns_message_renderreset(dns_message_t *msg) {
2165         unsigned int i;
2166         dns_name_t *name;
2167         dns_rdataset_t *rds;
2168
2169         /*
2170          * Reset the message so that it may be rendered again.
2171          */
2172
2173         REQUIRE(DNS_MESSAGE_VALID(msg));
2174         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2175
2176         msg->buffer = NULL;
2177
2178         for (i = 0; i < DNS_SECTION_MAX; i++) {
2179                 msg->cursors[i] = NULL;
2180                 msg->counts[i] = 0;
2181                 for (name = ISC_LIST_HEAD(msg->sections[i]);
2182                      name != NULL;
2183                      name = ISC_LIST_NEXT(name, link)) {
2184                         for (rds = ISC_LIST_HEAD(name->list);
2185                              rds != NULL;
2186                              rds = ISC_LIST_NEXT(rds, link)) {
2187                                 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2188                         }
2189                 }
2190         }
2191         if (msg->tsigname != NULL)
2192                 dns_message_puttempname(msg, &msg->tsigname);
2193         if (msg->tsig != NULL) {
2194                 dns_rdataset_disassociate(msg->tsig);
2195                 dns_message_puttemprdataset(msg, &msg->tsig);
2196         }
2197         if (msg->sig0 != NULL) {
2198                 dns_rdataset_disassociate(msg->sig0);
2199                 dns_message_puttemprdataset(msg, &msg->sig0);
2200         }
2201 }
2202
2203 isc_result_t
2204 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2205         REQUIRE(DNS_MESSAGE_VALID(msg));
2206         REQUIRE(VALID_NAMED_SECTION(section));
2207
2208         msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2209
2210         if (msg->cursors[section] == NULL)
2211                 return (ISC_R_NOMORE);
2212
2213         return (ISC_R_SUCCESS);
2214 }
2215
2216 isc_result_t
2217 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2218         REQUIRE(DNS_MESSAGE_VALID(msg));
2219         REQUIRE(VALID_NAMED_SECTION(section));
2220         REQUIRE(msg->cursors[section] != NULL);
2221
2222         msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2223
2224         if (msg->cursors[section] == NULL)
2225                 return (ISC_R_NOMORE);
2226
2227         return (ISC_R_SUCCESS);
2228 }
2229
2230 void
2231 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2232                         dns_name_t **name)
2233 {
2234         REQUIRE(DNS_MESSAGE_VALID(msg));
2235         REQUIRE(VALID_NAMED_SECTION(section));
2236         REQUIRE(name != NULL && *name == NULL);
2237         REQUIRE(msg->cursors[section] != NULL);
2238
2239         *name = msg->cursors[section];
2240 }
2241
2242 isc_result_t
2243 dns_message_findname(dns_message_t *msg, dns_section_t section,
2244                      dns_name_t *target, dns_rdatatype_t type,
2245                      dns_rdatatype_t covers, dns_name_t **name,
2246                      dns_rdataset_t **rdataset)
2247 {
2248         dns_name_t *foundname;
2249         isc_result_t result;
2250
2251         /*
2252          * XXX These requirements are probably too intensive, especially
2253          * where things can be NULL, but as they are they ensure that if
2254          * something is NON-NULL, indicating that the caller expects it
2255          * to be filled in, that we can in fact fill it in.
2256          */
2257         REQUIRE(msg != NULL);
2258         REQUIRE(VALID_SECTION(section));
2259         REQUIRE(target != NULL);
2260         if (name != NULL)
2261                 REQUIRE(*name == NULL);
2262         if (type == dns_rdatatype_any) {
2263                 REQUIRE(rdataset == NULL);
2264         } else {
2265                 if (rdataset != NULL)
2266                         REQUIRE(*rdataset == NULL);
2267         }
2268
2269         result = findname(&foundname, target,
2270                           &msg->sections[section]);
2271
2272         if (result == ISC_R_NOTFOUND)
2273                 return (DNS_R_NXDOMAIN);
2274         else if (result != ISC_R_SUCCESS)
2275                 return (result);
2276
2277         if (name != NULL)
2278                 *name = foundname;
2279
2280         /*
2281          * And now look for the type.
2282          */
2283         if (type == dns_rdatatype_any)
2284                 return (ISC_R_SUCCESS);
2285
2286         result = dns_message_findtype(foundname, type, covers, rdataset);
2287         if (result == ISC_R_NOTFOUND)
2288                 return (DNS_R_NXRRSET);
2289
2290         return (result);
2291 }
2292
2293 void
2294 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2295                      dns_section_t fromsection,
2296                      dns_section_t tosection)
2297 {
2298         REQUIRE(msg != NULL);
2299         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2300         REQUIRE(name != NULL);
2301         REQUIRE(VALID_NAMED_SECTION(fromsection));
2302         REQUIRE(VALID_NAMED_SECTION(tosection));
2303
2304         /*
2305          * Unlink the name from the old section
2306          */
2307         ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2308         ISC_LIST_APPEND(msg->sections[tosection], name, link);
2309 }
2310
2311 void
2312 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2313                     dns_section_t section)
2314 {
2315         REQUIRE(msg != NULL);
2316         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2317         REQUIRE(name != NULL);
2318         REQUIRE(VALID_NAMED_SECTION(section));
2319
2320         ISC_LIST_APPEND(msg->sections[section], name, link);
2321 }
2322
2323 void
2324 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2325                        dns_section_t section)
2326 {
2327         REQUIRE(msg != NULL);
2328         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2329         REQUIRE(name != NULL);
2330         REQUIRE(VALID_NAMED_SECTION(section));
2331
2332         ISC_LIST_UNLINK(msg->sections[section], name, link);
2333 }
2334
2335 isc_result_t
2336 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2337         REQUIRE(DNS_MESSAGE_VALID(msg));
2338         REQUIRE(item != NULL && *item == NULL);
2339
2340         *item = isc_mempool_get(msg->namepool);
2341         if (*item == NULL)
2342                 return (ISC_R_NOMEMORY);
2343         dns_name_init(*item, NULL);
2344
2345         return (ISC_R_SUCCESS);
2346 }
2347
2348 isc_result_t
2349 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2350         REQUIRE(DNS_MESSAGE_VALID(msg));
2351         REQUIRE(item != NULL && *item == NULL);
2352
2353         *item = newoffsets(msg);
2354         if (*item == NULL)
2355                 return (ISC_R_NOMEMORY);
2356
2357         return (ISC_R_SUCCESS);
2358 }
2359
2360 isc_result_t
2361 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2362         REQUIRE(DNS_MESSAGE_VALID(msg));
2363         REQUIRE(item != NULL && *item == NULL);
2364
2365         *item = newrdata(msg);
2366         if (*item == NULL)
2367                 return (ISC_R_NOMEMORY);
2368
2369         return (ISC_R_SUCCESS);
2370 }
2371
2372 isc_result_t
2373 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2374         REQUIRE(DNS_MESSAGE_VALID(msg));
2375         REQUIRE(item != NULL && *item == NULL);
2376
2377         *item = isc_mempool_get(msg->rdspool);
2378         if (*item == NULL)
2379                 return (ISC_R_NOMEMORY);
2380
2381         dns_rdataset_init(*item);
2382
2383         return (ISC_R_SUCCESS);
2384 }
2385
2386 isc_result_t
2387 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2388         REQUIRE(DNS_MESSAGE_VALID(msg));
2389         REQUIRE(item != NULL && *item == NULL);
2390
2391         *item = newrdatalist(msg);
2392         if (*item == NULL)
2393                 return (ISC_R_NOMEMORY);
2394
2395         return (ISC_R_SUCCESS);
2396 }
2397
2398 void
2399 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2400         REQUIRE(DNS_MESSAGE_VALID(msg));
2401         REQUIRE(item != NULL && *item != NULL);
2402
2403         if (dns_name_dynamic(*item))
2404                 dns_name_free(*item, msg->mctx);
2405         isc_mempool_put(msg->namepool, *item);
2406         *item = NULL;
2407 }
2408
2409 void
2410 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2411         REQUIRE(DNS_MESSAGE_VALID(msg));
2412         REQUIRE(item != NULL && *item != NULL);
2413
2414         releaserdata(msg, *item);
2415         *item = NULL;
2416 }
2417
2418 void
2419 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2420         REQUIRE(DNS_MESSAGE_VALID(msg));
2421         REQUIRE(item != NULL && *item != NULL);
2422
2423         REQUIRE(!dns_rdataset_isassociated(*item));
2424         isc_mempool_put(msg->rdspool, *item);
2425         *item = NULL;
2426 }
2427
2428 void
2429 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2430         REQUIRE(DNS_MESSAGE_VALID(msg));
2431         REQUIRE(item != NULL && *item != NULL);
2432
2433         releaserdatalist(msg, *item);
2434         *item = NULL;
2435 }
2436
2437 isc_result_t
2438 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2439                        unsigned int *flagsp)
2440 {
2441         isc_region_t r;
2442         isc_buffer_t buffer;
2443         dns_messageid_t id;
2444         unsigned int flags;
2445
2446         REQUIRE(source != NULL);
2447
2448         buffer = *source;
2449
2450         isc_buffer_remainingregion(&buffer, &r);
2451         if (r.length < DNS_MESSAGE_HEADERLEN)
2452                 return (ISC_R_UNEXPECTEDEND);
2453
2454         id = isc_buffer_getuint16(&buffer);
2455         flags = isc_buffer_getuint16(&buffer);
2456         flags &= DNS_MESSAGE_FLAG_MASK;
2457
2458         if (flagsp != NULL)
2459                 *flagsp = flags;
2460         if (idp != NULL)
2461                 *idp = id;
2462
2463         return (ISC_R_SUCCESS);
2464 }
2465
2466 isc_result_t
2467 dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
2468         unsigned int first_section;
2469         isc_result_t result;
2470
2471         REQUIRE(DNS_MESSAGE_VALID(msg));
2472         REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2473
2474         if (!msg->header_ok)
2475                 return (DNS_R_FORMERR);
2476         if (msg->opcode != dns_opcode_query &&
2477             msg->opcode != dns_opcode_notify)
2478                 want_question_section = ISC_FALSE;
2479         if (want_question_section) {
2480                 if (!msg->question_ok)
2481                         return (DNS_R_FORMERR);
2482                 first_section = DNS_SECTION_ANSWER;
2483         } else
2484                 first_section = DNS_SECTION_QUESTION;
2485         msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2486         msgresetnames(msg, first_section);
2487         msgresetopt(msg);
2488         msgresetsigs(msg, ISC_TRUE);
2489         msginitprivate(msg);
2490         /*
2491          * We now clear most flags and then set QR, ensuring that the
2492          * reply's flags will be in a reasonable state.
2493          */
2494         msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2495         msg->flags |= DNS_MESSAGEFLAG_QR;
2496
2497         /*
2498          * This saves the query TSIG status, if the query was signed, and
2499          * reserves space in the reply for the TSIG.
2500          */
2501         if (msg->tsigkey != NULL) {
2502                 unsigned int otherlen = 0;
2503                 msg->querytsigstatus = msg->tsigstatus;
2504                 msg->tsigstatus = dns_rcode_noerror;
2505                 if (msg->querytsigstatus == dns_tsigerror_badtime)
2506                         otherlen = 6;
2507                 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2508                 result = dns_message_renderreserve(msg, msg->sig_reserved);
2509                 if (result != ISC_R_SUCCESS) {
2510                         msg->sig_reserved = 0;
2511                         return (result);
2512                 }
2513         }
2514         if (msg->saved.base != NULL) {
2515                 msg->query.base = msg->saved.base;
2516                 msg->query.length = msg->saved.length;
2517                 msg->free_query = msg->free_saved;
2518                 msg->saved.base = NULL;
2519                 msg->saved.length = 0;
2520                 msg->free_saved = 0;
2521         }
2522
2523         return (ISC_R_SUCCESS);
2524 }
2525
2526 dns_rdataset_t *
2527 dns_message_getopt(dns_message_t *msg) {
2528
2529         /*
2530          * Get the OPT record for 'msg'.
2531          */
2532
2533         REQUIRE(DNS_MESSAGE_VALID(msg));
2534
2535         return (msg->opt);
2536 }
2537
2538 isc_result_t
2539 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2540         isc_result_t result;
2541         dns_rdata_t rdata = DNS_RDATA_INIT;
2542
2543         /*
2544          * Set the OPT record for 'msg'.
2545          */
2546
2547         /*
2548          * The space required for an OPT record is:
2549          *
2550          *      1 byte for the name
2551          *      2 bytes for the type
2552          *      2 bytes for the class
2553          *      4 bytes for the ttl
2554          *      2 bytes for the rdata length
2555          * ---------------------------------
2556          *     11 bytes
2557          *
2558          * plus the length of the rdata.
2559          */
2560
2561         REQUIRE(DNS_MESSAGE_VALID(msg));
2562         REQUIRE(opt->type == dns_rdatatype_opt);
2563         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2564         REQUIRE(msg->state == DNS_SECTION_ANY);
2565
2566         msgresetopt(msg);
2567
2568         result = dns_rdataset_first(opt);
2569         if (result != ISC_R_SUCCESS)
2570                 goto cleanup;
2571         dns_rdataset_current(opt, &rdata);
2572         msg->opt_reserved = 11 + rdata.length;
2573         result = dns_message_renderreserve(msg, msg->opt_reserved);
2574         if (result != ISC_R_SUCCESS) {
2575                 msg->opt_reserved = 0;
2576                 goto cleanup;
2577         }
2578
2579         msg->opt = opt;
2580
2581         return (ISC_R_SUCCESS);
2582
2583  cleanup:
2584         dns_message_puttemprdataset(msg, &opt);
2585         return (result);
2586
2587 }
2588
2589 dns_rdataset_t *
2590 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2591
2592         /*
2593          * Get the TSIG record and owner for 'msg'.
2594          */
2595
2596         REQUIRE(DNS_MESSAGE_VALID(msg));
2597         REQUIRE(owner == NULL || *owner == NULL);
2598
2599         if (owner != NULL)
2600                 *owner = msg->tsigname;
2601         return (msg->tsig);
2602 }
2603
2604 isc_result_t
2605 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2606         isc_result_t result;
2607
2608         /*
2609          * Set the TSIG key for 'msg'
2610          */
2611
2612         REQUIRE(DNS_MESSAGE_VALID(msg));
2613         REQUIRE(msg->state == DNS_SECTION_ANY);
2614
2615         if (key == NULL && msg->tsigkey != NULL) {
2616                 if (msg->sig_reserved != 0) {
2617                         dns_message_renderrelease(msg, msg->sig_reserved);
2618                         msg->sig_reserved = 0;
2619                 }
2620                 dns_tsigkey_detach(&msg->tsigkey);
2621         }
2622         if (key != NULL) {
2623                 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2624                 dns_tsigkey_attach(key, &msg->tsigkey);
2625                 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2626                         msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2627                         result = dns_message_renderreserve(msg,
2628                                                            msg->sig_reserved);
2629                         if (result != ISC_R_SUCCESS) {
2630                                 dns_tsigkey_detach(&msg->tsigkey);
2631                                 msg->sig_reserved = 0;
2632                                 return (result);
2633                         }
2634                 }
2635         }
2636         return (ISC_R_SUCCESS);
2637 }
2638
2639 dns_tsigkey_t *
2640 dns_message_gettsigkey(dns_message_t *msg) {
2641
2642         /*
2643          * Get the TSIG key for 'msg'
2644          */
2645
2646         REQUIRE(DNS_MESSAGE_VALID(msg));
2647
2648         return (msg->tsigkey);
2649 }
2650
2651 isc_result_t
2652 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2653         dns_rdata_t *rdata = NULL;
2654         dns_rdatalist_t *list = NULL;
2655         dns_rdataset_t *set = NULL;
2656         isc_buffer_t *buf = NULL;
2657         isc_region_t r;
2658         isc_result_t result;
2659
2660         REQUIRE(DNS_MESSAGE_VALID(msg));
2661         REQUIRE(msg->querytsig == NULL);
2662
2663         if (querytsig == NULL)
2664                 return (ISC_R_SUCCESS);
2665
2666         result = dns_message_gettemprdata(msg, &rdata);
2667         if (result != ISC_R_SUCCESS)
2668                 goto cleanup;
2669
2670         result = dns_message_gettemprdatalist(msg, &list);
2671         if (result != ISC_R_SUCCESS)
2672                 goto cleanup;
2673         result = dns_message_gettemprdataset(msg, &set);
2674         if (result != ISC_R_SUCCESS)
2675                 goto cleanup;
2676
2677         isc_buffer_usedregion(querytsig, &r);
2678         result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2679         if (result != ISC_R_SUCCESS)
2680                 goto cleanup;
2681         isc_buffer_putmem(buf, r.base, r.length);
2682         isc_buffer_usedregion(buf, &r);
2683         dns_rdata_init(rdata);
2684         dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2685         dns_message_takebuffer(msg, &buf);
2686         ISC_LIST_INIT(list->rdata);
2687         ISC_LIST_APPEND(list->rdata, rdata, link);
2688         result = dns_rdatalist_tordataset(list, set);
2689         if (result != ISC_R_SUCCESS)
2690                 goto cleanup;
2691
2692         msg->querytsig = set;
2693
2694         return (result);
2695
2696  cleanup:
2697         if (rdata != NULL)
2698                 dns_message_puttemprdata(msg, &rdata);
2699         if (list != NULL)
2700                 dns_message_puttemprdatalist(msg, &list);
2701         if (set != NULL)
2702                 dns_message_puttemprdataset(msg, &set);
2703         return (ISC_R_NOMEMORY);
2704 }
2705
2706 isc_result_t
2707 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2708                          isc_buffer_t **querytsig) {
2709         isc_result_t result;
2710         dns_rdata_t rdata = DNS_RDATA_INIT;
2711         isc_region_t r;
2712
2713         REQUIRE(DNS_MESSAGE_VALID(msg));
2714         REQUIRE(mctx != NULL);
2715         REQUIRE(querytsig != NULL && *querytsig == NULL);
2716
2717         if (msg->tsig == NULL)
2718                 return (ISC_R_SUCCESS);
2719
2720         result = dns_rdataset_first(msg->tsig);
2721         if (result != ISC_R_SUCCESS)
2722                 return (result);
2723         dns_rdataset_current(msg->tsig, &rdata);
2724         dns_rdata_toregion(&rdata, &r);
2725
2726         result = isc_buffer_allocate(mctx, querytsig, r.length);
2727         if (result != ISC_R_SUCCESS)
2728                 return (result);
2729         isc_buffer_putmem(*querytsig, r.base, r.length);
2730         return (ISC_R_SUCCESS);
2731 }
2732
2733 dns_rdataset_t *
2734 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2735
2736         /*
2737          * Get the SIG(0) record for 'msg'.
2738          */
2739
2740         REQUIRE(DNS_MESSAGE_VALID(msg));
2741         REQUIRE(owner == NULL || *owner == NULL);
2742
2743         if (msg->sig0 != NULL && owner != NULL) {
2744                 /* If dns_message_getsig0 is called on a rendered message
2745                  * after the SIG(0) has been applied, we need to return the
2746                  * root name, not NULL.
2747                  */
2748                 if (msg->sig0name == NULL)
2749                         *owner = dns_rootname;
2750                 else
2751                         *owner = msg->sig0name;
2752         }
2753         return (msg->sig0);
2754 }
2755
2756 isc_result_t
2757 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2758         isc_region_t r;
2759         unsigned int x;
2760         isc_result_t result;
2761
2762         /*
2763          * Set the SIG(0) key for 'msg'
2764          */
2765
2766         /*
2767          * The space required for an SIG(0) record is:
2768          *
2769          *      1 byte for the name
2770          *      2 bytes for the type
2771          *      2 bytes for the class
2772          *      4 bytes for the ttl
2773          *      2 bytes for the type covered
2774          *      1 byte for the algorithm
2775          *      1 bytes for the labels
2776          *      4 bytes for the original ttl
2777          *      4 bytes for the signature expiration
2778          *      4 bytes for the signature inception
2779          *      2 bytes for the key tag
2780          *      n bytes for the signer's name
2781          *      x bytes for the signature
2782          * ---------------------------------
2783          *     27 + n + x bytes
2784          */
2785         REQUIRE(DNS_MESSAGE_VALID(msg));
2786         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2787         REQUIRE(msg->state == DNS_SECTION_ANY);
2788
2789         if (key != NULL) {
2790                 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2791                 dns_name_toregion(dst_key_name(key), &r);
2792                 result = dst_key_sigsize(key, &x);
2793                 if (result != ISC_R_SUCCESS) {
2794                         msg->sig_reserved = 0;
2795                         return (result);
2796                 }
2797                 msg->sig_reserved = 27 + r.length + x;
2798                 result = dns_message_renderreserve(msg, msg->sig_reserved);
2799                 if (result != ISC_R_SUCCESS) {
2800                         msg->sig_reserved = 0;
2801                         return (result);
2802                 }
2803                 msg->sig0key = key;
2804         }
2805         return (ISC_R_SUCCESS);
2806 }
2807
2808 dst_key_t *
2809 dns_message_getsig0key(dns_message_t *msg) {
2810
2811         /*
2812          * Get the SIG(0) key for 'msg'
2813          */
2814
2815         REQUIRE(DNS_MESSAGE_VALID(msg));
2816
2817         return (msg->sig0key);
2818 }
2819
2820 void
2821 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2822         REQUIRE(DNS_MESSAGE_VALID(msg));
2823         REQUIRE(buffer != NULL);
2824         REQUIRE(ISC_BUFFER_VALID(*buffer));
2825
2826         ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2827         *buffer = NULL;
2828 }
2829
2830 isc_result_t
2831 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
2832         isc_result_t result = ISC_R_SUCCESS;
2833         dns_rdata_t rdata = DNS_RDATA_INIT;
2834
2835         REQUIRE(DNS_MESSAGE_VALID(msg));
2836         REQUIRE(signer != NULL);
2837         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2838
2839         if (msg->tsig == NULL && msg->sig0 == NULL)
2840                 return (ISC_R_NOTFOUND);
2841
2842         if (msg->verify_attempted == 0)
2843                 return (DNS_R_NOTVERIFIEDYET);
2844
2845         if (!dns_name_hasbuffer(signer)) {
2846                 isc_buffer_t *dynbuf = NULL;
2847                 result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
2848                 if (result != ISC_R_SUCCESS)
2849                         return (result);
2850                 dns_name_setbuffer(signer, dynbuf);
2851                 dns_message_takebuffer(msg, &dynbuf);
2852         }
2853
2854         if (msg->sig0 != NULL) {
2855                 dns_rdata_sig_t sig;
2856
2857                 result = dns_rdataset_first(msg->sig0);
2858                 INSIST(result == ISC_R_SUCCESS);
2859                 dns_rdataset_current(msg->sig0, &rdata);
2860
2861                 result = dns_rdata_tostruct(&rdata, &sig, NULL);
2862                 if (result != ISC_R_SUCCESS)
2863                         return (result);
2864
2865                 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
2866                         result = ISC_R_SUCCESS;
2867                 else
2868                         result = DNS_R_SIGINVALID;
2869                 dns_name_clone(&sig.signer, signer);
2870                 dns_rdata_freestruct(&sig);
2871         } else {
2872                 dns_name_t *identity;
2873                 dns_rdata_any_tsig_t tsig;
2874
2875                 result = dns_rdataset_first(msg->tsig);
2876                 INSIST(result == ISC_R_SUCCESS);
2877                 dns_rdataset_current(msg->tsig, &rdata);
2878
2879                 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2880                 if (msg->tsigstatus != dns_rcode_noerror)
2881                         result = DNS_R_TSIGVERIFYFAILURE;
2882                 else if (tsig.error != dns_rcode_noerror)
2883                         result = DNS_R_TSIGERRORSET;
2884                 else
2885                         result = ISC_R_SUCCESS;
2886                 dns_rdata_freestruct(&tsig);
2887
2888                 if (msg->tsigkey == NULL) {
2889                         /*
2890                          * If msg->tsigstatus & tsig.error are both
2891                          * dns_rcode_noerror, the message must have been
2892                          * verified, which means msg->tsigkey will be
2893                          * non-NULL.
2894                          */
2895                         INSIST(result != ISC_R_SUCCESS);
2896                 } else {
2897                         identity = dns_tsigkey_identity(msg->tsigkey);
2898                         if (identity == NULL) {
2899                                 if (result == ISC_R_SUCCESS)
2900                                         result = DNS_R_NOIDENTITY;
2901                                 identity = &msg->tsigkey->name;
2902                         }
2903                         dns_name_clone(identity, signer);
2904                 }
2905         }
2906
2907         return (result);
2908 }
2909
2910 void
2911 dns_message_resetsig(dns_message_t *msg) {
2912         REQUIRE(DNS_MESSAGE_VALID(msg));
2913         msg->verified_sig = 0;
2914         msg->verify_attempted = 0;
2915         msg->tsigstatus = dns_rcode_noerror;
2916         msg->sig0status = dns_rcode_noerror;
2917         msg->timeadjust = 0;
2918         if (msg->tsigkey != NULL) {
2919                 dns_tsigkey_detach(&msg->tsigkey);
2920                 msg->tsigkey = NULL;
2921         }
2922 }
2923
2924 isc_result_t
2925 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
2926         dns_message_resetsig(msg);
2927         return (dns_message_checksig(msg, view));
2928 }
2929
2930 #ifdef SKAN_MSG_DEBUG
2931 void
2932 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
2933         dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
2934         dns_rdata_any_tsig_t querytsig;
2935         isc_result_t result;
2936
2937         if (msg->tsig != NULL) {
2938                 result = dns_rdataset_first(msg->tsig);
2939                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2940                 dns_rdataset_current(msg->tsig, &querytsigrdata);
2941                 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
2942                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2943                 hexdump(txt1, "TSIG", querytsig.signature,
2944                         querytsig.siglen);
2945         }
2946
2947         if (msg->querytsig != NULL) {
2948                 result = dns_rdataset_first(msg->querytsig);
2949                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2950                 dns_rdataset_current(msg->querytsig, &querytsigrdata);
2951                 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
2952                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2953                 hexdump(txt1, "QUERYTSIG", querytsig.signature,
2954                         querytsig.siglen);
2955         }
2956 }
2957 #endif
2958
2959 isc_result_t
2960 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
2961         isc_buffer_t b, msgb;
2962
2963         REQUIRE(DNS_MESSAGE_VALID(msg));
2964
2965         if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
2966                 return (ISC_R_SUCCESS);
2967
2968         INSIST(msg->saved.base != NULL);
2969         isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
2970         isc_buffer_add(&msgb, msg->saved.length);
2971         if (msg->tsigkey != NULL || msg->tsig != NULL) {
2972 #ifdef SKAN_MSG_DEBUG
2973                 dns_message_dumpsig(msg, "dns_message_checksig#1");
2974 #endif
2975                 if (view != NULL)
2976                         return (dns_view_checksig(view, &msgb, msg));
2977                 else
2978                         return (dns_tsig_verify(&msgb, msg, NULL, NULL));
2979         } else {
2980                 dns_rdata_t rdata = DNS_RDATA_INIT;
2981                 dns_rdata_sig_t sig;
2982                 dns_rdataset_t keyset;
2983                 isc_result_t result;
2984
2985                 result = dns_rdataset_first(msg->sig0);
2986                 INSIST(result == ISC_R_SUCCESS);
2987                 dns_rdataset_current(msg->sig0, &rdata);
2988
2989                 /*
2990                  * This can occur when the message is a dynamic update, since
2991                  * the rdata length checking is relaxed.  This should not
2992                  * happen in a well-formed message, since the SIG(0) is only
2993                  * looked for in the additional section, and the dynamic update
2994                  * meta-records are in the prerequisite and update sections.
2995                  */
2996                 if (rdata.length == 0)
2997                         return (ISC_R_UNEXPECTEDEND);
2998
2999                 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
3000                 if (result != ISC_R_SUCCESS)
3001                         return (result);
3002
3003                 dns_rdataset_init(&keyset);
3004                 if (view == NULL)
3005                         return (DNS_R_KEYUNAUTHORIZED);
3006                 result = dns_view_simplefind(view, &sig.signer,
3007                                              dns_rdatatype_key /* SIG(0) */,
3008                                              0, 0, ISC_FALSE, &keyset, NULL);
3009
3010                 if (result != ISC_R_SUCCESS) {
3011                         /* XXXBEW Should possibly create a fetch here */
3012                         result = DNS_R_KEYUNAUTHORIZED;
3013                         goto freesig;
3014                 } else if (keyset.trust < dns_trust_secure) {
3015                         /* XXXBEW Should call a validator here */
3016                         result = DNS_R_KEYUNAUTHORIZED;
3017                         goto freesig;
3018                 }
3019                 result = dns_rdataset_first(&keyset);
3020                 INSIST(result == ISC_R_SUCCESS);
3021                 for (;
3022                      result == ISC_R_SUCCESS;
3023                      result = dns_rdataset_next(&keyset))
3024                 {
3025                         dst_key_t *key = NULL;
3026
3027                         dns_rdata_reset(&rdata);
3028                         dns_rdataset_current(&keyset, &rdata);
3029                         isc_buffer_init(&b, rdata.data, rdata.length);
3030                         isc_buffer_add(&b, rdata.length);
3031
3032                         result = dst_key_fromdns(&sig.signer, rdata.rdclass,
3033                                                  &b, view->mctx, &key);
3034                         if (result != ISC_R_SUCCESS)
3035                                 continue;
3036                         if (dst_key_alg(key) != sig.algorithm ||
3037                             dst_key_id(key) != sig.keyid ||
3038                             !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3039                               dst_key_proto(key) == DNS_KEYPROTO_ANY))
3040                         {
3041                                 dst_key_free(&key);
3042                                 continue;
3043                         }
3044                         result = dns_dnssec_verifymessage(&msgb, msg, key);
3045                         dst_key_free(&key);
3046                         if (result == ISC_R_SUCCESS)
3047                                 break;
3048                 }
3049                 if (result == ISC_R_NOMORE)
3050                         result = DNS_R_KEYUNAUTHORIZED;
3051
3052  freesig:
3053                 if (dns_rdataset_isassociated(&keyset))
3054                         dns_rdataset_disassociate(&keyset);
3055                 dns_rdata_freestruct(&sig);
3056                 return (result);
3057         }
3058 }
3059
3060 isc_result_t
3061 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3062                           const dns_master_style_t *style,
3063                           dns_messagetextflag_t flags,
3064                           isc_buffer_t *target) {
3065         dns_name_t *name, empty_name;
3066         dns_rdataset_t *rdataset;
3067         isc_result_t result;
3068
3069         REQUIRE(DNS_MESSAGE_VALID(msg));
3070         REQUIRE(target != NULL);
3071         REQUIRE(VALID_SECTION(section));
3072
3073         if (ISC_LIST_EMPTY(msg->sections[section]))
3074                 return (ISC_R_SUCCESS);
3075
3076         if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3077                 ADD_STRING(target, ";; ");
3078                 if (msg->opcode != dns_opcode_update) {
3079                         ADD_STRING(target, sectiontext[section]);
3080                 } else {
3081                         ADD_STRING(target, updsectiontext[section]);
3082                 }
3083                 ADD_STRING(target, " SECTION:\n");
3084         }
3085
3086         dns_name_init(&empty_name, NULL);
3087         result = dns_message_firstname(msg, section);
3088         if (result != ISC_R_SUCCESS) {
3089                 return (result);
3090         }
3091         do {
3092                 name = NULL;
3093                 dns_message_currentname(msg, section, &name);
3094                 for (rdataset = ISC_LIST_HEAD(name->list);
3095                      rdataset != NULL;
3096                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
3097                         if (section == DNS_SECTION_QUESTION) {
3098                                 ADD_STRING(target, ";");
3099                                 result = dns_master_questiontotext(name,
3100                                                                    rdataset,
3101                                                                    style,
3102                                                                    target);
3103                         } else {
3104                                 result = dns_master_rdatasettotext(name,
3105                                                                    rdataset,
3106                                                                    style,
3107                                                                    target);
3108                         }
3109                         if (result != ISC_R_SUCCESS)
3110                                 return (result);
3111                 }
3112                 result = dns_message_nextname(msg, section);
3113         } while (result == ISC_R_SUCCESS);
3114         if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3115             (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3116                 ADD_STRING(target, "\n");
3117         if (result == ISC_R_NOMORE)
3118                 result = ISC_R_SUCCESS;
3119         return (result);
3120 }
3121
3122 isc_result_t
3123 dns_message_pseudosectiontotext(dns_message_t *msg,
3124                                 dns_pseudosection_t section,
3125                                 const dns_master_style_t *style,
3126                                 dns_messagetextflag_t flags,
3127                                 isc_buffer_t *target) {
3128         dns_rdataset_t *ps = NULL;
3129         dns_name_t *name = NULL;
3130         isc_result_t result;
3131         char buf[sizeof("1234567890")];
3132         isc_uint32_t mbz;
3133         dns_rdata_t rdata;
3134         isc_buffer_t optbuf;
3135         isc_uint16_t optcode, optlen;
3136         unsigned char *optdata;
3137
3138         REQUIRE(DNS_MESSAGE_VALID(msg));
3139         REQUIRE(target != NULL);
3140         REQUIRE(VALID_PSEUDOSECTION(section));
3141
3142         switch (section) {
3143         case DNS_PSEUDOSECTION_OPT:
3144                 ps = dns_message_getopt(msg);
3145                 if (ps == NULL)
3146                         return (ISC_R_SUCCESS);
3147                 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3148                         ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3149                 ADD_STRING(target, "; EDNS: version: ");
3150                 snprintf(buf, sizeof(buf), "%u",
3151                          (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3152                 ADD_STRING(target, buf);
3153                 ADD_STRING(target, ", flags:");
3154                 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3155                         ADD_STRING(target, " do");
3156                 mbz = ps->ttl & ~DNS_MESSAGEEXTFLAG_DO & 0xffff;
3157                 if (mbz != 0) {
3158                         ADD_STRING(target, "; MBZ: ");
3159                         snprintf(buf, sizeof(buf), "%.4x ", mbz);
3160                         ADD_STRING(target, buf);
3161                         ADD_STRING(target, ", udp: ");
3162                 } else
3163                         ADD_STRING(target, "; udp: ");
3164                 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3165                 ADD_STRING(target, buf);
3166
3167                 result = dns_rdataset_first(ps);
3168                 if (result != ISC_R_SUCCESS)
3169                         return (ISC_R_SUCCESS);
3170
3171                 /* Print EDNS info, if any */
3172                 dns_rdata_init(&rdata);
3173                 dns_rdataset_current(ps, &rdata);
3174                 if (rdata.length < 4)
3175                         return (ISC_R_SUCCESS);
3176
3177                 isc_buffer_init(&optbuf, rdata.data, rdata.length);
3178                 isc_buffer_add(&optbuf, rdata.length);
3179                 optcode = isc_buffer_getuint16(&optbuf);
3180                 optlen = isc_buffer_getuint16(&optbuf);
3181
3182                 if (optcode == DNS_OPT_NSID) {
3183                         ADD_STRING(target, "; NSID");
3184                 } else {
3185                         ADD_STRING(target, "; OPT=");
3186                         sprintf(buf, "%u", optcode);
3187                         ADD_STRING(target, buf);
3188                 }
3189
3190                 if (optlen != 0) {
3191                         int i;
3192                         ADD_STRING(target, ": ");
3193
3194                         optdata = rdata.data + 4;
3195                         for (i = 0; i < optlen; i++) {
3196                                 sprintf(buf, "%02x ", optdata[i]);
3197                                 ADD_STRING(target, buf);
3198                         }
3199                         for (i = 0; i < optlen; i++) {
3200                                 ADD_STRING(target, " (");
3201                                 if (isprint(optdata[i]))
3202                                         isc_buffer_putmem(target, &optdata[i],
3203                                                           1);
3204                                 else
3205                                         isc_buffer_putstr(target, ".");
3206                                 ADD_STRING(target, ")");
3207                         }
3208                 }
3209                 ADD_STRING(target, "\n");
3210                 return (ISC_R_SUCCESS);
3211         case DNS_PSEUDOSECTION_TSIG:
3212                 ps = dns_message_gettsig(msg, &name);
3213                 if (ps == NULL)
3214                         return (ISC_R_SUCCESS);
3215                 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3216                         ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
3217                 result = dns_master_rdatasettotext(name, ps, style, target);
3218                 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3219                     (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3220                         ADD_STRING(target, "\n");
3221                 return (result);
3222         case DNS_PSEUDOSECTION_SIG0:
3223                 ps = dns_message_getsig0(msg, &name);
3224                 if (ps == NULL)
3225                         return (ISC_R_SUCCESS);
3226                 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3227                         ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3228                 result = dns_master_rdatasettotext(name, ps, style, target);
3229                 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3230                     (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3231                         ADD_STRING(target, "\n");
3232                 return (result);
3233         }
3234         return (ISC_R_UNEXPECTED);
3235 }
3236
3237 isc_result_t
3238 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3239                    dns_messagetextflag_t flags, isc_buffer_t *target) {
3240         char buf[sizeof("1234567890")];
3241         isc_result_t result;
3242
3243         REQUIRE(DNS_MESSAGE_VALID(msg));
3244         REQUIRE(target != NULL);
3245
3246         if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
3247                 ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
3248                 ADD_STRING(target, opcodetext[msg->opcode]);
3249                 ADD_STRING(target, ", status: ");
3250                 if (msg->rcode < (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
3251                         ADD_STRING(target, rcodetext[msg->rcode]);
3252                 } else {
3253                         snprintf(buf, sizeof(buf), "%4u", msg->rcode);
3254                         ADD_STRING(target, buf);
3255                 }
3256                 ADD_STRING(target, ", id: ");
3257                 snprintf(buf, sizeof(buf), "%6u", msg->id);
3258                 ADD_STRING(target, buf);
3259                 ADD_STRING(target, "\n;; flags: ");
3260                 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3261                         ADD_STRING(target, "qr ");
3262                 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3263                         ADD_STRING(target, "aa ");
3264                 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3265                         ADD_STRING(target, "tc ");
3266                 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3267                         ADD_STRING(target, "rd ");
3268                 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3269                         ADD_STRING(target, "ra ");
3270                 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3271                         ADD_STRING(target, "ad ");
3272                 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
3273                         ADD_STRING(target, "cd ");
3274                 if (msg->opcode != dns_opcode_update) {
3275                         ADD_STRING(target, "; QUESTION: ");
3276                 } else {
3277                         ADD_STRING(target, "; ZONE: ");
3278                 }
3279                 snprintf(buf, sizeof(buf), "%1u",
3280                          msg->counts[DNS_SECTION_QUESTION]);
3281                 ADD_STRING(target, buf);
3282                 if (msg->opcode != dns_opcode_update) {
3283                         ADD_STRING(target, ", ANSWER: ");
3284                 } else {
3285                         ADD_STRING(target, ", PREREQ: ");
3286                 }
3287                 snprintf(buf, sizeof(buf), "%1u",
3288                          msg->counts[DNS_SECTION_ANSWER]);
3289                 ADD_STRING(target, buf);
3290                 if (msg->opcode != dns_opcode_update) {
3291                         ADD_STRING(target, ", AUTHORITY: ");
3292                 } else {
3293                         ADD_STRING(target, ", UPDATE: ");
3294                 }
3295                 snprintf(buf, sizeof(buf), "%1u",
3296                         msg->counts[DNS_SECTION_AUTHORITY]);
3297                 ADD_STRING(target, buf);
3298                 ADD_STRING(target, ", ADDITIONAL: ");
3299                 snprintf(buf, sizeof(buf), "%1u",
3300                         msg->counts[DNS_SECTION_ADDITIONAL]);
3301                 ADD_STRING(target, buf);
3302                 ADD_STRING(target, "\n");
3303         }
3304         result = dns_message_pseudosectiontotext(msg,
3305                                                  DNS_PSEUDOSECTION_OPT,
3306                                                  style, flags, target);
3307         if (result != ISC_R_SUCCESS)
3308                 return (result);
3309
3310         result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
3311                                            style, flags, target);
3312         if (result != ISC_R_SUCCESS)
3313                 return (result);
3314         result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
3315                                            style, flags, target);
3316         if (result != ISC_R_SUCCESS)
3317                 return (result);
3318         result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
3319                                            style, flags, target);
3320         if (result != ISC_R_SUCCESS)
3321                 return (result);
3322         result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
3323                                            style, flags, target);
3324         if (result != ISC_R_SUCCESS)
3325                 return (result);
3326
3327         result = dns_message_pseudosectiontotext(msg,
3328                                                  DNS_PSEUDOSECTION_TSIG,
3329                                                  style, flags, target);
3330         if (result != ISC_R_SUCCESS)
3331                 return (result);
3332
3333         result = dns_message_pseudosectiontotext(msg,
3334                                                  DNS_PSEUDOSECTION_SIG0,
3335                                                  style, flags, target);
3336         if (result != ISC_R_SUCCESS)
3337                 return (result);
3338
3339         return (ISC_R_SUCCESS);
3340 }
3341
3342 isc_region_t *
3343 dns_message_getrawmessage(dns_message_t *msg) {
3344         REQUIRE(DNS_MESSAGE_VALID(msg));
3345         return (&msg->saved);
3346 }
3347
3348 void
3349 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3350                          const void *order_arg)
3351 {
3352         REQUIRE(DNS_MESSAGE_VALID(msg));
3353         msg->order = order;
3354         msg->order_arg = order_arg;
3355 }
3356
3357 void
3358 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3359         REQUIRE(DNS_MESSAGE_VALID(msg));
3360         msg->timeadjust = timeadjust;
3361 }
3362
3363 int
3364 dns_message_gettimeadjust(dns_message_t *msg) {
3365         REQUIRE(DNS_MESSAGE_VALID(msg));
3366         return (msg->timeadjust);
3367 }
3368
3369 isc_result_t
3370 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3371
3372         REQUIRE(opcode < 16);
3373
3374         if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
3375                 return (ISC_R_NOSPACE);
3376         isc_buffer_putstr(target, opcodetext[opcode]);
3377         return (ISC_R_SUCCESS);
3378 }