]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - contrib/bind9/lib/dns/message.c
Update to version 9.6-ESV-R4-P3
[FreeBSD/stable/8.git] / contrib / bind9 / lib / dns / message.c
1 /*
2  * Copyright (C) 2004-2011  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.7.6.3 2011-06-21 20:13:22 each 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                         /* Windows doesn't like TSIG names to be compressed. */
1535                         msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1536                         rdataset = NULL;
1537                         free_rdataset = ISC_FALSE;
1538                         free_name = ISC_FALSE;
1539                 }
1540
1541                 if (seen_problem) {
1542                         if (free_name)
1543                                 isc_mempool_put(msg->namepool, name);
1544                         if (free_rdataset)
1545                                 isc_mempool_put(msg->rdspool, rdataset);
1546                         free_name = free_rdataset = ISC_FALSE;
1547                 }
1548                 INSIST(free_name == ISC_FALSE);
1549                 INSIST(free_rdataset == ISC_FALSE);
1550         }
1551
1552         if (seen_problem)
1553                 return (DNS_R_RECOVERABLE);
1554         return (ISC_R_SUCCESS);
1555
1556  cleanup:
1557         if (free_name)
1558                 isc_mempool_put(msg->namepool, name);
1559         if (free_rdataset)
1560                 isc_mempool_put(msg->rdspool, rdataset);
1561
1562         return (result);
1563 }
1564
1565 isc_result_t
1566 dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1567                   unsigned int options)
1568 {
1569         isc_region_t r;
1570         dns_decompress_t dctx;
1571         isc_result_t ret;
1572         isc_uint16_t tmpflags;
1573         isc_buffer_t origsource;
1574         isc_boolean_t seen_problem;
1575         isc_boolean_t ignore_tc;
1576
1577         REQUIRE(DNS_MESSAGE_VALID(msg));
1578         REQUIRE(source != NULL);
1579         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1580
1581         seen_problem = ISC_FALSE;
1582         ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1583
1584         origsource = *source;
1585
1586         msg->header_ok = 0;
1587         msg->question_ok = 0;
1588
1589         isc_buffer_remainingregion(source, &r);
1590         if (r.length < DNS_MESSAGE_HEADERLEN)
1591                 return (ISC_R_UNEXPECTEDEND);
1592
1593         msg->id = isc_buffer_getuint16(source);
1594         tmpflags = isc_buffer_getuint16(source);
1595         msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1596                        >> DNS_MESSAGE_OPCODE_SHIFT);
1597         msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1598         msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1599         msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1600         msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1601         msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1602         msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1603
1604         msg->header_ok = 1;
1605
1606         /*
1607          * -1 means no EDNS.
1608          */
1609         dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1610
1611         dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1612
1613         ret = getquestions(source, msg, &dctx, options);
1614         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1615                 goto truncated;
1616         if (ret == DNS_R_RECOVERABLE) {
1617                 seen_problem = ISC_TRUE;
1618                 ret = ISC_R_SUCCESS;
1619         }
1620         if (ret != ISC_R_SUCCESS)
1621                 return (ret);
1622         msg->question_ok = 1;
1623
1624         ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1625         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1626                 goto truncated;
1627         if (ret == DNS_R_RECOVERABLE) {
1628                 seen_problem = ISC_TRUE;
1629                 ret = ISC_R_SUCCESS;
1630         }
1631         if (ret != ISC_R_SUCCESS)
1632                 return (ret);
1633
1634         ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1635         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1636                 goto truncated;
1637         if (ret == DNS_R_RECOVERABLE) {
1638                 seen_problem = ISC_TRUE;
1639                 ret = ISC_R_SUCCESS;
1640         }
1641         if (ret != ISC_R_SUCCESS)
1642                 return (ret);
1643
1644         ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1645         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1646                 goto truncated;
1647         if (ret == DNS_R_RECOVERABLE) {
1648                 seen_problem = ISC_TRUE;
1649                 ret = ISC_R_SUCCESS;
1650         }
1651         if (ret != ISC_R_SUCCESS)
1652                 return (ret);
1653
1654         isc_buffer_remainingregion(source, &r);
1655         if (r.length != 0) {
1656                 isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1657                               DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1658                               "message has %u byte(s) of trailing garbage",
1659                               r.length);
1660         }
1661
1662  truncated:
1663         if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1664                 isc_buffer_usedregion(&origsource, &msg->saved);
1665         else {
1666                 msg->saved.length = isc_buffer_usedlength(&origsource);
1667                 msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1668                 if (msg->saved.base == NULL)
1669                         return (ISC_R_NOMEMORY);
1670                 memcpy(msg->saved.base, isc_buffer_base(&origsource),
1671                        msg->saved.length);
1672                 msg->free_saved = 1;
1673         }
1674
1675         if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1676                 return (DNS_R_RECOVERABLE);
1677         if (seen_problem == ISC_TRUE)
1678                 return (DNS_R_RECOVERABLE);
1679         return (ISC_R_SUCCESS);
1680 }
1681
1682 isc_result_t
1683 dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1684                         isc_buffer_t *buffer)
1685 {
1686         isc_region_t r;
1687
1688         REQUIRE(DNS_MESSAGE_VALID(msg));
1689         REQUIRE(buffer != NULL);
1690         REQUIRE(msg->buffer == NULL);
1691         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1692
1693         msg->cctx = cctx;
1694
1695         /*
1696          * Erase the contents of this buffer.
1697          */
1698         isc_buffer_clear(buffer);
1699
1700         /*
1701          * Make certain there is enough for at least the header in this
1702          * buffer.
1703          */
1704         isc_buffer_availableregion(buffer, &r);
1705         if (r.length < DNS_MESSAGE_HEADERLEN)
1706                 return (ISC_R_NOSPACE);
1707
1708         if (r.length < msg->reserved)
1709                 return (ISC_R_NOSPACE);
1710
1711         /*
1712          * Reserve enough space for the header in this buffer.
1713          */
1714         isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1715
1716         msg->buffer = buffer;
1717
1718         return (ISC_R_SUCCESS);
1719 }
1720
1721 isc_result_t
1722 dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1723         isc_region_t r, rn;
1724
1725         REQUIRE(DNS_MESSAGE_VALID(msg));
1726         REQUIRE(buffer != NULL);
1727         REQUIRE(msg->buffer != NULL);
1728
1729         /*
1730          * Ensure that the new buffer is empty, and has enough space to
1731          * hold the current contents.
1732          */
1733         isc_buffer_clear(buffer);
1734
1735         isc_buffer_availableregion(buffer, &rn);
1736         isc_buffer_usedregion(msg->buffer, &r);
1737         REQUIRE(rn.length > r.length);
1738
1739         /*
1740          * Copy the contents from the old to the new buffer.
1741          */
1742         isc_buffer_add(buffer, r.length);
1743         memcpy(rn.base, r.base, r.length);
1744
1745         msg->buffer = buffer;
1746
1747         return (ISC_R_SUCCESS);
1748 }
1749
1750 void
1751 dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1752         REQUIRE(DNS_MESSAGE_VALID(msg));
1753         REQUIRE(space <= msg->reserved);
1754
1755         msg->reserved -= space;
1756 }
1757
1758 isc_result_t
1759 dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1760         isc_region_t r;
1761
1762         REQUIRE(DNS_MESSAGE_VALID(msg));
1763
1764         if (msg->buffer != NULL) {
1765                 isc_buffer_availableregion(msg->buffer, &r);
1766                 if (r.length < (space + msg->reserved))
1767                         return (ISC_R_NOSPACE);
1768         }
1769
1770         msg->reserved += space;
1771
1772         return (ISC_R_SUCCESS);
1773 }
1774
1775 static inline isc_boolean_t
1776 wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1777         int pass_needed;
1778
1779         /*
1780          * If we are not rendering class IN, this ordering is bogus.
1781          */
1782         if (rds->rdclass != dns_rdataclass_in)
1783                 return (ISC_FALSE);
1784
1785         switch (rds->type) {
1786         case dns_rdatatype_a:
1787         case dns_rdatatype_aaaa:
1788                 if (preferred_glue == rds->type)
1789                         pass_needed = 4;
1790                 else
1791                         pass_needed = 3;
1792                 break;
1793         case dns_rdatatype_rrsig:
1794         case dns_rdatatype_dnskey:
1795                 pass_needed = 2;
1796                 break;
1797         default:
1798                 pass_needed = 1;
1799         }
1800
1801         if (pass_needed >= pass)
1802                 return (ISC_FALSE);
1803
1804         return (ISC_TRUE);
1805 }
1806
1807 isc_result_t
1808 dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1809                           unsigned int options)
1810 {
1811         dns_namelist_t *section;
1812         dns_name_t *name, *next_name;
1813         dns_rdataset_t *rdataset, *next_rdataset;
1814         unsigned int count, total;
1815         isc_result_t result;
1816         isc_buffer_t st; /* for rollbacks */
1817         int pass;
1818         isc_boolean_t partial = ISC_FALSE;
1819         unsigned int rd_options;
1820         dns_rdatatype_t preferred_glue = 0;
1821
1822         REQUIRE(DNS_MESSAGE_VALID(msg));
1823         REQUIRE(msg->buffer != NULL);
1824         REQUIRE(VALID_NAMED_SECTION(sectionid));
1825
1826         section = &msg->sections[sectionid];
1827
1828         if ((sectionid == DNS_SECTION_ADDITIONAL)
1829             && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1830                 if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1831                         preferred_glue = dns_rdatatype_a;
1832                         pass = 4;
1833                 } else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1834                         preferred_glue = dns_rdatatype_aaaa;
1835                         pass = 4;
1836                 } else
1837                         pass = 3;
1838         } else
1839                 pass = 1;
1840
1841         if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1842                 rd_options = 0;
1843         else
1844                 rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1845
1846         /*
1847          * Shrink the space in the buffer by the reserved amount.
1848          */
1849         msg->buffer->length -= msg->reserved;
1850
1851         total = 0;
1852         if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1853                 partial = ISC_TRUE;
1854
1855         /*
1856          * Render required glue first.  Set TC if it won't fit.
1857          */
1858         name = ISC_LIST_HEAD(*section);
1859         if (name != NULL) {
1860                 rdataset = ISC_LIST_HEAD(name->list);
1861                 if (rdataset != NULL &&
1862                     (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
1863                     (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
1864                         const void *order_arg = msg->order_arg;
1865                         st = *(msg->buffer);
1866                         count = 0;
1867                         if (partial)
1868                                 result = dns_rdataset_towirepartial(rdataset,
1869                                                                     name,
1870                                                                     msg->cctx,
1871                                                                     msg->buffer,
1872                                                                     msg->order,
1873                                                                     order_arg,
1874                                                                     rd_options,
1875                                                                     &count,
1876                                                                     NULL);
1877                         else
1878                                 result = dns_rdataset_towiresorted(rdataset,
1879                                                                    name,
1880                                                                    msg->cctx,
1881                                                                    msg->buffer,
1882                                                                    msg->order,
1883                                                                    order_arg,
1884                                                                    rd_options,
1885                                                                    &count);
1886                         total += count;
1887                         if (partial && result == ISC_R_NOSPACE) {
1888                                 msg->flags |= DNS_MESSAGEFLAG_TC;
1889                                 msg->buffer->length += msg->reserved;
1890                                 msg->counts[sectionid] += total;
1891                                 return (result);
1892                         }
1893                         if (result == ISC_R_NOSPACE)
1894                                 msg->flags |= DNS_MESSAGEFLAG_TC;
1895                         if (result != ISC_R_SUCCESS) {
1896                                 INSIST(st.used < 65536);
1897                                 dns_compress_rollback(msg->cctx,
1898                                                       (isc_uint16_t)st.used);
1899                                 *(msg->buffer) = st;  /* rollback */
1900                                 msg->buffer->length += msg->reserved;
1901                                 msg->counts[sectionid] += total;
1902                                 return (result);
1903                         }
1904                         rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
1905                 }
1906         }
1907
1908         do {
1909                 name = ISC_LIST_HEAD(*section);
1910                 if (name == NULL) {
1911                         msg->buffer->length += msg->reserved;
1912                         msg->counts[sectionid] += total;
1913                         return (ISC_R_SUCCESS);
1914                 }
1915
1916                 while (name != NULL) {
1917                         next_name = ISC_LIST_NEXT(name, link);
1918
1919                         rdataset = ISC_LIST_HEAD(name->list);
1920                         while (rdataset != NULL) {
1921                                 next_rdataset = ISC_LIST_NEXT(rdataset, link);
1922
1923                                 if ((rdataset->attributes &
1924                                      DNS_RDATASETATTR_RENDERED) != 0)
1925                                         goto next;
1926
1927                                 if (((options & DNS_MESSAGERENDER_ORDERED)
1928                                      == 0)
1929                                     && (sectionid == DNS_SECTION_ADDITIONAL)
1930                                     && wrong_priority(rdataset, pass,
1931                                                       preferred_glue))
1932                                         goto next;
1933
1934                                 st = *(msg->buffer);
1935
1936                                 count = 0;
1937                                 if (partial)
1938                                         result = dns_rdataset_towirepartial(
1939                                                           rdataset,
1940                                                           name,
1941                                                           msg->cctx,
1942                                                           msg->buffer,
1943                                                           msg->order,
1944                                                           msg->order_arg,
1945                                                           rd_options,
1946                                                           &count,
1947                                                           NULL);
1948                                 else
1949                                         result = dns_rdataset_towiresorted(
1950                                                           rdataset,
1951                                                           name,
1952                                                           msg->cctx,
1953                                                           msg->buffer,
1954                                                           msg->order,
1955                                                           msg->order_arg,
1956                                                           rd_options,
1957                                                           &count);
1958
1959                                 total += count;
1960
1961                                 /*
1962                                  * If out of space, record stats on what we
1963                                  * rendered so far, and return that status.
1964                                  *
1965                                  * XXXMLG Need to change this when
1966                                  * dns_rdataset_towire() can render partial
1967                                  * sets starting at some arbitrary point in the
1968                                  * set.  This will include setting a bit in the
1969                                  * rdataset to indicate that a partial
1970                                  * rendering was done, and some state saved
1971                                  * somewhere (probably in the message struct)
1972                                  * to indicate where to continue from.
1973                                  */
1974                                 if (partial && result == ISC_R_NOSPACE) {
1975                                         msg->buffer->length += msg->reserved;
1976                                         msg->counts[sectionid] += total;
1977                                         return (result);
1978                                 }
1979                                 if (result != ISC_R_SUCCESS) {
1980                                         INSIST(st.used < 65536);
1981                                         dns_compress_rollback(msg->cctx,
1982                                                         (isc_uint16_t)st.used);
1983                                         *(msg->buffer) = st;  /* rollback */
1984                                         msg->buffer->length += msg->reserved;
1985                                         msg->counts[sectionid] += total;
1986                                         return (result);
1987                                 }
1988
1989                                 /*
1990                                  * If we have rendered non-validated data,
1991                                  * ensure that the AD bit is not set.
1992                                  */
1993                                 if (rdataset->trust != dns_trust_secure &&
1994                                     (sectionid == DNS_SECTION_ANSWER ||
1995                                      sectionid == DNS_SECTION_AUTHORITY))
1996                                         msg->flags &= ~DNS_MESSAGEFLAG_AD;
1997                                 if (OPTOUT(rdataset))
1998                                         msg->flags &= ~DNS_MESSAGEFLAG_AD;
1999
2000                                 rdataset->attributes |=
2001                                         DNS_RDATASETATTR_RENDERED;
2002
2003                         next:
2004                                 rdataset = next_rdataset;
2005                         }
2006
2007                         name = next_name;
2008                 }
2009         } while (--pass != 0);
2010
2011         msg->buffer->length += msg->reserved;
2012         msg->counts[sectionid] += total;
2013
2014         return (ISC_R_SUCCESS);
2015 }
2016
2017 void
2018 dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2019         isc_uint16_t tmp;
2020         isc_region_t r;
2021
2022         REQUIRE(DNS_MESSAGE_VALID(msg));
2023         REQUIRE(target != NULL);
2024
2025         isc_buffer_availableregion(target, &r);
2026         REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2027
2028         isc_buffer_putuint16(target, msg->id);
2029
2030         tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
2031                & DNS_MESSAGE_OPCODE_MASK);
2032         tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2033         tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2034
2035         INSIST(msg->counts[DNS_SECTION_QUESTION]  < 65536 &&
2036                msg->counts[DNS_SECTION_ANSWER]    < 65536 &&
2037                msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2038                msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2039
2040         isc_buffer_putuint16(target, tmp);
2041         isc_buffer_putuint16(target,
2042                             (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2043         isc_buffer_putuint16(target,
2044                             (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2045         isc_buffer_putuint16(target,
2046                             (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2047         isc_buffer_putuint16(target,
2048                             (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2049 }
2050
2051 isc_result_t
2052 dns_message_renderend(dns_message_t *msg) {
2053         isc_buffer_t tmpbuf;
2054         isc_region_t r;
2055         int result;
2056         unsigned int count;
2057
2058         REQUIRE(DNS_MESSAGE_VALID(msg));
2059         REQUIRE(msg->buffer != NULL);
2060
2061         if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2062                 /*
2063                  * We have an extended rcode but are not using EDNS.
2064                  */
2065                 return (DNS_R_FORMERR);
2066         }
2067
2068         /*
2069          * If we've got an OPT record, render it.
2070          */
2071         if (msg->opt != NULL) {
2072                 dns_message_renderrelease(msg, msg->opt_reserved);
2073                 msg->opt_reserved = 0;
2074                 /*
2075                  * Set the extended rcode.
2076                  */
2077                 msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2078                 msg->opt->ttl |= ((msg->rcode << 20) &
2079                                   DNS_MESSAGE_EDNSRCODE_MASK);
2080                 /*
2081                  * Render.
2082                  */
2083                 count = 0;
2084                 result = dns_rdataset_towire(msg->opt, dns_rootname,
2085                                              msg->cctx, msg->buffer, 0,
2086                                              &count);
2087                 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2088                 if (result != ISC_R_SUCCESS)
2089                         return (result);
2090         }
2091
2092         /*
2093          * If we're adding a TSIG or SIG(0) to a truncated message,
2094          * clear all rdatasets from the message except for the question
2095          * before adding the TSIG or SIG(0).  If the question doesn't fit,
2096          * don't include it.
2097          */
2098         if ((msg->tsigkey != NULL || msg->sig0key != NULL) &&
2099             (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2100         {
2101                 isc_buffer_t *buf;
2102
2103                 msgresetnames(msg, DNS_SECTION_ANSWER);
2104                 buf = msg->buffer;
2105                 dns_message_renderreset(msg);
2106                 msg->buffer = buf;
2107                 isc_buffer_clear(msg->buffer);
2108                 isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2109                 dns_compress_rollback(msg->cctx, 0);
2110                 result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2111                                                    0);
2112                 if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2113                         return (result);
2114         }
2115
2116         /*
2117          * If we're adding a TSIG record, generate and render it.
2118          */
2119         if (msg->tsigkey != NULL) {
2120                 dns_message_renderrelease(msg, msg->sig_reserved);
2121                 msg->sig_reserved = 0;
2122                 result = dns_tsig_sign(msg);
2123                 if (result != ISC_R_SUCCESS)
2124                         return (result);
2125                 count = 0;
2126                 result = dns_rdataset_towire(msg->tsig, msg->tsigname,
2127                                              msg->cctx, msg->buffer, 0,
2128                                              &count);
2129                 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2130                 if (result != ISC_R_SUCCESS)
2131                         return (result);
2132         }
2133
2134         /*
2135          * If we're adding a SIG(0) record, generate and render it.
2136          */
2137         if (msg->sig0key != NULL) {
2138                 dns_message_renderrelease(msg, msg->sig_reserved);
2139                 msg->sig_reserved = 0;
2140                 result = dns_dnssec_signmessage(msg, msg->sig0key);
2141                 if (result != ISC_R_SUCCESS)
2142                         return (result);
2143                 count = 0;
2144                 /*
2145                  * Note: dns_rootname is used here, not msg->sig0name, since
2146                  * the owner name of a SIG(0) is irrelevant, and will not
2147                  * be set in a message being rendered.
2148                  */
2149                 result = dns_rdataset_towire(msg->sig0, dns_rootname,
2150                                              msg->cctx, msg->buffer, 0,
2151                                              &count);
2152                 msg->counts[DNS_SECTION_ADDITIONAL] += count;
2153                 if (result != ISC_R_SUCCESS)
2154                         return (result);
2155         }
2156
2157         isc_buffer_usedregion(msg->buffer, &r);
2158         isc_buffer_init(&tmpbuf, r.base, r.length);
2159
2160         dns_message_renderheader(msg, &tmpbuf);
2161
2162         msg->buffer = NULL;  /* forget about this buffer only on success XXX */
2163
2164         return (ISC_R_SUCCESS);
2165 }
2166
2167 void
2168 dns_message_renderreset(dns_message_t *msg) {
2169         unsigned int i;
2170         dns_name_t *name;
2171         dns_rdataset_t *rds;
2172
2173         /*
2174          * Reset the message so that it may be rendered again.
2175          */
2176
2177         REQUIRE(DNS_MESSAGE_VALID(msg));
2178         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2179
2180         msg->buffer = NULL;
2181
2182         for (i = 0; i < DNS_SECTION_MAX; i++) {
2183                 msg->cursors[i] = NULL;
2184                 msg->counts[i] = 0;
2185                 for (name = ISC_LIST_HEAD(msg->sections[i]);
2186                      name != NULL;
2187                      name = ISC_LIST_NEXT(name, link)) {
2188                         for (rds = ISC_LIST_HEAD(name->list);
2189                              rds != NULL;
2190                              rds = ISC_LIST_NEXT(rds, link)) {
2191                                 rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2192                         }
2193                 }
2194         }
2195         if (msg->tsigname != NULL)
2196                 dns_message_puttempname(msg, &msg->tsigname);
2197         if (msg->tsig != NULL) {
2198                 dns_rdataset_disassociate(msg->tsig);
2199                 dns_message_puttemprdataset(msg, &msg->tsig);
2200         }
2201         if (msg->sig0 != NULL) {
2202                 dns_rdataset_disassociate(msg->sig0);
2203                 dns_message_puttemprdataset(msg, &msg->sig0);
2204         }
2205 }
2206
2207 isc_result_t
2208 dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2209         REQUIRE(DNS_MESSAGE_VALID(msg));
2210         REQUIRE(VALID_NAMED_SECTION(section));
2211
2212         msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2213
2214         if (msg->cursors[section] == NULL)
2215                 return (ISC_R_NOMORE);
2216
2217         return (ISC_R_SUCCESS);
2218 }
2219
2220 isc_result_t
2221 dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2222         REQUIRE(DNS_MESSAGE_VALID(msg));
2223         REQUIRE(VALID_NAMED_SECTION(section));
2224         REQUIRE(msg->cursors[section] != NULL);
2225
2226         msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2227
2228         if (msg->cursors[section] == NULL)
2229                 return (ISC_R_NOMORE);
2230
2231         return (ISC_R_SUCCESS);
2232 }
2233
2234 void
2235 dns_message_currentname(dns_message_t *msg, dns_section_t section,
2236                         dns_name_t **name)
2237 {
2238         REQUIRE(DNS_MESSAGE_VALID(msg));
2239         REQUIRE(VALID_NAMED_SECTION(section));
2240         REQUIRE(name != NULL && *name == NULL);
2241         REQUIRE(msg->cursors[section] != NULL);
2242
2243         *name = msg->cursors[section];
2244 }
2245
2246 isc_result_t
2247 dns_message_findname(dns_message_t *msg, dns_section_t section,
2248                      dns_name_t *target, dns_rdatatype_t type,
2249                      dns_rdatatype_t covers, dns_name_t **name,
2250                      dns_rdataset_t **rdataset)
2251 {
2252         dns_name_t *foundname;
2253         isc_result_t result;
2254
2255         /*
2256          * XXX These requirements are probably too intensive, especially
2257          * where things can be NULL, but as they are they ensure that if
2258          * something is NON-NULL, indicating that the caller expects it
2259          * to be filled in, that we can in fact fill it in.
2260          */
2261         REQUIRE(msg != NULL);
2262         REQUIRE(VALID_SECTION(section));
2263         REQUIRE(target != NULL);
2264         if (name != NULL)
2265                 REQUIRE(*name == NULL);
2266         if (type == dns_rdatatype_any) {
2267                 REQUIRE(rdataset == NULL);
2268         } else {
2269                 if (rdataset != NULL)
2270                         REQUIRE(*rdataset == NULL);
2271         }
2272
2273         result = findname(&foundname, target,
2274                           &msg->sections[section]);
2275
2276         if (result == ISC_R_NOTFOUND)
2277                 return (DNS_R_NXDOMAIN);
2278         else if (result != ISC_R_SUCCESS)
2279                 return (result);
2280
2281         if (name != NULL)
2282                 *name = foundname;
2283
2284         /*
2285          * And now look for the type.
2286          */
2287         if (type == dns_rdatatype_any)
2288                 return (ISC_R_SUCCESS);
2289
2290         result = dns_message_findtype(foundname, type, covers, rdataset);
2291         if (result == ISC_R_NOTFOUND)
2292                 return (DNS_R_NXRRSET);
2293
2294         return (result);
2295 }
2296
2297 void
2298 dns_message_movename(dns_message_t *msg, dns_name_t *name,
2299                      dns_section_t fromsection,
2300                      dns_section_t tosection)
2301 {
2302         REQUIRE(msg != NULL);
2303         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2304         REQUIRE(name != NULL);
2305         REQUIRE(VALID_NAMED_SECTION(fromsection));
2306         REQUIRE(VALID_NAMED_SECTION(tosection));
2307
2308         /*
2309          * Unlink the name from the old section
2310          */
2311         ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2312         ISC_LIST_APPEND(msg->sections[tosection], name, link);
2313 }
2314
2315 void
2316 dns_message_addname(dns_message_t *msg, dns_name_t *name,
2317                     dns_section_t section)
2318 {
2319         REQUIRE(msg != NULL);
2320         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2321         REQUIRE(name != NULL);
2322         REQUIRE(VALID_NAMED_SECTION(section));
2323
2324         ISC_LIST_APPEND(msg->sections[section], name, link);
2325 }
2326
2327 void
2328 dns_message_removename(dns_message_t *msg, dns_name_t *name,
2329                        dns_section_t section)
2330 {
2331         REQUIRE(msg != NULL);
2332         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2333         REQUIRE(name != NULL);
2334         REQUIRE(VALID_NAMED_SECTION(section));
2335
2336         ISC_LIST_UNLINK(msg->sections[section], name, link);
2337 }
2338
2339 isc_result_t
2340 dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2341         REQUIRE(DNS_MESSAGE_VALID(msg));
2342         REQUIRE(item != NULL && *item == NULL);
2343
2344         *item = isc_mempool_get(msg->namepool);
2345         if (*item == NULL)
2346                 return (ISC_R_NOMEMORY);
2347         dns_name_init(*item, NULL);
2348
2349         return (ISC_R_SUCCESS);
2350 }
2351
2352 isc_result_t
2353 dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2354         REQUIRE(DNS_MESSAGE_VALID(msg));
2355         REQUIRE(item != NULL && *item == NULL);
2356
2357         *item = newoffsets(msg);
2358         if (*item == NULL)
2359                 return (ISC_R_NOMEMORY);
2360
2361         return (ISC_R_SUCCESS);
2362 }
2363
2364 isc_result_t
2365 dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2366         REQUIRE(DNS_MESSAGE_VALID(msg));
2367         REQUIRE(item != NULL && *item == NULL);
2368
2369         *item = newrdata(msg);
2370         if (*item == NULL)
2371                 return (ISC_R_NOMEMORY);
2372
2373         return (ISC_R_SUCCESS);
2374 }
2375
2376 isc_result_t
2377 dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2378         REQUIRE(DNS_MESSAGE_VALID(msg));
2379         REQUIRE(item != NULL && *item == NULL);
2380
2381         *item = isc_mempool_get(msg->rdspool);
2382         if (*item == NULL)
2383                 return (ISC_R_NOMEMORY);
2384
2385         dns_rdataset_init(*item);
2386
2387         return (ISC_R_SUCCESS);
2388 }
2389
2390 isc_result_t
2391 dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2392         REQUIRE(DNS_MESSAGE_VALID(msg));
2393         REQUIRE(item != NULL && *item == NULL);
2394
2395         *item = newrdatalist(msg);
2396         if (*item == NULL)
2397                 return (ISC_R_NOMEMORY);
2398
2399         return (ISC_R_SUCCESS);
2400 }
2401
2402 void
2403 dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2404         REQUIRE(DNS_MESSAGE_VALID(msg));
2405         REQUIRE(item != NULL && *item != NULL);
2406
2407         if (dns_name_dynamic(*item))
2408                 dns_name_free(*item, msg->mctx);
2409         isc_mempool_put(msg->namepool, *item);
2410         *item = NULL;
2411 }
2412
2413 void
2414 dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2415         REQUIRE(DNS_MESSAGE_VALID(msg));
2416         REQUIRE(item != NULL && *item != NULL);
2417
2418         releaserdata(msg, *item);
2419         *item = NULL;
2420 }
2421
2422 void
2423 dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2424         REQUIRE(DNS_MESSAGE_VALID(msg));
2425         REQUIRE(item != NULL && *item != NULL);
2426
2427         REQUIRE(!dns_rdataset_isassociated(*item));
2428         isc_mempool_put(msg->rdspool, *item);
2429         *item = NULL;
2430 }
2431
2432 void
2433 dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2434         REQUIRE(DNS_MESSAGE_VALID(msg));
2435         REQUIRE(item != NULL && *item != NULL);
2436
2437         releaserdatalist(msg, *item);
2438         *item = NULL;
2439 }
2440
2441 isc_result_t
2442 dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2443                        unsigned int *flagsp)
2444 {
2445         isc_region_t r;
2446         isc_buffer_t buffer;
2447         dns_messageid_t id;
2448         unsigned int flags;
2449
2450         REQUIRE(source != NULL);
2451
2452         buffer = *source;
2453
2454         isc_buffer_remainingregion(&buffer, &r);
2455         if (r.length < DNS_MESSAGE_HEADERLEN)
2456                 return (ISC_R_UNEXPECTEDEND);
2457
2458         id = isc_buffer_getuint16(&buffer);
2459         flags = isc_buffer_getuint16(&buffer);
2460         flags &= DNS_MESSAGE_FLAG_MASK;
2461
2462         if (flagsp != NULL)
2463                 *flagsp = flags;
2464         if (idp != NULL)
2465                 *idp = id;
2466
2467         return (ISC_R_SUCCESS);
2468 }
2469
2470 isc_result_t
2471 dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
2472         unsigned int clear_after;
2473         isc_result_t result;
2474
2475         REQUIRE(DNS_MESSAGE_VALID(msg));
2476         REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2477
2478         if (!msg->header_ok)
2479                 return (DNS_R_FORMERR);
2480         if (msg->opcode != dns_opcode_query &&
2481             msg->opcode != dns_opcode_notify)
2482                 want_question_section = ISC_FALSE;
2483         if (msg->opcode == dns_opcode_update)
2484                 clear_after = DNS_SECTION_PREREQUISITE;
2485         else if (want_question_section) {
2486                 if (!msg->question_ok)
2487                         return (DNS_R_FORMERR);
2488                 clear_after = DNS_SECTION_ANSWER;
2489         } else
2490                 clear_after = DNS_SECTION_QUESTION;
2491         msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2492         msgresetnames(msg, clear_after);
2493         msgresetopt(msg);
2494         msgresetsigs(msg, ISC_TRUE);
2495         msginitprivate(msg);
2496         /*
2497          * We now clear most flags and then set QR, ensuring that the
2498          * reply's flags will be in a reasonable state.
2499          */
2500         msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2501         msg->flags |= DNS_MESSAGEFLAG_QR;
2502
2503         /*
2504          * This saves the query TSIG status, if the query was signed, and
2505          * reserves space in the reply for the TSIG.
2506          */
2507         if (msg->tsigkey != NULL) {
2508                 unsigned int otherlen = 0;
2509                 msg->querytsigstatus = msg->tsigstatus;
2510                 msg->tsigstatus = dns_rcode_noerror;
2511                 if (msg->querytsigstatus == dns_tsigerror_badtime)
2512                         otherlen = 6;
2513                 msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2514                 result = dns_message_renderreserve(msg, msg->sig_reserved);
2515                 if (result != ISC_R_SUCCESS) {
2516                         msg->sig_reserved = 0;
2517                         return (result);
2518                 }
2519         }
2520         if (msg->saved.base != NULL) {
2521                 msg->query.base = msg->saved.base;
2522                 msg->query.length = msg->saved.length;
2523                 msg->free_query = msg->free_saved;
2524                 msg->saved.base = NULL;
2525                 msg->saved.length = 0;
2526                 msg->free_saved = 0;
2527         }
2528
2529         return (ISC_R_SUCCESS);
2530 }
2531
2532 dns_rdataset_t *
2533 dns_message_getopt(dns_message_t *msg) {
2534
2535         /*
2536          * Get the OPT record for 'msg'.
2537          */
2538
2539         REQUIRE(DNS_MESSAGE_VALID(msg));
2540
2541         return (msg->opt);
2542 }
2543
2544 isc_result_t
2545 dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2546         isc_result_t result;
2547         dns_rdata_t rdata = DNS_RDATA_INIT;
2548
2549         /*
2550          * Set the OPT record for 'msg'.
2551          */
2552
2553         /*
2554          * The space required for an OPT record is:
2555          *
2556          *      1 byte for the name
2557          *      2 bytes for the type
2558          *      2 bytes for the class
2559          *      4 bytes for the ttl
2560          *      2 bytes for the rdata length
2561          * ---------------------------------
2562          *     11 bytes
2563          *
2564          * plus the length of the rdata.
2565          */
2566
2567         REQUIRE(DNS_MESSAGE_VALID(msg));
2568         REQUIRE(opt->type == dns_rdatatype_opt);
2569         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2570         REQUIRE(msg->state == DNS_SECTION_ANY);
2571
2572         msgresetopt(msg);
2573
2574         result = dns_rdataset_first(opt);
2575         if (result != ISC_R_SUCCESS)
2576                 goto cleanup;
2577         dns_rdataset_current(opt, &rdata);
2578         msg->opt_reserved = 11 + rdata.length;
2579         result = dns_message_renderreserve(msg, msg->opt_reserved);
2580         if (result != ISC_R_SUCCESS) {
2581                 msg->opt_reserved = 0;
2582                 goto cleanup;
2583         }
2584
2585         msg->opt = opt;
2586
2587         return (ISC_R_SUCCESS);
2588
2589  cleanup:
2590         dns_message_puttemprdataset(msg, &opt);
2591         return (result);
2592
2593 }
2594
2595 dns_rdataset_t *
2596 dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2597
2598         /*
2599          * Get the TSIG record and owner for 'msg'.
2600          */
2601
2602         REQUIRE(DNS_MESSAGE_VALID(msg));
2603         REQUIRE(owner == NULL || *owner == NULL);
2604
2605         if (owner != NULL)
2606                 *owner = msg->tsigname;
2607         return (msg->tsig);
2608 }
2609
2610 isc_result_t
2611 dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2612         isc_result_t result;
2613
2614         /*
2615          * Set the TSIG key for 'msg'
2616          */
2617
2618         REQUIRE(DNS_MESSAGE_VALID(msg));
2619         REQUIRE(msg->state == DNS_SECTION_ANY);
2620
2621         if (key == NULL && msg->tsigkey != NULL) {
2622                 if (msg->sig_reserved != 0) {
2623                         dns_message_renderrelease(msg, msg->sig_reserved);
2624                         msg->sig_reserved = 0;
2625                 }
2626                 dns_tsigkey_detach(&msg->tsigkey);
2627         }
2628         if (key != NULL) {
2629                 REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2630                 dns_tsigkey_attach(key, &msg->tsigkey);
2631                 if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2632                         msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2633                         result = dns_message_renderreserve(msg,
2634                                                            msg->sig_reserved);
2635                         if (result != ISC_R_SUCCESS) {
2636                                 dns_tsigkey_detach(&msg->tsigkey);
2637                                 msg->sig_reserved = 0;
2638                                 return (result);
2639                         }
2640                 }
2641         }
2642         return (ISC_R_SUCCESS);
2643 }
2644
2645 dns_tsigkey_t *
2646 dns_message_gettsigkey(dns_message_t *msg) {
2647
2648         /*
2649          * Get the TSIG key for 'msg'
2650          */
2651
2652         REQUIRE(DNS_MESSAGE_VALID(msg));
2653
2654         return (msg->tsigkey);
2655 }
2656
2657 isc_result_t
2658 dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2659         dns_rdata_t *rdata = NULL;
2660         dns_rdatalist_t *list = NULL;
2661         dns_rdataset_t *set = NULL;
2662         isc_buffer_t *buf = NULL;
2663         isc_region_t r;
2664         isc_result_t result;
2665
2666         REQUIRE(DNS_MESSAGE_VALID(msg));
2667         REQUIRE(msg->querytsig == NULL);
2668
2669         if (querytsig == NULL)
2670                 return (ISC_R_SUCCESS);
2671
2672         result = dns_message_gettemprdata(msg, &rdata);
2673         if (result != ISC_R_SUCCESS)
2674                 goto cleanup;
2675
2676         result = dns_message_gettemprdatalist(msg, &list);
2677         if (result != ISC_R_SUCCESS)
2678                 goto cleanup;
2679         result = dns_message_gettemprdataset(msg, &set);
2680         if (result != ISC_R_SUCCESS)
2681                 goto cleanup;
2682
2683         isc_buffer_usedregion(querytsig, &r);
2684         result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2685         if (result != ISC_R_SUCCESS)
2686                 goto cleanup;
2687         isc_buffer_putmem(buf, r.base, r.length);
2688         isc_buffer_usedregion(buf, &r);
2689         dns_rdata_init(rdata);
2690         dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2691         dns_message_takebuffer(msg, &buf);
2692         ISC_LIST_INIT(list->rdata);
2693         ISC_LIST_APPEND(list->rdata, rdata, link);
2694         result = dns_rdatalist_tordataset(list, set);
2695         if (result != ISC_R_SUCCESS)
2696                 goto cleanup;
2697
2698         msg->querytsig = set;
2699
2700         return (result);
2701
2702  cleanup:
2703         if (rdata != NULL)
2704                 dns_message_puttemprdata(msg, &rdata);
2705         if (list != NULL)
2706                 dns_message_puttemprdatalist(msg, &list);
2707         if (set != NULL)
2708                 dns_message_puttemprdataset(msg, &set);
2709         return (ISC_R_NOMEMORY);
2710 }
2711
2712 isc_result_t
2713 dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2714                          isc_buffer_t **querytsig) {
2715         isc_result_t result;
2716         dns_rdata_t rdata = DNS_RDATA_INIT;
2717         isc_region_t r;
2718
2719         REQUIRE(DNS_MESSAGE_VALID(msg));
2720         REQUIRE(mctx != NULL);
2721         REQUIRE(querytsig != NULL && *querytsig == NULL);
2722
2723         if (msg->tsig == NULL)
2724                 return (ISC_R_SUCCESS);
2725
2726         result = dns_rdataset_first(msg->tsig);
2727         if (result != ISC_R_SUCCESS)
2728                 return (result);
2729         dns_rdataset_current(msg->tsig, &rdata);
2730         dns_rdata_toregion(&rdata, &r);
2731
2732         result = isc_buffer_allocate(mctx, querytsig, r.length);
2733         if (result != ISC_R_SUCCESS)
2734                 return (result);
2735         isc_buffer_putmem(*querytsig, r.base, r.length);
2736         return (ISC_R_SUCCESS);
2737 }
2738
2739 dns_rdataset_t *
2740 dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2741
2742         /*
2743          * Get the SIG(0) record for 'msg'.
2744          */
2745
2746         REQUIRE(DNS_MESSAGE_VALID(msg));
2747         REQUIRE(owner == NULL || *owner == NULL);
2748
2749         if (msg->sig0 != NULL && owner != NULL) {
2750                 /* If dns_message_getsig0 is called on a rendered message
2751                  * after the SIG(0) has been applied, we need to return the
2752                  * root name, not NULL.
2753                  */
2754                 if (msg->sig0name == NULL)
2755                         *owner = dns_rootname;
2756                 else
2757                         *owner = msg->sig0name;
2758         }
2759         return (msg->sig0);
2760 }
2761
2762 isc_result_t
2763 dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2764         isc_region_t r;
2765         unsigned int x;
2766         isc_result_t result;
2767
2768         /*
2769          * Set the SIG(0) key for 'msg'
2770          */
2771
2772         /*
2773          * The space required for an SIG(0) record is:
2774          *
2775          *      1 byte for the name
2776          *      2 bytes for the type
2777          *      2 bytes for the class
2778          *      4 bytes for the ttl
2779          *      2 bytes for the type covered
2780          *      1 byte for the algorithm
2781          *      1 bytes for the labels
2782          *      4 bytes for the original ttl
2783          *      4 bytes for the signature expiration
2784          *      4 bytes for the signature inception
2785          *      2 bytes for the key tag
2786          *      n bytes for the signer's name
2787          *      x bytes for the signature
2788          * ---------------------------------
2789          *     27 + n + x bytes
2790          */
2791         REQUIRE(DNS_MESSAGE_VALID(msg));
2792         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2793         REQUIRE(msg->state == DNS_SECTION_ANY);
2794
2795         if (key != NULL) {
2796                 REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2797                 dns_name_toregion(dst_key_name(key), &r);
2798                 result = dst_key_sigsize(key, &x);
2799                 if (result != ISC_R_SUCCESS) {
2800                         msg->sig_reserved = 0;
2801                         return (result);
2802                 }
2803                 msg->sig_reserved = 27 + r.length + x;
2804                 result = dns_message_renderreserve(msg, msg->sig_reserved);
2805                 if (result != ISC_R_SUCCESS) {
2806                         msg->sig_reserved = 0;
2807                         return (result);
2808                 }
2809                 msg->sig0key = key;
2810         }
2811         return (ISC_R_SUCCESS);
2812 }
2813
2814 dst_key_t *
2815 dns_message_getsig0key(dns_message_t *msg) {
2816
2817         /*
2818          * Get the SIG(0) key for 'msg'
2819          */
2820
2821         REQUIRE(DNS_MESSAGE_VALID(msg));
2822
2823         return (msg->sig0key);
2824 }
2825
2826 void
2827 dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2828         REQUIRE(DNS_MESSAGE_VALID(msg));
2829         REQUIRE(buffer != NULL);
2830         REQUIRE(ISC_BUFFER_VALID(*buffer));
2831
2832         ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2833         *buffer = NULL;
2834 }
2835
2836 isc_result_t
2837 dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
2838         isc_result_t result = ISC_R_SUCCESS;
2839         dns_rdata_t rdata = DNS_RDATA_INIT;
2840
2841         REQUIRE(DNS_MESSAGE_VALID(msg));
2842         REQUIRE(signer != NULL);
2843         REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2844
2845         if (msg->tsig == NULL && msg->sig0 == NULL)
2846                 return (ISC_R_NOTFOUND);
2847
2848         if (msg->verify_attempted == 0)
2849                 return (DNS_R_NOTVERIFIEDYET);
2850
2851         if (!dns_name_hasbuffer(signer)) {
2852                 isc_buffer_t *dynbuf = NULL;
2853                 result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
2854                 if (result != ISC_R_SUCCESS)
2855                         return (result);
2856                 dns_name_setbuffer(signer, dynbuf);
2857                 dns_message_takebuffer(msg, &dynbuf);
2858         }
2859
2860         if (msg->sig0 != NULL) {
2861                 dns_rdata_sig_t sig;
2862
2863                 result = dns_rdataset_first(msg->sig0);
2864                 INSIST(result == ISC_R_SUCCESS);
2865                 dns_rdataset_current(msg->sig0, &rdata);
2866
2867                 result = dns_rdata_tostruct(&rdata, &sig, NULL);
2868                 if (result != ISC_R_SUCCESS)
2869                         return (result);
2870
2871                 if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
2872                         result = ISC_R_SUCCESS;
2873                 else
2874                         result = DNS_R_SIGINVALID;
2875                 dns_name_clone(&sig.signer, signer);
2876                 dns_rdata_freestruct(&sig);
2877         } else {
2878                 dns_name_t *identity;
2879                 dns_rdata_any_tsig_t tsig;
2880
2881                 result = dns_rdataset_first(msg->tsig);
2882                 INSIST(result == ISC_R_SUCCESS);
2883                 dns_rdataset_current(msg->tsig, &rdata);
2884
2885                 result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2886                 if (msg->tsigstatus != dns_rcode_noerror)
2887                         result = DNS_R_TSIGVERIFYFAILURE;
2888                 else if (tsig.error != dns_rcode_noerror)
2889                         result = DNS_R_TSIGERRORSET;
2890                 else
2891                         result = ISC_R_SUCCESS;
2892                 dns_rdata_freestruct(&tsig);
2893
2894                 if (msg->tsigkey == NULL) {
2895                         /*
2896                          * If msg->tsigstatus & tsig.error are both
2897                          * dns_rcode_noerror, the message must have been
2898                          * verified, which means msg->tsigkey will be
2899                          * non-NULL.
2900                          */
2901                         INSIST(result != ISC_R_SUCCESS);
2902                 } else {
2903                         identity = dns_tsigkey_identity(msg->tsigkey);
2904                         if (identity == NULL) {
2905                                 if (result == ISC_R_SUCCESS)
2906                                         result = DNS_R_NOIDENTITY;
2907                                 identity = &msg->tsigkey->name;
2908                         }
2909                         dns_name_clone(identity, signer);
2910                 }
2911         }
2912
2913         return (result);
2914 }
2915
2916 void
2917 dns_message_resetsig(dns_message_t *msg) {
2918         REQUIRE(DNS_MESSAGE_VALID(msg));
2919         msg->verified_sig = 0;
2920         msg->verify_attempted = 0;
2921         msg->tsigstatus = dns_rcode_noerror;
2922         msg->sig0status = dns_rcode_noerror;
2923         msg->timeadjust = 0;
2924         if (msg->tsigkey != NULL) {
2925                 dns_tsigkey_detach(&msg->tsigkey);
2926                 msg->tsigkey = NULL;
2927         }
2928 }
2929
2930 isc_result_t
2931 dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
2932         dns_message_resetsig(msg);
2933         return (dns_message_checksig(msg, view));
2934 }
2935
2936 #ifdef SKAN_MSG_DEBUG
2937 void
2938 dns_message_dumpsig(dns_message_t *msg, char *txt1) {
2939         dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
2940         dns_rdata_any_tsig_t querytsig;
2941         isc_result_t result;
2942
2943         if (msg->tsig != NULL) {
2944                 result = dns_rdataset_first(msg->tsig);
2945                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2946                 dns_rdataset_current(msg->tsig, &querytsigrdata);
2947                 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
2948                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2949                 hexdump(txt1, "TSIG", querytsig.signature,
2950                         querytsig.siglen);
2951         }
2952
2953         if (msg->querytsig != NULL) {
2954                 result = dns_rdataset_first(msg->querytsig);
2955                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2956                 dns_rdataset_current(msg->querytsig, &querytsigrdata);
2957                 result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
2958                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2959                 hexdump(txt1, "QUERYTSIG", querytsig.signature,
2960                         querytsig.siglen);
2961         }
2962 }
2963 #endif
2964
2965 isc_result_t
2966 dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
2967         isc_buffer_t b, msgb;
2968
2969         REQUIRE(DNS_MESSAGE_VALID(msg));
2970
2971         if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
2972                 return (ISC_R_SUCCESS);
2973
2974         INSIST(msg->saved.base != NULL);
2975         isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
2976         isc_buffer_add(&msgb, msg->saved.length);
2977         if (msg->tsigkey != NULL || msg->tsig != NULL) {
2978 #ifdef SKAN_MSG_DEBUG
2979                 dns_message_dumpsig(msg, "dns_message_checksig#1");
2980 #endif
2981                 if (view != NULL)
2982                         return (dns_view_checksig(view, &msgb, msg));
2983                 else
2984                         return (dns_tsig_verify(&msgb, msg, NULL, NULL));
2985         } else {
2986                 dns_rdata_t rdata = DNS_RDATA_INIT;
2987                 dns_rdata_sig_t sig;
2988                 dns_rdataset_t keyset;
2989                 isc_result_t result;
2990
2991                 result = dns_rdataset_first(msg->sig0);
2992                 INSIST(result == ISC_R_SUCCESS);
2993                 dns_rdataset_current(msg->sig0, &rdata);
2994
2995                 /*
2996                  * This can occur when the message is a dynamic update, since
2997                  * the rdata length checking is relaxed.  This should not
2998                  * happen in a well-formed message, since the SIG(0) is only
2999                  * looked for in the additional section, and the dynamic update
3000                  * meta-records are in the prerequisite and update sections.
3001                  */
3002                 if (rdata.length == 0)
3003                         return (ISC_R_UNEXPECTEDEND);
3004
3005                 result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
3006                 if (result != ISC_R_SUCCESS)
3007                         return (result);
3008
3009                 dns_rdataset_init(&keyset);
3010                 if (view == NULL)
3011                         return (DNS_R_KEYUNAUTHORIZED);
3012                 result = dns_view_simplefind(view, &sig.signer,
3013                                              dns_rdatatype_key /* SIG(0) */,
3014                                              0, 0, ISC_FALSE, &keyset, NULL);
3015
3016                 if (result != ISC_R_SUCCESS) {
3017                         /* XXXBEW Should possibly create a fetch here */
3018                         result = DNS_R_KEYUNAUTHORIZED;
3019                         goto freesig;
3020                 } else if (keyset.trust < dns_trust_secure) {
3021                         /* XXXBEW Should call a validator here */
3022                         result = DNS_R_KEYUNAUTHORIZED;
3023                         goto freesig;
3024                 }
3025                 result = dns_rdataset_first(&keyset);
3026                 INSIST(result == ISC_R_SUCCESS);
3027                 for (;
3028                      result == ISC_R_SUCCESS;
3029                      result = dns_rdataset_next(&keyset))
3030                 {
3031                         dst_key_t *key = NULL;
3032
3033                         dns_rdata_reset(&rdata);
3034                         dns_rdataset_current(&keyset, &rdata);
3035                         isc_buffer_init(&b, rdata.data, rdata.length);
3036                         isc_buffer_add(&b, rdata.length);
3037
3038                         result = dst_key_fromdns(&sig.signer, rdata.rdclass,
3039                                                  &b, view->mctx, &key);
3040                         if (result != ISC_R_SUCCESS)
3041                                 continue;
3042                         if (dst_key_alg(key) != sig.algorithm ||
3043                             dst_key_id(key) != sig.keyid ||
3044                             !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3045                               dst_key_proto(key) == DNS_KEYPROTO_ANY))
3046                         {
3047                                 dst_key_free(&key);
3048                                 continue;
3049                         }
3050                         result = dns_dnssec_verifymessage(&msgb, msg, key);
3051                         dst_key_free(&key);
3052                         if (result == ISC_R_SUCCESS)
3053                                 break;
3054                 }
3055                 if (result == ISC_R_NOMORE)
3056                         result = DNS_R_KEYUNAUTHORIZED;
3057
3058  freesig:
3059                 if (dns_rdataset_isassociated(&keyset))
3060                         dns_rdataset_disassociate(&keyset);
3061                 dns_rdata_freestruct(&sig);
3062                 return (result);
3063         }
3064 }
3065
3066 isc_result_t
3067 dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3068                           const dns_master_style_t *style,
3069                           dns_messagetextflag_t flags,
3070                           isc_buffer_t *target) {
3071         dns_name_t *name, empty_name;
3072         dns_rdataset_t *rdataset;
3073         isc_result_t result;
3074
3075         REQUIRE(DNS_MESSAGE_VALID(msg));
3076         REQUIRE(target != NULL);
3077         REQUIRE(VALID_SECTION(section));
3078
3079         if (ISC_LIST_EMPTY(msg->sections[section]))
3080                 return (ISC_R_SUCCESS);
3081
3082         if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3083                 ADD_STRING(target, ";; ");
3084                 if (msg->opcode != dns_opcode_update) {
3085                         ADD_STRING(target, sectiontext[section]);
3086                 } else {
3087                         ADD_STRING(target, updsectiontext[section]);
3088                 }
3089                 ADD_STRING(target, " SECTION:\n");
3090         }
3091
3092         dns_name_init(&empty_name, NULL);
3093         result = dns_message_firstname(msg, section);
3094         if (result != ISC_R_SUCCESS) {
3095                 return (result);
3096         }
3097         do {
3098                 name = NULL;
3099                 dns_message_currentname(msg, section, &name);
3100                 for (rdataset = ISC_LIST_HEAD(name->list);
3101                      rdataset != NULL;
3102                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
3103                         if (section == DNS_SECTION_QUESTION) {
3104                                 ADD_STRING(target, ";");
3105                                 result = dns_master_questiontotext(name,
3106                                                                    rdataset,
3107                                                                    style,
3108                                                                    target);
3109                         } else {
3110                                 result = dns_master_rdatasettotext(name,
3111                                                                    rdataset,
3112                                                                    style,
3113                                                                    target);
3114                         }
3115                         if (result != ISC_R_SUCCESS)
3116                                 return (result);
3117                 }
3118                 result = dns_message_nextname(msg, section);
3119         } while (result == ISC_R_SUCCESS);
3120         if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3121             (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3122                 ADD_STRING(target, "\n");
3123         if (result == ISC_R_NOMORE)
3124                 result = ISC_R_SUCCESS;
3125         return (result);
3126 }
3127
3128 isc_result_t
3129 dns_message_pseudosectiontotext(dns_message_t *msg,
3130                                 dns_pseudosection_t section,
3131                                 const dns_master_style_t *style,
3132                                 dns_messagetextflag_t flags,
3133                                 isc_buffer_t *target) {
3134         dns_rdataset_t *ps = NULL;
3135         dns_name_t *name = NULL;
3136         isc_result_t result;
3137         char buf[sizeof("1234567890")];
3138         isc_uint32_t mbz;
3139         dns_rdata_t rdata;
3140         isc_buffer_t optbuf;
3141         isc_uint16_t optcode, optlen;
3142         unsigned char *optdata;
3143
3144         REQUIRE(DNS_MESSAGE_VALID(msg));
3145         REQUIRE(target != NULL);
3146         REQUIRE(VALID_PSEUDOSECTION(section));
3147
3148         switch (section) {
3149         case DNS_PSEUDOSECTION_OPT:
3150                 ps = dns_message_getopt(msg);
3151                 if (ps == NULL)
3152                         return (ISC_R_SUCCESS);
3153                 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3154                         ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3155                 ADD_STRING(target, "; EDNS: version: ");
3156                 snprintf(buf, sizeof(buf), "%u",
3157                          (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3158                 ADD_STRING(target, buf);
3159                 ADD_STRING(target, ", flags:");
3160                 if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3161                         ADD_STRING(target, " do");
3162                 mbz = ps->ttl & 0xffff;
3163                 mbz &= ~DNS_MESSAGEEXTFLAG_DO;          /* Known Flags. */
3164                 if (mbz != 0) {
3165                         ADD_STRING(target, "; MBZ: ");
3166                         snprintf(buf, sizeof(buf), "%.4x ", mbz);
3167                         ADD_STRING(target, buf);
3168                         ADD_STRING(target, ", udp: ");
3169                 } else
3170                         ADD_STRING(target, "; udp: ");
3171                 snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3172                 ADD_STRING(target, buf);
3173
3174                 result = dns_rdataset_first(ps);
3175                 if (result != ISC_R_SUCCESS)
3176                         return (ISC_R_SUCCESS);
3177
3178                 /* Print EDNS info, if any */
3179                 dns_rdata_init(&rdata);
3180                 dns_rdataset_current(ps, &rdata);
3181
3182                 isc_buffer_init(&optbuf, rdata.data, rdata.length);
3183                 isc_buffer_add(&optbuf, rdata.length);
3184                 while (isc_buffer_remaininglength(&optbuf) != 0) {
3185                         INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3186                         optcode = isc_buffer_getuint16(&optbuf);
3187                         optlen = isc_buffer_getuint16(&optbuf);
3188                         INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3189
3190                         if (optcode == DNS_OPT_NSID) {
3191                                 ADD_STRING(target, "; NSID");
3192                         } else {
3193                                 ADD_STRING(target, "; OPT=");
3194                                 sprintf(buf, "%u", optcode);
3195                                 ADD_STRING(target, buf);
3196                         }
3197
3198                         if (optlen != 0) {
3199                                 int i;
3200                                 ADD_STRING(target, ": ");
3201
3202                                 optdata = isc_buffer_current(&optbuf);
3203                                 for (i = 0; i < optlen; i++) {
3204                                         sprintf(buf, "%02x ", optdata[i]);
3205                                         ADD_STRING(target, buf);
3206                                 }
3207                                 for (i = 0; i < optlen; i++) {
3208                                         ADD_STRING(target, " (");
3209                                         if (isprint(optdata[i]))
3210                                                 isc_buffer_putmem(target,
3211                                                                   &optdata[i],
3212                                                                   1);
3213                                         else
3214                                                 isc_buffer_putstr(target, ".");
3215                                         ADD_STRING(target, ")");
3216                                 }
3217                                 isc_buffer_forward(&optbuf, optlen);
3218                         }
3219                         ADD_STRING(target, "\n");
3220                 }
3221                 return (ISC_R_SUCCESS);
3222         case DNS_PSEUDOSECTION_TSIG:
3223                 ps = dns_message_gettsig(msg, &name);
3224                 if (ps == NULL)
3225                         return (ISC_R_SUCCESS);
3226                 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3227                         ADD_STRING(target, ";; TSIG 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         case DNS_PSEUDOSECTION_SIG0:
3234                 ps = dns_message_getsig0(msg, &name);
3235                 if (ps == NULL)
3236                         return (ISC_R_SUCCESS);
3237                 if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3238                         ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3239                 result = dns_master_rdatasettotext(name, ps, style, target);
3240                 if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3241                     (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3242                         ADD_STRING(target, "\n");
3243                 return (result);
3244         }
3245         return (ISC_R_UNEXPECTED);
3246 }
3247
3248 isc_result_t
3249 dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3250                    dns_messagetextflag_t flags, isc_buffer_t *target) {
3251         char buf[sizeof("1234567890")];
3252         isc_result_t result;
3253
3254         REQUIRE(DNS_MESSAGE_VALID(msg));
3255         REQUIRE(target != NULL);
3256
3257         if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
3258                 ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
3259                 ADD_STRING(target, opcodetext[msg->opcode]);
3260                 ADD_STRING(target, ", status: ");
3261                 if (msg->rcode < (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
3262                         ADD_STRING(target, rcodetext[msg->rcode]);
3263                 } else {
3264                         snprintf(buf, sizeof(buf), "%4u", msg->rcode);
3265                         ADD_STRING(target, buf);
3266                 }
3267                 ADD_STRING(target, ", id: ");
3268                 snprintf(buf, sizeof(buf), "%6u", msg->id);
3269                 ADD_STRING(target, buf);
3270                 ADD_STRING(target, "\n;; flags:");
3271                 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3272                         ADD_STRING(target, " qr");
3273                 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3274                         ADD_STRING(target, " aa");
3275                 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3276                         ADD_STRING(target, " tc");
3277                 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3278                         ADD_STRING(target, " rd");
3279                 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3280                         ADD_STRING(target, " ra");
3281                 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3282                         ADD_STRING(target, " ad");
3283                 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
3284                         ADD_STRING(target, " cd");
3285                 /*
3286                  * The final unnamed flag must be zero.
3287                  */
3288                 if ((msg->flags & 0x0040U) != 0)
3289                         ADD_STRING(target, "; MBZ: 0x4");
3290                 if (msg->opcode != dns_opcode_update) {
3291                         ADD_STRING(target, "; QUESTION: ");
3292                 } else {
3293                         ADD_STRING(target, "; ZONE: ");
3294                 }
3295                 snprintf(buf, sizeof(buf), "%1u",
3296                          msg->counts[DNS_SECTION_QUESTION]);
3297                 ADD_STRING(target, buf);
3298                 if (msg->opcode != dns_opcode_update) {
3299                         ADD_STRING(target, ", ANSWER: ");
3300                 } else {
3301                         ADD_STRING(target, ", PREREQ: ");
3302                 }
3303                 snprintf(buf, sizeof(buf), "%1u",
3304                          msg->counts[DNS_SECTION_ANSWER]);
3305                 ADD_STRING(target, buf);
3306                 if (msg->opcode != dns_opcode_update) {
3307                         ADD_STRING(target, ", AUTHORITY: ");
3308                 } else {
3309                         ADD_STRING(target, ", UPDATE: ");
3310                 }
3311                 snprintf(buf, sizeof(buf), "%1u",
3312                         msg->counts[DNS_SECTION_AUTHORITY]);
3313                 ADD_STRING(target, buf);
3314                 ADD_STRING(target, ", ADDITIONAL: ");
3315                 snprintf(buf, sizeof(buf), "%1u",
3316                         msg->counts[DNS_SECTION_ADDITIONAL]);
3317                 ADD_STRING(target, buf);
3318                 ADD_STRING(target, "\n");
3319         }
3320         result = dns_message_pseudosectiontotext(msg,
3321                                                  DNS_PSEUDOSECTION_OPT,
3322                                                  style, flags, target);
3323         if (result != ISC_R_SUCCESS)
3324                 return (result);
3325
3326         result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
3327                                            style, flags, target);
3328         if (result != ISC_R_SUCCESS)
3329                 return (result);
3330         result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
3331                                            style, flags, target);
3332         if (result != ISC_R_SUCCESS)
3333                 return (result);
3334         result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
3335                                            style, flags, target);
3336         if (result != ISC_R_SUCCESS)
3337                 return (result);
3338         result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
3339                                            style, flags, target);
3340         if (result != ISC_R_SUCCESS)
3341                 return (result);
3342
3343         result = dns_message_pseudosectiontotext(msg,
3344                                                  DNS_PSEUDOSECTION_TSIG,
3345                                                  style, flags, target);
3346         if (result != ISC_R_SUCCESS)
3347                 return (result);
3348
3349         result = dns_message_pseudosectiontotext(msg,
3350                                                  DNS_PSEUDOSECTION_SIG0,
3351                                                  style, flags, target);
3352         if (result != ISC_R_SUCCESS)
3353                 return (result);
3354
3355         return (ISC_R_SUCCESS);
3356 }
3357
3358 isc_region_t *
3359 dns_message_getrawmessage(dns_message_t *msg) {
3360         REQUIRE(DNS_MESSAGE_VALID(msg));
3361         return (&msg->saved);
3362 }
3363
3364 void
3365 dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3366                          const void *order_arg)
3367 {
3368         REQUIRE(DNS_MESSAGE_VALID(msg));
3369         msg->order = order;
3370         msg->order_arg = order_arg;
3371 }
3372
3373 void
3374 dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3375         REQUIRE(DNS_MESSAGE_VALID(msg));
3376         msg->timeadjust = timeadjust;
3377 }
3378
3379 int
3380 dns_message_gettimeadjust(dns_message_t *msg) {
3381         REQUIRE(DNS_MESSAGE_VALID(msg));
3382         return (msg->timeadjust);
3383 }
3384
3385 isc_result_t
3386 dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3387
3388         REQUIRE(opcode < 16);
3389
3390         if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
3391                 return (ISC_R_NOSPACE);
3392         isc_buffer_putstr(target, opcodetext[opcode]);
3393         return (ISC_R_SUCCESS);
3394 }