message.c revision 135446
1/*
2 * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: message.c,v 1.194.2.10.2.17 2004/05/05 01:32:16 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_findtype(dns_name_t *name, dns_rdatatype_t type,
805		     dns_rdatatype_t covers, dns_rdataset_t **rdataset)
806{
807	dns_rdataset_t *curr;
808
809	if (rdataset != NULL) {
810		REQUIRE(*rdataset == NULL);
811	}
812
813	for (curr = ISC_LIST_TAIL(name->list);
814	     curr != NULL;
815	     curr = ISC_LIST_PREV(curr, link)) {
816		if (curr->type == type && curr->covers == covers) {
817			if (rdataset != NULL)
818				*rdataset = curr;
819			return (ISC_R_SUCCESS);
820		}
821	}
822
823	return (ISC_R_NOTFOUND);
824}
825
826/*
827 * Read a name from buffer "source".
828 */
829static isc_result_t
830getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
831	dns_decompress_t *dctx)
832{
833	isc_buffer_t *scratch;
834	isc_result_t result;
835	unsigned int tries;
836
837	scratch = currentbuffer(msg);
838
839	/*
840	 * First try:  use current buffer.
841	 * Second try:  allocate a new buffer and use that.
842	 */
843	tries = 0;
844	while (tries < 2) {
845		result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
846					   scratch);
847
848		if (result == ISC_R_NOSPACE) {
849			tries++;
850
851			result = newbuffer(msg, SCRATCHPAD_SIZE);
852			if (result != ISC_R_SUCCESS)
853				return (result);
854
855			scratch = currentbuffer(msg);
856			dns_name_reset(name);
857		} else {
858			return (result);
859		}
860	}
861
862	INSIST(0);  /* Cannot get here... */
863	return (ISC_R_UNEXPECTED);
864}
865
866static isc_result_t
867getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
868	 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
869	 unsigned int rdatalen, dns_rdata_t *rdata)
870{
871	isc_buffer_t *scratch;
872	isc_result_t result;
873	unsigned int tries;
874	unsigned int trysize;
875
876	scratch = currentbuffer(msg);
877
878	isc_buffer_setactive(source, rdatalen);
879
880	/*
881	 * First try:  use current buffer.
882	 * Second try:  allocate a new buffer of size
883	 *     max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
884	 *     (the data will fit if it was not more than 50% compressed)
885	 * Subsequent tries: double buffer size on each try.
886	 */
887	tries = 0;
888	trysize = 0;
889	/* XXX possibly change this to a while (tries < 2) loop */
890	for (;;) {
891		result = dns_rdata_fromwire(rdata, rdclass, rdtype,
892					    source, dctx, 0,
893					    scratch);
894
895		if (result == ISC_R_NOSPACE) {
896			if (tries == 0) {
897				trysize = 2 * rdatalen;
898				if (trysize < SCRATCHPAD_SIZE)
899					trysize = SCRATCHPAD_SIZE;
900			} else {
901				INSIST(trysize != 0);
902				if (trysize >= 65535)
903					return (ISC_R_NOSPACE);
904					/* XXX DNS_R_RRTOOLONG? */
905				trysize *= 2;
906			}
907			tries++;
908			result = newbuffer(msg, trysize);
909			if (result != ISC_R_SUCCESS)
910				return (result);
911
912			scratch = currentbuffer(msg);
913		} else {
914			return (result);
915		}
916	}
917}
918
919#define DO_FORMERR					\
920	do {						\
921		if (best_effort)			\
922			seen_problem = ISC_TRUE;	\
923		else {					\
924			result = DNS_R_FORMERR;		\
925			goto cleanup;			\
926		}					\
927	} while (0)
928
929static isc_result_t
930getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
931	     unsigned int options)
932{
933	isc_region_t r;
934	unsigned int count;
935	dns_name_t *name;
936	dns_name_t *name2;
937	dns_offsets_t *offsets;
938	dns_rdataset_t *rdataset;
939	dns_rdatalist_t *rdatalist;
940	isc_result_t result;
941	dns_rdatatype_t rdtype;
942	dns_rdataclass_t rdclass;
943	dns_namelist_t *section;
944	isc_boolean_t free_name;
945	isc_boolean_t best_effort;
946	isc_boolean_t seen_problem;
947
948	section = &msg->sections[DNS_SECTION_QUESTION];
949
950	best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
951	seen_problem = ISC_FALSE;
952
953	name = NULL;
954	rdataset = NULL;
955	rdatalist = NULL;
956
957	for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
958		name = isc_mempool_get(msg->namepool);
959		if (name == NULL)
960			return (ISC_R_NOMEMORY);
961		free_name = ISC_TRUE;
962
963		offsets = newoffsets(msg);
964		if (offsets == NULL) {
965			result = ISC_R_NOMEMORY;
966			goto cleanup;
967		}
968		dns_name_init(name, *offsets);
969
970		/*
971		 * Parse the name out of this packet.
972		 */
973		isc_buffer_remainingregion(source, &r);
974		isc_buffer_setactive(source, r.length);
975		result = getname(name, source, msg, dctx);
976		if (result != ISC_R_SUCCESS)
977			goto cleanup;
978
979		/*
980		 * Run through the section, looking to see if this name
981		 * is already there.  If it is found, put back the allocated
982		 * name since we no longer need it, and set our name pointer
983		 * to point to the name we found.
984		 */
985		result = findname(&name2, name, section);
986
987		/*
988		 * If it is the first name in the section, accept it.
989		 *
990		 * If it is not, but is not the same as the name already
991		 * in the question section, append to the section.  Note that
992		 * here in the question section this is illegal, so return
993		 * FORMERR.  In the future, check the opcode to see if
994		 * this should be legal or not.  In either case we no longer
995		 * need this name pointer.
996		 */
997		if (result != ISC_R_SUCCESS) {
998			if (!ISC_LIST_EMPTY(*section))
999				DO_FORMERR;
1000			ISC_LIST_APPEND(*section, name, link);
1001			free_name = ISC_FALSE;
1002		} else {
1003			isc_mempool_put(msg->namepool, name);
1004			name = name2;
1005			name2 = NULL;
1006			free_name = ISC_FALSE;
1007		}
1008
1009		/*
1010		 * Get type and class.
1011		 */
1012		isc_buffer_remainingregion(source, &r);
1013		if (r.length < 4) {
1014			result = ISC_R_UNEXPECTEDEND;
1015			goto cleanup;
1016		}
1017		rdtype = isc_buffer_getuint16(source);
1018		rdclass = isc_buffer_getuint16(source);
1019
1020		/*
1021		 * If this class is different than the one we already read,
1022		 * this is an error.
1023		 */
1024		if (msg->state == DNS_SECTION_ANY) {
1025			msg->state = DNS_SECTION_QUESTION;
1026			msg->rdclass = rdclass;
1027		} else if (msg->rdclass != rdclass)
1028			DO_FORMERR;
1029
1030		/*
1031		 * Can't ask the same question twice.
1032		 */
1033		result = dns_message_findtype(name, rdtype, 0, NULL);
1034		if (result == ISC_R_SUCCESS)
1035			DO_FORMERR;
1036
1037		/*
1038		 * Allocate a new rdatalist.
1039		 */
1040		rdatalist = newrdatalist(msg);
1041		if (rdatalist == NULL) {
1042			result = ISC_R_NOMEMORY;
1043			goto cleanup;
1044		}
1045		rdataset =  isc_mempool_get(msg->rdspool);
1046		if (rdataset == NULL) {
1047			result = ISC_R_NOMEMORY;
1048			goto cleanup;
1049		}
1050
1051		/*
1052		 * Convert rdatalist to rdataset, and attach the latter to
1053		 * the name.
1054		 */
1055		rdatalist->type = rdtype;
1056		rdatalist->covers = 0;
1057		rdatalist->rdclass = rdclass;
1058		rdatalist->ttl = 0;
1059		ISC_LIST_INIT(rdatalist->rdata);
1060
1061		dns_rdataset_init(rdataset);
1062		result = dns_rdatalist_tordataset(rdatalist, rdataset);
1063		if (result != ISC_R_SUCCESS)
1064			goto cleanup;
1065
1066		rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1067
1068		ISC_LIST_APPEND(name->list, rdataset, link);
1069		rdataset = NULL;
1070	}
1071
1072	if (seen_problem)
1073		return (DNS_R_RECOVERABLE);
1074	return (ISC_R_SUCCESS);
1075
1076 cleanup:
1077	if (rdataset != NULL) {
1078		INSIST(!dns_rdataset_isassociated(rdataset));
1079		isc_mempool_put(msg->rdspool, rdataset);
1080	}
1081#if 0
1082	if (rdatalist != NULL)
1083		isc_mempool_put(msg->rdlpool, rdatalist);
1084#endif
1085	if (free_name)
1086		isc_mempool_put(msg->namepool, name);
1087
1088	return (result);
1089}
1090
1091static isc_boolean_t
1092update(dns_section_t section, dns_rdataclass_t rdclass) {
1093	if (section == DNS_SECTION_PREREQUISITE)
1094		return (ISC_TF(rdclass == dns_rdataclass_any ||
1095			       rdclass == dns_rdataclass_none));
1096	if (section == DNS_SECTION_UPDATE)
1097		return (ISC_TF(rdclass == dns_rdataclass_any));
1098	return (ISC_FALSE);
1099}
1100
1101static isc_result_t
1102getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1103	   dns_section_t sectionid, unsigned int options)
1104{
1105	isc_region_t r;
1106	unsigned int count, rdatalen;
1107	dns_name_t *name;
1108	dns_name_t *name2;
1109	dns_offsets_t *offsets;
1110	dns_rdataset_t *rdataset;
1111	dns_rdatalist_t *rdatalist;
1112	isc_result_t result;
1113	dns_rdatatype_t rdtype, covers;
1114	dns_rdataclass_t rdclass;
1115	dns_rdata_t *rdata;
1116	dns_ttl_t ttl;
1117	dns_namelist_t *section;
1118	isc_boolean_t free_name, free_rdataset;
1119	isc_boolean_t preserve_order, best_effort, seen_problem;
1120	isc_boolean_t issigzero;
1121
1122	preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
1123	best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1124	seen_problem = ISC_FALSE;
1125
1126	for (count = 0; count < msg->counts[sectionid]; count++) {
1127		int recstart = source->current;
1128		isc_boolean_t skip_name_search, skip_type_search;
1129
1130		section = &msg->sections[sectionid];
1131
1132		skip_name_search = ISC_FALSE;
1133		skip_type_search = ISC_FALSE;
1134		free_name = ISC_FALSE;
1135		free_rdataset = ISC_FALSE;
1136
1137		name = isc_mempool_get(msg->namepool);
1138		if (name == NULL)
1139			return (ISC_R_NOMEMORY);
1140		free_name = ISC_TRUE;
1141
1142		offsets = newoffsets(msg);
1143		if (offsets == NULL) {
1144			result = ISC_R_NOMEMORY;
1145			goto cleanup;
1146		}
1147		dns_name_init(name, *offsets);
1148
1149		/*
1150		 * Parse the name out of this packet.
1151		 */
1152		isc_buffer_remainingregion(source, &r);
1153		isc_buffer_setactive(source, r.length);
1154		result = getname(name, source, msg, dctx);
1155		if (result != ISC_R_SUCCESS)
1156			goto cleanup;
1157
1158		/*
1159		 * Get type, class, ttl, and rdatalen.  Verify that at least
1160		 * rdatalen bytes remain.  (Some of this is deferred to
1161		 * later.)
1162		 */
1163		isc_buffer_remainingregion(source, &r);
1164		if (r.length < 2 + 2 + 4 + 2) {
1165			result = ISC_R_UNEXPECTEDEND;
1166			goto cleanup;
1167		}
1168		rdtype = isc_buffer_getuint16(source);
1169		rdclass = isc_buffer_getuint16(source);
1170
1171		/*
1172		 * If there was no question section, we may not yet have
1173		 * established a class.  Do so now.
1174		 */
1175		if (msg->state == DNS_SECTION_ANY &&
1176		    rdtype != dns_rdatatype_opt &&	/* class is UDP SIZE */
1177		    rdtype != dns_rdatatype_tsig &&	/* class is ANY */
1178		    rdtype != dns_rdatatype_tkey) {	/* class is undefined */
1179			msg->rdclass = rdclass;
1180			msg->state = DNS_SECTION_QUESTION;
1181		}
1182
1183		/*
1184		 * If this class is different than the one in the question
1185		 * section, bail.
1186		 */
1187		if (msg->opcode != dns_opcode_update
1188		    && rdtype != dns_rdatatype_tsig
1189		    && rdtype != dns_rdatatype_opt
1190		    && rdtype != dns_rdatatype_dnskey /* in a TKEY query */
1191		    && rdtype != dns_rdatatype_sig /* SIG(0) */
1192		    && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1193		    && msg->rdclass != rdclass)
1194			DO_FORMERR;
1195
1196		/*
1197		 * Special type handling for TSIG, OPT, and TKEY.
1198		 */
1199		if (rdtype == dns_rdatatype_tsig) {
1200			/*
1201			 * If it is a tsig, verify that it is in the
1202			 * additional data section.
1203			 */
1204			if (sectionid != DNS_SECTION_ADDITIONAL ||
1205			    rdclass != dns_rdataclass_any ||
1206			    count != msg->counts[sectionid]  - 1)
1207				DO_FORMERR;
1208			msg->sigstart = recstart;
1209			skip_name_search = ISC_TRUE;
1210			skip_type_search = ISC_TRUE;
1211		} else if (rdtype == dns_rdatatype_opt) {
1212			/*
1213			 * The name of an OPT record must be ".", it
1214			 * must be in the additional data section, and
1215			 * it must be the first OPT we've seen.
1216			 */
1217			if (!dns_name_equal(dns_rootname, name) ||
1218			    msg->opt != NULL)
1219				DO_FORMERR;
1220			skip_name_search = ISC_TRUE;
1221			skip_type_search = ISC_TRUE;
1222		} else if (rdtype == dns_rdatatype_tkey) {
1223			/*
1224			 * A TKEY must be in the additional section if this
1225			 * is a query, and the answer section if this is a
1226			 * response.  Unless it's a Win2000 client.
1227			 *
1228			 * Its class is ignored.
1229			 */
1230			dns_section_t tkeysection;
1231
1232			if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1233				tkeysection = DNS_SECTION_ADDITIONAL;
1234			else
1235				tkeysection = DNS_SECTION_ANSWER;
1236			if (sectionid != tkeysection &&
1237			    sectionid != DNS_SECTION_ANSWER)
1238				DO_FORMERR;
1239		}
1240
1241		/*
1242		 * ... now get ttl and rdatalen, and check buffer.
1243		 */
1244		ttl = isc_buffer_getuint32(source);
1245		rdatalen = isc_buffer_getuint16(source);
1246		r.length -= (2 + 2 + 4 + 2);
1247		if (r.length < rdatalen) {
1248			result = ISC_R_UNEXPECTEDEND;
1249			goto cleanup;
1250		}
1251
1252		/*
1253		 * Read the rdata from the wire format.  Interpret the
1254		 * rdata according to its actual class, even if it had a
1255		 * DynDNS meta-class in the packet (unless this is a TSIG).
1256		 * Then put the meta-class back into the finished rdata.
1257		 */
1258		rdata = newrdata(msg);
1259		if (rdata == NULL) {
1260			result = ISC_R_NOMEMORY;
1261			goto cleanup;
1262		}
1263		if (msg->opcode == dns_opcode_update &&
1264		    update(sectionid, rdclass)) {
1265			if (rdatalen != 0) {
1266				result = DNS_R_FORMERR;
1267				goto cleanup;
1268			}
1269			/*
1270			 * When the rdata is empty, the data pointer is
1271			 * never dereferenced, but it must still be non-NULL.
1272			 * Casting 1 rather than "" avoids warnings about
1273			 * discarding the const attribute of a string,
1274			 * for compilers that would warn about such things.
1275			 */
1276			rdata->data = (unsigned char *)1;
1277			rdata->length = 0;
1278			rdata->rdclass = rdclass;
1279			rdata->type = rdtype;
1280			rdata->flags = DNS_RDATA_UPDATE;
1281			result = ISC_R_SUCCESS;
1282		} else if (rdtype == dns_rdatatype_tsig)
1283			result = getrdata(source, msg, dctx, rdclass,
1284					  rdtype, rdatalen, rdata);
1285		else
1286			result = getrdata(source, msg, dctx, msg->rdclass,
1287					  rdtype, rdatalen, rdata);
1288		if (result != ISC_R_SUCCESS)
1289			goto cleanup;
1290		rdata->rdclass = rdclass;
1291		issigzero = ISC_FALSE;
1292		if (rdtype == dns_rdatatype_rrsig  &&
1293		    rdata->flags == 0) {
1294			covers = dns_rdata_covers(rdata);
1295			if (covers == 0)
1296				DO_FORMERR;
1297		} else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1298			   rdata->flags == 0) {
1299			covers = dns_rdata_covers(rdata);
1300			if (covers == 0) {
1301				if (sectionid != DNS_SECTION_ADDITIONAL ||
1302				    count != msg->counts[sectionid]  - 1)
1303					DO_FORMERR;
1304				msg->sigstart = recstart;
1305				skip_name_search = ISC_TRUE;
1306				skip_type_search = ISC_TRUE;
1307				issigzero = ISC_TRUE;
1308			}
1309		} else
1310			covers = 0;
1311
1312		/*
1313		 * If we are doing a dynamic update or this is a meta-type,
1314		 * don't bother searching for a name, just append this one
1315		 * to the end of the message.
1316		 */
1317		if (preserve_order || msg->opcode == dns_opcode_update ||
1318		    skip_name_search) {
1319			if (rdtype != dns_rdatatype_opt &&
1320			    rdtype != dns_rdatatype_tsig &&
1321			    !issigzero)
1322			{
1323				ISC_LIST_APPEND(*section, name, link);
1324				free_name = ISC_FALSE;
1325			}
1326		} else {
1327			/*
1328			 * Run through the section, looking to see if this name
1329			 * is already there.  If it is found, put back the
1330			 * allocated name since we no longer need it, and set
1331			 * our name pointer to point to the name we found.
1332			 */
1333			result = findname(&name2, name, section);
1334
1335			/*
1336			 * If it is a new name, append to the section.
1337			 */
1338			if (result == ISC_R_SUCCESS) {
1339				isc_mempool_put(msg->namepool, name);
1340				name = name2;
1341			} else {
1342				ISC_LIST_APPEND(*section, name, link);
1343			}
1344			free_name = ISC_FALSE;
1345		}
1346
1347		/*
1348		 * Search name for the particular type and class.
1349		 * Skip this stage if in update mode or this is a meta-type.
1350		 */
1351		if (preserve_order || msg->opcode == dns_opcode_update ||
1352		    skip_type_search)
1353			result = ISC_R_NOTFOUND;
1354		else {
1355			/*
1356			 * If this is a type that can only occur in
1357			 * the question section, fail.
1358			 */
1359			if (dns_rdatatype_questiononly(rdtype))
1360				DO_FORMERR;
1361
1362			rdataset = NULL;
1363			result = dns_message_findtype(name, rdtype, covers,
1364						      &rdataset);
1365		}
1366
1367		/*
1368		 * If we found an rdataset that matches, we need to
1369		 * append this rdata to that set.  If we did not, we need
1370		 * to create a new rdatalist, store the important bits there,
1371		 * convert it to an rdataset, and link the latter to the name.
1372		 * Yuck.  When appending, make certain that the type isn't
1373		 * a singleton type, such as SOA or CNAME.
1374		 *
1375		 * Note that this check will be bypassed when preserving order,
1376		 * the opcode is an update, or the type search is skipped.
1377		 */
1378		if (result == ISC_R_SUCCESS) {
1379			if (dns_rdatatype_issingleton(rdtype))
1380				DO_FORMERR;
1381		}
1382
1383		if (result == ISC_R_NOTFOUND) {
1384			rdataset = isc_mempool_get(msg->rdspool);
1385			if (rdataset == NULL) {
1386				result = ISC_R_NOMEMORY;
1387				goto cleanup;
1388			}
1389			free_rdataset = ISC_TRUE;
1390
1391			rdatalist = newrdatalist(msg);
1392			if (rdatalist == NULL) {
1393				result = ISC_R_NOMEMORY;
1394				goto cleanup;
1395			}
1396
1397			rdatalist->type = rdtype;
1398			rdatalist->covers = covers;
1399			rdatalist->rdclass = rdclass;
1400			rdatalist->ttl = ttl;
1401			ISC_LIST_INIT(rdatalist->rdata);
1402
1403			dns_rdataset_init(rdataset);
1404			RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1405							       rdataset)
1406				      == ISC_R_SUCCESS);
1407
1408			if (rdtype != dns_rdatatype_opt &&
1409			    rdtype != dns_rdatatype_tsig &&
1410			    !issigzero)
1411			{
1412				ISC_LIST_APPEND(name->list, rdataset, link);
1413				free_rdataset = ISC_FALSE;
1414			}
1415		}
1416
1417		/*
1418		 * Minimize TTLs.
1419		 *
1420		 * Section 5.2 of RFC 2181 says we should drop
1421		 * nonauthoritative rrsets where the TTLs differ, but we
1422		 * currently treat them the as if they were authoritative and
1423		 * minimize them.
1424		 */
1425		if (ttl != rdataset->ttl) {
1426			rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1427			if (ttl < rdataset->ttl)
1428				rdataset->ttl = ttl;
1429		}
1430
1431		/*
1432		 * XXXMLG Perform a totally ugly hack here to pull
1433		 * the rdatalist out of the private field in the rdataset,
1434		 * and append this rdata to the rdatalist's linked list
1435		 * of rdata.
1436		 */
1437		rdatalist = (dns_rdatalist_t *)(rdataset->private1);
1438
1439		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1440
1441		/*
1442		 * If this is an OPT record, remember it.  Also, set
1443		 * the extended rcode.  Note that msg->opt will only be set
1444		 * if best-effort parsing is enabled.
1445		 */
1446		if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1447			dns_rcode_t ercode;
1448
1449			msg->opt = rdataset;
1450			rdataset = NULL;
1451			free_rdataset = ISC_FALSE;
1452			ercode = (dns_rcode_t)
1453				((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1454				 >> 20);
1455			msg->rcode |= ercode;
1456			isc_mempool_put(msg->namepool, name);
1457			free_name = ISC_FALSE;
1458		}
1459
1460		/*
1461		 * If this is an SIG(0) or TSIG record, remember it.  Note
1462		 * that msg->sig0 or msg->tsig will only be set if best-effort
1463		 * parsing is enabled.
1464		 */
1465		if (issigzero && msg->sig0 == NULL) {
1466			msg->sig0 = rdataset;
1467			msg->sig0name = name;
1468			rdataset = NULL;
1469			free_rdataset = ISC_FALSE;
1470			free_name = ISC_FALSE;
1471		} else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1472			msg->tsig = rdataset;
1473			msg->tsigname = name;
1474			rdataset = NULL;
1475			free_rdataset = ISC_FALSE;
1476			free_name = ISC_FALSE;
1477		}
1478
1479		INSIST(free_name == ISC_FALSE);
1480		INSIST(free_rdataset == ISC_FALSE);
1481	}
1482
1483	if (seen_problem)
1484		return (DNS_R_RECOVERABLE);
1485	return (ISC_R_SUCCESS);
1486
1487 cleanup:
1488	if (free_name)
1489		isc_mempool_put(msg->namepool, name);
1490	if (free_rdataset)
1491		isc_mempool_put(msg->rdspool, rdataset);
1492
1493	return (result);
1494}
1495
1496isc_result_t
1497dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1498		  unsigned int options)
1499{
1500	isc_region_t r;
1501	dns_decompress_t dctx;
1502	isc_result_t ret;
1503	isc_uint16_t tmpflags;
1504	isc_buffer_t origsource;
1505	isc_boolean_t seen_problem;
1506	isc_boolean_t ignore_tc;
1507
1508	REQUIRE(DNS_MESSAGE_VALID(msg));
1509	REQUIRE(source != NULL);
1510	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1511
1512	seen_problem = ISC_FALSE;
1513	ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1514
1515	origsource = *source;
1516
1517	msg->header_ok = 0;
1518	msg->question_ok = 0;
1519
1520	isc_buffer_remainingregion(source, &r);
1521	if (r.length < DNS_MESSAGE_HEADERLEN)
1522		return (ISC_R_UNEXPECTEDEND);
1523
1524	msg->id = isc_buffer_getuint16(source);
1525	tmpflags = isc_buffer_getuint16(source);
1526	msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1527		       >> DNS_MESSAGE_OPCODE_SHIFT);
1528	msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1529	msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1530	msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1531	msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1532	msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1533	msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1534
1535	msg->header_ok = 1;
1536
1537	/*
1538	 * -1 means no EDNS.
1539	 */
1540	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1541
1542	dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1543
1544	ret = getquestions(source, msg, &dctx, options);
1545	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1546		goto truncated;
1547	if (ret == DNS_R_RECOVERABLE) {
1548		seen_problem = ISC_TRUE;
1549		ret = ISC_R_SUCCESS;
1550	}
1551	if (ret != ISC_R_SUCCESS)
1552		return (ret);
1553	msg->question_ok = 1;
1554
1555	ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1556	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1557		goto truncated;
1558	if (ret == DNS_R_RECOVERABLE) {
1559		seen_problem = ISC_TRUE;
1560		ret = ISC_R_SUCCESS;
1561	}
1562	if (ret != ISC_R_SUCCESS)
1563		return (ret);
1564
1565	ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1566	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1567		goto truncated;
1568	if (ret == DNS_R_RECOVERABLE) {
1569		seen_problem = ISC_TRUE;
1570		ret = ISC_R_SUCCESS;
1571	}
1572	if (ret != ISC_R_SUCCESS)
1573		return (ret);
1574
1575	ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, 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
1585	isc_buffer_remainingregion(source, &r);
1586	if (r.length != 0) {
1587		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1588			      DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1589			      "message has %u byte(s) of trailing garbage",
1590			      r.length);
1591	}
1592
1593 truncated:
1594	if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1595		isc_buffer_usedregion(&origsource, &msg->saved);
1596	else {
1597		msg->saved.length = isc_buffer_usedlength(&origsource);
1598		msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1599		if (msg->saved.base == NULL)
1600			return (ISC_R_NOMEMORY);
1601		memcpy(msg->saved.base, isc_buffer_base(&origsource),
1602		       msg->saved.length);
1603		msg->free_saved = 1;
1604	}
1605
1606	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1607		return (DNS_R_RECOVERABLE);
1608	if (seen_problem == ISC_TRUE)
1609		return (DNS_R_RECOVERABLE);
1610	return (ISC_R_SUCCESS);
1611}
1612
1613isc_result_t
1614dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1615			isc_buffer_t *buffer)
1616{
1617	isc_region_t r;
1618
1619	REQUIRE(DNS_MESSAGE_VALID(msg));
1620	REQUIRE(buffer != NULL);
1621	REQUIRE(msg->buffer == NULL);
1622	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1623
1624	msg->cctx = cctx;
1625
1626	/*
1627	 * Erase the contents of this buffer.
1628	 */
1629	isc_buffer_clear(buffer);
1630
1631	/*
1632	 * Make certain there is enough for at least the header in this
1633	 * buffer.
1634	 */
1635	isc_buffer_availableregion(buffer, &r);
1636	if (r.length < DNS_MESSAGE_HEADERLEN)
1637		return (ISC_R_NOSPACE);
1638
1639	if (r.length < msg->reserved)
1640		return (ISC_R_NOSPACE);
1641
1642	/*
1643	 * Reserve enough space for the header in this buffer.
1644	 */
1645	isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1646
1647	msg->buffer = buffer;
1648
1649	return (ISC_R_SUCCESS);
1650}
1651
1652isc_result_t
1653dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1654	isc_region_t r, rn;
1655
1656	REQUIRE(DNS_MESSAGE_VALID(msg));
1657	REQUIRE(buffer != NULL);
1658	REQUIRE(msg->buffer != NULL);
1659
1660	/*
1661	 * Ensure that the new buffer is empty, and has enough space to
1662	 * hold the current contents.
1663	 */
1664	isc_buffer_clear(buffer);
1665
1666	isc_buffer_availableregion(buffer, &rn);
1667	isc_buffer_usedregion(msg->buffer, &r);
1668	REQUIRE(rn.length > r.length);
1669
1670	/*
1671	 * Copy the contents from the old to the new buffer.
1672	 */
1673	isc_buffer_add(buffer, r.length);
1674	memcpy(rn.base, r.base, r.length);
1675
1676	msg->buffer = buffer;
1677
1678	return (ISC_R_SUCCESS);
1679}
1680
1681void
1682dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1683	REQUIRE(DNS_MESSAGE_VALID(msg));
1684	REQUIRE(space <= msg->reserved);
1685
1686	msg->reserved -= space;
1687}
1688
1689isc_result_t
1690dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1691	isc_region_t r;
1692
1693	REQUIRE(DNS_MESSAGE_VALID(msg));
1694
1695	if (msg->buffer != NULL) {
1696		isc_buffer_availableregion(msg->buffer, &r);
1697		if (r.length < (space + msg->reserved))
1698			return (ISC_R_NOSPACE);
1699	}
1700
1701	msg->reserved += space;
1702
1703	return (ISC_R_SUCCESS);
1704}
1705
1706static inline isc_boolean_t
1707wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1708	int pass_needed;
1709
1710	/*
1711	 * If we are not rendering class IN, this ordering is bogus.
1712	 */
1713	if (rds->rdclass != dns_rdataclass_in)
1714		return (ISC_FALSE);
1715
1716	switch (rds->type) {
1717	case dns_rdatatype_a:
1718	case dns_rdatatype_aaaa:
1719		if (preferred_glue == rds->type)
1720			pass_needed = 4;
1721		else
1722			pass_needed = 3;
1723		break;
1724	case dns_rdatatype_rrsig:
1725	case dns_rdatatype_dnskey:
1726		pass_needed = 2;
1727		break;
1728	default:
1729		pass_needed = 1;
1730	}
1731
1732	if (pass_needed >= pass)
1733		return (ISC_FALSE);
1734
1735	return (ISC_TRUE);
1736}
1737
1738isc_result_t
1739dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1740			  unsigned int options)
1741{
1742	dns_namelist_t *section;
1743	dns_name_t *name, *next_name;
1744	dns_rdataset_t *rdataset, *next_rdataset;
1745	unsigned int count, total;
1746	isc_result_t result;
1747	isc_buffer_t st; /* for rollbacks */
1748	int pass;
1749	isc_boolean_t partial = ISC_FALSE;
1750	unsigned int rd_options;
1751	dns_rdatatype_t preferred_glue = 0;
1752
1753	REQUIRE(DNS_MESSAGE_VALID(msg));
1754	REQUIRE(msg->buffer != NULL);
1755	REQUIRE(VALID_NAMED_SECTION(sectionid));
1756
1757	section = &msg->sections[sectionid];
1758
1759	if ((sectionid == DNS_SECTION_ADDITIONAL)
1760	    && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1761		if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1762			preferred_glue = dns_rdatatype_a;
1763			pass = 4;
1764		} else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1765			preferred_glue = dns_rdatatype_aaaa;
1766			pass = 4;
1767		} else
1768			pass = 3;
1769	} else
1770		pass = 1;
1771
1772	if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1773		rd_options = 0;
1774	else
1775		rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1776
1777	/*
1778	 * Shrink the space in the buffer by the reserved amount.
1779	 */
1780	msg->buffer->length -= msg->reserved;
1781
1782	total = 0;
1783	if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1784		partial = ISC_TRUE;
1785
1786	do {
1787		name = ISC_LIST_HEAD(*section);
1788		if (name == NULL) {
1789			msg->buffer->length += msg->reserved;
1790			msg->counts[sectionid] += total;
1791			return (ISC_R_SUCCESS);
1792		}
1793
1794		while (name != NULL) {
1795			next_name = ISC_LIST_NEXT(name, link);
1796
1797			rdataset = ISC_LIST_HEAD(name->list);
1798			while (rdataset != NULL) {
1799				next_rdataset = ISC_LIST_NEXT(rdataset, link);
1800
1801				if ((rdataset->attributes &
1802				     DNS_RDATASETATTR_RENDERED) != 0)
1803					goto next;
1804
1805				if (((options & DNS_MESSAGERENDER_ORDERED)
1806				     == 0)
1807				    && (sectionid == DNS_SECTION_ADDITIONAL)
1808				    && wrong_priority(rdataset, pass,
1809						      preferred_glue))
1810					goto next;
1811
1812				st = *(msg->buffer);
1813
1814				count = 0;
1815				if (partial)
1816					result = dns_rdataset_towirepartial(
1817							  rdataset,
1818							  name,
1819							  msg->cctx,
1820							  msg->buffer,
1821							  msg->order,
1822							  msg->order_arg,
1823							  rd_options,
1824							  &count,
1825							  NULL);
1826				else
1827					result = dns_rdataset_towiresorted(
1828							  rdataset,
1829							  name,
1830							  msg->cctx,
1831							  msg->buffer,
1832							  msg->order,
1833							  msg->order_arg,
1834							  rd_options,
1835							  &count);
1836
1837				total += count;
1838
1839				/*
1840				 * If out of space, record stats on what we
1841				 * rendered so far, and return that status.
1842				 *
1843				 * XXXMLG Need to change this when
1844				 * dns_rdataset_towire() can render partial
1845				 * sets starting at some arbitary point in the
1846				 * set.  This will include setting a bit in the
1847				 * rdataset to indicate that a partial
1848				 * rendering was done, and some state saved
1849				 * somewhere (probably in the message struct)
1850				 * to indicate where to continue from.
1851				 */
1852				if (partial && result == ISC_R_NOSPACE) {
1853					msg->buffer->length += msg->reserved;
1854					msg->counts[sectionid] += total;
1855					return (result);
1856				}
1857				if (result != ISC_R_SUCCESS) {
1858					INSIST(st.used < 65536);
1859					dns_compress_rollback(msg->cctx,
1860							(isc_uint16_t)st.used);
1861					*(msg->buffer) = st;  /* rollback */
1862					msg->buffer->length += msg->reserved;
1863					msg->counts[sectionid] += total;
1864					return (result);
1865				}
1866
1867				/*
1868				 * If we have rendered non-validated data,
1869				 * ensure that the AD bit is not set.
1870				 */
1871				if (rdataset->trust != dns_trust_secure &&
1872				    (sectionid == DNS_SECTION_ANSWER ||
1873				     sectionid == DNS_SECTION_AUTHORITY))
1874					msg->flags &= ~DNS_MESSAGEFLAG_AD;
1875
1876				rdataset->attributes |=
1877					DNS_RDATASETATTR_RENDERED;
1878
1879			next:
1880				rdataset = next_rdataset;
1881			}
1882
1883			name = next_name;
1884		}
1885	} while (--pass != 0);
1886
1887	msg->buffer->length += msg->reserved;
1888	msg->counts[sectionid] += total;
1889
1890	return (ISC_R_SUCCESS);
1891}
1892
1893void
1894dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
1895	isc_uint16_t tmp;
1896	isc_region_t r;
1897
1898	REQUIRE(DNS_MESSAGE_VALID(msg));
1899	REQUIRE(target != NULL);
1900
1901	isc_buffer_availableregion(target, &r);
1902	REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
1903
1904	isc_buffer_putuint16(target, msg->id);
1905
1906	tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
1907	       & DNS_MESSAGE_OPCODE_MASK);
1908	tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
1909	tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
1910
1911	INSIST(msg->counts[DNS_SECTION_QUESTION]  < 65536 &&
1912	       msg->counts[DNS_SECTION_ANSWER]    < 65536 &&
1913	       msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
1914	       msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
1915
1916	isc_buffer_putuint16(target, tmp);
1917	isc_buffer_putuint16(target,
1918			    (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
1919	isc_buffer_putuint16(target,
1920			    (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
1921	isc_buffer_putuint16(target,
1922			    (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
1923	isc_buffer_putuint16(target,
1924			    (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
1925}
1926
1927isc_result_t
1928dns_message_renderend(dns_message_t *msg) {
1929	isc_buffer_t tmpbuf;
1930	isc_region_t r;
1931	int result;
1932	unsigned int count;
1933
1934	REQUIRE(DNS_MESSAGE_VALID(msg));
1935	REQUIRE(msg->buffer != NULL);
1936
1937	if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
1938		/*
1939		 * We have an extended rcode but are not using EDNS.
1940		 */
1941		return (DNS_R_FORMERR);
1942	}
1943
1944	/*
1945	 * If we've got an OPT record, render it.
1946	 */
1947	if (msg->opt != NULL) {
1948		dns_message_renderrelease(msg, msg->opt_reserved);
1949		msg->opt_reserved = 0;
1950		/*
1951		 * Set the extended rcode.
1952		 */
1953		msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
1954		msg->opt->ttl |= ((msg->rcode << 20) &
1955				  DNS_MESSAGE_EDNSRCODE_MASK);
1956		/*
1957		 * Render.
1958		 */
1959		count = 0;
1960		result = dns_rdataset_towire(msg->opt, dns_rootname,
1961					     msg->cctx, msg->buffer, 0,
1962					     &count);
1963		msg->counts[DNS_SECTION_ADDITIONAL] += count;
1964		if (result != ISC_R_SUCCESS)
1965			return (result);
1966	}
1967
1968	/*
1969	 * If we're adding a TSIG or SIG(0) to a truncated message,
1970	 * clear all rdatasets from the message except for the question
1971	 * before adding the TSIG or SIG(0).  If the question doesn't fit,
1972	 * don't include it.
1973	 */
1974	if ((msg->tsigkey != NULL || msg->sig0key != NULL) &&
1975	    (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
1976	{
1977		isc_buffer_t *buf;
1978
1979		msgresetnames(msg, DNS_SECTION_ANSWER);
1980		buf = msg->buffer;
1981		dns_message_renderreset(msg);
1982		msg->buffer = buf;
1983		isc_buffer_clear(msg->buffer);
1984		isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
1985		dns_compress_rollback(msg->cctx, 0);
1986		result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
1987						   0);
1988		if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
1989			return (result);
1990	}
1991
1992	/*
1993	 * If we're adding a TSIG record, generate and render it.
1994	 */
1995	if (msg->tsigkey != NULL) {
1996		dns_message_renderrelease(msg, msg->sig_reserved);
1997		msg->sig_reserved = 0;
1998		result = dns_tsig_sign(msg);
1999		if (result != ISC_R_SUCCESS)
2000			return (result);
2001		count = 0;
2002		result = dns_rdataset_towire(msg->tsig, msg->tsigname,
2003					     msg->cctx, msg->buffer, 0,
2004					     &count);
2005		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2006		if (result != ISC_R_SUCCESS)
2007			return (result);
2008	}
2009
2010	/*
2011	 * If we're adding a SIG(0) record, generate and render it.
2012	 */
2013	if (msg->sig0key != NULL) {
2014		dns_message_renderrelease(msg, msg->sig_reserved);
2015		msg->sig_reserved = 0;
2016		result = dns_dnssec_signmessage(msg, msg->sig0key);
2017		if (result != ISC_R_SUCCESS)
2018			return (result);
2019		count = 0;
2020		/*
2021		 * Note: dns_rootname is used here, not msg->sig0name, since
2022		 * the owner name of a SIG(0) is irrelevant, and will not
2023		 * be set in a message being rendered.
2024		 */
2025		result = dns_rdataset_towire(msg->sig0, dns_rootname,
2026					     msg->cctx, msg->buffer, 0,
2027					     &count);
2028		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2029		if (result != ISC_R_SUCCESS)
2030			return (result);
2031	}
2032
2033	isc_buffer_usedregion(msg->buffer, &r);
2034	isc_buffer_init(&tmpbuf, r.base, r.length);
2035
2036	dns_message_renderheader(msg, &tmpbuf);
2037
2038	msg->buffer = NULL;  /* forget about this buffer only on success XXX */
2039
2040	return (ISC_R_SUCCESS);
2041}
2042
2043void
2044dns_message_renderreset(dns_message_t *msg) {
2045	unsigned int i;
2046	dns_name_t *name;
2047	dns_rdataset_t *rds;
2048
2049	/*
2050	 * Reset the message so that it may be rendered again.
2051	 */
2052
2053	REQUIRE(DNS_MESSAGE_VALID(msg));
2054	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2055
2056	msg->buffer = NULL;
2057
2058	for (i = 0; i < DNS_SECTION_MAX; i++) {
2059		msg->cursors[i] = NULL;
2060		msg->counts[i] = 0;
2061		for (name = ISC_LIST_HEAD(msg->sections[i]);
2062		     name != NULL;
2063		     name = ISC_LIST_NEXT(name, link)) {
2064			for (rds = ISC_LIST_HEAD(name->list);
2065			     rds != NULL;
2066			     rds = ISC_LIST_NEXT(rds, link)) {
2067				rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2068			}
2069		}
2070	}
2071	if (msg->tsigname != NULL)
2072		dns_message_puttempname(msg, &msg->tsigname);
2073	if (msg->tsig != NULL) {
2074		dns_rdataset_disassociate(msg->tsig);
2075		dns_message_puttemprdataset(msg, &msg->tsig);
2076	}
2077	if (msg->sig0 != NULL) {
2078		dns_rdataset_disassociate(msg->sig0);
2079		dns_message_puttemprdataset(msg, &msg->sig0);
2080	}
2081}
2082
2083isc_result_t
2084dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2085	REQUIRE(DNS_MESSAGE_VALID(msg));
2086	REQUIRE(VALID_NAMED_SECTION(section));
2087
2088	msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2089
2090	if (msg->cursors[section] == NULL)
2091		return (ISC_R_NOMORE);
2092
2093	return (ISC_R_SUCCESS);
2094}
2095
2096isc_result_t
2097dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2098	REQUIRE(DNS_MESSAGE_VALID(msg));
2099	REQUIRE(VALID_NAMED_SECTION(section));
2100	REQUIRE(msg->cursors[section] != NULL);
2101
2102	msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2103
2104	if (msg->cursors[section] == NULL)
2105		return (ISC_R_NOMORE);
2106
2107	return (ISC_R_SUCCESS);
2108}
2109
2110void
2111dns_message_currentname(dns_message_t *msg, dns_section_t section,
2112			dns_name_t **name)
2113{
2114	REQUIRE(DNS_MESSAGE_VALID(msg));
2115	REQUIRE(VALID_NAMED_SECTION(section));
2116	REQUIRE(name != NULL && *name == NULL);
2117	REQUIRE(msg->cursors[section] != NULL);
2118
2119	*name = msg->cursors[section];
2120}
2121
2122isc_result_t
2123dns_message_findname(dns_message_t *msg, dns_section_t section,
2124		     dns_name_t *target, dns_rdatatype_t type,
2125		     dns_rdatatype_t covers, dns_name_t **name,
2126		     dns_rdataset_t **rdataset)
2127{
2128	dns_name_t *foundname;
2129	isc_result_t result;
2130
2131	/*
2132	 * XXX These requirements are probably too intensive, especially
2133	 * where things can be NULL, but as they are they ensure that if
2134	 * something is NON-NULL, indicating that the caller expects it
2135	 * to be filled in, that we can in fact fill it in.
2136	 */
2137	REQUIRE(msg != NULL);
2138	REQUIRE(VALID_SECTION(section));
2139	REQUIRE(target != NULL);
2140	if (name != NULL)
2141		REQUIRE(*name == NULL);
2142	if (type == dns_rdatatype_any) {
2143		REQUIRE(rdataset == NULL);
2144	} else {
2145		if (rdataset != NULL)
2146			REQUIRE(*rdataset == NULL);
2147	}
2148
2149	result = findname(&foundname, target,
2150			  &msg->sections[section]);
2151
2152	if (result == ISC_R_NOTFOUND)
2153		return (DNS_R_NXDOMAIN);
2154	else if (result != ISC_R_SUCCESS)
2155		return (result);
2156
2157	if (name != NULL)
2158		*name = foundname;
2159
2160	/*
2161	 * And now look for the type.
2162	 */
2163	if (type == dns_rdatatype_any)
2164		return (ISC_R_SUCCESS);
2165
2166	result = dns_message_findtype(foundname, type, covers, rdataset);
2167	if (result == ISC_R_NOTFOUND)
2168		return (DNS_R_NXRRSET);
2169
2170	return (result);
2171}
2172
2173void
2174dns_message_movename(dns_message_t *msg, dns_name_t *name,
2175		     dns_section_t fromsection,
2176		     dns_section_t tosection)
2177{
2178	REQUIRE(msg != NULL);
2179	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2180	REQUIRE(name != NULL);
2181	REQUIRE(VALID_NAMED_SECTION(fromsection));
2182	REQUIRE(VALID_NAMED_SECTION(tosection));
2183
2184	/*
2185	 * Unlink the name from the old section
2186	 */
2187	ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2188	ISC_LIST_APPEND(msg->sections[tosection], name, link);
2189}
2190
2191void
2192dns_message_addname(dns_message_t *msg, dns_name_t *name,
2193		    dns_section_t section)
2194{
2195	REQUIRE(msg != NULL);
2196	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2197	REQUIRE(name != NULL);
2198	REQUIRE(VALID_NAMED_SECTION(section));
2199
2200	ISC_LIST_APPEND(msg->sections[section], name, link);
2201}
2202
2203isc_result_t
2204dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2205	REQUIRE(DNS_MESSAGE_VALID(msg));
2206	REQUIRE(item != NULL && *item == NULL);
2207
2208	*item = isc_mempool_get(msg->namepool);
2209	if (*item == NULL)
2210		return (ISC_R_NOMEMORY);
2211	dns_name_init(*item, NULL);
2212
2213	return (ISC_R_SUCCESS);
2214}
2215
2216isc_result_t
2217dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2218	REQUIRE(DNS_MESSAGE_VALID(msg));
2219	REQUIRE(item != NULL && *item == NULL);
2220
2221	*item = newoffsets(msg);
2222	if (*item == NULL)
2223		return (ISC_R_NOMEMORY);
2224
2225	return (ISC_R_SUCCESS);
2226}
2227
2228isc_result_t
2229dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2230	REQUIRE(DNS_MESSAGE_VALID(msg));
2231	REQUIRE(item != NULL && *item == NULL);
2232
2233	*item = newrdata(msg);
2234	if (*item == NULL)
2235		return (ISC_R_NOMEMORY);
2236
2237	return (ISC_R_SUCCESS);
2238}
2239
2240isc_result_t
2241dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2242	REQUIRE(DNS_MESSAGE_VALID(msg));
2243	REQUIRE(item != NULL && *item == NULL);
2244
2245	*item = isc_mempool_get(msg->rdspool);
2246	if (*item == NULL)
2247		return (ISC_R_NOMEMORY);
2248
2249	dns_rdataset_init(*item);
2250
2251	return (ISC_R_SUCCESS);
2252}
2253
2254isc_result_t
2255dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2256	REQUIRE(DNS_MESSAGE_VALID(msg));
2257	REQUIRE(item != NULL && *item == NULL);
2258
2259	*item = newrdatalist(msg);
2260	if (*item == NULL)
2261		return (ISC_R_NOMEMORY);
2262
2263	return (ISC_R_SUCCESS);
2264}
2265
2266void
2267dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2268	REQUIRE(DNS_MESSAGE_VALID(msg));
2269	REQUIRE(item != NULL && *item != NULL);
2270
2271	if (dns_name_dynamic(*item))
2272		dns_name_free(*item, msg->mctx);
2273	isc_mempool_put(msg->namepool, *item);
2274	*item = NULL;
2275}
2276
2277void
2278dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2279	REQUIRE(DNS_MESSAGE_VALID(msg));
2280	REQUIRE(item != NULL && *item != NULL);
2281
2282	releaserdata(msg, *item);
2283	*item = NULL;
2284}
2285
2286void
2287dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2288	REQUIRE(DNS_MESSAGE_VALID(msg));
2289	REQUIRE(item != NULL && *item != NULL);
2290
2291	REQUIRE(!dns_rdataset_isassociated(*item));
2292	isc_mempool_put(msg->rdspool, *item);
2293	*item = NULL;
2294}
2295
2296void
2297dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2298	REQUIRE(DNS_MESSAGE_VALID(msg));
2299	REQUIRE(item != NULL && *item != NULL);
2300
2301	releaserdatalist(msg, *item);
2302	*item = NULL;
2303}
2304
2305isc_result_t
2306dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2307		       unsigned int *flagsp)
2308{
2309	isc_region_t r;
2310	isc_buffer_t buffer;
2311	dns_messageid_t id;
2312	unsigned int flags;
2313
2314	REQUIRE(source != NULL);
2315
2316	buffer = *source;
2317
2318	isc_buffer_remainingregion(&buffer, &r);
2319	if (r.length < DNS_MESSAGE_HEADERLEN)
2320		return (ISC_R_UNEXPECTEDEND);
2321
2322	id = isc_buffer_getuint16(&buffer);
2323	flags = isc_buffer_getuint16(&buffer);
2324	flags &= DNS_MESSAGE_FLAG_MASK;
2325
2326	if (flagsp != NULL)
2327		*flagsp = flags;
2328	if (idp != NULL)
2329		*idp = id;
2330
2331	return (ISC_R_SUCCESS);
2332}
2333
2334isc_result_t
2335dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
2336	unsigned int first_section;
2337	isc_result_t result;
2338
2339	REQUIRE(DNS_MESSAGE_VALID(msg));
2340	REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2341
2342	if (!msg->header_ok)
2343		return (DNS_R_FORMERR);
2344	if (msg->opcode != dns_opcode_query &&
2345	    msg->opcode != dns_opcode_notify)
2346		want_question_section = ISC_FALSE;
2347	if (want_question_section) {
2348		if (!msg->question_ok)
2349			return (DNS_R_FORMERR);
2350		first_section = DNS_SECTION_ANSWER;
2351	} else
2352		first_section = DNS_SECTION_QUESTION;
2353	msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2354	msgresetnames(msg, first_section);
2355	msgresetopt(msg);
2356	msgresetsigs(msg, ISC_TRUE);
2357	msginitprivate(msg);
2358	/*
2359	 * We now clear most flags and then set QR, ensuring that the
2360	 * reply's flags will be in a reasonable state.
2361	 */
2362	msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2363	msg->flags |= DNS_MESSAGEFLAG_QR;
2364
2365	/*
2366	 * This saves the query TSIG status, if the query was signed, and
2367	 * reserves space in the reply for the TSIG.
2368	 */
2369	if (msg->tsigkey != NULL) {
2370		unsigned int otherlen = 0;
2371		msg->querytsigstatus = msg->tsigstatus;
2372		msg->tsigstatus = dns_rcode_noerror;
2373		if (msg->querytsigstatus == dns_tsigerror_badtime)
2374			otherlen = 6;
2375		msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2376		result = dns_message_renderreserve(msg, msg->sig_reserved);
2377		if (result != ISC_R_SUCCESS) {
2378			msg->sig_reserved = 0;
2379			return (result);
2380		}
2381	}
2382	if (msg->saved.base != NULL) {
2383		msg->query.base = msg->saved.base;
2384		msg->query.length = msg->saved.length;
2385		msg->free_query = msg->free_saved;
2386		msg->saved.base = NULL;
2387		msg->saved.length = 0;
2388		msg->free_saved = 0;
2389	}
2390
2391	return (ISC_R_SUCCESS);
2392}
2393
2394dns_rdataset_t *
2395dns_message_getopt(dns_message_t *msg) {
2396
2397	/*
2398	 * Get the OPT record for 'msg'.
2399	 */
2400
2401	REQUIRE(DNS_MESSAGE_VALID(msg));
2402
2403	return (msg->opt);
2404}
2405
2406isc_result_t
2407dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2408	isc_result_t result;
2409	dns_rdata_t rdata = DNS_RDATA_INIT;
2410
2411	/*
2412	 * Set the OPT record for 'msg'.
2413	 */
2414
2415	/*
2416	 * The space required for an OPT record is:
2417	 *
2418	 *	1 byte for the name
2419	 *	2 bytes for the type
2420	 *	2 bytes for the class
2421	 *	4 bytes for the ttl
2422	 *	2 bytes for the rdata length
2423	 * ---------------------------------
2424	 *     11 bytes
2425	 *
2426	 * plus the length of the rdata.
2427	 */
2428
2429	REQUIRE(DNS_MESSAGE_VALID(msg));
2430	REQUIRE(opt->type == dns_rdatatype_opt);
2431	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2432	REQUIRE(msg->state == DNS_SECTION_ANY);
2433
2434	msgresetopt(msg);
2435
2436	result = dns_rdataset_first(opt);
2437	if (result != ISC_R_SUCCESS)
2438		goto cleanup;
2439	dns_rdataset_current(opt, &rdata);
2440	msg->opt_reserved = 11 + rdata.length;
2441	result = dns_message_renderreserve(msg, msg->opt_reserved);
2442	if (result != ISC_R_SUCCESS) {
2443		msg->opt_reserved = 0;
2444		goto cleanup;
2445	}
2446
2447	msg->opt = opt;
2448
2449	return (ISC_R_SUCCESS);
2450
2451 cleanup:
2452	dns_message_puttemprdataset(msg, &opt);
2453	return (result);
2454
2455}
2456
2457dns_rdataset_t *
2458dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2459
2460	/*
2461	 * Get the TSIG record and owner for 'msg'.
2462	 */
2463
2464	REQUIRE(DNS_MESSAGE_VALID(msg));
2465	REQUIRE(owner == NULL || *owner == NULL);
2466
2467	if (owner != NULL)
2468		*owner = msg->tsigname;
2469	return (msg->tsig);
2470}
2471
2472isc_result_t
2473dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2474	isc_result_t result;
2475
2476	/*
2477	 * Set the TSIG key for 'msg'
2478	 */
2479
2480	REQUIRE(DNS_MESSAGE_VALID(msg));
2481	REQUIRE(msg->state == DNS_SECTION_ANY);
2482
2483	if (key == NULL && msg->tsigkey != NULL) {
2484		if (msg->sig_reserved != 0) {
2485			dns_message_renderrelease(msg, msg->sig_reserved);
2486			msg->sig_reserved = 0;
2487		}
2488		dns_tsigkey_detach(&msg->tsigkey);
2489	}
2490	if (key != NULL) {
2491		REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2492		dns_tsigkey_attach(key, &msg->tsigkey);
2493		if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2494			msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2495			result = dns_message_renderreserve(msg,
2496							   msg->sig_reserved);
2497			if (result != ISC_R_SUCCESS) {
2498				dns_tsigkey_detach(&msg->tsigkey);
2499				msg->sig_reserved = 0;
2500				return (result);
2501			}
2502		}
2503	}
2504	return (ISC_R_SUCCESS);
2505}
2506
2507dns_tsigkey_t *
2508dns_message_gettsigkey(dns_message_t *msg) {
2509
2510	/*
2511	 * Get the TSIG key for 'msg'
2512	 */
2513
2514	REQUIRE(DNS_MESSAGE_VALID(msg));
2515
2516	return (msg->tsigkey);
2517}
2518
2519isc_result_t
2520dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2521	dns_rdata_t *rdata = NULL;
2522	dns_rdatalist_t *list = NULL;
2523	dns_rdataset_t *set = NULL;
2524	isc_buffer_t *buf = NULL;
2525	isc_region_t r;
2526	isc_result_t result;
2527
2528	REQUIRE(DNS_MESSAGE_VALID(msg));
2529	REQUIRE(msg->querytsig == NULL);
2530
2531	if (querytsig == NULL)
2532		return (ISC_R_SUCCESS);
2533
2534	result = dns_message_gettemprdata(msg, &rdata);
2535	if (result != ISC_R_SUCCESS)
2536		goto cleanup;
2537
2538	result = dns_message_gettemprdatalist(msg, &list);
2539	if (result != ISC_R_SUCCESS)
2540		goto cleanup;
2541	result = dns_message_gettemprdataset(msg, &set);
2542	if (result != ISC_R_SUCCESS)
2543		goto cleanup;
2544
2545	isc_buffer_usedregion(querytsig, &r);
2546	result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2547	if (result != ISC_R_SUCCESS)
2548		goto cleanup;
2549	isc_buffer_putmem(buf, r.base, r.length);
2550	isc_buffer_usedregion(buf, &r);
2551	dns_rdata_init(rdata);
2552	dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2553	dns_message_takebuffer(msg, &buf);
2554	ISC_LIST_INIT(list->rdata);
2555	ISC_LIST_APPEND(list->rdata, rdata, link);
2556	result = dns_rdatalist_tordataset(list, set);
2557	if (result != ISC_R_SUCCESS)
2558		goto cleanup;
2559
2560	msg->querytsig = set;
2561
2562	return (result);
2563
2564 cleanup:
2565	if (rdata != NULL)
2566		dns_message_puttemprdata(msg, &rdata);
2567	if (list != NULL)
2568		dns_message_puttemprdatalist(msg, &list);
2569	if (set != NULL)
2570		dns_message_puttemprdataset(msg, &set);
2571	return (ISC_R_NOMEMORY);
2572}
2573
2574isc_result_t
2575dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2576			 isc_buffer_t **querytsig) {
2577	isc_result_t result;
2578	dns_rdata_t rdata = DNS_RDATA_INIT;
2579	isc_region_t r;
2580
2581	REQUIRE(DNS_MESSAGE_VALID(msg));
2582	REQUIRE(mctx != NULL);
2583	REQUIRE(querytsig != NULL && *querytsig == NULL);
2584
2585	if (msg->tsig == NULL)
2586		return (ISC_R_SUCCESS);
2587
2588	result = dns_rdataset_first(msg->tsig);
2589	if (result != ISC_R_SUCCESS)
2590		return (result);
2591	dns_rdataset_current(msg->tsig, &rdata);
2592	dns_rdata_toregion(&rdata, &r);
2593
2594	result = isc_buffer_allocate(mctx, querytsig, r.length);
2595	if (result != ISC_R_SUCCESS)
2596		return (result);
2597	isc_buffer_putmem(*querytsig, r.base, r.length);
2598	return (ISC_R_SUCCESS);
2599}
2600
2601dns_rdataset_t *
2602dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2603
2604	/*
2605	 * Get the SIG(0) record for 'msg'.
2606	 */
2607
2608	REQUIRE(DNS_MESSAGE_VALID(msg));
2609	REQUIRE(owner == NULL || *owner == NULL);
2610
2611	if (msg->sig0 != NULL && owner != NULL) {
2612		/* If dns_message_getsig0 is called on a rendered message
2613		 * after the SIG(0) has been applied, we need to return the
2614		 * root name, not NULL.
2615		 */
2616		if (msg->sig0name == NULL)
2617			*owner = dns_rootname;
2618		else
2619			*owner = msg->sig0name;
2620	}
2621	return (msg->sig0);
2622}
2623
2624isc_result_t
2625dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2626	isc_region_t r;
2627	unsigned int x;
2628	isc_result_t result;
2629
2630	/*
2631	 * Set the SIG(0) key for 'msg'
2632	 */
2633
2634	/*
2635	 * The space required for an SIG(0) record is:
2636	 *
2637	 *	1 byte for the name
2638	 *	2 bytes for the type
2639	 *	2 bytes for the class
2640	 *	4 bytes for the ttl
2641	 *	2 bytes for the type covered
2642	 *	1 byte for the algorithm
2643	 *	1 bytes for the labels
2644	 *	4 bytes for the original ttl
2645	 *	4 bytes for the signature expiration
2646	 *	4 bytes for the signature inception
2647	 *	2 bytes for the key tag
2648	 *	n bytes for the signer's name
2649	 *	x bytes for the signature
2650	 * ---------------------------------
2651	 *     27 + n + x bytes
2652	 */
2653	REQUIRE(DNS_MESSAGE_VALID(msg));
2654	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2655	REQUIRE(msg->state == DNS_SECTION_ANY);
2656
2657	if (key != NULL) {
2658		REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2659		dns_name_toregion(dst_key_name(key), &r);
2660		result = dst_key_sigsize(key, &x);
2661		if (result != ISC_R_SUCCESS) {
2662			msg->sig_reserved = 0;
2663			return (result);
2664		}
2665		msg->sig_reserved = 27 + r.length + x;
2666		result = dns_message_renderreserve(msg, msg->sig_reserved);
2667		if (result != ISC_R_SUCCESS) {
2668			msg->sig_reserved = 0;
2669			return (result);
2670		}
2671		msg->sig0key = key;
2672	}
2673	return (ISC_R_SUCCESS);
2674}
2675
2676dst_key_t *
2677dns_message_getsig0key(dns_message_t *msg) {
2678
2679	/*
2680	 * Get the SIG(0) key for 'msg'
2681	 */
2682
2683	REQUIRE(DNS_MESSAGE_VALID(msg));
2684
2685	return (msg->sig0key);
2686}
2687
2688void
2689dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2690	REQUIRE(DNS_MESSAGE_VALID(msg));
2691	REQUIRE(buffer != NULL);
2692	REQUIRE(ISC_BUFFER_VALID(*buffer));
2693
2694	ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2695	*buffer = NULL;
2696}
2697
2698isc_result_t
2699dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
2700	isc_result_t result = ISC_R_SUCCESS;
2701	dns_rdata_t rdata = DNS_RDATA_INIT;
2702
2703	REQUIRE(DNS_MESSAGE_VALID(msg));
2704	REQUIRE(signer != NULL);
2705	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2706
2707	if (msg->tsig == NULL && msg->sig0 == NULL)
2708		return (ISC_R_NOTFOUND);
2709
2710	if (msg->verify_attempted == 0)
2711		return (DNS_R_NOTVERIFIEDYET);
2712
2713	if (!dns_name_hasbuffer(signer)) {
2714		isc_buffer_t *dynbuf = NULL;
2715		result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
2716		if (result != ISC_R_SUCCESS)
2717			return (result);
2718		dns_name_setbuffer(signer, dynbuf);
2719		dns_message_takebuffer(msg, &dynbuf);
2720	}
2721
2722	if (msg->sig0 != NULL) {
2723		dns_rdata_sig_t sig;
2724
2725		result = dns_rdataset_first(msg->sig0);
2726		INSIST(result == ISC_R_SUCCESS);
2727		dns_rdataset_current(msg->sig0, &rdata);
2728
2729		result = dns_rdata_tostruct(&rdata, &sig, NULL);
2730		if (result != ISC_R_SUCCESS)
2731			return (result);
2732
2733		if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
2734			result = ISC_R_SUCCESS;
2735		else
2736			result = DNS_R_SIGINVALID;
2737		dns_name_clone(&sig.signer, signer);
2738		dns_rdata_freestruct(&sig);
2739	} else {
2740		dns_name_t *identity;
2741		dns_rdata_any_tsig_t tsig;
2742
2743		result = dns_rdataset_first(msg->tsig);
2744		INSIST(result == ISC_R_SUCCESS);
2745		dns_rdataset_current(msg->tsig, &rdata);
2746
2747		result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2748		if (msg->tsigstatus != dns_rcode_noerror)
2749			result = DNS_R_TSIGVERIFYFAILURE;
2750		else if (tsig.error != dns_rcode_noerror)
2751			result = DNS_R_TSIGERRORSET;
2752		else
2753			result = ISC_R_SUCCESS;
2754		dns_rdata_freestruct(&tsig);
2755
2756		if (msg->tsigkey == NULL) {
2757			/*
2758			 * If msg->tsigstatus & tsig.error are both
2759			 * dns_rcode_noerror, the message must have been
2760			 * verified, which means msg->tsigkey will be
2761			 * non-NULL.
2762			 */
2763			INSIST(result != ISC_R_SUCCESS);
2764		} else {
2765			identity = dns_tsigkey_identity(msg->tsigkey);
2766			if (identity == NULL) {
2767				if (result == ISC_R_SUCCESS)
2768					result = DNS_R_NOIDENTITY;
2769				identity = &msg->tsigkey->name;
2770			}
2771			dns_name_clone(identity, signer);
2772		}
2773	}
2774
2775	return (result);
2776}
2777
2778void
2779dns_message_resetsig(dns_message_t *msg) {
2780	REQUIRE(DNS_MESSAGE_VALID(msg));
2781	msg->verified_sig = 0;
2782	msg->verify_attempted = 0;
2783	msg->tsigstatus = dns_rcode_noerror;
2784	msg->sig0status = dns_rcode_noerror;
2785	msg->timeadjust = 0;
2786	if (msg->tsigkey != NULL) {
2787		dns_tsigkey_detach(&msg->tsigkey);
2788		msg->tsigkey = NULL;
2789	}
2790}
2791
2792isc_result_t
2793dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
2794	dns_message_resetsig(msg);
2795	return (dns_message_checksig(msg, view));
2796}
2797
2798isc_result_t
2799dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
2800	isc_buffer_t b, msgb;
2801
2802	REQUIRE(DNS_MESSAGE_VALID(msg));
2803
2804	if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
2805		return (ISC_R_SUCCESS);
2806	INSIST(msg->saved.base != NULL);
2807	isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
2808	isc_buffer_add(&msgb, msg->saved.length);
2809	if (msg->tsigkey != NULL || msg->tsig != NULL) {
2810		if (view != NULL)
2811			return (dns_view_checksig(view, &msgb, msg));
2812		else
2813			return (dns_tsig_verify(&msgb, msg, NULL, NULL));
2814	} else {
2815		dns_rdata_t rdata = DNS_RDATA_INIT;
2816		dns_rdata_sig_t sig;
2817		dns_rdataset_t keyset;
2818		isc_result_t result;
2819
2820		result = dns_rdataset_first(msg->sig0);
2821		INSIST(result == ISC_R_SUCCESS);
2822		dns_rdataset_current(msg->sig0, &rdata);
2823
2824		/*
2825		 * This can occur when the message is a dynamic update, since
2826		 * the rdata length checking is relaxed.  This should not
2827		 * happen in a well-formed message, since the SIG(0) is only
2828		 * looked for in the additional section, and the dynamic update
2829		 * meta-records are in the prerequisite and update sections.
2830		 */
2831		if (rdata.length == 0)
2832			return (ISC_R_UNEXPECTEDEND);
2833
2834		result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
2835		if (result != ISC_R_SUCCESS)
2836			return (result);
2837
2838		dns_rdataset_init(&keyset);
2839		if (view == NULL)
2840			return (DNS_R_KEYUNAUTHORIZED);
2841		result = dns_view_simplefind(view, &sig.signer,
2842					     dns_rdatatype_key /* SIG(0) */,
2843					     0, 0, ISC_FALSE, &keyset, NULL);
2844
2845		if (result != ISC_R_SUCCESS) {
2846			/* XXXBEW Should possibly create a fetch here */
2847			result = DNS_R_KEYUNAUTHORIZED;
2848			goto freesig;
2849		} else if (keyset.trust < dns_trust_secure) {
2850			/* XXXBEW Should call a validator here */
2851			result = DNS_R_KEYUNAUTHORIZED;
2852			goto freesig;
2853		}
2854		result = dns_rdataset_first(&keyset);
2855		INSIST(result == ISC_R_SUCCESS);
2856		for (;
2857		     result == ISC_R_SUCCESS;
2858		     result = dns_rdataset_next(&keyset))
2859		{
2860			dst_key_t *key = NULL;
2861
2862			dns_rdataset_current(&keyset, &rdata);
2863			isc_buffer_init(&b, rdata.data, rdata.length);
2864			isc_buffer_add(&b, rdata.length);
2865
2866			result = dst_key_fromdns(&sig.signer, rdata.rdclass,
2867						 &b, view->mctx, &key);
2868			if (result != ISC_R_SUCCESS)
2869				continue;
2870			if (dst_key_alg(key) != sig.algorithm ||
2871			    dst_key_id(key) != sig.keyid ||
2872			    !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
2873			      dst_key_proto(key) == DNS_KEYPROTO_ANY))
2874			{
2875				dst_key_free(&key);
2876				continue;
2877			}
2878			result = dns_dnssec_verifymessage(&msgb, msg, key);
2879			dst_key_free(&key);
2880			if (result == ISC_R_SUCCESS)
2881				break;
2882		}
2883		if (result == ISC_R_NOMORE)
2884			result = DNS_R_KEYUNAUTHORIZED;
2885
2886 freesig:
2887		if (dns_rdataset_isassociated(&keyset))
2888			dns_rdataset_disassociate(&keyset);
2889		dns_rdata_freestruct(&sig);
2890		return (result);
2891	}
2892}
2893
2894isc_result_t
2895dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
2896			  const dns_master_style_t *style,
2897			  dns_messagetextflag_t flags,
2898			  isc_buffer_t *target) {
2899	dns_name_t *name, empty_name;
2900	dns_rdataset_t *rdataset;
2901	isc_result_t result;
2902
2903	REQUIRE(DNS_MESSAGE_VALID(msg));
2904	REQUIRE(target != NULL);
2905	REQUIRE(VALID_SECTION(section));
2906
2907	if (ISC_LIST_EMPTY(msg->sections[section]))
2908		return (ISC_R_SUCCESS);
2909
2910	if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
2911		ADD_STRING(target, ";; ");
2912		if (msg->opcode != dns_opcode_update) {
2913			ADD_STRING(target, sectiontext[section]);
2914		}
2915		else {
2916			ADD_STRING(target, updsectiontext[section]);
2917		}
2918		ADD_STRING(target, " SECTION:\n");
2919	}
2920
2921	dns_name_init(&empty_name, NULL);
2922	result = dns_message_firstname(msg, section);
2923	if (result != ISC_R_SUCCESS) {
2924		return (result);
2925	}
2926	do {
2927		name = NULL;
2928		dns_message_currentname(msg, section, &name);
2929		for (rdataset = ISC_LIST_HEAD(name->list);
2930		     rdataset != NULL;
2931		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
2932			if (section == DNS_SECTION_QUESTION) {
2933				ADD_STRING(target, ";");
2934				result = dns_master_questiontotext(name,
2935								   rdataset,
2936								   style,
2937								   target);
2938			} else {
2939				result = dns_master_rdatasettotext(name,
2940								   rdataset,
2941								   style,
2942								   target);
2943			}
2944			if (result != ISC_R_SUCCESS)
2945				return (result);
2946		}
2947		result = dns_message_nextname(msg, section);
2948	} while (result == ISC_R_SUCCESS);
2949	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
2950	    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2951		ADD_STRING(target, "\n");
2952	if (result == ISC_R_NOMORE)
2953		result = ISC_R_SUCCESS;
2954	return (result);
2955}
2956
2957isc_result_t
2958dns_message_pseudosectiontotext(dns_message_t *msg,
2959				dns_pseudosection_t section,
2960				const dns_master_style_t *style,
2961				dns_messagetextflag_t flags,
2962				isc_buffer_t *target) {
2963	dns_rdataset_t *ps = NULL;
2964	dns_name_t *name = NULL;
2965	isc_result_t result;
2966	char buf[sizeof("1234567890")];
2967	isc_uint32_t mbz;
2968
2969	REQUIRE(DNS_MESSAGE_VALID(msg));
2970	REQUIRE(target != NULL);
2971	REQUIRE(VALID_PSEUDOSECTION(section));
2972
2973	switch (section) {
2974	case DNS_PSEUDOSECTION_OPT:
2975		ps = dns_message_getopt(msg);
2976		if (ps == NULL)
2977			return (ISC_R_SUCCESS);
2978		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
2979			ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
2980		ADD_STRING(target, "; EDNS: version: ");
2981		snprintf(buf, sizeof(buf), "%u",
2982			 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
2983		ADD_STRING(target, buf);
2984		ADD_STRING(target, ", flags:");
2985		if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
2986			ADD_STRING(target, " do");
2987		mbz = ps->ttl & ~DNS_MESSAGEEXTFLAG_DO & 0xffff;
2988		if (mbz != 0) {
2989			ADD_STRING(target, "; MBZ: ");
2990			snprintf(buf, sizeof(buf), "%.4x ", mbz);
2991			ADD_STRING(target, buf);
2992			ADD_STRING(target, ", udp: ");
2993		} else
2994			ADD_STRING(target, "; udp: ");
2995		snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
2996		ADD_STRING(target, buf);
2997		return (ISC_R_SUCCESS);
2998	case DNS_PSEUDOSECTION_TSIG:
2999		ps = dns_message_gettsig(msg, &name);
3000		if (ps == NULL)
3001			return (ISC_R_SUCCESS);
3002		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3003			ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
3004		result = dns_master_rdatasettotext(name, ps, style, target);
3005		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3006		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3007			ADD_STRING(target, "\n");
3008		return (result);
3009	case DNS_PSEUDOSECTION_SIG0:
3010		ps = dns_message_getsig0(msg, &name);
3011		if (ps == NULL)
3012			return (ISC_R_SUCCESS);
3013		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3014			ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3015		result = dns_master_rdatasettotext(name, ps, style, target);
3016		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3017		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3018			ADD_STRING(target, "\n");
3019		return (result);
3020	}
3021	return (ISC_R_UNEXPECTED);
3022}
3023
3024isc_result_t
3025dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3026		   dns_messagetextflag_t flags, isc_buffer_t *target) {
3027	char buf[sizeof("1234567890")];
3028	isc_result_t result;
3029
3030	REQUIRE(DNS_MESSAGE_VALID(msg));
3031	REQUIRE(target != NULL);
3032
3033	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
3034		ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
3035		ADD_STRING(target, opcodetext[msg->opcode]);
3036		ADD_STRING(target, ", status: ");
3037		ADD_STRING(target, rcodetext[msg->rcode]);
3038		ADD_STRING(target, ", id: ");
3039		snprintf(buf, sizeof(buf), "%6u", msg->id);
3040		ADD_STRING(target, buf);
3041		ADD_STRING(target, "\n;; flags: ");
3042		if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3043			ADD_STRING(target, "qr ");
3044		if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3045			ADD_STRING(target, "aa ");
3046		if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3047			ADD_STRING(target, "tc ");
3048		if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3049			ADD_STRING(target, "rd ");
3050		if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3051			ADD_STRING(target, "ra ");
3052		if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3053			ADD_STRING(target, "ad ");
3054		if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
3055			ADD_STRING(target, "cd ");
3056		if (msg->opcode != dns_opcode_update) {
3057			ADD_STRING(target, "; QUESTION: ");
3058		} else {
3059			ADD_STRING(target, "; ZONE: ");
3060		}
3061		snprintf(buf, sizeof(buf), "%1u",
3062			 msg->counts[DNS_SECTION_QUESTION]);
3063		ADD_STRING(target, buf);
3064		if (msg->opcode != dns_opcode_update) {
3065			ADD_STRING(target, ", ANSWER: ");
3066		} else {
3067			ADD_STRING(target, ", PREREQ: ");
3068		}
3069		snprintf(buf, sizeof(buf), "%1u",
3070			 msg->counts[DNS_SECTION_ANSWER]);
3071		ADD_STRING(target, buf);
3072		if (msg->opcode != dns_opcode_update) {
3073			ADD_STRING(target, ", AUTHORITY: ");
3074		} else {
3075			ADD_STRING(target, ", UPDATE: ");
3076		}
3077		snprintf(buf, sizeof(buf), "%1u",
3078			msg->counts[DNS_SECTION_AUTHORITY]);
3079		ADD_STRING(target, buf);
3080		ADD_STRING(target, ", ADDITIONAL: ");
3081		snprintf(buf, sizeof(buf), "%1u",
3082			msg->counts[DNS_SECTION_ADDITIONAL]);
3083		ADD_STRING(target, buf);
3084		ADD_STRING(target, "\n");
3085	}
3086	result = dns_message_pseudosectiontotext(msg,
3087						 DNS_PSEUDOSECTION_OPT,
3088						 style, flags, target);
3089	if (result != ISC_R_SUCCESS)
3090		return (result);
3091
3092	result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
3093					   style, flags, target);
3094	if (result != ISC_R_SUCCESS)
3095		return (result);
3096	result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
3097					   style, flags, target);
3098	if (result != ISC_R_SUCCESS)
3099		return (result);
3100	result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
3101					   style, flags, target);
3102	if (result != ISC_R_SUCCESS)
3103		return (result);
3104	result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
3105					   style, flags, target);
3106	if (result != ISC_R_SUCCESS)
3107		return (result);
3108
3109	result = dns_message_pseudosectiontotext(msg,
3110						 DNS_PSEUDOSECTION_TSIG,
3111						 style, flags, target);
3112	if (result != ISC_R_SUCCESS)
3113		return (result);
3114
3115	result = dns_message_pseudosectiontotext(msg,
3116						 DNS_PSEUDOSECTION_SIG0,
3117						 style, flags, target);
3118	if (result != ISC_R_SUCCESS)
3119		return (result);
3120
3121	return (ISC_R_SUCCESS);
3122}
3123
3124isc_region_t *
3125dns_message_getrawmessage(dns_message_t *msg) {
3126	REQUIRE(DNS_MESSAGE_VALID(msg));
3127	return (&msg->saved);
3128}
3129
3130void
3131dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3132			 void *order_arg)
3133{
3134	REQUIRE(DNS_MESSAGE_VALID(msg));
3135	msg->order = order;
3136	msg->order_arg = order_arg;
3137}
3138
3139void
3140dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3141	REQUIRE(DNS_MESSAGE_VALID(msg));
3142	msg->timeadjust = timeadjust;
3143}
3144
3145int
3146dns_message_gettimeadjust(dns_message_t *msg) {
3147	REQUIRE(DNS_MESSAGE_VALID(msg));
3148	return (msg->timeadjust);
3149}
3150
3151isc_result_t
3152dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3153
3154	REQUIRE(opcode < 16);
3155
3156	if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
3157		return (ISC_R_NOSPACE);
3158	isc_buffer_putstr(target, opcodetext[opcode]);
3159	return (ISC_R_SUCCESS);
3160}
3161