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