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