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