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