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