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