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