rdataset.c revision 225361
1135446Strhodes/*
2223812Sdougb * Copyright (C) 2004-2011  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1999-2003  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18225361Sdougb/* $Id: rdataset.c,v 1.86.148.4 2011-06-08 23:02:42 each Exp $ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <stdlib.h>
25135446Strhodes
26135446Strhodes#include <isc/buffer.h>
27135446Strhodes#include <isc/mem.h>
28135446Strhodes#include <isc/random.h>
29135446Strhodes#include <isc/util.h>
30135446Strhodes
31135446Strhodes#include <dns/name.h>
32135446Strhodes#include <dns/ncache.h>
33135446Strhodes#include <dns/rdata.h>
34135446Strhodes#include <dns/rdataset.h>
35135446Strhodes#include <dns/compress.h>
36135446Strhodes
37222395Sdougbstatic const char *trustnames[] = {
38222395Sdougb	"none",
39222395Sdougb	"pending-additional",
40222395Sdougb	"pending-answer",
41222395Sdougb	"additional",
42222395Sdougb	"glue",
43222395Sdougb	"answer",
44222395Sdougb	"authauthority",
45222395Sdougb	"authanswer",
46222395Sdougb	"secure",
47222395Sdougb	"local" /* aka ultimate */
48222395Sdougb};
49222395Sdougb
50222395Sdougbconst char *
51222395Sdougbdns_trust_totext(dns_trust_t trust) {
52222395Sdougb	if (trust >= sizeof(trustnames)/sizeof(*trustnames))
53222395Sdougb		return ("bad");
54222395Sdougb	return (trustnames[trust]);
55222395Sdougb}
56222395Sdougb
57135446Strhodesvoid
58135446Strhodesdns_rdataset_init(dns_rdataset_t *rdataset) {
59135446Strhodes
60135446Strhodes	/*
61135446Strhodes	 * Make 'rdataset' a valid, disassociated rdataset.
62135446Strhodes	 */
63135446Strhodes
64135446Strhodes	REQUIRE(rdataset != NULL);
65135446Strhodes
66135446Strhodes	rdataset->magic = DNS_RDATASET_MAGIC;
67135446Strhodes	rdataset->methods = NULL;
68135446Strhodes	ISC_LINK_INIT(rdataset, link);
69135446Strhodes	rdataset->rdclass = 0;
70135446Strhodes	rdataset->type = 0;
71135446Strhodes	rdataset->ttl = 0;
72135446Strhodes	rdataset->trust = 0;
73135446Strhodes	rdataset->covers = 0;
74135446Strhodes	rdataset->attributes = 0;
75135446Strhodes	rdataset->count = ISC_UINT32_MAX;
76135446Strhodes	rdataset->private1 = NULL;
77135446Strhodes	rdataset->private2 = NULL;
78135446Strhodes	rdataset->private3 = NULL;
79135446Strhodes	rdataset->privateuint4 = 0;
80135446Strhodes	rdataset->private5 = NULL;
81135446Strhodes	rdataset->private6 = NULL;
82193149Sdougb	rdataset->resign = 0;
83135446Strhodes}
84135446Strhodes
85135446Strhodesvoid
86135446Strhodesdns_rdataset_invalidate(dns_rdataset_t *rdataset) {
87135446Strhodes
88135446Strhodes	/*
89135446Strhodes	 * Invalidate 'rdataset'.
90135446Strhodes	 */
91135446Strhodes
92135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
93135446Strhodes	REQUIRE(rdataset->methods == NULL);
94135446Strhodes
95135446Strhodes	rdataset->magic = 0;
96135446Strhodes	ISC_LINK_INIT(rdataset, link);
97135446Strhodes	rdataset->rdclass = 0;
98135446Strhodes	rdataset->type = 0;
99135446Strhodes	rdataset->ttl = 0;
100135446Strhodes	rdataset->trust = 0;
101135446Strhodes	rdataset->covers = 0;
102135446Strhodes	rdataset->attributes = 0;
103135446Strhodes	rdataset->count = ISC_UINT32_MAX;
104135446Strhodes	rdataset->private1 = NULL;
105135446Strhodes	rdataset->private2 = NULL;
106135446Strhodes	rdataset->private3 = NULL;
107135446Strhodes	rdataset->privateuint4 = 0;
108135446Strhodes	rdataset->private5 = NULL;
109135446Strhodes}
110135446Strhodes
111135446Strhodesvoid
112135446Strhodesdns_rdataset_disassociate(dns_rdataset_t *rdataset) {
113135446Strhodes
114135446Strhodes	/*
115135446Strhodes	 * Disassociate 'rdataset' from its rdata, allowing it to be reused.
116135446Strhodes	 */
117135446Strhodes
118135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
119135446Strhodes	REQUIRE(rdataset->methods != NULL);
120135446Strhodes
121135446Strhodes	(rdataset->methods->disassociate)(rdataset);
122135446Strhodes	rdataset->methods = NULL;
123135446Strhodes	ISC_LINK_INIT(rdataset, link);
124135446Strhodes	rdataset->rdclass = 0;
125135446Strhodes	rdataset->type = 0;
126135446Strhodes	rdataset->ttl = 0;
127135446Strhodes	rdataset->trust = 0;
128135446Strhodes	rdataset->covers = 0;
129135446Strhodes	rdataset->attributes = 0;
130135446Strhodes	rdataset->count = ISC_UINT32_MAX;
131135446Strhodes	rdataset->private1 = NULL;
132135446Strhodes	rdataset->private2 = NULL;
133135446Strhodes	rdataset->private3 = NULL;
134135446Strhodes	rdataset->privateuint4 = 0;
135135446Strhodes	rdataset->private5 = NULL;
136135446Strhodes	rdataset->private6 = NULL;
137135446Strhodes}
138135446Strhodes
139135446Strhodesisc_boolean_t
140135446Strhodesdns_rdataset_isassociated(dns_rdataset_t *rdataset) {
141135446Strhodes	/*
142135446Strhodes	 * Is 'rdataset' associated?
143135446Strhodes	 */
144135446Strhodes
145135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
146135446Strhodes
147135446Strhodes	if (rdataset->methods != NULL)
148135446Strhodes		return (ISC_TRUE);
149135446Strhodes
150135446Strhodes	return (ISC_FALSE);
151135446Strhodes}
152135446Strhodes
153135446Strhodesstatic void
154135446Strhodesquestion_disassociate(dns_rdataset_t *rdataset) {
155135446Strhodes	UNUSED(rdataset);
156135446Strhodes}
157135446Strhodes
158135446Strhodesstatic isc_result_t
159135446Strhodesquestion_cursor(dns_rdataset_t *rdataset) {
160135446Strhodes	UNUSED(rdataset);
161193149Sdougb
162135446Strhodes	return (ISC_R_NOMORE);
163135446Strhodes}
164135446Strhodes
165135446Strhodesstatic void
166135446Strhodesquestion_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
167135446Strhodes	/*
168135446Strhodes	 * This routine should never be called.
169135446Strhodes	 */
170135446Strhodes	UNUSED(rdataset);
171135446Strhodes	UNUSED(rdata);
172193149Sdougb
173135446Strhodes	REQUIRE(0);
174135446Strhodes}
175135446Strhodes
176135446Strhodesstatic void
177135446Strhodesquestion_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
178135446Strhodes	*target = *source;
179135446Strhodes}
180135446Strhodes
181135446Strhodesstatic unsigned int
182135446Strhodesquestion_count(dns_rdataset_t *rdataset) {
183135446Strhodes	/*
184135446Strhodes	 * This routine should never be called.
185135446Strhodes	 */
186135446Strhodes	UNUSED(rdataset);
187135446Strhodes	REQUIRE(0);
188135446Strhodes
189135446Strhodes	return (0);
190135446Strhodes}
191135446Strhodes
192135446Strhodesstatic dns_rdatasetmethods_t question_methods = {
193135446Strhodes	question_disassociate,
194135446Strhodes	question_cursor,
195135446Strhodes	question_cursor,
196135446Strhodes	question_current,
197135446Strhodes	question_clone,
198135446Strhodes	question_count,
199135446Strhodes	NULL,
200170222Sdougb	NULL,
201170222Sdougb	NULL,
202170222Sdougb	NULL,
203193149Sdougb	NULL,
204193149Sdougb	NULL,
205205292Sdougb	NULL,
206205292Sdougb	NULL,
207135446Strhodes	NULL
208135446Strhodes};
209135446Strhodes
210135446Strhodesvoid
211135446Strhodesdns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass,
212135446Strhodes			  dns_rdatatype_t type)
213135446Strhodes{
214135446Strhodes
215135446Strhodes	/*
216135446Strhodes	 * Make 'rdataset' a valid, associated, question rdataset, with a
217135446Strhodes	 * question class of 'rdclass' and type 'type'.
218135446Strhodes	 */
219135446Strhodes
220135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
221135446Strhodes	REQUIRE(rdataset->methods == NULL);
222135446Strhodes
223135446Strhodes	rdataset->methods = &question_methods;
224135446Strhodes	rdataset->rdclass = rdclass;
225135446Strhodes	rdataset->type = type;
226135446Strhodes	rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
227135446Strhodes}
228135446Strhodes
229135446Strhodesunsigned int
230135446Strhodesdns_rdataset_count(dns_rdataset_t *rdataset) {
231135446Strhodes
232135446Strhodes	/*
233135446Strhodes	 * Return the number of records in 'rdataset'.
234135446Strhodes	 */
235135446Strhodes
236135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
237135446Strhodes	REQUIRE(rdataset->methods != NULL);
238135446Strhodes
239135446Strhodes	return ((rdataset->methods->count)(rdataset));
240135446Strhodes}
241135446Strhodes
242135446Strhodesvoid
243135446Strhodesdns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
244135446Strhodes
245135446Strhodes	/*
246135446Strhodes	 * Make 'target' refer to the same rdataset as 'source'.
247135446Strhodes	 */
248135446Strhodes
249135446Strhodes	REQUIRE(DNS_RDATASET_VALID(source));
250135446Strhodes	REQUIRE(source->methods != NULL);
251135446Strhodes	REQUIRE(DNS_RDATASET_VALID(target));
252135446Strhodes	REQUIRE(target->methods == NULL);
253135446Strhodes
254135446Strhodes	(source->methods->clone)(source, target);
255135446Strhodes}
256135446Strhodes
257135446Strhodesisc_result_t
258135446Strhodesdns_rdataset_first(dns_rdataset_t *rdataset) {
259135446Strhodes
260135446Strhodes	/*
261135446Strhodes	 * Move the rdata cursor to the first rdata in the rdataset (if any).
262135446Strhodes	 */
263135446Strhodes
264135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
265135446Strhodes	REQUIRE(rdataset->methods != NULL);
266135446Strhodes
267135446Strhodes	return ((rdataset->methods->first)(rdataset));
268135446Strhodes}
269135446Strhodes
270135446Strhodesisc_result_t
271135446Strhodesdns_rdataset_next(dns_rdataset_t *rdataset) {
272135446Strhodes
273135446Strhodes	/*
274135446Strhodes	 * Move the rdata cursor to the next rdata in the rdataset (if any).
275135446Strhodes	 */
276135446Strhodes
277135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
278135446Strhodes	REQUIRE(rdataset->methods != NULL);
279135446Strhodes
280135446Strhodes	return ((rdataset->methods->next)(rdataset));
281135446Strhodes}
282135446Strhodes
283135446Strhodesvoid
284135446Strhodesdns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
285135446Strhodes
286135446Strhodes	/*
287135446Strhodes	 * Make 'rdata' refer to the current rdata.
288135446Strhodes	 */
289135446Strhodes
290135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
291135446Strhodes	REQUIRE(rdataset->methods != NULL);
292135446Strhodes
293135446Strhodes	(rdataset->methods->current)(rdataset, rdata);
294135446Strhodes}
295135446Strhodes
296135446Strhodes#define MAX_SHUFFLE	32
297135446Strhodes#define WANT_FIXED(r)	(((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
298135446Strhodes#define WANT_RANDOM(r)	(((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
299135446Strhodes
300135446Strhodesstruct towire_sort {
301135446Strhodes	int key;
302135446Strhodes	dns_rdata_t *rdata;
303135446Strhodes};
304135446Strhodes
305135446Strhodesstatic int
306135446Strhodestowire_compare(const void *av, const void *bv) {
307135446Strhodes	const struct towire_sort *a = (const struct towire_sort *) av;
308135446Strhodes	const struct towire_sort *b = (const struct towire_sort *) bv;
309135446Strhodes	return (a->key - b->key);
310135446Strhodes}
311135446Strhodes
312135446Strhodesstatic isc_result_t
313165071Sdougbtowiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
314135446Strhodes	     dns_compress_t *cctx, isc_buffer_t *target,
315165071Sdougb	     dns_rdatasetorderfunc_t order, const void *order_arg,
316135446Strhodes	     isc_boolean_t partial, unsigned int options,
317135446Strhodes	     unsigned int *countp, void **state)
318135446Strhodes{
319135446Strhodes	dns_rdata_t rdata = DNS_RDATA_INIT;
320135446Strhodes	isc_region_t r;
321135446Strhodes	isc_result_t result;
322225361Sdougb	unsigned int i, count = 0, added, choice;
323135446Strhodes	isc_buffer_t savedbuffer, rdlen, rrbuffer;
324135446Strhodes	unsigned int headlen;
325135446Strhodes	isc_boolean_t question = ISC_FALSE;
326135446Strhodes	isc_boolean_t shuffle = ISC_FALSE;
327135446Strhodes	dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE];
328135446Strhodes	struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE];
329135446Strhodes
330135446Strhodes	UNUSED(state);
331135446Strhodes
332135446Strhodes	/*
333135446Strhodes	 * Convert 'rdataset' to wire format, compressing names as specified
334135446Strhodes	 * in cctx, and storing the result in 'target'.
335135446Strhodes	 */
336135446Strhodes
337135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
338135446Strhodes	REQUIRE(countp != NULL);
339135446Strhodes	REQUIRE((order == NULL) == (order_arg == NULL));
340135446Strhodes	REQUIRE(cctx != NULL && cctx->mctx != NULL);
341135446Strhodes
342135446Strhodes	if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
343135446Strhodes		question = ISC_TRUE;
344135446Strhodes		count = 1;
345135446Strhodes		result = dns_rdataset_first(rdataset);
346135446Strhodes		INSIST(result == ISC_R_NOMORE);
347223812Sdougb	} else if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
348135446Strhodes		/*
349135446Strhodes		 * This is a negative caching rdataset.
350135446Strhodes		 */
351135446Strhodes		unsigned int ncache_opts = 0;
352135446Strhodes		if ((options & DNS_RDATASETTOWIRE_OMITDNSSEC) != 0)
353135446Strhodes			ncache_opts |= DNS_NCACHETOWIRE_OMITDNSSEC;
354135446Strhodes		return (dns_ncache_towire(rdataset, cctx, target, ncache_opts,
355135446Strhodes					  countp));
356135446Strhodes	} else {
357135446Strhodes		count = (rdataset->methods->count)(rdataset);
358135446Strhodes		result = dns_rdataset_first(rdataset);
359135446Strhodes		if (result == ISC_R_NOMORE)
360135446Strhodes			return (ISC_R_SUCCESS);
361135446Strhodes		if (result != ISC_R_SUCCESS)
362135446Strhodes			return (result);
363135446Strhodes	}
364135446Strhodes
365135446Strhodes	/*
366193149Sdougb	 * Do we want to shuffle this answer?
367135446Strhodes	 */
368135446Strhodes	if (!question && count > 1 &&
369135446Strhodes	    (!WANT_FIXED(rdataset) || order != NULL) &&
370135446Strhodes	    rdataset->type != dns_rdatatype_rrsig)
371135446Strhodes		shuffle = ISC_TRUE;
372135446Strhodes
373135446Strhodes	if (shuffle && count > MAX_SHUFFLE) {
374135446Strhodes		shuffled = isc_mem_get(cctx->mctx, count * sizeof(*shuffled));
375135446Strhodes		sorted = isc_mem_get(cctx->mctx, count * sizeof(*sorted));
376135446Strhodes		if (shuffled == NULL || sorted == NULL)
377135446Strhodes			shuffle = ISC_FALSE;
378135446Strhodes	} else {
379135446Strhodes		shuffled = shuffled_fixed;
380135446Strhodes		sorted = sorted_fixed;
381135446Strhodes	}
382135446Strhodes
383135446Strhodes	if (shuffle) {
384135446Strhodes		/*
385135446Strhodes		 * First we get handles to all of the rdata.
386135446Strhodes		 */
387135446Strhodes		i = 0;
388135446Strhodes		do {
389135446Strhodes			INSIST(i < count);
390135446Strhodes			dns_rdata_init(&shuffled[i]);
391135446Strhodes			dns_rdataset_current(rdataset, &shuffled[i]);
392135446Strhodes			i++;
393135446Strhodes			result = dns_rdataset_next(rdataset);
394135446Strhodes		} while (result == ISC_R_SUCCESS);
395135446Strhodes		if (result != ISC_R_NOMORE)
396135446Strhodes			goto cleanup;
397135446Strhodes		INSIST(i == count);
398135446Strhodes
399135446Strhodes		/*
400135446Strhodes		 * Now we shuffle.
401135446Strhodes		 */
402135446Strhodes		if (WANT_FIXED(rdataset)) {
403135446Strhodes			/*
404135446Strhodes			 * 'Fixed' order.
405135446Strhodes			 */
406135446Strhodes			INSIST(order != NULL);
407135446Strhodes			for (i = 0; i < count; i++) {
408135446Strhodes				sorted[i].key = (*order)(&shuffled[i],
409135446Strhodes							 order_arg);
410135446Strhodes				sorted[i].rdata = &shuffled[i];
411135446Strhodes			}
412135446Strhodes		} else if (WANT_RANDOM(rdataset)) {
413135446Strhodes			/*
414135446Strhodes			 * 'Random' order.
415135446Strhodes			 */
416135446Strhodes			for (i = 0; i < count; i++) {
417135446Strhodes				dns_rdata_t rdata;
418135446Strhodes				isc_uint32_t val;
419135446Strhodes
420135446Strhodes				isc_random_get(&val);
421135446Strhodes				choice = i + (val % (count - i));
422135446Strhodes				rdata = shuffled[i];
423135446Strhodes				shuffled[i] = shuffled[choice];
424135446Strhodes				shuffled[choice] = rdata;
425135446Strhodes				if (order != NULL)
426135446Strhodes					sorted[i].key = (*order)(&shuffled[i],
427135446Strhodes								 order_arg);
428135446Strhodes				else
429135446Strhodes					sorted[i].key = 0; /* Unused */
430135446Strhodes				sorted[i].rdata = &shuffled[i];
431135446Strhodes			}
432135446Strhodes		} else {
433135446Strhodes			/*
434135446Strhodes			 * "Cyclic" order.
435135446Strhodes			 */
436135446Strhodes			isc_uint32_t val;
437135446Strhodes			unsigned int j;
438135446Strhodes
439135446Strhodes			val = rdataset->count;
440135446Strhodes			if (val == ISC_UINT32_MAX)
441135446Strhodes				isc_random_get(&val);
442135446Strhodes			j = val % count;
443135446Strhodes			for (i = 0; i < count; i++) {
444135446Strhodes				if (order != NULL)
445135446Strhodes					sorted[j].key = (*order)(&shuffled[i],
446135446Strhodes								 order_arg);
447135446Strhodes				else
448135446Strhodes					sorted[j].key = 0; /* Unused */
449135446Strhodes				sorted[j].rdata = &shuffled[i];
450135446Strhodes				j++;
451135446Strhodes				if (j == count)
452135446Strhodes					j = 0; /* Wrap around. */
453135446Strhodes			}
454135446Strhodes		}
455135446Strhodes
456135446Strhodes		/*
457135446Strhodes		 * Sorted order.
458135446Strhodes		 */
459135446Strhodes		if (order != NULL)
460135446Strhodes			qsort(sorted, count, sizeof(sorted[0]),
461135446Strhodes			      towire_compare);
462135446Strhodes	}
463135446Strhodes
464135446Strhodes	savedbuffer = *target;
465135446Strhodes	i = 0;
466135446Strhodes	added = 0;
467135446Strhodes
468135446Strhodes	do {
469135446Strhodes		/*
470135446Strhodes		 * Copy out the name, type, class, ttl.
471135446Strhodes		 */
472193149Sdougb
473135446Strhodes		rrbuffer = *target;
474135446Strhodes		dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
475135446Strhodes		result = dns_name_towire(owner_name, cctx, target);
476135446Strhodes		if (result != ISC_R_SUCCESS)
477135446Strhodes			goto rollback;
478135446Strhodes		headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
479135446Strhodes		if (!question)
480135446Strhodes			headlen += sizeof(dns_ttl_t)
481135446Strhodes				+ 2;  /* XXX 2 for rdata len */
482135446Strhodes		isc_buffer_availableregion(target, &r);
483135446Strhodes		if (r.length < headlen) {
484135446Strhodes			result = ISC_R_NOSPACE;
485135446Strhodes			goto rollback;
486135446Strhodes		}
487135446Strhodes		isc_buffer_putuint16(target, rdataset->type);
488135446Strhodes		isc_buffer_putuint16(target, rdataset->rdclass);
489135446Strhodes		if (!question) {
490135446Strhodes			isc_buffer_putuint32(target, rdataset->ttl);
491135446Strhodes
492135446Strhodes			/*
493135446Strhodes			 * Save space for rdlen.
494135446Strhodes			 */
495135446Strhodes			rdlen = *target;
496135446Strhodes			isc_buffer_add(target, 2);
497135446Strhodes
498135446Strhodes			/*
499135446Strhodes			 * Copy out the rdata
500135446Strhodes			 */
501135446Strhodes			if (shuffle)
502135446Strhodes				rdata = *(sorted[i].rdata);
503135446Strhodes			else {
504135446Strhodes				dns_rdata_reset(&rdata);
505135446Strhodes				dns_rdataset_current(rdataset, &rdata);
506135446Strhodes			}
507135446Strhodes			result = dns_rdata_towire(&rdata, cctx, target);
508135446Strhodes			if (result != ISC_R_SUCCESS)
509135446Strhodes				goto rollback;
510135446Strhodes			INSIST((target->used >= rdlen.used + 2) &&
511135446Strhodes			       (target->used - rdlen.used - 2 < 65536));
512135446Strhodes			isc_buffer_putuint16(&rdlen,
513135446Strhodes					     (isc_uint16_t)(target->used -
514135446Strhodes							    rdlen.used - 2));
515135446Strhodes			added++;
516135446Strhodes		}
517135446Strhodes
518135446Strhodes		if (shuffle) {
519135446Strhodes			i++;
520135446Strhodes			if (i == count)
521135446Strhodes				result = ISC_R_NOMORE;
522135446Strhodes			else
523135446Strhodes				result = ISC_R_SUCCESS;
524135446Strhodes		} else {
525135446Strhodes			result = dns_rdataset_next(rdataset);
526135446Strhodes		}
527135446Strhodes	} while (result == ISC_R_SUCCESS);
528135446Strhodes
529135446Strhodes	if (result != ISC_R_NOMORE)
530135446Strhodes		goto rollback;
531135446Strhodes
532135446Strhodes	*countp += count;
533135446Strhodes
534135446Strhodes	result = ISC_R_SUCCESS;
535135446Strhodes	goto cleanup;
536135446Strhodes
537135446Strhodes rollback:
538135446Strhodes	if (partial && result == ISC_R_NOSPACE) {
539135446Strhodes		INSIST(rrbuffer.used < 65536);
540135446Strhodes		dns_compress_rollback(cctx, (isc_uint16_t)rrbuffer.used);
541135446Strhodes		*countp += added;
542135446Strhodes		*target = rrbuffer;
543135446Strhodes		goto cleanup;
544135446Strhodes	}
545135446Strhodes	INSIST(savedbuffer.used < 65536);
546135446Strhodes	dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
547135446Strhodes	*countp = 0;
548135446Strhodes	*target = savedbuffer;
549135446Strhodes
550135446Strhodes cleanup:
551135446Strhodes	if (sorted != NULL && sorted != sorted_fixed)
552135446Strhodes		isc_mem_put(cctx->mctx, sorted, count * sizeof(*sorted));
553135446Strhodes	if (shuffled != NULL && shuffled != shuffled_fixed)
554135446Strhodes		isc_mem_put(cctx->mctx, shuffled, count * sizeof(*shuffled));
555135446Strhodes	return (result);
556135446Strhodes}
557135446Strhodes
558135446Strhodesisc_result_t
559135446Strhodesdns_rdataset_towiresorted(dns_rdataset_t *rdataset,
560165071Sdougb			  const dns_name_t *owner_name,
561135446Strhodes			  dns_compress_t *cctx,
562135446Strhodes			  isc_buffer_t *target,
563135446Strhodes			  dns_rdatasetorderfunc_t order,
564165071Sdougb			  const void *order_arg,
565135446Strhodes			  unsigned int options,
566135446Strhodes			  unsigned int *countp)
567135446Strhodes{
568135446Strhodes	return (towiresorted(rdataset, owner_name, cctx, target,
569135446Strhodes			     order, order_arg, ISC_FALSE, options,
570135446Strhodes			     countp, NULL));
571135446Strhodes}
572135446Strhodes
573135446Strhodesisc_result_t
574135446Strhodesdns_rdataset_towirepartial(dns_rdataset_t *rdataset,
575165071Sdougb			   const dns_name_t *owner_name,
576135446Strhodes			   dns_compress_t *cctx,
577135446Strhodes			   isc_buffer_t *target,
578135446Strhodes			   dns_rdatasetorderfunc_t order,
579165071Sdougb			   const void *order_arg,
580135446Strhodes			   unsigned int options,
581135446Strhodes			   unsigned int *countp,
582135446Strhodes			   void **state)
583135446Strhodes{
584135446Strhodes	REQUIRE(state == NULL);	/* XXX remove when implemented */
585135446Strhodes	return (towiresorted(rdataset, owner_name, cctx, target,
586135446Strhodes			     order, order_arg, ISC_TRUE, options,
587135446Strhodes			     countp, state));
588135446Strhodes}
589135446Strhodes
590135446Strhodesisc_result_t
591135446Strhodesdns_rdataset_towire(dns_rdataset_t *rdataset,
592135446Strhodes		    dns_name_t *owner_name,
593135446Strhodes		    dns_compress_t *cctx,
594135446Strhodes		    isc_buffer_t *target,
595135446Strhodes		    unsigned int options,
596135446Strhodes		    unsigned int *countp)
597135446Strhodes{
598135446Strhodes	return (towiresorted(rdataset, owner_name, cctx, target,
599135446Strhodes			     NULL, NULL, ISC_FALSE, options, countp, NULL));
600135446Strhodes}
601135446Strhodes
602135446Strhodesisc_result_t
603135446Strhodesdns_rdataset_additionaldata(dns_rdataset_t *rdataset,
604135446Strhodes			    dns_additionaldatafunc_t add, void *arg)
605135446Strhodes{
606135446Strhodes	dns_rdata_t rdata = DNS_RDATA_INIT;
607135446Strhodes	isc_result_t result;
608135446Strhodes
609135446Strhodes	/*
610135446Strhodes	 * For each rdata in rdataset, call 'add' for each name and type in the
611135446Strhodes	 * rdata which is subject to additional section processing.
612135446Strhodes	 */
613135446Strhodes
614135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
615135446Strhodes	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
616135446Strhodes
617135446Strhodes	result = dns_rdataset_first(rdataset);
618135446Strhodes	if (result != ISC_R_SUCCESS)
619135446Strhodes		return (result);
620135446Strhodes
621135446Strhodes	do {
622135446Strhodes		dns_rdataset_current(rdataset, &rdata);
623135446Strhodes		result = dns_rdata_additionaldata(&rdata, add, arg);
624135446Strhodes		if (result == ISC_R_SUCCESS)
625135446Strhodes			result = dns_rdataset_next(rdataset);
626135446Strhodes		dns_rdata_reset(&rdata);
627135446Strhodes	} while (result == ISC_R_SUCCESS);
628135446Strhodes
629135446Strhodes	if (result != ISC_R_NOMORE)
630135446Strhodes		return (result);
631135446Strhodes
632135446Strhodes	return (ISC_R_SUCCESS);
633135446Strhodes}
634135446Strhodes
635135446Strhodesisc_result_t
636135446Strhodesdns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
637135446Strhodes
638135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
639135446Strhodes	REQUIRE(rdataset->methods != NULL);
640135446Strhodes	if (rdataset->methods->addnoqname == NULL)
641135446Strhodes		return (ISC_R_NOTIMPLEMENTED);
642135446Strhodes	return((rdataset->methods->addnoqname)(rdataset, name));
643135446Strhodes}
644135446Strhodes
645135446Strhodesisc_result_t
646135446Strhodesdns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
647193149Sdougb			dns_rdataset_t *neg, dns_rdataset_t *negsig)
648135446Strhodes{
649135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
650135446Strhodes	REQUIRE(rdataset->methods != NULL);
651135446Strhodes
652135446Strhodes	if (rdataset->methods->getnoqname == NULL)
653135446Strhodes		return (ISC_R_NOTIMPLEMENTED);
654193149Sdougb	return((rdataset->methods->getnoqname)(rdataset, name, neg, negsig));
655135446Strhodes}
656170222Sdougb
657193149Sdougbisc_result_t
658193149Sdougbdns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) {
659193149Sdougb
660193149Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
661193149Sdougb	REQUIRE(rdataset->methods != NULL);
662193149Sdougb	if (rdataset->methods->addclosest == NULL)
663193149Sdougb		return (ISC_R_NOTIMPLEMENTED);
664193149Sdougb	return((rdataset->methods->addclosest)(rdataset, name));
665193149Sdougb}
666193149Sdougb
667193149Sdougbisc_result_t
668193149Sdougbdns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
669193149Sdougb			dns_rdataset_t *neg, dns_rdataset_t *negsig)
670193149Sdougb{
671193149Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
672193149Sdougb	REQUIRE(rdataset->methods != NULL);
673193149Sdougb
674193149Sdougb	if (rdataset->methods->getclosest == NULL)
675193149Sdougb		return (ISC_R_NOTIMPLEMENTED);
676193149Sdougb	return((rdataset->methods->getclosest)(rdataset, name, neg, negsig));
677193149Sdougb}
678193149Sdougb
679170222Sdougb/*
680170222Sdougb * Additional cache stuff
681170222Sdougb */
682170222Sdougbisc_result_t
683170222Sdougbdns_rdataset_getadditional(dns_rdataset_t *rdataset,
684170222Sdougb			   dns_rdatasetadditional_t type,
685170222Sdougb			   dns_rdatatype_t qtype,
686170222Sdougb			   dns_acache_t *acache,
687170222Sdougb			   dns_zone_t **zonep,
688170222Sdougb			   dns_db_t **dbp,
689170222Sdougb			   dns_dbversion_t **versionp,
690170222Sdougb			   dns_dbnode_t **nodep,
691170222Sdougb			   dns_name_t *fname,
692170222Sdougb			   dns_message_t *msg,
693170222Sdougb			   isc_stdtime_t now)
694170222Sdougb{
695170222Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
696170222Sdougb	REQUIRE(rdataset->methods != NULL);
697170222Sdougb	REQUIRE(zonep == NULL || *zonep == NULL);
698170222Sdougb	REQUIRE(dbp != NULL && *dbp == NULL);
699170222Sdougb	REQUIRE(versionp != NULL && *versionp == NULL);
700170222Sdougb	REQUIRE(nodep != NULL && *nodep == NULL);
701170222Sdougb	REQUIRE(fname != NULL);
702170222Sdougb	REQUIRE(msg != NULL);
703170222Sdougb
704170222Sdougb	if (acache != NULL && rdataset->methods->getadditional != NULL) {
705170222Sdougb		return ((rdataset->methods->getadditional)(rdataset, type,
706170222Sdougb							   qtype, acache,
707170222Sdougb							   zonep, dbp,
708170222Sdougb							   versionp, nodep,
709170222Sdougb							   fname, msg, now));
710170222Sdougb	}
711170222Sdougb
712170222Sdougb	return (ISC_R_FAILURE);
713170222Sdougb}
714170222Sdougb
715170222Sdougbisc_result_t
716170222Sdougbdns_rdataset_setadditional(dns_rdataset_t *rdataset,
717170222Sdougb			   dns_rdatasetadditional_t type,
718170222Sdougb			   dns_rdatatype_t qtype,
719170222Sdougb			   dns_acache_t *acache,
720170222Sdougb			   dns_zone_t *zone,
721170222Sdougb			   dns_db_t *db,
722170222Sdougb			   dns_dbversion_t *version,
723170222Sdougb			   dns_dbnode_t *node,
724170222Sdougb			   dns_name_t *fname)
725170222Sdougb{
726170222Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
727170222Sdougb	REQUIRE(rdataset->methods != NULL);
728170222Sdougb
729170222Sdougb	if (acache != NULL && rdataset->methods->setadditional != NULL) {
730170222Sdougb		return ((rdataset->methods->setadditional)(rdataset, type,
731170222Sdougb							   qtype, acache, zone,
732170222Sdougb							   db, version,
733170222Sdougb							   node, fname));
734170222Sdougb	}
735170222Sdougb
736170222Sdougb	return (ISC_R_FAILURE);
737170222Sdougb}
738170222Sdougb
739170222Sdougbisc_result_t
740170222Sdougbdns_rdataset_putadditional(dns_acache_t *acache,
741170222Sdougb			   dns_rdataset_t *rdataset,
742170222Sdougb			   dns_rdatasetadditional_t type,
743170222Sdougb			   dns_rdatatype_t qtype)
744170222Sdougb{
745170222Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
746170222Sdougb	REQUIRE(rdataset->methods != NULL);
747170222Sdougb
748170222Sdougb	if (acache != NULL && rdataset->methods->putadditional != NULL) {
749170222Sdougb		return ((rdataset->methods->putadditional)(acache, rdataset,
750170222Sdougb							   type, qtype));
751170222Sdougb	}
752170222Sdougb
753170222Sdougb	return (ISC_R_FAILURE);
754170222Sdougb}
755170222Sdougb
756205292Sdougbvoid
757205292Sdougbdns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
758205292Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
759205292Sdougb	REQUIRE(rdataset->methods != NULL);
760205292Sdougb
761205292Sdougb	if (rdataset->methods->settrust != NULL)
762205292Sdougb		(rdataset->methods->settrust)(rdataset, trust);
763205292Sdougb	else
764205292Sdougb		rdataset->trust = trust;
765205292Sdougb}
766205292Sdougb
767205292Sdougbvoid
768205292Sdougbdns_rdataset_expire(dns_rdataset_t *rdataset) {
769205292Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
770205292Sdougb	REQUIRE(rdataset->methods != NULL);
771205292Sdougb
772205292Sdougb	if (rdataset->methods->expire != NULL)
773205292Sdougb		(rdataset->methods->expire)(rdataset);
774205292Sdougb}
775