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