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