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