message.c revision 224092
165285Siwasaki/*
265285Siwasaki * Copyright (C) 2004-2011  Internet Systems Consortium, Inc. ("ISC")
365285Siwasaki * Copyright (C) 1999-2003  Internet Software Consortium.
465285Siwasaki *
565285Siwasaki * Permission to use, copy, modify, and/or distribute this software for any
665285Siwasaki * purpose with or without fee is hereby granted, provided that the above
765285Siwasaki * copyright notice and this permission notice appear in all copies.
865285Siwasaki *
965285Siwasaki * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
1065285Siwasaki * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1165285Siwasaki * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
1265285Siwasaki * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1365285Siwasaki * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
1465285Siwasaki * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1565285Siwasaki * PERFORMANCE OF THIS SOFTWARE.
1665285Siwasaki */
1765285Siwasaki
1865285Siwasaki/* $Id: message.c,v 1.254.186.3 2011-06-21 20:15:47 each Exp $ */
1965285Siwasaki
2065285Siwasaki/*! \file */
2165285Siwasaki
2265285Siwasaki/***
2365285Siwasaki *** Imports
2465285Siwasaki ***/
2565285Siwasaki
2665285Siwasaki#include <config.h>
2765285Siwasaki#include <ctype.h>
2865285Siwasaki
2965285Siwasaki#include <isc/buffer.h>
30119515Snjl#include <isc/mem.h>
3165285Siwasaki#include <isc/print.h>
3265285Siwasaki#include <isc/string.h>		/* Required for HP/UX (and others?) */
33119515Snjl#include <isc/util.h>
3465285Siwasaki
3565285Siwasaki#include <dns/dnssec.h>
3665285Siwasaki#include <dns/keyvalues.h>
3765285Siwasaki#include <dns/log.h>
38119515Snjl#include <dns/masterdump.h>
3965285Siwasaki#include <dns/message.h>
4065285Siwasaki#include <dns/opcode.h>
4165285Siwasaki#include <dns/rdata.h>
4265285Siwasaki#include <dns/rdatalist.h>
4385323Siwasaki#include <dns/rdataset.h>
4485323Siwasaki#include <dns/rdatastruct.h>
4585323Siwasaki#include <dns/result.h>
46119515Snjl#include <dns/tsig.h>
47119912Snjl#include <dns/view.h>
48119912Snjl
49119515Snjl#ifdef SKAN_MSG_DEBUG
50119515Snjlstatic void
51119515Snjlhexdump(const char *msg, const char *msg2, void *base, size_t len) {
52119515Snjl	unsigned char *p;
53119515Snjl	unsigned int cnt;
54119515Snjl
55119515Snjl	p = base;
56119515Snjl	cnt = 0;
57119515Snjl
58119515Snjl	printf("*** %s [%s] (%u bytes @ %p)\n", msg, msg2, len, base);
59119515Snjl
60119912Snjl	while (cnt < len) {
61119912Snjl		if (cnt % 16 == 0)
62119515Snjl			printf("%p: ", p);
63119515Snjl		else if (cnt % 8 == 0)
64119515Snjl			printf(" |");
65119515Snjl		printf(" %02x %c", *p, (isprint(*p) ? *p : ' '));
66119515Snjl		p++;
6785323Siwasaki		cnt++;
6865285Siwasaki
6965285Siwasaki		if (cnt % 16 == 0)
7065285Siwasaki			printf("\n");
7165285Siwasaki	}
7265285Siwasaki
7365285Siwasaki	if (cnt % 16 != 0)
7465285Siwasaki		printf("\n");
7565285Siwasaki}
7665285Siwasaki#endif
7765285Siwasaki
7865285Siwasaki#define DNS_MESSAGE_OPCODE_MASK		0x7800U
7965285Siwasaki#define DNS_MESSAGE_OPCODE_SHIFT	11
8065285Siwasaki#define DNS_MESSAGE_RCODE_MASK		0x000fU
8165285Siwasaki#define DNS_MESSAGE_FLAG_MASK		0x8ff0U
8265285Siwasaki#define DNS_MESSAGE_EDNSRCODE_MASK	0xff000000U
8365285Siwasaki#define DNS_MESSAGE_EDNSRCODE_SHIFT	24
84119912Snjl#define DNS_MESSAGE_EDNSVERSION_MASK	0x00ff0000U
8565285Siwasaki#define DNS_MESSAGE_EDNSVERSION_SHIFT	16
86119912Snjl
87119912Snjl#define VALID_NAMED_SECTION(s)  (((s) > DNS_SECTION_ANY) \
88119912Snjl				 && ((s) < DNS_SECTION_MAX))
89119912Snjl#define VALID_SECTION(s)	(((s) >= DNS_SECTION_ANY) \
90119912Snjl				 && ((s) < DNS_SECTION_MAX))
91119912Snjl#define ADD_STRING(b, s)	{if (strlen(s) >= \
92119912Snjl				   isc_buffer_availablelength(b)) \
93119912Snjl				       return(ISC_R_NOSPACE); else \
94119912Snjl				       isc_buffer_putstr(b, s);}
95119912Snjl#define VALID_PSEUDOSECTION(s)	(((s) >= DNS_PSEUDOSECTION_ANY) \
96119912Snjl				 && ((s) < DNS_PSEUDOSECTION_MAX))
97119912Snjl
98119912Snjl#define OPTOUT(x) (((x)->attributes & DNS_RDATASETATTR_OPTOUT) != 0)
99119912Snjl
100119912Snjl/*%
101119912Snjl * This is the size of each individual scratchpad buffer, and the numbers
102119912Snjl * of various block allocations used within the server.
103119912Snjl * XXXMLG These should come from a config setting.
104119912Snjl */
105119912Snjl#define SCRATCHPAD_SIZE		512
106119912Snjl#define NAME_COUNT		  8
107119912Snjl#define OFFSET_COUNT		  4
108119912Snjl#define RDATA_COUNT		  8
109119912Snjl#define RDATALIST_COUNT		  8
110119912Snjl#define RDATASET_COUNT		 RDATALIST_COUNT
111119912Snjl
112119912Snjl/*%
113119912Snjl * Text representation of the different items, for message_totext
114119912Snjl * functions.
11565285Siwasaki */
116119912Snjlstatic const char *sectiontext[] = {
117119912Snjl	"QUESTION",
118119912Snjl	"ANSWER",
119119912Snjl	"AUTHORITY",
120119912Snjl	"ADDITIONAL"
121119912Snjl};
122119912Snjl
123119912Snjlstatic const char *updsectiontext[] = {
124119912Snjl	"ZONE",
125119912Snjl	"PREREQUISITE",
126119912Snjl	"UPDATE",
127119912Snjl	"ADDITIONAL"
128119912Snjl};
129119912Snjl
13065285Siwasakistatic const char *opcodetext[] = {
131119515Snjl	"QUERY",
132119515Snjl	"IQUERY",
13365285Siwasaki	"STATUS",
13465285Siwasaki	"RESERVED3",
13585323Siwasaki	"NOTIFY",
136108967Sjhb	"UPDATE",
137108967Sjhb	"RESERVED6",
138108967Sjhb	"RESERVED7",
139108967Sjhb	"RESERVED8",
140108967Sjhb	"RESERVED9",
141108967Sjhb	"RESERVED10",
142108967Sjhb	"RESERVED11",
143108967Sjhb	"RESERVED12",
144108967Sjhb	"RESERVED13",
145108967Sjhb	"RESERVED14",
146108967Sjhb	"RESERVED15"
147108967Sjhb};
148108967Sjhb
149108967Sjhbstatic const char *rcodetext[] = {
150108967Sjhb	"NOERROR",
151108967Sjhb	"FORMERR",
152108967Sjhb	"SERVFAIL",
153108967Sjhb	"NXDOMAIN",
154108967Sjhb	"NOTIMP",
155108967Sjhb	"REFUSED",
156108967Sjhb	"YXDOMAIN",
157108967Sjhb	"YXRRSET",
158108967Sjhb	"NXRRSET",
159108967Sjhb	"NOTAUTH",
160108967Sjhb	"NOTZONE",
161108967Sjhb	"RESERVED11",
162108967Sjhb	"RESERVED12",
163108967Sjhb	"RESERVED13",
164119515Snjl	"RESERVED14",
165108967Sjhb	"RESERVED15",
166108967Sjhb	"BADVERS"
167108967Sjhb};
168108967Sjhb
169108967Sjhb
170108967Sjhb/*%
171108967Sjhb * "helper" type, which consists of a block of some type, and is linkable.
172108967Sjhb * For it to work, sizeof(dns_msgblock_t) must be a multiple of the pointer
173108967Sjhb * size, or the allocated elements will not be aligned correctly.
174108967Sjhb */
175108967Sjhbstruct dns_msgblock {
176108967Sjhb	unsigned int			count;
177108967Sjhb	unsigned int			remaining;
178108967Sjhb	ISC_LINK(dns_msgblock_t)	link;
179108967Sjhb}; /* dynamically sized */
180108967Sjhb
181108967Sjhbstatic inline dns_msgblock_t *
182108967Sjhbmsgblock_allocate(isc_mem_t *, unsigned int, unsigned int);
183108967Sjhb
184108967Sjhb#define msgblock_get(block, type) \
185108967Sjhb	((type *)msgblock_internalget(block, sizeof(type)))
186108967Sjhb
187108967Sjhbstatic inline void *
188108967Sjhbmsgblock_internalget(dns_msgblock_t *, unsigned int);
189108967Sjhb
190108967Sjhbstatic inline void
191108967Sjhbmsgblock_reset(dns_msgblock_t *);
192108967Sjhb
193108967Sjhbstatic inline void
194108967Sjhbmsgblock_free(isc_mem_t *, dns_msgblock_t *, unsigned int);
195108967Sjhb
196108967Sjhb/*
197108967Sjhb * Allocate a new dns_msgblock_t, and return a pointer to it.  If no memory
198108967Sjhb * is free, return NULL.
199108967Sjhb */
200108967Sjhbstatic inline dns_msgblock_t *
201108967Sjhbmsgblock_allocate(isc_mem_t *mctx, unsigned int sizeof_type,
202108967Sjhb		  unsigned int count)
203108967Sjhb{
204108967Sjhb	dns_msgblock_t *block;
205108967Sjhb	unsigned int length;
206108967Sjhb
207108967Sjhb	length = sizeof(dns_msgblock_t) + (sizeof_type * count);
208108967Sjhb
209108967Sjhb	block = isc_mem_get(mctx, length);
210108967Sjhb	if (block == NULL)
211108967Sjhb		return (NULL);
212108967Sjhb
213108967Sjhb	block->count = count;
214108967Sjhb	block->remaining = count;
215108967Sjhb
216108967Sjhb	ISC_LINK_INIT(block, link);
217108967Sjhb
218108967Sjhb	return (block);
219108967Sjhb}
220108967Sjhb
221108967Sjhb/*
222108967Sjhb * Return an element from the msgblock.  If no more are available, return
223108967Sjhb * NULL.
224108967Sjhb */
225108967Sjhbstatic inline void *
226108967Sjhbmsgblock_internalget(dns_msgblock_t *block, unsigned int sizeof_type) {
227108967Sjhb	void *ptr;
228108967Sjhb
229108967Sjhb	if (block == NULL || block->remaining == 0)
230108967Sjhb		return (NULL);
231108967Sjhb
232108967Sjhb	block->remaining--;
233108967Sjhb
234108967Sjhb	ptr = (((unsigned char *)block)
235108967Sjhb	       + sizeof(dns_msgblock_t)
236108967Sjhb	       + (sizeof_type * block->remaining));
237108967Sjhb
238108967Sjhb	return (ptr);
239108967Sjhb}
240108967Sjhb
241108967Sjhbstatic inline void
242108967Sjhbmsgblock_reset(dns_msgblock_t *block) {
243108967Sjhb	block->remaining = block->count;
244108967Sjhb}
245108967Sjhb
246108967Sjhb/*
247119515Snjl * Release memory associated with a message block.
248119515Snjl */
249108967Sjhbstatic inline void
250108967Sjhbmsgblock_free(isc_mem_t *mctx, dns_msgblock_t *block, unsigned int sizeof_type)
251108967Sjhb{
252108967Sjhb	unsigned int length;
253108967Sjhb
254108967Sjhb	length = sizeof(dns_msgblock_t) + (sizeof_type * block->count);
255108967Sjhb
256108967Sjhb	isc_mem_put(mctx, block, length);
257108967Sjhb}
258108967Sjhb
259108967Sjhb/*
260108967Sjhb * Allocate a new dynamic buffer, and attach it to this message as the
261108967Sjhb * "current" buffer.  (which is always the last on the list, for our
262108967Sjhb * uses)
263108967Sjhb */
264108967Sjhbstatic inline isc_result_t
265108967Sjhbnewbuffer(dns_message_t *msg, unsigned int size) {
266108967Sjhb	isc_result_t result;
267108967Sjhb	isc_buffer_t *dynbuf;
268108967Sjhb
269108967Sjhb	dynbuf = NULL;
270108967Sjhb	result = isc_buffer_allocate(msg->mctx, &dynbuf, size);
271108967Sjhb	if (result != ISC_R_SUCCESS)
272119515Snjl		return (ISC_R_NOMEMORY);
273108967Sjhb
274108967Sjhb	ISC_LIST_APPEND(msg->scratchpad, dynbuf, link);
275108967Sjhb	return (ISC_R_SUCCESS);
276108967Sjhb}
277108967Sjhb
278108967Sjhbstatic inline isc_buffer_t *
279108967Sjhbcurrentbuffer(dns_message_t *msg) {
280108967Sjhb	isc_buffer_t *dynbuf;
281108967Sjhb
282119515Snjl	dynbuf = ISC_LIST_TAIL(msg->scratchpad);
283108967Sjhb	INSIST(dynbuf != NULL);
284108967Sjhb
285108967Sjhb	return (dynbuf);
286108967Sjhb}
287108967Sjhb
288108967Sjhbstatic inline void
289119515Snjlreleaserdata(dns_message_t *msg, dns_rdata_t *rdata) {
290108967Sjhb	ISC_LIST_PREPEND(msg->freerdata, rdata, link);
291108967Sjhb}
292108967Sjhb
293108967Sjhbstatic inline dns_rdata_t *
294108967Sjhbnewrdata(dns_message_t *msg) {
295108967Sjhb	dns_msgblock_t *msgblock;
296108967Sjhb	dns_rdata_t *rdata;
297108967Sjhb
298108967Sjhb	rdata = ISC_LIST_HEAD(msg->freerdata);
299108967Sjhb	if (rdata != NULL) {
300118334Speter		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
301118334Speter		return (rdata);
302118334Speter	}
303118334Speter
304119515Snjl	msgblock = ISC_LIST_TAIL(msg->rdatas);
305118334Speter	rdata = msgblock_get(msgblock, dns_rdata_t);
306118334Speter	if (rdata == NULL) {
307118334Speter		msgblock = msgblock_allocate(msg->mctx, sizeof(dns_rdata_t),
308118334Speter					     RDATA_COUNT);
309118334Speter		if (msgblock == NULL)
310118334Speter			return (NULL);
311118334Speter
312118334Speter		ISC_LIST_APPEND(msg->rdatas, msgblock, link);
313118334Speter
314118334Speter		rdata = msgblock_get(msgblock, dns_rdata_t);
315118334Speter	}
316118334Speter
317118335Speter	dns_rdata_init(rdata);
318118334Speter	return (rdata);
319118334Speter}
320118334Speter
321118334Speterstatic inline void
322119515Snjlreleaserdatalist(dns_message_t *msg, dns_rdatalist_t *rdatalist) {
32385323Siwasaki	ISC_LIST_PREPEND(msg->freerdatalist, rdatalist, link);
324119515Snjl}
32565285Siwasaki
32685323Siwasakistatic inline dns_rdatalist_t *
32765285Siwasakinewrdatalist(dns_message_t *msg) {
32865285Siwasaki	dns_msgblock_t *msgblock;
32965285Siwasaki	dns_rdatalist_t *rdatalist;
33065285Siwasaki
33165285Siwasaki	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
33265285Siwasaki	if (rdatalist != NULL) {
33365285Siwasaki		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
33465285Siwasaki		return (rdatalist);
33565285Siwasaki	}
336119515Snjl
337119515Snjl	msgblock = ISC_LIST_TAIL(msg->rdatalists);
33865285Siwasaki	rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
33965285Siwasaki	if (rdatalist == NULL) {
340119515Snjl		msgblock = msgblock_allocate(msg->mctx,
34165285Siwasaki					     sizeof(dns_rdatalist_t),
34265285Siwasaki					     RDATALIST_COUNT);
34365285Siwasaki		if (msgblock == NULL)
34465285Siwasaki			return (NULL);
345119515Snjl
34665285Siwasaki		ISC_LIST_APPEND(msg->rdatalists, msgblock, link);
34765285Siwasaki
34865285Siwasaki		rdatalist = msgblock_get(msgblock, dns_rdatalist_t);
34965285Siwasaki	}
35065285Siwasaki
35165285Siwasaki	return (rdatalist);
35265285Siwasaki}
35365285Siwasaki
35485323Siwasakistatic inline dns_offsets_t *
35565285Siwasakinewoffsets(dns_message_t *msg) {
35665285Siwasaki	dns_msgblock_t *msgblock;
357119912Snjl	dns_offsets_t *offsets;
358119912Snjl
359119912Snjl	msgblock = ISC_LIST_TAIL(msg->offsets);
360119912Snjl	offsets = msgblock_get(msgblock, dns_offsets_t);
361119912Snjl	if (offsets == NULL) {
362119515Snjl		msgblock = msgblock_allocate(msg->mctx,
363119912Snjl					     sizeof(dns_offsets_t),
36465285Siwasaki					     OFFSET_COUNT);
365119912Snjl		if (msgblock == NULL)
366119912Snjl			return (NULL);
36765285Siwasaki
36885323Siwasaki		ISC_LIST_APPEND(msg->offsets, msgblock, link);
369119912Snjl
370119912Snjl		offsets = msgblock_get(msgblock, dns_offsets_t);
371119912Snjl	}
372119912Snjl
373119912Snjl	return (offsets);
374119912Snjl}
375119912Snjl
376119912Snjlstatic inline void
377119912Snjlmsginitheader(dns_message_t *m) {
378119912Snjl	m->id = 0;
379119912Snjl	m->flags = 0;
380119912Snjl	m->rcode = 0;
381119912Snjl	m->opcode = 0;
382119912Snjl	m->rdclass = 0;
383119912Snjl}
38465285Siwasaki
385119912Snjlstatic inline void
386119912Snjlmsginitprivate(dns_message_t *m) {
387119912Snjl	unsigned int i;
38865285Siwasaki
389119912Snjl	for (i = 0; i < DNS_SECTION_MAX; i++) {
390119912Snjl		m->cursors[i] = NULL;
391119912Snjl		m->counts[i] = 0;
39265285Siwasaki	}
393119912Snjl	m->opt = NULL;
394119912Snjl	m->sig0 = NULL;
395119912Snjl	m->sig0name = NULL;
39665285Siwasaki	m->tsig = NULL;
397119912Snjl	m->tsigname = NULL;
398119912Snjl	m->state = DNS_SECTION_ANY;  /* indicate nothing parsed or rendered */
399119912Snjl	m->opt_reserved = 0;
40065285Siwasaki	m->sig_reserved = 0;
401119912Snjl	m->reserved = 0;
402119912Snjl	m->buffer = NULL;
403119912Snjl}
40465285Siwasaki
405119912Snjlstatic inline void
406119912Snjlmsginittsig(dns_message_t *m) {
407119912Snjl	m->tsigstatus = dns_rcode_noerror;
408119912Snjl	m->querytsigstatus = dns_rcode_noerror;
409119912Snjl	m->tsigkey = NULL;
410119912Snjl	m->tsigctx = NULL;
411119912Snjl	m->sigstart = -1;
412119912Snjl	m->sig0key = NULL;
413119912Snjl	m->sig0status = dns_rcode_noerror;
414119912Snjl	m->timeadjust = 0;
415119912Snjl}
416119912Snjl
417119912Snjl/*
41865285Siwasaki * Init elements to default state.  Used both when allocating a new element
419119912Snjl * and when resetting one.
42065285Siwasaki */
421119912Snjlstatic inline void
42265285Siwasakimsginit(dns_message_t *m) {
423119912Snjl	msginitheader(m);
42465285Siwasaki	msginitprivate(m);
425119912Snjl	msginittsig(m);
42665285Siwasaki	m->header_ok = 0;
427119912Snjl	m->question_ok = 0;
428119912Snjl	m->tcp_continuation = 0;
429119912Snjl	m->verified_sig = 0;
430119912Snjl	m->verify_attempted = 0;
43165285Siwasaki	m->order = NULL;
43265285Siwasaki	m->order_arg = NULL;
433119912Snjl	m->query.base = NULL;
434119912Snjl	m->query.length = 0;
435119912Snjl	m->free_query = 0;
436119912Snjl	m->saved.base = NULL;
437119912Snjl	m->saved.length = 0;
43865285Siwasaki	m->free_saved = 0;
439119912Snjl	m->querytsig = NULL;
440119912Snjl}
441119912Snjl
442119912Snjlstatic inline void
443119912Snjlmsgresetnames(dns_message_t *msg, unsigned int first_section) {
444119912Snjl	unsigned int i;
445119912Snjl	dns_name_t *name, *next_name;
446119912Snjl	dns_rdataset_t *rds, *next_rds;
447119912Snjl
448119912Snjl	/*
449119912Snjl	 * Clean up name lists by calling the rdataset disassociate function.
450119912Snjl	 */
451119912Snjl	for (i = first_section; i < DNS_SECTION_MAX; i++) {
452119912Snjl		name = ISC_LIST_HEAD(msg->sections[i]);
453119912Snjl		while (name != NULL) {
454119912Snjl			next_name = ISC_LIST_NEXT(name, link);
455119912Snjl			ISC_LIST_UNLINK(msg->sections[i], name, link);
456119912Snjl
45765285Siwasaki			rds = ISC_LIST_HEAD(name->list);
45865285Siwasaki			while (rds != NULL) {
459119912Snjl				next_rds = ISC_LIST_NEXT(rds, link);
460119912Snjl				ISC_LIST_UNLINK(name->list, rds, link);
461119912Snjl
462119912Snjl				INSIST(dns_rdataset_isassociated(rds));
463119912Snjl				dns_rdataset_disassociate(rds);
464119912Snjl				isc_mempool_put(msg->rdspool, rds);
465119912Snjl				rds = next_rds;
466119912Snjl			}
467119912Snjl			if (dns_name_dynamic(name))
468119912Snjl				dns_name_free(name, msg->mctx);
469119912Snjl			isc_mempool_put(msg->namepool, name);
470119912Snjl			name = next_name;
471119912Snjl		}
472119912Snjl	}
473119912Snjl}
474119912Snjl
475119912Snjlstatic void
476119912Snjlmsgresetopt(dns_message_t *msg)
477119912Snjl{
478119912Snjl	if (msg->opt != NULL) {
479119912Snjl		if (msg->opt_reserved > 0) {
480119912Snjl			dns_message_renderrelease(msg, msg->opt_reserved);
481119912Snjl			msg->opt_reserved = 0;
482119912Snjl		}
48365285Siwasaki		INSIST(dns_rdataset_isassociated(msg->opt));
484119912Snjl		dns_rdataset_disassociate(msg->opt);
485119912Snjl		isc_mempool_put(msg->rdspool, msg->opt);
486119912Snjl		msg->opt = NULL;
487119912Snjl	}
488119912Snjl}
489119912Snjl
490119912Snjlstatic void
491119912Snjlmsgresetsigs(dns_message_t *msg, isc_boolean_t replying) {
492119912Snjl	if (msg->sig_reserved > 0) {
493119912Snjl		dns_message_renderrelease(msg, msg->sig_reserved);
494119912Snjl		msg->sig_reserved = 0;
49585323Siwasaki	}
49665285Siwasaki	if (msg->tsig != NULL) {
49765285Siwasaki		INSIST(dns_rdataset_isassociated(msg->tsig));
498119515Snjl		INSIST(msg->namepool != NULL);
49965285Siwasaki		if (replying) {
50065285Siwasaki			INSIST(msg->querytsig == NULL);
501119515Snjl			msg->querytsig = msg->tsig;
50265285Siwasaki		} else {
50365285Siwasaki			dns_rdataset_disassociate(msg->tsig);
50465285Siwasaki			isc_mempool_put(msg->rdspool, msg->tsig);
50565285Siwasaki			if (msg->querytsig != NULL) {
50665285Siwasaki				dns_rdataset_disassociate(msg->querytsig);
50765285Siwasaki				isc_mempool_put(msg->rdspool, msg->querytsig);
50865285Siwasaki			}
50965285Siwasaki		}
51065285Siwasaki		if (dns_name_dynamic(msg->tsigname))
51165285Siwasaki			dns_name_free(msg->tsigname, msg->mctx);
51265285Siwasaki		isc_mempool_put(msg->namepool, msg->tsigname);
51365285Siwasaki		msg->tsig = NULL;
51465285Siwasaki		msg->tsigname = NULL;
51565285Siwasaki	} else if (msg->querytsig != NULL && !replying) {
51665285Siwasaki		dns_rdataset_disassociate(msg->querytsig);
51765285Siwasaki		isc_mempool_put(msg->rdspool, msg->querytsig);
518119515Snjl		msg->querytsig = NULL;
51965285Siwasaki	}
52065285Siwasaki	if (msg->sig0 != NULL) {
52165285Siwasaki		INSIST(dns_rdataset_isassociated(msg->sig0));
52265285Siwasaki		dns_rdataset_disassociate(msg->sig0);
52365285Siwasaki		isc_mempool_put(msg->rdspool, msg->sig0);
52465285Siwasaki		if (msg->sig0name != NULL) {
52565285Siwasaki			if (dns_name_dynamic(msg->sig0name))
52665285Siwasaki				dns_name_free(msg->sig0name, msg->mctx);
52765285Siwasaki			isc_mempool_put(msg->namepool, msg->sig0name);
528119515Snjl		}
52965285Siwasaki		msg->sig0 = NULL;
53065285Siwasaki		msg->sig0name = NULL;
53165285Siwasaki	}
53285323Siwasaki}
533119515Snjl
53465285Siwasaki/*
535108082Smarcel * Free all but one (or everything) for this message.  This is used by
53685323Siwasaki * both dns_message_reset() and dns_message_destroy().
53765285Siwasaki */
53865285Siwasakistatic void
539119515Snjlmsgreset(dns_message_t *msg, isc_boolean_t everything) {
54065285Siwasaki	dns_msgblock_t *msgblock, *next_msgblock;
54165285Siwasaki	isc_buffer_t *dynbuf, *next_dynbuf;
54265285Siwasaki	dns_rdata_t *rdata;
54365285Siwasaki	dns_rdatalist_t *rdatalist;
54465285Siwasaki
54565285Siwasaki	msgresetnames(msg, 0);
54665285Siwasaki	msgresetopt(msg);
54765285Siwasaki	msgresetsigs(msg, ISC_FALSE);
54865285Siwasaki
549119515Snjl	/*
55065285Siwasaki	 * Clean up linked lists.
551119515Snjl	 */
552119515Snjl
553119912Snjl	/*
554119515Snjl	 * Run through the free lists, and just unlink anything found there.
555108967Sjhb	 * The memory isn't lost since these are part of message blocks we
556119515Snjl	 * have allocated.
557118334Speter	 */
558119515Snjl	rdata = ISC_LIST_HEAD(msg->freerdata);
559119515Snjl	while (rdata != NULL) {
56065285Siwasaki		ISC_LIST_UNLINK(msg->freerdata, rdata, link);
56165285Siwasaki		rdata = ISC_LIST_HEAD(msg->freerdata);
56285323Siwasaki	}
563119515Snjl	rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
564119515Snjl	while (rdatalist != NULL) {
56585323Siwasaki		ISC_LIST_UNLINK(msg->freerdatalist, rdatalist, link);
566119515Snjl		rdatalist = ISC_LIST_HEAD(msg->freerdatalist);
567119515Snjl	}
56885323Siwasaki
569119515Snjl	dynbuf = ISC_LIST_HEAD(msg->scratchpad);
570119515Snjl	INSIST(dynbuf != NULL);
571119515Snjl	if (!everything) {
572119515Snjl		isc_buffer_clear(dynbuf);
573119515Snjl		dynbuf = ISC_LIST_NEXT(dynbuf, link);
574119515Snjl	}
575119515Snjl	while (dynbuf != NULL) {
576119515Snjl		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
577119515Snjl		ISC_LIST_UNLINK(msg->scratchpad, dynbuf, link);
578119515Snjl		isc_buffer_free(&dynbuf);
579119515Snjl		dynbuf = next_dynbuf;
580119515Snjl	}
58185323Siwasaki
58285323Siwasaki	msgblock = ISC_LIST_HEAD(msg->rdatas);
583119515Snjl	if (!everything && msgblock != NULL) {
584119515Snjl		msgblock_reset(msgblock);
58585323Siwasaki		msgblock = ISC_LIST_NEXT(msgblock, link);
586119515Snjl	}
587119515Snjl	while (msgblock != NULL) {
58885323Siwasaki		next_msgblock = ISC_LIST_NEXT(msgblock, link);
589119515Snjl		ISC_LIST_UNLINK(msg->rdatas, msgblock, link);
590119515Snjl		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdata_t));
591119515Snjl		msgblock = next_msgblock;
592119515Snjl	}
593119515Snjl
594119515Snjl	/*
595119515Snjl	 * rdatalists could be empty.
596119515Snjl	 */
597119515Snjl
598119515Snjl	msgblock = ISC_LIST_HEAD(msg->rdatalists);
59985323Siwasaki	if (!everything && msgblock != NULL) {
60085323Siwasaki		msgblock_reset(msgblock);
601119515Snjl		msgblock = ISC_LIST_NEXT(msgblock, link);
602119515Snjl	}
60385323Siwasaki	while (msgblock != NULL) {
604119515Snjl		next_msgblock = ISC_LIST_NEXT(msgblock, link);
605119515Snjl		ISC_LIST_UNLINK(msg->rdatalists, msgblock, link);
606119515Snjl		msgblock_free(msg->mctx, msgblock, sizeof(dns_rdatalist_t));
60785323Siwasaki		msgblock = next_msgblock;
608119515Snjl	}
609119515Snjl
610119515Snjl	msgblock = ISC_LIST_HEAD(msg->offsets);
611119515Snjl	if (!everything && msgblock != NULL) {
612119515Snjl		msgblock_reset(msgblock);
613119515Snjl		msgblock = ISC_LIST_NEXT(msgblock, link);
614119515Snjl	}
615119515Snjl	while (msgblock != NULL) {
616119515Snjl		next_msgblock = ISC_LIST_NEXT(msgblock, link);
617119515Snjl		ISC_LIST_UNLINK(msg->offsets, msgblock, link);
618119515Snjl		msgblock_free(msg->mctx, msgblock, sizeof(dns_offsets_t));
619119515Snjl		msgblock = next_msgblock;
620119515Snjl	}
621119515Snjl
622119515Snjl	if (msg->tsigkey != NULL) {
623119515Snjl		dns_tsigkey_detach(&msg->tsigkey);
624119515Snjl		msg->tsigkey = NULL;
625119515Snjl	}
626119515Snjl
627119515Snjl	if (msg->tsigctx != NULL)
628119515Snjl		dst_context_destroy(&msg->tsigctx);
629119515Snjl
630119515Snjl	if (msg->query.base != NULL) {
631119515Snjl		if (msg->free_query != 0)
632119515Snjl			isc_mem_put(msg->mctx, msg->query.base,
633119515Snjl				    msg->query.length);
634119515Snjl		msg->query.base = NULL;
635119515Snjl		msg->query.length = 0;
636119515Snjl	}
637119515Snjl
638119515Snjl	if (msg->saved.base != NULL) {
639119515Snjl		if (msg->free_saved != 0)
640119515Snjl			isc_mem_put(msg->mctx, msg->saved.base,
641119515Snjl				    msg->saved.length);
64285323Siwasaki		msg->saved.base = NULL;
64385323Siwasaki		msg->saved.length = 0;
644119515Snjl	}
645119515Snjl
64685323Siwasaki	/*
647119515Snjl	 * cleanup the buffer cleanup list
64885323Siwasaki	 */
64985323Siwasaki	dynbuf = ISC_LIST_HEAD(msg->cleanup);
650119515Snjl	while (dynbuf != NULL) {
651119515Snjl		next_dynbuf = ISC_LIST_NEXT(dynbuf, link);
652119515Snjl		ISC_LIST_UNLINK(msg->cleanup, dynbuf, link);
65385323Siwasaki		isc_buffer_free(&dynbuf);
654119515Snjl		dynbuf = next_dynbuf;
655119515Snjl	}
656119515Snjl
65785323Siwasaki	/*
658119515Snjl	 * Set other bits to normal default values.
659119515Snjl	 */
660119515Snjl	if (!everything)
661119515Snjl		msginit(msg);
662119515Snjl
663119515Snjl	ENSURE(isc_mempool_getallocated(msg->namepool) == 0);
664119515Snjl	ENSURE(isc_mempool_getallocated(msg->rdspool) == 0);
665119515Snjl}
666119515Snjl
667119515Snjlstatic unsigned int
66885323Siwasakispacefortsig(dns_tsigkey_t *key, int otherlen) {
66985323Siwasaki	isc_region_t r1, r2;
670119515Snjl	unsigned int x;
671119912Snjl	isc_result_t result;
67285323Siwasaki
673119515Snjl	/*
67485323Siwasaki	 * The space required for an TSIG record is:
675119912Snjl	 *
676119515Snjl	 *	n1 bytes for the name
677119515Snjl	 *	2 bytes for the type
678119515Snjl	 *	2 bytes for the class
67985323Siwasaki	 *	4 bytes for the ttl
680	 *	2 bytes for the rdlength
681	 *	n2 bytes for the algorithm name
682	 *	6 bytes for the time signed
683	 *	2 bytes for the fudge
684	 *	2 bytes for the MAC size
685	 *	x bytes for the MAC
686	 *	2 bytes for the original id
687	 *	2 bytes for the error
688	 *	2 bytes for the other data length
689	 *	y bytes for the other data (at most)
690	 * ---------------------------------
691	 *     26 + n1 + n2 + x + y bytes
692	 */
693
694	dns_name_toregion(&key->name, &r1);
695	dns_name_toregion(key->algorithm, &r2);
696	if (key->key == NULL)
697		x = 0;
698	else {
699		result = dst_key_sigsize(key->key, &x);
700		if (result != ISC_R_SUCCESS)
701			x = 0;
702	}
703	return (26 + r1.length + r2.length + x + otherlen);
704}
705
706isc_result_t
707dns_message_create(isc_mem_t *mctx, unsigned int intent, dns_message_t **msgp)
708{
709	dns_message_t *m;
710	isc_result_t result;
711	isc_buffer_t *dynbuf;
712	unsigned int i;
713
714	REQUIRE(mctx != NULL);
715	REQUIRE(msgp != NULL);
716	REQUIRE(*msgp == NULL);
717	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
718		|| intent == DNS_MESSAGE_INTENTRENDER);
719
720	m = isc_mem_get(mctx, sizeof(dns_message_t));
721	if (m == NULL)
722		return (ISC_R_NOMEMORY);
723
724	/*
725	 * No allocations until further notice.  Just initialize all lists
726	 * and other members that are freed in the cleanup phase here.
727	 */
728
729	m->magic = DNS_MESSAGE_MAGIC;
730	m->from_to_wire = intent;
731	msginit(m);
732
733	for (i = 0; i < DNS_SECTION_MAX; i++)
734		ISC_LIST_INIT(m->sections[i]);
735	m->mctx = mctx;
736
737	ISC_LIST_INIT(m->scratchpad);
738	ISC_LIST_INIT(m->cleanup);
739	m->namepool = NULL;
740	m->rdspool = NULL;
741	ISC_LIST_INIT(m->rdatas);
742	ISC_LIST_INIT(m->rdatalists);
743	ISC_LIST_INIT(m->offsets);
744	ISC_LIST_INIT(m->freerdata);
745	ISC_LIST_INIT(m->freerdatalist);
746
747	/*
748	 * Ok, it is safe to allocate (and then "goto cleanup" if failure)
749	 */
750
751	result = isc_mempool_create(m->mctx, sizeof(dns_name_t), &m->namepool);
752	if (result != ISC_R_SUCCESS)
753		goto cleanup;
754	isc_mempool_setfreemax(m->namepool, NAME_COUNT);
755	isc_mempool_setname(m->namepool, "msg:names");
756
757	result = isc_mempool_create(m->mctx, sizeof(dns_rdataset_t),
758				    &m->rdspool);
759	if (result != ISC_R_SUCCESS)
760		goto cleanup;
761	isc_mempool_setfreemax(m->rdspool, NAME_COUNT);
762	isc_mempool_setname(m->rdspool, "msg:rdataset");
763
764	dynbuf = NULL;
765	result = isc_buffer_allocate(mctx, &dynbuf, SCRATCHPAD_SIZE);
766	if (result != ISC_R_SUCCESS)
767		goto cleanup;
768	ISC_LIST_APPEND(m->scratchpad, dynbuf, link);
769
770	m->cctx = NULL;
771
772	*msgp = m;
773	return (ISC_R_SUCCESS);
774
775	/*
776	 * Cleanup for error returns.
777	 */
778 cleanup:
779	dynbuf = ISC_LIST_HEAD(m->scratchpad);
780	if (dynbuf != NULL) {
781		ISC_LIST_UNLINK(m->scratchpad, dynbuf, link);
782		isc_buffer_free(&dynbuf);
783	}
784	if (m->namepool != NULL)
785		isc_mempool_destroy(&m->namepool);
786	if (m->rdspool != NULL)
787		isc_mempool_destroy(&m->rdspool);
788	m->magic = 0;
789	isc_mem_put(mctx, m, sizeof(dns_message_t));
790
791	return (ISC_R_NOMEMORY);
792}
793
794void
795dns_message_reset(dns_message_t *msg, unsigned int intent) {
796	REQUIRE(DNS_MESSAGE_VALID(msg));
797	REQUIRE(intent == DNS_MESSAGE_INTENTPARSE
798		|| intent == DNS_MESSAGE_INTENTRENDER);
799
800	msgreset(msg, ISC_FALSE);
801	msg->from_to_wire = intent;
802}
803
804void
805dns_message_destroy(dns_message_t **msgp) {
806	dns_message_t *msg;
807
808	REQUIRE(msgp != NULL);
809	REQUIRE(DNS_MESSAGE_VALID(*msgp));
810
811	msg = *msgp;
812	*msgp = NULL;
813
814	msgreset(msg, ISC_TRUE);
815	isc_mempool_destroy(&msg->namepool);
816	isc_mempool_destroy(&msg->rdspool);
817	msg->magic = 0;
818	isc_mem_put(msg->mctx, msg, sizeof(dns_message_t));
819}
820
821static isc_result_t
822findname(dns_name_t **foundname, dns_name_t *target,
823	 dns_namelist_t *section)
824{
825	dns_name_t *curr;
826
827	for (curr = ISC_LIST_TAIL(*section);
828	     curr != NULL;
829	     curr = ISC_LIST_PREV(curr, link)) {
830		if (dns_name_equal(curr, target)) {
831			if (foundname != NULL)
832				*foundname = curr;
833			return (ISC_R_SUCCESS);
834		}
835	}
836
837	return (ISC_R_NOTFOUND);
838}
839
840isc_result_t
841dns_message_find(dns_name_t *name, dns_rdataclass_t rdclass,
842		 dns_rdatatype_t type, dns_rdatatype_t covers,
843		 dns_rdataset_t **rdataset)
844{
845	dns_rdataset_t *curr;
846
847	if (rdataset != NULL) {
848		REQUIRE(*rdataset == NULL);
849	}
850
851	for (curr = ISC_LIST_TAIL(name->list);
852	     curr != NULL;
853	     curr = ISC_LIST_PREV(curr, link)) {
854		if (curr->rdclass == rdclass &&
855		    curr->type == type && curr->covers == covers) {
856			if (rdataset != NULL)
857				*rdataset = curr;
858			return (ISC_R_SUCCESS);
859		}
860	}
861
862	return (ISC_R_NOTFOUND);
863}
864
865isc_result_t
866dns_message_findtype(dns_name_t *name, dns_rdatatype_t type,
867		     dns_rdatatype_t covers, dns_rdataset_t **rdataset)
868{
869	dns_rdataset_t *curr;
870
871	REQUIRE(name != NULL);
872	if (rdataset != NULL) {
873		REQUIRE(*rdataset == NULL);
874	}
875
876	for (curr = ISC_LIST_TAIL(name->list);
877	     curr != NULL;
878	     curr = ISC_LIST_PREV(curr, link)) {
879		if (curr->type == type && curr->covers == covers) {
880			if (rdataset != NULL)
881				*rdataset = curr;
882			return (ISC_R_SUCCESS);
883		}
884	}
885
886	return (ISC_R_NOTFOUND);
887}
888
889/*
890 * Read a name from buffer "source".
891 */
892static isc_result_t
893getname(dns_name_t *name, isc_buffer_t *source, dns_message_t *msg,
894	dns_decompress_t *dctx)
895{
896	isc_buffer_t *scratch;
897	isc_result_t result;
898	unsigned int tries;
899
900	scratch = currentbuffer(msg);
901
902	/*
903	 * First try:  use current buffer.
904	 * Second try:  allocate a new buffer and use that.
905	 */
906	tries = 0;
907	while (tries < 2) {
908		result = dns_name_fromwire(name, source, dctx, ISC_FALSE,
909					   scratch);
910
911		if (result == ISC_R_NOSPACE) {
912			tries++;
913
914			result = newbuffer(msg, SCRATCHPAD_SIZE);
915			if (result != ISC_R_SUCCESS)
916				return (result);
917
918			scratch = currentbuffer(msg);
919			dns_name_reset(name);
920		} else {
921			return (result);
922		}
923	}
924
925	INSIST(0);  /* Cannot get here... */
926	return (ISC_R_UNEXPECTED);
927}
928
929static isc_result_t
930getrdata(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
931	 dns_rdataclass_t rdclass, dns_rdatatype_t rdtype,
932	 unsigned int rdatalen, dns_rdata_t *rdata)
933{
934	isc_buffer_t *scratch;
935	isc_result_t result;
936	unsigned int tries;
937	unsigned int trysize;
938
939	scratch = currentbuffer(msg);
940
941	isc_buffer_setactive(source, rdatalen);
942
943	/*
944	 * First try:  use current buffer.
945	 * Second try:  allocate a new buffer of size
946	 *     max(SCRATCHPAD_SIZE, 2 * compressed_rdatalen)
947	 *     (the data will fit if it was not more than 50% compressed)
948	 * Subsequent tries: double buffer size on each try.
949	 */
950	tries = 0;
951	trysize = 0;
952	/* XXX possibly change this to a while (tries < 2) loop */
953	for (;;) {
954		result = dns_rdata_fromwire(rdata, rdclass, rdtype,
955					    source, dctx, 0,
956					    scratch);
957
958		if (result == ISC_R_NOSPACE) {
959			if (tries == 0) {
960				trysize = 2 * rdatalen;
961				if (trysize < SCRATCHPAD_SIZE)
962					trysize = SCRATCHPAD_SIZE;
963			} else {
964				INSIST(trysize != 0);
965				if (trysize >= 65535)
966					return (ISC_R_NOSPACE);
967					/* XXX DNS_R_RRTOOLONG? */
968				trysize *= 2;
969			}
970			tries++;
971			result = newbuffer(msg, trysize);
972			if (result != ISC_R_SUCCESS)
973				return (result);
974
975			scratch = currentbuffer(msg);
976		} else {
977			return (result);
978		}
979	}
980}
981
982#define DO_FORMERR					\
983	do {						\
984		if (best_effort)			\
985			seen_problem = ISC_TRUE;	\
986		else {					\
987			result = DNS_R_FORMERR;		\
988			goto cleanup;			\
989		}					\
990	} while (0)
991
992static isc_result_t
993getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
994	     unsigned int options)
995{
996	isc_region_t r;
997	unsigned int count;
998	dns_name_t *name;
999	dns_name_t *name2;
1000	dns_offsets_t *offsets;
1001	dns_rdataset_t *rdataset;
1002	dns_rdatalist_t *rdatalist;
1003	isc_result_t result;
1004	dns_rdatatype_t rdtype;
1005	dns_rdataclass_t rdclass;
1006	dns_namelist_t *section;
1007	isc_boolean_t free_name;
1008	isc_boolean_t best_effort;
1009	isc_boolean_t seen_problem;
1010
1011	section = &msg->sections[DNS_SECTION_QUESTION];
1012
1013	best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1014	seen_problem = ISC_FALSE;
1015
1016	name = NULL;
1017	rdataset = NULL;
1018	rdatalist = NULL;
1019
1020	for (count = 0; count < msg->counts[DNS_SECTION_QUESTION]; count++) {
1021		name = isc_mempool_get(msg->namepool);
1022		if (name == NULL)
1023			return (ISC_R_NOMEMORY);
1024		free_name = ISC_TRUE;
1025
1026		offsets = newoffsets(msg);
1027		if (offsets == NULL) {
1028			result = ISC_R_NOMEMORY;
1029			goto cleanup;
1030		}
1031		dns_name_init(name, *offsets);
1032
1033		/*
1034		 * Parse the name out of this packet.
1035		 */
1036		isc_buffer_remainingregion(source, &r);
1037		isc_buffer_setactive(source, r.length);
1038		result = getname(name, source, msg, dctx);
1039		if (result != ISC_R_SUCCESS)
1040			goto cleanup;
1041
1042		/*
1043		 * Run through the section, looking to see if this name
1044		 * is already there.  If it is found, put back the allocated
1045		 * name since we no longer need it, and set our name pointer
1046		 * to point to the name we found.
1047		 */
1048		result = findname(&name2, name, section);
1049
1050		/*
1051		 * If it is the first name in the section, accept it.
1052		 *
1053		 * If it is not, but is not the same as the name already
1054		 * in the question section, append to the section.  Note that
1055		 * here in the question section this is illegal, so return
1056		 * FORMERR.  In the future, check the opcode to see if
1057		 * this should be legal or not.  In either case we no longer
1058		 * need this name pointer.
1059		 */
1060		if (result != ISC_R_SUCCESS) {
1061			if (!ISC_LIST_EMPTY(*section))
1062				DO_FORMERR;
1063			ISC_LIST_APPEND(*section, name, link);
1064			free_name = ISC_FALSE;
1065		} else {
1066			isc_mempool_put(msg->namepool, name);
1067			name = name2;
1068			name2 = NULL;
1069			free_name = ISC_FALSE;
1070		}
1071
1072		/*
1073		 * Get type and class.
1074		 */
1075		isc_buffer_remainingregion(source, &r);
1076		if (r.length < 4) {
1077			result = ISC_R_UNEXPECTEDEND;
1078			goto cleanup;
1079		}
1080		rdtype = isc_buffer_getuint16(source);
1081		rdclass = isc_buffer_getuint16(source);
1082
1083		/*
1084		 * If this class is different than the one we already read,
1085		 * this is an error.
1086		 */
1087		if (msg->state == DNS_SECTION_ANY) {
1088			msg->state = DNS_SECTION_QUESTION;
1089			msg->rdclass = rdclass;
1090		} else if (msg->rdclass != rdclass)
1091			DO_FORMERR;
1092
1093		/*
1094		 * Can't ask the same question twice.
1095		 */
1096		result = dns_message_find(name, rdclass, rdtype, 0, NULL);
1097		if (result == ISC_R_SUCCESS)
1098			DO_FORMERR;
1099
1100		/*
1101		 * Allocate a new rdatalist.
1102		 */
1103		rdatalist = newrdatalist(msg);
1104		if (rdatalist == NULL) {
1105			result = ISC_R_NOMEMORY;
1106			goto cleanup;
1107		}
1108		rdataset =  isc_mempool_get(msg->rdspool);
1109		if (rdataset == NULL) {
1110			result = ISC_R_NOMEMORY;
1111			goto cleanup;
1112		}
1113
1114		/*
1115		 * Convert rdatalist to rdataset, and attach the latter to
1116		 * the name.
1117		 */
1118		rdatalist->type = rdtype;
1119		rdatalist->covers = 0;
1120		rdatalist->rdclass = rdclass;
1121		rdatalist->ttl = 0;
1122		ISC_LIST_INIT(rdatalist->rdata);
1123
1124		dns_rdataset_init(rdataset);
1125		result = dns_rdatalist_tordataset(rdatalist, rdataset);
1126		if (result != ISC_R_SUCCESS)
1127			goto cleanup;
1128
1129		rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
1130
1131		ISC_LIST_APPEND(name->list, rdataset, link);
1132		rdataset = NULL;
1133	}
1134
1135	if (seen_problem)
1136		return (DNS_R_RECOVERABLE);
1137	return (ISC_R_SUCCESS);
1138
1139 cleanup:
1140	if (rdataset != NULL) {
1141		INSIST(!dns_rdataset_isassociated(rdataset));
1142		isc_mempool_put(msg->rdspool, rdataset);
1143	}
1144#if 0
1145	if (rdatalist != NULL)
1146		isc_mempool_put(msg->rdlpool, rdatalist);
1147#endif
1148	if (free_name)
1149		isc_mempool_put(msg->namepool, name);
1150
1151	return (result);
1152}
1153
1154static isc_boolean_t
1155update(dns_section_t section, dns_rdataclass_t rdclass) {
1156	if (section == DNS_SECTION_PREREQUISITE)
1157		return (ISC_TF(rdclass == dns_rdataclass_any ||
1158			       rdclass == dns_rdataclass_none));
1159	if (section == DNS_SECTION_UPDATE)
1160		return (ISC_TF(rdclass == dns_rdataclass_any));
1161	return (ISC_FALSE);
1162}
1163
1164static isc_result_t
1165getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx,
1166	   dns_section_t sectionid, unsigned int options)
1167{
1168	isc_region_t r;
1169	unsigned int count, rdatalen;
1170	dns_name_t *name;
1171	dns_name_t *name2;
1172	dns_offsets_t *offsets;
1173	dns_rdataset_t *rdataset;
1174	dns_rdatalist_t *rdatalist;
1175	isc_result_t result;
1176	dns_rdatatype_t rdtype, covers;
1177	dns_rdataclass_t rdclass;
1178	dns_rdata_t *rdata;
1179	dns_ttl_t ttl;
1180	dns_namelist_t *section;
1181	isc_boolean_t free_name, free_rdataset;
1182	isc_boolean_t preserve_order, best_effort, seen_problem;
1183	isc_boolean_t issigzero;
1184
1185	preserve_order = ISC_TF(options & DNS_MESSAGEPARSE_PRESERVEORDER);
1186	best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT);
1187	seen_problem = ISC_FALSE;
1188
1189	for (count = 0; count < msg->counts[sectionid]; count++) {
1190		int recstart = source->current;
1191		isc_boolean_t skip_name_search, skip_type_search;
1192
1193		section = &msg->sections[sectionid];
1194
1195		skip_name_search = ISC_FALSE;
1196		skip_type_search = ISC_FALSE;
1197		free_name = ISC_FALSE;
1198		free_rdataset = ISC_FALSE;
1199
1200		name = isc_mempool_get(msg->namepool);
1201		if (name == NULL)
1202			return (ISC_R_NOMEMORY);
1203		free_name = ISC_TRUE;
1204
1205		offsets = newoffsets(msg);
1206		if (offsets == NULL) {
1207			result = ISC_R_NOMEMORY;
1208			goto cleanup;
1209		}
1210		dns_name_init(name, *offsets);
1211
1212		/*
1213		 * Parse the name out of this packet.
1214		 */
1215		isc_buffer_remainingregion(source, &r);
1216		isc_buffer_setactive(source, r.length);
1217		result = getname(name, source, msg, dctx);
1218		if (result != ISC_R_SUCCESS)
1219			goto cleanup;
1220
1221		/*
1222		 * Get type, class, ttl, and rdatalen.  Verify that at least
1223		 * rdatalen bytes remain.  (Some of this is deferred to
1224		 * later.)
1225		 */
1226		isc_buffer_remainingregion(source, &r);
1227		if (r.length < 2 + 2 + 4 + 2) {
1228			result = ISC_R_UNEXPECTEDEND;
1229			goto cleanup;
1230		}
1231		rdtype = isc_buffer_getuint16(source);
1232		rdclass = isc_buffer_getuint16(source);
1233
1234		/*
1235		 * If there was no question section, we may not yet have
1236		 * established a class.  Do so now.
1237		 */
1238		if (msg->state == DNS_SECTION_ANY &&
1239		    rdtype != dns_rdatatype_opt &&	/* class is UDP SIZE */
1240		    rdtype != dns_rdatatype_tsig &&	/* class is ANY */
1241		    rdtype != dns_rdatatype_tkey) {	/* class is undefined */
1242			msg->rdclass = rdclass;
1243			msg->state = DNS_SECTION_QUESTION;
1244		}
1245
1246		/*
1247		 * If this class is different than the one in the question
1248		 * section, bail.
1249		 */
1250		if (msg->opcode != dns_opcode_update
1251		    && rdtype != dns_rdatatype_tsig
1252		    && rdtype != dns_rdatatype_opt
1253		    && rdtype != dns_rdatatype_dnskey /* in a TKEY query */
1254		    && rdtype != dns_rdatatype_sig /* SIG(0) */
1255		    && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */
1256		    && msg->rdclass != dns_rdataclass_any
1257		    && msg->rdclass != rdclass)
1258			DO_FORMERR;
1259
1260		/*
1261		 * Special type handling for TSIG, OPT, and TKEY.
1262		 */
1263		if (rdtype == dns_rdatatype_tsig) {
1264			/*
1265			 * If it is a tsig, verify that it is in the
1266			 * additional data section.
1267			 */
1268			if (sectionid != DNS_SECTION_ADDITIONAL ||
1269			    rdclass != dns_rdataclass_any ||
1270			    count != msg->counts[sectionid]  - 1)
1271				DO_FORMERR;
1272			msg->sigstart = recstart;
1273			skip_name_search = ISC_TRUE;
1274			skip_type_search = ISC_TRUE;
1275		} else if (rdtype == dns_rdatatype_opt) {
1276			/*
1277			 * The name of an OPT record must be ".", it
1278			 * must be in the additional data section, and
1279			 * it must be the first OPT we've seen.
1280			 */
1281			if (!dns_name_equal(dns_rootname, name) ||
1282			    msg->opt != NULL)
1283				DO_FORMERR;
1284			skip_name_search = ISC_TRUE;
1285			skip_type_search = ISC_TRUE;
1286		} else if (rdtype == dns_rdatatype_tkey) {
1287			/*
1288			 * A TKEY must be in the additional section if this
1289			 * is a query, and the answer section if this is a
1290			 * response.  Unless it's a Win2000 client.
1291			 *
1292			 * Its class is ignored.
1293			 */
1294			dns_section_t tkeysection;
1295
1296			if ((msg->flags & DNS_MESSAGEFLAG_QR) == 0)
1297				tkeysection = DNS_SECTION_ADDITIONAL;
1298			else
1299				tkeysection = DNS_SECTION_ANSWER;
1300			if (sectionid != tkeysection &&
1301			    sectionid != DNS_SECTION_ANSWER)
1302				DO_FORMERR;
1303		}
1304
1305		/*
1306		 * ... now get ttl and rdatalen, and check buffer.
1307		 */
1308		ttl = isc_buffer_getuint32(source);
1309		rdatalen = isc_buffer_getuint16(source);
1310		r.length -= (2 + 2 + 4 + 2);
1311		if (r.length < rdatalen) {
1312			result = ISC_R_UNEXPECTEDEND;
1313			goto cleanup;
1314		}
1315
1316		/*
1317		 * Read the rdata from the wire format.  Interpret the
1318		 * rdata according to its actual class, even if it had a
1319		 * DynDNS meta-class in the packet (unless this is a TSIG).
1320		 * Then put the meta-class back into the finished rdata.
1321		 */
1322		rdata = newrdata(msg);
1323		if (rdata == NULL) {
1324			result = ISC_R_NOMEMORY;
1325			goto cleanup;
1326		}
1327		if (msg->opcode == dns_opcode_update &&
1328		    update(sectionid, rdclass)) {
1329			if (rdatalen != 0) {
1330				result = DNS_R_FORMERR;
1331				goto cleanup;
1332			}
1333			/*
1334			 * When the rdata is empty, the data pointer is
1335			 * never dereferenced, but it must still be non-NULL.
1336			 * Casting 1 rather than "" avoids warnings about
1337			 * discarding the const attribute of a string,
1338			 * for compilers that would warn about such things.
1339			 */
1340			rdata->data = (unsigned char *)1;
1341			rdata->length = 0;
1342			rdata->rdclass = rdclass;
1343			rdata->type = rdtype;
1344			rdata->flags = DNS_RDATA_UPDATE;
1345			result = ISC_R_SUCCESS;
1346		} else if (rdclass == dns_rdataclass_none &&
1347			   msg->opcode == dns_opcode_update &&
1348			   sectionid == DNS_SECTION_UPDATE) {
1349			result = getrdata(source, msg, dctx, msg->rdclass,
1350					  rdtype, rdatalen, rdata);
1351		} else
1352			result = getrdata(source, msg, dctx, rdclass,
1353					  rdtype, rdatalen, rdata);
1354		if (result != ISC_R_SUCCESS)
1355			goto cleanup;
1356		rdata->rdclass = rdclass;
1357		issigzero = ISC_FALSE;
1358		if (rdtype == dns_rdatatype_rrsig  &&
1359		    rdata->flags == 0) {
1360			covers = dns_rdata_covers(rdata);
1361			if (covers == 0)
1362				DO_FORMERR;
1363		} else if (rdtype == dns_rdatatype_sig /* SIG(0) */ &&
1364			   rdata->flags == 0) {
1365			covers = dns_rdata_covers(rdata);
1366			if (covers == 0) {
1367				if (sectionid != DNS_SECTION_ADDITIONAL ||
1368				    count != msg->counts[sectionid]  - 1)
1369					DO_FORMERR;
1370				msg->sigstart = recstart;
1371				skip_name_search = ISC_TRUE;
1372				skip_type_search = ISC_TRUE;
1373				issigzero = ISC_TRUE;
1374			}
1375		} else
1376			covers = 0;
1377
1378		/*
1379		 * If we are doing a dynamic update or this is a meta-type,
1380		 * don't bother searching for a name, just append this one
1381		 * to the end of the message.
1382		 */
1383		if (preserve_order || msg->opcode == dns_opcode_update ||
1384		    skip_name_search) {
1385			if (rdtype != dns_rdatatype_opt &&
1386			    rdtype != dns_rdatatype_tsig &&
1387			    !issigzero)
1388			{
1389				ISC_LIST_APPEND(*section, name, link);
1390				free_name = ISC_FALSE;
1391			}
1392		} else {
1393			/*
1394			 * Run through the section, looking to see if this name
1395			 * is already there.  If it is found, put back the
1396			 * allocated name since we no longer need it, and set
1397			 * our name pointer to point to the name we found.
1398			 */
1399			result = findname(&name2, name, section);
1400
1401			/*
1402			 * If it is a new name, append to the section.
1403			 */
1404			if (result == ISC_R_SUCCESS) {
1405				isc_mempool_put(msg->namepool, name);
1406				name = name2;
1407			} else {
1408				ISC_LIST_APPEND(*section, name, link);
1409			}
1410			free_name = ISC_FALSE;
1411		}
1412
1413		/*
1414		 * Search name for the particular type and class.
1415		 * Skip this stage if in update mode or this is a meta-type.
1416		 */
1417		if (preserve_order || msg->opcode == dns_opcode_update ||
1418		    skip_type_search)
1419			result = ISC_R_NOTFOUND;
1420		else {
1421			/*
1422			 * If this is a type that can only occur in
1423			 * the question section, fail.
1424			 */
1425			if (dns_rdatatype_questiononly(rdtype))
1426				DO_FORMERR;
1427
1428			rdataset = NULL;
1429			result = dns_message_find(name, rdclass, rdtype,
1430						   covers, &rdataset);
1431		}
1432
1433		/*
1434		 * If we found an rdataset that matches, we need to
1435		 * append this rdata to that set.  If we did not, we need
1436		 * to create a new rdatalist, store the important bits there,
1437		 * convert it to an rdataset, and link the latter to the name.
1438		 * Yuck.  When appending, make certain that the type isn't
1439		 * a singleton type, such as SOA or CNAME.
1440		 *
1441		 * Note that this check will be bypassed when preserving order,
1442		 * the opcode is an update, or the type search is skipped.
1443		 */
1444		if (result == ISC_R_SUCCESS) {
1445			if (dns_rdatatype_issingleton(rdtype))
1446				DO_FORMERR;
1447		}
1448
1449		if (result == ISC_R_NOTFOUND) {
1450			rdataset = isc_mempool_get(msg->rdspool);
1451			if (rdataset == NULL) {
1452				result = ISC_R_NOMEMORY;
1453				goto cleanup;
1454			}
1455			free_rdataset = ISC_TRUE;
1456
1457			rdatalist = newrdatalist(msg);
1458			if (rdatalist == NULL) {
1459				result = ISC_R_NOMEMORY;
1460				goto cleanup;
1461			}
1462
1463			rdatalist->type = rdtype;
1464			rdatalist->covers = covers;
1465			rdatalist->rdclass = rdclass;
1466			rdatalist->ttl = ttl;
1467			ISC_LIST_INIT(rdatalist->rdata);
1468
1469			dns_rdataset_init(rdataset);
1470			RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist,
1471							       rdataset)
1472				      == ISC_R_SUCCESS);
1473
1474			if (rdtype != dns_rdatatype_opt &&
1475			    rdtype != dns_rdatatype_tsig &&
1476			    !issigzero)
1477			{
1478				ISC_LIST_APPEND(name->list, rdataset, link);
1479				free_rdataset = ISC_FALSE;
1480			}
1481		}
1482
1483		/*
1484		 * Minimize TTLs.
1485		 *
1486		 * Section 5.2 of RFC2181 says we should drop
1487		 * nonauthoritative rrsets where the TTLs differ, but we
1488		 * currently treat them the as if they were authoritative and
1489		 * minimize them.
1490		 */
1491		if (ttl != rdataset->ttl) {
1492			rdataset->attributes |= DNS_RDATASETATTR_TTLADJUSTED;
1493			if (ttl < rdataset->ttl)
1494				rdataset->ttl = ttl;
1495		}
1496
1497		/* Append this rdata to the rdataset. */
1498		dns_rdatalist_fromrdataset(rdataset, &rdatalist);
1499		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1500
1501		/*
1502		 * If this is an OPT record, remember it.  Also, set
1503		 * the extended rcode.  Note that msg->opt will only be set
1504		 * if best-effort parsing is enabled.
1505		 */
1506		if (rdtype == dns_rdatatype_opt && msg->opt == NULL) {
1507			dns_rcode_t ercode;
1508
1509			msg->opt = rdataset;
1510			rdataset = NULL;
1511			free_rdataset = ISC_FALSE;
1512			ercode = (dns_rcode_t)
1513				((msg->opt->ttl & DNS_MESSAGE_EDNSRCODE_MASK)
1514				 >> 20);
1515			msg->rcode |= ercode;
1516			isc_mempool_put(msg->namepool, name);
1517			free_name = ISC_FALSE;
1518		}
1519
1520		/*
1521		 * If this is an SIG(0) or TSIG record, remember it.  Note
1522		 * that msg->sig0 or msg->tsig will only be set if best-effort
1523		 * parsing is enabled.
1524		 */
1525		if (issigzero && msg->sig0 == NULL) {
1526			msg->sig0 = rdataset;
1527			msg->sig0name = name;
1528			rdataset = NULL;
1529			free_rdataset = ISC_FALSE;
1530			free_name = ISC_FALSE;
1531		} else if (rdtype == dns_rdatatype_tsig && msg->tsig == NULL) {
1532			msg->tsig = rdataset;
1533			msg->tsigname = name;
1534			/* Windows doesn't like TSIG names to be compressed. */
1535			msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1536			rdataset = NULL;
1537			free_rdataset = ISC_FALSE;
1538			free_name = ISC_FALSE;
1539		}
1540
1541		if (seen_problem) {
1542			if (free_name)
1543				isc_mempool_put(msg->namepool, name);
1544			if (free_rdataset)
1545				isc_mempool_put(msg->rdspool, rdataset);
1546			free_name = free_rdataset = ISC_FALSE;
1547		}
1548		INSIST(free_name == ISC_FALSE);
1549		INSIST(free_rdataset == ISC_FALSE);
1550	}
1551
1552	if (seen_problem)
1553		return (DNS_R_RECOVERABLE);
1554	return (ISC_R_SUCCESS);
1555
1556 cleanup:
1557	if (free_name)
1558		isc_mempool_put(msg->namepool, name);
1559	if (free_rdataset)
1560		isc_mempool_put(msg->rdspool, rdataset);
1561
1562	return (result);
1563}
1564
1565isc_result_t
1566dns_message_parse(dns_message_t *msg, isc_buffer_t *source,
1567		  unsigned int options)
1568{
1569	isc_region_t r;
1570	dns_decompress_t dctx;
1571	isc_result_t ret;
1572	isc_uint16_t tmpflags;
1573	isc_buffer_t origsource;
1574	isc_boolean_t seen_problem;
1575	isc_boolean_t ignore_tc;
1576
1577	REQUIRE(DNS_MESSAGE_VALID(msg));
1578	REQUIRE(source != NULL);
1579	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
1580
1581	seen_problem = ISC_FALSE;
1582	ignore_tc = ISC_TF(options & DNS_MESSAGEPARSE_IGNORETRUNCATION);
1583
1584	origsource = *source;
1585
1586	msg->header_ok = 0;
1587	msg->question_ok = 0;
1588
1589	isc_buffer_remainingregion(source, &r);
1590	if (r.length < DNS_MESSAGE_HEADERLEN)
1591		return (ISC_R_UNEXPECTEDEND);
1592
1593	msg->id = isc_buffer_getuint16(source);
1594	tmpflags = isc_buffer_getuint16(source);
1595	msg->opcode = ((tmpflags & DNS_MESSAGE_OPCODE_MASK)
1596		       >> DNS_MESSAGE_OPCODE_SHIFT);
1597	msg->rcode = (dns_rcode_t)(tmpflags & DNS_MESSAGE_RCODE_MASK);
1598	msg->flags = (tmpflags & DNS_MESSAGE_FLAG_MASK);
1599	msg->counts[DNS_SECTION_QUESTION] = isc_buffer_getuint16(source);
1600	msg->counts[DNS_SECTION_ANSWER] = isc_buffer_getuint16(source);
1601	msg->counts[DNS_SECTION_AUTHORITY] = isc_buffer_getuint16(source);
1602	msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source);
1603
1604	msg->header_ok = 1;
1605
1606	/*
1607	 * -1 means no EDNS.
1608	 */
1609	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
1610
1611	dns_decompress_setmethods(&dctx, DNS_COMPRESS_GLOBAL14);
1612
1613	ret = getquestions(source, msg, &dctx, options);
1614	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1615		goto truncated;
1616	if (ret == DNS_R_RECOVERABLE) {
1617		seen_problem = ISC_TRUE;
1618		ret = ISC_R_SUCCESS;
1619	}
1620	if (ret != ISC_R_SUCCESS)
1621		return (ret);
1622	msg->question_ok = 1;
1623
1624	ret = getsection(source, msg, &dctx, DNS_SECTION_ANSWER, options);
1625	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1626		goto truncated;
1627	if (ret == DNS_R_RECOVERABLE) {
1628		seen_problem = ISC_TRUE;
1629		ret = ISC_R_SUCCESS;
1630	}
1631	if (ret != ISC_R_SUCCESS)
1632		return (ret);
1633
1634	ret = getsection(source, msg, &dctx, DNS_SECTION_AUTHORITY, options);
1635	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1636		goto truncated;
1637	if (ret == DNS_R_RECOVERABLE) {
1638		seen_problem = ISC_TRUE;
1639		ret = ISC_R_SUCCESS;
1640	}
1641	if (ret != ISC_R_SUCCESS)
1642		return (ret);
1643
1644	ret = getsection(source, msg, &dctx, DNS_SECTION_ADDITIONAL, options);
1645	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1646		goto truncated;
1647	if (ret == DNS_R_RECOVERABLE) {
1648		seen_problem = ISC_TRUE;
1649		ret = ISC_R_SUCCESS;
1650	}
1651	if (ret != ISC_R_SUCCESS)
1652		return (ret);
1653
1654	isc_buffer_remainingregion(source, &r);
1655	if (r.length != 0) {
1656		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1657			      DNS_LOGMODULE_MESSAGE, ISC_LOG_DEBUG(3),
1658			      "message has %u byte(s) of trailing garbage",
1659			      r.length);
1660	}
1661
1662 truncated:
1663	if ((options & DNS_MESSAGEPARSE_CLONEBUFFER) == 0)
1664		isc_buffer_usedregion(&origsource, &msg->saved);
1665	else {
1666		msg->saved.length = isc_buffer_usedlength(&origsource);
1667		msg->saved.base = isc_mem_get(msg->mctx, msg->saved.length);
1668		if (msg->saved.base == NULL)
1669			return (ISC_R_NOMEMORY);
1670		memcpy(msg->saved.base, isc_buffer_base(&origsource),
1671		       msg->saved.length);
1672		msg->free_saved = 1;
1673	}
1674
1675	if (ret == ISC_R_UNEXPECTEDEND && ignore_tc)
1676		return (DNS_R_RECOVERABLE);
1677	if (seen_problem == ISC_TRUE)
1678		return (DNS_R_RECOVERABLE);
1679	return (ISC_R_SUCCESS);
1680}
1681
1682isc_result_t
1683dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx,
1684			isc_buffer_t *buffer)
1685{
1686	isc_region_t r;
1687
1688	REQUIRE(DNS_MESSAGE_VALID(msg));
1689	REQUIRE(buffer != NULL);
1690	REQUIRE(msg->buffer == NULL);
1691	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
1692
1693	msg->cctx = cctx;
1694
1695	/*
1696	 * Erase the contents of this buffer.
1697	 */
1698	isc_buffer_clear(buffer);
1699
1700	/*
1701	 * Make certain there is enough for at least the header in this
1702	 * buffer.
1703	 */
1704	isc_buffer_availableregion(buffer, &r);
1705	if (r.length < DNS_MESSAGE_HEADERLEN)
1706		return (ISC_R_NOSPACE);
1707
1708	if (r.length < msg->reserved)
1709		return (ISC_R_NOSPACE);
1710
1711	/*
1712	 * Reserve enough space for the header in this buffer.
1713	 */
1714	isc_buffer_add(buffer, DNS_MESSAGE_HEADERLEN);
1715
1716	msg->buffer = buffer;
1717
1718	return (ISC_R_SUCCESS);
1719}
1720
1721isc_result_t
1722dns_message_renderchangebuffer(dns_message_t *msg, isc_buffer_t *buffer) {
1723	isc_region_t r, rn;
1724
1725	REQUIRE(DNS_MESSAGE_VALID(msg));
1726	REQUIRE(buffer != NULL);
1727	REQUIRE(msg->buffer != NULL);
1728
1729	/*
1730	 * Ensure that the new buffer is empty, and has enough space to
1731	 * hold the current contents.
1732	 */
1733	isc_buffer_clear(buffer);
1734
1735	isc_buffer_availableregion(buffer, &rn);
1736	isc_buffer_usedregion(msg->buffer, &r);
1737	REQUIRE(rn.length > r.length);
1738
1739	/*
1740	 * Copy the contents from the old to the new buffer.
1741	 */
1742	isc_buffer_add(buffer, r.length);
1743	memcpy(rn.base, r.base, r.length);
1744
1745	msg->buffer = buffer;
1746
1747	return (ISC_R_SUCCESS);
1748}
1749
1750void
1751dns_message_renderrelease(dns_message_t *msg, unsigned int space) {
1752	REQUIRE(DNS_MESSAGE_VALID(msg));
1753	REQUIRE(space <= msg->reserved);
1754
1755	msg->reserved -= space;
1756}
1757
1758isc_result_t
1759dns_message_renderreserve(dns_message_t *msg, unsigned int space) {
1760	isc_region_t r;
1761
1762	REQUIRE(DNS_MESSAGE_VALID(msg));
1763
1764	if (msg->buffer != NULL) {
1765		isc_buffer_availableregion(msg->buffer, &r);
1766		if (r.length < (space + msg->reserved))
1767			return (ISC_R_NOSPACE);
1768	}
1769
1770	msg->reserved += space;
1771
1772	return (ISC_R_SUCCESS);
1773}
1774
1775static inline isc_boolean_t
1776wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) {
1777	int pass_needed;
1778
1779	/*
1780	 * If we are not rendering class IN, this ordering is bogus.
1781	 */
1782	if (rds->rdclass != dns_rdataclass_in)
1783		return (ISC_FALSE);
1784
1785	switch (rds->type) {
1786	case dns_rdatatype_a:
1787	case dns_rdatatype_aaaa:
1788		if (preferred_glue == rds->type)
1789			pass_needed = 4;
1790		else
1791			pass_needed = 3;
1792		break;
1793	case dns_rdatatype_rrsig:
1794	case dns_rdatatype_dnskey:
1795		pass_needed = 2;
1796		break;
1797	default:
1798		pass_needed = 1;
1799	}
1800
1801	if (pass_needed >= pass)
1802		return (ISC_FALSE);
1803
1804	return (ISC_TRUE);
1805}
1806
1807#ifdef ALLOW_FILTER_AAAA_ON_V4
1808/*
1809 * Decide whether to not answer with an AAAA record and its RRSIG
1810 */
1811static inline isc_boolean_t
1812norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options)
1813{
1814	switch (rdataset->type) {
1815	case dns_rdatatype_aaaa:
1816		if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0)
1817			return (ISC_FALSE);
1818		break;
1819
1820	case dns_rdatatype_rrsig:
1821		if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 ||
1822		    rdataset->covers != dns_rdatatype_aaaa)
1823			return (ISC_FALSE);
1824		break;
1825
1826	default:
1827		return (ISC_FALSE);
1828	}
1829
1830	if (rdataset->rdclass != dns_rdataclass_in)
1831		return (ISC_FALSE);
1832
1833	return (ISC_TRUE);
1834}
1835
1836#endif
1837isc_result_t
1838dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid,
1839			  unsigned int options)
1840{
1841	dns_namelist_t *section;
1842	dns_name_t *name, *next_name;
1843	dns_rdataset_t *rdataset, *next_rdataset;
1844	unsigned int count, total;
1845	isc_result_t result;
1846	isc_buffer_t st; /* for rollbacks */
1847	int pass;
1848	isc_boolean_t partial = ISC_FALSE;
1849	unsigned int rd_options;
1850	dns_rdatatype_t preferred_glue = 0;
1851
1852	REQUIRE(DNS_MESSAGE_VALID(msg));
1853	REQUIRE(msg->buffer != NULL);
1854	REQUIRE(VALID_NAMED_SECTION(sectionid));
1855
1856	section = &msg->sections[sectionid];
1857
1858	if ((sectionid == DNS_SECTION_ADDITIONAL)
1859	    && (options & DNS_MESSAGERENDER_ORDERED) == 0) {
1860		if ((options & DNS_MESSAGERENDER_PREFER_A) != 0) {
1861			preferred_glue = dns_rdatatype_a;
1862			pass = 4;
1863		} else if ((options & DNS_MESSAGERENDER_PREFER_AAAA) != 0) {
1864			preferred_glue = dns_rdatatype_aaaa;
1865			pass = 4;
1866		} else
1867			pass = 3;
1868	} else
1869		pass = 1;
1870
1871	if ((options & DNS_MESSAGERENDER_OMITDNSSEC) == 0)
1872		rd_options = 0;
1873	else
1874		rd_options = DNS_RDATASETTOWIRE_OMITDNSSEC;
1875
1876	/*
1877	 * Shrink the space in the buffer by the reserved amount.
1878	 */
1879	msg->buffer->length -= msg->reserved;
1880
1881	total = 0;
1882	if (msg->reserved == 0 && (options & DNS_MESSAGERENDER_PARTIAL) != 0)
1883		partial = ISC_TRUE;
1884
1885	/*
1886	 * Render required glue first.  Set TC if it won't fit.
1887	 */
1888	name = ISC_LIST_HEAD(*section);
1889	if (name != NULL) {
1890		rdataset = ISC_LIST_HEAD(name->list);
1891		if (rdataset != NULL &&
1892		    (rdataset->attributes & DNS_RDATASETATTR_REQUIREDGLUE) != 0 &&
1893		    (rdataset->attributes & DNS_RDATASETATTR_RENDERED) == 0) {
1894			const void *order_arg = msg->order_arg;
1895			st = *(msg->buffer);
1896			count = 0;
1897			if (partial)
1898				result = dns_rdataset_towirepartial(rdataset,
1899								    name,
1900								    msg->cctx,
1901								    msg->buffer,
1902								    msg->order,
1903								    order_arg,
1904								    rd_options,
1905								    &count,
1906								    NULL);
1907			else
1908				result = dns_rdataset_towiresorted(rdataset,
1909								   name,
1910								   msg->cctx,
1911								   msg->buffer,
1912								   msg->order,
1913								   order_arg,
1914								   rd_options,
1915								   &count);
1916			total += count;
1917			if (partial && result == ISC_R_NOSPACE) {
1918				msg->flags |= DNS_MESSAGEFLAG_TC;
1919				msg->buffer->length += msg->reserved;
1920				msg->counts[sectionid] += total;
1921				return (result);
1922			}
1923			if (result == ISC_R_NOSPACE)
1924				msg->flags |= DNS_MESSAGEFLAG_TC;
1925			if (result != ISC_R_SUCCESS) {
1926				INSIST(st.used < 65536);
1927				dns_compress_rollback(msg->cctx,
1928						      (isc_uint16_t)st.used);
1929				*(msg->buffer) = st;  /* rollback */
1930				msg->buffer->length += msg->reserved;
1931				msg->counts[sectionid] += total;
1932				return (result);
1933			}
1934			rdataset->attributes |= DNS_RDATASETATTR_RENDERED;
1935		}
1936	}
1937
1938	do {
1939		name = ISC_LIST_HEAD(*section);
1940		if (name == NULL) {
1941			msg->buffer->length += msg->reserved;
1942			msg->counts[sectionid] += total;
1943			return (ISC_R_SUCCESS);
1944		}
1945
1946		while (name != NULL) {
1947			next_name = ISC_LIST_NEXT(name, link);
1948
1949			rdataset = ISC_LIST_HEAD(name->list);
1950			while (rdataset != NULL) {
1951				next_rdataset = ISC_LIST_NEXT(rdataset, link);
1952
1953				if ((rdataset->attributes &
1954				     DNS_RDATASETATTR_RENDERED) != 0)
1955					goto next;
1956
1957				if (((options & DNS_MESSAGERENDER_ORDERED)
1958				     == 0)
1959				    && (sectionid == DNS_SECTION_ADDITIONAL)
1960				    && wrong_priority(rdataset, pass,
1961						      preferred_glue))
1962					goto next;
1963
1964#ifdef ALLOW_FILTER_AAAA_ON_V4
1965				/*
1966				 * Suppress AAAAs if asked and we are
1967				 * not doing DNSSEC or are breaking DNSSEC.
1968				 * Say so in the AD bit if we break DNSSEC.
1969				 */
1970				if (norender_rdataset(rdataset, options) &&
1971				    sectionid != DNS_SECTION_QUESTION) {
1972					if (sectionid == DNS_SECTION_ANSWER ||
1973					    sectionid == DNS_SECTION_AUTHORITY)
1974					    msg->flags &= ~DNS_MESSAGEFLAG_AD;
1975					if (OPTOUT(rdataset))
1976					    msg->flags &= ~DNS_MESSAGEFLAG_AD;
1977					goto next;
1978				}
1979
1980#endif
1981				st = *(msg->buffer);
1982
1983				count = 0;
1984				if (partial)
1985					result = dns_rdataset_towirepartial(
1986							  rdataset,
1987							  name,
1988							  msg->cctx,
1989							  msg->buffer,
1990							  msg->order,
1991							  msg->order_arg,
1992							  rd_options,
1993							  &count,
1994							  NULL);
1995				else
1996					result = dns_rdataset_towiresorted(
1997							  rdataset,
1998							  name,
1999							  msg->cctx,
2000							  msg->buffer,
2001							  msg->order,
2002							  msg->order_arg,
2003							  rd_options,
2004							  &count);
2005
2006				total += count;
2007
2008				/*
2009				 * If out of space, record stats on what we
2010				 * rendered so far, and return that status.
2011				 *
2012				 * XXXMLG Need to change this when
2013				 * dns_rdataset_towire() can render partial
2014				 * sets starting at some arbitrary point in the
2015				 * set.  This will include setting a bit in the
2016				 * rdataset to indicate that a partial
2017				 * rendering was done, and some state saved
2018				 * somewhere (probably in the message struct)
2019				 * to indicate where to continue from.
2020				 */
2021				if (partial && result == ISC_R_NOSPACE) {
2022					msg->buffer->length += msg->reserved;
2023					msg->counts[sectionid] += total;
2024					return (result);
2025				}
2026				if (result != ISC_R_SUCCESS) {
2027					INSIST(st.used < 65536);
2028					dns_compress_rollback(msg->cctx,
2029							(isc_uint16_t)st.used);
2030					*(msg->buffer) = st;  /* rollback */
2031					msg->buffer->length += msg->reserved;
2032					msg->counts[sectionid] += total;
2033					return (result);
2034				}
2035
2036				/*
2037				 * If we have rendered non-validated data,
2038				 * ensure that the AD bit is not set.
2039				 */
2040				if (rdataset->trust != dns_trust_secure &&
2041				    (sectionid == DNS_SECTION_ANSWER ||
2042				     sectionid == DNS_SECTION_AUTHORITY))
2043					msg->flags &= ~DNS_MESSAGEFLAG_AD;
2044				if (OPTOUT(rdataset))
2045					msg->flags &= ~DNS_MESSAGEFLAG_AD;
2046
2047				rdataset->attributes |=
2048					DNS_RDATASETATTR_RENDERED;
2049
2050			next:
2051				rdataset = next_rdataset;
2052			}
2053
2054			name = next_name;
2055		}
2056	} while (--pass != 0);
2057
2058	msg->buffer->length += msg->reserved;
2059	msg->counts[sectionid] += total;
2060
2061	return (ISC_R_SUCCESS);
2062}
2063
2064void
2065dns_message_renderheader(dns_message_t *msg, isc_buffer_t *target) {
2066	isc_uint16_t tmp;
2067	isc_region_t r;
2068
2069	REQUIRE(DNS_MESSAGE_VALID(msg));
2070	REQUIRE(target != NULL);
2071
2072	isc_buffer_availableregion(target, &r);
2073	REQUIRE(r.length >= DNS_MESSAGE_HEADERLEN);
2074
2075	isc_buffer_putuint16(target, msg->id);
2076
2077	tmp = ((msg->opcode << DNS_MESSAGE_OPCODE_SHIFT)
2078	       & DNS_MESSAGE_OPCODE_MASK);
2079	tmp |= (msg->rcode & DNS_MESSAGE_RCODE_MASK);
2080	tmp |= (msg->flags & DNS_MESSAGE_FLAG_MASK);
2081
2082	INSIST(msg->counts[DNS_SECTION_QUESTION]  < 65536 &&
2083	       msg->counts[DNS_SECTION_ANSWER]    < 65536 &&
2084	       msg->counts[DNS_SECTION_AUTHORITY] < 65536 &&
2085	       msg->counts[DNS_SECTION_ADDITIONAL] < 65536);
2086
2087	isc_buffer_putuint16(target, tmp);
2088	isc_buffer_putuint16(target,
2089			    (isc_uint16_t)msg->counts[DNS_SECTION_QUESTION]);
2090	isc_buffer_putuint16(target,
2091			    (isc_uint16_t)msg->counts[DNS_SECTION_ANSWER]);
2092	isc_buffer_putuint16(target,
2093			    (isc_uint16_t)msg->counts[DNS_SECTION_AUTHORITY]);
2094	isc_buffer_putuint16(target,
2095			    (isc_uint16_t)msg->counts[DNS_SECTION_ADDITIONAL]);
2096}
2097
2098isc_result_t
2099dns_message_renderend(dns_message_t *msg) {
2100	isc_buffer_t tmpbuf;
2101	isc_region_t r;
2102	int result;
2103	unsigned int count;
2104
2105	REQUIRE(DNS_MESSAGE_VALID(msg));
2106	REQUIRE(msg->buffer != NULL);
2107
2108	if ((msg->rcode & ~DNS_MESSAGE_RCODE_MASK) != 0 && msg->opt == NULL) {
2109		/*
2110		 * We have an extended rcode but are not using EDNS.
2111		 */
2112		return (DNS_R_FORMERR);
2113	}
2114
2115	/*
2116	 * If we've got an OPT record, render it.
2117	 */
2118	if (msg->opt != NULL) {
2119		dns_message_renderrelease(msg, msg->opt_reserved);
2120		msg->opt_reserved = 0;
2121		/*
2122		 * Set the extended rcode.
2123		 */
2124		msg->opt->ttl &= ~DNS_MESSAGE_EDNSRCODE_MASK;
2125		msg->opt->ttl |= ((msg->rcode << 20) &
2126				  DNS_MESSAGE_EDNSRCODE_MASK);
2127		/*
2128		 * Render.
2129		 */
2130		count = 0;
2131		result = dns_rdataset_towire(msg->opt, dns_rootname,
2132					     msg->cctx, msg->buffer, 0,
2133					     &count);
2134		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2135		if (result != ISC_R_SUCCESS)
2136			return (result);
2137	}
2138
2139	/*
2140	 * If we're adding a TSIG or SIG(0) to a truncated message,
2141	 * clear all rdatasets from the message except for the question
2142	 * before adding the TSIG or SIG(0).  If the question doesn't fit,
2143	 * don't include it.
2144	 */
2145	if ((msg->tsigkey != NULL || msg->sig0key != NULL) &&
2146	    (msg->flags & DNS_MESSAGEFLAG_TC) != 0)
2147	{
2148		isc_buffer_t *buf;
2149
2150		msgresetnames(msg, DNS_SECTION_ANSWER);
2151		buf = msg->buffer;
2152		dns_message_renderreset(msg);
2153		msg->buffer = buf;
2154		isc_buffer_clear(msg->buffer);
2155		isc_buffer_add(msg->buffer, DNS_MESSAGE_HEADERLEN);
2156		dns_compress_rollback(msg->cctx, 0);
2157		result = dns_message_rendersection(msg, DNS_SECTION_QUESTION,
2158						   0);
2159		if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE)
2160			return (result);
2161	}
2162
2163	/*
2164	 * If we're adding a TSIG record, generate and render it.
2165	 */
2166	if (msg->tsigkey != NULL) {
2167		dns_message_renderrelease(msg, msg->sig_reserved);
2168		msg->sig_reserved = 0;
2169		result = dns_tsig_sign(msg);
2170		if (result != ISC_R_SUCCESS)
2171			return (result);
2172		count = 0;
2173		result = dns_rdataset_towire(msg->tsig, msg->tsigname,
2174					     msg->cctx, msg->buffer, 0,
2175					     &count);
2176		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2177		if (result != ISC_R_SUCCESS)
2178			return (result);
2179	}
2180
2181	/*
2182	 * If we're adding a SIG(0) record, generate and render it.
2183	 */
2184	if (msg->sig0key != NULL) {
2185		dns_message_renderrelease(msg, msg->sig_reserved);
2186		msg->sig_reserved = 0;
2187		result = dns_dnssec_signmessage(msg, msg->sig0key);
2188		if (result != ISC_R_SUCCESS)
2189			return (result);
2190		count = 0;
2191		/*
2192		 * Note: dns_rootname is used here, not msg->sig0name, since
2193		 * the owner name of a SIG(0) is irrelevant, and will not
2194		 * be set in a message being rendered.
2195		 */
2196		result = dns_rdataset_towire(msg->sig0, dns_rootname,
2197					     msg->cctx, msg->buffer, 0,
2198					     &count);
2199		msg->counts[DNS_SECTION_ADDITIONAL] += count;
2200		if (result != ISC_R_SUCCESS)
2201			return (result);
2202	}
2203
2204	isc_buffer_usedregion(msg->buffer, &r);
2205	isc_buffer_init(&tmpbuf, r.base, r.length);
2206
2207	dns_message_renderheader(msg, &tmpbuf);
2208
2209	msg->buffer = NULL;  /* forget about this buffer only on success XXX */
2210
2211	return (ISC_R_SUCCESS);
2212}
2213
2214void
2215dns_message_renderreset(dns_message_t *msg) {
2216	unsigned int i;
2217	dns_name_t *name;
2218	dns_rdataset_t *rds;
2219
2220	/*
2221	 * Reset the message so that it may be rendered again.
2222	 */
2223
2224	REQUIRE(DNS_MESSAGE_VALID(msg));
2225	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2226
2227	msg->buffer = NULL;
2228
2229	for (i = 0; i < DNS_SECTION_MAX; i++) {
2230		msg->cursors[i] = NULL;
2231		msg->counts[i] = 0;
2232		for (name = ISC_LIST_HEAD(msg->sections[i]);
2233		     name != NULL;
2234		     name = ISC_LIST_NEXT(name, link)) {
2235			for (rds = ISC_LIST_HEAD(name->list);
2236			     rds != NULL;
2237			     rds = ISC_LIST_NEXT(rds, link)) {
2238				rds->attributes &= ~DNS_RDATASETATTR_RENDERED;
2239			}
2240		}
2241	}
2242	if (msg->tsigname != NULL)
2243		dns_message_puttempname(msg, &msg->tsigname);
2244	if (msg->tsig != NULL) {
2245		dns_rdataset_disassociate(msg->tsig);
2246		dns_message_puttemprdataset(msg, &msg->tsig);
2247	}
2248	if (msg->sig0 != NULL) {
2249		dns_rdataset_disassociate(msg->sig0);
2250		dns_message_puttemprdataset(msg, &msg->sig0);
2251	}
2252}
2253
2254isc_result_t
2255dns_message_firstname(dns_message_t *msg, dns_section_t section) {
2256	REQUIRE(DNS_MESSAGE_VALID(msg));
2257	REQUIRE(VALID_NAMED_SECTION(section));
2258
2259	msg->cursors[section] = ISC_LIST_HEAD(msg->sections[section]);
2260
2261	if (msg->cursors[section] == NULL)
2262		return (ISC_R_NOMORE);
2263
2264	return (ISC_R_SUCCESS);
2265}
2266
2267isc_result_t
2268dns_message_nextname(dns_message_t *msg, dns_section_t section) {
2269	REQUIRE(DNS_MESSAGE_VALID(msg));
2270	REQUIRE(VALID_NAMED_SECTION(section));
2271	REQUIRE(msg->cursors[section] != NULL);
2272
2273	msg->cursors[section] = ISC_LIST_NEXT(msg->cursors[section], link);
2274
2275	if (msg->cursors[section] == NULL)
2276		return (ISC_R_NOMORE);
2277
2278	return (ISC_R_SUCCESS);
2279}
2280
2281void
2282dns_message_currentname(dns_message_t *msg, dns_section_t section,
2283			dns_name_t **name)
2284{
2285	REQUIRE(DNS_MESSAGE_VALID(msg));
2286	REQUIRE(VALID_NAMED_SECTION(section));
2287	REQUIRE(name != NULL && *name == NULL);
2288	REQUIRE(msg->cursors[section] != NULL);
2289
2290	*name = msg->cursors[section];
2291}
2292
2293isc_result_t
2294dns_message_findname(dns_message_t *msg, dns_section_t section,
2295		     dns_name_t *target, dns_rdatatype_t type,
2296		     dns_rdatatype_t covers, dns_name_t **name,
2297		     dns_rdataset_t **rdataset)
2298{
2299	dns_name_t *foundname;
2300	isc_result_t result;
2301
2302	/*
2303	 * XXX These requirements are probably too intensive, especially
2304	 * where things can be NULL, but as they are they ensure that if
2305	 * something is NON-NULL, indicating that the caller expects it
2306	 * to be filled in, that we can in fact fill it in.
2307	 */
2308	REQUIRE(msg != NULL);
2309	REQUIRE(VALID_SECTION(section));
2310	REQUIRE(target != NULL);
2311	if (name != NULL)
2312		REQUIRE(*name == NULL);
2313	if (type == dns_rdatatype_any) {
2314		REQUIRE(rdataset == NULL);
2315	} else {
2316		if (rdataset != NULL)
2317			REQUIRE(*rdataset == NULL);
2318	}
2319
2320	result = findname(&foundname, target,
2321			  &msg->sections[section]);
2322
2323	if (result == ISC_R_NOTFOUND)
2324		return (DNS_R_NXDOMAIN);
2325	else if (result != ISC_R_SUCCESS)
2326		return (result);
2327
2328	if (name != NULL)
2329		*name = foundname;
2330
2331	/*
2332	 * And now look for the type.
2333	 */
2334	if (type == dns_rdatatype_any)
2335		return (ISC_R_SUCCESS);
2336
2337	result = dns_message_findtype(foundname, type, covers, rdataset);
2338	if (result == ISC_R_NOTFOUND)
2339		return (DNS_R_NXRRSET);
2340
2341	return (result);
2342}
2343
2344void
2345dns_message_movename(dns_message_t *msg, dns_name_t *name,
2346		     dns_section_t fromsection,
2347		     dns_section_t tosection)
2348{
2349	REQUIRE(msg != NULL);
2350	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2351	REQUIRE(name != NULL);
2352	REQUIRE(VALID_NAMED_SECTION(fromsection));
2353	REQUIRE(VALID_NAMED_SECTION(tosection));
2354
2355	/*
2356	 * Unlink the name from the old section
2357	 */
2358	ISC_LIST_UNLINK(msg->sections[fromsection], name, link);
2359	ISC_LIST_APPEND(msg->sections[tosection], name, link);
2360}
2361
2362void
2363dns_message_addname(dns_message_t *msg, dns_name_t *name,
2364		    dns_section_t section)
2365{
2366	REQUIRE(msg != NULL);
2367	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2368	REQUIRE(name != NULL);
2369	REQUIRE(VALID_NAMED_SECTION(section));
2370
2371	ISC_LIST_APPEND(msg->sections[section], name, link);
2372}
2373
2374void
2375dns_message_removename(dns_message_t *msg, dns_name_t *name,
2376		       dns_section_t section)
2377{
2378	REQUIRE(msg != NULL);
2379	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2380	REQUIRE(name != NULL);
2381	REQUIRE(VALID_NAMED_SECTION(section));
2382
2383	ISC_LIST_UNLINK(msg->sections[section], name, link);
2384}
2385
2386isc_result_t
2387dns_message_gettempname(dns_message_t *msg, dns_name_t **item) {
2388	REQUIRE(DNS_MESSAGE_VALID(msg));
2389	REQUIRE(item != NULL && *item == NULL);
2390
2391	*item = isc_mempool_get(msg->namepool);
2392	if (*item == NULL)
2393		return (ISC_R_NOMEMORY);
2394	dns_name_init(*item, NULL);
2395
2396	return (ISC_R_SUCCESS);
2397}
2398
2399isc_result_t
2400dns_message_gettempoffsets(dns_message_t *msg, dns_offsets_t **item) {
2401	REQUIRE(DNS_MESSAGE_VALID(msg));
2402	REQUIRE(item != NULL && *item == NULL);
2403
2404	*item = newoffsets(msg);
2405	if (*item == NULL)
2406		return (ISC_R_NOMEMORY);
2407
2408	return (ISC_R_SUCCESS);
2409}
2410
2411isc_result_t
2412dns_message_gettemprdata(dns_message_t *msg, dns_rdata_t **item) {
2413	REQUIRE(DNS_MESSAGE_VALID(msg));
2414	REQUIRE(item != NULL && *item == NULL);
2415
2416	*item = newrdata(msg);
2417	if (*item == NULL)
2418		return (ISC_R_NOMEMORY);
2419
2420	return (ISC_R_SUCCESS);
2421}
2422
2423isc_result_t
2424dns_message_gettemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2425	REQUIRE(DNS_MESSAGE_VALID(msg));
2426	REQUIRE(item != NULL && *item == NULL);
2427
2428	*item = isc_mempool_get(msg->rdspool);
2429	if (*item == NULL)
2430		return (ISC_R_NOMEMORY);
2431
2432	dns_rdataset_init(*item);
2433
2434	return (ISC_R_SUCCESS);
2435}
2436
2437isc_result_t
2438dns_message_gettemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2439	REQUIRE(DNS_MESSAGE_VALID(msg));
2440	REQUIRE(item != NULL && *item == NULL);
2441
2442	*item = newrdatalist(msg);
2443	if (*item == NULL)
2444		return (ISC_R_NOMEMORY);
2445
2446	return (ISC_R_SUCCESS);
2447}
2448
2449void
2450dns_message_puttempname(dns_message_t *msg, dns_name_t **item) {
2451	REQUIRE(DNS_MESSAGE_VALID(msg));
2452	REQUIRE(item != NULL && *item != NULL);
2453
2454	if (dns_name_dynamic(*item))
2455		dns_name_free(*item, msg->mctx);
2456	isc_mempool_put(msg->namepool, *item);
2457	*item = NULL;
2458}
2459
2460void
2461dns_message_puttemprdata(dns_message_t *msg, dns_rdata_t **item) {
2462	REQUIRE(DNS_MESSAGE_VALID(msg));
2463	REQUIRE(item != NULL && *item != NULL);
2464
2465	releaserdata(msg, *item);
2466	*item = NULL;
2467}
2468
2469void
2470dns_message_puttemprdataset(dns_message_t *msg, dns_rdataset_t **item) {
2471	REQUIRE(DNS_MESSAGE_VALID(msg));
2472	REQUIRE(item != NULL && *item != NULL);
2473
2474	REQUIRE(!dns_rdataset_isassociated(*item));
2475	isc_mempool_put(msg->rdspool, *item);
2476	*item = NULL;
2477}
2478
2479void
2480dns_message_puttemprdatalist(dns_message_t *msg, dns_rdatalist_t **item) {
2481	REQUIRE(DNS_MESSAGE_VALID(msg));
2482	REQUIRE(item != NULL && *item != NULL);
2483
2484	releaserdatalist(msg, *item);
2485	*item = NULL;
2486}
2487
2488isc_result_t
2489dns_message_peekheader(isc_buffer_t *source, dns_messageid_t *idp,
2490		       unsigned int *flagsp)
2491{
2492	isc_region_t r;
2493	isc_buffer_t buffer;
2494	dns_messageid_t id;
2495	unsigned int flags;
2496
2497	REQUIRE(source != NULL);
2498
2499	buffer = *source;
2500
2501	isc_buffer_remainingregion(&buffer, &r);
2502	if (r.length < DNS_MESSAGE_HEADERLEN)
2503		return (ISC_R_UNEXPECTEDEND);
2504
2505	id = isc_buffer_getuint16(&buffer);
2506	flags = isc_buffer_getuint16(&buffer);
2507	flags &= DNS_MESSAGE_FLAG_MASK;
2508
2509	if (flagsp != NULL)
2510		*flagsp = flags;
2511	if (idp != NULL)
2512		*idp = id;
2513
2514	return (ISC_R_SUCCESS);
2515}
2516
2517isc_result_t
2518dns_message_reply(dns_message_t *msg, isc_boolean_t want_question_section) {
2519	unsigned int clear_after;
2520	isc_result_t result;
2521
2522	REQUIRE(DNS_MESSAGE_VALID(msg));
2523	REQUIRE((msg->flags & DNS_MESSAGEFLAG_QR) == 0);
2524
2525	if (!msg->header_ok)
2526		return (DNS_R_FORMERR);
2527	if (msg->opcode != dns_opcode_query &&
2528	    msg->opcode != dns_opcode_notify)
2529		want_question_section = ISC_FALSE;
2530	if (msg->opcode == dns_opcode_update)
2531		clear_after = DNS_SECTION_PREREQUISITE;
2532	else if (want_question_section) {
2533		if (!msg->question_ok)
2534			return (DNS_R_FORMERR);
2535		clear_after = DNS_SECTION_ANSWER;
2536	} else
2537		clear_after = DNS_SECTION_QUESTION;
2538	msg->from_to_wire = DNS_MESSAGE_INTENTRENDER;
2539	msgresetnames(msg, clear_after);
2540	msgresetopt(msg);
2541	msgresetsigs(msg, ISC_TRUE);
2542	msginitprivate(msg);
2543	/*
2544	 * We now clear most flags and then set QR, ensuring that the
2545	 * reply's flags will be in a reasonable state.
2546	 */
2547	msg->flags &= DNS_MESSAGE_REPLYPRESERVE;
2548	msg->flags |= DNS_MESSAGEFLAG_QR;
2549
2550	/*
2551	 * This saves the query TSIG status, if the query was signed, and
2552	 * reserves space in the reply for the TSIG.
2553	 */
2554	if (msg->tsigkey != NULL) {
2555		unsigned int otherlen = 0;
2556		msg->querytsigstatus = msg->tsigstatus;
2557		msg->tsigstatus = dns_rcode_noerror;
2558		if (msg->querytsigstatus == dns_tsigerror_badtime)
2559			otherlen = 6;
2560		msg->sig_reserved = spacefortsig(msg->tsigkey, otherlen);
2561		result = dns_message_renderreserve(msg, msg->sig_reserved);
2562		if (result != ISC_R_SUCCESS) {
2563			msg->sig_reserved = 0;
2564			return (result);
2565		}
2566	}
2567	if (msg->saved.base != NULL) {
2568		msg->query.base = msg->saved.base;
2569		msg->query.length = msg->saved.length;
2570		msg->free_query = msg->free_saved;
2571		msg->saved.base = NULL;
2572		msg->saved.length = 0;
2573		msg->free_saved = 0;
2574	}
2575
2576	return (ISC_R_SUCCESS);
2577}
2578
2579dns_rdataset_t *
2580dns_message_getopt(dns_message_t *msg) {
2581
2582	/*
2583	 * Get the OPT record for 'msg'.
2584	 */
2585
2586	REQUIRE(DNS_MESSAGE_VALID(msg));
2587
2588	return (msg->opt);
2589}
2590
2591isc_result_t
2592dns_message_setopt(dns_message_t *msg, dns_rdataset_t *opt) {
2593	isc_result_t result;
2594	dns_rdata_t rdata = DNS_RDATA_INIT;
2595
2596	/*
2597	 * Set the OPT record for 'msg'.
2598	 */
2599
2600	/*
2601	 * The space required for an OPT record is:
2602	 *
2603	 *	1 byte for the name
2604	 *	2 bytes for the type
2605	 *	2 bytes for the class
2606	 *	4 bytes for the ttl
2607	 *	2 bytes for the rdata length
2608	 * ---------------------------------
2609	 *     11 bytes
2610	 *
2611	 * plus the length of the rdata.
2612	 */
2613
2614	REQUIRE(DNS_MESSAGE_VALID(msg));
2615	REQUIRE(opt->type == dns_rdatatype_opt);
2616	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2617	REQUIRE(msg->state == DNS_SECTION_ANY);
2618
2619	msgresetopt(msg);
2620
2621	result = dns_rdataset_first(opt);
2622	if (result != ISC_R_SUCCESS)
2623		goto cleanup;
2624	dns_rdataset_current(opt, &rdata);
2625	msg->opt_reserved = 11 + rdata.length;
2626	result = dns_message_renderreserve(msg, msg->opt_reserved);
2627	if (result != ISC_R_SUCCESS) {
2628		msg->opt_reserved = 0;
2629		goto cleanup;
2630	}
2631
2632	msg->opt = opt;
2633
2634	return (ISC_R_SUCCESS);
2635
2636 cleanup:
2637	dns_message_puttemprdataset(msg, &opt);
2638	return (result);
2639
2640}
2641
2642dns_rdataset_t *
2643dns_message_gettsig(dns_message_t *msg, dns_name_t **owner) {
2644
2645	/*
2646	 * Get the TSIG record and owner for 'msg'.
2647	 */
2648
2649	REQUIRE(DNS_MESSAGE_VALID(msg));
2650	REQUIRE(owner == NULL || *owner == NULL);
2651
2652	if (owner != NULL)
2653		*owner = msg->tsigname;
2654	return (msg->tsig);
2655}
2656
2657isc_result_t
2658dns_message_settsigkey(dns_message_t *msg, dns_tsigkey_t *key) {
2659	isc_result_t result;
2660
2661	/*
2662	 * Set the TSIG key for 'msg'
2663	 */
2664
2665	REQUIRE(DNS_MESSAGE_VALID(msg));
2666	REQUIRE(msg->state == DNS_SECTION_ANY);
2667
2668	if (key == NULL && msg->tsigkey != NULL) {
2669		if (msg->sig_reserved != 0) {
2670			dns_message_renderrelease(msg, msg->sig_reserved);
2671			msg->sig_reserved = 0;
2672		}
2673		dns_tsigkey_detach(&msg->tsigkey);
2674	}
2675	if (key != NULL) {
2676		REQUIRE(msg->tsigkey == NULL && msg->sig0key == NULL);
2677		dns_tsigkey_attach(key, &msg->tsigkey);
2678		if (msg->from_to_wire == DNS_MESSAGE_INTENTRENDER) {
2679			msg->sig_reserved = spacefortsig(msg->tsigkey, 0);
2680			result = dns_message_renderreserve(msg,
2681							   msg->sig_reserved);
2682			if (result != ISC_R_SUCCESS) {
2683				dns_tsigkey_detach(&msg->tsigkey);
2684				msg->sig_reserved = 0;
2685				return (result);
2686			}
2687		}
2688	}
2689	return (ISC_R_SUCCESS);
2690}
2691
2692dns_tsigkey_t *
2693dns_message_gettsigkey(dns_message_t *msg) {
2694
2695	/*
2696	 * Get the TSIG key for 'msg'
2697	 */
2698
2699	REQUIRE(DNS_MESSAGE_VALID(msg));
2700
2701	return (msg->tsigkey);
2702}
2703
2704isc_result_t
2705dns_message_setquerytsig(dns_message_t *msg, isc_buffer_t *querytsig) {
2706	dns_rdata_t *rdata = NULL;
2707	dns_rdatalist_t *list = NULL;
2708	dns_rdataset_t *set = NULL;
2709	isc_buffer_t *buf = NULL;
2710	isc_region_t r;
2711	isc_result_t result;
2712
2713	REQUIRE(DNS_MESSAGE_VALID(msg));
2714	REQUIRE(msg->querytsig == NULL);
2715
2716	if (querytsig == NULL)
2717		return (ISC_R_SUCCESS);
2718
2719	result = dns_message_gettemprdata(msg, &rdata);
2720	if (result != ISC_R_SUCCESS)
2721		goto cleanup;
2722
2723	result = dns_message_gettemprdatalist(msg, &list);
2724	if (result != ISC_R_SUCCESS)
2725		goto cleanup;
2726	result = dns_message_gettemprdataset(msg, &set);
2727	if (result != ISC_R_SUCCESS)
2728		goto cleanup;
2729
2730	isc_buffer_usedregion(querytsig, &r);
2731	result = isc_buffer_allocate(msg->mctx, &buf, r.length);
2732	if (result != ISC_R_SUCCESS)
2733		goto cleanup;
2734	isc_buffer_putmem(buf, r.base, r.length);
2735	isc_buffer_usedregion(buf, &r);
2736	dns_rdata_init(rdata);
2737	dns_rdata_fromregion(rdata, dns_rdataclass_any, dns_rdatatype_tsig, &r);
2738	dns_message_takebuffer(msg, &buf);
2739	ISC_LIST_INIT(list->rdata);
2740	ISC_LIST_APPEND(list->rdata, rdata, link);
2741	result = dns_rdatalist_tordataset(list, set);
2742	if (result != ISC_R_SUCCESS)
2743		goto cleanup;
2744
2745	msg->querytsig = set;
2746
2747	return (result);
2748
2749 cleanup:
2750	if (rdata != NULL)
2751		dns_message_puttemprdata(msg, &rdata);
2752	if (list != NULL)
2753		dns_message_puttemprdatalist(msg, &list);
2754	if (set != NULL)
2755		dns_message_puttemprdataset(msg, &set);
2756	return (ISC_R_NOMEMORY);
2757}
2758
2759isc_result_t
2760dns_message_getquerytsig(dns_message_t *msg, isc_mem_t *mctx,
2761			 isc_buffer_t **querytsig) {
2762	isc_result_t result;
2763	dns_rdata_t rdata = DNS_RDATA_INIT;
2764	isc_region_t r;
2765
2766	REQUIRE(DNS_MESSAGE_VALID(msg));
2767	REQUIRE(mctx != NULL);
2768	REQUIRE(querytsig != NULL && *querytsig == NULL);
2769
2770	if (msg->tsig == NULL)
2771		return (ISC_R_SUCCESS);
2772
2773	result = dns_rdataset_first(msg->tsig);
2774	if (result != ISC_R_SUCCESS)
2775		return (result);
2776	dns_rdataset_current(msg->tsig, &rdata);
2777	dns_rdata_toregion(&rdata, &r);
2778
2779	result = isc_buffer_allocate(mctx, querytsig, r.length);
2780	if (result != ISC_R_SUCCESS)
2781		return (result);
2782	isc_buffer_putmem(*querytsig, r.base, r.length);
2783	return (ISC_R_SUCCESS);
2784}
2785
2786dns_rdataset_t *
2787dns_message_getsig0(dns_message_t *msg, dns_name_t **owner) {
2788
2789	/*
2790	 * Get the SIG(0) record for 'msg'.
2791	 */
2792
2793	REQUIRE(DNS_MESSAGE_VALID(msg));
2794	REQUIRE(owner == NULL || *owner == NULL);
2795
2796	if (msg->sig0 != NULL && owner != NULL) {
2797		/* If dns_message_getsig0 is called on a rendered message
2798		 * after the SIG(0) has been applied, we need to return the
2799		 * root name, not NULL.
2800		 */
2801		if (msg->sig0name == NULL)
2802			*owner = dns_rootname;
2803		else
2804			*owner = msg->sig0name;
2805	}
2806	return (msg->sig0);
2807}
2808
2809isc_result_t
2810dns_message_setsig0key(dns_message_t *msg, dst_key_t *key) {
2811	isc_region_t r;
2812	unsigned int x;
2813	isc_result_t result;
2814
2815	/*
2816	 * Set the SIG(0) key for 'msg'
2817	 */
2818
2819	/*
2820	 * The space required for an SIG(0) record is:
2821	 *
2822	 *	1 byte for the name
2823	 *	2 bytes for the type
2824	 *	2 bytes for the class
2825	 *	4 bytes for the ttl
2826	 *	2 bytes for the type covered
2827	 *	1 byte for the algorithm
2828	 *	1 bytes for the labels
2829	 *	4 bytes for the original ttl
2830	 *	4 bytes for the signature expiration
2831	 *	4 bytes for the signature inception
2832	 *	2 bytes for the key tag
2833	 *	n bytes for the signer's name
2834	 *	x bytes for the signature
2835	 * ---------------------------------
2836	 *     27 + n + x bytes
2837	 */
2838	REQUIRE(DNS_MESSAGE_VALID(msg));
2839	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTRENDER);
2840	REQUIRE(msg->state == DNS_SECTION_ANY);
2841
2842	if (key != NULL) {
2843		REQUIRE(msg->sig0key == NULL && msg->tsigkey == NULL);
2844		dns_name_toregion(dst_key_name(key), &r);
2845		result = dst_key_sigsize(key, &x);
2846		if (result != ISC_R_SUCCESS) {
2847			msg->sig_reserved = 0;
2848			return (result);
2849		}
2850		msg->sig_reserved = 27 + r.length + x;
2851		result = dns_message_renderreserve(msg, msg->sig_reserved);
2852		if (result != ISC_R_SUCCESS) {
2853			msg->sig_reserved = 0;
2854			return (result);
2855		}
2856		msg->sig0key = key;
2857	}
2858	return (ISC_R_SUCCESS);
2859}
2860
2861dst_key_t *
2862dns_message_getsig0key(dns_message_t *msg) {
2863
2864	/*
2865	 * Get the SIG(0) key for 'msg'
2866	 */
2867
2868	REQUIRE(DNS_MESSAGE_VALID(msg));
2869
2870	return (msg->sig0key);
2871}
2872
2873void
2874dns_message_takebuffer(dns_message_t *msg, isc_buffer_t **buffer) {
2875	REQUIRE(DNS_MESSAGE_VALID(msg));
2876	REQUIRE(buffer != NULL);
2877	REQUIRE(ISC_BUFFER_VALID(*buffer));
2878
2879	ISC_LIST_APPEND(msg->cleanup, *buffer, link);
2880	*buffer = NULL;
2881}
2882
2883isc_result_t
2884dns_message_signer(dns_message_t *msg, dns_name_t *signer) {
2885	isc_result_t result = ISC_R_SUCCESS;
2886	dns_rdata_t rdata = DNS_RDATA_INIT;
2887
2888	REQUIRE(DNS_MESSAGE_VALID(msg));
2889	REQUIRE(signer != NULL);
2890	REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE);
2891
2892	if (msg->tsig == NULL && msg->sig0 == NULL)
2893		return (ISC_R_NOTFOUND);
2894
2895	if (msg->verify_attempted == 0)
2896		return (DNS_R_NOTVERIFIEDYET);
2897
2898	if (!dns_name_hasbuffer(signer)) {
2899		isc_buffer_t *dynbuf = NULL;
2900		result = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
2901		if (result != ISC_R_SUCCESS)
2902			return (result);
2903		dns_name_setbuffer(signer, dynbuf);
2904		dns_message_takebuffer(msg, &dynbuf);
2905	}
2906
2907	if (msg->sig0 != NULL) {
2908		dns_rdata_sig_t sig;
2909
2910		result = dns_rdataset_first(msg->sig0);
2911		INSIST(result == ISC_R_SUCCESS);
2912		dns_rdataset_current(msg->sig0, &rdata);
2913
2914		result = dns_rdata_tostruct(&rdata, &sig, NULL);
2915		if (result != ISC_R_SUCCESS)
2916			return (result);
2917
2918		if (msg->verified_sig && msg->sig0status == dns_rcode_noerror)
2919			result = ISC_R_SUCCESS;
2920		else
2921			result = DNS_R_SIGINVALID;
2922		dns_name_clone(&sig.signer, signer);
2923		dns_rdata_freestruct(&sig);
2924	} else {
2925		dns_name_t *identity;
2926		dns_rdata_any_tsig_t tsig;
2927
2928		result = dns_rdataset_first(msg->tsig);
2929		INSIST(result == ISC_R_SUCCESS);
2930		dns_rdataset_current(msg->tsig, &rdata);
2931
2932		result = dns_rdata_tostruct(&rdata, &tsig, NULL);
2933		if (msg->tsigstatus != dns_rcode_noerror)
2934			result = DNS_R_TSIGVERIFYFAILURE;
2935		else if (tsig.error != dns_rcode_noerror)
2936			result = DNS_R_TSIGERRORSET;
2937		else
2938			result = ISC_R_SUCCESS;
2939		dns_rdata_freestruct(&tsig);
2940
2941		if (msg->tsigkey == NULL) {
2942			/*
2943			 * If msg->tsigstatus & tsig.error are both
2944			 * dns_rcode_noerror, the message must have been
2945			 * verified, which means msg->tsigkey will be
2946			 * non-NULL.
2947			 */
2948			INSIST(result != ISC_R_SUCCESS);
2949		} else {
2950			identity = dns_tsigkey_identity(msg->tsigkey);
2951			if (identity == NULL) {
2952				if (result == ISC_R_SUCCESS)
2953					result = DNS_R_NOIDENTITY;
2954				identity = &msg->tsigkey->name;
2955			}
2956			dns_name_clone(identity, signer);
2957		}
2958	}
2959
2960	return (result);
2961}
2962
2963void
2964dns_message_resetsig(dns_message_t *msg) {
2965	REQUIRE(DNS_MESSAGE_VALID(msg));
2966	msg->verified_sig = 0;
2967	msg->verify_attempted = 0;
2968	msg->tsigstatus = dns_rcode_noerror;
2969	msg->sig0status = dns_rcode_noerror;
2970	msg->timeadjust = 0;
2971	if (msg->tsigkey != NULL) {
2972		dns_tsigkey_detach(&msg->tsigkey);
2973		msg->tsigkey = NULL;
2974	}
2975}
2976
2977isc_result_t
2978dns_message_rechecksig(dns_message_t *msg, dns_view_t *view) {
2979	dns_message_resetsig(msg);
2980	return (dns_message_checksig(msg, view));
2981}
2982
2983#ifdef SKAN_MSG_DEBUG
2984void
2985dns_message_dumpsig(dns_message_t *msg, char *txt1) {
2986	dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
2987	dns_rdata_any_tsig_t querytsig;
2988	isc_result_t result;
2989
2990	if (msg->tsig != NULL) {
2991		result = dns_rdataset_first(msg->tsig);
2992		RUNTIME_CHECK(result == ISC_R_SUCCESS);
2993		dns_rdataset_current(msg->tsig, &querytsigrdata);
2994		result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
2995		RUNTIME_CHECK(result == ISC_R_SUCCESS);
2996		hexdump(txt1, "TSIG", querytsig.signature,
2997			querytsig.siglen);
2998	}
2999
3000	if (msg->querytsig != NULL) {
3001		result = dns_rdataset_first(msg->querytsig);
3002		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3003		dns_rdataset_current(msg->querytsig, &querytsigrdata);
3004		result = dns_rdata_tostruct(&querytsigrdata, &querytsig, NULL);
3005		RUNTIME_CHECK(result == ISC_R_SUCCESS);
3006		hexdump(txt1, "QUERYTSIG", querytsig.signature,
3007			querytsig.siglen);
3008	}
3009}
3010#endif
3011
3012isc_result_t
3013dns_message_checksig(dns_message_t *msg, dns_view_t *view) {
3014	isc_buffer_t b, msgb;
3015
3016	REQUIRE(DNS_MESSAGE_VALID(msg));
3017
3018	if (msg->tsigkey == NULL && msg->tsig == NULL && msg->sig0 == NULL)
3019		return (ISC_R_SUCCESS);
3020
3021	INSIST(msg->saved.base != NULL);
3022	isc_buffer_init(&msgb, msg->saved.base, msg->saved.length);
3023	isc_buffer_add(&msgb, msg->saved.length);
3024	if (msg->tsigkey != NULL || msg->tsig != NULL) {
3025#ifdef SKAN_MSG_DEBUG
3026		dns_message_dumpsig(msg, "dns_message_checksig#1");
3027#endif
3028		if (view != NULL)
3029			return (dns_view_checksig(view, &msgb, msg));
3030		else
3031			return (dns_tsig_verify(&msgb, msg, NULL, NULL));
3032	} else {
3033		dns_rdata_t rdata = DNS_RDATA_INIT;
3034		dns_rdata_sig_t sig;
3035		dns_rdataset_t keyset;
3036		isc_result_t result;
3037
3038		result = dns_rdataset_first(msg->sig0);
3039		INSIST(result == ISC_R_SUCCESS);
3040		dns_rdataset_current(msg->sig0, &rdata);
3041
3042		/*
3043		 * This can occur when the message is a dynamic update, since
3044		 * the rdata length checking is relaxed.  This should not
3045		 * happen in a well-formed message, since the SIG(0) is only
3046		 * looked for in the additional section, and the dynamic update
3047		 * meta-records are in the prerequisite and update sections.
3048		 */
3049		if (rdata.length == 0)
3050			return (ISC_R_UNEXPECTEDEND);
3051
3052		result = dns_rdata_tostruct(&rdata, &sig, msg->mctx);
3053		if (result != ISC_R_SUCCESS)
3054			return (result);
3055
3056		dns_rdataset_init(&keyset);
3057		if (view == NULL)
3058			return (DNS_R_KEYUNAUTHORIZED);
3059		result = dns_view_simplefind(view, &sig.signer,
3060					     dns_rdatatype_key /* SIG(0) */,
3061					     0, 0, ISC_FALSE, &keyset, NULL);
3062
3063		if (result != ISC_R_SUCCESS) {
3064			/* XXXBEW Should possibly create a fetch here */
3065			result = DNS_R_KEYUNAUTHORIZED;
3066			goto freesig;
3067		} else if (keyset.trust < dns_trust_secure) {
3068			/* XXXBEW Should call a validator here */
3069			result = DNS_R_KEYUNAUTHORIZED;
3070			goto freesig;
3071		}
3072		result = dns_rdataset_first(&keyset);
3073		INSIST(result == ISC_R_SUCCESS);
3074		for (;
3075		     result == ISC_R_SUCCESS;
3076		     result = dns_rdataset_next(&keyset))
3077		{
3078			dst_key_t *key = NULL;
3079
3080			dns_rdata_reset(&rdata);
3081			dns_rdataset_current(&keyset, &rdata);
3082			isc_buffer_init(&b, rdata.data, rdata.length);
3083			isc_buffer_add(&b, rdata.length);
3084
3085			result = dst_key_fromdns(&sig.signer, rdata.rdclass,
3086						 &b, view->mctx, &key);
3087			if (result != ISC_R_SUCCESS)
3088				continue;
3089			if (dst_key_alg(key) != sig.algorithm ||
3090			    dst_key_id(key) != sig.keyid ||
3091			    !(dst_key_proto(key) == DNS_KEYPROTO_DNSSEC ||
3092			      dst_key_proto(key) == DNS_KEYPROTO_ANY))
3093			{
3094				dst_key_free(&key);
3095				continue;
3096			}
3097			result = dns_dnssec_verifymessage(&msgb, msg, key);
3098			dst_key_free(&key);
3099			if (result == ISC_R_SUCCESS)
3100				break;
3101		}
3102		if (result == ISC_R_NOMORE)
3103			result = DNS_R_KEYUNAUTHORIZED;
3104
3105 freesig:
3106		if (dns_rdataset_isassociated(&keyset))
3107			dns_rdataset_disassociate(&keyset);
3108		dns_rdata_freestruct(&sig);
3109		return (result);
3110	}
3111}
3112
3113isc_result_t
3114dns_message_sectiontotext(dns_message_t *msg, dns_section_t section,
3115			  const dns_master_style_t *style,
3116			  dns_messagetextflag_t flags,
3117			  isc_buffer_t *target) {
3118	dns_name_t *name, empty_name;
3119	dns_rdataset_t *rdataset;
3120	isc_result_t result;
3121	isc_boolean_t seensoa = ISC_FALSE;
3122
3123	REQUIRE(DNS_MESSAGE_VALID(msg));
3124	REQUIRE(target != NULL);
3125	REQUIRE(VALID_SECTION(section));
3126
3127	if (ISC_LIST_EMPTY(msg->sections[section]))
3128		return (ISC_R_SUCCESS);
3129
3130	if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0) {
3131		ADD_STRING(target, ";; ");
3132		if (msg->opcode != dns_opcode_update) {
3133			ADD_STRING(target, sectiontext[section]);
3134		} else {
3135			ADD_STRING(target, updsectiontext[section]);
3136		}
3137		ADD_STRING(target, " SECTION:\n");
3138	}
3139
3140	dns_name_init(&empty_name, NULL);
3141	result = dns_message_firstname(msg, section);
3142	if (result != ISC_R_SUCCESS) {
3143		return (result);
3144	}
3145	do {
3146		name = NULL;
3147		dns_message_currentname(msg, section, &name);
3148		for (rdataset = ISC_LIST_HEAD(name->list);
3149		     rdataset != NULL;
3150		     rdataset = ISC_LIST_NEXT(rdataset, link)) {
3151			if (section == DNS_SECTION_ANSWER &&
3152			    rdataset->type == dns_rdatatype_soa) {
3153				if ((flags & DNS_MESSAGETEXTFLAG_OMITSOA) != 0)
3154					continue;
3155				if (seensoa &&
3156				    (flags & DNS_MESSAGETEXTFLAG_ONESOA) != 0)
3157					continue;
3158				seensoa = ISC_TRUE;
3159			}
3160			if (section == DNS_SECTION_QUESTION) {
3161				ADD_STRING(target, ";");
3162				result = dns_master_questiontotext(name,
3163								   rdataset,
3164								   style,
3165								   target);
3166			} else {
3167				result = dns_master_rdatasettotext(name,
3168								   rdataset,
3169								   style,
3170								   target);
3171			}
3172			if (result != ISC_R_SUCCESS)
3173				return (result);
3174		}
3175		result = dns_message_nextname(msg, section);
3176	} while (result == ISC_R_SUCCESS);
3177	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3178	    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3179		ADD_STRING(target, "\n");
3180	if (result == ISC_R_NOMORE)
3181		result = ISC_R_SUCCESS;
3182	return (result);
3183}
3184
3185isc_result_t
3186dns_message_pseudosectiontotext(dns_message_t *msg,
3187				dns_pseudosection_t section,
3188				const dns_master_style_t *style,
3189				dns_messagetextflag_t flags,
3190				isc_buffer_t *target) {
3191	dns_rdataset_t *ps = NULL;
3192	dns_name_t *name = NULL;
3193	isc_result_t result;
3194	char buf[sizeof("1234567890")];
3195	isc_uint32_t mbz;
3196	dns_rdata_t rdata;
3197	isc_buffer_t optbuf;
3198	isc_uint16_t optcode, optlen;
3199	unsigned char *optdata;
3200
3201	REQUIRE(DNS_MESSAGE_VALID(msg));
3202	REQUIRE(target != NULL);
3203	REQUIRE(VALID_PSEUDOSECTION(section));
3204
3205	switch (section) {
3206	case DNS_PSEUDOSECTION_OPT:
3207		ps = dns_message_getopt(msg);
3208		if (ps == NULL)
3209			return (ISC_R_SUCCESS);
3210		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3211			ADD_STRING(target, ";; OPT PSEUDOSECTION:\n");
3212		ADD_STRING(target, "; EDNS: version: ");
3213		snprintf(buf, sizeof(buf), "%u",
3214			 (unsigned int)((ps->ttl & 0x00ff0000) >> 16));
3215		ADD_STRING(target, buf);
3216		ADD_STRING(target, ", flags:");
3217		if ((ps->ttl & DNS_MESSAGEEXTFLAG_DO) != 0)
3218			ADD_STRING(target, " do");
3219		mbz = ps->ttl & 0xffff;
3220		mbz &= ~DNS_MESSAGEEXTFLAG_DO;		/* Known Flags. */
3221		if (mbz != 0) {
3222			ADD_STRING(target, "; MBZ: ");
3223			snprintf(buf, sizeof(buf), "%.4x ", mbz);
3224			ADD_STRING(target, buf);
3225			ADD_STRING(target, ", udp: ");
3226		} else
3227			ADD_STRING(target, "; udp: ");
3228		snprintf(buf, sizeof(buf), "%u\n", (unsigned int)ps->rdclass);
3229		ADD_STRING(target, buf);
3230
3231		result = dns_rdataset_first(ps);
3232		if (result != ISC_R_SUCCESS)
3233			return (ISC_R_SUCCESS);
3234
3235		/* Print EDNS info, if any */
3236		dns_rdata_init(&rdata);
3237		dns_rdataset_current(ps, &rdata);
3238
3239		isc_buffer_init(&optbuf, rdata.data, rdata.length);
3240		isc_buffer_add(&optbuf, rdata.length);
3241		while (isc_buffer_remaininglength(&optbuf) != 0) {
3242			INSIST(isc_buffer_remaininglength(&optbuf) >= 4U);
3243			optcode = isc_buffer_getuint16(&optbuf);
3244			optlen = isc_buffer_getuint16(&optbuf);
3245			INSIST(isc_buffer_remaininglength(&optbuf) >= optlen);
3246
3247			if (optcode == DNS_OPT_NSID) {
3248				ADD_STRING(target, "; NSID");
3249			} else {
3250				ADD_STRING(target, "; OPT=");
3251				sprintf(buf, "%u", optcode);
3252				ADD_STRING(target, buf);
3253			}
3254
3255			if (optlen != 0) {
3256				int i;
3257				ADD_STRING(target, ": ");
3258
3259				optdata = isc_buffer_current(&optbuf);
3260				for (i = 0; i < optlen; i++) {
3261					sprintf(buf, "%02x ", optdata[i]);
3262					ADD_STRING(target, buf);
3263				}
3264				for (i = 0; i < optlen; i++) {
3265					ADD_STRING(target, " (");
3266					if (isprint(optdata[i]))
3267						isc_buffer_putmem(target,
3268								  &optdata[i],
3269								  1);
3270					else
3271						isc_buffer_putstr(target, ".");
3272					ADD_STRING(target, ")");
3273				}
3274				isc_buffer_forward(&optbuf, optlen);
3275			}
3276			ADD_STRING(target, "\n");
3277		}
3278		return (ISC_R_SUCCESS);
3279	case DNS_PSEUDOSECTION_TSIG:
3280		ps = dns_message_gettsig(msg, &name);
3281		if (ps == NULL)
3282			return (ISC_R_SUCCESS);
3283		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3284			ADD_STRING(target, ";; TSIG PSEUDOSECTION:\n");
3285		result = dns_master_rdatasettotext(name, ps, style, target);
3286		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3287		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3288			ADD_STRING(target, "\n");
3289		return (result);
3290	case DNS_PSEUDOSECTION_SIG0:
3291		ps = dns_message_getsig0(msg, &name);
3292		if (ps == NULL)
3293			return (ISC_R_SUCCESS);
3294		if ((flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3295			ADD_STRING(target, ";; SIG0 PSEUDOSECTION:\n");
3296		result = dns_master_rdatasettotext(name, ps, style, target);
3297		if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0 &&
3298		    (flags & DNS_MESSAGETEXTFLAG_NOCOMMENTS) == 0)
3299			ADD_STRING(target, "\n");
3300		return (result);
3301	}
3302	return (ISC_R_UNEXPECTED);
3303}
3304
3305isc_result_t
3306dns_message_totext(dns_message_t *msg, const dns_master_style_t *style,
3307		   dns_messagetextflag_t flags, isc_buffer_t *target) {
3308	char buf[sizeof("1234567890")];
3309	isc_result_t result;
3310
3311	REQUIRE(DNS_MESSAGE_VALID(msg));
3312	REQUIRE(target != NULL);
3313
3314	if ((flags & DNS_MESSAGETEXTFLAG_NOHEADERS) == 0) {
3315		ADD_STRING(target, ";; ->>HEADER<<- opcode: ");
3316		ADD_STRING(target, opcodetext[msg->opcode]);
3317		ADD_STRING(target, ", status: ");
3318		if (msg->rcode < (sizeof(rcodetext)/sizeof(rcodetext[0]))) {
3319			ADD_STRING(target, rcodetext[msg->rcode]);
3320		} else {
3321			snprintf(buf, sizeof(buf), "%4u", msg->rcode);
3322			ADD_STRING(target, buf);
3323		}
3324		ADD_STRING(target, ", id: ");
3325		snprintf(buf, sizeof(buf), "%6u", msg->id);
3326		ADD_STRING(target, buf);
3327		ADD_STRING(target, "\n;; flags:");
3328		if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
3329			ADD_STRING(target, " qr");
3330		if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0)
3331			ADD_STRING(target, " aa");
3332		if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0)
3333			ADD_STRING(target, " tc");
3334		if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0)
3335			ADD_STRING(target, " rd");
3336		if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0)
3337			ADD_STRING(target, " ra");
3338		if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0)
3339			ADD_STRING(target, " ad");
3340		if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0)
3341			ADD_STRING(target, " cd");
3342		/*
3343		 * The final unnamed flag must be zero.
3344		 */
3345		if ((msg->flags & 0x0040U) != 0)
3346			ADD_STRING(target, "; MBZ: 0x4");
3347		if (msg->opcode != dns_opcode_update) {
3348			ADD_STRING(target, "; QUESTION: ");
3349		} else {
3350			ADD_STRING(target, "; ZONE: ");
3351		}
3352		snprintf(buf, sizeof(buf), "%1u",
3353			 msg->counts[DNS_SECTION_QUESTION]);
3354		ADD_STRING(target, buf);
3355		if (msg->opcode != dns_opcode_update) {
3356			ADD_STRING(target, ", ANSWER: ");
3357		} else {
3358			ADD_STRING(target, ", PREREQ: ");
3359		}
3360		snprintf(buf, sizeof(buf), "%1u",
3361			 msg->counts[DNS_SECTION_ANSWER]);
3362		ADD_STRING(target, buf);
3363		if (msg->opcode != dns_opcode_update) {
3364			ADD_STRING(target, ", AUTHORITY: ");
3365		} else {
3366			ADD_STRING(target, ", UPDATE: ");
3367		}
3368		snprintf(buf, sizeof(buf), "%1u",
3369			msg->counts[DNS_SECTION_AUTHORITY]);
3370		ADD_STRING(target, buf);
3371		ADD_STRING(target, ", ADDITIONAL: ");
3372		snprintf(buf, sizeof(buf), "%1u",
3373			msg->counts[DNS_SECTION_ADDITIONAL]);
3374		ADD_STRING(target, buf);
3375		ADD_STRING(target, "\n");
3376	}
3377	result = dns_message_pseudosectiontotext(msg,
3378						 DNS_PSEUDOSECTION_OPT,
3379						 style, flags, target);
3380	if (result != ISC_R_SUCCESS)
3381		return (result);
3382
3383	result = dns_message_sectiontotext(msg, DNS_SECTION_QUESTION,
3384					   style, flags, target);
3385	if (result != ISC_R_SUCCESS)
3386		return (result);
3387	result = dns_message_sectiontotext(msg, DNS_SECTION_ANSWER,
3388					   style, flags, target);
3389	if (result != ISC_R_SUCCESS)
3390		return (result);
3391	result = dns_message_sectiontotext(msg, DNS_SECTION_AUTHORITY,
3392					   style, flags, target);
3393	if (result != ISC_R_SUCCESS)
3394		return (result);
3395	result = dns_message_sectiontotext(msg, DNS_SECTION_ADDITIONAL,
3396					   style, flags, target);
3397	if (result != ISC_R_SUCCESS)
3398		return (result);
3399
3400	result = dns_message_pseudosectiontotext(msg,
3401						 DNS_PSEUDOSECTION_TSIG,
3402						 style, flags, target);
3403	if (result != ISC_R_SUCCESS)
3404		return (result);
3405
3406	result = dns_message_pseudosectiontotext(msg,
3407						 DNS_PSEUDOSECTION_SIG0,
3408						 style, flags, target);
3409	if (result != ISC_R_SUCCESS)
3410		return (result);
3411
3412	return (ISC_R_SUCCESS);
3413}
3414
3415isc_region_t *
3416dns_message_getrawmessage(dns_message_t *msg) {
3417	REQUIRE(DNS_MESSAGE_VALID(msg));
3418	return (&msg->saved);
3419}
3420
3421void
3422dns_message_setsortorder(dns_message_t *msg, dns_rdatasetorderfunc_t order,
3423			 const void *order_arg)
3424{
3425	REQUIRE(DNS_MESSAGE_VALID(msg));
3426	msg->order = order;
3427	msg->order_arg = order_arg;
3428}
3429
3430void
3431dns_message_settimeadjust(dns_message_t *msg, int timeadjust) {
3432	REQUIRE(DNS_MESSAGE_VALID(msg));
3433	msg->timeadjust = timeadjust;
3434}
3435
3436int
3437dns_message_gettimeadjust(dns_message_t *msg) {
3438	REQUIRE(DNS_MESSAGE_VALID(msg));
3439	return (msg->timeadjust);
3440}
3441
3442isc_result_t
3443dns_opcode_totext(dns_opcode_t opcode, isc_buffer_t *target) {
3444
3445	REQUIRE(opcode < 16);
3446
3447	if (isc_buffer_availablelength(target) < strlen(opcodetext[opcode]))
3448		return (ISC_R_NOSPACE);
3449	isc_buffer_putstr(target, opcodetext[opcode]);
3450	return (ISC_R_SUCCESS);
3451}
3452