rdataset.c revision 222395
1135446Strhodes/*
2205292Sdougb * Copyright (C) 2004-2010  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
18222395Sdougb/* $Id: rdataset.c,v 1.82.50.4.6.1 2011-05-27 00:19:19 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;
322135446Strhodes	unsigned int i, count, 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	count = 0;
343135446Strhodes	if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
344135446Strhodes		question = ISC_TRUE;
345135446Strhodes		count = 1;
346135446Strhodes		result = dns_rdataset_first(rdataset);
347135446Strhodes		INSIST(result == ISC_R_NOMORE);
348135446Strhodes	} else if (rdataset->type == 0) {
349135446Strhodes		/*
350135446Strhodes		 * This is a negative caching rdataset.
351135446Strhodes		 */
352135446Strhodes		unsigned int ncache_opts = 0;
353135446Strhodes		if ((options & DNS_RDATASETTOWIRE_OMITDNSSEC) != 0)
354135446Strhodes			ncache_opts |= DNS_NCACHETOWIRE_OMITDNSSEC;
355135446Strhodes		return (dns_ncache_towire(rdataset, cctx, target, ncache_opts,
356135446Strhodes					  countp));
357135446Strhodes	} else {
358135446Strhodes		count = (rdataset->methods->count)(rdataset);
359135446Strhodes		result = dns_rdataset_first(rdataset);
360135446Strhodes		if (result == ISC_R_NOMORE)
361135446Strhodes			return (ISC_R_SUCCESS);
362135446Strhodes		if (result != ISC_R_SUCCESS)
363135446Strhodes			return (result);
364135446Strhodes	}
365135446Strhodes
366135446Strhodes	/*
367193149Sdougb	 * Do we want to shuffle this answer?
368135446Strhodes	 */
369135446Strhodes	if (!question && count > 1 &&
370135446Strhodes	    (!WANT_FIXED(rdataset) || order != NULL) &&
371135446Strhodes	    rdataset->type != dns_rdatatype_rrsig)
372135446Strhodes		shuffle = ISC_TRUE;
373135446Strhodes
374135446Strhodes	if (shuffle && count > MAX_SHUFFLE) {
375135446Strhodes		shuffled = isc_mem_get(cctx->mctx, count * sizeof(*shuffled));
376135446Strhodes		sorted = isc_mem_get(cctx->mctx, count * sizeof(*sorted));
377135446Strhodes		if (shuffled == NULL || sorted == NULL)
378135446Strhodes			shuffle = ISC_FALSE;
379135446Strhodes	} else {
380135446Strhodes		shuffled = shuffled_fixed;
381135446Strhodes		sorted = sorted_fixed;
382135446Strhodes	}
383135446Strhodes
384135446Strhodes	if (shuffle) {
385135446Strhodes		/*
386135446Strhodes		 * First we get handles to all of the rdata.
387135446Strhodes		 */
388135446Strhodes		i = 0;
389135446Strhodes		do {
390135446Strhodes			INSIST(i < count);
391135446Strhodes			dns_rdata_init(&shuffled[i]);
392135446Strhodes			dns_rdataset_current(rdataset, &shuffled[i]);
393135446Strhodes			i++;
394135446Strhodes			result = dns_rdataset_next(rdataset);
395135446Strhodes		} while (result == ISC_R_SUCCESS);
396135446Strhodes		if (result != ISC_R_NOMORE)
397135446Strhodes			goto cleanup;
398135446Strhodes		INSIST(i == count);
399135446Strhodes
400135446Strhodes		/*
401135446Strhodes		 * Now we shuffle.
402135446Strhodes		 */
403135446Strhodes		if (WANT_FIXED(rdataset)) {
404135446Strhodes			/*
405135446Strhodes			 * 'Fixed' order.
406135446Strhodes			 */
407135446Strhodes			INSIST(order != NULL);
408135446Strhodes			for (i = 0; i < count; i++) {
409135446Strhodes				sorted[i].key = (*order)(&shuffled[i],
410135446Strhodes							 order_arg);
411135446Strhodes				sorted[i].rdata = &shuffled[i];
412135446Strhodes			}
413135446Strhodes		} else if (WANT_RANDOM(rdataset)) {
414135446Strhodes			/*
415135446Strhodes			 * 'Random' order.
416135446Strhodes			 */
417135446Strhodes			for (i = 0; i < count; i++) {
418135446Strhodes				dns_rdata_t rdata;
419135446Strhodes				isc_uint32_t val;
420135446Strhodes
421135446Strhodes				isc_random_get(&val);
422135446Strhodes				choice = i + (val % (count - i));
423135446Strhodes				rdata = shuffled[i];
424135446Strhodes				shuffled[i] = shuffled[choice];
425135446Strhodes				shuffled[choice] = rdata;
426135446Strhodes				if (order != NULL)
427135446Strhodes					sorted[i].key = (*order)(&shuffled[i],
428135446Strhodes								 order_arg);
429135446Strhodes				else
430135446Strhodes					sorted[i].key = 0; /* Unused */
431135446Strhodes				sorted[i].rdata = &shuffled[i];
432135446Strhodes			}
433135446Strhodes		} else {
434135446Strhodes			/*
435135446Strhodes			 * "Cyclic" order.
436135446Strhodes			 */
437135446Strhodes			isc_uint32_t val;
438135446Strhodes			unsigned int j;
439135446Strhodes
440135446Strhodes			val = rdataset->count;
441135446Strhodes			if (val == ISC_UINT32_MAX)
442135446Strhodes				isc_random_get(&val);
443135446Strhodes			j = val % count;
444135446Strhodes			for (i = 0; i < count; i++) {
445135446Strhodes				if (order != NULL)
446135446Strhodes					sorted[j].key = (*order)(&shuffled[i],
447135446Strhodes								 order_arg);
448135446Strhodes				else
449135446Strhodes					sorted[j].key = 0; /* Unused */
450135446Strhodes				sorted[j].rdata = &shuffled[i];
451135446Strhodes				j++;
452135446Strhodes				if (j == count)
453135446Strhodes					j = 0; /* Wrap around. */
454135446Strhodes			}
455135446Strhodes		}
456135446Strhodes
457135446Strhodes		/*
458135446Strhodes		 * Sorted order.
459135446Strhodes		 */
460135446Strhodes		if (order != NULL)
461135446Strhodes			qsort(sorted, count, sizeof(sorted[0]),
462135446Strhodes			      towire_compare);
463135446Strhodes	}
464135446Strhodes
465135446Strhodes	savedbuffer = *target;
466135446Strhodes	i = 0;
467135446Strhodes	added = 0;
468135446Strhodes
469135446Strhodes	do {
470135446Strhodes		/*
471135446Strhodes		 * Copy out the name, type, class, ttl.
472135446Strhodes		 */
473193149Sdougb
474135446Strhodes		rrbuffer = *target;
475135446Strhodes		dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
476135446Strhodes		result = dns_name_towire(owner_name, cctx, target);
477135446Strhodes		if (result != ISC_R_SUCCESS)
478135446Strhodes			goto rollback;
479135446Strhodes		headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
480135446Strhodes		if (!question)
481135446Strhodes			headlen += sizeof(dns_ttl_t)
482135446Strhodes				+ 2;  /* XXX 2 for rdata len */
483135446Strhodes		isc_buffer_availableregion(target, &r);
484135446Strhodes		if (r.length < headlen) {
485135446Strhodes			result = ISC_R_NOSPACE;
486135446Strhodes			goto rollback;
487135446Strhodes		}
488135446Strhodes		isc_buffer_putuint16(target, rdataset->type);
489135446Strhodes		isc_buffer_putuint16(target, rdataset->rdclass);
490135446Strhodes		if (!question) {
491135446Strhodes			isc_buffer_putuint32(target, rdataset->ttl);
492135446Strhodes
493135446Strhodes			/*
494135446Strhodes			 * Save space for rdlen.
495135446Strhodes			 */
496135446Strhodes			rdlen = *target;
497135446Strhodes			isc_buffer_add(target, 2);
498135446Strhodes
499135446Strhodes			/*
500135446Strhodes			 * Copy out the rdata
501135446Strhodes			 */
502135446Strhodes			if (shuffle)
503135446Strhodes				rdata = *(sorted[i].rdata);
504135446Strhodes			else {
505135446Strhodes				dns_rdata_reset(&rdata);
506135446Strhodes				dns_rdataset_current(rdataset, &rdata);
507135446Strhodes			}
508135446Strhodes			result = dns_rdata_towire(&rdata, cctx, target);
509135446Strhodes			if (result != ISC_R_SUCCESS)
510135446Strhodes				goto rollback;
511135446Strhodes			INSIST((target->used >= rdlen.used + 2) &&
512135446Strhodes			       (target->used - rdlen.used - 2 < 65536));
513135446Strhodes			isc_buffer_putuint16(&rdlen,
514135446Strhodes					     (isc_uint16_t)(target->used -
515135446Strhodes							    rdlen.used - 2));
516135446Strhodes			added++;
517135446Strhodes		}
518135446Strhodes
519135446Strhodes		if (shuffle) {
520135446Strhodes			i++;
521135446Strhodes			if (i == count)
522135446Strhodes				result = ISC_R_NOMORE;
523135446Strhodes			else
524135446Strhodes				result = ISC_R_SUCCESS;
525135446Strhodes		} else {
526135446Strhodes			result = dns_rdataset_next(rdataset);
527135446Strhodes		}
528135446Strhodes	} while (result == ISC_R_SUCCESS);
529135446Strhodes
530135446Strhodes	if (result != ISC_R_NOMORE)
531135446Strhodes		goto rollback;
532135446Strhodes
533135446Strhodes	*countp += count;
534135446Strhodes
535135446Strhodes	result = ISC_R_SUCCESS;
536135446Strhodes	goto cleanup;
537135446Strhodes
538135446Strhodes rollback:
539135446Strhodes	if (partial && result == ISC_R_NOSPACE) {
540135446Strhodes		INSIST(rrbuffer.used < 65536);
541135446Strhodes		dns_compress_rollback(cctx, (isc_uint16_t)rrbuffer.used);
542135446Strhodes		*countp += added;
543135446Strhodes		*target = rrbuffer;
544135446Strhodes		goto cleanup;
545135446Strhodes	}
546135446Strhodes	INSIST(savedbuffer.used < 65536);
547135446Strhodes	dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
548135446Strhodes	*countp = 0;
549135446Strhodes	*target = savedbuffer;
550135446Strhodes
551135446Strhodes cleanup:
552135446Strhodes	if (sorted != NULL && sorted != sorted_fixed)
553135446Strhodes		isc_mem_put(cctx->mctx, sorted, count * sizeof(*sorted));
554135446Strhodes	if (shuffled != NULL && shuffled != shuffled_fixed)
555135446Strhodes		isc_mem_put(cctx->mctx, shuffled, count * sizeof(*shuffled));
556135446Strhodes	return (result);
557135446Strhodes}
558135446Strhodes
559135446Strhodesisc_result_t
560135446Strhodesdns_rdataset_towiresorted(dns_rdataset_t *rdataset,
561165071Sdougb			  const dns_name_t *owner_name,
562135446Strhodes			  dns_compress_t *cctx,
563135446Strhodes			  isc_buffer_t *target,
564135446Strhodes			  dns_rdatasetorderfunc_t order,
565165071Sdougb			  const void *order_arg,
566135446Strhodes			  unsigned int options,
567135446Strhodes			  unsigned int *countp)
568135446Strhodes{
569135446Strhodes	return (towiresorted(rdataset, owner_name, cctx, target,
570135446Strhodes			     order, order_arg, ISC_FALSE, options,
571135446Strhodes			     countp, NULL));
572135446Strhodes}
573135446Strhodes
574135446Strhodesisc_result_t
575135446Strhodesdns_rdataset_towirepartial(dns_rdataset_t *rdataset,
576165071Sdougb			   const dns_name_t *owner_name,
577135446Strhodes			   dns_compress_t *cctx,
578135446Strhodes			   isc_buffer_t *target,
579135446Strhodes			   dns_rdatasetorderfunc_t order,
580165071Sdougb			   const void *order_arg,
581135446Strhodes			   unsigned int options,
582135446Strhodes			   unsigned int *countp,
583135446Strhodes			   void **state)
584135446Strhodes{
585135446Strhodes	REQUIRE(state == NULL);	/* XXX remove when implemented */
586135446Strhodes	return (towiresorted(rdataset, owner_name, cctx, target,
587135446Strhodes			     order, order_arg, ISC_TRUE, options,
588135446Strhodes			     countp, state));
589135446Strhodes}
590135446Strhodes
591135446Strhodesisc_result_t
592135446Strhodesdns_rdataset_towire(dns_rdataset_t *rdataset,
593135446Strhodes		    dns_name_t *owner_name,
594135446Strhodes		    dns_compress_t *cctx,
595135446Strhodes		    isc_buffer_t *target,
596135446Strhodes		    unsigned int options,
597135446Strhodes		    unsigned int *countp)
598135446Strhodes{
599135446Strhodes	return (towiresorted(rdataset, owner_name, cctx, target,
600135446Strhodes			     NULL, NULL, ISC_FALSE, options, countp, NULL));
601135446Strhodes}
602135446Strhodes
603135446Strhodesisc_result_t
604135446Strhodesdns_rdataset_additionaldata(dns_rdataset_t *rdataset,
605135446Strhodes			    dns_additionaldatafunc_t add, void *arg)
606135446Strhodes{
607135446Strhodes	dns_rdata_t rdata = DNS_RDATA_INIT;
608135446Strhodes	isc_result_t result;
609135446Strhodes
610135446Strhodes	/*
611135446Strhodes	 * For each rdata in rdataset, call 'add' for each name and type in the
612135446Strhodes	 * rdata which is subject to additional section processing.
613135446Strhodes	 */
614135446Strhodes
615135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
616135446Strhodes	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
617135446Strhodes
618135446Strhodes	result = dns_rdataset_first(rdataset);
619135446Strhodes	if (result != ISC_R_SUCCESS)
620135446Strhodes		return (result);
621135446Strhodes
622135446Strhodes	do {
623135446Strhodes		dns_rdataset_current(rdataset, &rdata);
624135446Strhodes		result = dns_rdata_additionaldata(&rdata, add, arg);
625135446Strhodes		if (result == ISC_R_SUCCESS)
626135446Strhodes			result = dns_rdataset_next(rdataset);
627135446Strhodes		dns_rdata_reset(&rdata);
628135446Strhodes	} while (result == ISC_R_SUCCESS);
629135446Strhodes
630135446Strhodes	if (result != ISC_R_NOMORE)
631135446Strhodes		return (result);
632135446Strhodes
633135446Strhodes	return (ISC_R_SUCCESS);
634135446Strhodes}
635135446Strhodes
636135446Strhodesisc_result_t
637135446Strhodesdns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
638135446Strhodes
639135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
640135446Strhodes	REQUIRE(rdataset->methods != NULL);
641135446Strhodes	if (rdataset->methods->addnoqname == NULL)
642135446Strhodes		return (ISC_R_NOTIMPLEMENTED);
643135446Strhodes	return((rdataset->methods->addnoqname)(rdataset, name));
644135446Strhodes}
645135446Strhodes
646135446Strhodesisc_result_t
647135446Strhodesdns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
648193149Sdougb			dns_rdataset_t *neg, dns_rdataset_t *negsig)
649135446Strhodes{
650135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
651135446Strhodes	REQUIRE(rdataset->methods != NULL);
652135446Strhodes
653135446Strhodes	if (rdataset->methods->getnoqname == NULL)
654135446Strhodes		return (ISC_R_NOTIMPLEMENTED);
655193149Sdougb	return((rdataset->methods->getnoqname)(rdataset, name, neg, negsig));
656135446Strhodes}
657170222Sdougb
658193149Sdougbisc_result_t
659193149Sdougbdns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) {
660193149Sdougb
661193149Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
662193149Sdougb	REQUIRE(rdataset->methods != NULL);
663193149Sdougb	if (rdataset->methods->addclosest == NULL)
664193149Sdougb		return (ISC_R_NOTIMPLEMENTED);
665193149Sdougb	return((rdataset->methods->addclosest)(rdataset, name));
666193149Sdougb}
667193149Sdougb
668193149Sdougbisc_result_t
669193149Sdougbdns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
670193149Sdougb			dns_rdataset_t *neg, dns_rdataset_t *negsig)
671193149Sdougb{
672193149Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
673193149Sdougb	REQUIRE(rdataset->methods != NULL);
674193149Sdougb
675193149Sdougb	if (rdataset->methods->getclosest == NULL)
676193149Sdougb		return (ISC_R_NOTIMPLEMENTED);
677193149Sdougb	return((rdataset->methods->getclosest)(rdataset, name, neg, negsig));
678193149Sdougb}
679193149Sdougb
680170222Sdougb/*
681170222Sdougb * Additional cache stuff
682170222Sdougb */
683170222Sdougbisc_result_t
684170222Sdougbdns_rdataset_getadditional(dns_rdataset_t *rdataset,
685170222Sdougb			   dns_rdatasetadditional_t type,
686170222Sdougb			   dns_rdatatype_t qtype,
687170222Sdougb			   dns_acache_t *acache,
688170222Sdougb			   dns_zone_t **zonep,
689170222Sdougb			   dns_db_t **dbp,
690170222Sdougb			   dns_dbversion_t **versionp,
691170222Sdougb			   dns_dbnode_t **nodep,
692170222Sdougb			   dns_name_t *fname,
693170222Sdougb			   dns_message_t *msg,
694170222Sdougb			   isc_stdtime_t now)
695170222Sdougb{
696170222Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
697170222Sdougb	REQUIRE(rdataset->methods != NULL);
698170222Sdougb	REQUIRE(zonep == NULL || *zonep == NULL);
699170222Sdougb	REQUIRE(dbp != NULL && *dbp == NULL);
700170222Sdougb	REQUIRE(versionp != NULL && *versionp == NULL);
701170222Sdougb	REQUIRE(nodep != NULL && *nodep == NULL);
702170222Sdougb	REQUIRE(fname != NULL);
703170222Sdougb	REQUIRE(msg != NULL);
704170222Sdougb
705170222Sdougb	if (acache != NULL && rdataset->methods->getadditional != NULL) {
706170222Sdougb		return ((rdataset->methods->getadditional)(rdataset, type,
707170222Sdougb							   qtype, acache,
708170222Sdougb							   zonep, dbp,
709170222Sdougb							   versionp, nodep,
710170222Sdougb							   fname, msg, now));
711170222Sdougb	}
712170222Sdougb
713170222Sdougb	return (ISC_R_FAILURE);
714170222Sdougb}
715170222Sdougb
716170222Sdougbisc_result_t
717170222Sdougbdns_rdataset_setadditional(dns_rdataset_t *rdataset,
718170222Sdougb			   dns_rdatasetadditional_t type,
719170222Sdougb			   dns_rdatatype_t qtype,
720170222Sdougb			   dns_acache_t *acache,
721170222Sdougb			   dns_zone_t *zone,
722170222Sdougb			   dns_db_t *db,
723170222Sdougb			   dns_dbversion_t *version,
724170222Sdougb			   dns_dbnode_t *node,
725170222Sdougb			   dns_name_t *fname)
726170222Sdougb{
727170222Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
728170222Sdougb	REQUIRE(rdataset->methods != NULL);
729170222Sdougb
730170222Sdougb	if (acache != NULL && rdataset->methods->setadditional != NULL) {
731170222Sdougb		return ((rdataset->methods->setadditional)(rdataset, type,
732170222Sdougb							   qtype, acache, zone,
733170222Sdougb							   db, version,
734170222Sdougb							   node, fname));
735170222Sdougb	}
736170222Sdougb
737170222Sdougb	return (ISC_R_FAILURE);
738170222Sdougb}
739170222Sdougb
740170222Sdougbisc_result_t
741170222Sdougbdns_rdataset_putadditional(dns_acache_t *acache,
742170222Sdougb			   dns_rdataset_t *rdataset,
743170222Sdougb			   dns_rdatasetadditional_t type,
744170222Sdougb			   dns_rdatatype_t qtype)
745170222Sdougb{
746170222Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
747170222Sdougb	REQUIRE(rdataset->methods != NULL);
748170222Sdougb
749170222Sdougb	if (acache != NULL && rdataset->methods->putadditional != NULL) {
750170222Sdougb		return ((rdataset->methods->putadditional)(acache, rdataset,
751170222Sdougb							   type, qtype));
752170222Sdougb	}
753170222Sdougb
754170222Sdougb	return (ISC_R_FAILURE);
755170222Sdougb}
756170222Sdougb
757205292Sdougbvoid
758205292Sdougbdns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
759205292Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
760205292Sdougb	REQUIRE(rdataset->methods != NULL);
761205292Sdougb
762205292Sdougb	if (rdataset->methods->settrust != NULL)
763205292Sdougb		(rdataset->methods->settrust)(rdataset, trust);
764205292Sdougb	else
765205292Sdougb		rdataset->trust = trust;
766205292Sdougb}
767205292Sdougb
768205292Sdougbvoid
769205292Sdougbdns_rdataset_expire(dns_rdataset_t *rdataset) {
770205292Sdougb	REQUIRE(DNS_RDATASET_VALID(rdataset));
771205292Sdougb	REQUIRE(rdataset->methods != NULL);
772205292Sdougb
773205292Sdougb	if (rdataset->methods->expire != NULL)
774205292Sdougb		(rdataset->methods->expire)(rdataset);
775205292Sdougb}
776