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