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