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