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