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