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 $ */
26 #include <isc/buffer.h>
28 #include <isc/random.h>
32 #include <dns/ncache.h>
33 #include <dns/rdata.h>
34 #include <dns/rdataset.h>
35 #include <dns/compress.h>
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;
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;
65 dns_rdataset_invalidate(dns_rdataset_t *rdataset) {
68 * Invalidate 'rdataset'.
71 REQUIRE(DNS_RDATASET_VALID(rdataset));
72 REQUIRE(rdataset->methods == NULL);
75 ISC_LINK_INIT(rdataset, link);
76 rdataset->rdclass = 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;
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;
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;
119 dns_rdataset_isassociated(dns_rdataset_t *rdataset) {
121 * Is 'rdataset' associated?
124 REQUIRE(DNS_RDATASET_VALID(rdataset));
126 if (rdataset->methods != NULL)
133 question_disassociate(dns_rdataset_t *rdataset) {
138 question_cursor(dns_rdataset_t *rdataset) {
141 return (ISC_R_NOMORE);
145 question_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
147 * This routine should never be called.
156 question_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
161 question_count(dns_rdataset_t *rdataset) {
163 * This routine should never be called.
171 static dns_rdatasetmethods_t question_methods = {
172 question_disassociate,
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;
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));
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);
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));
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));
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)
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);
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;
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];
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);
320 if ((rdataset->attributes & DNS_RDATASETATTR_QUESTION) != 0) {
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,
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)
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)
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)
357 shuffled = shuffled_fixed;
358 sorted = sorted_fixed;
363 * First we get handles to all of the rdata.
368 dns_rdata_init(&shuffled[i]);
369 dns_rdataset_current(rdataset, &shuffled[i]);
371 result = dns_rdataset_next(rdataset);
372 } while (result == ISC_R_SUCCESS);
373 if (result != ISC_R_NOMORE)
380 if (WANT_FIXED(rdataset)) {
384 INSIST(order != NULL);
385 for (i = 0; i < count; i++) {
386 sorted[i].key = (*order)(&shuffled[i],
388 sorted[i].rdata = &shuffled[i];
390 } else if (WANT_RANDOM(rdataset)) {
394 for (i = 0; i < count; i++) {
398 isc_random_get(&val);
399 choice = i + (val % (count - i));
401 shuffled[i] = shuffled[choice];
402 shuffled[choice] = rdata;
404 sorted[i].key = (*order)(&shuffled[i],
407 sorted[i].key = 0; /* Unused */
408 sorted[i].rdata = &shuffled[i];
417 val = rdataset->count;
418 if (val == ISC_UINT32_MAX)
419 isc_random_get(&val);
421 for (i = 0; i < count; i++) {
423 sorted[j].key = (*order)(&shuffled[i],
426 sorted[j].key = 0; /* Unused */
427 sorted[j].rdata = &shuffled[i];
430 j = 0; /* Wrap around. */
438 qsort(sorted, count, sizeof(sorted[0]),
442 savedbuffer = *target;
448 * Copy out the name, type, class, ttl.
452 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
453 result = dns_name_towire(owner_name, cctx, target);
454 if (result != ISC_R_SUCCESS)
456 headlen = sizeof(dns_rdataclass_t) + sizeof(dns_rdatatype_t);
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;
465 isc_buffer_putuint16(target, rdataset->type);
466 isc_buffer_putuint16(target, rdataset->rdclass);
468 isc_buffer_putuint32(target, rdataset->ttl);
471 * Save space for rdlen.
474 isc_buffer_add(target, 2);
480 rdata = *(sorted[i].rdata);
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)
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 -
499 result = ISC_R_NOMORE;
501 result = ISC_R_SUCCESS;
503 result = dns_rdataset_next(rdataset);
505 } while (result == ISC_R_SUCCESS);
507 if (result != ISC_R_NOMORE)
512 result = ISC_R_SUCCESS;
516 if (partial && result == ISC_R_NOSPACE) {
517 INSIST(rrbuffer.used < 65536);
518 dns_compress_rollback(cctx, (isc_uint16_t)rrbuffer.used);
523 INSIST(savedbuffer.used < 65536);
524 dns_compress_rollback(cctx, (isc_uint16_t)savedbuffer.used);
526 *target = savedbuffer;
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));
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,
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,
562 REQUIRE(state == NULL); /* XXX remove when implemented */
563 return (towiresorted(rdataset, owner_name, cctx, target,
564 order, order_arg, ISC_TRUE, options,
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));
581 dns_rdataset_additionaldata(dns_rdataset_t *rdataset,
582 dns_additionaldatafunc_t add, void *arg)
584 dns_rdata_t rdata = DNS_RDATA_INIT;
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)
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)
610 return (ISC_R_SUCCESS);
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));
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
639 dns_rdataset_getadditional(dns_rdataset_t *rdataset,
640 dns_rdatasetadditional_t type,
641 dns_rdatatype_t qtype,
642 dns_acache_t *acache,
645 dns_dbversion_t **versionp,
646 dns_dbnode_t **nodep,
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,
668 return (ISC_R_FAILURE);
672 dns_rdataset_setadditional(dns_rdataset_t *rdataset,
673 dns_rdatasetadditional_t type,
674 dns_rdatatype_t qtype,
675 dns_acache_t *acache,
678 dns_dbversion_t *version,
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,
692 return (ISC_R_FAILURE);
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,
709 return (ISC_R_FAILURE);
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);
720 rdataset->trust = trust;
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);