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