2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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: rbtdb.c,v 1.168.2.18 2004/05/23 11:05:21 marka Exp $ */
21 * Principal Author: Bob Halley
26 #include <isc/event.h>
28 #include <isc/print.h>
29 #include <isc/mutex.h>
30 #include <isc/random.h>
31 #include <isc/refcount.h>
32 #include <isc/rwlock.h>
33 #include <isc/string.h>
38 #include <dns/dbiterator.h>
39 #include <dns/events.h>
40 #include <dns/fixedname.h>
42 #include <dns/masterdump.h>
44 #include <dns/rdata.h>
45 #include <dns/rdataset.h>
46 #include <dns/rdatasetiter.h>
47 #include <dns/rdataslab.h>
48 #include <dns/result.h>
49 #include <dns/zonekey.h>
51 #ifdef DNS_RBTDB_VERSION64
57 #ifdef DNS_RBTDB_VERSION64
58 #define RBTDB_MAGIC ISC_MAGIC('R', 'B', 'D', '8')
60 #define RBTDB_MAGIC ISC_MAGIC('R', 'B', 'D', '4')
64 * Note that "impmagic" is not the first four bytes of the struct, so
65 * ISC_MAGIC_VALID cannot be used.
67 #define VALID_RBTDB(rbtdb) ((rbtdb) != NULL && \
68 (rbtdb)->common.impmagic == RBTDB_MAGIC)
70 #ifdef DNS_RBTDB_VERSION64
71 typedef isc_uint64_t rbtdb_serial_t
;
73 typedef isc_uint32_t rbtdb_serial_t
;
76 typedef isc_uint32_t rbtdb_rdatatype_t
;
78 #define RBTDB_RDATATYPE_BASE(type) ((dns_rdatatype_t)((type) & 0xFFFF))
79 #define RBTDB_RDATATYPE_EXT(type) ((dns_rdatatype_t)((type) >> 16))
80 #define RBTDB_RDATATYPE_VALUE(b, e) (((e) << 16) | (b))
82 #define RBTDB_RDATATYPE_SIGNXT \
83 RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig, dns_rdatatype_nxt)
84 #define RBTDB_RDATATYPE_SIGNS \
85 RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig, dns_rdatatype_ns)
86 #define RBTDB_RDATATYPE_SIGCNAME \
87 RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig, dns_rdatatype_cname)
88 #define RBTDB_RDATATYPE_SIGDNAME \
89 RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig, dns_rdatatype_dname)
90 #define RBTDB_RDATATYPE_NCACHEANY \
91 RBTDB_RDATATYPE_VALUE(0, dns_rdatatype_any)
93 typedef struct rdatasetheader
{
95 * Locked by the owning node's lock.
97 rbtdb_serial_t serial
;
99 rbtdb_rdatatype_t type
;
100 isc_uint16_t attributes
;
103 * We don't use the LIST macros, because the LIST structure has
104 * both head and tail pointers, and is doubly linked.
106 struct rdatasetheader
*next
;
107 struct rdatasetheader
*down
;
110 #define RDATASET_ATTR_NONEXISTENT 0x0001
111 #define RDATASET_ATTR_STALE 0x0002
112 #define RDATASET_ATTR_IGNORE 0x0004
113 #define RDATASET_ATTR_RETAIN 0x0008
114 #define RDATASET_ATTR_NXDOMAIN 0x0010
118 * When the cache will pre-expire data (due to memory low or other
119 * situations) before the rdataset's TTL has expired, it MUST
120 * respect the RETAIN bit and not expire the data until its TTL is
124 #undef IGNORE /* WIN32 winbase.h defines this. */
126 #define EXISTS(header) \
127 (((header)->attributes & RDATASET_ATTR_NONEXISTENT) == 0)
128 #define NONEXISTENT(header) \
129 (((header)->attributes & RDATASET_ATTR_NONEXISTENT) != 0)
130 #define IGNORE(header) \
131 (((header)->attributes & RDATASET_ATTR_IGNORE) != 0)
132 #define RETAIN(header) \
133 (((header)->attributes & RDATASET_ATTR_RETAIN) != 0)
134 #define NXDOMAIN(header) \
135 (((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
137 #define DEFAULT_NODE_LOCK_COUNT 7 /* Should be prime. */
141 /* Locked by lock. */
142 unsigned int references
;
143 isc_boolean_t exiting
;
146 typedef struct rbtdb_changed
{
147 dns_rbtnode_t
* node
;
149 ISC_LINK(struct rbtdb_changed
) link
;
152 typedef ISC_LIST(rbtdb_changed_t
) rbtdb_changedlist_t
;
154 typedef struct rbtdb_version
{
156 rbtdb_serial_t serial
;
157 /* Locked by database lock. */
158 isc_boolean_t writer
;
159 unsigned int references
;
160 isc_boolean_t commit_ok
;
161 rbtdb_changedlist_t changed_list
;
162 ISC_LINK(struct rbtdb_version
) link
;
165 typedef ISC_LIST(rbtdb_version_t
) rbtdb_versionlist_t
;
171 isc_rwlock_t tree_lock
;
172 unsigned int node_lock_count
;
173 rbtdb_nodelock_t
* node_locks
;
174 dns_rbtnode_t
* origin_node
;
175 /* Locked by lock. */
177 isc_refcount_t references
;
178 unsigned int attributes
;
179 rbtdb_serial_t current_serial
;
180 rbtdb_serial_t least_serial
;
181 rbtdb_serial_t next_serial
;
182 rbtdb_version_t
* current_version
;
183 rbtdb_version_t
* future_version
;
184 rbtdb_versionlist_t open_versions
;
185 isc_boolean_t overmem
;
187 /* Locked by tree_lock. */
189 isc_boolean_t secure
;
192 #define RBTDB_ATTR_LOADED 0x01
193 #define RBTDB_ATTR_LOADING 0x02
200 rbtdb_version_t
* rbtversion
;
201 rbtdb_serial_t serial
;
202 unsigned int options
;
203 dns_rbtnodechain_t chain
;
204 isc_boolean_t copy_name
;
205 isc_boolean_t need_cleanup
;
207 dns_rbtnode_t
* zonecut
;
208 rdatasetheader_t
* zonecut_rdataset
;
209 rdatasetheader_t
* zonecut_sigrdataset
;
210 dns_fixedname_t zonecut_name
;
222 static void rdataset_disassociate(dns_rdataset_t
*rdataset
);
223 static isc_result_t
rdataset_first(dns_rdataset_t
*rdataset
);
224 static isc_result_t
rdataset_next(dns_rdataset_t
*rdataset
);
225 static void rdataset_current(dns_rdataset_t
*rdataset
, dns_rdata_t
*rdata
);
226 static void rdataset_clone(dns_rdataset_t
*source
, dns_rdataset_t
*target
);
227 static unsigned int rdataset_count(dns_rdataset_t
*rdataset
);
229 static dns_rdatasetmethods_t rdataset_methods
= {
230 rdataset_disassociate
,
238 static void rdatasetiter_destroy(dns_rdatasetiter_t
**iteratorp
);
239 static isc_result_t
rdatasetiter_first(dns_rdatasetiter_t
*iterator
);
240 static isc_result_t
rdatasetiter_next(dns_rdatasetiter_t
*iterator
);
241 static void rdatasetiter_current(dns_rdatasetiter_t
*iterator
,
242 dns_rdataset_t
*rdataset
);
244 static dns_rdatasetitermethods_t rdatasetiter_methods
= {
245 rdatasetiter_destroy
,
251 typedef struct rbtdb_rdatasetiter
{
252 dns_rdatasetiter_t common
;
253 rdatasetheader_t
* current
;
254 } rbtdb_rdatasetiter_t
;
256 static void dbiterator_destroy(dns_dbiterator_t
**iteratorp
);
257 static isc_result_t
dbiterator_first(dns_dbiterator_t
*iterator
);
258 static isc_result_t
dbiterator_last(dns_dbiterator_t
*iterator
);
259 static isc_result_t
dbiterator_seek(dns_dbiterator_t
*iterator
,
261 static isc_result_t
dbiterator_prev(dns_dbiterator_t
*iterator
);
262 static isc_result_t
dbiterator_next(dns_dbiterator_t
*iterator
);
263 static isc_result_t
dbiterator_current(dns_dbiterator_t
*iterator
,
264 dns_dbnode_t
**nodep
,
266 static isc_result_t
dbiterator_pause(dns_dbiterator_t
*iterator
);
267 static isc_result_t
dbiterator_origin(dns_dbiterator_t
*iterator
,
270 static dns_dbiteratormethods_t dbiterator_methods
= {
282 #define DELETION_BATCH_MAX 64
285 * If 'paused' is ISC_TRUE, then the tree lock is not being held.
287 typedef struct rbtdb_dbiterator
{
288 dns_dbiterator_t common
;
289 isc_boolean_t paused
;
290 isc_boolean_t new_origin
;
291 isc_rwlocktype_t tree_locked
;
293 dns_fixedname_t name
;
294 dns_fixedname_t origin
;
295 dns_rbtnodechain_t chain
;
297 dns_rbtnode_t
*deletions
[DELETION_BATCH_MAX
];
299 } rbtdb_dbiterator_t
;
302 #define IS_STUB(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_STUB) != 0)
303 #define IS_CACHE(rbtdb) (((rbtdb)->common.attributes & DNS_DBATTR_CACHE) != 0)
305 static void free_rbtdb(dns_rbtdb_t
*rbtdb
, isc_boolean_t log
,
311 * If a routine is going to lock more than one lock in this module, then
312 * the locking must be done in the following order:
316 * Node Lock (Only one from the set may be locked at one time by
321 * Failure to follow this hierarchy can result in deadlock.
327 * Currently there is no deletion of nodes from the database, except when
328 * the database is being destroyed.
330 * If node deletion is added in the future, then for zone databases the node
331 * for the origin of the zone MUST NOT be deleted.
340 attach(dns_db_t
*source
, dns_db_t
**targetp
) {
341 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)source
;
343 REQUIRE(VALID_RBTDB(rbtdb
));
345 isc_refcount_increment(&rbtdb
->references
, NULL
);
351 free_rbtdb_callback(isc_task_t
*task
, isc_event_t
*event
) {
352 dns_rbtdb_t
*rbtdb
= event
->ev_arg
;
356 free_rbtdb(rbtdb
, ISC_TRUE
, event
);
360 free_rbtdb(dns_rbtdb_t
*rbtdb
, isc_boolean_t log
, isc_event_t
*event
) {
362 isc_ondestroy_t ondest
;
364 char buf
[DNS_NAME_FORMATSIZE
];
366 REQUIRE(EMPTY(rbtdb
->open_versions
));
367 REQUIRE(rbtdb
->future_version
== NULL
);
369 if (rbtdb
->current_version
!= NULL
)
370 isc_mem_put(rbtdb
->common
.mctx
, rbtdb
->current_version
,
371 sizeof (rbtdb_version_t
));
373 if (rbtdb
->tree
!= NULL
) {
374 result
= dns_rbt_destroy2(&rbtdb
->tree
,
375 (rbtdb
->task
!= NULL
) ? 5 : 0);
376 if (result
== ISC_R_QUOTA
) {
377 INSIST(rbtdb
->task
!= NULL
);
379 event
= isc_event_allocate(rbtdb
->common
.mctx
,
381 DNS_EVENT_FREESTORAGE
,
384 sizeof(isc_event_t
));
387 isc_task_send(rbtdb
->task
, &event
);
390 INSIST(result
== ISC_R_SUCCESS
&& rbtdb
->tree
== NULL
);
393 isc_event_free(&event
);
395 if (dns_name_dynamic(&rbtdb
->common
.origin
))
396 dns_name_format(&rbtdb
->common
.origin
, buf
,
399 strcpy(buf
, "<UNKNOWN>");
400 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
401 DNS_LOGMODULE_CACHE
, ISC_LOG_DEBUG(1),
402 "done free_rbtdb(%s)", buf
);
404 if (dns_name_dynamic(&rbtdb
->common
.origin
))
405 dns_name_free(&rbtdb
->common
.origin
, rbtdb
->common
.mctx
);
406 for (i
= 0; i
< rbtdb
->node_lock_count
; i
++)
407 DESTROYLOCK(&rbtdb
->node_locks
[i
].lock
);
408 isc_mem_put(rbtdb
->common
.mctx
, rbtdb
->node_locks
,
409 rbtdb
->node_lock_count
* sizeof (rbtdb_nodelock_t
));
410 isc_rwlock_destroy(&rbtdb
->tree_lock
);
411 isc_refcount_destroy(&rbtdb
->references
);
412 if (rbtdb
->task
!= NULL
)
413 isc_task_detach(&rbtdb
->task
);
414 DESTROYLOCK(&rbtdb
->lock
);
415 rbtdb
->common
.magic
= 0;
416 rbtdb
->common
.impmagic
= 0;
417 ondest
= rbtdb
->common
.ondest
;
418 isc_mem_putanddetach(&rbtdb
->common
.mctx
, rbtdb
, sizeof(*rbtdb
));
419 isc_ondestroy_notify(&ondest
, rbtdb
);
423 maybe_free_rbtdb(dns_rbtdb_t
*rbtdb
) {
424 isc_boolean_t want_free
= ISC_FALSE
;
426 unsigned int inactive
= 0;
428 /* XXX check for open versions here */
431 * Even though there are no external direct references, there still
432 * may be nodes in use.
434 for (i
= 0; i
< rbtdb
->node_lock_count
; i
++) {
435 LOCK(&rbtdb
->node_locks
[i
].lock
);
436 rbtdb
->node_locks
[i
].exiting
= ISC_TRUE
;
437 if (rbtdb
->node_locks
[i
].references
== 0)
439 UNLOCK(&rbtdb
->node_locks
[i
].lock
);
444 rbtdb
->active
-= inactive
;
445 if (rbtdb
->active
== 0)
446 want_free
= ISC_TRUE
;
447 UNLOCK(&rbtdb
->lock
);
449 char buf
[DNS_NAME_FORMATSIZE
];
450 if (dns_name_dynamic(&rbtdb
->common
.origin
))
451 dns_name_format(&rbtdb
->common
.origin
, buf
,
454 strcpy(buf
, "<UNKNOWN>");
455 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
456 DNS_LOGMODULE_CACHE
, ISC_LOG_DEBUG(1),
457 "calling free_rbtdb(%s)", buf
);
458 free_rbtdb(rbtdb
, ISC_TRUE
, NULL
);
464 detach(dns_db_t
**dbp
) {
465 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)(*dbp
);
468 REQUIRE(VALID_RBTDB(rbtdb
));
470 isc_refcount_decrement(&rbtdb
->references
, &refs
);
473 maybe_free_rbtdb(rbtdb
);
479 currentversion(dns_db_t
*db
, dns_dbversion_t
**versionp
) {
480 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
481 rbtdb_version_t
*version
;
483 REQUIRE(VALID_RBTDB(rbtdb
));
486 version
= rbtdb
->current_version
;
487 if (version
->references
== 0)
488 PREPEND(rbtdb
->open_versions
, version
, link
);
489 version
->references
++;
490 UNLOCK(&rbtdb
->lock
);
492 *versionp
= (dns_dbversion_t
*)version
;
495 static inline rbtdb_version_t
*
496 allocate_version(isc_mem_t
*mctx
, rbtdb_serial_t serial
,
497 unsigned int references
, isc_boolean_t writer
)
499 rbtdb_version_t
*version
;
501 version
= isc_mem_get(mctx
, sizeof *version
);
504 version
->serial
= serial
;
505 version
->references
= references
;
506 version
->writer
= writer
;
507 version
->commit_ok
= ISC_FALSE
;
508 ISC_LIST_INIT(version
->changed_list
);
509 ISC_LINK_INIT(version
, link
);
515 newversion(dns_db_t
*db
, dns_dbversion_t
**versionp
) {
516 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
517 rbtdb_version_t
*version
;
519 REQUIRE(VALID_RBTDB(rbtdb
));
520 REQUIRE(versionp
!= NULL
&& *versionp
== NULL
);
521 REQUIRE(rbtdb
->future_version
== NULL
);
524 RUNTIME_CHECK(rbtdb
->next_serial
!= 0); /* XXX Error? */
525 version
= allocate_version(rbtdb
->common
.mctx
, rbtdb
->next_serial
, 1,
527 if (version
!= NULL
) {
528 version
->commit_ok
= ISC_TRUE
;
529 rbtdb
->next_serial
++;
530 rbtdb
->future_version
= version
;
532 UNLOCK(&rbtdb
->lock
);
535 return (ISC_R_NOMEMORY
);
539 return (ISC_R_SUCCESS
);
543 attachversion(dns_db_t
*db
, dns_dbversion_t
*source
,
544 dns_dbversion_t
**targetp
)
546 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
547 rbtdb_version_t
*rbtversion
= source
;
549 REQUIRE(VALID_RBTDB(rbtdb
));
553 INSIST(rbtversion
->references
> 0);
554 rbtversion
->references
++;
555 INSIST(rbtversion
->references
!= 0);
557 UNLOCK(&rbtdb
->lock
);
559 *targetp
= rbtversion
;
562 static rbtdb_changed_t
*
563 add_changed(dns_rbtdb_t
*rbtdb
, rbtdb_version_t
*version
,
566 rbtdb_changed_t
*changed
;
569 * Caller must be holding the node lock.
572 changed
= isc_mem_get(rbtdb
->common
.mctx
, sizeof *changed
);
576 REQUIRE(version
->writer
);
578 if (changed
!= NULL
) {
579 INSIST(node
->references
> 0);
581 INSIST(node
->references
!= 0);
582 changed
->node
= node
;
583 changed
->dirty
= ISC_FALSE
;
584 ISC_LIST_INITANDAPPEND(version
->changed_list
, changed
, link
);
586 version
->commit_ok
= ISC_FALSE
;
588 UNLOCK(&rbtdb
->lock
);
594 free_rdataset(isc_mem_t
*mctx
, rdatasetheader_t
*rdataset
) {
597 if ((rdataset
->attributes
& RDATASET_ATTR_NONEXISTENT
) != 0)
598 size
= sizeof *rdataset
;
600 size
= dns_rdataslab_size((unsigned char *)rdataset
,
602 isc_mem_put(mctx
, rdataset
, size
);
606 rollback_node(dns_rbtnode_t
*node
, rbtdb_serial_t serial
) {
607 rdatasetheader_t
*header
, *dcurrent
;
608 isc_boolean_t make_dirty
= ISC_FALSE
;
611 * Caller must hold the node lock.
615 * We set the IGNORE attribute on rdatasets with serial number
616 * 'serial'. When the reference count goes to zero, these rdatasets
617 * will be cleaned up; until that time, they will be ignored.
619 for (header
= node
->data
; header
!= NULL
; header
= header
->next
) {
620 if (header
->serial
== serial
) {
621 header
->attributes
|= RDATASET_ATTR_IGNORE
;
622 make_dirty
= ISC_TRUE
;
624 for (dcurrent
= header
->down
;
626 dcurrent
= dcurrent
->down
) {
627 if (dcurrent
->serial
== serial
) {
628 dcurrent
->attributes
|= RDATASET_ATTR_IGNORE
;
629 make_dirty
= ISC_TRUE
;
638 clean_cache_node(dns_rbtdb_t
*rbtdb
, dns_rbtnode_t
*node
) {
639 rdatasetheader_t
*current
, *dcurrent
, *top_prev
, *top_next
, *down_next
;
640 isc_mem_t
*mctx
= rbtdb
->common
.mctx
;
643 * Caller must be holding the node lock.
647 for (current
= node
->data
; current
!= NULL
; current
= top_next
) {
648 top_next
= current
->next
;
649 dcurrent
= current
->down
;
650 if (dcurrent
!= NULL
) {
652 down_next
= dcurrent
->down
;
653 free_rdataset(mctx
, dcurrent
);
654 dcurrent
= down_next
;
655 } while (dcurrent
!= NULL
);
656 current
->down
= NULL
;
659 * If current is nonexistent or stale, we can clean it up.
661 if ((current
->attributes
&
662 (RDATASET_ATTR_NONEXISTENT
|RDATASET_ATTR_STALE
)) != 0) {
663 if (top_prev
!= NULL
)
664 top_prev
->next
= current
->next
;
666 node
->data
= current
->next
;
667 free_rdataset(mctx
, current
);
675 clean_zone_node(dns_rbtdb_t
*rbtdb
, dns_rbtnode_t
*node
,
676 rbtdb_serial_t least_serial
)
678 rdatasetheader_t
*current
, *dcurrent
, *down_next
, *dparent
;
679 rdatasetheader_t
*top_prev
, *top_next
;
680 isc_mem_t
*mctx
= rbtdb
->common
.mctx
;
681 isc_boolean_t still_dirty
= ISC_FALSE
;
684 * Caller must be holding the node lock.
686 REQUIRE(least_serial
!= 0);
689 for (current
= node
->data
; current
!= NULL
; current
= top_next
) {
690 top_next
= current
->next
;
693 * First, we clean up any instances of multiple rdatasets
694 * with the same serial number, or that have the IGNORE
698 for (dcurrent
= current
->down
;
700 dcurrent
= down_next
) {
701 down_next
= dcurrent
->down
;
702 INSIST(dcurrent
->serial
<= dparent
->serial
);
703 if (dcurrent
->serial
== dparent
->serial
||
705 if (down_next
!= NULL
)
706 down_next
->next
= dparent
;
707 dparent
->down
= down_next
;
708 free_rdataset(mctx
, dcurrent
);
714 * We've now eliminated all IGNORE datasets with the possible
715 * exception of current, which we now check.
717 if (IGNORE(current
)) {
718 down_next
= current
->down
;
719 if (down_next
== NULL
) {
720 if (top_prev
!= NULL
)
721 top_prev
->next
= current
->next
;
723 node
->data
= current
->next
;
724 free_rdataset(mctx
, current
);
726 * current no longer exists, so we can
727 * just continue with the loop.
732 * Pull up current->down, making it the new
735 if (top_prev
!= NULL
)
736 top_prev
->next
= down_next
;
738 node
->data
= down_next
;
739 down_next
->next
= top_next
;
740 free_rdataset(mctx
, current
);
746 * We now try to find the first down node less than the
750 for (dcurrent
= current
->down
;
752 dcurrent
= down_next
) {
753 down_next
= dcurrent
->down
;
754 if (dcurrent
->serial
< least_serial
)
760 * If there is a such an rdataset, delete it and any older
763 if (dcurrent
!= NULL
) {
765 down_next
= dcurrent
->down
;
766 INSIST(dcurrent
->serial
<= least_serial
);
767 free_rdataset(mctx
, dcurrent
);
768 dcurrent
= down_next
;
769 } while (dcurrent
!= NULL
);
770 dparent
->down
= NULL
;
774 * Note. The serial number of 'current' might be less than
775 * least_serial too, but we cannot delete it because it is
776 * the most recent version, unless it is a NONEXISTENT
779 if (current
->down
!= NULL
) {
780 still_dirty
= ISC_TRUE
;
784 * If this is a NONEXISTENT rdataset, we can delete it.
786 if ((current
->attributes
& RDATASET_ATTR_NONEXISTENT
)
788 if (top_prev
!= NULL
)
789 top_prev
->next
= current
->next
;
791 node
->data
= current
->next
;
792 free_rdataset(mctx
, current
);
802 new_reference(dns_rbtdb_t
*rbtdb
, dns_rbtnode_t
*node
) {
803 if (node
->references
== 0) {
804 rbtdb
->node_locks
[node
->locknum
].references
++;
805 INSIST(rbtdb
->node_locks
[node
->locknum
].references
!= 0);
808 INSIST(node
->references
!= 0);
812 no_references(dns_rbtdb_t
*rbtdb
, dns_rbtnode_t
*node
,
813 rbtdb_serial_t least_serial
, isc_rwlocktype_t lock
)
816 isc_boolean_t write_locked
;
817 unsigned int locknum
;
820 * Caller must be holding the node lock.
823 REQUIRE(node
->references
== 0);
827 clean_cache_node(rbtdb
, node
);
829 if (least_serial
== 0) {
831 * Caller doesn't know the least serial.
835 least_serial
= rbtdb
->least_serial
;
836 UNLOCK(&rbtdb
->lock
);
838 clean_zone_node(rbtdb
, node
, least_serial
);
842 locknum
= node
->locknum
;
844 INSIST(rbtdb
->node_locks
[locknum
].references
> 0);
845 rbtdb
->node_locks
[locknum
].references
--;
848 * XXXDCL should this only be done for cache zones?
850 if (node
->data
!= NULL
|| node
->down
!= NULL
)
854 * XXXDCL need to add a deferred delete method for ISC_R_LOCKBUSY.
856 if (lock
!= isc_rwlocktype_write
) {
858 * Locking hierarchy notwithstanding, we don't need to free
859 * the node lock before acquiring the tree write lock because
860 * we only do a trylock.
862 if (lock
== isc_rwlocktype_read
)
863 result
= isc_rwlock_tryupgrade(&rbtdb
->tree_lock
);
865 result
= isc_rwlock_trylock(&rbtdb
->tree_lock
,
866 isc_rwlocktype_write
);
867 RUNTIME_CHECK(result
== ISC_R_SUCCESS
||
868 result
== ISC_R_LOCKBUSY
);
870 write_locked
= ISC_TF(result
== ISC_R_SUCCESS
);
872 write_locked
= ISC_TRUE
;
875 if (isc_log_wouldlog(dns_lctx
, ISC_LOG_DEBUG(1))) {
876 char printname
[DNS_NAME_FORMATSIZE
];
878 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
879 DNS_LOGMODULE_CACHE
, ISC_LOG_DEBUG(1),
880 "no_references: delete from rbt: %p %s",
882 dns_rbt_formatnodename(node
, printname
,
886 result
= dns_rbt_deletenode(rbtdb
->tree
, node
, ISC_FALSE
);
887 if (result
!= ISC_R_SUCCESS
)
888 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
889 DNS_LOGMODULE_CACHE
, ISC_LOG_WARNING
,
890 "no_references: dns_rbt_deletenode: %s",
891 isc_result_totext(result
));
895 * Relock a read lock, or unlock the write lock if no lock was held.
897 if (lock
== isc_rwlocktype_none
)
899 RWUNLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_write
);
901 if (lock
== isc_rwlocktype_read
)
903 isc_rwlock_downgrade(&rbtdb
->tree_lock
);
907 make_least_version(dns_rbtdb_t
*rbtdb
, rbtdb_version_t
*version
,
908 rbtdb_changedlist_t
*cleanup_list
)
911 * Caller must be holding the database lock.
914 rbtdb
->least_serial
= version
->serial
;
915 *cleanup_list
= version
->changed_list
;
916 ISC_LIST_INIT(version
->changed_list
);
920 cleanup_nondirty(rbtdb_version_t
*version
, rbtdb_changedlist_t
*cleanup_list
) {
921 rbtdb_changed_t
*changed
, *next_changed
;
924 * If the changed record is dirty, then
925 * an update created multiple versions of
926 * a given rdataset. We keep this list
927 * until we're the least open version, at
928 * which point it's safe to get rid of any
931 * If the changed record isn't dirty, then
932 * we don't need it anymore since we're
933 * committing and not rolling back.
935 * The caller must be holding the database lock.
937 for (changed
= HEAD(version
->changed_list
);
939 changed
= next_changed
) {
940 next_changed
= NEXT(changed
, link
);
941 if (!changed
->dirty
) {
942 UNLINK(version
->changed_list
,
944 APPEND(*cleanup_list
,
951 closeversion(dns_db_t
*db
, dns_dbversion_t
**versionp
, isc_boolean_t commit
) {
952 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
953 rbtdb_version_t
*version
, *cleanup_version
, *least_greater
;
954 isc_boolean_t rollback
= ISC_FALSE
;
955 rbtdb_changedlist_t cleanup_list
;
956 rbtdb_changed_t
*changed
, *next_changed
;
957 rbtdb_serial_t serial
, least_serial
;
958 dns_rbtnode_t
*rbtnode
;
961 REQUIRE(VALID_RBTDB(rbtdb
));
962 version
= (rbtdb_version_t
*)*versionp
;
964 cleanup_version
= NULL
;
965 ISC_LIST_INIT(cleanup_list
);
968 INSIST(version
->references
> 0);
969 INSIST(!version
->writer
|| !(commit
&& version
->references
> 1));
970 version
->references
--;
971 serial
= version
->serial
;
972 if (version
->references
== 0) {
973 if (version
->writer
) {
975 INSIST(version
->commit_ok
);
976 INSIST(version
== rbtdb
->future_version
);
977 if (EMPTY(rbtdb
->open_versions
)) {
979 * We're going to become the least open
982 make_least_version(rbtdb
, version
,
986 * Some other open version is the
987 * least version. We can't cleanup
988 * records that were changed in this
989 * version because the older versions
990 * may still be in use by an open
993 * We can, however, discard the
994 * changed records for things that
995 * we've added that didn't exist in
998 cleanup_nondirty(version
,
1002 * If the (soon to be former) current version
1003 * isn't being used by anyone, we can clean
1006 if (rbtdb
->current_version
->references
== 0) {
1008 rbtdb
->current_version
;
1009 APPENDLIST(version
->changed_list
,
1010 cleanup_version
->changed_list
,
1014 * Become the current version.
1016 version
->writer
= ISC_FALSE
;
1017 rbtdb
->current_version
= version
;
1018 rbtdb
->current_serial
= version
->serial
;
1019 rbtdb
->future_version
= NULL
;
1022 * We're rolling back this transaction.
1024 cleanup_list
= version
->changed_list
;
1025 ISC_LIST_INIT(version
->changed_list
);
1026 rollback
= ISC_TRUE
;
1027 cleanup_version
= version
;
1028 rbtdb
->future_version
= NULL
;
1031 if (version
!= rbtdb
->current_version
) {
1033 * There are no external or internal references
1034 * to this version and it can be cleaned up.
1036 cleanup_version
= version
;
1039 * Find the version with the least serial
1040 * number greater than ours.
1042 least_greater
= PREV(version
, link
);
1043 if (least_greater
== NULL
)
1044 least_greater
= rbtdb
->current_version
;
1046 INSIST(version
->serial
< least_greater
->serial
);
1048 * Is this the least open version?
1050 if (version
->serial
== rbtdb
->least_serial
) {
1052 * Yes. Install the new least open
1055 make_least_version(rbtdb
,
1060 * Add any unexecuted cleanups to
1061 * those of the least greater version.
1063 APPENDLIST(least_greater
->changed_list
,
1064 version
->changed_list
,
1067 } else if (version
->serial
== rbtdb
->least_serial
)
1068 INSIST(EMPTY(version
->changed_list
));
1069 UNLINK(rbtdb
->open_versions
, version
, link
);
1072 least_serial
= rbtdb
->least_serial
;
1073 UNLOCK(&rbtdb
->lock
);
1075 if (cleanup_version
!= NULL
) {
1076 INSIST(EMPTY(cleanup_version
->changed_list
));
1077 isc_mem_put(rbtdb
->common
.mctx
, cleanup_version
,
1078 sizeof *cleanup_version
);
1081 if (!EMPTY(cleanup_list
)) {
1082 for (changed
= HEAD(cleanup_list
);
1084 changed
= next_changed
) {
1085 next_changed
= NEXT(changed
, link
);
1086 rbtnode
= changed
->node
;
1087 lock
= &rbtdb
->node_locks
[rbtnode
->locknum
].lock
;
1091 INSIST(rbtnode
->references
> 0);
1092 rbtnode
->references
--;
1094 rollback_node(rbtnode
, serial
);
1096 if (rbtnode
->references
== 0)
1097 no_references(rbtdb
, rbtnode
, least_serial
,
1098 isc_rwlocktype_none
);
1102 isc_mem_put(rbtdb
->common
.mctx
, changed
,
1111 * Add the necessary magic for the wildcard name 'name'
1112 * to be found in 'rbtdb'.
1114 * In order for wildcard matching to work correctly in
1115 * zone_find(), we must ensure that a node for the wildcarding
1116 * level exists in the database, and has its 'find_callback'
1117 * and 'wild' bits set.
1119 * E.g. if the wildcard name is "*.sub.example." then we
1120 * must ensure that "sub.example." exists and is marked as
1124 add_wildcard_magic(dns_rbtdb_t
*rbtdb
, dns_name_t
*name
) {
1125 isc_result_t result
;
1126 dns_name_t foundname
;
1127 dns_offsets_t offsets
;
1129 dns_rbtnode_t
*node
= NULL
;
1131 dns_name_init(&foundname
, offsets
);
1132 n
= dns_name_countlabels(name
);
1135 dns_name_getlabelsequence(name
, 1, n
, &foundname
);
1136 result
= dns_rbt_addnode(rbtdb
->tree
, &foundname
, &node
);
1137 if (result
!= ISC_R_SUCCESS
&& result
!= ISC_R_EXISTS
)
1139 node
->find_callback
= 1;
1141 return (ISC_R_SUCCESS
);
1145 add_empty_wildcards(dns_rbtdb_t
*rbtdb
, dns_name_t
*name
) {
1146 isc_result_t result
;
1147 dns_name_t foundname
;
1148 dns_offsets_t offsets
;
1149 unsigned int n
, l
, i
;
1151 dns_name_init(&foundname
, offsets
);
1152 n
= dns_name_countlabels(name
);
1153 l
= dns_name_countlabels(&rbtdb
->common
.origin
);
1156 dns_rbtnode_t
*node
= NULL
; /* dummy */
1157 dns_name_getlabelsequence(name
, n
- i
, i
, &foundname
);
1158 if (dns_name_iswildcard(&foundname
)) {
1159 result
= add_wildcard_magic(rbtdb
, &foundname
);
1160 if (result
!= ISC_R_SUCCESS
)
1162 result
= dns_rbt_addnode(rbtdb
->tree
, &foundname
,
1164 if (result
!= ISC_R_SUCCESS
&& result
!= ISC_R_EXISTS
)
1169 return (ISC_R_SUCCESS
);
1173 findnode(dns_db_t
*db
, dns_name_t
*name
, isc_boolean_t create
,
1174 dns_dbnode_t
**nodep
)
1176 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
1177 dns_rbtnode_t
*node
= NULL
;
1178 dns_name_t nodename
;
1179 unsigned int locknum
;
1180 isc_result_t result
;
1181 isc_rwlocktype_t locktype
= isc_rwlocktype_read
;
1183 REQUIRE(VALID_RBTDB(rbtdb
));
1185 dns_name_init(&nodename
, NULL
);
1186 RWLOCK(&rbtdb
->tree_lock
, locktype
);
1187 result
= dns_rbt_findnode(rbtdb
->tree
, name
, NULL
, &node
, NULL
,
1188 DNS_RBTFIND_EMPTYDATA
, NULL
, NULL
);
1189 if (result
!= ISC_R_SUCCESS
) {
1190 RWUNLOCK(&rbtdb
->tree_lock
, locktype
);
1192 if (result
== DNS_R_PARTIALMATCH
)
1193 result
= ISC_R_NOTFOUND
;
1197 * It would be nice to try to upgrade the lock instead of
1198 * unlocking then relocking.
1200 locktype
= isc_rwlocktype_write
;
1201 RWLOCK(&rbtdb
->tree_lock
, locktype
);
1203 result
= dns_rbt_addnode(rbtdb
->tree
, name
, &node
);
1204 if (result
== ISC_R_SUCCESS
) {
1205 dns_rbt_namefromnode(node
, &nodename
);
1206 #ifdef DNS_RBT_USEHASH
1207 node
->locknum
= node
->hashval
% rbtdb
->node_lock_count
;
1209 node
->locknum
= dns_name_hash(&nodename
, ISC_TRUE
) %
1210 rbtdb
->node_lock_count
;
1212 add_empty_wildcards(rbtdb
, name
);
1214 if (dns_name_iswildcard(name
)) {
1215 result
= add_wildcard_magic(rbtdb
, name
);
1216 if (result
!= ISC_R_SUCCESS
) {
1217 RWUNLOCK(&rbtdb
->tree_lock
, locktype
);
1221 } else if (result
!= ISC_R_EXISTS
) {
1222 RWUNLOCK(&rbtdb
->tree_lock
, locktype
);
1226 locknum
= node
->locknum
;
1227 LOCK(&rbtdb
->node_locks
[locknum
].lock
);
1228 new_reference(rbtdb
, node
);
1229 UNLOCK(&rbtdb
->node_locks
[locknum
].lock
);
1230 RWUNLOCK(&rbtdb
->tree_lock
, locktype
);
1232 *nodep
= (dns_dbnode_t
*)node
;
1234 return (ISC_R_SUCCESS
);
1238 zone_zonecut_callback(dns_rbtnode_t
*node
, dns_name_t
*name
, void *arg
) {
1239 rbtdb_search_t
*search
= arg
;
1240 rdatasetheader_t
*header
, *header_next
;
1241 rdatasetheader_t
*dname_header
, *sigdname_header
, *ns_header
;
1242 rdatasetheader_t
*found
;
1243 isc_result_t result
;
1244 dns_rbtnode_t
*onode
;
1247 * We only want to remember the topmost zone cut, since it's the one
1248 * that counts, so we'll just continue if we've already found a
1251 if (search
->zonecut
!= NULL
)
1252 return (DNS_R_CONTINUE
);
1255 result
= DNS_R_CONTINUE
;
1256 onode
= search
->rbtdb
->origin_node
;
1258 LOCK(&(search
->rbtdb
->node_locks
[node
->locknum
].lock
));
1261 * Look for an NS or DNAME rdataset active in our version.
1264 dname_header
= NULL
;
1265 sigdname_header
= NULL
;
1266 for (header
= node
->data
; header
!= NULL
; header
= header_next
) {
1267 header_next
= header
->next
;
1268 if (header
->type
== dns_rdatatype_ns
||
1269 header
->type
== dns_rdatatype_dname
||
1270 header
->type
== RBTDB_RDATATYPE_SIGDNAME
) {
1272 if (header
->serial
<= search
->serial
&&
1275 * Is this a "this rdataset doesn't
1278 if (NONEXISTENT(header
))
1282 header
= header
->down
;
1283 } while (header
!= NULL
);
1284 if (header
!= NULL
) {
1285 if (header
->type
== dns_rdatatype_dname
)
1286 dname_header
= header
;
1287 else if (header
->type
==
1288 RBTDB_RDATATYPE_SIGDNAME
)
1289 sigdname_header
= header
;
1290 else if (node
!= onode
||
1291 IS_STUB(search
->rbtdb
)) {
1293 * We've found an NS rdataset that
1294 * isn't at the origin node. We check
1295 * that they're not at the origin node,
1296 * because otherwise we'd erroneously
1297 * treat the zone top as if it were
1307 * Did we find anything?
1309 if (dname_header
!= NULL
) {
1311 * Note that DNAME has precedence over NS if both exist.
1313 found
= dname_header
;
1314 search
->zonecut_sigrdataset
= sigdname_header
;
1315 } else if (ns_header
!= NULL
) {
1317 search
->zonecut_sigrdataset
= NULL
;
1320 if (found
!= NULL
) {
1322 * We increment the reference count on node to ensure that
1323 * search->zonecut_rdataset will still be valid later.
1325 new_reference(search
->rbtdb
, node
);
1326 search
->zonecut
= node
;
1327 search
->zonecut_rdataset
= found
;
1328 search
->need_cleanup
= ISC_TRUE
;
1330 * Since we've found a zonecut, anything beneath it is
1331 * glue and is not subject to wildcard matching, so we
1332 * may clear search->wild.
1334 search
->wild
= ISC_FALSE
;
1335 if ((search
->options
& DNS_DBFIND_GLUEOK
) == 0) {
1337 * If the caller does not want to find glue, then
1338 * this is the best answer and the search should
1341 result
= DNS_R_PARTIALMATCH
;
1346 * The search will continue beneath the zone cut.
1347 * This may or may not be the best match. In case it
1348 * is, we need to remember the node name.
1350 zcname
= dns_fixedname_name(&search
->zonecut_name
);
1351 RUNTIME_CHECK(dns_name_copy(name
, zcname
, NULL
) ==
1353 search
->copy_name
= ISC_TRUE
;
1357 * There is no zonecut at this node which is active in this
1360 * If this is a "wild" node and the caller hasn't disabled
1361 * wildcard matching, remember that we've seen a wild node
1362 * in case we need to go searching for wildcard matches
1365 if (node
->wild
&& (search
->options
& DNS_DBFIND_NOWILD
) == 0)
1366 search
->wild
= ISC_TRUE
;
1369 UNLOCK(&(search
->rbtdb
->node_locks
[node
->locknum
].lock
));
1375 bind_rdataset(dns_rbtdb_t
*rbtdb
, dns_rbtnode_t
*node
,
1376 rdatasetheader_t
*header
, isc_stdtime_t now
,
1377 dns_rdataset_t
*rdataset
)
1382 * Caller must be holding the node lock.
1385 if (rdataset
== NULL
)
1388 new_reference(rbtdb
, node
);
1390 INSIST(rdataset
->methods
== NULL
); /* We must be disassociated. */
1392 rdataset
->methods
= &rdataset_methods
;
1393 rdataset
->rdclass
= rbtdb
->common
.rdclass
;
1394 rdataset
->type
= RBTDB_RDATATYPE_BASE(header
->type
);
1395 rdataset
->covers
= RBTDB_RDATATYPE_EXT(header
->type
);
1396 rdataset
->ttl
= header
->ttl
- now
;
1397 rdataset
->trust
= header
->trust
;
1398 if (NXDOMAIN(header
))
1399 rdataset
->attributes
|= DNS_RDATASETATTR_NXDOMAIN
;
1400 rdataset
->private1
= rbtdb
;
1401 rdataset
->private2
= node
;
1402 raw
= (unsigned char *)header
+ sizeof(*header
);
1403 rdataset
->private3
= raw
;
1406 * Reset iterator state.
1408 rdataset
->privateuint4
= 0;
1409 rdataset
->private5
= NULL
;
1412 static inline isc_result_t
1413 setup_delegation(rbtdb_search_t
*search
, dns_dbnode_t
**nodep
,
1414 dns_name_t
*foundname
, dns_rdataset_t
*rdataset
,
1415 dns_rdataset_t
*sigrdataset
)
1417 isc_result_t result
;
1419 rbtdb_rdatatype_t type
;
1420 dns_rbtnode_t
*node
;
1423 * The caller MUST NOT be holding any node locks.
1426 node
= search
->zonecut
;
1427 type
= search
->zonecut_rdataset
->type
;
1430 * If we have to set foundname, we do it before anything else.
1431 * If we were to set foundname after we had set nodep or bound the
1432 * rdataset, then we'd have to undo that work if dns_name_concatenate()
1433 * failed. By setting foundname first, there's nothing to undo if
1436 if (foundname
!= NULL
&& search
->copy_name
) {
1437 zcname
= dns_fixedname_name(&search
->zonecut_name
);
1438 result
= dns_name_copy(zcname
, foundname
, NULL
);
1439 if (result
!= ISC_R_SUCCESS
)
1442 if (nodep
!= NULL
) {
1444 * Note that we don't have to increment the node's reference
1445 * count here because we're going to use the reference we
1446 * already have in the search block.
1449 search
->need_cleanup
= ISC_FALSE
;
1451 if (rdataset
!= NULL
) {
1452 LOCK(&(search
->rbtdb
->node_locks
[node
->locknum
].lock
));
1453 bind_rdataset(search
->rbtdb
, node
, search
->zonecut_rdataset
,
1454 search
->now
, rdataset
);
1455 if (sigrdataset
!= NULL
&& search
->zonecut_sigrdataset
!= NULL
)
1456 bind_rdataset(search
->rbtdb
, node
,
1457 search
->zonecut_sigrdataset
,
1458 search
->now
, sigrdataset
);
1459 UNLOCK(&(search
->rbtdb
->node_locks
[node
->locknum
].lock
));
1462 if (type
== dns_rdatatype_dname
)
1463 return (DNS_R_DNAME
);
1464 return (DNS_R_DELEGATION
);
1467 static inline isc_boolean_t
1468 valid_glue(rbtdb_search_t
*search
, dns_name_t
*name
, rbtdb_rdatatype_t type
,
1469 dns_rbtnode_t
*node
)
1472 unsigned int count
, size
;
1474 isc_boolean_t valid
= ISC_FALSE
;
1475 dns_offsets_t offsets
;
1476 isc_region_t region
;
1477 rdatasetheader_t
*header
;
1480 * No additional locking is required.
1484 * Valid glue types are A, AAAA, A6. NS is also a valid glue type
1485 * if it occurs at a zone cut, but is not valid below it.
1487 if (type
== dns_rdatatype_ns
) {
1488 if (node
!= search
->zonecut
) {
1491 } else if (type
!= dns_rdatatype_a
&&
1492 type
!= dns_rdatatype_aaaa
&&
1493 type
!= dns_rdatatype_a6
) {
1497 header
= search
->zonecut_rdataset
;
1498 raw
= (unsigned char *)header
+ sizeof *header
;
1499 count
= raw
[0] * 256 + raw
[1];
1504 size
= raw
[0] * 256 + raw
[1];
1507 region
.length
= size
;
1510 * XXX Until we have rdata structures, we have no choice but
1511 * to directly access the rdata format.
1513 dns_name_init(&ns_name
, offsets
);
1514 dns_name_fromregion(&ns_name
, ®ion
);
1515 if (dns_name_compare(&ns_name
, name
) == 0) {
1524 static inline isc_boolean_t
1525 activeempty(rbtdb_search_t
*search
, dns_rbtnodechain_t
*chain
,
1528 dns_fixedname_t fnext
;
1529 dns_fixedname_t forigin
;
1534 dns_rbtnode_t
*node
;
1535 isc_result_t result
;
1536 isc_boolean_t answer
= ISC_FALSE
;
1537 rdatasetheader_t
*header
;
1539 rbtdb
= search
->rbtdb
;
1541 dns_name_init(&prefix
, NULL
);
1542 dns_fixedname_init(&fnext
);
1543 next
= dns_fixedname_name(&fnext
);
1544 dns_fixedname_init(&forigin
);
1545 origin
= dns_fixedname_name(&forigin
);
1547 result
= dns_rbtnodechain_next(chain
, NULL
, NULL
);
1548 while (result
== ISC_R_SUCCESS
|| result
== DNS_R_NEWORIGIN
) {
1550 result
= dns_rbtnodechain_current(chain
, &prefix
,
1552 if (result
!= ISC_R_SUCCESS
)
1554 LOCK(&(rbtdb
->node_locks
[node
->locknum
].lock
));
1555 for (header
= node
->data
;
1557 header
= header
->next
) {
1558 if (header
->serial
<= search
->serial
&&
1559 !IGNORE(header
) && EXISTS(header
))
1562 UNLOCK(&(rbtdb
->node_locks
[node
->locknum
].lock
));
1565 result
= dns_rbtnodechain_next(chain
, NULL
, NULL
);
1567 if (result
== ISC_R_SUCCESS
)
1568 result
= dns_name_concatenate(&prefix
, origin
, next
, NULL
);
1569 if (result
== ISC_R_SUCCESS
&& dns_name_issubdomain(next
, name
))
1574 static inline isc_boolean_t
1575 activeemtpynode(rbtdb_search_t
*search
, dns_name_t
*qname
, dns_name_t
*wname
) {
1576 dns_fixedname_t fnext
;
1577 dns_fixedname_t forigin
;
1578 dns_fixedname_t fprev
;
1586 dns_rbtnode_t
*node
;
1587 dns_rbtnodechain_t chain
;
1588 isc_boolean_t check_next
= ISC_TRUE
;
1589 isc_boolean_t check_prev
= ISC_TRUE
;
1590 isc_boolean_t answer
= ISC_FALSE
;
1591 isc_result_t result
;
1592 rdatasetheader_t
*header
;
1595 rbtdb
= search
->rbtdb
;
1597 dns_name_init(&name
, NULL
);
1598 dns_name_init(&tname
, NULL
);
1599 dns_name_init(&rname
, NULL
);
1600 dns_fixedname_init(&fnext
);
1601 next
= dns_fixedname_name(&fnext
);
1602 dns_fixedname_init(&fprev
);
1603 prev
= dns_fixedname_name(&fprev
);
1604 dns_fixedname_init(&forigin
);
1605 origin
= dns_fixedname_name(&forigin
);
1608 * Find if qname is at or below a empty node.
1609 * Use our own copy of the chain.
1612 chain
= search
->chain
;
1615 result
= dns_rbtnodechain_current(&chain
, &name
,
1617 if (result
!= ISC_R_SUCCESS
)
1619 LOCK(&(rbtdb
->node_locks
[node
->locknum
].lock
));
1620 for (header
= node
->data
;
1622 header
= header
->next
) {
1623 if (header
->serial
<= search
->serial
&&
1624 !IGNORE(header
) && EXISTS(header
))
1627 UNLOCK(&(rbtdb
->node_locks
[node
->locknum
].lock
));
1630 result
= dns_rbtnodechain_prev(&chain
, NULL
, NULL
);
1631 } while (result
== ISC_R_SUCCESS
|| result
== DNS_R_NEWORIGIN
);
1632 if (result
== ISC_R_SUCCESS
)
1633 result
= dns_name_concatenate(&name
, origin
, prev
, NULL
);
1634 if (result
!= ISC_R_SUCCESS
)
1635 check_prev
= ISC_FALSE
;
1637 result
= dns_rbtnodechain_next(&chain
, NULL
, NULL
);
1638 while (result
== ISC_R_SUCCESS
|| result
== DNS_R_NEWORIGIN
) {
1640 result
= dns_rbtnodechain_current(&chain
, &name
,
1642 if (result
!= ISC_R_SUCCESS
)
1644 LOCK(&(rbtdb
->node_locks
[node
->locknum
].lock
));
1645 for (header
= node
->data
;
1647 header
= header
->next
) {
1648 if (header
->serial
<= search
->serial
&&
1649 !IGNORE(header
) && EXISTS(header
))
1652 UNLOCK(&(rbtdb
->node_locks
[node
->locknum
].lock
));
1655 result
= dns_rbtnodechain_next(&chain
, NULL
, NULL
);
1657 if (result
== ISC_R_SUCCESS
)
1658 result
= dns_name_concatenate(&name
, origin
, next
, NULL
);
1659 if (result
!= ISC_R_SUCCESS
)
1660 check_next
= ISC_FALSE
;
1662 dns_name_clone(qname
, &rname
);
1665 * Remove the wildcard label to find the terminal name.
1667 n
= dns_name_countlabels(wname
);
1668 dns_name_getlabelsequence(wname
, 1, n
- 1, &tname
);
1671 if ((check_prev
&& dns_name_issubdomain(prev
, &rname
)) ||
1672 (check_next
&& dns_name_issubdomain(next
, &rname
))) {
1677 * Remove the left hand label.
1679 n
= dns_name_countlabels(&rname
);
1680 dns_name_getlabelsequence(&rname
, 1, n
- 1, &rname
);
1681 } while (!dns_name_equal(&rname
, &tname
));
1685 static inline isc_result_t
1686 find_wildcard(rbtdb_search_t
*search
, dns_rbtnode_t
**nodep
,
1690 dns_rbtnode_t
*node
, *level_node
, *wnode
;
1691 rdatasetheader_t
*header
;
1692 isc_result_t result
= ISC_R_NOTFOUND
;
1695 dns_fixedname_t fwname
;
1697 isc_boolean_t done
, wild
, active
;
1698 dns_rbtnodechain_t wchain
;
1701 * Caller must be holding the tree lock and MUST NOT be holding
1706 * Examine each ancestor level. If the level's wild bit
1707 * is set, then construct the corresponding wildcard name and
1708 * search for it. If the wildcard node exists, and is active in
1709 * this version, we're done. If not, then we next check to see
1710 * if the ancestor is active in this version. If so, then there
1711 * can be no possible wildcard match and again we're done. If not,
1712 * continue the search.
1715 rbtdb
= search
->rbtdb
;
1716 i
= search
->chain
.level_matches
;
1720 LOCK(&(rbtdb
->node_locks
[node
->locknum
].lock
));
1723 * First we try to figure out if this node is active in
1724 * the search's version. We do this now, even though we
1725 * may not need the information, because it simplifies the
1726 * locking and code flow.
1728 for (header
= node
->data
;
1730 header
= header
->next
) {
1731 if (header
->serial
<= search
->serial
&&
1732 !IGNORE(header
) && EXISTS(header
))
1745 UNLOCK(&(rbtdb
->node_locks
[node
->locknum
].lock
));
1749 * Construct the wildcard name for this level.
1751 dns_name_init(&name
, NULL
);
1752 dns_rbt_namefromnode(node
, &name
);
1753 dns_fixedname_init(&fwname
);
1754 wname
= dns_fixedname_name(&fwname
);
1755 result
= dns_name_concatenate(dns_wildcardname
, &name
,
1758 while (result
== ISC_R_SUCCESS
&& j
!= 0) {
1760 level_node
= search
->chain
.levels
[j
];
1761 dns_name_init(&name
, NULL
);
1762 dns_rbt_namefromnode(level_node
, &name
);
1763 result
= dns_name_concatenate(wname
,
1768 if (result
!= ISC_R_SUCCESS
)
1772 dns_rbtnodechain_init(&wchain
, NULL
);
1773 result
= dns_rbt_findnode(rbtdb
->tree
, wname
,
1774 NULL
, &wnode
, &wchain
,
1775 DNS_RBTFIND_EMPTYDATA
,
1777 if (result
== ISC_R_SUCCESS
) {
1779 * We have found the wildcard node. If it
1780 * is active in the search's version, we're
1783 LOCK(&(rbtdb
->node_locks
[wnode
->locknum
].lock
));
1784 for (header
= wnode
->data
;
1786 header
= header
->next
) {
1787 if (header
->serial
<= search
->serial
&&
1788 !IGNORE(header
) && EXISTS(header
))
1791 UNLOCK(&(rbtdb
->node_locks
[wnode
->locknum
].lock
));
1792 if (header
!= NULL
||
1793 activeempty(search
, &wchain
, wname
)) {
1794 if (activeemtpynode(search
, qname
, wname
))
1795 return (ISC_R_NOTFOUND
);
1797 * The wildcard node is active!
1799 * Note: result is still ISC_R_SUCCESS
1800 * so we don't have to set it.
1805 } else if (result
!= ISC_R_NOTFOUND
&&
1806 result
!= DNS_R_PARTIALMATCH
) {
1808 * An error has occurred. Bail out.
1816 * The level node is active. Any wildcarding
1817 * present at higher levels has no
1818 * effect and we're done.
1820 result
= ISC_R_NOTFOUND
;
1826 node
= search
->chain
.levels
[i
];
1834 static inline isc_result_t
1835 find_closest_nxt(rbtdb_search_t
*search
, dns_dbnode_t
**nodep
,
1836 dns_name_t
*foundname
, dns_rdataset_t
*rdataset
,
1837 dns_rdataset_t
*sigrdataset
)
1839 dns_rbtnode_t
*node
;
1840 rdatasetheader_t
*header
, *header_next
, *found
, *foundsig
;
1841 isc_boolean_t empty_node
;
1842 isc_result_t result
;
1843 dns_fixedname_t fname
, forigin
;
1844 dns_name_t
*name
, *origin
;
1848 dns_fixedname_init(&fname
);
1849 name
= dns_fixedname_name(&fname
);
1850 dns_fixedname_init(&forigin
);
1851 origin
= dns_fixedname_name(&forigin
);
1852 result
= dns_rbtnodechain_current(&search
->chain
, name
,
1854 if (result
!= ISC_R_SUCCESS
)
1856 LOCK(&(search
->rbtdb
->node_locks
[node
->locknum
].lock
));
1859 empty_node
= ISC_TRUE
;
1860 for (header
= node
->data
;
1862 header
= header_next
) {
1863 header_next
= header
->next
;
1865 * Look for an active, extant NXT or SIG NXT.
1868 if (header
->serial
<= search
->serial
&&
1871 * Is this a "this rdataset doesn't
1874 if ((header
->attributes
&
1875 RDATASET_ATTR_NONEXISTENT
) != 0)
1879 header
= header
->down
;
1880 } while (header
!= NULL
);
1881 if (header
!= NULL
) {
1883 * We now know that there is at least one
1884 * active rdataset at this node.
1886 empty_node
= ISC_FALSE
;
1887 if (header
->type
== dns_rdatatype_nxt
) {
1889 if (foundsig
!= NULL
)
1891 } else if (header
->type
==
1892 RBTDB_RDATATYPE_SIGNXT
) {
1900 if (found
!= NULL
&& foundsig
!= NULL
) {
1902 * We've found the right NXT record.
1904 * Note: for this to really be the right
1905 * NXT record, it's essential that the NXT
1906 * records of any nodes obscured by a zone
1907 * cut have been removed; we assume this is
1910 result
= dns_name_concatenate(name
, origin
,
1912 if (result
== ISC_R_SUCCESS
) {
1913 if (nodep
!= NULL
) {
1914 new_reference(search
->rbtdb
,
1918 bind_rdataset(search
->rbtdb
, node
,
1921 bind_rdataset(search
->rbtdb
, node
,
1922 foundsig
, search
->now
,
1925 } else if (found
== NULL
&& foundsig
== NULL
) {
1927 * This node is active, but has no NXT or
1928 * SIG NXT. That means it's glue or
1929 * other obscured zone data that isn't
1930 * relevant for our search. Treat the
1931 * node as if it were empty and keep looking.
1933 empty_node
= ISC_TRUE
;
1934 result
= dns_rbtnodechain_prev(&search
->chain
,
1938 * We found an active node, but either the
1939 * NXT or the SIG NXT is missing. This
1942 result
= DNS_R_BADDB
;
1946 * This node isn't active. We've got to keep
1949 result
= dns_rbtnodechain_prev(&search
->chain
, NULL
,
1952 UNLOCK(&(search
->rbtdb
->node_locks
[node
->locknum
].lock
));
1953 } while (empty_node
&& result
== ISC_R_SUCCESS
);
1956 * If the result is ISC_R_NOMORE, then we got to the beginning of
1957 * the database and didn't find a NXT record. This shouldn't
1960 if (result
== ISC_R_NOMORE
)
1961 result
= DNS_R_BADDB
;
1967 zone_find(dns_db_t
*db
, dns_name_t
*name
, dns_dbversion_t
*version
,
1968 dns_rdatatype_t type
, unsigned int options
, isc_stdtime_t now
,
1969 dns_dbnode_t
**nodep
, dns_name_t
*foundname
,
1970 dns_rdataset_t
*rdataset
, dns_rdataset_t
*sigrdataset
)
1972 dns_rbtnode_t
*node
= NULL
;
1973 isc_result_t result
;
1974 rbtdb_search_t search
;
1975 isc_boolean_t cname_ok
= ISC_TRUE
;
1976 isc_boolean_t close_version
= ISC_FALSE
;
1977 isc_boolean_t maybe_zonecut
= ISC_FALSE
;
1978 isc_boolean_t at_zonecut
= ISC_FALSE
;
1980 isc_boolean_t empty_node
;
1982 rdatasetheader_t
*header
, *header_next
, *found
, *nxtheader
;
1983 rdatasetheader_t
*foundsig
, *cnamesig
, *nxtsig
;
1984 rbtdb_rdatatype_t sigtype
;
1985 isc_boolean_t active
;
1986 dns_rbtnodechain_t chain
;
1989 search
.rbtdb
= (dns_rbtdb_t
*)db
;
1991 REQUIRE(VALID_RBTDB(search
.rbtdb
));
1994 * We don't care about 'now'.
1999 * If the caller didn't supply a version, attach to the current
2002 if (version
== NULL
) {
2003 currentversion(db
, &version
);
2004 close_version
= ISC_TRUE
;
2007 search
.rbtversion
= version
;
2008 search
.serial
= search
.rbtversion
->serial
;
2009 search
.options
= options
;
2010 search
.copy_name
= ISC_FALSE
;
2011 search
.need_cleanup
= ISC_FALSE
;
2012 search
.wild
= ISC_FALSE
;
2013 search
.zonecut
= NULL
;
2014 dns_fixedname_init(&search
.zonecut_name
);
2015 dns_rbtnodechain_init(&search
.chain
, search
.rbtdb
->common
.mctx
);
2019 * 'wild' will be true iff. we've matched a wildcard.
2023 RWLOCK(&search
.rbtdb
->tree_lock
, isc_rwlocktype_read
);
2026 * Search down from the root of the tree. If, while going down, we
2027 * encounter a callback node, zone_zonecut_callback() will search the
2028 * rdatasets at the zone cut for active DNAME or NS rdatasets.
2030 result
= dns_rbt_findnode(search
.rbtdb
->tree
, name
, foundname
, &node
,
2031 &search
.chain
, DNS_RBTFIND_EMPTYDATA
,
2032 zone_zonecut_callback
, &search
);
2034 if (result
== DNS_R_PARTIALMATCH
) {
2036 if (search
.zonecut
!= NULL
) {
2037 result
= setup_delegation(&search
, nodep
, foundname
,
2038 rdataset
, sigrdataset
);
2044 * At least one of the levels in the search chain
2045 * potentially has a wildcard. For each such level,
2046 * we must see if there's a matching wildcard active
2047 * in the current version.
2049 result
= find_wildcard(&search
, &node
, name
);
2050 if (result
== ISC_R_SUCCESS
) {
2051 result
= dns_name_copy(name
, foundname
, NULL
);
2052 if (result
!= ISC_R_SUCCESS
)
2057 else if (result
!= ISC_R_NOTFOUND
)
2061 chain
= search
.chain
;
2062 active
= activeempty(&search
, &chain
, name
);
2065 * If we're here, then the name does not exist, is not
2066 * beneath a zonecut, and there's no matching wildcard.
2068 if (search
.rbtdb
->secure
) {
2069 result
= find_closest_nxt(&search
, nodep
, foundname
,
2070 rdataset
, sigrdataset
);
2071 if (result
== ISC_R_SUCCESS
)
2072 result
= active
? DNS_R_EMPTYNAME
:
2075 result
= active
? DNS_R_EMPTYNAME
: DNS_R_NXDOMAIN
;
2077 } else if (result
!= ISC_R_SUCCESS
)
2082 * We have found a node whose name is the desired name, or we
2083 * have matched a wildcard.
2086 if (search
.zonecut
!= NULL
) {
2088 * If we're beneath a zone cut, we don't want to look for
2089 * CNAMEs because they're not legitimate zone glue.
2091 cname_ok
= ISC_FALSE
;
2094 * The node may be a zone cut itself. If it might be one,
2095 * make sure we check for it later.
2097 if (node
->find_callback
&&
2098 (node
!= search
.rbtdb
->origin_node
||
2099 IS_STUB(search
.rbtdb
)))
2100 maybe_zonecut
= ISC_TRUE
;
2104 * Certain DNSSEC types are not subject to CNAME matching
2105 * (RFC 2535, section 2.3.5).
2107 * We don't check for SIG, because we don't store SIG records
2110 if (type
== dns_rdatatype_key
|| type
== dns_rdatatype_nxt
)
2111 cname_ok
= ISC_FALSE
;
2114 * We now go looking for rdata...
2117 LOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
2121 sigtype
= RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig
, type
);
2125 empty_node
= ISC_TRUE
;
2126 for (header
= node
->data
; header
!= NULL
; header
= header_next
) {
2127 header_next
= header
->next
;
2129 * Look for an active, extant rdataset.
2132 if (header
->serial
<= search
.serial
&&
2135 * Is this a "this rdataset doesn't
2138 if ((header
->attributes
&
2139 RDATASET_ATTR_NONEXISTENT
) != 0)
2143 header
= header
->down
;
2144 } while (header
!= NULL
);
2145 if (header
!= NULL
) {
2147 * We now know that there is at least one active
2148 * rdataset at this node.
2150 empty_node
= ISC_FALSE
;
2153 * Do special zone cut handling, if requested.
2155 if (maybe_zonecut
&&
2156 header
->type
== dns_rdatatype_ns
) {
2158 * We increment the reference count on node to
2159 * ensure that search->zonecut_rdataset will
2160 * still be valid later.
2162 new_reference(search
.rbtdb
, node
);
2163 search
.zonecut
= node
;
2164 search
.zonecut_rdataset
= header
;
2165 search
.zonecut_sigrdataset
= NULL
;
2166 search
.need_cleanup
= ISC_TRUE
;
2167 maybe_zonecut
= ISC_FALSE
;
2168 at_zonecut
= ISC_TRUE
;
2169 if ((search
.options
& DNS_DBFIND_GLUEOK
) == 0
2170 && type
!= dns_rdatatype_nxt
2171 && type
!= dns_rdatatype_key
) {
2173 * Glue is not OK, but any answer we
2174 * could return would be glue. Return
2180 if (found
!= NULL
&& foundsig
!= NULL
)
2185 * If we found a type we were looking for,
2188 if (header
->type
== type
||
2189 type
== dns_rdatatype_any
||
2190 (header
->type
== dns_rdatatype_cname
&&
2193 * We've found the answer!
2196 if (header
->type
== dns_rdatatype_cname
&&
2199 * We may be finding a CNAME instead
2200 * of the desired type.
2202 * If we've already got the CNAME SIG,
2203 * use it, otherwise change sigtype
2204 * so that we find it.
2206 if (cnamesig
!= NULL
)
2207 foundsig
= cnamesig
;
2210 RBTDB_RDATATYPE_SIGCNAME
;
2213 * If we've got all we need, end the search.
2215 if (!maybe_zonecut
&& foundsig
!= NULL
)
2217 } else if (header
->type
== sigtype
) {
2219 * We've found the SIG rdataset for our
2220 * target type. Remember it.
2224 * If we've got all we need, end the search.
2226 if (!maybe_zonecut
&& found
!= NULL
)
2228 } else if (header
->type
== dns_rdatatype_nxt
) {
2230 * Remember a NXT rdataset even if we're
2231 * not specifically looking for it, because
2232 * we might need it later.
2235 } else if (header
->type
== RBTDB_RDATATYPE_SIGNXT
) {
2237 * If we need the NXT rdataset, we'll also
2238 * need its signature.
2241 } else if (cname_ok
&&
2242 header
->type
== RBTDB_RDATATYPE_SIGCNAME
) {
2244 * If we get a CNAME match, we'll also need
2254 * We have an exact match for the name, but there are no
2255 * active rdatasets in the desired version. That means that
2256 * this node doesn't exist in the desired version, and that
2257 * we really have a partial match.
2260 UNLOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
2266 * If we didn't find what we were looking for...
2268 if (found
== NULL
) {
2269 if (search
.zonecut
!= NULL
) {
2271 * We were trying to find glue at a node beneath a
2272 * zone cut, but didn't.
2274 * Return the delegation.
2276 UNLOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
2277 result
= setup_delegation(&search
, nodep
, foundname
,
2278 rdataset
, sigrdataset
);
2282 * The desired type doesn't exist.
2284 result
= DNS_R_NXRRSET
;
2285 if (search
.rbtdb
->secure
&&
2286 (nxtheader
== NULL
|| nxtsig
== NULL
)) {
2288 * The zone is secure but there's no NXT,
2289 * or the NXT has no signature!
2292 result
= DNS_R_BADDB
;
2295 UNLOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
2296 result
= find_closest_nxt(&search
, nodep
, foundname
,
2297 rdataset
, sigrdataset
);
2298 if (result
== ISC_R_SUCCESS
)
2299 result
= DNS_R_EMPTYWILD
;
2302 if (nodep
!= NULL
) {
2303 new_reference(search
.rbtdb
, node
);
2306 if (search
.rbtdb
->secure
) {
2307 bind_rdataset(search
.rbtdb
, node
, nxtheader
,
2309 bind_rdataset(search
.rbtdb
, node
, nxtsig
,
2316 * We found what we were looking for, or we found a CNAME.
2319 if (type
!= found
->type
&&
2320 type
!= dns_rdatatype_any
&&
2321 found
->type
== dns_rdatatype_cname
) {
2323 * We weren't doing an ANY query and we found a CNAME instead
2324 * of the type we were looking for, so we need to indicate
2325 * that result to the caller.
2327 result
= DNS_R_CNAME
;
2328 } else if (search
.zonecut
!= NULL
) {
2330 * If we're beneath a zone cut, we must indicate that the
2331 * result is glue, unless we're actually at the zone cut
2332 * and the type is NXT or KEY.
2334 if (search
.zonecut
== node
) {
2335 if (type
== dns_rdatatype_nxt
||
2336 type
== dns_rdatatype_key
)
2337 result
= ISC_R_SUCCESS
;
2338 else if (type
== dns_rdatatype_any
)
2339 result
= DNS_R_ZONECUT
;
2341 result
= DNS_R_GLUE
;
2343 result
= DNS_R_GLUE
;
2345 * We might have found data that isn't glue, but was occluded
2346 * by a dynamic update. If the caller cares about this, they
2347 * will have told us to validate glue.
2349 * XXX We should cache the glue validity state!
2351 if (result
== DNS_R_GLUE
&&
2352 (search
.options
& DNS_DBFIND_VALIDATEGLUE
) != 0 &&
2353 !valid_glue(&search
, foundname
, type
, node
)) {
2354 UNLOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
2355 result
= setup_delegation(&search
, nodep
, foundname
,
2356 rdataset
, sigrdataset
);
2361 * An ordinary successful query!
2363 result
= ISC_R_SUCCESS
;
2366 if (nodep
!= NULL
) {
2368 new_reference(search
.rbtdb
, node
);
2370 search
.need_cleanup
= ISC_FALSE
;
2374 if (type
!= dns_rdatatype_any
) {
2375 bind_rdataset(search
.rbtdb
, node
, found
, 0, rdataset
);
2376 if (foundsig
!= NULL
)
2377 bind_rdataset(search
.rbtdb
, node
, foundsig
, 0,
2382 UNLOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
2385 RWUNLOCK(&search
.rbtdb
->tree_lock
, isc_rwlocktype_read
);
2388 * If we found a zonecut but aren't going to use it, we have to
2391 if (search
.need_cleanup
) {
2392 node
= search
.zonecut
;
2393 lock
= &(search
.rbtdb
->node_locks
[node
->locknum
].lock
);
2396 INSIST(node
->references
> 0);
2398 if (node
->references
== 0)
2399 no_references(search
.rbtdb
, node
, 0,
2400 isc_rwlocktype_none
);
2406 closeversion(db
, &version
, ISC_FALSE
);
2408 dns_rbtnodechain_reset(&search
.chain
);
2414 zone_findzonecut(dns_db_t
*db
, dns_name_t
*name
, unsigned int options
,
2415 isc_stdtime_t now
, dns_dbnode_t
**nodep
,
2416 dns_name_t
*foundname
,
2417 dns_rdataset_t
*rdataset
, dns_rdataset_t
*sigrdataset
)
2426 UNUSED(sigrdataset
);
2428 FATAL_ERROR(__FILE__
, __LINE__
, "zone_findzonecut() called!");
2430 return (ISC_R_NOTIMPLEMENTED
);
2434 cache_zonecut_callback(dns_rbtnode_t
*node
, dns_name_t
*name
, void *arg
) {
2435 rbtdb_search_t
*search
= arg
;
2436 rdatasetheader_t
*header
, *header_prev
, *header_next
;
2437 rdatasetheader_t
*dname_header
, *sigdname_header
;
2438 isc_result_t result
;
2442 REQUIRE(search
->zonecut
== NULL
);
2445 * Keep compiler silent.
2449 LOCK(&(search
->rbtdb
->node_locks
[node
->locknum
].lock
));
2452 * Look for a DNAME or SIG DNAME rdataset.
2454 dname_header
= NULL
;
2455 sigdname_header
= NULL
;
2457 for (header
= node
->data
; header
!= NULL
; header
= header_next
) {
2458 header_next
= header
->next
;
2459 if (header
->ttl
<= search
->now
) {
2461 * This rdataset is stale. If no one else is
2462 * using the node, we can clean it up right
2463 * now, otherwise we mark it as stale, and
2464 * the node as dirty, so it will get cleaned
2467 if (node
->references
== 0) {
2468 INSIST(header
->down
== NULL
);
2469 if (header_prev
!= NULL
)
2473 node
->data
= header
->next
;
2474 free_rdataset(search
->rbtdb
->common
.mctx
,
2477 header
->attributes
|=
2478 RDATASET_ATTR_STALE
;
2480 header_prev
= header
;
2482 } else if (header
->type
== dns_rdatatype_dname
&&
2484 dname_header
= header
;
2485 header_prev
= header
;
2486 } else if (header
->type
== RBTDB_RDATATYPE_SIGDNAME
&&
2488 sigdname_header
= header
;
2489 header_prev
= header
;
2491 header_prev
= header
;
2494 if (dname_header
!= NULL
&&
2495 (dname_header
->trust
!= dns_trust_pending
||
2496 (search
->options
& DNS_DBFIND_PENDINGOK
) != 0)) {
2498 * We increment the reference count on node to ensure that
2499 * search->zonecut_rdataset will still be valid later.
2501 new_reference(search
->rbtdb
, node
);
2502 search
->zonecut
= node
;
2503 search
->zonecut_rdataset
= dname_header
;
2504 search
->zonecut_sigrdataset
= sigdname_header
;
2505 search
->need_cleanup
= ISC_TRUE
;
2506 result
= DNS_R_PARTIALMATCH
;
2508 result
= DNS_R_CONTINUE
;
2510 UNLOCK(&(search
->rbtdb
->node_locks
[node
->locknum
].lock
));
2515 static inline isc_result_t
2516 find_deepest_zonecut(rbtdb_search_t
*search
, dns_rbtnode_t
*node
,
2517 dns_dbnode_t
**nodep
, dns_name_t
*foundname
,
2518 dns_rdataset_t
*rdataset
, dns_rdataset_t
*sigrdataset
)
2521 dns_rbtnode_t
*level_node
;
2522 rdatasetheader_t
*header
, *header_prev
, *header_next
;
2523 rdatasetheader_t
*found
, *foundsig
;
2524 isc_result_t result
= ISC_R_NOTFOUND
;
2530 * Caller must be holding the tree lock.
2533 rbtdb
= search
->rbtdb
;
2534 i
= search
->chain
.level_matches
;
2537 LOCK(&(rbtdb
->node_locks
[node
->locknum
].lock
));
2540 * Look for NS and SIG NS rdatasets.
2545 for (header
= node
->data
;
2547 header
= header_next
) {
2548 header_next
= header
->next
;
2549 if (header
->ttl
<= search
->now
) {
2551 * This rdataset is stale. If no one else is
2552 * using the node, we can clean it up right
2553 * now, otherwise we mark it as stale, and
2554 * the node as dirty, so it will get cleaned
2557 if (node
->references
== 0) {
2558 INSIST(header
->down
== NULL
);
2559 if (header_prev
!= NULL
)
2563 node
->data
= header
->next
;
2564 free_rdataset(rbtdb
->common
.mctx
,
2567 header
->attributes
|=
2568 RDATASET_ATTR_STALE
;
2570 header_prev
= header
;
2572 } else if ((header
->attributes
&
2573 RDATASET_ATTR_NONEXISTENT
) == 0) {
2575 * We've found an extant rdataset. See if
2576 * we're interested in it.
2578 if (header
->type
== dns_rdatatype_ns
) {
2580 if (foundsig
!= NULL
)
2582 } else if (header
->type
==
2583 RBTDB_RDATATYPE_SIGNS
) {
2588 header_prev
= header
;
2590 header_prev
= header
;
2593 if (found
!= NULL
) {
2595 * If we have to set foundname, we do it before
2596 * anything else. If we were to set foundname after
2597 * we had set nodep or bound the rdataset, then we'd
2598 * have to undo that work if dns_name_concatenate()
2599 * failed. By setting foundname first, there's
2600 * nothing to undo if we have trouble.
2602 if (foundname
!= NULL
) {
2603 dns_name_init(&name
, NULL
);
2604 dns_rbt_namefromnode(node
, &name
);
2605 result
= dns_name_copy(&name
, foundname
, NULL
);
2606 while (result
== ISC_R_SUCCESS
&& i
> 0) {
2608 level_node
= search
->chain
.levels
[i
];
2609 dns_name_init(&name
, NULL
);
2610 dns_rbt_namefromnode(level_node
,
2613 dns_name_concatenate(foundname
,
2618 if (result
!= ISC_R_SUCCESS
) {
2623 result
= DNS_R_DELEGATION
;
2624 if (nodep
!= NULL
) {
2625 new_reference(search
->rbtdb
, node
);
2628 bind_rdataset(search
->rbtdb
, node
, found
, search
->now
,
2630 if (foundsig
!= NULL
)
2631 bind_rdataset(search
->rbtdb
, node
, foundsig
,
2632 search
->now
, sigrdataset
);
2636 UNLOCK(&(search
->rbtdb
->node_locks
[node
->locknum
].lock
));
2638 if (found
== NULL
&& i
> 0) {
2640 node
= search
->chain
.levels
[i
];
2650 cache_find(dns_db_t
*db
, dns_name_t
*name
, dns_dbversion_t
*version
,
2651 dns_rdatatype_t type
, unsigned int options
, isc_stdtime_t now
,
2652 dns_dbnode_t
**nodep
, dns_name_t
*foundname
,
2653 dns_rdataset_t
*rdataset
, dns_rdataset_t
*sigrdataset
)
2655 dns_rbtnode_t
*node
= NULL
;
2656 isc_result_t result
;
2657 rbtdb_search_t search
;
2658 isc_boolean_t cname_ok
= ISC_TRUE
;
2659 isc_boolean_t empty_node
;
2661 rdatasetheader_t
*header
, *header_prev
, *header_next
;
2662 rdatasetheader_t
*found
, *nsheader
;
2663 rdatasetheader_t
*foundsig
, *nssig
, *cnamesig
;
2664 rbtdb_rdatatype_t sigtype
, nxtype
;
2668 search
.rbtdb
= (dns_rbtdb_t
*)db
;
2670 REQUIRE(VALID_RBTDB(search
.rbtdb
));
2671 REQUIRE(version
== NULL
);
2674 isc_stdtime_get(&now
);
2676 search
.rbtversion
= NULL
;
2678 search
.options
= options
;
2679 search
.copy_name
= ISC_FALSE
;
2680 search
.need_cleanup
= ISC_FALSE
;
2681 search
.wild
= ISC_FALSE
;
2682 search
.zonecut
= NULL
;
2683 dns_fixedname_init(&search
.zonecut_name
);
2684 dns_rbtnodechain_init(&search
.chain
, search
.rbtdb
->common
.mctx
);
2687 RWLOCK(&search
.rbtdb
->tree_lock
, isc_rwlocktype_read
);
2690 * Search down from the root of the tree. If, while going down, we
2691 * encounter a callback node, cache_zonecut_callback() will search the
2692 * rdatasets at the zone cut for a DNAME rdataset.
2694 result
= dns_rbt_findnode(search
.rbtdb
->tree
, name
, foundname
, &node
,
2695 &search
.chain
, DNS_RBTFIND_EMPTYDATA
,
2696 cache_zonecut_callback
, &search
);
2698 if (result
== DNS_R_PARTIALMATCH
) {
2699 if (search
.zonecut
!= NULL
) {
2700 result
= setup_delegation(&search
, nodep
, foundname
,
2701 rdataset
, sigrdataset
);
2705 result
= find_deepest_zonecut(&search
, node
, nodep
,
2706 foundname
, rdataset
,
2710 } else if (result
!= ISC_R_SUCCESS
)
2714 * Certain DNSSEC types are not subject to CNAME matching
2715 * (RFC 2535, section 2.3.5).
2717 * We don't check for SIG, because we don't store SIG records
2720 if (type
== dns_rdatatype_key
|| type
== dns_rdatatype_nxt
)
2721 cname_ok
= ISC_FALSE
;
2724 * We now go looking for rdata...
2727 LOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
2731 sigtype
= RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig
, type
);
2732 nxtype
= RBTDB_RDATATYPE_VALUE(0, type
);
2736 empty_node
= ISC_TRUE
;
2738 for (header
= node
->data
; header
!= NULL
; header
= header_next
) {
2739 header_next
= header
->next
;
2740 if (header
->ttl
<= now
) {
2742 * This rdataset is stale. If no one else is using the
2743 * node, we can clean it up right now, otherwise we
2744 * mark it as stale, and the node as dirty, so it will
2745 * get cleaned up later.
2747 if (node
->references
== 0) {
2748 INSIST(header
->down
== NULL
);
2749 if (header_prev
!= NULL
)
2750 header_prev
->next
= header
->next
;
2752 node
->data
= header
->next
;
2753 free_rdataset(search
.rbtdb
->common
.mctx
,
2756 header
->attributes
|= RDATASET_ATTR_STALE
;
2758 header_prev
= header
;
2760 } else if ((header
->attributes
& RDATASET_ATTR_NONEXISTENT
)
2763 * We now know that there is at least one active
2764 * non-stale rdataset at this node.
2766 empty_node
= ISC_FALSE
;
2769 * If we found a type we were looking for, remember
2772 if (header
->type
== type
||
2773 (type
== dns_rdatatype_any
&&
2774 RBTDB_RDATATYPE_BASE(header
->type
) != 0) ||
2775 (cname_ok
&& header
->type
==
2776 dns_rdatatype_cname
)) {
2778 * We've found the answer.
2781 if (header
->type
== dns_rdatatype_cname
&&
2785 * If we've already got the CNAME SIG,
2786 * use it, otherwise change sigtype
2787 * so that we find it.
2789 if (cnamesig
!= NULL
)
2790 foundsig
= cnamesig
;
2793 RBTDB_RDATATYPE_SIGCNAME
;
2794 foundsig
= cnamesig
;
2796 } else if (header
->type
== sigtype
) {
2798 * We've found the SIG rdataset for our
2799 * target type. Remember it.
2802 } else if (header
->type
== RBTDB_RDATATYPE_NCACHEANY
||
2803 header
->type
== nxtype
) {
2805 * We've found a negative cache entry.
2808 } else if (header
->type
== dns_rdatatype_ns
) {
2810 * Remember a NS rdataset even if we're
2811 * not specifically looking for it, because
2812 * we might need it later.
2815 } else if (header
->type
== RBTDB_RDATATYPE_SIGNS
) {
2817 * If we need the NS rdataset, we'll also
2818 * need its signature.
2821 } else if (cname_ok
&&
2822 header
->type
== RBTDB_RDATATYPE_SIGCNAME
) {
2824 * If we get a CNAME match, we'll also need
2829 header_prev
= header
;
2831 header_prev
= header
;
2836 * We have an exact match for the name, but there are no
2837 * extant rdatasets. That means that this node doesn't
2838 * meaningfully exist, and that we really have a partial match.
2840 UNLOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
2845 * If we didn't find what we were looking for...
2847 if (found
== NULL
||
2848 (found
->trust
== dns_trust_glue
&&
2849 ((options
& DNS_DBFIND_GLUEOK
) == 0)) ||
2850 (found
->trust
== dns_trust_pending
&&
2851 ((options
& DNS_DBFIND_PENDINGOK
) == 0))) {
2853 * If there is an NS rdataset at this node, then this is the
2856 if (nsheader
!= NULL
) {
2857 if (nodep
!= NULL
) {
2858 new_reference(search
.rbtdb
, node
);
2861 bind_rdataset(search
.rbtdb
, node
, nsheader
, search
.now
,
2864 bind_rdataset(search
.rbtdb
, node
, nssig
,
2865 search
.now
, sigrdataset
);
2866 result
= DNS_R_DELEGATION
;
2871 * Go find the deepest zone cut.
2873 UNLOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
2878 * We found what we were looking for, or we found a CNAME.
2881 if (nodep
!= NULL
) {
2882 new_reference(search
.rbtdb
, node
);
2886 if (RBTDB_RDATATYPE_BASE(found
->type
) == 0) {
2888 * We found a negative cache entry.
2890 if (NXDOMAIN(found
))
2891 result
= DNS_R_NCACHENXDOMAIN
;
2893 result
= DNS_R_NCACHENXRRSET
;
2894 } else if (type
!= found
->type
&&
2895 type
!= dns_rdatatype_any
&&
2896 found
->type
== dns_rdatatype_cname
) {
2898 * We weren't doing an ANY query and we found a CNAME instead
2899 * of the type we were looking for, so we need to indicate
2900 * that result to the caller.
2902 result
= DNS_R_CNAME
;
2905 * An ordinary successful query!
2907 result
= ISC_R_SUCCESS
;
2910 if (type
!= dns_rdatatype_any
|| result
== DNS_R_NCACHENXDOMAIN
||
2911 result
== DNS_R_NCACHENXRRSET
) {
2912 bind_rdataset(search
.rbtdb
, node
, found
, search
.now
,
2914 if (foundsig
!= NULL
)
2915 bind_rdataset(search
.rbtdb
, node
, foundsig
, search
.now
,
2920 UNLOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
2923 RWUNLOCK(&search
.rbtdb
->tree_lock
, isc_rwlocktype_read
);
2926 * If we found a zonecut but aren't going to use it, we have to
2929 if (search
.need_cleanup
) {
2930 node
= search
.zonecut
;
2931 lock
= &(search
.rbtdb
->node_locks
[node
->locknum
].lock
);
2934 INSIST(node
->references
> 0);
2936 if (node
->references
== 0)
2937 no_references(search
.rbtdb
, node
, 0,
2938 isc_rwlocktype_none
);
2942 dns_rbtnodechain_reset(&search
.chain
);
2948 cache_findzonecut(dns_db_t
*db
, dns_name_t
*name
, unsigned int options
,
2949 isc_stdtime_t now
, dns_dbnode_t
**nodep
,
2950 dns_name_t
*foundname
,
2951 dns_rdataset_t
*rdataset
, dns_rdataset_t
*sigrdataset
)
2953 dns_rbtnode_t
*node
= NULL
;
2954 isc_result_t result
;
2955 rbtdb_search_t search
;
2956 rdatasetheader_t
*header
, *header_prev
, *header_next
;
2957 rdatasetheader_t
*found
, *foundsig
;
2958 unsigned int rbtoptions
= DNS_RBTFIND_EMPTYDATA
;
2960 search
.rbtdb
= (dns_rbtdb_t
*)db
;
2962 REQUIRE(VALID_RBTDB(search
.rbtdb
));
2965 isc_stdtime_get(&now
);
2967 search
.rbtversion
= NULL
;
2969 search
.options
= options
;
2970 search
.copy_name
= ISC_FALSE
;
2971 search
.need_cleanup
= ISC_FALSE
;
2972 search
.wild
= ISC_FALSE
;
2973 search
.zonecut
= NULL
;
2974 dns_fixedname_init(&search
.zonecut_name
);
2975 dns_rbtnodechain_init(&search
.chain
, search
.rbtdb
->common
.mctx
);
2978 if ((options
& DNS_DBFIND_NOEXACT
) != 0)
2979 rbtoptions
|= DNS_RBTFIND_NOEXACT
;
2981 RWLOCK(&search
.rbtdb
->tree_lock
, isc_rwlocktype_read
);
2984 * Search down from the root of the tree.
2986 result
= dns_rbt_findnode(search
.rbtdb
->tree
, name
, foundname
, &node
,
2987 &search
.chain
, rbtoptions
, NULL
, &search
);
2989 if (result
== DNS_R_PARTIALMATCH
) {
2991 result
= find_deepest_zonecut(&search
, node
, nodep
, foundname
,
2992 rdataset
, sigrdataset
);
2994 } else if (result
!= ISC_R_SUCCESS
)
2998 * We now go looking for an NS rdataset at the node.
3001 LOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
3006 for (header
= node
->data
; header
!= NULL
; header
= header_next
) {
3007 header_next
= header
->next
;
3008 if (header
->ttl
<= now
) {
3010 * This rdataset is stale. If no one else is using the
3011 * node, we can clean it up right now, otherwise we
3012 * mark it as stale, and the node as dirty, so it will
3013 * get cleaned up later.
3015 if (node
->references
== 0) {
3016 INSIST(header
->down
== NULL
);
3017 if (header_prev
!= NULL
)
3018 header_prev
->next
= header
->next
;
3020 node
->data
= header
->next
;
3021 free_rdataset(search
.rbtdb
->common
.mctx
,
3024 header
->attributes
|= RDATASET_ATTR_STALE
;
3026 header_prev
= header
;
3028 } else if ((header
->attributes
& RDATASET_ATTR_NONEXISTENT
)
3031 * If we found a type we were looking for, remember
3034 if (header
->type
== dns_rdatatype_ns
) {
3036 * Remember a NS rdataset even if we're
3037 * not specifically looking for it, because
3038 * we might need it later.
3041 } else if (header
->type
== RBTDB_RDATATYPE_SIGNS
) {
3043 * If we need the NS rdataset, we'll also
3044 * need its signature.
3048 header_prev
= header
;
3050 header_prev
= header
;
3053 if (found
== NULL
) {
3055 * No NS records here.
3057 UNLOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
3061 if (nodep
!= NULL
) {
3062 new_reference(search
.rbtdb
, node
);
3066 bind_rdataset(search
.rbtdb
, node
, found
, search
.now
, rdataset
);
3067 if (foundsig
!= NULL
)
3068 bind_rdataset(search
.rbtdb
, node
, foundsig
, search
.now
,
3071 UNLOCK(&(search
.rbtdb
->node_locks
[node
->locknum
].lock
));
3074 RWUNLOCK(&search
.rbtdb
->tree_lock
, isc_rwlocktype_read
);
3076 INSIST(!search
.need_cleanup
);
3078 dns_rbtnodechain_reset(&search
.chain
);
3080 if (result
== DNS_R_DELEGATION
)
3081 result
= ISC_R_SUCCESS
;
3087 attachnode(dns_db_t
*db
, dns_dbnode_t
*source
, dns_dbnode_t
**targetp
) {
3088 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
3089 dns_rbtnode_t
*node
= (dns_rbtnode_t
*)source
;
3091 REQUIRE(VALID_RBTDB(rbtdb
));
3093 LOCK(&rbtdb
->node_locks
[node
->locknum
].lock
);
3094 INSIST(node
->references
> 0);
3096 INSIST(node
->references
!= 0); /* Catch overflow. */
3097 UNLOCK(&rbtdb
->node_locks
[node
->locknum
].lock
);
3103 detachnode(dns_db_t
*db
, dns_dbnode_t
**targetp
) {
3104 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
3105 dns_rbtnode_t
*node
;
3106 isc_boolean_t want_free
= ISC_FALSE
;
3107 isc_boolean_t inactive
= ISC_FALSE
;
3108 unsigned int locknum
;
3110 REQUIRE(VALID_RBTDB(rbtdb
));
3111 REQUIRE(targetp
!= NULL
&& *targetp
!= NULL
);
3113 node
= (dns_rbtnode_t
*)(*targetp
);
3114 locknum
= node
->locknum
;
3116 LOCK(&rbtdb
->node_locks
[locknum
].lock
);
3118 INSIST(node
->references
> 0);
3120 if (node
->references
== 0) {
3121 no_references(rbtdb
, node
, 0, isc_rwlocktype_none
);
3122 if (rbtdb
->node_locks
[locknum
].references
== 0 &&
3123 rbtdb
->node_locks
[locknum
].exiting
)
3124 inactive
= ISC_TRUE
;
3127 UNLOCK(&rbtdb
->node_locks
[locknum
].lock
);
3134 if (rbtdb
->active
== 0)
3135 want_free
= ISC_TRUE
;
3136 UNLOCK(&rbtdb
->lock
);
3138 char buf
[DNS_NAME_FORMATSIZE
];
3139 if (dns_name_dynamic(&rbtdb
->common
.origin
))
3140 dns_name_format(&rbtdb
->common
.origin
, buf
,
3143 strcpy(buf
, "<UNKNOWN>");
3144 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
3145 DNS_LOGMODULE_CACHE
, ISC_LOG_DEBUG(1),
3146 "calling free_rbtdb(%s)", buf
);
3147 free_rbtdb(rbtdb
, ISC_TRUE
, NULL
);
3153 expirenode(dns_db_t
*db
, dns_dbnode_t
*node
, isc_stdtime_t now
) {
3154 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
3155 dns_rbtnode_t
*rbtnode
= node
;
3156 rdatasetheader_t
*header
;
3157 isc_boolean_t force_expire
= ISC_FALSE
;
3159 * These are the category and module used by the cache cleaner.
3161 isc_boolean_t log
= ISC_FALSE
;
3162 isc_logcategory_t
*category
= DNS_LOGCATEGORY_DATABASE
;
3163 isc_logmodule_t
*module
= DNS_LOGMODULE_CACHE
;
3164 int level
= ISC_LOG_DEBUG(2);
3165 char printname
[DNS_NAME_FORMATSIZE
];
3167 REQUIRE(VALID_RBTDB(rbtdb
));
3170 * Caller must hold a tree lock.
3174 isc_stdtime_get(&now
);
3176 if (rbtdb
->overmem
) {
3179 isc_random_get(&val
);
3181 * XXXDCL Could stand to have a better policy, like LRU.
3183 force_expire
= ISC_TF(rbtnode
->down
== NULL
&& val
% 4 == 0);
3186 * Note that 'log' can be true IFF rbtdb->overmem is also true.
3187 * rbtdb->ovemem can currently only be true for cache databases
3188 * -- hence all of the "overmem cache" log strings.
3190 log
= ISC_TF(isc_log_wouldlog(dns_lctx
, level
));
3192 isc_log_write(dns_lctx
, category
, module
, level
,
3193 "overmem cache: %s %s",
3194 force_expire
? "FORCE" : "check",
3195 dns_rbt_formatnodename(rbtnode
,
3197 sizeof(printname
)));
3200 LOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
3202 for (header
= rbtnode
->data
; header
!= NULL
; header
= header
->next
)
3203 if (header
->ttl
<= now
) {
3205 * We don't check if rbtnode->references == 0 and try
3206 * to free like we do in cache_find(), because
3207 * rbtnode->references must be non-zero. This is so
3208 * because 'node' is an argument to the function.
3210 header
->attributes
|= RDATASET_ATTR_STALE
;
3213 isc_log_write(dns_lctx
, category
, module
,
3214 level
, "overmem cache: stale %s",
3216 } else if (force_expire
) {
3217 if (! RETAIN(header
)) {
3219 header
->attributes
|= RDATASET_ATTR_STALE
;
3222 isc_log_write(dns_lctx
, category
, module
,
3223 level
, "overmem cache: "
3224 "reprieve by RETAIN() %s",
3227 } else if (rbtdb
->overmem
&& log
)
3228 isc_log_write(dns_lctx
, category
, module
, level
,
3229 "overmem cache: saved %s", printname
);
3231 UNLOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
3233 return (ISC_R_SUCCESS
);
3237 overmem(dns_db_t
*db
, isc_boolean_t overmem
) {
3238 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
3240 if (IS_CACHE(rbtdb
)) {
3241 rbtdb
->overmem
= overmem
;
3246 printnode(dns_db_t
*db
, dns_dbnode_t
*node
, FILE *out
) {
3247 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
3248 dns_rbtnode_t
*rbtnode
= node
;
3249 isc_boolean_t first
;
3251 REQUIRE(VALID_RBTDB(rbtdb
));
3253 LOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
3255 fprintf(out
, "node %p, %u references, locknum = %u\n",
3256 rbtnode
, rbtnode
->references
, rbtnode
->locknum
);
3257 if (rbtnode
->data
!= NULL
) {
3258 rdatasetheader_t
*current
, *top_next
;
3260 for (current
= rbtnode
->data
; current
!= NULL
;
3261 current
= top_next
) {
3262 top_next
= current
->next
;
3264 fprintf(out
, "\ttype %u", current
->type
);
3270 "\tserial = %lu, ttl = %u, "
3271 "trust = %u, attributes = %u\n",
3272 (unsigned long)current
->serial
,
3275 current
->attributes
);
3276 current
= current
->down
;
3277 } while (current
!= NULL
);
3280 fprintf(out
, "(empty)\n");
3282 UNLOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
3286 createiterator(dns_db_t
*db
, isc_boolean_t relative_names
,
3287 dns_dbiterator_t
**iteratorp
)
3289 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
3290 rbtdb_dbiterator_t
*rbtdbiter
;
3292 REQUIRE(VALID_RBTDB(rbtdb
));
3294 rbtdbiter
= isc_mem_get(rbtdb
->common
.mctx
, sizeof *rbtdbiter
);
3295 if (rbtdbiter
== NULL
)
3296 return (ISC_R_NOMEMORY
);
3298 rbtdbiter
->common
.methods
= &dbiterator_methods
;
3299 rbtdbiter
->common
.db
= NULL
;
3300 dns_db_attach(db
, &rbtdbiter
->common
.db
);
3301 rbtdbiter
->common
.relative_names
= relative_names
;
3302 rbtdbiter
->common
.magic
= DNS_DBITERATOR_MAGIC
;
3303 rbtdbiter
->common
.cleaning
= ISC_FALSE
;
3304 rbtdbiter
->paused
= ISC_TRUE
;
3305 rbtdbiter
->tree_locked
= isc_rwlocktype_none
;
3306 rbtdbiter
->result
= ISC_R_SUCCESS
;
3307 dns_fixedname_init(&rbtdbiter
->name
);
3308 dns_fixedname_init(&rbtdbiter
->origin
);
3309 rbtdbiter
->node
= NULL
;
3310 rbtdbiter
->delete = 0;
3311 memset(rbtdbiter
->deletions
, 0, sizeof(rbtdbiter
->deletions
));
3312 dns_rbtnodechain_init(&rbtdbiter
->chain
, db
->mctx
);
3314 *iteratorp
= (dns_dbiterator_t
*)rbtdbiter
;
3316 return (ISC_R_SUCCESS
);
3320 zone_findrdataset(dns_db_t
*db
, dns_dbnode_t
*node
, dns_dbversion_t
*version
,
3321 dns_rdatatype_t type
, dns_rdatatype_t covers
,
3322 isc_stdtime_t now
, dns_rdataset_t
*rdataset
,
3323 dns_rdataset_t
*sigrdataset
)
3325 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
3326 dns_rbtnode_t
*rbtnode
= (dns_rbtnode_t
*)node
;
3327 rdatasetheader_t
*header
, *header_next
, *found
, *foundsig
;
3328 rbtdb_serial_t serial
;
3329 rbtdb_version_t
*rbtversion
= version
;
3330 isc_boolean_t close_version
= ISC_FALSE
;
3331 rbtdb_rdatatype_t matchtype
, sigmatchtype
;
3333 REQUIRE(VALID_RBTDB(rbtdb
));
3334 REQUIRE(type
!= dns_rdatatype_any
);
3336 if (rbtversion
== NULL
) {
3337 currentversion(db
, (dns_dbversion_t
**) (void *)(&rbtversion
));
3338 close_version
= ISC_TRUE
;
3340 serial
= rbtversion
->serial
;
3343 LOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
3347 matchtype
= RBTDB_RDATATYPE_VALUE(type
, covers
);
3349 sigmatchtype
= RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig
, type
);
3353 for (header
= rbtnode
->data
; header
!= NULL
; header
= header_next
) {
3354 header_next
= header
->next
;
3356 if (header
->serial
<= serial
&&
3359 * Is this a "this rdataset doesn't
3362 if ((header
->attributes
&
3363 RDATASET_ATTR_NONEXISTENT
) != 0)
3367 header
= header
->down
;
3368 } while (header
!= NULL
);
3369 if (header
!= NULL
) {
3371 * We have an active, extant rdataset. If it's a
3372 * type we're looking for, remember it.
3374 if (header
->type
== matchtype
) {
3376 if (foundsig
!= NULL
)
3378 } else if (header
->type
== sigmatchtype
) {
3385 if (found
!= NULL
) {
3386 bind_rdataset(rbtdb
, rbtnode
, found
, now
, rdataset
);
3387 if (foundsig
!= NULL
)
3388 bind_rdataset(rbtdb
, rbtnode
, foundsig
, now
,
3392 UNLOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
3395 closeversion(db
, (dns_dbversion_t
**) (void *)(&rbtversion
),
3399 return (ISC_R_NOTFOUND
);
3401 return (ISC_R_SUCCESS
);
3405 cache_findrdataset(dns_db_t
*db
, dns_dbnode_t
*node
, dns_dbversion_t
*version
,
3406 dns_rdatatype_t type
, dns_rdatatype_t covers
,
3407 isc_stdtime_t now
, dns_rdataset_t
*rdataset
,
3408 dns_rdataset_t
*sigrdataset
)
3410 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
3411 dns_rbtnode_t
*rbtnode
= (dns_rbtnode_t
*)node
;
3412 rdatasetheader_t
*header
, *header_next
, *found
, *foundsig
;
3413 rbtdb_rdatatype_t matchtype
, sigmatchtype
, nxtype
;
3414 isc_result_t result
;
3416 REQUIRE(VALID_RBTDB(rbtdb
));
3417 REQUIRE(type
!= dns_rdatatype_any
);
3421 result
= ISC_R_SUCCESS
;
3424 isc_stdtime_get(&now
);
3426 LOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
3430 matchtype
= RBTDB_RDATATYPE_VALUE(type
, covers
);
3431 nxtype
= RBTDB_RDATATYPE_VALUE(0, type
);
3433 sigmatchtype
= RBTDB_RDATATYPE_VALUE(dns_rdatatype_sig
, type
);
3437 for (header
= rbtnode
->data
; header
!= NULL
; header
= header_next
) {
3438 header_next
= header
->next
;
3439 if (header
->ttl
<= now
) {
3441 * We don't check if rbtnode->references == 0 and try
3442 * to free like we do in cache_find(), because
3443 * rbtnode->references must be non-zero. This is so
3444 * because 'node' is an argument to the function.
3446 header
->attributes
|= RDATASET_ATTR_STALE
;
3448 } else if ((header
->attributes
& RDATASET_ATTR_NONEXISTENT
) ==
3450 if (header
->type
== matchtype
)
3452 else if (header
->type
== RBTDB_RDATATYPE_NCACHEANY
||
3453 header
->type
== nxtype
)
3455 else if (header
->type
== sigmatchtype
)
3459 if (found
!= NULL
) {
3460 bind_rdataset(rbtdb
, rbtnode
, found
, now
, rdataset
);
3461 if (foundsig
!= NULL
)
3462 bind_rdataset(rbtdb
, rbtnode
, foundsig
, now
,
3466 UNLOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
3469 return (ISC_R_NOTFOUND
);
3471 if (RBTDB_RDATATYPE_BASE(found
->type
) == 0) {
3473 * We found a negative cache entry.
3475 if (NXDOMAIN(found
))
3476 result
= DNS_R_NCACHENXDOMAIN
;
3478 result
= DNS_R_NCACHENXRRSET
;
3485 allrdatasets(dns_db_t
*db
, dns_dbnode_t
*node
, dns_dbversion_t
*version
,
3486 isc_stdtime_t now
, dns_rdatasetiter_t
**iteratorp
)
3488 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
3489 dns_rbtnode_t
*rbtnode
= (dns_rbtnode_t
*)node
;
3490 rbtdb_version_t
*rbtversion
= version
;
3491 rbtdb_rdatasetiter_t
*iterator
;
3493 REQUIRE(VALID_RBTDB(rbtdb
));
3495 iterator
= isc_mem_get(rbtdb
->common
.mctx
, sizeof *iterator
);
3496 if (iterator
== NULL
)
3497 return (ISC_R_NOMEMORY
);
3499 if ((db
->attributes
& DNS_DBATTR_CACHE
) == 0) {
3501 if (rbtversion
== NULL
)
3503 (dns_dbversion_t
**) (void *)(&rbtversion
));
3506 INSIST(rbtversion
->references
> 0);
3507 rbtversion
->references
++;
3508 INSIST(rbtversion
->references
!= 0);
3509 UNLOCK(&rbtdb
->lock
);
3513 isc_stdtime_get(&now
);
3517 iterator
->common
.magic
= DNS_RDATASETITER_MAGIC
;
3518 iterator
->common
.methods
= &rdatasetiter_methods
;
3519 iterator
->common
.db
= db
;
3520 iterator
->common
.node
= node
;
3521 iterator
->common
.version
= (dns_dbversion_t
*)rbtversion
;
3522 iterator
->common
.now
= now
;
3524 LOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
3526 INSIST(rbtnode
->references
> 0);
3527 rbtnode
->references
++;
3528 INSIST(rbtnode
->references
!= 0);
3529 iterator
->current
= NULL
;
3531 UNLOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
3533 *iteratorp
= (dns_rdatasetiter_t
*)iterator
;
3535 return (ISC_R_SUCCESS
);
3538 static isc_boolean_t
3539 cname_and_other_data(dns_rbtnode_t
*node
, rbtdb_serial_t serial
) {
3540 rdatasetheader_t
*header
, *header_next
;
3541 isc_boolean_t cname
, other_data
;
3542 dns_rdatatype_t rdtype
;
3545 * The caller must hold the node lock.
3549 * Look for CNAME and "other data" rdatasets active in our version.
3552 other_data
= ISC_FALSE
;
3553 for (header
= node
->data
; header
!= NULL
; header
= header_next
) {
3554 header_next
= header
->next
;
3555 if (header
->type
== dns_rdatatype_cname
) {
3557 * Look for an active extant CNAME.
3560 if (header
->serial
<= serial
&&
3563 * Is this a "this rdataset doesn't
3566 if (NONEXISTENT(header
))
3570 header
= header
->down
;
3571 } while (header
!= NULL
);
3576 * Look for active extant "other data".
3578 * "Other data" is any rdataset whose type is not
3579 * KEY, SIG KEY, NXT, SIG NXT, or SIG CNAME.
3581 rdtype
= RBTDB_RDATATYPE_BASE(header
->type
);
3582 if (rdtype
== dns_rdatatype_sig
)
3583 rdtype
= RBTDB_RDATATYPE_EXT(header
->type
);
3584 if (rdtype
!= dns_rdatatype_nxt
&&
3585 rdtype
!= dns_rdatatype_key
&&
3586 rdtype
!= dns_rdatatype_cname
) {
3588 * We've found a type that isn't
3589 * NXT, KEY, CNAME, or one of their
3590 * signatures. Is it active and extant?
3593 if (header
->serial
<= serial
&&
3596 * Is this a "this rdataset
3597 * doesn't exist" record?
3599 if (NONEXISTENT(header
))
3603 header
= header
->down
;
3604 } while (header
!= NULL
);
3606 other_data
= ISC_TRUE
;
3611 if (cname
&& other_data
)
3618 add(dns_rbtdb_t
*rbtdb
, dns_rbtnode_t
*rbtnode
, rbtdb_version_t
*rbtversion
,
3619 rdatasetheader_t
*newheader
, unsigned int options
, isc_boolean_t loading
,
3620 dns_rdataset_t
*addedrdataset
, isc_stdtime_t now
)
3622 rbtdb_changed_t
*changed
= NULL
;
3623 rdatasetheader_t
*topheader
, *topheader_prev
, *header
;
3624 unsigned char *merged
;
3625 isc_result_t result
;
3626 isc_boolean_t header_nx
;
3627 isc_boolean_t newheader_nx
;
3628 isc_boolean_t merge
;
3629 dns_rdatatype_t nxtype
, rdtype
, covers
;
3633 * Add an rdatasetheader_t to a node.
3637 * Caller must be holding the node lock.
3640 if ((options
& DNS_DBADD_MERGE
) != 0) {
3641 REQUIRE(rbtversion
!= NULL
);
3646 if ((options
& DNS_DBADD_FORCE
) != 0)
3647 trust
= dns_trust_ultimate
;
3649 trust
= newheader
->trust
;
3651 if (rbtversion
!= NULL
&& !loading
) {
3653 * We always add a changed record, even if no changes end up
3654 * being made to this node, because it's harmless and
3655 * simplifies the code.
3657 changed
= add_changed(rbtdb
, rbtversion
, rbtnode
);
3658 if (changed
== NULL
) {
3659 free_rdataset(rbtdb
->common
.mctx
, newheader
);
3660 return (ISC_R_NOMEMORY
);
3664 newheader_nx
= NONEXISTENT(newheader
) ? ISC_TRUE
: ISC_FALSE
;
3665 topheader_prev
= NULL
;
3668 if (rbtversion
== NULL
&& !newheader_nx
) {
3669 rdtype
= RBTDB_RDATATYPE_BASE(newheader
->type
);
3672 * We're adding a negative cache entry.
3674 covers
= RBTDB_RDATATYPE_EXT(newheader
->type
);
3675 if (covers
== dns_rdatatype_any
) {
3677 * We're adding an NXDOMAIN negative cache
3680 * We make all other data stale so that the
3681 * only rdataset that can be found at this
3682 * node is the NXDOMAIN negative cache entry.
3684 for (topheader
= rbtnode
->data
;
3686 topheader
= topheader
->next
) {
3688 topheader
->attributes
|=
3689 RDATASET_ATTR_STALE
;
3694 nxtype
= RBTDB_RDATATYPE_VALUE(covers
, 0);
3697 * We're adding something that isn't a
3698 * negative cache entry. Look for an extant
3699 * non-stale NXDOMAIN negative cache entry.
3701 for (topheader
= rbtnode
->data
;
3703 topheader
= topheader
->next
) {
3704 if (NXDOMAIN(topheader
))
3707 if (topheader
!= NULL
&& EXISTS(topheader
) &&
3708 topheader
->ttl
> now
) {
3712 if (trust
< topheader
->trust
) {
3714 * The NXDOMAIN is more trusted.
3716 free_rdataset(rbtdb
->common
.mctx
,
3718 if (addedrdataset
!= NULL
)
3719 bind_rdataset(rbtdb
, rbtnode
,
3722 return (DNS_R_UNCHANGED
);
3725 * The new rdataset is better. Expire the
3729 topheader
->attributes
|= RDATASET_ATTR_STALE
;
3734 nxtype
= RBTDB_RDATATYPE_VALUE(0, rdtype
);
3738 for (topheader
= rbtnode
->data
;
3740 topheader
= topheader
->next
) {
3741 if (topheader
->type
== newheader
->type
||
3742 topheader
->type
== nxtype
)
3744 topheader_prev
= topheader
;
3749 * If header isn't NULL, we've found the right type. There may be
3750 * IGNORE rdatasets between the top of the chain and the first real
3751 * data. We skip over them.
3754 while (header
!= NULL
&& IGNORE(header
))
3755 header
= header
->down
;
3756 if (header
!= NULL
) {
3757 header_nx
= NONEXISTENT(header
) ? ISC_TRUE
: ISC_FALSE
;
3760 * Deleting an already non-existent rdataset has no effect.
3762 if (header_nx
&& newheader_nx
) {
3763 free_rdataset(rbtdb
->common
.mctx
, newheader
);
3764 return (DNS_R_UNCHANGED
);
3768 * Trying to add an rdataset with lower trust to a cache DB
3769 * has no effect, provided that the cache data isn't stale.
3771 if (rbtversion
== NULL
&& trust
< header
->trust
&&
3772 (header
->ttl
> now
|| header_nx
)) {
3773 free_rdataset(rbtdb
->common
.mctx
, newheader
);
3774 if (addedrdataset
!= NULL
)
3775 bind_rdataset(rbtdb
, rbtnode
, header
, now
,
3777 return (DNS_R_UNCHANGED
);
3781 * Don't merge if a nonexistent rdataset is involved.
3783 if (merge
&& (header_nx
|| newheader_nx
))
3787 * If 'merge' is ISC_TRUE, we'll try to create a new rdataset
3788 * that is the union of 'newheader' and 'header'.
3791 unsigned int flags
= 0;
3792 INSIST(rbtversion
->serial
>= header
->serial
);
3794 result
= ISC_R_SUCCESS
;
3796 if ((options
& DNS_DBADD_EXACT
) != 0)
3797 flags
|= DNS_RDATASLAB_EXACT
;
3798 if ((options
& DNS_DBADD_EXACTTTL
) != 0 &&
3799 newheader
->ttl
!= header
->ttl
)
3800 result
= DNS_R_NOTEXACT
;
3801 else if (newheader
->ttl
!= header
->ttl
)
3802 flags
|= DNS_RDATASLAB_FORCE
;
3803 if (result
== ISC_R_SUCCESS
)
3804 result
= dns_rdataslab_merge(
3805 (unsigned char *)header
,
3806 (unsigned char *)newheader
,
3807 (unsigned int)(sizeof *newheader
),
3809 rbtdb
->common
.rdclass
,
3810 (dns_rdatatype_t
)header
->type
,
3812 if (result
== ISC_R_SUCCESS
) {
3814 * If 'header' has the same serial number as
3815 * we do, we could clean it up now if we knew
3816 * that our caller had no references to it.
3817 * We don't know this, however, so we leave it
3818 * alone. It will get cleaned up when
3819 * clean_zone_node() runs.
3821 free_rdataset(rbtdb
->common
.mctx
, newheader
);
3822 newheader
= (rdatasetheader_t
*)merged
;
3824 free_rdataset(rbtdb
->common
.mctx
, newheader
);
3829 * Don't replace existing NS, A and AAAA RRsets
3830 * in the cache if they are already exist. This
3831 * prevents named being locked to old servers.
3833 if (IS_CACHE(rbtdb
) && header
->ttl
> now
&&
3834 header
->type
== dns_rdatatype_ns
&&
3835 !header_nx
&& !newheader_nx
&&
3836 header
->trust
== newheader
->trust
&&
3837 dns_rdataslab_equalx((unsigned char *)header
,
3838 (unsigned char *)newheader
,
3839 (unsigned int)(sizeof(*newheader
)),
3840 rbtdb
->common
.rdclass
,
3841 (dns_rdatatype_t
)header
->type
)) {
3843 * Honour the new ttl if it is less than the
3846 if (header
->ttl
> newheader
->ttl
)
3847 header
->ttl
= newheader
->ttl
;
3848 free_rdataset(rbtdb
->common
.mctx
, newheader
);
3849 if (addedrdataset
!= NULL
)
3850 bind_rdataset(rbtdb
, rbtnode
, header
, now
,
3852 return (ISC_R_SUCCESS
);
3854 if (IS_CACHE(rbtdb
) && header
->ttl
> now
&&
3855 (header
->type
== dns_rdatatype_a
||
3856 header
->type
== dns_rdatatype_aaaa
) &&
3857 !header_nx
&& !newheader_nx
&&
3858 header
->trust
== newheader
->trust
&&
3859 dns_rdataslab_equal((unsigned char *)header
,
3860 (unsigned char *)newheader
,
3861 (unsigned int)(sizeof(*newheader
)))) {
3863 * Honour the new ttl if it is less than the
3866 if (header
->ttl
> newheader
->ttl
)
3867 header
->ttl
= newheader
->ttl
;
3868 free_rdataset(rbtdb
->common
.mctx
, newheader
);
3869 if (addedrdataset
!= NULL
)
3870 bind_rdataset(rbtdb
, rbtnode
, header
, now
,
3872 return (ISC_R_SUCCESS
);
3874 INSIST(rbtversion
== NULL
||
3875 rbtversion
->serial
>= topheader
->serial
);
3876 if (topheader_prev
!= NULL
)
3877 topheader_prev
->next
= newheader
;
3879 rbtnode
->data
= newheader
;
3880 newheader
->next
= topheader
->next
;
3883 * There are no other references to 'header' when
3884 * loading, so we MAY clean up 'header' now.
3885 * Since we don't generate changed records when
3886 * loading, we MUST clean up 'header' now.
3888 newheader
->down
= NULL
;
3889 free_rdataset(rbtdb
->common
.mctx
, header
);
3891 newheader
->down
= topheader
;
3892 topheader
->next
= newheader
;
3894 if (changed
!= NULL
)
3895 changed
->dirty
= ISC_TRUE
;
3899 * No non-IGNORED rdatasets of the given type exist at
3904 * If we're trying to delete the type, don't bother.
3907 free_rdataset(rbtdb
->common
.mctx
, newheader
);
3908 return (DNS_R_UNCHANGED
);
3911 if (topheader
!= NULL
) {
3913 * We have an list of rdatasets of the given type,
3914 * but they're all marked IGNORE. We simply insert
3915 * the new rdataset at the head of the list.
3917 * Ignored rdatasets cannot occur during loading, so
3921 INSIST(rbtversion
== NULL
||
3922 rbtversion
->serial
>= topheader
->serial
);
3923 if (topheader_prev
!= NULL
)
3924 topheader_prev
->next
= newheader
;
3926 rbtnode
->data
= newheader
;
3927 newheader
->next
= topheader
->next
;
3928 newheader
->down
= topheader
;
3929 topheader
->next
= newheader
;
3931 if (changed
!= NULL
)
3932 changed
->dirty
= ISC_TRUE
;
3935 * No rdatasets of the given type exist at the node.
3937 newheader
->next
= rbtnode
->data
;
3938 newheader
->down
= NULL
;
3939 rbtnode
->data
= newheader
;
3944 * Check if the node now contains CNAME and other data.
3946 if (rbtversion
!= NULL
&&
3947 cname_and_other_data(rbtnode
, rbtversion
->serial
))
3948 return (DNS_R_CNAMEANDOTHER
);
3950 if (addedrdataset
!= NULL
)
3951 bind_rdataset(rbtdb
, rbtnode
, newheader
, now
, addedrdataset
);
3953 return (ISC_R_SUCCESS
);
3956 static inline isc_boolean_t
3957 delegating_type(dns_rbtdb_t
*rbtdb
, dns_rbtnode_t
*node
,
3958 rbtdb_rdatatype_t type
)
3960 if (IS_CACHE(rbtdb
)) {
3961 if (type
== dns_rdatatype_dname
)
3965 } else if (type
== dns_rdatatype_dname
||
3966 (type
== dns_rdatatype_ns
&&
3967 (node
!= rbtdb
->origin_node
|| IS_STUB(rbtdb
))))
3973 addrdataset(dns_db_t
*db
, dns_dbnode_t
*node
, dns_dbversion_t
*version
,
3974 isc_stdtime_t now
, dns_rdataset_t
*rdataset
, unsigned int options
,
3975 dns_rdataset_t
*addedrdataset
)
3977 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
3978 dns_rbtnode_t
*rbtnode
= (dns_rbtnode_t
*)node
;
3979 rbtdb_version_t
*rbtversion
= version
;
3980 isc_region_t region
;
3981 rdatasetheader_t
*newheader
;
3982 isc_result_t result
;
3983 isc_boolean_t delegating
;
3985 REQUIRE(VALID_RBTDB(rbtdb
));
3987 if (rbtversion
== NULL
) {
3989 isc_stdtime_get(&now
);
3993 result
= dns_rdataslab_fromrdataset(rdataset
, rbtdb
->common
.mctx
,
3995 sizeof (rdatasetheader_t
));
3996 if (result
!= ISC_R_SUCCESS
)
3999 newheader
= (rdatasetheader_t
*)region
.base
;
4000 newheader
->ttl
= rdataset
->ttl
+ now
;
4001 newheader
->type
= RBTDB_RDATATYPE_VALUE(rdataset
->type
,
4003 newheader
->attributes
= 0;
4004 newheader
->trust
= rdataset
->trust
;
4005 if (rbtversion
!= NULL
) {
4006 newheader
->serial
= rbtversion
->serial
;
4009 newheader
->serial
= 1;
4010 if ((rdataset
->attributes
& DNS_RDATASETATTR_NXDOMAIN
) != 0)
4011 newheader
->attributes
|= RDATASET_ATTR_NXDOMAIN
;
4015 * If we're adding a delegation type (e.g. NS or DNAME for a zone,
4016 * just DNAME for the cache), then we need to set the callback bit
4017 * on the node, and to do that we must be holding an exclusive lock
4020 if (delegating_type(rbtdb
, rbtnode
, rdataset
->type
)) {
4021 delegating
= ISC_TRUE
;
4022 RWLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_write
);
4024 delegating
= ISC_FALSE
;
4026 LOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4028 result
= add(rbtdb
, rbtnode
, rbtversion
, newheader
, options
, ISC_FALSE
,
4029 addedrdataset
, now
);
4030 if (result
== ISC_R_SUCCESS
&& delegating
)
4031 rbtnode
->find_callback
= 1;
4033 UNLOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4036 RWUNLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_write
);
4042 subtractrdataset(dns_db_t
*db
, dns_dbnode_t
*node
, dns_dbversion_t
*version
,
4043 dns_rdataset_t
*rdataset
, unsigned int options
,
4044 dns_rdataset_t
*newrdataset
)
4046 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
4047 dns_rbtnode_t
*rbtnode
= (dns_rbtnode_t
*)node
;
4048 rbtdb_version_t
*rbtversion
= version
;
4049 rdatasetheader_t
*topheader
, *topheader_prev
, *header
, *newheader
;
4050 unsigned char *subresult
;
4051 isc_region_t region
;
4052 isc_result_t result
;
4053 rbtdb_changed_t
*changed
;
4055 REQUIRE(VALID_RBTDB(rbtdb
));
4057 result
= dns_rdataslab_fromrdataset(rdataset
, rbtdb
->common
.mctx
,
4059 sizeof (rdatasetheader_t
));
4060 if (result
!= ISC_R_SUCCESS
)
4062 newheader
= (rdatasetheader_t
*)region
.base
;
4063 newheader
->ttl
= rdataset
->ttl
;
4064 newheader
->type
= RBTDB_RDATATYPE_VALUE(rdataset
->type
,
4066 newheader
->attributes
= 0;
4067 newheader
->serial
= rbtversion
->serial
;
4068 newheader
->trust
= 0;
4070 LOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4072 changed
= add_changed(rbtdb
, rbtversion
, rbtnode
);
4073 if (changed
== NULL
) {
4074 free_rdataset(rbtdb
->common
.mctx
, newheader
);
4075 return (ISC_R_NOMEMORY
);
4078 topheader_prev
= NULL
;
4079 for (topheader
= rbtnode
->data
;
4081 topheader
= topheader
->next
) {
4082 if (topheader
->type
== newheader
->type
)
4084 topheader_prev
= topheader
;
4087 * If header isn't NULL, we've found the right type. There may be
4088 * IGNORE rdatasets between the top of the chain and the first real
4089 * data. We skip over them.
4092 while (header
!= NULL
&& IGNORE(header
))
4093 header
= header
->down
;
4094 if (header
!= NULL
&& EXISTS(header
)) {
4095 unsigned int flags
= 0;
4097 result
= ISC_R_SUCCESS
;
4098 if ((options
& DNS_DBSUB_EXACT
) != 0) {
4099 flags
|= DNS_RDATASLAB_EXACT
;
4100 if (newheader
->ttl
!= header
->ttl
)
4101 result
= DNS_R_NOTEXACT
;
4103 if (result
== ISC_R_SUCCESS
)
4104 result
= dns_rdataslab_subtract(
4105 (unsigned char *)header
,
4106 (unsigned char *)newheader
,
4107 (unsigned int)(sizeof *newheader
),
4109 rbtdb
->common
.rdclass
,
4110 (dns_rdatatype_t
)header
->type
,
4112 if (result
== ISC_R_SUCCESS
) {
4113 free_rdataset(rbtdb
->common
.mctx
, newheader
);
4114 newheader
= (rdatasetheader_t
*)subresult
;
4116 * We have to set the serial since the rdataslab
4117 * subtraction routine copies the reserved portion of
4118 * header, not newheader.
4120 newheader
->serial
= rbtversion
->serial
;
4121 } else if (result
== DNS_R_NXRRSET
) {
4123 * This subtraction would remove all of the rdata;
4124 * add a nonexistent header instead.
4126 free_rdataset(rbtdb
->common
.mctx
, newheader
);
4127 newheader
= isc_mem_get(rbtdb
->common
.mctx
,
4129 if (newheader
== NULL
) {
4130 result
= ISC_R_NOMEMORY
;
4134 newheader
->type
= topheader
->type
;
4135 newheader
->attributes
= RDATASET_ATTR_NONEXISTENT
;
4136 newheader
->trust
= 0;
4137 newheader
->serial
= rbtversion
->serial
;
4139 free_rdataset(rbtdb
->common
.mctx
, newheader
);
4144 * If we're here, we want to link newheader in front of
4147 INSIST(rbtversion
->serial
>= topheader
->serial
);
4148 if (topheader_prev
!= NULL
)
4149 topheader_prev
->next
= newheader
;
4151 rbtnode
->data
= newheader
;
4152 newheader
->next
= topheader
->next
;
4153 newheader
->down
= topheader
;
4154 topheader
->next
= newheader
;
4156 changed
->dirty
= ISC_TRUE
;
4159 * The rdataset doesn't exist, so we don't need to do anything
4160 * to satisfy the deletion request.
4162 free_rdataset(rbtdb
->common
.mctx
, newheader
);
4163 if ((options
& DNS_DBSUB_EXACT
) != 0)
4164 result
= DNS_R_NOTEXACT
;
4166 result
= DNS_R_UNCHANGED
;
4169 if (result
== ISC_R_SUCCESS
&& newrdataset
!= NULL
)
4170 bind_rdataset(rbtdb
, rbtnode
, newheader
, 0, newrdataset
);
4173 UNLOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4179 deleterdataset(dns_db_t
*db
, dns_dbnode_t
*node
, dns_dbversion_t
*version
,
4180 dns_rdatatype_t type
, dns_rdatatype_t covers
)
4182 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
4183 dns_rbtnode_t
*rbtnode
= (dns_rbtnode_t
*)node
;
4184 rbtdb_version_t
*rbtversion
= version
;
4185 isc_result_t result
;
4186 rdatasetheader_t
*newheader
;
4188 REQUIRE(VALID_RBTDB(rbtdb
));
4190 if (type
== dns_rdatatype_any
)
4191 return (ISC_R_NOTIMPLEMENTED
);
4192 if (type
== dns_rdatatype_sig
&& covers
== 0)
4193 return (ISC_R_NOTIMPLEMENTED
);
4195 newheader
= isc_mem_get(rbtdb
->common
.mctx
, sizeof *newheader
);
4196 if (newheader
== NULL
)
4197 return (ISC_R_NOMEMORY
);
4199 newheader
->type
= RBTDB_RDATATYPE_VALUE(type
, covers
);
4200 newheader
->attributes
= RDATASET_ATTR_NONEXISTENT
;
4201 newheader
->trust
= 0;
4202 if (rbtversion
!= NULL
)
4203 newheader
->serial
= rbtversion
->serial
;
4205 newheader
->serial
= 0;
4207 LOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4209 result
= add(rbtdb
, rbtnode
, rbtversion
, newheader
, DNS_DBADD_FORCE
,
4210 ISC_FALSE
, NULL
, 0);
4212 UNLOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4218 loading_addrdataset(void *arg
, dns_name_t
*name
, dns_rdataset_t
*rdataset
) {
4219 rbtdb_load_t
*loadctx
= arg
;
4220 dns_rbtdb_t
*rbtdb
= loadctx
->rbtdb
;
4221 dns_rbtnode_t
*node
;
4222 isc_result_t result
;
4223 isc_region_t region
;
4224 rdatasetheader_t
*newheader
;
4227 * This routine does no node locking. See comments in
4228 * 'load' below for more information on loading and
4234 * SOA records are only allowed at top of zone.
4236 if (rdataset
->type
== dns_rdatatype_soa
&&
4237 !IS_CACHE(rbtdb
) && !dns_name_equal(name
, &rbtdb
->common
.origin
))
4238 return (DNS_R_NOTZONETOP
);
4240 add_empty_wildcards(rbtdb
, name
);
4242 if (dns_name_iswildcard(name
)) {
4244 * NS record owners cannot legally be wild cards.
4246 if (rdataset
->type
== dns_rdatatype_ns
)
4247 return (DNS_R_INVALIDNS
);
4248 result
= add_wildcard_magic(rbtdb
, name
);
4249 if (result
!= ISC_R_SUCCESS
)
4254 result
= dns_rbt_addnode(rbtdb
->tree
, name
, &node
);
4255 if (result
!= ISC_R_SUCCESS
&& result
!= ISC_R_EXISTS
)
4257 if (result
!= ISC_R_EXISTS
) {
4258 dns_name_t foundname
;
4259 dns_name_init(&foundname
, NULL
);
4260 dns_rbt_namefromnode(node
, &foundname
);
4261 #ifdef DNS_RBT_USEHASH
4262 node
->locknum
= node
->hashval
% rbtdb
->node_lock_count
;
4264 node
->locknum
= dns_name_hash(&foundname
, ISC_TRUE
) %
4265 rbtdb
->node_lock_count
;
4269 result
= dns_rdataslab_fromrdataset(rdataset
, rbtdb
->common
.mctx
,
4271 sizeof (rdatasetheader_t
));
4272 if (result
!= ISC_R_SUCCESS
)
4274 newheader
= (rdatasetheader_t
*)region
.base
;
4275 newheader
->ttl
= rdataset
->ttl
+ loadctx
->now
; /* XXX overflow check */
4276 newheader
->type
= RBTDB_RDATATYPE_VALUE(rdataset
->type
,
4278 newheader
->attributes
= 0;
4279 newheader
->trust
= rdataset
->trust
;
4280 newheader
->serial
= 1;
4282 result
= add(rbtdb
, node
, rbtdb
->current_version
, newheader
,
4283 DNS_DBADD_MERGE
, ISC_TRUE
, NULL
, 0);
4284 if (result
== ISC_R_SUCCESS
&&
4285 delegating_type(rbtdb
, node
, rdataset
->type
))
4286 node
->find_callback
= 1;
4287 else if (result
== DNS_R_UNCHANGED
)
4288 result
= ISC_R_SUCCESS
;
4294 beginload(dns_db_t
*db
, dns_addrdatasetfunc_t
*addp
, dns_dbload_t
**dbloadp
) {
4295 rbtdb_load_t
*loadctx
;
4298 rbtdb
= (dns_rbtdb_t
*)db
;
4300 REQUIRE(VALID_RBTDB(rbtdb
));
4302 loadctx
= isc_mem_get(rbtdb
->common
.mctx
, sizeof *loadctx
);
4303 if (loadctx
== NULL
)
4304 return (ISC_R_NOMEMORY
);
4306 loadctx
->rbtdb
= rbtdb
;
4307 if (IS_CACHE(rbtdb
))
4308 isc_stdtime_get(&loadctx
->now
);
4314 REQUIRE((rbtdb
->attributes
& (RBTDB_ATTR_LOADED
|RBTDB_ATTR_LOADING
))
4316 rbtdb
->attributes
|= RBTDB_ATTR_LOADING
;
4318 UNLOCK(&rbtdb
->lock
);
4320 *addp
= loading_addrdataset
;
4323 return (ISC_R_SUCCESS
);
4326 static isc_boolean_t
4327 iszonesecure(dns_db_t
*db
, dns_dbnode_t
*origin
) {
4328 dns_rdataset_t keyset
;
4329 dns_rdataset_t nxtset
, signxtset
;
4330 isc_boolean_t haszonekey
= ISC_FALSE
;
4331 isc_boolean_t hasnxt
= ISC_FALSE
;
4332 isc_result_t result
;
4334 dns_rdataset_init(&keyset
);
4335 result
= dns_db_findrdataset(db
, origin
, NULL
, dns_rdatatype_key
, 0,
4337 if (result
== ISC_R_SUCCESS
) {
4338 dns_rdata_t keyrdata
= DNS_RDATA_INIT
;
4339 result
= dns_rdataset_first(&keyset
);
4340 while (result
== ISC_R_SUCCESS
) {
4341 dns_rdataset_current(&keyset
, &keyrdata
);
4342 if (dns_zonekey_iszonekey(&keyrdata
)) {
4343 haszonekey
= ISC_TRUE
;
4346 result
= dns_rdataset_next(&keyset
);
4348 dns_rdataset_disassociate(&keyset
);
4353 dns_rdataset_init(&nxtset
);
4354 dns_rdataset_init(&signxtset
);
4355 result
= dns_db_findrdataset(db
, origin
, NULL
, dns_rdatatype_nxt
, 0,
4356 0, &nxtset
, &signxtset
);
4357 if (result
== ISC_R_SUCCESS
) {
4358 if (dns_rdataset_isassociated(&signxtset
)) {
4360 dns_rdataset_disassociate(&signxtset
);
4362 dns_rdataset_disassociate(&nxtset
);
4369 endload(dns_db_t
*db
, dns_dbload_t
**dbloadp
) {
4370 rbtdb_load_t
*loadctx
;
4371 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)db
;
4373 REQUIRE(VALID_RBTDB(rbtdb
));
4374 REQUIRE(dbloadp
!= NULL
);
4376 REQUIRE(loadctx
->rbtdb
== rbtdb
);
4380 REQUIRE((rbtdb
->attributes
& RBTDB_ATTR_LOADING
) != 0);
4381 REQUIRE((rbtdb
->attributes
& RBTDB_ATTR_LOADED
) == 0);
4383 rbtdb
->attributes
&= ~RBTDB_ATTR_LOADING
;
4384 rbtdb
->attributes
|= RBTDB_ATTR_LOADED
;
4386 UNLOCK(&rbtdb
->lock
);
4389 * If there's a KEY rdataset at the zone origin containing a
4390 * zone key, we consider the zone secure.
4392 if (! IS_CACHE(rbtdb
))
4393 rbtdb
->secure
= iszonesecure(db
, rbtdb
->origin_node
);
4397 isc_mem_put(rbtdb
->common
.mctx
, loadctx
, sizeof *loadctx
);
4399 return (ISC_R_SUCCESS
);
4403 dump(dns_db_t
*db
, dns_dbversion_t
*version
, const char *filename
) {
4406 rbtdb
= (dns_rbtdb_t
*)db
;
4408 REQUIRE(VALID_RBTDB(rbtdb
));
4410 return (dns_master_dump(rbtdb
->common
.mctx
, db
, version
,
4411 &dns_master_style_default
,
4416 delete_callback(void *data
, void *arg
) {
4417 dns_rbtdb_t
*rbtdb
= arg
;
4418 rdatasetheader_t
*current
, *next
;
4420 for (current
= data
; current
!= NULL
; current
= next
) {
4421 next
= current
->next
;
4422 free_rdataset(rbtdb
->common
.mctx
, current
);
4426 static isc_boolean_t
4427 issecure(dns_db_t
*db
) {
4429 isc_boolean_t secure
;
4431 rbtdb
= (dns_rbtdb_t
*)db
;
4433 REQUIRE(VALID_RBTDB(rbtdb
));
4435 RWLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_read
);
4436 secure
= rbtdb
->secure
;
4437 RWUNLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_read
);
4443 nodecount(dns_db_t
*db
) {
4447 rbtdb
= (dns_rbtdb_t
*)db
;
4449 REQUIRE(VALID_RBTDB(rbtdb
));
4451 RWLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_read
);
4452 count
= dns_rbt_nodecount(rbtdb
->tree
);
4453 RWUNLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_read
);
4459 settask(dns_db_t
*db
, isc_task_t
*task
) {
4462 rbtdb
= (dns_rbtdb_t
*)db
;
4464 REQUIRE(VALID_RBTDB(rbtdb
));
4467 if (rbtdb
->task
!= NULL
)
4468 isc_task_detach(&rbtdb
->task
);
4470 isc_task_attach(task
, &rbtdb
->task
);
4471 UNLOCK(&rbtdb
->lock
);
4474 static isc_boolean_t
4475 ispersistent(dns_db_t
*db
) {
4480 static dns_dbmethods_t zone_methods
= {
4510 static dns_dbmethods_t cache_methods
= {
4541 #ifdef DNS_RBTDB_VERSION64
4546 (isc_mem_t
*mctx
, dns_name_t
*origin
, dns_dbtype_t type
,
4547 dns_rdataclass_t rdclass
, unsigned int argc
, char *argv
[],
4548 void *driverarg
, dns_db_t
**dbp
)
4551 isc_result_t result
;
4555 /* Keep the compiler happy. */
4560 rbtdb
= isc_mem_get(mctx
, sizeof *rbtdb
);
4562 return (ISC_R_NOMEMORY
);
4563 memset(rbtdb
, '\0', sizeof *rbtdb
);
4564 dns_name_init(&rbtdb
->common
.origin
, NULL
);
4565 rbtdb
->common
.attributes
= 0;
4566 if (type
== dns_dbtype_cache
) {
4567 rbtdb
->common
.methods
= &cache_methods
;
4568 rbtdb
->common
.attributes
|= DNS_DBATTR_CACHE
;
4569 } else if (type
== dns_dbtype_stub
) {
4570 rbtdb
->common
.methods
= &zone_methods
;
4571 rbtdb
->common
.attributes
|= DNS_DBATTR_STUB
;
4573 rbtdb
->common
.methods
= &zone_methods
;
4574 rbtdb
->common
.rdclass
= rdclass
;
4575 rbtdb
->common
.mctx
= NULL
;
4577 result
= isc_mutex_init(&rbtdb
->lock
);
4578 if (result
!= ISC_R_SUCCESS
) {
4579 isc_mem_put(mctx
, rbtdb
, sizeof *rbtdb
);
4580 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
4581 "isc_mutex_init() failed: %s",
4582 isc_result_totext(result
));
4583 return (ISC_R_UNEXPECTED
);
4586 result
= isc_rwlock_init(&rbtdb
->tree_lock
, 0, 0);
4587 if (result
!= ISC_R_SUCCESS
) {
4588 DESTROYLOCK(&rbtdb
->lock
);
4589 isc_mem_put(mctx
, rbtdb
, sizeof *rbtdb
);
4590 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
4591 "isc_rwlock_init() failed: %s",
4592 isc_result_totext(result
));
4593 return (ISC_R_UNEXPECTED
);
4596 INSIST(rbtdb
->node_lock_count
< (1 << DNS_RBT_LOCKLENGTH
));
4598 if (rbtdb
->node_lock_count
== 0)
4599 rbtdb
->node_lock_count
= DEFAULT_NODE_LOCK_COUNT
;
4600 rbtdb
->node_locks
= isc_mem_get(mctx
, rbtdb
->node_lock_count
*
4601 sizeof (rbtdb_nodelock_t
));
4602 rbtdb
->active
= rbtdb
->node_lock_count
;
4603 for (i
= 0; i
< (int)(rbtdb
->node_lock_count
); i
++) {
4604 result
= isc_mutex_init(&rbtdb
->node_locks
[i
].lock
);
4605 if (result
!= ISC_R_SUCCESS
) {
4608 DESTROYLOCK(&rbtdb
->node_locks
[i
].lock
);
4611 isc_mem_put(mctx
, rbtdb
->node_locks
,
4612 rbtdb
->node_lock_count
*
4613 sizeof (rbtdb_nodelock_t
));
4614 isc_rwlock_destroy(&rbtdb
->tree_lock
);
4615 DESTROYLOCK(&rbtdb
->lock
);
4616 isc_mem_put(mctx
, rbtdb
, sizeof *rbtdb
);
4617 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
4618 "isc_mutex_init() failed: %s",
4619 isc_result_totext(result
));
4620 return (ISC_R_UNEXPECTED
);
4622 rbtdb
->node_locks
[i
].references
= 0;
4623 rbtdb
->node_locks
[i
].exiting
= ISC_FALSE
;
4627 * Attach to the mctx. The database will persist so long as there
4628 * are references to it, and attaching to the mctx ensures that our
4629 * mctx won't disappear out from under us.
4631 isc_mem_attach(mctx
, &rbtdb
->common
.mctx
);
4634 * Make a copy of the origin name.
4636 result
= dns_name_dupwithoffsets(origin
, mctx
, &rbtdb
->common
.origin
);
4637 if (result
!= ISC_R_SUCCESS
) {
4638 free_rbtdb(rbtdb
, ISC_FALSE
, NULL
);
4643 * Make the Red-Black Tree.
4645 result
= dns_rbt_create(mctx
, delete_callback
, rbtdb
, &rbtdb
->tree
);
4646 if (result
!= ISC_R_SUCCESS
) {
4647 free_rbtdb(rbtdb
, ISC_FALSE
, NULL
);
4651 * In order to set the node callback bit correctly in zone databases,
4652 * we need to know if the node has the origin name of the zone.
4653 * In loading_addrdataset() we could simply compare the new name
4654 * to the origin name, but this is expensive. Also, we don't know the
4655 * node name in addrdataset(), so we need another way of knowing the
4658 * We now explicitly create a node for the zone's origin, and then
4659 * we simply remember the node's address. This is safe, because
4660 * the top-of-zone node can never be deleted, nor can its address
4663 if (! IS_CACHE(rbtdb
)) {
4664 rbtdb
->origin_node
= NULL
;
4665 result
= dns_rbt_addnode(rbtdb
->tree
, &rbtdb
->common
.origin
,
4666 &rbtdb
->origin_node
);
4667 if (result
!= ISC_R_SUCCESS
) {
4668 INSIST(result
!= ISC_R_EXISTS
);
4669 free_rbtdb(rbtdb
, ISC_FALSE
, NULL
);
4673 * We need to give the origin node the right locknum.
4675 dns_name_init(&name
, NULL
);
4676 dns_rbt_namefromnode(rbtdb
->origin_node
, &name
);
4677 #ifdef DNS_RBT_USEHASH
4678 rbtdb
->origin_node
->locknum
=
4679 rbtdb
->origin_node
->hashval
%
4680 rbtdb
->node_lock_count
;
4682 rbtdb
->origin_node
->locknum
=
4683 dns_name_hash(&name
, ISC_TRUE
) %
4684 rbtdb
->node_lock_count
;
4689 * Misc. Initialization.
4691 isc_refcount_init(&rbtdb
->references
, 1);
4692 rbtdb
->attributes
= 0;
4693 rbtdb
->secure
= ISC_FALSE
;
4694 rbtdb
->overmem
= ISC_FALSE
;
4698 * Version Initialization.
4700 rbtdb
->current_serial
= 1;
4701 rbtdb
->least_serial
= 1;
4702 rbtdb
->next_serial
= 2;
4703 rbtdb
->current_version
= allocate_version(mctx
, 1, 0, ISC_FALSE
);
4704 if (rbtdb
->current_version
== NULL
) {
4705 free_rbtdb(rbtdb
, ISC_FALSE
, NULL
);
4706 return (ISC_R_NOMEMORY
);
4708 rbtdb
->future_version
= NULL
;
4709 ISC_LIST_INIT(rbtdb
->open_versions
);
4711 isc_ondestroy_init(&rbtdb
->common
.ondest
);
4713 rbtdb
->common
.magic
= DNS_DB_MAGIC
;
4714 rbtdb
->common
.impmagic
= RBTDB_MAGIC
;
4716 *dbp
= (dns_db_t
*)rbtdb
;
4718 return (ISC_R_SUCCESS
);
4723 * Slabbed Rdataset Methods
4727 rdataset_disassociate(dns_rdataset_t
*rdataset
) {
4728 dns_db_t
*db
= rdataset
->private1
;
4729 dns_dbnode_t
*node
= rdataset
->private2
;
4731 detachnode(db
, &node
);
4735 rdataset_first(dns_rdataset_t
*rdataset
) {
4736 unsigned char *raw
= rdataset
->private3
;
4739 count
= raw
[0] * 256 + raw
[1];
4741 rdataset
->private5
= NULL
;
4742 return (ISC_R_NOMORE
);
4746 * The privateuint4 field is the number of rdata beyond the cursor
4747 * position, so we decrement the total count by one before storing
4751 rdataset
->privateuint4
= count
;
4752 rdataset
->private5
= raw
;
4754 return (ISC_R_SUCCESS
);
4758 rdataset_next(dns_rdataset_t
*rdataset
) {
4760 unsigned int length
;
4763 count
= rdataset
->privateuint4
;
4765 return (ISC_R_NOMORE
);
4767 rdataset
->privateuint4
= count
;
4768 raw
= rdataset
->private5
;
4769 length
= raw
[0] * 256 + raw
[1];
4771 rdataset
->private5
= raw
;
4773 return (ISC_R_SUCCESS
);
4777 rdataset_current(dns_rdataset_t
*rdataset
, dns_rdata_t
*rdata
) {
4778 unsigned char *raw
= rdataset
->private5
;
4781 REQUIRE(raw
!= NULL
);
4783 r
.length
= raw
[0] * 256 + raw
[1];
4786 dns_rdata_fromregion(rdata
, rdataset
->rdclass
, rdataset
->type
, &r
);
4790 rdataset_clone(dns_rdataset_t
*source
, dns_rdataset_t
*target
) {
4791 dns_db_t
*db
= source
->private1
;
4792 dns_dbnode_t
*node
= source
->private2
;
4793 dns_dbnode_t
*cloned_node
;
4795 attachnode(db
, node
, &cloned_node
);
4799 * Reset iterator state.
4801 target
->privateuint4
= 0;
4802 target
->private5
= NULL
;
4806 rdataset_count(dns_rdataset_t
*rdataset
) {
4807 unsigned char *raw
= rdataset
->private3
;
4810 count
= raw
[0] * 256 + raw
[1];
4817 * Rdataset Iterator Methods
4821 rdatasetiter_destroy(dns_rdatasetiter_t
**iteratorp
) {
4822 rbtdb_rdatasetiter_t
*rbtiterator
;
4824 rbtiterator
= (rbtdb_rdatasetiter_t
*)(*iteratorp
);
4826 if (rbtiterator
->common
.version
!= NULL
)
4827 closeversion(rbtiterator
->common
.db
,
4828 &rbtiterator
->common
.version
, ISC_FALSE
);
4829 detachnode(rbtiterator
->common
.db
, &rbtiterator
->common
.node
);
4830 isc_mem_put(rbtiterator
->common
.db
->mctx
, rbtiterator
,
4831 sizeof *rbtiterator
);
4837 rdatasetiter_first(dns_rdatasetiter_t
*iterator
) {
4838 rbtdb_rdatasetiter_t
*rbtiterator
= (rbtdb_rdatasetiter_t
*)iterator
;
4839 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)(rbtiterator
->common
.db
);
4840 dns_rbtnode_t
*rbtnode
= rbtiterator
->common
.node
;
4841 rbtdb_version_t
*rbtversion
= rbtiterator
->common
.version
;
4842 rdatasetheader_t
*header
, *top_next
;
4843 rbtdb_serial_t serial
;
4846 if (IS_CACHE(rbtdb
)) {
4848 now
= rbtiterator
->common
.now
;
4850 serial
= rbtversion
->serial
;
4854 LOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4856 for (header
= rbtnode
->data
; header
!= NULL
; header
= top_next
) {
4857 top_next
= header
->next
;
4859 if (header
->serial
<= serial
&& !IGNORE(header
)) {
4861 * Is this a "this rdataset doesn't exist"
4862 * record? Or is it too old in the cache?
4864 * Note: unlike everywhere else, we
4865 * check for now > header->ttl instead
4866 * of now >= header->ttl. This allows
4867 * ANY and SIG queries for 0 TTL
4868 * rdatasets to work.
4870 if (NONEXISTENT(header
) ||
4871 (now
!= 0 && now
> header
->ttl
))
4875 header
= header
->down
;
4876 } while (header
!= NULL
);
4881 UNLOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4883 rbtiterator
->current
= header
;
4886 return (ISC_R_NOMORE
);
4888 return (ISC_R_SUCCESS
);
4892 rdatasetiter_next(dns_rdatasetiter_t
*iterator
) {
4893 rbtdb_rdatasetiter_t
*rbtiterator
= (rbtdb_rdatasetiter_t
*)iterator
;
4894 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)(rbtiterator
->common
.db
);
4895 dns_rbtnode_t
*rbtnode
= rbtiterator
->common
.node
;
4896 rbtdb_version_t
*rbtversion
= rbtiterator
->common
.version
;
4897 rdatasetheader_t
*header
, *top_next
;
4898 rbtdb_serial_t serial
;
4900 rbtdb_rdatatype_t type
;
4902 header
= rbtiterator
->current
;
4904 return (ISC_R_NOMORE
);
4906 if (IS_CACHE(rbtdb
)) {
4908 now
= rbtiterator
->common
.now
;
4910 serial
= rbtversion
->serial
;
4914 LOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4916 type
= header
->type
;
4917 for (header
= header
->next
; header
!= NULL
; header
= top_next
) {
4918 top_next
= header
->next
;
4919 if (header
->type
!= type
) {
4921 if (header
->serial
<= serial
&&
4924 * Is this a "this rdataset doesn't
4927 * Note: unlike everywhere else, we
4928 * check for now > header->ttl instead
4929 * of now >= header->ttl. This allows
4930 * ANY and SIG queries for 0 TTL
4931 * rdatasets to work.
4933 if ((header
->attributes
&
4934 RDATASET_ATTR_NONEXISTENT
) != 0 ||
4935 (now
!= 0 && now
> header
->ttl
))
4939 header
= header
->down
;
4940 } while (header
!= NULL
);
4946 UNLOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4948 rbtiterator
->current
= header
;
4951 return (ISC_R_NOMORE
);
4953 return (ISC_R_SUCCESS
);
4957 rdatasetiter_current(dns_rdatasetiter_t
*iterator
, dns_rdataset_t
*rdataset
) {
4958 rbtdb_rdatasetiter_t
*rbtiterator
= (rbtdb_rdatasetiter_t
*)iterator
;
4959 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)(rbtiterator
->common
.db
);
4960 dns_rbtnode_t
*rbtnode
= rbtiterator
->common
.node
;
4961 rdatasetheader_t
*header
;
4963 header
= rbtiterator
->current
;
4964 REQUIRE(header
!= NULL
);
4966 LOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4968 bind_rdataset(rbtdb
, rbtnode
, header
, rbtiterator
->common
.now
,
4971 UNLOCK(&rbtdb
->node_locks
[rbtnode
->locknum
].lock
);
4976 * Database Iterator Methods
4980 reference_iter_node(rbtdb_dbiterator_t
*rbtdbiter
) {
4981 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)rbtdbiter
->common
.db
;
4982 dns_rbtnode_t
*node
= rbtdbiter
->node
;
4987 INSIST(rbtdbiter
->tree_locked
!= isc_rwlocktype_none
);
4988 LOCK(&rbtdb
->node_locks
[node
->locknum
].lock
);
4989 new_reference(rbtdb
, node
);
4990 UNLOCK(&rbtdb
->node_locks
[node
->locknum
].lock
);
4994 dereference_iter_node(rbtdb_dbiterator_t
*rbtdbiter
) {
4995 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)rbtdbiter
->common
.db
;
4996 dns_rbtnode_t
*node
= rbtdbiter
->node
;
5002 lock
= &rbtdb
->node_locks
[node
->locknum
].lock
;
5004 INSIST(rbtdbiter
->node
->references
> 0);
5005 if (--node
->references
== 0)
5006 no_references(rbtdb
, node
, 0, rbtdbiter
->tree_locked
);
5009 rbtdbiter
->node
= NULL
;
5013 flush_deletions(rbtdb_dbiterator_t
*rbtdbiter
) {
5014 dns_rbtnode_t
*node
;
5015 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)rbtdbiter
->common
.db
;
5016 isc_boolean_t was_read_locked
= ISC_FALSE
;
5020 if (rbtdbiter
->delete != 0) {
5022 * Note that "%d node of %d in tree" can report things like
5023 * "flush_deletions: 59 nodes of 41 in tree". This means
5024 * That some nodes appear on the deletions list more than
5025 * once. Only the last occurence will actually be deleted.
5027 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
5028 DNS_LOGMODULE_CACHE
, ISC_LOG_DEBUG(1),
5029 "flush_deletions: %d nodes of %d in tree",
5031 dns_rbt_nodecount(rbtdb
->tree
));
5033 if (rbtdbiter
->tree_locked
== isc_rwlocktype_read
) {
5034 RWUNLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_read
);
5035 was_read_locked
= ISC_TRUE
;
5037 RWLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_write
);
5038 rbtdbiter
->tree_locked
= isc_rwlocktype_write
;
5040 for (i
= 0; i
< rbtdbiter
->delete; i
++) {
5041 node
= rbtdbiter
->deletions
[i
];
5042 lock
= &rbtdb
->node_locks
[node
->locknum
].lock
;
5045 INSIST(node
->references
> 0);
5047 if (node
->references
== 0)
5048 no_references(rbtdb
, node
, 0,
5049 rbtdbiter
->tree_locked
);
5053 rbtdbiter
->delete = 0;
5055 RWUNLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_write
);
5056 if (was_read_locked
) {
5057 RWLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_read
);
5058 rbtdbiter
->tree_locked
= isc_rwlocktype_read
;
5061 rbtdbiter
->tree_locked
= isc_rwlocktype_none
;
5067 resume_iteration(rbtdb_dbiterator_t
*rbtdbiter
) {
5068 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)rbtdbiter
->common
.db
;
5070 REQUIRE(rbtdbiter
->paused
);
5071 REQUIRE(rbtdbiter
->tree_locked
== isc_rwlocktype_none
);
5073 RWLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_read
);
5074 rbtdbiter
->tree_locked
= isc_rwlocktype_read
;
5076 rbtdbiter
->paused
= ISC_FALSE
;
5080 dbiterator_destroy(dns_dbiterator_t
**iteratorp
) {
5081 rbtdb_dbiterator_t
*rbtdbiter
= (rbtdb_dbiterator_t
*)(*iteratorp
);
5082 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)rbtdbiter
->common
.db
;
5083 dns_db_t
*db
= NULL
;
5085 if (rbtdbiter
->tree_locked
== isc_rwlocktype_read
) {
5086 RWUNLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_read
);
5087 rbtdbiter
->tree_locked
= isc_rwlocktype_none
;
5089 INSIST(rbtdbiter
->tree_locked
== isc_rwlocktype_none
);
5091 dereference_iter_node(rbtdbiter
);
5093 flush_deletions(rbtdbiter
);
5095 dns_db_attach(rbtdbiter
->common
.db
, &db
);
5096 dns_db_detach(&rbtdbiter
->common
.db
);
5098 dns_rbtnodechain_reset(&rbtdbiter
->chain
);
5099 isc_mem_put(db
->mctx
, rbtdbiter
, sizeof(*rbtdbiter
));
5106 dbiterator_first(dns_dbiterator_t
*iterator
) {
5107 isc_result_t result
;
5108 rbtdb_dbiterator_t
*rbtdbiter
= (rbtdb_dbiterator_t
*)iterator
;
5109 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)iterator
->db
;
5110 dns_name_t
*name
, *origin
;
5112 if (rbtdbiter
->result
!= ISC_R_SUCCESS
&&
5113 rbtdbiter
->result
!= ISC_R_NOMORE
)
5114 return (rbtdbiter
->result
);
5116 if (rbtdbiter
->paused
)
5117 resume_iteration(rbtdbiter
);
5119 dereference_iter_node(rbtdbiter
);
5121 name
= dns_fixedname_name(&rbtdbiter
->name
);
5122 origin
= dns_fixedname_name(&rbtdbiter
->origin
);
5123 dns_rbtnodechain_reset(&rbtdbiter
->chain
);
5125 result
= dns_rbtnodechain_first(&rbtdbiter
->chain
, rbtdb
->tree
, name
,
5128 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_NEWORIGIN
) {
5129 result
= dns_rbtnodechain_current(&rbtdbiter
->chain
, NULL
,
5130 NULL
, &rbtdbiter
->node
);
5131 if (result
== ISC_R_SUCCESS
) {
5132 rbtdbiter
->new_origin
= ISC_TRUE
;
5133 reference_iter_node(rbtdbiter
);
5136 INSIST(result
== ISC_R_NOTFOUND
);
5137 result
= ISC_R_NOMORE
; /* The tree is empty. */
5140 rbtdbiter
->result
= result
;
5146 dbiterator_last(dns_dbiterator_t
*iterator
) {
5147 isc_result_t result
;
5148 rbtdb_dbiterator_t
*rbtdbiter
= (rbtdb_dbiterator_t
*)iterator
;
5149 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)iterator
->db
;
5150 dns_name_t
*name
, *origin
;
5152 if (rbtdbiter
->result
!= ISC_R_SUCCESS
&&
5153 rbtdbiter
->result
!= ISC_R_NOMORE
)
5154 return (rbtdbiter
->result
);
5156 if (rbtdbiter
->paused
)
5157 resume_iteration(rbtdbiter
);
5159 dereference_iter_node(rbtdbiter
);
5161 name
= dns_fixedname_name(&rbtdbiter
->name
);
5162 origin
= dns_fixedname_name(&rbtdbiter
->origin
);
5163 dns_rbtnodechain_reset(&rbtdbiter
->chain
);
5165 result
= dns_rbtnodechain_last(&rbtdbiter
->chain
, rbtdb
->tree
, name
,
5167 if (result
== ISC_R_SUCCESS
|| result
== DNS_R_NEWORIGIN
) {
5168 result
= dns_rbtnodechain_current(&rbtdbiter
->chain
, NULL
,
5169 NULL
, &rbtdbiter
->node
);
5170 if (result
== ISC_R_SUCCESS
) {
5171 rbtdbiter
->new_origin
= ISC_TRUE
;
5172 reference_iter_node(rbtdbiter
);
5175 INSIST(result
== ISC_R_NOTFOUND
);
5176 result
= ISC_R_NOMORE
; /* The tree is empty. */
5179 rbtdbiter
->result
= result
;
5185 dbiterator_seek(dns_dbiterator_t
*iterator
, dns_name_t
*name
) {
5186 isc_result_t result
;
5187 rbtdb_dbiterator_t
*rbtdbiter
= (rbtdb_dbiterator_t
*)iterator
;
5188 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)iterator
->db
;
5189 dns_name_t
*iname
, *origin
;
5191 if (rbtdbiter
->result
!= ISC_R_SUCCESS
&&
5192 rbtdbiter
->result
!= ISC_R_NOMORE
)
5193 return (rbtdbiter
->result
);
5195 if (rbtdbiter
->paused
)
5196 resume_iteration(rbtdbiter
);
5198 dereference_iter_node(rbtdbiter
);
5200 iname
= dns_fixedname_name(&rbtdbiter
->name
);
5201 origin
= dns_fixedname_name(&rbtdbiter
->origin
);
5202 dns_rbtnodechain_reset(&rbtdbiter
->chain
);
5204 result
= dns_rbt_findnode(rbtdb
->tree
, name
, NULL
, &rbtdbiter
->node
,
5205 &rbtdbiter
->chain
, DNS_RBTFIND_EMPTYDATA
,
5207 if (result
== ISC_R_SUCCESS
) {
5208 result
= dns_rbtnodechain_current(&rbtdbiter
->chain
, iname
,
5210 if (result
== ISC_R_SUCCESS
) {
5211 rbtdbiter
->new_origin
= ISC_TRUE
;
5212 reference_iter_node(rbtdbiter
);
5215 } else if (result
== DNS_R_PARTIALMATCH
)
5216 result
= ISC_R_NOTFOUND
;
5218 rbtdbiter
->result
= result
;
5224 dbiterator_prev(dns_dbiterator_t
*iterator
) {
5225 isc_result_t result
;
5226 rbtdb_dbiterator_t
*rbtdbiter
= (rbtdb_dbiterator_t
*)iterator
;
5227 dns_name_t
*name
, *origin
;
5229 REQUIRE(rbtdbiter
->node
!= NULL
);
5231 if (rbtdbiter
->result
!= ISC_R_SUCCESS
)
5232 return (rbtdbiter
->result
);
5234 if (rbtdbiter
->paused
)
5235 resume_iteration(rbtdbiter
);
5237 name
= dns_fixedname_name(&rbtdbiter
->name
);
5238 origin
= dns_fixedname_name(&rbtdbiter
->origin
);
5239 result
= dns_rbtnodechain_prev(&rbtdbiter
->chain
, name
, origin
);
5241 dereference_iter_node(rbtdbiter
);
5243 if (result
== DNS_R_NEWORIGIN
|| result
== ISC_R_SUCCESS
) {
5244 rbtdbiter
->new_origin
= ISC_TF(result
== DNS_R_NEWORIGIN
);
5245 result
= dns_rbtnodechain_current(&rbtdbiter
->chain
, NULL
,
5246 NULL
, &rbtdbiter
->node
);
5249 if (result
== ISC_R_SUCCESS
)
5250 reference_iter_node(rbtdbiter
);
5252 rbtdbiter
->result
= result
;
5258 dbiterator_next(dns_dbiterator_t
*iterator
) {
5259 isc_result_t result
;
5260 rbtdb_dbiterator_t
*rbtdbiter
= (rbtdb_dbiterator_t
*)iterator
;
5261 dns_name_t
*name
, *origin
;
5263 REQUIRE(rbtdbiter
->node
!= NULL
);
5265 if (rbtdbiter
->result
!= ISC_R_SUCCESS
)
5266 return (rbtdbiter
->result
);
5268 if (rbtdbiter
->paused
)
5269 resume_iteration(rbtdbiter
);
5271 name
= dns_fixedname_name(&rbtdbiter
->name
);
5272 origin
= dns_fixedname_name(&rbtdbiter
->origin
);
5273 result
= dns_rbtnodechain_next(&rbtdbiter
->chain
, name
, origin
);
5275 dereference_iter_node(rbtdbiter
);
5277 if (result
== DNS_R_NEWORIGIN
|| result
== ISC_R_SUCCESS
) {
5278 rbtdbiter
->new_origin
= ISC_TF(result
== DNS_R_NEWORIGIN
);
5279 result
= dns_rbtnodechain_current(&rbtdbiter
->chain
, NULL
,
5280 NULL
, &rbtdbiter
->node
);
5282 if (result
== ISC_R_SUCCESS
)
5283 reference_iter_node(rbtdbiter
);
5285 rbtdbiter
->result
= result
;
5291 dbiterator_current(dns_dbiterator_t
*iterator
, dns_dbnode_t
**nodep
,
5294 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)iterator
->db
;
5295 rbtdb_dbiterator_t
*rbtdbiter
= (rbtdb_dbiterator_t
*)iterator
;
5296 dns_rbtnode_t
*node
= rbtdbiter
->node
;
5297 isc_result_t result
;
5298 dns_name_t
*nodename
= dns_fixedname_name(&rbtdbiter
->name
);
5299 dns_name_t
*origin
= dns_fixedname_name(&rbtdbiter
->origin
);
5301 REQUIRE(rbtdbiter
->result
== ISC_R_SUCCESS
);
5302 REQUIRE(rbtdbiter
->node
!= NULL
);
5304 if (rbtdbiter
->paused
)
5305 resume_iteration(rbtdbiter
);
5308 if (rbtdbiter
->common
.relative_names
)
5310 result
= dns_name_concatenate(nodename
, origin
, name
, NULL
);
5311 if (result
!= ISC_R_SUCCESS
)
5313 if (rbtdbiter
->common
.relative_names
&& rbtdbiter
->new_origin
)
5314 result
= DNS_R_NEWORIGIN
;
5316 result
= ISC_R_SUCCESS
;
5318 LOCK(&rbtdb
->node_locks
[node
->locknum
].lock
);
5319 new_reference(rbtdb
, node
);
5320 UNLOCK(&rbtdb
->node_locks
[node
->locknum
].lock
);
5322 *nodep
= rbtdbiter
->node
;
5324 if (iterator
->cleaning
&& result
== ISC_R_SUCCESS
) {
5325 isc_result_t expire_result
;
5328 * If the deletion array is full, flush it before trying
5329 * to expire the current node. The current node can't
5330 * fully deleted while the iteration cursor is still on it.
5332 if (rbtdbiter
->delete == DELETION_BATCH_MAX
)
5333 flush_deletions(rbtdbiter
);
5335 expire_result
= expirenode(iterator
->db
, *nodep
, 0);
5338 * expirenode() currently always returns success.
5340 if (expire_result
== ISC_R_SUCCESS
&& node
->down
== NULL
) {
5341 rbtdbiter
->deletions
[rbtdbiter
->delete++] = node
;
5342 LOCK(&rbtdb
->node_locks
[node
->locknum
].lock
);
5344 UNLOCK(&rbtdb
->node_locks
[node
->locknum
].lock
);
5352 dbiterator_pause(dns_dbiterator_t
*iterator
) {
5353 dns_rbtdb_t
*rbtdb
= (dns_rbtdb_t
*)iterator
->db
;
5354 rbtdb_dbiterator_t
*rbtdbiter
= (rbtdb_dbiterator_t
*)iterator
;
5356 if (rbtdbiter
->result
!= ISC_R_SUCCESS
&&
5357 rbtdbiter
->result
!= ISC_R_NOMORE
)
5358 return (rbtdbiter
->result
);
5360 if (rbtdbiter
->paused
)
5361 return (ISC_R_SUCCESS
);
5363 rbtdbiter
->paused
= ISC_TRUE
;
5365 if (rbtdbiter
->tree_locked
!= isc_rwlocktype_none
) {
5366 INSIST(rbtdbiter
->tree_locked
== isc_rwlocktype_read
);
5367 RWUNLOCK(&rbtdb
->tree_lock
, isc_rwlocktype_read
);
5368 rbtdbiter
->tree_locked
= isc_rwlocktype_none
;
5371 flush_deletions(rbtdbiter
);
5373 return (ISC_R_SUCCESS
);
5377 dbiterator_origin(dns_dbiterator_t
*iterator
, dns_name_t
*name
) {
5378 rbtdb_dbiterator_t
*rbtdbiter
= (rbtdb_dbiterator_t
*)iterator
;
5379 dns_name_t
*origin
= dns_fixedname_name(&rbtdbiter
->origin
);
5381 if (rbtdbiter
->result
!= ISC_R_SUCCESS
)
5382 return (rbtdbiter
->result
);
5384 return (dns_name_copy(origin
, name
, NULL
));