1/*
2 * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id$ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <stdlib.h>
25
26#include <isc/buffer.h>
27#include <isc/mem.h>
28#include <isc/random.h>
29#include <isc/serial.h>
30#include <isc/util.h>
31
32#include <dns/name.h>
33#include <dns/ncache.h>
34#include <dns/rdata.h>
35#include <dns/rdataset.h>
36#include <dns/compress.h>
37
38static const char *trustnames[] = {
39	"none",
40	"pending-additional",
41	"pending-answer",
42	"additional",
43	"glue",
44	"answer",
45	"authauthority",
46	"authanswer",
47	"secure",
48	"local" /* aka ultimate */
49};
50
51const char *
52dns_trust_totext(dns_trust_t trust) {
53	if (trust >= sizeof(trustnames)/sizeof(*trustnames))
54		return ("bad");
55	return (trustnames[trust]);
56}
57
58void
59dns_rdataset_init(dns_rdataset_t *rdataset) {
60
61	/*
62	 * Make 'rdataset' a valid, disassociated rdataset.
63	 */
64
65	REQUIRE(rdataset != NULL);
66
67	rdataset->magic = DNS_RDATASET_MAGIC;
68	rdataset->methods = NULL;
69	ISC_LINK_INIT(rdataset, link);
70	rdataset->rdclass = 0;
71	rdataset->type = 0;
72	rdataset->ttl = 0;
73	rdataset->trust = 0;
74	rdataset->covers = 0;
75	rdataset->attributes = 0;
76	rdataset->count = ISC_UINT32_MAX;
77	rdataset->private1 = NULL;
78	rdataset->private2 = NULL;
79	rdataset->private3 = NULL;
80	rdataset->privateuint4 = 0;
81	rdataset->private5 = NULL;
82	rdataset->private6 = NULL;
83	rdataset->resign = 0;
84}
85
86void
87dns_rdataset_invalidate(dns_rdataset_t *rdataset) {
88
89	/*
90	 * Invalidate 'rdataset'.
91	 */
92
93	REQUIRE(DNS_RDATASET_VALID(rdataset));
94	REQUIRE(rdataset->methods == NULL);
95
96	rdataset->magic = 0;
97	ISC_LINK_INIT(rdataset, link);
98	rdataset->rdclass = 0;
99	rdataset->type = 0;
100	rdataset->ttl = 0;
101	rdataset->trust = 0;
102	rdataset->covers = 0;
103	rdataset->attributes = 0;
104	rdataset->count = ISC_UINT32_MAX;
105	rdataset->private1 = NULL;
106	rdataset->private2 = NULL;
107	rdataset->private3 = NULL;
108	rdataset->privateuint4 = 0;
109	rdataset->private5 = NULL;
110}
111
112void
113dns_rdataset_disassociate(dns_rdataset_t *rdataset) {
114
115	/*
116	 * Disassociate 'rdataset' from its rdata, allowing it to be reused.
117	 */
118
119	REQUIRE(DNS_RDATASET_VALID(rdataset));
120	REQUIRE(rdataset->methods != NULL);
121
122	(rdataset->methods->disassociate)(rdataset);
123	rdataset->methods = NULL;
124	ISC_LINK_INIT(rdataset, link);
125	rdataset->rdclass = 0;
126	rdataset->type = 0;
127	rdataset->ttl = 0;
128	rdataset->trust = 0;
129	rdataset->covers = 0;
130	rdataset->attributes = 0;
131	rdataset->count = ISC_UINT32_MAX;
132	rdataset->private1 = NULL;
133	rdataset->private2 = NULL;
134	rdataset->private3 = NULL;
135	rdataset->privateuint4 = 0;
136	rdataset->private5 = NULL;
137	rdataset->private6 = NULL;
138}
139
140isc_boolean_t
141dns_rdataset_isassociated(dns_rdataset_t *rdataset) {
142	/*
143	 * Is 'rdataset' associated?
144	 */
145
146	REQUIRE(DNS_RDATASET_VALID(rdataset));
147
148	if (rdataset->methods != NULL)
149		return (ISC_TRUE);
150
151	return (ISC_FALSE);
152}
153
154static void
155question_disassociate(dns_rdataset_t *rdataset) {
156	UNUSED(rdataset);
157}
158
159static isc_result_t
160question_cursor(dns_rdataset_t *rdataset) {
161	UNUSED(rdataset);
162
163	return (ISC_R_NOMORE);
164}
165
166static void
167question_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
168	/*
169	 * This routine should never be called.
170	 */
171	UNUSED(rdataset);
172	UNUSED(rdata);
173
174	REQUIRE(0);
175}
176
177static void
178question_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
179	*target = *source;
180}
181
182static unsigned int
183question_count(dns_rdataset_t *rdataset) {
184	/*
185	 * This routine should never be called.
186	 */
187	UNUSED(rdataset);
188	REQUIRE(0);
189
190	return (0);
191}
192
193static dns_rdatasetmethods_t question_methods = {
194	question_disassociate,
195	question_cursor,
196	question_cursor,
197	question_current,
198	question_clone,
199	question_count,
200	NULL,
201	NULL,
202	NULL,
203	NULL,
204	NULL,
205	NULL,
206	NULL,
207	NULL,
208	NULL
209};
210
211void
212dns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass,
213			  dns_rdatatype_t type)
214{
215
216	/*
217	 * Make 'rdataset' a valid, associated, question rdataset, with a
218	 * question class of 'rdclass' and type 'type'.
219	 */
220
221	REQUIRE(DNS_RDATASET_VALID(rdataset));
222	REQUIRE(rdataset->methods == NULL);
223
224	rdataset->methods = &question_methods;
225	rdataset->rdclass = rdclass;
226	rdataset->type = type;
227	rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
228}
229
230unsigned int
231dns_rdataset_count(dns_rdataset_t *rdataset) {
232
233	/*
234	 * Return the number of records in 'rdataset'.
235	 */
236
237	REQUIRE(DNS_RDATASET_VALID(rdataset));
238	REQUIRE(rdataset->methods != NULL);
239
240	return ((rdataset->methods->count)(rdataset));
241}
242
243void
244dns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
245
246	/*
247	 * Make 'target' refer to the same rdataset as 'source'.
248	 */
249
250	REQUIRE(DNS_RDATASET_VALID(source));
251	REQUIRE(source->methods != NULL);
252	REQUIRE(DNS_RDATASET_VALID(target));
253	REQUIRE(target->methods == NULL);
254
255	(source->methods->clone)(source, target);
256}
257
258isc_result_t
259dns_rdataset_first(dns_rdataset_t *rdataset) {
260
261	/*
262	 * Move the rdata cursor to the first rdata in the rdataset (if any).
263	 */
264
265	REQUIRE(DNS_RDATASET_VALID(rdataset));
266	REQUIRE(rdataset->methods != NULL);
267
268	return ((rdataset->methods->first)(rdataset));
269}
270
271isc_result_t
272dns_rdataset_next(dns_rdataset_t *rdataset) {
273
274	/*
275	 * Move the rdata cursor to the next rdata in the rdataset (if any).
276	 */
277
278	REQUIRE(DNS_RDATASET_VALID(rdataset));
279	REQUIRE(rdataset->methods != NULL);
280
281	return ((rdataset->methods->next)(rdataset));
282}
283
284void
285dns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
286
287	/*
288	 * Make 'rdata' refer to the current rdata.
289	 */
290
291	REQUIRE(DNS_RDATASET_VALID(rdataset));
292	REQUIRE(rdataset->methods != NULL);
293
294	(rdataset->methods->current)(rdataset, rdata);
295}
296
297#define MAX_SHUFFLE	32
298#define WANT_FIXED(r)	(((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
299#define WANT_RANDOM(r)	(((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
300
301struct towire_sort {
302	int key;
303	dns_rdata_t *rdata;
304};
305
306static int
307towire_compare(const void *av, const void *bv) {
308	const struct towire_sort *a = (const struct towire_sort *) av;
309	const struct towire_sort *b = (const struct towire_sort *) bv;
310	return (a->key - b->key);
311}
312
313static isc_result_t
314towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
315	     dns_compress_t *cctx, isc_buffer_t *target,
316	     dns_rdatasetorderfunc_t order, const void *order_arg,
317	     isc_boolean_t partial, unsigned int options,
318	     unsigned int *countp, void **state)
319{
320	dns_rdata_t rdata = DNS_RDATA_INIT;
321	isc_region_t r;
322	isc_result_t result;
323	unsigned int i, count = 0, added, choice;
324	isc_buffer_t savedbuffer, rdlen, rrbuffer;
325	unsigned int headlen;
326	isc_boolean_t question = ISC_FALSE;
327	isc_boolean_t shuffle = ISC_FALSE;
328	dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE];
329	struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE];
330
331	UNUSED(state);
332
333	/*
334	 * Convert 'rdataset' to wire format, compressing names as specified
335	 * in cctx, and storing the result in 'target'.
336	 */
337
338	REQUIRE(DNS_RDATASET_VALID(rdataset));
339	REQUIRE(countp != NULL);
340	REQUIRE((order == NULL) == (order_arg == NULL));
341	REQUIRE(cctx != NULL && cctx->mctx != NULL);
342
343	if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
344		question = ISC_TRUE;
345		count = 1;
346		result = dns_rdataset_first(rdataset);
347		INSIST(result == ISC_R_NOMORE);
348	} else if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
349		/*
350		 * This is a negative caching rdataset.
351		 */
352		unsigned int ncache_opts = 0;
353		if ((options & DNS_RDATASETTOWIRE_OMITDNSSEC) != 0)
354			ncache_opts |= DNS_NCACHETOWIRE_OMITDNSSEC;
355		return (dns_ncache_towire(rdataset, cctx, target, ncache_opts,
356					  countp));
357	} else {
358		count = (rdataset->methods->count)(rdataset);
359		result = dns_rdataset_first(rdataset);
360		if (result == ISC_R_NOMORE)
361			return (ISC_R_SUCCESS);
362		if (result != ISC_R_SUCCESS)
363			return (result);
364	}
365
366	/*
367	 * Do we want to shuffle this answer?
368	 */
369	if (!question && count > 1 &&
370	    (!WANT_FIXED(rdataset) || order != NULL) &&
371	    rdataset->type != dns_rdatatype_rrsig)
372		shuffle = ISC_TRUE;
373
374	if (shuffle && count > MAX_SHUFFLE) {
375		shuffled = isc_mem_get(cctx->mctx, count * sizeof(*shuffled));
376		sorted = isc_mem_get(cctx->mctx, count * sizeof(*sorted));
377		if (shuffled == NULL || sorted == NULL)
378			shuffle = ISC_FALSE;
379	} else {
380		shuffled = shuffled_fixed;
381		sorted = sorted_fixed;
382	}
383
384	if (shuffle) {
385		/*
386		 * First we get handles to all of the rdata.
387		 */
388		i = 0;
389		do {
390			INSIST(i < count);
391			dns_rdata_init(&shuffled[i]);
392			dns_rdataset_current(rdataset, &shuffled[i]);
393			i++;
394			result = dns_rdataset_next(rdataset);
395		} while (result == ISC_R_SUCCESS);
396		if (result != ISC_R_NOMORE)
397			goto cleanup;
398		INSIST(i == count);
399
400		/*
401		 * Now we shuffle.
402		 */
403		if (WANT_FIXED(rdataset)) {
404			/*
405			 * 'Fixed' order.
406			 */
407			INSIST(order != NULL);
408			for (i = 0; i < count; i++) {
409				sorted[i].key = (*order)(&shuffled[i],
410							 order_arg);
411				sorted[i].rdata = &shuffled[i];
412			}
413		} else if (WANT_RANDOM(rdataset)) {
414			/*
415			 * 'Random' order.
416			 */
417			for (i = 0; i < count; i++) {
418				dns_rdata_t rdata;
419				isc_uint32_t val;
420
421				isc_random_get(&val);
422				choice = i + (val % (count - i));
423				rdata = shuffled[i];
424				shuffled[i] = shuffled[choice];
425				shuffled[choice] = rdata;
426				if (order != NULL)
427					sorted[i].key = (*order)(&shuffled[i],
428								 order_arg);
429				else
430					sorted[i].key = 0; /* Unused */
431				sorted[i].rdata = &shuffled[i];
432			}
433		} else {
434			/*
435			 * "Cyclic" order.
436			 */
437			isc_uint32_t val;
438			unsigned int j;
439
440			val = rdataset->count;
441			if (val == ISC_UINT32_MAX)
442				isc_random_get(&val);
443			j = val % count;
444			for (i = 0; i < count; i++) {
445				if (order != NULL)
446					sorted[i].key = (*order)(&shuffled[j],
447								 order_arg);
448				else
449					sorted[i].key = 0; /* Unused */
450				sorted[i].rdata = &shuffled[j];
451				j++;
452				if (j == count)
453					j = 0; /* Wrap around. */
454			}
455		}
456
457		/*
458		 * Sorted order.
459		 */
460		if (order != NULL)
461			qsort(sorted, count, sizeof(sorted[0]),
462			      towire_compare);
463	}
464
465	savedbuffer = *target;
466	i = 0;
467	added = 0;
468
469	do {
470		/*
471		 * Copy out the name, type, class, ttl.
472		 */
473
474		rrbuffer = *target;
475		dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
476		result = dns_name_towire(owner_name, cctx, target);
477		if (result != ISC_R_SUCCESS)
478			goto rollback;
479		headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
480		if (!question)
481			headlen += sizeof(dns_ttl_t)
482				+ 2;  /* XXX 2 for rdata len */
483		isc_buffer_availableregion(target, &r);
484		if (r.length < headlen) {
485			result = ISC_R_NOSPACE;
486			goto rollback;
487		}
488		isc_buffer_putuint16(target, rdataset->type);
489		isc_buffer_putuint16(target, rdataset->rdclass);
490		if (!question) {
491			isc_buffer_putuint32(target, rdataset->ttl);
492
493			/*
494			 * Save space for rdlen.
495			 */
496			rdlen = *target;
497			isc_buffer_add(target, 2);
498
499			/*
500			 * Copy out the rdata
501			 */
502			if (shuffle)
503				rdata = *(sorted[i].rdata);
504			else {
505				dns_rdata_reset(&rdata);
506				dns_rdataset_current(rdataset, &rdata);
507			}
508			result = dns_rdata_towire(&rdata, cctx, target);
509			if (result != ISC_R_SUCCESS)
510				goto rollback;
511			INSIST((target->used >= rdlen.used + 2) &&
512			       (target->used - rdlen.used - 2 < 65536));
513			isc_buffer_putuint16(&rdlen,
514					     (isc_uint16_t)(target->used -
515							    rdlen.used - 2));
516			added++;
517		}
518
519		if (shuffle) {
520			i++;
521			if (i == count)
522				result = ISC_R_NOMORE;
523			else
524				result = ISC_R_SUCCESS;
525		} else {
526			result = dns_rdataset_next(rdataset);
527		}
528	} while (result == ISC_R_SUCCESS);
529
530	if (result != ISC_R_NOMORE)
531		goto rollback;
532
533	*countp += count;
534
535	result = ISC_R_SUCCESS;
536	goto cleanup;
537
538 rollback:
539	if (partial && result == ISC_R_NOSPACE) {
540		INSIST(rrbuffer.used < 65536);
541		dns_compress_rollback(cctx, (isc_uint16_t)rrbuffer.used);
542		*countp += added;
543		*target = rrbuffer;
544		goto cleanup;
545	}
546	INSIST(savedbuffer.used < 65536);
547	dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
548	*countp = 0;
549	*target = savedbuffer;
550
551 cleanup:
552	if (sorted != NULL && sorted != sorted_fixed)
553		isc_mem_put(cctx->mctx, sorted, count * sizeof(*sorted));
554	if (shuffled != NULL && shuffled != shuffled_fixed)
555		isc_mem_put(cctx->mctx, shuffled, count * sizeof(*shuffled));
556	return (result);
557}
558
559isc_result_t
560dns_rdataset_towiresorted(dns_rdataset_t *rdataset,
561			  const dns_name_t *owner_name,
562			  dns_compress_t *cctx,
563			  isc_buffer_t *target,
564			  dns_rdatasetorderfunc_t order,
565			  const void *order_arg,
566			  unsigned int options,
567			  unsigned int *countp)
568{
569	return (towiresorted(rdataset, owner_name, cctx, target,
570			     order, order_arg, ISC_FALSE, options,
571			     countp, NULL));
572}
573
574isc_result_t
575dns_rdataset_towirepartial(dns_rdataset_t *rdataset,
576			   const dns_name_t *owner_name,
577			   dns_compress_t *cctx,
578			   isc_buffer_t *target,
579			   dns_rdatasetorderfunc_t order,
580			   const void *order_arg,
581			   unsigned int options,
582			   unsigned int *countp,
583			   void **state)
584{
585	REQUIRE(state == NULL);	/* XXX remove when implemented */
586	return (towiresorted(rdataset, owner_name, cctx, target,
587			     order, order_arg, ISC_TRUE, options,
588			     countp, state));
589}
590
591isc_result_t
592dns_rdataset_towire(dns_rdataset_t *rdataset,
593		    dns_name_t *owner_name,
594		    dns_compress_t *cctx,
595		    isc_buffer_t *target,
596		    unsigned int options,
597		    unsigned int *countp)
598{
599	return (towiresorted(rdataset, owner_name, cctx, target,
600			     NULL, NULL, ISC_FALSE, options, countp, NULL));
601}
602
603isc_result_t
604dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
605			    dns_additionaldatafunc_t add, void *arg)
606{
607	dns_rdata_t rdata = DNS_RDATA_INIT;
608	isc_result_t result;
609
610	/*
611	 * For each rdata in rdataset, call 'add' for each name and type in the
612	 * rdata which is subject to additional section processing.
613	 */
614
615	REQUIRE(DNS_RDATASET_VALID(rdataset));
616	REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
617
618	result = dns_rdataset_first(rdataset);
619	if (result != ISC_R_SUCCESS)
620		return (result);
621
622	do {
623		dns_rdataset_current(rdataset, &rdata);
624		result = dns_rdata_additionaldata(&rdata, add, arg);
625		if (result == ISC_R_SUCCESS)
626			result = dns_rdataset_next(rdataset);
627		dns_rdata_reset(&rdata);
628	} while (result == ISC_R_SUCCESS);
629
630	if (result != ISC_R_NOMORE)
631		return (result);
632
633	return (ISC_R_SUCCESS);
634}
635
636isc_result_t
637dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
638
639	REQUIRE(DNS_RDATASET_VALID(rdataset));
640	REQUIRE(rdataset->methods != NULL);
641	if (rdataset->methods->addnoqname == NULL)
642		return (ISC_R_NOTIMPLEMENTED);
643	return((rdataset->methods->addnoqname)(rdataset, name));
644}
645
646isc_result_t
647dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
648			dns_rdataset_t *neg, dns_rdataset_t *negsig)
649{
650	REQUIRE(DNS_RDATASET_VALID(rdataset));
651	REQUIRE(rdataset->methods != NULL);
652
653	if (rdataset->methods->getnoqname == NULL)
654		return (ISC_R_NOTIMPLEMENTED);
655	return((rdataset->methods->getnoqname)(rdataset, name, neg, negsig));
656}
657
658isc_result_t
659dns_rdataset_addclosest(dns_rdataset_t *rdataset, dns_name_t *name) {
660
661	REQUIRE(DNS_RDATASET_VALID(rdataset));
662	REQUIRE(rdataset->methods != NULL);
663	if (rdataset->methods->addclosest == NULL)
664		return (ISC_R_NOTIMPLEMENTED);
665	return((rdataset->methods->addclosest)(rdataset, name));
666}
667
668isc_result_t
669dns_rdataset_getclosest(dns_rdataset_t *rdataset, dns_name_t *name,
670			dns_rdataset_t *neg, dns_rdataset_t *negsig)
671{
672	REQUIRE(DNS_RDATASET_VALID(rdataset));
673	REQUIRE(rdataset->methods != NULL);
674
675	if (rdataset->methods->getclosest == NULL)
676		return (ISC_R_NOTIMPLEMENTED);
677	return((rdataset->methods->getclosest)(rdataset, name, neg, negsig));
678}
679
680/*
681 * Additional cache stuff
682 */
683isc_result_t
684dns_rdataset_getadditional(dns_rdataset_t *rdataset,
685			   dns_rdatasetadditional_t type,
686			   dns_rdatatype_t qtype,
687			   dns_acache_t *acache,
688			   dns_zone_t **zonep,
689			   dns_db_t **dbp,
690			   dns_dbversion_t **versionp,
691			   dns_dbnode_t **nodep,
692			   dns_name_t *fname,
693			   dns_message_t *msg,
694			   isc_stdtime_t now)
695{
696	REQUIRE(DNS_RDATASET_VALID(rdataset));
697	REQUIRE(rdataset->methods != NULL);
698	REQUIRE(zonep == NULL || *zonep == NULL);
699	REQUIRE(dbp != NULL && *dbp == NULL);
700	REQUIRE(versionp != NULL && *versionp == NULL);
701	REQUIRE(nodep != NULL && *nodep == NULL);
702	REQUIRE(fname != NULL);
703	REQUIRE(msg != NULL);
704
705	if (acache != NULL && rdataset->methods->getadditional != NULL) {
706		return ((rdataset->methods->getadditional)(rdataset, type,
707							   qtype, acache,
708							   zonep, dbp,
709							   versionp, nodep,
710							   fname, msg, now));
711	}
712
713	return (ISC_R_FAILURE);
714}
715
716isc_result_t
717dns_rdataset_setadditional(dns_rdataset_t *rdataset,
718			   dns_rdatasetadditional_t type,
719			   dns_rdatatype_t qtype,
720			   dns_acache_t *acache,
721			   dns_zone_t *zone,
722			   dns_db_t *db,
723			   dns_dbversion_t *version,
724			   dns_dbnode_t *node,
725			   dns_name_t *fname)
726{
727	REQUIRE(DNS_RDATASET_VALID(rdataset));
728	REQUIRE(rdataset->methods != NULL);
729
730	if (acache != NULL && rdataset->methods->setadditional != NULL) {
731		return ((rdataset->methods->setadditional)(rdataset, type,
732							   qtype, acache, zone,
733							   db, version,
734							   node, fname));
735	}
736
737	return (ISC_R_FAILURE);
738}
739
740isc_result_t
741dns_rdataset_putadditional(dns_acache_t *acache,
742			   dns_rdataset_t *rdataset,
743			   dns_rdatasetadditional_t type,
744			   dns_rdatatype_t qtype)
745{
746	REQUIRE(DNS_RDATASET_VALID(rdataset));
747	REQUIRE(rdataset->methods != NULL);
748
749	if (acache != NULL && rdataset->methods->putadditional != NULL) {
750		return ((rdataset->methods->putadditional)(acache, rdataset,
751							   type, qtype));
752	}
753
754	return (ISC_R_FAILURE);
755}
756
757void
758dns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
759	REQUIRE(DNS_RDATASET_VALID(rdataset));
760	REQUIRE(rdataset->methods != NULL);
761
762	if (rdataset->methods->settrust != NULL)
763		(rdataset->methods->settrust)(rdataset, trust);
764	else
765		rdataset->trust = trust;
766}
767
768void
769dns_rdataset_expire(dns_rdataset_t *rdataset) {
770	REQUIRE(DNS_RDATASET_VALID(rdataset));
771	REQUIRE(rdataset->methods != NULL);
772
773	if (rdataset->methods->expire != NULL)
774		(rdataset->methods->expire)(rdataset);
775}
776
777void
778dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
779		     dns_rdata_rrsig_t *rrsig, isc_stdtime_t now,
780		     isc_boolean_t acceptexpired)
781{
782	isc_uint32_t ttl = 0;
783
784	REQUIRE(DNS_RDATASET_VALID(rdataset));
785	REQUIRE(DNS_RDATASET_VALID(sigrdataset));
786	REQUIRE(rrsig != NULL);
787
788	/*
789	 * If we accept expired RRsets keep them for no more than 120 seconds.
790	 */
791	if (acceptexpired &&
792	    (isc_serial_le(rrsig->timeexpire, ((now + 120) & 0xffffffff)) ||
793	     isc_serial_le(rrsig->timeexpire, now)))
794		ttl = 120;
795	else if (isc_serial_ge(rrsig->timeexpire, now))
796		ttl = rrsig->timeexpire - now;
797
798	ttl = ISC_MIN(ISC_MIN(rdataset->ttl, sigrdataset->ttl),
799		      ISC_MIN(rrsig->originalttl, ttl));
800	rdataset->ttl = ttl;
801	sigrdataset->ttl = ttl;
802}
803