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