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