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