1 /* $NetBSD: rdataset.c,v 1.8 2015/07/08 17:28:59 christos Exp $ */
4 * Copyright (C) 2004-2012, 2014, 2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
28 #include <isc/buffer.h>
30 #include <isc/random.h>
31 #include <isc/serial.h>
35 #include <dns/ncache.h>
36 #include <dns/rdata.h>
37 #include <dns/rdataset.h>
38 #include <dns/compress.h>
40 static const char *trustnames
[] = {
50 "local" /* aka ultimate */
54 dns_trust_totext(dns_trust_t trust
) {
55 if (trust
>= sizeof(trustnames
)/sizeof(*trustnames
))
57 return (trustnames
[trust
]);
61 dns_rdataset_init(dns_rdataset_t
*rdataset
) {
64 * Make 'rdataset' a valid, disassociated rdataset.
67 REQUIRE(rdataset
!= NULL
);
69 rdataset
->magic
= DNS_RDATASET_MAGIC
;
70 rdataset
->methods
= NULL
;
71 ISC_LINK_INIT(rdataset
, link
);
72 rdataset
->rdclass
= 0;
77 rdataset
->attributes
= 0;
78 rdataset
->count
= ISC_UINT32_MAX
;
79 rdataset
->private1
= NULL
;
80 rdataset
->private2
= NULL
;
81 rdataset
->private3
= NULL
;
82 rdataset
->privateuint4
= 0;
83 rdataset
->private5
= NULL
;
84 rdataset
->private6
= NULL
;
85 rdataset
->private7
= NULL
;
90 dns_rdataset_invalidate(dns_rdataset_t
*rdataset
) {
93 * Invalidate 'rdataset'.
96 REQUIRE(DNS_RDATASET_VALID(rdataset
));
97 REQUIRE(rdataset
->methods
== NULL
);
100 ISC_LINK_INIT(rdataset
, link
);
101 rdataset
->rdclass
= 0;
105 rdataset
->covers
= 0;
106 rdataset
->attributes
= 0;
107 rdataset
->count
= ISC_UINT32_MAX
;
108 rdataset
->private1
= NULL
;
109 rdataset
->private2
= NULL
;
110 rdataset
->private3
= NULL
;
111 rdataset
->privateuint4
= 0;
112 rdataset
->private5
= NULL
;
116 dns_rdataset_disassociate(dns_rdataset_t
*rdataset
) {
119 * Disassociate 'rdataset' from its rdata, allowing it to be reused.
122 REQUIRE(DNS_RDATASET_VALID(rdataset
));
123 REQUIRE(rdataset
->methods
!= NULL
);
125 (rdataset
->methods
->disassociate
)(rdataset
);
126 rdataset
->methods
= NULL
;
127 ISC_LINK_INIT(rdataset
, link
);
128 rdataset
->rdclass
= 0;
132 rdataset
->covers
= 0;
133 rdataset
->attributes
= 0;
134 rdataset
->count
= ISC_UINT32_MAX
;
135 rdataset
->private1
= NULL
;
136 rdataset
->private2
= NULL
;
137 rdataset
->private3
= NULL
;
138 rdataset
->privateuint4
= 0;
139 rdataset
->private5
= NULL
;
140 rdataset
->private6
= NULL
;
144 dns_rdataset_isassociated(dns_rdataset_t
*rdataset
) {
146 * Is 'rdataset' associated?
149 REQUIRE(DNS_RDATASET_VALID(rdataset
));
151 if (rdataset
->methods
!= NULL
)
158 question_disassociate(dns_rdataset_t
*rdataset
) {
163 question_cursor(dns_rdataset_t
*rdataset
) {
166 return (ISC_R_NOMORE
);
170 question_current(dns_rdataset_t
*rdataset
, dns_rdata_t
*rdata
) {
172 * This routine should never be called.
181 question_clone(dns_rdataset_t
*source
, dns_rdataset_t
*target
) {
186 question_count(dns_rdataset_t
*rdataset
) {
188 * This routine should never be called.
196 static dns_rdatasetmethods_t question_methods
= {
197 question_disassociate
,
216 dns_rdataset_makequestion(dns_rdataset_t
*rdataset
, dns_rdataclass_t rdclass
,
217 dns_rdatatype_t type
)
221 * Make 'rdataset' a valid, associated, question rdataset, with a
222 * question class of 'rdclass' and type 'type'.
225 REQUIRE(DNS_RDATASET_VALID(rdataset
));
226 REQUIRE(rdataset
->methods
== NULL
);
228 rdataset
->methods
= &question_methods
;
229 rdataset
->rdclass
= rdclass
;
230 rdataset
->type
= type
;
231 rdataset
->attributes
|= DNS_RDATASETATTR_QUESTION
;
235 dns_rdataset_count(dns_rdataset_t
*rdataset
) {
238 * Return the number of records in 'rdataset'.
241 REQUIRE(DNS_RDATASET_VALID(rdataset
));
242 REQUIRE(rdataset
->methods
!= NULL
);
244 return ((rdataset
->methods
->count
)(rdataset
));
248 dns_rdataset_clone(dns_rdataset_t
*source
, dns_rdataset_t
*target
) {
251 * Make 'target' refer to the same rdataset as 'source'.
254 REQUIRE(DNS_RDATASET_VALID(source
));
255 REQUIRE(source
->methods
!= NULL
);
256 REQUIRE(DNS_RDATASET_VALID(target
));
257 REQUIRE(target
->methods
== NULL
);
259 (source
->methods
->clone
)(source
, target
);
263 dns_rdataset_first(dns_rdataset_t
*rdataset
) {
266 * Move the rdata cursor to the first rdata in the rdataset (if any).
269 REQUIRE(DNS_RDATASET_VALID(rdataset
));
270 REQUIRE(rdataset
->methods
!= NULL
);
272 return ((rdataset
->methods
->first
)(rdataset
));
276 dns_rdataset_next(dns_rdataset_t
*rdataset
) {
279 * Move the rdata cursor to the next rdata in the rdataset (if any).
282 REQUIRE(DNS_RDATASET_VALID(rdataset
));
283 REQUIRE(rdataset
->methods
!= NULL
);
285 return ((rdataset
->methods
->next
)(rdataset
));
289 dns_rdataset_current(dns_rdataset_t
*rdataset
, dns_rdata_t
*rdata
) {
292 * Make 'rdata' refer to the current rdata.
295 REQUIRE(DNS_RDATASET_VALID(rdataset
));
296 REQUIRE(rdataset
->methods
!= NULL
);
298 (rdataset
->methods
->current
)(rdataset
, rdata
);
301 #define MAX_SHUFFLE 32
302 #define WANT_FIXED(r) (((r)->attributes & DNS_RDATASETATTR_FIXEDORDER) != 0)
303 #define WANT_RANDOM(r) (((r)->attributes & DNS_RDATASETATTR_RANDOMIZE) != 0)
311 towire_compare(const void *av
, const void *bv
) {
312 const struct towire_sort
*a
= (const struct towire_sort
*) av
;
313 const struct towire_sort
*b
= (const struct towire_sort
*) bv
;
314 return (a
->key
- b
->key
);
318 towiresorted(dns_rdataset_t
*rdataset
, const dns_name_t
*owner_name
,
319 dns_compress_t
*cctx
, isc_buffer_t
*target
,
320 dns_rdatasetorderfunc_t order
, const void *order_arg
,
321 isc_boolean_t partial
, unsigned int options
,
322 unsigned int *countp
, void **state
)
324 dns_rdata_t rdata
= DNS_RDATA_INIT
;
327 unsigned int i
, count
= 0, added
, choice
;
328 isc_buffer_t savedbuffer
, rdlen
, rrbuffer
;
329 unsigned int headlen
;
330 isc_boolean_t question
= ISC_FALSE
;
331 isc_boolean_t shuffle
= ISC_FALSE
;
332 dns_rdata_t
*shuffled
= NULL
, shuffled_fixed
[MAX_SHUFFLE
];
333 struct towire_sort
*sorted
= NULL
, sorted_fixed
[MAX_SHUFFLE
];
338 * Convert 'rdataset' to wire format, compressing names as specified
339 * in cctx, and storing the result in 'target'.
342 REQUIRE(DNS_RDATASET_VALID(rdataset
));
343 REQUIRE(countp
!= NULL
);
344 REQUIRE((order
== NULL
) == (order_arg
== NULL
));
345 REQUIRE(cctx
!= NULL
&& cctx
->mctx
!= NULL
);
347 if ((rdataset
->attributes
& DNS_RDATASETATTR_QUESTION
) != 0) {
350 result
= dns_rdataset_first(rdataset
);
351 INSIST(result
== ISC_R_NOMORE
);
352 } else if ((rdataset
->attributes
& DNS_RDATASETATTR_NEGATIVE
) != 0) {
354 * This is a negative caching rdataset.
356 unsigned int ncache_opts
= 0;
357 if ((options
& DNS_RDATASETTOWIRE_OMITDNSSEC
) != 0)
358 ncache_opts
|= DNS_NCACHETOWIRE_OMITDNSSEC
;
359 return (dns_ncache_towire(rdataset
, cctx
, target
, ncache_opts
,
362 count
= (rdataset
->methods
->count
)(rdataset
);
363 result
= dns_rdataset_first(rdataset
);
364 if (result
== ISC_R_NOMORE
)
365 return (ISC_R_SUCCESS
);
366 if (result
!= ISC_R_SUCCESS
)
371 * Do we want to shuffle this answer?
373 if (!question
&& count
> 1 &&
374 (!WANT_FIXED(rdataset
) || order
!= NULL
) &&
375 rdataset
->type
!= dns_rdatatype_rrsig
)
378 if (shuffle
&& count
> MAX_SHUFFLE
) {
379 shuffled
= isc_mem_get(cctx
->mctx
, count
* sizeof(*shuffled
));
380 sorted
= isc_mem_get(cctx
->mctx
, count
* sizeof(*sorted
));
381 if (shuffled
== NULL
|| sorted
== NULL
)
384 shuffled
= shuffled_fixed
;
385 sorted
= sorted_fixed
;
390 * First we get handles to all of the rdata.
395 dns_rdata_init(&shuffled
[i
]);
396 dns_rdataset_current(rdataset
, &shuffled
[i
]);
398 result
= dns_rdataset_next(rdataset
);
399 } while (result
== ISC_R_SUCCESS
);
400 if (result
!= ISC_R_NOMORE
)
407 if (WANT_FIXED(rdataset
)) {
411 INSIST(order
!= NULL
);
412 for (i
= 0; i
< count
; i
++) {
413 sorted
[i
].key
= (*order
)(&shuffled
[i
],
415 sorted
[i
].rdata
= &shuffled
[i
];
417 } else if (WANT_RANDOM(rdataset
)) {
421 for (i
= 0; i
< count
; i
++) {
424 isc_random_get(&val
);
425 choice
= i
+ (val
% (count
- i
));
427 shuffled
[i
] = shuffled
[choice
];
428 shuffled
[choice
] = rdata
;
430 sorted
[i
].key
= (*order
)(&shuffled
[i
],
433 sorted
[i
].key
= 0; /* Unused */
434 sorted
[i
].rdata
= &shuffled
[i
];
443 val
= rdataset
->count
;
444 if (val
== ISC_UINT32_MAX
)
445 isc_random_get(&val
);
447 for (i
= 0; i
< count
; i
++) {
449 sorted
[i
].key
= (*order
)(&shuffled
[j
],
452 sorted
[i
].key
= 0; /* Unused */
453 sorted
[i
].rdata
= &shuffled
[j
];
456 j
= 0; /* Wrap around. */
464 qsort(sorted
, count
, sizeof(sorted
[0]),
468 savedbuffer
= *target
;
474 * Copy out the name, type, class, ttl.
478 dns_compress_setmethods(cctx
, DNS_COMPRESS_GLOBAL14
);
479 result
= dns_name_towire(owner_name
, cctx
, target
);
480 if (result
!= ISC_R_SUCCESS
)
482 headlen
= sizeof(dns_rdataclass_t
) + sizeof(dns_rdatatype_t
);
484 headlen
+= sizeof(dns_ttl_t
)
485 + 2; /* XXX 2 for rdata len */
486 isc_buffer_availableregion(target
, &r
);
487 if (r
.length
< headlen
) {
488 result
= ISC_R_NOSPACE
;
491 isc_buffer_putuint16(target
, rdataset
->type
);
492 isc_buffer_putuint16(target
, rdataset
->rdclass
);
494 isc_buffer_putuint32(target
, rdataset
->ttl
);
497 * Save space for rdlen.
500 isc_buffer_add(target
, 2);
506 rdata
= *(sorted
[i
].rdata
);
508 dns_rdata_reset(&rdata
);
509 dns_rdataset_current(rdataset
, &rdata
);
511 result
= dns_rdata_towire(&rdata
, cctx
, target
);
512 if (result
!= ISC_R_SUCCESS
)
514 INSIST((target
->used
>= rdlen
.used
+ 2) &&
515 (target
->used
- rdlen
.used
- 2 < 65536));
516 isc_buffer_putuint16(&rdlen
,
517 (isc_uint16_t
)(target
->used
-
525 result
= ISC_R_NOMORE
;
527 result
= ISC_R_SUCCESS
;
529 result
= dns_rdataset_next(rdataset
);
531 } while (result
== ISC_R_SUCCESS
);
533 if (result
!= ISC_R_NOMORE
)
538 result
= ISC_R_SUCCESS
;
542 if (partial
&& result
== ISC_R_NOSPACE
) {
543 INSIST(rrbuffer
.used
< 65536);
544 dns_compress_rollback(cctx
, (isc_uint16_t
)rrbuffer
.used
);
549 INSIST(savedbuffer
.used
< 65536);
550 dns_compress_rollback(cctx
, (isc_uint16_t
)savedbuffer
.used
);
552 *target
= savedbuffer
;
555 if (sorted
!= NULL
&& sorted
!= sorted_fixed
)
556 isc_mem_put(cctx
->mctx
, sorted
, count
* sizeof(*sorted
));
557 if (shuffled
!= NULL
&& shuffled
!= shuffled_fixed
)
558 isc_mem_put(cctx
->mctx
, shuffled
, count
* sizeof(*shuffled
));
563 dns_rdataset_towiresorted(dns_rdataset_t
*rdataset
,
564 const dns_name_t
*owner_name
,
565 dns_compress_t
*cctx
,
566 isc_buffer_t
*target
,
567 dns_rdatasetorderfunc_t order
,
568 const void *order_arg
,
569 unsigned int options
,
570 unsigned int *countp
)
572 return (towiresorted(rdataset
, owner_name
, cctx
, target
,
573 order
, order_arg
, ISC_FALSE
, options
,
578 dns_rdataset_towirepartial(dns_rdataset_t
*rdataset
,
579 const dns_name_t
*owner_name
,
580 dns_compress_t
*cctx
,
581 isc_buffer_t
*target
,
582 dns_rdatasetorderfunc_t order
,
583 const void *order_arg
,
584 unsigned int options
,
585 unsigned int *countp
,
588 REQUIRE(state
== NULL
); /* XXX remove when implemented */
589 return (towiresorted(rdataset
, owner_name
, cctx
, target
,
590 order
, order_arg
, ISC_TRUE
, options
,
595 dns_rdataset_towire(dns_rdataset_t
*rdataset
,
596 dns_name_t
*owner_name
,
597 dns_compress_t
*cctx
,
598 isc_buffer_t
*target
,
599 unsigned int options
,
600 unsigned int *countp
)
602 return (towiresorted(rdataset
, owner_name
, cctx
, target
,
603 NULL
, NULL
, ISC_FALSE
, options
, countp
, NULL
));
607 dns_rdataset_additionaldata(dns_rdataset_t
*rdataset
,
608 dns_additionaldatafunc_t add
, void *arg
)
610 dns_rdata_t rdata
= DNS_RDATA_INIT
;
614 * For each rdata in rdataset, call 'add' for each name and type in the
615 * rdata which is subject to additional section processing.
618 REQUIRE(DNS_RDATASET_VALID(rdataset
));
619 REQUIRE((rdataset
->attributes
& DNS_RDATASETATTR_QUESTION
) == 0);
621 result
= dns_rdataset_first(rdataset
);
622 if (result
!= ISC_R_SUCCESS
)
626 dns_rdataset_current(rdataset
, &rdata
);
627 result
= dns_rdata_additionaldata(&rdata
, add
, arg
);
628 if (result
== ISC_R_SUCCESS
)
629 result
= dns_rdataset_next(rdataset
);
630 dns_rdata_reset(&rdata
);
631 } while (result
== ISC_R_SUCCESS
);
633 if (result
!= ISC_R_NOMORE
)
636 return (ISC_R_SUCCESS
);
640 dns_rdataset_addnoqname(dns_rdataset_t
*rdataset
, dns_name_t
*name
) {
642 REQUIRE(DNS_RDATASET_VALID(rdataset
));
643 REQUIRE(rdataset
->methods
!= NULL
);
644 if (rdataset
->methods
->addnoqname
== NULL
)
645 return (ISC_R_NOTIMPLEMENTED
);
646 return((rdataset
->methods
->addnoqname
)(rdataset
, name
));
650 dns_rdataset_getnoqname(dns_rdataset_t
*rdataset
, dns_name_t
*name
,
651 dns_rdataset_t
*neg
, dns_rdataset_t
*negsig
)
653 REQUIRE(DNS_RDATASET_VALID(rdataset
));
654 REQUIRE(rdataset
->methods
!= NULL
);
656 if (rdataset
->methods
->getnoqname
== NULL
)
657 return (ISC_R_NOTIMPLEMENTED
);
658 return((rdataset
->methods
->getnoqname
)(rdataset
, name
, neg
, negsig
));
662 dns_rdataset_addclosest(dns_rdataset_t
*rdataset
, dns_name_t
*name
) {
664 REQUIRE(DNS_RDATASET_VALID(rdataset
));
665 REQUIRE(rdataset
->methods
!= NULL
);
666 if (rdataset
->methods
->addclosest
== NULL
)
667 return (ISC_R_NOTIMPLEMENTED
);
668 return((rdataset
->methods
->addclosest
)(rdataset
, name
));
672 dns_rdataset_getclosest(dns_rdataset_t
*rdataset
, dns_name_t
*name
,
673 dns_rdataset_t
*neg
, dns_rdataset_t
*negsig
)
675 REQUIRE(DNS_RDATASET_VALID(rdataset
));
676 REQUIRE(rdataset
->methods
!= NULL
);
678 if (rdataset
->methods
->getclosest
== NULL
)
679 return (ISC_R_NOTIMPLEMENTED
);
680 return((rdataset
->methods
->getclosest
)(rdataset
, name
, neg
, negsig
));
684 * Additional cache stuff
687 dns_rdataset_getadditional(dns_rdataset_t
*rdataset
,
688 dns_rdatasetadditional_t type
,
689 dns_rdatatype_t qtype
,
690 dns_acache_t
*acache
,
693 dns_dbversion_t
**versionp
,
694 dns_dbnode_t
**nodep
,
699 REQUIRE(DNS_RDATASET_VALID(rdataset
));
700 REQUIRE(rdataset
->methods
!= NULL
);
701 REQUIRE(zonep
== NULL
|| *zonep
== NULL
);
702 REQUIRE(dbp
!= NULL
&& *dbp
== NULL
);
703 REQUIRE(versionp
!= NULL
&& *versionp
== NULL
);
704 REQUIRE(nodep
!= NULL
&& *nodep
== NULL
);
705 REQUIRE(fname
!= NULL
);
706 REQUIRE(msg
!= NULL
);
708 if (acache
!= NULL
&& rdataset
->methods
->getadditional
!= NULL
) {
709 return ((rdataset
->methods
->getadditional
)(rdataset
, type
,
716 return (ISC_R_FAILURE
);
720 dns_rdataset_setadditional(dns_rdataset_t
*rdataset
,
721 dns_rdatasetadditional_t type
,
722 dns_rdatatype_t qtype
,
723 dns_acache_t
*acache
,
726 dns_dbversion_t
*version
,
730 REQUIRE(DNS_RDATASET_VALID(rdataset
));
731 REQUIRE(rdataset
->methods
!= NULL
);
733 if (acache
!= NULL
&& rdataset
->methods
->setadditional
!= NULL
) {
734 return ((rdataset
->methods
->setadditional
)(rdataset
, type
,
740 return (ISC_R_FAILURE
);
744 dns_rdataset_putadditional(dns_acache_t
*acache
,
745 dns_rdataset_t
*rdataset
,
746 dns_rdatasetadditional_t type
,
747 dns_rdatatype_t qtype
)
749 REQUIRE(DNS_RDATASET_VALID(rdataset
));
750 REQUIRE(rdataset
->methods
!= NULL
);
752 if (acache
!= NULL
&& rdataset
->methods
->putadditional
!= NULL
) {
753 return ((rdataset
->methods
->putadditional
)(acache
, rdataset
,
757 return (ISC_R_FAILURE
);
761 dns_rdataset_settrust(dns_rdataset_t
*rdataset
, dns_trust_t trust
) {
762 REQUIRE(DNS_RDATASET_VALID(rdataset
));
763 REQUIRE(rdataset
->methods
!= NULL
);
765 if (rdataset
->methods
->settrust
!= NULL
)
766 (rdataset
->methods
->settrust
)(rdataset
, trust
);
768 rdataset
->trust
= trust
;
772 dns_rdataset_expire(dns_rdataset_t
*rdataset
) {
773 REQUIRE(DNS_RDATASET_VALID(rdataset
));
774 REQUIRE(rdataset
->methods
!= NULL
);
776 if (rdataset
->methods
->expire
!= NULL
)
777 (rdataset
->methods
->expire
)(rdataset
);
781 dns_rdataset_clearprefetch(dns_rdataset_t
*rdataset
) {
782 REQUIRE(DNS_RDATASET_VALID(rdataset
));
783 REQUIRE(rdataset
->methods
!= NULL
);
785 if (rdataset
->methods
->clearprefetch
!= NULL
)
786 (rdataset
->methods
->clearprefetch
)(rdataset
);
790 dns_rdataset_trimttl(dns_rdataset_t
*rdataset
, dns_rdataset_t
*sigrdataset
,
791 dns_rdata_rrsig_t
*rrsig
, isc_stdtime_t now
,
792 isc_boolean_t acceptexpired
)
794 isc_uint32_t ttl
= 0;
796 REQUIRE(DNS_RDATASET_VALID(rdataset
));
797 REQUIRE(DNS_RDATASET_VALID(sigrdataset
));
798 REQUIRE(rrsig
!= NULL
);
801 * If we accept expired RRsets keep them for no more than 120 seconds.
804 (isc_serial_le(rrsig
->timeexpire
, ((now
+ 120) & 0xffffffff)) ||
805 isc_serial_le(rrsig
->timeexpire
, now
)))
807 else if (isc_serial_ge(rrsig
->timeexpire
, now
))
808 ttl
= rrsig
->timeexpire
- now
;
810 ttl
= ISC_MIN(ISC_MIN(rdataset
->ttl
, sigrdataset
->ttl
),
811 ISC_MIN(rrsig
->originalttl
, ttl
));
813 sigrdataset
->ttl
= ttl
;