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