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