2 * Copyright (C) 2004-2007, 2009 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 2009/01/19 23:47:02 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
,
186 dns_rdataset_makequestion(dns_rdataset_t
*rdataset
, dns_rdataclass_t rdclass
,
187 dns_rdatatype_t type
)
191 * Make 'rdataset' a valid, associated, question rdataset, with a
192 * question class of 'rdclass' and type 'type'.
195 REQUIRE(DNS_RDATASET_VALID(rdataset
));
196 REQUIRE(rdataset
->methods
== NULL
);
198 rdataset
->methods
= &question_methods
;
199 rdataset
->rdclass
= rdclass
;
200 rdataset
->type
= type
;
201 rdataset
->attributes
|= DNS_RDATASETATTR_QUESTION
;
205 dns_rdataset_count(dns_rdataset_t
*rdataset
) {
208 * Return the number of records in 'rdataset'.
211 REQUIRE(DNS_RDATASET_VALID(rdataset
));
212 REQUIRE(rdataset
->methods
!= NULL
);
214 return ((rdataset
->methods
->count
)(rdataset
));
218 dns_rdataset_clone(dns_rdataset_t
*source
, dns_rdataset_t
*target
) {
221 * Make 'target' refer to the same rdataset as 'source'.
224 REQUIRE(DNS_RDATASET_VALID(source
));
225 REQUIRE(source
->methods
!= NULL
);
226 REQUIRE(DNS_RDATASET_VALID(target
));
227 REQUIRE(target
->methods
== NULL
);
229 (source
->methods
->clone
)(source
, target
);
233 dns_rdataset_first(dns_rdataset_t
*rdataset
) {
236 * Move the rdata cursor to the first rdata in the rdataset (if any).
239 REQUIRE(DNS_RDATASET_VALID(rdataset
));
240 REQUIRE(rdataset
->methods
!= NULL
);
242 return ((rdataset
->methods
->first
)(rdataset
));
246 dns_rdataset_next(dns_rdataset_t
*rdataset
) {
249 * Move the rdata cursor to the next rdata in the rdataset (if any).
252 REQUIRE(DNS_RDATASET_VALID(rdataset
));
253 REQUIRE(rdataset
->methods
!= NULL
);
255 return ((rdataset
->methods
->next
)(rdataset
));
259 dns_rdataset_current(dns_rdataset_t
*rdataset
, dns_rdata_t
*rdata
) {
262 * Make 'rdata' refer to the current rdata.
265 REQUIRE(DNS_RDATASET_VALID(rdataset
));
266 REQUIRE(rdataset
->methods
!= NULL
);
268 (rdataset
->methods
->current
)(rdataset
, rdata
);
271 #define MAX_SHUFFLE 32
272 #define WANT_FIXED(r) (((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
273 #define WANT_RANDOM(r) (((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
281 towire_compare(const void *av
, const void *bv
) {
282 const struct towire_sort
*a
= (const struct towire_sort
*) av
;
283 const struct towire_sort
*b
= (const struct towire_sort
*) bv
;
284 return (a
->key
- b
->key
);
288 towiresorted(dns_rdataset_t
*rdataset
, const dns_name_t
*owner_name
,
289 dns_compress_t
*cctx
, isc_buffer_t
*target
,
290 dns_rdatasetorderfunc_t order
, const void *order_arg
,
291 isc_boolean_t partial
, unsigned int options
,
292 unsigned int *countp
, void **state
)
294 dns_rdata_t rdata
= DNS_RDATA_INIT
;
297 unsigned int i
, count
, added
, choice
;
298 isc_buffer_t savedbuffer
, rdlen
, rrbuffer
;
299 unsigned int headlen
;
300 isc_boolean_t question
= ISC_FALSE
;
301 isc_boolean_t shuffle
= ISC_FALSE
;
302 dns_rdata_t
*shuffled
= NULL
, shuffled_fixed
[MAX_SHUFFLE
];
303 struct towire_sort
*sorted
= NULL
, sorted_fixed
[MAX_SHUFFLE
];
308 * Convert 'rdataset' to wire format, compressing names as specified
309 * in cctx, and storing the result in 'target'.
312 REQUIRE(DNS_RDATASET_VALID(rdataset
));
313 REQUIRE(countp
!= NULL
);
314 REQUIRE((order
== NULL
) == (order_arg
== NULL
));
315 REQUIRE(cctx
!= NULL
&& cctx
->mctx
!= NULL
);
318 if ((rdataset
->attributes
& DNS_RDATASETATTR_QUESTION
) != 0) {
321 result
= dns_rdataset_first(rdataset
);
322 INSIST(result
== ISC_R_NOMORE
);
323 } else if (rdataset
->type
== 0) {
325 * This is a negative caching rdataset.
327 unsigned int ncache_opts
= 0;
328 if ((options
& DNS_RDATASETTOWIRE_OMITDNSSEC
) != 0)
329 ncache_opts
|= DNS_NCACHETOWIRE_OMITDNSSEC
;
330 return (dns_ncache_towire(rdataset
, cctx
, target
, ncache_opts
,
333 count
= (rdataset
->methods
->count
)(rdataset
);
334 result
= dns_rdataset_first(rdataset
);
335 if (result
== ISC_R_NOMORE
)
336 return (ISC_R_SUCCESS
);
337 if (result
!= ISC_R_SUCCESS
)
342 * Do we want to shuffle this answer?
344 if (!question
&& count
> 1 &&
345 (!WANT_FIXED(rdataset
) || order
!= NULL
) &&
346 rdataset
->type
!= dns_rdatatype_rrsig
)
349 if (shuffle
&& count
> MAX_SHUFFLE
) {
350 shuffled
= isc_mem_get(cctx
->mctx
, count
* sizeof(*shuffled
));
351 sorted
= isc_mem_get(cctx
->mctx
, count
* sizeof(*sorted
));
352 if (shuffled
== NULL
|| sorted
== NULL
)
355 shuffled
= shuffled_fixed
;
356 sorted
= sorted_fixed
;
361 * First we get handles to all of the rdata.
366 dns_rdata_init(&shuffled
[i
]);
367 dns_rdataset_current(rdataset
, &shuffled
[i
]);
369 result
= dns_rdataset_next(rdataset
);
370 } while (result
== ISC_R_SUCCESS
);
371 if (result
!= ISC_R_NOMORE
)
378 if (WANT_FIXED(rdataset
)) {
382 INSIST(order
!= NULL
);
383 for (i
= 0; i
< count
; i
++) {
384 sorted
[i
].key
= (*order
)(&shuffled
[i
],
386 sorted
[i
].rdata
= &shuffled
[i
];
388 } else if (WANT_RANDOM(rdataset
)) {
392 for (i
= 0; i
< count
; i
++) {
396 isc_random_get(&val
);
397 choice
= i
+ (val
% (count
- i
));
399 shuffled
[i
] = shuffled
[choice
];
400 shuffled
[choice
] = rdata
;
402 sorted
[i
].key
= (*order
)(&shuffled
[i
],
405 sorted
[i
].key
= 0; /* Unused */
406 sorted
[i
].rdata
= &shuffled
[i
];
415 val
= rdataset
->count
;
416 if (val
== ISC_UINT32_MAX
)
417 isc_random_get(&val
);
419 for (i
= 0; i
< count
; i
++) {
421 sorted
[j
].key
= (*order
)(&shuffled
[i
],
424 sorted
[j
].key
= 0; /* Unused */
425 sorted
[j
].rdata
= &shuffled
[i
];
428 j
= 0; /* Wrap around. */
436 qsort(sorted
, count
, sizeof(sorted
[0]),
440 savedbuffer
= *target
;
446 * Copy out the name, type, class, ttl.
450 dns_compress_setmethods(cctx
, DNS_COMPRESS_GLOBAL14
);
451 result
= dns_name_towire(owner_name
, cctx
, target
);
452 if (result
!= ISC_R_SUCCESS
)
454 headlen
= sizeof(dns_rdataclass_t
) + sizeof(dns_rdatatype_t
);
456 headlen
+= sizeof(dns_ttl_t
)
457 + 2; /* XXX 2 for rdata len */
458 isc_buffer_availableregion(target
, &r
);
459 if (r
.length
< headlen
) {
460 result
= ISC_R_NOSPACE
;
463 isc_buffer_putuint16(target
, rdataset
->type
);
464 isc_buffer_putuint16(target
, rdataset
->rdclass
);
466 isc_buffer_putuint32(target
, rdataset
->ttl
);
469 * Save space for rdlen.
472 isc_buffer_add(target
, 2);
478 rdata
= *(sorted
[i
].rdata
);
480 dns_rdata_reset(&rdata
);
481 dns_rdataset_current(rdataset
, &rdata
);
483 result
= dns_rdata_towire(&rdata
, cctx
, target
);
484 if (result
!= ISC_R_SUCCESS
)
486 INSIST((target
->used
>= rdlen
.used
+ 2) &&
487 (target
->used
- rdlen
.used
- 2 < 65536));
488 isc_buffer_putuint16(&rdlen
,
489 (isc_uint16_t
)(target
->used
-
497 result
= ISC_R_NOMORE
;
499 result
= ISC_R_SUCCESS
;
501 result
= dns_rdataset_next(rdataset
);
503 } while (result
== ISC_R_SUCCESS
);
505 if (result
!= ISC_R_NOMORE
)
510 result
= ISC_R_SUCCESS
;
514 if (partial
&& result
== ISC_R_NOSPACE
) {
515 INSIST(rrbuffer
.used
< 65536);
516 dns_compress_rollback(cctx
, (isc_uint16_t
)rrbuffer
.used
);
521 INSIST(savedbuffer
.used
< 65536);
522 dns_compress_rollback(cctx
, (isc_uint16_t
)savedbuffer
.used
);
524 *target
= savedbuffer
;
527 if (sorted
!= NULL
&& sorted
!= sorted_fixed
)
528 isc_mem_put(cctx
->mctx
, sorted
, count
* sizeof(*sorted
));
529 if (shuffled
!= NULL
&& shuffled
!= shuffled_fixed
)
530 isc_mem_put(cctx
->mctx
, shuffled
, count
* sizeof(*shuffled
));
535 dns_rdataset_towiresorted(dns_rdataset_t
*rdataset
,
536 const dns_name_t
*owner_name
,
537 dns_compress_t
*cctx
,
538 isc_buffer_t
*target
,
539 dns_rdatasetorderfunc_t order
,
540 const void *order_arg
,
541 unsigned int options
,
542 unsigned int *countp
)
544 return (towiresorted(rdataset
, owner_name
, cctx
, target
,
545 order
, order_arg
, ISC_FALSE
, options
,
550 dns_rdataset_towirepartial(dns_rdataset_t
*rdataset
,
551 const dns_name_t
*owner_name
,
552 dns_compress_t
*cctx
,
553 isc_buffer_t
*target
,
554 dns_rdatasetorderfunc_t order
,
555 const void *order_arg
,
556 unsigned int options
,
557 unsigned int *countp
,
560 REQUIRE(state
== NULL
); /* XXX remove when implemented */
561 return (towiresorted(rdataset
, owner_name
, cctx
, target
,
562 order
, order_arg
, ISC_TRUE
, options
,
567 dns_rdataset_towire(dns_rdataset_t
*rdataset
,
568 dns_name_t
*owner_name
,
569 dns_compress_t
*cctx
,
570 isc_buffer_t
*target
,
571 unsigned int options
,
572 unsigned int *countp
)
574 return (towiresorted(rdataset
, owner_name
, cctx
, target
,
575 NULL
, NULL
, ISC_FALSE
, options
, countp
, NULL
));
579 dns_rdataset_additionaldata(dns_rdataset_t
*rdataset
,
580 dns_additionaldatafunc_t add
, void *arg
)
582 dns_rdata_t rdata
= DNS_RDATA_INIT
;
586 * For each rdata in rdataset, call 'add' for each name and type in the
587 * rdata which is subject to additional section processing.
590 REQUIRE(DNS_RDATASET_VALID(rdataset
));
591 REQUIRE((rdataset
->attributes
& DNS_RDATASETATTR_QUESTION
) == 0);
593 result
= dns_rdataset_first(rdataset
);
594 if (result
!= ISC_R_SUCCESS
)
598 dns_rdataset_current(rdataset
, &rdata
);
599 result
= dns_rdata_additionaldata(&rdata
, add
, arg
);
600 if (result
== ISC_R_SUCCESS
)
601 result
= dns_rdataset_next(rdataset
);
602 dns_rdata_reset(&rdata
);
603 } while (result
== ISC_R_SUCCESS
);
605 if (result
!= ISC_R_NOMORE
)
608 return (ISC_R_SUCCESS
);
612 dns_rdataset_addnoqname(dns_rdataset_t
*rdataset
, dns_name_t
*name
) {
614 REQUIRE(DNS_RDATASET_VALID(rdataset
));
615 REQUIRE(rdataset
->methods
!= NULL
);
616 if (rdataset
->methods
->addnoqname
== NULL
)
617 return (ISC_R_NOTIMPLEMENTED
);
618 return((rdataset
->methods
->addnoqname
)(rdataset
, name
));
622 dns_rdataset_getnoqname(dns_rdataset_t
*rdataset
, dns_name_t
*name
,
623 dns_rdataset_t
*nsec
, dns_rdataset_t
*nsecsig
)
625 REQUIRE(DNS_RDATASET_VALID(rdataset
));
626 REQUIRE(rdataset
->methods
!= NULL
);
628 if (rdataset
->methods
->getnoqname
== NULL
)
629 return (ISC_R_NOTIMPLEMENTED
);
630 return((rdataset
->methods
->getnoqname
)(rdataset
, name
, nsec
, nsecsig
));
634 * Additional cache stuff
637 dns_rdataset_getadditional(dns_rdataset_t
*rdataset
,
638 dns_rdatasetadditional_t type
,
639 dns_rdatatype_t qtype
,
640 dns_acache_t
*acache
,
643 dns_dbversion_t
**versionp
,
644 dns_dbnode_t
**nodep
,
649 REQUIRE(DNS_RDATASET_VALID(rdataset
));
650 REQUIRE(rdataset
->methods
!= NULL
);
651 REQUIRE(zonep
== NULL
|| *zonep
== NULL
);
652 REQUIRE(dbp
!= NULL
&& *dbp
== NULL
);
653 REQUIRE(versionp
!= NULL
&& *versionp
== NULL
);
654 REQUIRE(nodep
!= NULL
&& *nodep
== NULL
);
655 REQUIRE(fname
!= NULL
);
656 REQUIRE(msg
!= NULL
);
658 if (acache
!= NULL
&& rdataset
->methods
->getadditional
!= NULL
) {
659 return ((rdataset
->methods
->getadditional
)(rdataset
, type
,
666 return (ISC_R_FAILURE
);
670 dns_rdataset_setadditional(dns_rdataset_t
*rdataset
,
671 dns_rdatasetadditional_t type
,
672 dns_rdatatype_t qtype
,
673 dns_acache_t
*acache
,
676 dns_dbversion_t
*version
,
680 REQUIRE(DNS_RDATASET_VALID(rdataset
));
681 REQUIRE(rdataset
->methods
!= NULL
);
683 if (acache
!= NULL
&& rdataset
->methods
->setadditional
!= NULL
) {
684 return ((rdataset
->methods
->setadditional
)(rdataset
, type
,
690 return (ISC_R_FAILURE
);
694 dns_rdataset_putadditional(dns_acache_t
*acache
,
695 dns_rdataset_t
*rdataset
,
696 dns_rdatasetadditional_t type
,
697 dns_rdatatype_t qtype
)
699 REQUIRE(DNS_RDATASET_VALID(rdataset
));
700 REQUIRE(rdataset
->methods
!= NULL
);
702 if (acache
!= NULL
&& rdataset
->methods
->putadditional
!= NULL
) {
703 return ((rdataset
->methods
->putadditional
)(acache
, rdataset
,
707 return (ISC_R_FAILURE
);