vendor/BIND: Update to 9.5.2-P3
[dragonfly.git] / contrib / bind / lib / dns / rdataset.c
blob142438ed17872f7139b6d21ad7c0e86fde598d3d
1 /*
2 * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
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.
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.
18 /* $Id: rdataset.c,v 1.79.128.2.2.2 2010/02/25 10:56:01 tbox Exp $ */
20 /*! \file */
22 #include <config.h>
24 #include <stdlib.h>
26 #include <isc/buffer.h>
27 #include <isc/mem.h>
28 #include <isc/random.h>
29 #include <isc/util.h>
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>
37 void
38 dns_rdataset_init(dns_rdataset_t *rdataset) {
41 * Make 'rdataset' a valid, disassociated rdataset.
44 REQUIRE(rdataset != NULL);
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;
64 void
65 dns_rdataset_invalidate(dns_rdataset_t *rdataset) {
68 * Invalidate 'rdataset'.
71 REQUIRE(DNS_RDATASET_VALID(rdataset));
72 REQUIRE(rdataset->methods == NULL);
74 rdataset->magic = 0;
75 ISC_LINK_INIT(rdataset, link);
76 rdataset->rdclass = 0;
77 rdataset->type = 0;
78 rdataset->ttl = 0;
79 rdataset->trust = 0;
80 rdataset->covers = 0;
81 rdataset->attributes = 0;
82 rdataset->count = ISC_UINT32_MAX;
83 rdataset->private1 = NULL;
84 rdataset->private2 = NULL;
85 rdataset->private3 = NULL;
86 rdataset->privateuint4 = 0;
87 rdataset->private5 = NULL;
90 void
91 dns_rdataset_disassociate(dns_rdataset_t *rdataset) {
94 * Disassociate 'rdataset' from its rdata, allowing it to be reused.
97 REQUIRE(DNS_RDATASET_VALID(rdataset));
98 REQUIRE(rdataset->methods != NULL);
100 (rdataset->methods->disassociate)(rdataset);
101 rdataset->methods = NULL;
102 ISC_LINK_INIT(rdataset, link);
103 rdataset->rdclass = 0;
104 rdataset->type = 0;
105 rdataset->ttl = 0;
106 rdataset->trust = 0;
107 rdataset->covers = 0;
108 rdataset->attributes = 0;
109 rdataset->count = ISC_UINT32_MAX;
110 rdataset->private1 = NULL;
111 rdataset->private2 = NULL;
112 rdataset->private3 = NULL;
113 rdataset->privateuint4 = 0;
114 rdataset->private5 = NULL;
115 rdataset->private6 = NULL;
118 isc_boolean_t
119 dns_rdataset_isassociated(dns_rdataset_t *rdataset) {
121 * Is 'rdataset' associated?
124 REQUIRE(DNS_RDATASET_VALID(rdataset));
126 if (rdataset->methods != NULL)
127 return (ISC_TRUE);
129 return (ISC_FALSE);
132 static void
133 question_disassociate(dns_rdataset_t *rdataset) {
134 UNUSED(rdataset);
137 static isc_result_t
138 question_cursor(dns_rdataset_t *rdataset) {
139 UNUSED(rdataset);
141 return (ISC_R_NOMORE);
144 static void
145 question_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
147 * This routine should never be called.
149 UNUSED(rdataset);
150 UNUSED(rdata);
152 REQUIRE(0);
155 static void
156 question_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
157 *target = *source;
160 static unsigned int
161 question_count(dns_rdataset_t *rdataset) {
163 * This routine should never be called.
165 UNUSED(rdataset);
166 REQUIRE(0);
168 return (0);
171 static dns_rdatasetmethods_t question_methods = {
172 question_disassociate,
173 question_cursor,
174 question_cursor,
175 question_current,
176 question_clone,
177 question_count,
178 NULL,
179 NULL,
180 NULL,
181 NULL,
182 NULL,
183 NULL,
184 NULL
187 void
188 dns_rdataset_makequestion(dns_rdataset_t *rdataset, dns_rdataclass_t rdclass,
189 dns_rdatatype_t type)
193 * Make 'rdataset' a valid, associated, question rdataset, with a
194 * question class of 'rdclass' and type 'type'.
197 REQUIRE(DNS_RDATASET_VALID(rdataset));
198 REQUIRE(rdataset->methods == NULL);
200 rdataset->methods = &question_methods;
201 rdataset->rdclass = rdclass;
202 rdataset->type = type;
203 rdataset->attributes |= DNS_RDATASETATTR_QUESTION;
206 unsigned int
207 dns_rdataset_count(dns_rdataset_t *rdataset) {
210 * Return the number of records in 'rdataset'.
213 REQUIRE(DNS_RDATASET_VALID(rdataset));
214 REQUIRE(rdataset->methods != NULL);
216 return ((rdataset->methods->count)(rdataset));
219 void
220 dns_rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
223 * Make 'target' refer to the same rdataset as 'source'.
226 REQUIRE(DNS_RDATASET_VALID(source));
227 REQUIRE(source->methods != NULL);
228 REQUIRE(DNS_RDATASET_VALID(target));
229 REQUIRE(target->methods == NULL);
231 (source->methods->clone)(source, target);
234 isc_result_t
235 dns_rdataset_first(dns_rdataset_t *rdataset) {
238 * Move the rdata cursor to the first rdata in the rdataset (if any).
241 REQUIRE(DNS_RDATASET_VALID(rdataset));
242 REQUIRE(rdataset->methods != NULL);
244 return ((rdataset->methods->first)(rdataset));
247 isc_result_t
248 dns_rdataset_next(dns_rdataset_t *rdataset) {
251 * Move the rdata cursor to the next rdata in the rdataset (if any).
254 REQUIRE(DNS_RDATASET_VALID(rdataset));
255 REQUIRE(rdataset->methods != NULL);
257 return ((rdataset->methods->next)(rdataset));
260 void
261 dns_rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
264 * Make 'rdata' refer to the current rdata.
267 REQUIRE(DNS_RDATASET_VALID(rdataset));
268 REQUIRE(rdataset->methods != NULL);
270 (rdataset->methods->current)(rdataset, rdata);
273 #define MAX_SHUFFLE 32
274 #define WANT_FIXED(r) (((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
275 #define WANT_RANDOM(r) (((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
277 struct towire_sort {
278 int key;
279 dns_rdata_t *rdata;
282 static int
283 towire_compare(const void *av, const void *bv) {
284 const struct towire_sort *a = (const struct towire_sort *) av;
285 const struct towire_sort *b = (const struct towire_sort *) bv;
286 return (a->key - b->key);
289 static isc_result_t
290 towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
291 dns_compress_t *cctx, isc_buffer_t *target,
292 dns_rdatasetorderfunc_t order, const void *order_arg,
293 isc_boolean_t partial, unsigned int options,
294 unsigned int *countp, void **state)
296 dns_rdata_t rdata = DNS_RDATA_INIT;
297 isc_region_t r;
298 isc_result_t result;
299 unsigned int i, count, added, choice;
300 isc_buffer_t savedbuffer, rdlen, rrbuffer;
301 unsigned int headlen;
302 isc_boolean_t question = ISC_FALSE;
303 isc_boolean_t shuffle = ISC_FALSE;
304 dns_rdata_t *shuffled = NULL, shuffled_fixed[MAX_SHUFFLE];
305 struct towire_sort *sorted = NULL, sorted_fixed[MAX_SHUFFLE];
307 UNUSED(state);
310 * Convert 'rdataset' to wire format, compressing names as specified
311 * in cctx, and storing the result in 'target'.
314 REQUIRE(DNS_RDATASET_VALID(rdataset));
315 REQUIRE(countp != NULL);
316 REQUIRE((order == NULL) == (order_arg == NULL));
317 REQUIRE(cctx != NULL && cctx->mctx != NULL);
319 count = 0;
320 if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
321 question = ISC_TRUE;
322 count = 1;
323 result = dns_rdataset_first(rdataset);
324 INSIST(result == ISC_R_NOMORE);
325 } else if (rdataset->type == 0) {
327 * This is a negative caching rdataset.
329 unsigned int ncache_opts = 0;
330 if ((options & DNS_RDATASETTOWIRE_OMITDNSSEC) != 0)
331 ncache_opts |= DNS_NCACHETOWIRE_OMITDNSSEC;
332 return (dns_ncache_towire(rdataset, cctx, target, ncache_opts,
333 countp));
334 } else {
335 count = (rdataset->methods->count)(rdataset);
336 result = dns_rdataset_first(rdataset);
337 if (result == ISC_R_NOMORE)
338 return (ISC_R_SUCCESS);
339 if (result != ISC_R_SUCCESS)
340 return (result);
344 * Do we want to shuffle this answer?
346 if (!question && count > 1 &&
347 (!WANT_FIXED(rdataset) || order != NULL) &&
348 rdataset->type != dns_rdatatype_rrsig)
349 shuffle = ISC_TRUE;
351 if (shuffle && count > MAX_SHUFFLE) {
352 shuffled = isc_mem_get(cctx->mctx, count * sizeof(*shuffled));
353 sorted = isc_mem_get(cctx->mctx, count * sizeof(*sorted));
354 if (shuffled == NULL || sorted == NULL)
355 shuffle = ISC_FALSE;
356 } else {
357 shuffled = shuffled_fixed;
358 sorted = sorted_fixed;
361 if (shuffle) {
363 * First we get handles to all of the rdata.
365 i = 0;
366 do {
367 INSIST(i < count);
368 dns_rdata_init(&shuffled[i]);
369 dns_rdataset_current(rdataset, &shuffled[i]);
370 i++;
371 result = dns_rdataset_next(rdataset);
372 } while (result == ISC_R_SUCCESS);
373 if (result != ISC_R_NOMORE)
374 goto cleanup;
375 INSIST(i == count);
378 * Now we shuffle.
380 if (WANT_FIXED(rdataset)) {
382 * 'Fixed' order.
384 INSIST(order != NULL);
385 for (i = 0; i < count; i++) {
386 sorted[i].key = (*order)(&shuffled[i],
387 order_arg);
388 sorted[i].rdata = &shuffled[i];
390 } else if (WANT_RANDOM(rdataset)) {
392 * 'Random' order.
394 for (i = 0; i < count; i++) {
395 dns_rdata_t rdata;
396 isc_uint32_t val;
398 isc_random_get(&val);
399 choice = i + (val % (count - i));
400 rdata = shuffled[i];
401 shuffled[i] = shuffled[choice];
402 shuffled[choice] = rdata;
403 if (order != NULL)
404 sorted[i].key = (*order)(&shuffled[i],
405 order_arg);
406 else
407 sorted[i].key = 0; /* Unused */
408 sorted[i].rdata = &shuffled[i];
410 } else {
412 * "Cyclic" order.
414 isc_uint32_t val;
415 unsigned int j;
417 val = rdataset->count;
418 if (val == ISC_UINT32_MAX)
419 isc_random_get(&val);
420 j = val % count;
421 for (i = 0; i < count; i++) {
422 if (order != NULL)
423 sorted[j].key = (*order)(&shuffled[i],
424 order_arg);
425 else
426 sorted[j].key = 0; /* Unused */
427 sorted[j].rdata = &shuffled[i];
428 j++;
429 if (j == count)
430 j = 0; /* Wrap around. */
435 * Sorted order.
437 if (order != NULL)
438 qsort(sorted, count, sizeof(sorted[0]),
439 towire_compare);
442 savedbuffer = *target;
443 i = 0;
444 added = 0;
446 do {
448 * Copy out the name, type, class, ttl.
451 rrbuffer = *target;
452 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
453 result = dns_name_towire(owner_name, cctx, target);
454 if (result != ISC_R_SUCCESS)
455 goto rollback;
456 headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
457 if (!question)
458 headlen += sizeof(dns_ttl_t)
459 + 2; /* XXX 2 for rdata len */
460 isc_buffer_availableregion(target, &r);
461 if (r.length < headlen) {
462 result = ISC_R_NOSPACE;
463 goto rollback;
465 isc_buffer_putuint16(target, rdataset->type);
466 isc_buffer_putuint16(target, rdataset->rdclass);
467 if (!question) {
468 isc_buffer_putuint32(target, rdataset->ttl);
471 * Save space for rdlen.
473 rdlen = *target;
474 isc_buffer_add(target, 2);
477 * Copy out the rdata
479 if (shuffle)
480 rdata = *(sorted[i].rdata);
481 else {
482 dns_rdata_reset(&rdata);
483 dns_rdataset_current(rdataset, &rdata);
485 result = dns_rdata_towire(&rdata, cctx, target);
486 if (result != ISC_R_SUCCESS)
487 goto rollback;
488 INSIST((target->used >= rdlen.used + 2) &&
489 (target->used - rdlen.used - 2 < 65536));
490 isc_buffer_putuint16(&rdlen,
491 (isc_uint16_t)(target->used -
492 rdlen.used - 2));
493 added++;
496 if (shuffle) {
497 i++;
498 if (i == count)
499 result = ISC_R_NOMORE;
500 else
501 result = ISC_R_SUCCESS;
502 } else {
503 result = dns_rdataset_next(rdataset);
505 } while (result == ISC_R_SUCCESS);
507 if (result != ISC_R_NOMORE)
508 goto rollback;
510 *countp += count;
512 result = ISC_R_SUCCESS;
513 goto cleanup;
515 rollback:
516 if (partial && result == ISC_R_NOSPACE) {
517 INSIST(rrbuffer.used < 65536);
518 dns_compress_rollback(cctx, (isc_uint16_t)rrbuffer.used);
519 *countp += added;
520 *target = rrbuffer;
521 goto cleanup;
523 INSIST(savedbuffer.used < 65536);
524 dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
525 *countp = 0;
526 *target = savedbuffer;
528 cleanup:
529 if (sorted != NULL && sorted != sorted_fixed)
530 isc_mem_put(cctx->mctx, sorted, count * sizeof(*sorted));
531 if (shuffled != NULL && shuffled != shuffled_fixed)
532 isc_mem_put(cctx->mctx, shuffled, count * sizeof(*shuffled));
533 return (result);
536 isc_result_t
537 dns_rdataset_towiresorted(dns_rdataset_t *rdataset,
538 const dns_name_t *owner_name,
539 dns_compress_t *cctx,
540 isc_buffer_t *target,
541 dns_rdatasetorderfunc_t order,
542 const void *order_arg,
543 unsigned int options,
544 unsigned int *countp)
546 return (towiresorted(rdataset, owner_name, cctx, target,
547 order, order_arg, ISC_FALSE, options,
548 countp, NULL));
551 isc_result_t
552 dns_rdataset_towirepartial(dns_rdataset_t *rdataset,
553 const dns_name_t *owner_name,
554 dns_compress_t *cctx,
555 isc_buffer_t *target,
556 dns_rdatasetorderfunc_t order,
557 const void *order_arg,
558 unsigned int options,
559 unsigned int *countp,
560 void **state)
562 REQUIRE(state == NULL); /* XXX remove when implemented */
563 return (towiresorted(rdataset, owner_name, cctx, target,
564 order, order_arg, ISC_TRUE, options,
565 countp, state));
568 isc_result_t
569 dns_rdataset_towire(dns_rdataset_t *rdataset,
570 dns_name_t *owner_name,
571 dns_compress_t *cctx,
572 isc_buffer_t *target,
573 unsigned int options,
574 unsigned int *countp)
576 return (towiresorted(rdataset, owner_name, cctx, target,
577 NULL, NULL, ISC_FALSE, options, countp, NULL));
580 isc_result_t
581 dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
582 dns_additionaldatafunc_t add, void *arg)
584 dns_rdata_t rdata = DNS_RDATA_INIT;
585 isc_result_t result;
588 * For each rdata in rdataset, call 'add' for each name and type in the
589 * rdata which is subject to additional section processing.
592 REQUIRE(DNS_RDATASET_VALID(rdataset));
593 REQUIRE((rdataset->attributes & DNS_RDATASETATTR_QUESTION) == 0);
595 result = dns_rdataset_first(rdataset);
596 if (result != ISC_R_SUCCESS)
597 return (result);
599 do {
600 dns_rdataset_current(rdataset, &rdata);
601 result = dns_rdata_additionaldata(&rdata, add, arg);
602 if (result == ISC_R_SUCCESS)
603 result = dns_rdataset_next(rdataset);
604 dns_rdata_reset(&rdata);
605 } while (result == ISC_R_SUCCESS);
607 if (result != ISC_R_NOMORE)
608 return (result);
610 return (ISC_R_SUCCESS);
613 isc_result_t
614 dns_rdataset_addnoqname(dns_rdataset_t *rdataset, dns_name_t *name) {
616 REQUIRE(DNS_RDATASET_VALID(rdataset));
617 REQUIRE(rdataset->methods != NULL);
618 if (rdataset->methods->addnoqname == NULL)
619 return (ISC_R_NOTIMPLEMENTED);
620 return((rdataset->methods->addnoqname)(rdataset, name));
623 isc_result_t
624 dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
625 dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
627 REQUIRE(DNS_RDATASET_VALID(rdataset));
628 REQUIRE(rdataset->methods != NULL);
630 if (rdataset->methods->getnoqname == NULL)
631 return (ISC_R_NOTIMPLEMENTED);
632 return((rdataset->methods->getnoqname)(rdataset, name, nsec, nsecsig));
636 * Additional cache stuff
638 isc_result_t
639 dns_rdataset_getadditional(dns_rdataset_t *rdataset,
640 dns_rdatasetadditional_t type,
641 dns_rdatatype_t qtype,
642 dns_acache_t *acache,
643 dns_zone_t **zonep,
644 dns_db_t **dbp,
645 dns_dbversion_t **versionp,
646 dns_dbnode_t **nodep,
647 dns_name_t *fname,
648 dns_message_t *msg,
649 isc_stdtime_t now)
651 REQUIRE(DNS_RDATASET_VALID(rdataset));
652 REQUIRE(rdataset->methods != NULL);
653 REQUIRE(zonep == NULL || *zonep == NULL);
654 REQUIRE(dbp != NULL && *dbp == NULL);
655 REQUIRE(versionp != NULL && *versionp == NULL);
656 REQUIRE(nodep != NULL && *nodep == NULL);
657 REQUIRE(fname != NULL);
658 REQUIRE(msg != NULL);
660 if (acache != NULL && rdataset->methods->getadditional != NULL) {
661 return ((rdataset->methods->getadditional)(rdataset, type,
662 qtype, acache,
663 zonep, dbp,
664 versionp, nodep,
665 fname, msg, now));
668 return (ISC_R_FAILURE);
671 isc_result_t
672 dns_rdataset_setadditional(dns_rdataset_t *rdataset,
673 dns_rdatasetadditional_t type,
674 dns_rdatatype_t qtype,
675 dns_acache_t *acache,
676 dns_zone_t *zone,
677 dns_db_t *db,
678 dns_dbversion_t *version,
679 dns_dbnode_t *node,
680 dns_name_t *fname)
682 REQUIRE(DNS_RDATASET_VALID(rdataset));
683 REQUIRE(rdataset->methods != NULL);
685 if (acache != NULL && rdataset->methods->setadditional != NULL) {
686 return ((rdataset->methods->setadditional)(rdataset, type,
687 qtype, acache, zone,
688 db, version,
689 node, fname));
692 return (ISC_R_FAILURE);
695 isc_result_t
696 dns_rdataset_putadditional(dns_acache_t *acache,
697 dns_rdataset_t *rdataset,
698 dns_rdatasetadditional_t type,
699 dns_rdatatype_t qtype)
701 REQUIRE(DNS_RDATASET_VALID(rdataset));
702 REQUIRE(rdataset->methods != NULL);
704 if (acache != NULL && rdataset->methods->putadditional != NULL) {
705 return ((rdataset->methods->putadditional)(acache, rdataset,
706 type, qtype));
709 return (ISC_R_FAILURE);
712 void
713 dns_rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
714 REQUIRE(DNS_RDATASET_VALID(rdataset));
715 REQUIRE(rdataset->methods != NULL);
717 if (rdataset->methods->settrust != NULL)
718 (rdataset->methods->settrust)(rdataset, trust);
719 else
720 rdataset->trust = trust;
723 void
724 dns_rdataset_expire(dns_rdataset_t *rdataset) {
725 REQUIRE(DNS_RDATASET_VALID(rdataset));
726 REQUIRE(rdataset->methods != NULL);
728 if (rdataset->methods->expire != NULL)
729 (rdataset->methods->expire)(rdataset);