1135446Strhodes/*
2234010Sdougb * Copyright (C) 2004-2012  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
18234010Sdougb/* $Id$ */
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>
29245163Serwin#include <isc/serial.h>
30135446Strhodes#include <isc/util.h>
31135446Strhodes
32135446Strhodes#include <dns/name.h>
33135446Strhodes#include <dns/ncache.h>
34135446Strhodes#include <dns/rdata.h>
35135446Strhodes#include <dns/rdataset.h>
36135446Strhodes#include <dns/compress.h>
37135446Strhodes
38222395Sdougbstatic const char *trustnames[] = {
39222395Sdougb	"none",
40222395Sdougb	"pending-additional",
41222395Sdougb	"pending-answer",
42222395Sdougb	"additional",
43222395Sdougb	"glue",
44222395Sdougb	"answer",
45222395Sdougb	"authauthority",
46222395Sdougb	"authanswer",
47222395Sdougb	"secure",
48222395Sdougb	"local" /* aka ultimate */
49222395Sdougb};
50222395Sdougb
51222395Sdougbconst char *
52222395Sdougbdns_trust_totext(dns_trust_t trust) {
53222395Sdougb	if (trust >= sizeof(trustnames)/sizeof(*trustnames))
54222395Sdougb		return ("bad");
55222395Sdougb	return (trustnames[trust]);
56222395Sdougb}
57222395Sdougb
58135446Strhodesvoid
59135446Strhodesdns_rdataset_init(dns_rdataset_t *rdataset) {
60135446Strhodes
61135446Strhodes	/*
62135446Strhodes	 * Make 'rdataset' a valid, disassociated rdataset.
63135446Strhodes	 */
64135446Strhodes
65135446Strhodes	REQUIRE(rdataset != NULL);
66135446Strhodes
67135446Strhodes	rdataset->magic = DNS_RDATASET_MAGIC;
68135446Strhodes	rdataset->methods = NULL;
69135446Strhodes	ISC_LINK_INIT(rdataset, link);
70135446Strhodes	rdataset->rdclass = 0;
71135446Strhodes	rdataset->type = 0;
72135446Strhodes	rdataset->ttl = 0;
73135446Strhodes	rdataset->trust = 0;
74135446Strhodes	rdataset->covers = 0;
75135446Strhodes	rdataset->attributes = 0;
76135446Strhodes	rdataset->count = ISC_UINT32_MAX;
77135446Strhodes	rdataset->private1 = NULL;
78135446Strhodes	rdataset->private2 = NULL;
79135446Strhodes	rdataset->private3 = NULL;
80135446Strhodes	rdataset->privateuint4 = 0;
81135446Strhodes	rdataset->private5 = NULL;
82135446Strhodes	rdataset->private6 = NULL;
83193149Sdougb	rdataset->resign = 0;
84135446Strhodes}
85135446Strhodes
86135446Strhodesvoid
87135446Strhodesdns_rdataset_invalidate(dns_rdataset_t *rdataset) {
88135446Strhodes
89135446Strhodes	/*
90135446Strhodes	 * Invalidate 'rdataset'.
91135446Strhodes	 */
92135446Strhodes
93135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
94135446Strhodes	REQUIRE(rdataset->methods == NULL);
95135446Strhodes
96135446Strhodes	rdataset->magic = 0;
97135446Strhodes	ISC_LINK_INIT(rdataset, link);
98135446Strhodes	rdataset->rdclass = 0;
99135446Strhodes	rdataset->type = 0;
100135446Strhodes	rdataset->ttl = 0;
101135446Strhodes	rdataset->trust = 0;
102135446Strhodes	rdataset->covers = 0;
103135446Strhodes	rdataset->attributes = 0;
104135446Strhodes	rdataset->count = ISC_UINT32_MAX;
105135446Strhodes	rdataset->private1 = NULL;
106135446Strhodes	rdataset->private2 = NULL;
107135446Strhodes	rdataset->private3 = NULL;
108135446Strhodes	rdataset->privateuint4 = 0;
109135446Strhodes	rdataset->private5 = NULL;
110135446Strhodes}
111135446Strhodes
112135446Strhodesvoid
113135446Strhodesdns_rdataset_disassociate(dns_rdataset_t *rdataset) {
114135446Strhodes
115135446Strhodes	/*
116135446Strhodes	 * Disassociate 'rdataset' from its rdata, allowing it to be reused.
117135446Strhodes	 */
118135446Strhodes
119135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
120135446Strhodes	REQUIRE(rdataset->methods != NULL);
121135446Strhodes
122135446Strhodes	(rdataset->methods->disassociate)(rdataset);
123135446Strhodes	rdataset->methods = NULL;
124135446Strhodes	ISC_LINK_INIT(rdataset, link);
125135446Strhodes	rdataset->rdclass = 0;
126135446Strhodes	rdataset->type = 0;
127135446Strhodes	rdataset->ttl = 0;
128135446Strhodes	rdataset->trust = 0;
129135446Strhodes	rdataset->covers = 0;
130135446Strhodes	rdataset->attributes = 0;
131135446Strhodes	rdataset->count = ISC_UINT32_MAX;
132135446Strhodes	rdataset->private1 = NULL;
133135446Strhodes	rdataset->private2 = NULL;
134135446Strhodes	rdataset->private3 = NULL;
135135446Strhodes	rdataset->privateuint4 = 0;
136135446Strhodes	rdataset->private5 = NULL;
137135446Strhodes	rdataset->private6 = NULL;
138135446Strhodes}
139135446Strhodes
140135446Strhodesisc_boolean_t
141135446Strhodesdns_rdataset_isassociated(dns_rdataset_t *rdataset) {
142135446Strhodes	/*
143135446Strhodes	 * Is 'rdataset' associated?
144135446Strhodes	 */
145135446Strhodes
146135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
147135446Strhodes
148135446Strhodes	if (rdataset->methods != NULL)
149135446Strhodes		return (ISC_TRUE);
150135446Strhodes
151135446Strhodes	return (ISC_FALSE);
152135446Strhodes}
153135446Strhodes
154135446Strhodesstatic void
155135446Strhodesquestion_disassociate(dns_rdataset_t *rdataset) {
156135446Strhodes	UNUSED(rdataset);
157135446Strhodes}
158135446Strhodes
159135446Strhodesstatic isc_result_t
160135446Strhodesquestion_cursor(dns_rdataset_t *rdataset) {
161135446Strhodes	UNUSED(rdataset);
162193149Sdougb
163135446Strhodes	return (ISC_R_NOMORE);
164135446Strhodes}
165135446Strhodes
166135446Strhodesstatic void
167135446Strhodesquestion_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
168135446Strhodes	/*
169135446Strhodes	 * This routine should never be called.
170135446Strhodes	 */
171135446Strhodes	UNUSED(rdataset);
172135446Strhodes	UNUSED(rdata);
173193149Sdougb
174135446Strhodes	REQUIRE(0);
175135446Strhodes}
176135446Strhodes
177135446Strhodesstatic void
178135446Strhodesquestion_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
179135446Strhodes	*target = *source;
180135446Strhodes}
181135446Strhodes
182135446Strhodesstatic unsigned int
183135446Strhodesquestion_count(dns_rdataset_t *rdataset) {
184135446Strhodes	/*
185135446Strhodes	 * This routine should never be called.
186135446Strhodes	 */
187135446Strhodes	UNUSED(rdataset);
188135446Strhodes	REQUIRE(0);
189135446Strhodes
190135446Strhodes	return (0);
191135446Strhodes}
192135446Strhodes
193135446Strhodesstatic dns_rdatasetmethods_t question_methods = {
194135446Strhodes	question_disassociate,
195135446Strhodes	question_cursor,
196135446Strhodes	question_cursor,
197135446Strhodes	question_current,
198135446Strhodes	question_clone,
199135446Strhodes	question_count,
200135446Strhodes	NULL,
201170222Sdougb	NULL,
202170222Sdougb	NULL,
203170222Sdougb	NULL,
204193149Sdougb	NULL,
205193149Sdougb	NULL,
206205292Sdougb	NULL,
207205292Sdougb	NULL,
208135446Strhodes	NULL
209135446Strhodes};
210135446Strhodes
211135446Strhodesvoid
212135446Strhodesdns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass,
213135446Strhodes			  dns_rdatatype_t type)
214135446Strhodes{
215135446Strhodes
216135446Strhodes	/*
217135446Strhodes	 * Make 'rdataset' a valid, associated, question rdataset, with a
218135446Strhodes	 * question class of 'rdclass' and type 'type'.
219135446Strhodes	 */
220135446Strhodes
221135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
222135446Strhodes	REQUIRE(rdataset->methods == NULL);
223135446Strhodes
224135446Strhodes	rdataset->methods = &question_methods;
225135446Strhodes	rdataset->rdclass = rdclass;
226135446Strhodes	rdataset->type = type;
227135446Strhodes	rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
228135446Strhodes}
229135446Strhodes
230135446Strhodesunsigned int
231135446Strhodesdns_rdataset_count(dns_rdataset_t *rdataset) {
232135446Strhodes
233135446Strhodes	/*
234135446Strhodes	 * Return the number of records in 'rdataset'.
235135446Strhodes	 */
236135446Strhodes
237135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
238135446Strhodes	REQUIRE(rdataset->methods != NULL);
239135446Strhodes
240135446Strhodes	return ((rdataset->methods->count)(rdataset));
241135446Strhodes}
242135446Strhodes
243135446Strhodesvoid
244135446Strhodesdns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
245135446Strhodes
246135446Strhodes	/*
247135446Strhodes	 * Make 'target' refer to the same rdataset as 'source'.
248135446Strhodes	 */
249135446Strhodes
250135446Strhodes	REQUIRE(DNS_RDATASET_VALID(source));
251135446Strhodes	REQUIRE(source->methods != NULL);
252135446Strhodes	REQUIRE(DNS_RDATASET_VALID(target));
253135446Strhodes	REQUIRE(target->methods == NULL);
254135446Strhodes
255135446Strhodes	(source->methods->clone)(source, target);
256135446Strhodes}
257135446Strhodes
258135446Strhodesisc_result_t
259135446Strhodesdns_rdataset_first(dns_rdataset_t *rdataset) {
260135446Strhodes
261135446Strhodes	/*
262135446Strhodes	 * Move the rdata cursor to the first rdata in the rdataset (if any).
263135446Strhodes	 */
264135446Strhodes
265135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
266135446Strhodes	REQUIRE(rdataset->methods != NULL);
267135446Strhodes
268135446Strhodes	return ((rdataset->methods->first)(rdataset));
269135446Strhodes}
270135446Strhodes
271135446Strhodesisc_result_t
272135446Strhodesdns_rdataset_next(dns_rdataset_t *rdataset) {
273135446Strhodes
274135446Strhodes	/*
275135446Strhodes	 * Move the rdata cursor to the next rdata in the rdataset (if any).
276135446Strhodes	 */
277135446Strhodes
278135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
279135446Strhodes	REQUIRE(rdataset->methods != NULL);
280135446Strhodes
281135446Strhodes	return ((rdataset->methods->next)(rdataset));
282135446Strhodes}
283135446Strhodes
284135446Strhodesvoid
285135446Strhodesdns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
286135446Strhodes
287135446Strhodes	/*
288135446Strhodes	 * Make 'rdata' refer to the current rdata.
289135446Strhodes	 */
290135446Strhodes
291135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
292135446Strhodes	REQUIRE(rdataset->methods != NULL);
293135446Strhodes
294135446Strhodes	(rdataset->methods->current)(rdataset, rdata);
295135446Strhodes}
296135446Strhodes
297135446Strhodes#define MAX_SHUFFLE	32
298135446Strhodes#define WANT_FIXED(r)	(((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
299135446Strhodes#define WANT_RANDOM(r)	(((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
300135446Strhodes
301135446Strhodesstruct towire_sort {
302135446Strhodes	int key;
303135446Strhodes	dns_rdata_t *rdata;
304135446Strhodes};
305135446Strhodes
306135446Strhodesstatic int
307135446Strhodestowire_compare(const void *av, const void *bv) {
308135446Strhodes	const struct towire_sort *a = (const struct towire_sort *) av;
309135446Strhodes	const struct towire_sort *b = (const struct towire_sort *) bv;
310135446Strhodes	return (a->key - b->key);
311135446Strhodes}
312135446Strhodes
313135446Strhodesstatic isc_result_t
314165071Sdougbtowiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
315135446Strhodes	     dns_compress_t *cctx, isc_buffer_t *target,
316165071Sdougb	     dns_rdatasetorderfunc_t order, const void *order_arg,
317135446Strhodes	     isc_boolean_t partial, unsigned int options,
318135446Strhodes	     unsigned int *countp, void **state)
319135446Strhodes{
320135446Strhodes	dns_rdata_t rdata = DNS_RDATA_INIT;
321135446Strhodes	isc_region_t r;
322135446Strhodes	isc_result_t result;
323225361Sdougb	unsigned int i, count = 0, added, choice;
324135446Strhodes	isc_buffer_t savedbuffer, rdlen, rrbuffer;
325135446Strhodes	unsigned int headlen;
326135446Strhodes	isc_boolean_t question = ISC_FALSE;
327135446Strhodes	isc_boolean_t shuffle = ISC_FALSE;
328135446Strhodes	dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE];
329135446Strhodes	struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE];
330135446Strhodes
331135446Strhodes	UNUSED(state);
332135446Strhodes
333135446Strhodes	/*
334135446Strhodes	 * Convert 'rdataset' to wire format, compressing names as specified
335135446Strhodes	 * in cctx, and storing the result in 'target'.
336135446Strhodes	 */
337135446Strhodes
338135446Strhodes	REQUIRE(DNS_RDATASET_VALID(rdataset));
339135446Strhodes	REQUIRE(countp != NULL);
340135446Strhodes	REQUIRE((order == NULL) == (order_arg == NULL));
341135446Strhodes	REQUIRE(cctx != NULL && cctx->mctx != NULL);
342135446Strhodes
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);
348223812Sdougb	} else if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 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)
446234010Sdougb					sorted[i].key = (*order)(&shuffled[j],
447135446Strhodes								 order_arg);
448135446Strhodes				else
449234010Sdougb					sorted[i].key = 0; /* Unused */
450234010Sdougb				sorted[i].rdata = &shuffled[j];
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}
776245163Serwin
777245163Serwinvoid
778245163Serwindns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
779245163Serwin		     dns_rdata_rrsig_t *rrsig, isc_stdtime_t now,
780245163Serwin		     isc_boolean_t acceptexpired)
781245163Serwin{
782245163Serwin	isc_uint32_t ttl = 0;
783245163Serwin
784245163Serwin	REQUIRE(DNS_RDATASET_VALID(rdataset));
785245163Serwin	REQUIRE(DNS_RDATASET_VALID(sigrdataset));
786245163Serwin	REQUIRE(rrsig != NULL);
787245163Serwin
788245163Serwin	/*
789245163Serwin	 * If we accept expired RRsets keep them for no more than 120 seconds.
790245163Serwin	 */
791245163Serwin	if (acceptexpired &&
792245163Serwin	    (isc_serial_le(rrsig->timeexpire, ((now + 120) & 0xffffffff)) ||
793245163Serwin	     isc_serial_le(rrsig->timeexpire, now)))
794245163Serwin		ttl = 120;
795245163Serwin	else if (isc_serial_ge(rrsig->timeexpire, now))
796245163Serwin		ttl = rrsig->timeexpire - now;
797245163Serwin
798245163Serwin	ttl = ISC_MIN(ISC_MIN(rdataset->ttl, sigrdataset->ttl),
799245163Serwin		      ISC_MIN(rrsig->originalttl, ttl));
800245163Serwin	rdataset->ttl = ttl;
801245163Serwin	sigrdataset->ttl = ttl;
802245163Serwin}
803