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