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