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