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