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