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