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
);