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