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