summaryrefslogtreecommitdiff
path: root/contrib/bind9/lib/dns/rbtdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind9/lib/dns/rbtdb.c')
-rw-r--r--contrib/bind9/lib/dns/rbtdb.c381
1 files changed, 207 insertions, 174 deletions
diff --git a/contrib/bind9/lib/dns/rbtdb.c b/contrib/bind9/lib/dns/rbtdb.c
index 10525d921233c..1550221ab252c 100644
--- a/contrib/bind9/lib/dns/rbtdb.c
+++ b/contrib/bind9/lib/dns/rbtdb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2011 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rbtdb.c,v 1.310.8.5.4.1 2011-11-16 09:32:08 marka Exp $ */
+/* $Id$ */
/*! \file */
@@ -365,9 +365,12 @@ typedef enum {
dns_db_secure
} dns_db_secure_t;
+typedef struct dns_rbtdb dns_rbtdb_t;
+
typedef struct rbtdb_version {
/* Not locked */
rbtdb_serial_t serial;
+ dns_rbtdb_t * rbtdb;
/*
* Protected in the refcount routines.
* XXXJT: should we change the lock policy based on the refcount
@@ -392,7 +395,7 @@ typedef struct rbtdb_version {
typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t;
-typedef struct {
+struct dns_rbtdb {
/* Unlocked. */
dns_db_t common;
/* Locks the data in this struct */
@@ -452,7 +455,7 @@ typedef struct {
/* Unlocked */
unsigned int quantum;
-} dns_rbtdb_t;
+};
#define RBTDB_ATTR_LOADED 0x01
#define RBTDB_ATTR_LOADING 0x02
@@ -1105,6 +1108,7 @@ newversion(dns_db_t *db, dns_dbversion_t **versionp) {
version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1,
ISC_TRUE);
if (version != NULL) {
+ version->rbtdb = rbtdb;
version->commit_ok = ISC_TRUE;
version->secure = rbtdb->current_version->secure;
version->havensec3 = rbtdb->current_version->havensec3;
@@ -1146,6 +1150,7 @@ attachversion(dns_db_t *db, dns_dbversion_t *source,
unsigned int refs;
REQUIRE(VALID_RBTDB(rbtdb));
+ INSIST(rbtversion != NULL && rbtversion->rbtdb == rbtdb);
isc_refcount_increment(&rbtversion->references, &refs);
INSIST(refs > 1);
@@ -1603,14 +1608,14 @@ cleanup_dead_nodes(dns_rbtdb_t *rbtdb, int bucketnum) {
}
/*
- * Caller must be holding the node lock if its reference must be protected
- * by the lock.
+ * Caller must be holding the node lock.
*/
static inline void
new_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node) {
unsigned int lockrefs, noderefs;
isc_refcount_t *lockref;
+ INSIST(!ISC_LINK_LINKED(node, deadlink));
dns_rbtnode_refincrement0(node, &noderefs);
if (noderefs == 1) { /* this is the first reference to the node */
lockref = &rbtdb->node_locks[node->locknum].references;
@@ -1634,33 +1639,43 @@ static inline void
reactivate_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
isc_rwlocktype_t treelocktype)
{
- isc_boolean_t need_relock = ISC_FALSE;
+ isc_rwlocktype_t locktype = isc_rwlocktype_read;
+ nodelock_t *nodelock = &rbtdb->node_locks[node->locknum].lock;
+ isc_boolean_t maybe_cleanup = ISC_FALSE;
- NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
- new_reference(rbtdb, node);
+ POST(locktype);
+
+ NODE_STRONGLOCK(nodelock);
+ NODE_WEAKLOCK(nodelock, locktype);
+
+ /*
+ * Check if we can possibly cleanup the dead node. If so, upgrade
+ * the node lock below to perform the cleanup.
+ */
+ if (!ISC_LIST_EMPTY(rbtdb->deadnodes[node->locknum]) &&
+ treelocktype == isc_rwlocktype_write) {
+ maybe_cleanup = ISC_TRUE;
+ }
- NODE_WEAKLOCK(&rbtdb->node_locks[node->locknum].lock,
- isc_rwlocktype_read);
- if (ISC_LINK_LINKED(node, deadlink))
- need_relock = ISC_TRUE;
- else if (!ISC_LIST_EMPTY(rbtdb->deadnodes[node->locknum]) &&
- treelocktype == isc_rwlocktype_write)
- need_relock = ISC_TRUE;
- NODE_WEAKUNLOCK(&rbtdb->node_locks[node->locknum].lock,
- isc_rwlocktype_read);
- if (need_relock) {
- NODE_WEAKLOCK(&rbtdb->node_locks[node->locknum].lock,
- isc_rwlocktype_write);
+ if (ISC_LINK_LINKED(node, deadlink) || maybe_cleanup) {
+ /*
+ * Upgrade the lock and test if we still need to unlink.
+ */
+ NODE_WEAKUNLOCK(nodelock, locktype);
+ locktype = isc_rwlocktype_write;
+ POST(locktype);
+ NODE_WEAKLOCK(nodelock, locktype);
if (ISC_LINK_LINKED(node, deadlink))
ISC_LIST_UNLINK(rbtdb->deadnodes[node->locknum],
node, deadlink);
- if (treelocktype == isc_rwlocktype_write)
+ if (maybe_cleanup)
cleanup_dead_nodes(rbtdb, node->locknum);
- NODE_WEAKUNLOCK(&rbtdb->node_locks[node->locknum].lock,
- isc_rwlocktype_write);
}
- NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
+ new_reference(rbtdb, node);
+
+ NODE_WEAKUNLOCK(nodelock, locktype);
+ NODE_STRONGUNLOCK(nodelock);
}
/*
@@ -1684,7 +1699,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
rbtdb_nodelock_t *nodelock;
unsigned int refs, nrefs;
int bucket = node->locknum;
- isc_boolean_t no_reference;
+ isc_boolean_t no_reference = ISC_TRUE;
nodelock = &rbtdb->node_locks[bucket];
@@ -1704,6 +1719,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
NODE_WEAKUNLOCK(&nodelock->lock, isc_rwlocktype_read);
NODE_WEAKLOCK(&nodelock->lock, isc_rwlocktype_write);
}
+
dns_rbtnode_refdecrement(node, &nrefs);
INSIST((int)nrefs >= 0);
if (nrefs > 0) {
@@ -1713,7 +1729,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
return (ISC_FALSE);
}
- if (node->dirty && dns_rbtnode_refcurrent(node) == 0) {
+ if (node->dirty) {
if (IS_CACHE(rbtdb))
clean_cache_node(rbtdb, node);
else {
@@ -1731,19 +1747,6 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
}
}
- isc_refcount_decrement(&nodelock->references, &refs);
- INSIST((int)refs >= 0);
-
- /*
- * XXXDCL should this only be done for cache zones?
- */
- if (node->data != NULL || node->down != NULL) {
- /* Restore the lock? */
- if (nlock == isc_rwlocktype_read)
- NODE_WEAKDOWNGRADE(&nodelock->lock);
- return (ISC_TRUE);
- }
-
/*
* Attempt to switch to a write lock on the tree. If this fails,
* we will add this node to a linked list of nodes in this locking
@@ -1767,13 +1770,18 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
} else
write_locked = ISC_TRUE;
- no_reference = ISC_TRUE;
- if (write_locked && dns_rbtnode_refcurrent(node) == 0) {
+ isc_refcount_decrement(&nodelock->references, &refs);
+ INSIST((int)refs >= 0);
+
+ /*
+ * XXXDCL should this only be done for cache zones?
+ */
+ if (node->data != NULL || node->down != NULL)
+ goto restore_locks;
+
+ if (write_locked) {
/*
- * We can now delete the node if the reference counter is
- * zero. This should be typically the case, but a different
- * thread may still gain a (new) reference just before the
- * current thread locks the tree (e.g., in findnode()).
+ * We can now delete the node.
*/
/*
@@ -1825,6 +1833,7 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
ISC_LOG_INFO,
"decrement_reference: failed to "
"allocate pruning event");
+ INSIST(node->data == NULL);
INSIST(!ISC_LINK_LINKED(node, deadlink));
ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node,
deadlink);
@@ -1847,12 +1856,13 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
delete_node(rbtdb, node);
}
- } else if (dns_rbtnode_refcurrent(node) == 0) {
+ } else {
+ INSIST(node->data == NULL);
INSIST(!ISC_LINK_LINKED(node, deadlink));
ISC_LIST_APPEND(rbtdb->deadnodes[bucket], node, deadlink);
- } else
- no_reference = ISC_FALSE;
+ }
+ restore_locks:
/* Restore the lock? */
if (nlock == isc_rwlocktype_read)
NODE_WEAKDOWNGRADE(&nodelock->lock);
@@ -1919,11 +1929,10 @@ prune_tree(isc_task_t *task, isc_event_t *event) {
* from the list beforehand as we do in
* reactivate_node().
*/
- new_reference(rbtdb, parent);
- if (ISC_LINK_LINKED(parent, deadlink)) {
+ if (ISC_LINK_LINKED(parent, deadlink))
ISC_LIST_UNLINK(rbtdb->deadnodes[locknum],
parent, deadlink);
- }
+ new_reference(rbtdb, parent);
} else
parent = NULL;
@@ -1998,9 +2007,9 @@ iszonesecure(dns_db_t *db, rbtdb_version_t *version, dns_dbnode_t *origin) {
result = dns_db_findrdataset(db, origin, version, dns_rdatatype_dnskey,
0, 0, &keyset, NULL);
if (result == ISC_R_SUCCESS) {
- dns_rdata_t keyrdata = DNS_RDATA_INIT;
result = dns_rdataset_first(&keyset);
while (result == ISC_R_SUCCESS) {
+ dns_rdata_t keyrdata = DNS_RDATA_INIT;
dns_rdataset_current(&keyset, &keyrdata);
if (dns_zonekey_iszonekey(&keyrdata)) {
haszonekey = ISC_TRUE;
@@ -2182,6 +2191,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
REQUIRE(VALID_RBTDB(rbtdb));
version = (rbtdb_version_t *)*versionp;
+ INSIST(version->rbtdb == rbtdb);
cleanup_version = NULL;
ISC_LIST_INIT(cleanup_list);
@@ -2494,20 +2504,19 @@ add_empty_wildcards(dns_rbtdb_t *rbtdb, dns_name_t *name) {
}
static isc_result_t
-findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
- dns_dbnode_t **nodep)
+findnodeintree(dns_rbtdb_t *rbtdb, dns_rbt_t *tree, dns_name_t *name,
+ isc_boolean_t create, dns_dbnode_t **nodep)
{
- dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
dns_rbtnode_t *node = NULL;
dns_name_t nodename;
isc_result_t result;
isc_rwlocktype_t locktype = isc_rwlocktype_read;
- REQUIRE(VALID_RBTDB(rbtdb));
+ INSIST(tree == rbtdb->tree || tree == rbtdb->nsec3);
dns_name_init(&nodename, NULL);
RWLOCK(&rbtdb->tree_lock, locktype);
- result = dns_rbt_findnode(rbtdb->tree, name, NULL, &node, NULL,
+ result = dns_rbt_findnode(tree, name, NULL, &node, NULL,
DNS_RBTFIND_EMPTYDATA, NULL, NULL);
if (result != ISC_R_SUCCESS) {
RWUNLOCK(&rbtdb->tree_lock, locktype);
@@ -2523,10 +2532,10 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
locktype = isc_rwlocktype_write;
RWLOCK(&rbtdb->tree_lock, locktype);
node = NULL;
- result = dns_rbt_addnode(rbtdb->tree, name, &node);
+ result = dns_rbt_addnode(tree, name, &node);
if (result == ISC_R_SUCCESS) {
#ifdef BIND9
- if (rbtdb->rpz_cidr != NULL) {
+ if (tree == rbtdb->tree && rbtdb->rpz_cidr != NULL) {
dns_fixedname_t fnamef;
dns_name_t *fname;
@@ -2543,20 +2552,28 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
rbtdb->node_lock_count;
#endif
- add_empty_wildcards(rbtdb, name);
-
- if (dns_name_iswildcard(name)) {
- result = add_wildcard_magic(rbtdb, name);
- if (result != ISC_R_SUCCESS) {
- RWUNLOCK(&rbtdb->tree_lock, locktype);
- return (result);
+ if (tree == rbtdb->tree) {
+ add_empty_wildcards(rbtdb, name);
+
+ if (dns_name_iswildcard(name)) {
+ result = add_wildcard_magic(rbtdb, name);
+ if (result != ISC_R_SUCCESS) {
+ RWUNLOCK(&rbtdb->tree_lock, locktype);
+ return (result);
+ }
}
}
+ if (tree == rbtdb->nsec3)
+ node->nsec = DNS_RBT_NSEC_NSEC3;
} else if (result != ISC_R_EXISTS) {
RWUNLOCK(&rbtdb->tree_lock, locktype);
return (result);
}
}
+
+ if (tree == rbtdb->nsec3)
+ INSIST(node->nsec == DNS_RBT_NSEC_NSEC3);
+
reactivate_node(rbtdb, node, locktype);
RWUNLOCK(&rbtdb->tree_lock, locktype);
@@ -2566,60 +2583,25 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
}
static isc_result_t
-findnsec3node(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
- dns_dbnode_t **nodep)
+findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
+ dns_dbnode_t **nodep)
{
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
- dns_rbtnode_t *node = NULL;
- dns_name_t nodename;
- isc_result_t result;
- isc_rwlocktype_t locktype = isc_rwlocktype_read;
REQUIRE(VALID_RBTDB(rbtdb));
- dns_name_init(&nodename, NULL);
- RWLOCK(&rbtdb->tree_lock, locktype);
- result = dns_rbt_findnode(rbtdb->nsec3, name, NULL, &node, NULL,
- DNS_RBTFIND_EMPTYDATA, NULL, NULL);
- if (result != ISC_R_SUCCESS) {
- RWUNLOCK(&rbtdb->tree_lock, locktype);
- if (!create) {
- if (result == DNS_R_PARTIALMATCH)
- result = ISC_R_NOTFOUND;
- return (result);
- }
- /*
- * It would be nice to try to upgrade the lock instead of
- * unlocking then relocking.
- */
- locktype = isc_rwlocktype_write;
- RWLOCK(&rbtdb->tree_lock, locktype);
- node = NULL;
- result = dns_rbt_addnode(rbtdb->nsec3, name, &node);
- if (result == ISC_R_SUCCESS) {
- dns_rbt_namefromnode(node, &nodename);
-#ifdef DNS_RBT_USEHASH
- node->locknum = node->hashval % rbtdb->node_lock_count;
-#else
- node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
- rbtdb->node_lock_count;
-#endif
- node->nsec = DNS_RBT_NSEC_NSEC3;
- } else if (result != ISC_R_EXISTS) {
- RWUNLOCK(&rbtdb->tree_lock, locktype);
- return (result);
- }
- } else {
- INSIST(node->nsec == DNS_RBT_NSEC_NSEC3);
- }
- NODE_STRONGLOCK(&rbtdb->node_locks[node->locknum].lock);
- new_reference(rbtdb, node);
- NODE_STRONGUNLOCK(&rbtdb->node_locks[node->locknum].lock);
- RWUNLOCK(&rbtdb->tree_lock, locktype);
+ return (findnodeintree(rbtdb, rbtdb->tree, name, create, nodep));
+}
- *nodep = (dns_dbnode_t *)node;
+static isc_result_t
+findnsec3node(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
+ dns_dbnode_t **nodep)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
- return (ISC_R_SUCCESS);
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ return (findnodeintree(rbtdb, rbtdb->nsec3, name, create, nodep));
}
static isc_result_t
@@ -3649,6 +3631,8 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
search.rbtdb = (dns_rbtdb_t *)db;
REQUIRE(VALID_RBTDB(search.rbtdb));
+ INSIST(version == NULL ||
+ ((rbtdb_version_t *)version)->rbtdb == (dns_rbtdb_t *)db);
/*
* We don't care about 'now'.
@@ -4580,15 +4564,19 @@ get_rpz_enabled(dns_db_t *db, dns_rpz_st_t *st)
* Search the CDIR block tree of a response policy tree of trees for all of
* the IP addresses in an A or AAAA rdataset.
* Among the policies for all IPv4 and IPv6 addresses for a name, choose
- * the longest prefix. Among those with the longest prefix, the first
- * configured policy. Among answers for with the longest prefixes for
- * two or more IP addresses in the A and AAAA rdatasets the lexically
- * smallest address.
+ * the earliest configured policy,
+ * QNAME over IP over NSDNAME over NSIP,
+ * the longest prefix,
+ * the lexically smallest address.
+ * The caller must have already checked that any existing policy was not
+ * configured earlier than this policy zone and does not have a higher
+ * precedence type.
*/
static isc_result_t
rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
- dns_rdataset_t *ardataset, dns_rpz_st_t *st)
+ dns_rdataset_t *ardataset, dns_rpz_st_t *st,
+ dns_name_t *query_qname)
{
dns_rbtdb_t *rbtdb;
struct in_addr ina;
@@ -4609,8 +4597,6 @@ rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
if (rbtdb->rpz_cidr == NULL) {
RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
- dns_db_detach(&db);
- dns_zone_detach(&zone);
return (ISC_R_UNEXPECTED);
}
@@ -4645,17 +4631,19 @@ rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
continue;
/*
- * Choose the policy with the longest matching prefix.
- * Between policies with the same prefix, choose the first
- * configured.
+ * If we already have a rule, discard this new rule if
+ * is not better.
+ * The caller has checked that st->m.rpz->num > rpz->num
+ * or st->m.rpz->num == rpz->num and st->m.type >= rpz_type
*/
- if (st->m.policy != DNS_RPZ_POLICY_MISS) {
- if (prefix < st->m.prefix)
- continue;
- if (prefix == st->m.prefix &&
- rpz->num > st->m.rpz->num)
- continue;
- }
+ if (st->m.policy != DNS_RPZ_POLICY_MISS &&
+ st->m.rpz->num == rpz->num &&
+ (st->m.type < rpz_type ||
+ (st->m.type == rpz_type &&
+ (st->m.prefix > prefix ||
+ (st->m.prefix == prefix &&
+ 0 > dns_name_rdatacompare(st->qname, qname))))))
+ continue;
/*
* We have rpz_st an entry with a prefix at least as long as
@@ -4669,8 +4657,8 @@ rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
char namebuf[DNS_NAME_FORMATSIZE];
dns_name_format(qname, namebuf, sizeof(namebuf));
- isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
- DNS_LOGMODULE_CACHE, DNS_RPZ_ERROR_LEVEL,
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RPZ,
+ DNS_LOGMODULE_RBTDB, DNS_RPZ_ERROR_LEVEL,
"rpz_findips findnode(%s): %s",
namebuf, isc_result_totext(result));
continue;
@@ -4694,7 +4682,8 @@ rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
} else {
rpz_policy = dns_rpz_decode_cname(&zrdataset,
selfname);
- if (rpz_policy == DNS_RPZ_POLICY_RECORD)
+ if (rpz_policy == DNS_RPZ_POLICY_RECORD ||
+ rpz_policy == DNS_RPZ_POLICY_WILDCNAME)
result = DNS_R_CNAME;
}
ttl = zrdataset.ttl;
@@ -4707,44 +4696,60 @@ rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
/*
* Use an overriding action specified in the configuration file
*/
- if (rpz->policy != DNS_RPZ_POLICY_GIVEN &&
- rpz_policy != DNS_RPZ_POLICY_NO_OP)
+ if (rpz->policy != DNS_RPZ_POLICY_GIVEN) {
+ /*
+ * only log DNS_RPZ_POLICY_DISABLED hits
+ */
+ if (rpz->policy == DNS_RPZ_POLICY_DISABLED) {
+ if (isc_log_wouldlog(dns_lctx,
+ DNS_RPZ_INFO_LEVEL)) {
+ char qname_buf[DNS_NAME_FORMATSIZE];
+ char rpz_qname_buf[DNS_NAME_FORMATSIZE];
+ dns_name_format(query_qname, qname_buf,
+ sizeof(qname_buf));
+ dns_name_format(qname, rpz_qname_buf,
+ sizeof(rpz_qname_buf));
+
+ isc_log_write(dns_lctx,
+ DNS_LOGCATEGORY_RPZ,
+ DNS_LOGMODULE_RBTDB,
+ DNS_RPZ_INFO_LEVEL,
+ "disabled rpz %s %s rewrite"
+ " %s via %s",
+ dns_rpz_type2str(rpz_type),
+ dns_rpz_policy2str(rpz_policy),
+ qname_buf, rpz_qname_buf);
+ }
+ continue;
+ }
+
rpz_policy = rpz->policy;
+ }
- /*
- * We know the new prefix is at least as long as the current.
- * Prefer the new answer if the new prefix is longer.
- * Prefer the zone configured first if the prefixes are equal.
- * With two actions from the same zone, prefer the action
- * on the "smallest" name.
- */
- if (st->m.policy == DNS_RPZ_POLICY_MISS ||
- prefix > st->m.prefix ||
- rpz->num <= st->m.rpz->num ||
- 0 > dns_name_compare(qname, st->qname)) {
- if (dns_rdataset_isassociated(st->m.rdataset))
- dns_rdataset_disassociate(st->m.rdataset);
- if (st->m.node != NULL)
- dns_db_detachnode(st->m.db, &st->m.node);
- if (st->m.db != NULL)
- dns_db_detach(&st->m.db);
- if (st->m.zone != NULL)
- dns_zone_detach(&st->m.zone);
- st->m.rpz = rpz;
- st->m.type = rpz_type;
- st->m.prefix = prefix;
- st->m.policy = rpz_policy;
- st->m.ttl = ttl;
- st->m.result = result;
- dns_name_copy(qname, st->qname, NULL);
- if (rpz_policy == DNS_RPZ_POLICY_RECORD &&
- result != DNS_R_NXRRSET) {
- dns_rdataset_clone(&zrdataset,st->m.rdataset);
- dns_db_attachnode(db, node, &st->m.node);
- }
- dns_db_attach(db, &st->m.db);
- dns_zone_attach(zone, &st->m.zone);
+ if (dns_rdataset_isassociated(st->m.rdataset))
+ dns_rdataset_disassociate(st->m.rdataset);
+ if (st->m.node != NULL)
+ dns_db_detachnode(st->m.db, &st->m.node);
+ if (st->m.db != NULL)
+ dns_db_detach(&st->m.db);
+ if (st->m.zone != NULL)
+ dns_zone_detach(&st->m.zone);
+ st->m.rpz = rpz;
+ st->m.type = rpz_type;
+ st->m.prefix = prefix;
+ st->m.policy = rpz_policy;
+ st->m.ttl = ttl;
+ st->m.result = result;
+ dns_name_copy(qname, st->qname, NULL);
+ if ((rpz_policy == DNS_RPZ_POLICY_RECORD ||
+ rpz_policy == DNS_RPZ_POLICY_WILDCNAME) &&
+ result != DNS_R_NXRRSET) {
+ dns_rdataset_clone(&zrdataset,st->m.rdataset);
+ dns_db_attachnode(db, node, &st->m.node);
}
+ dns_db_attach(db, &st->m.db);
+ st->m.version = version;
+ dns_zone_attach(zone, &st->m.zone);
if (dns_rdataset_isassociated(&zrdataset))
dns_rdataset_disassociate(&zrdataset);
}
@@ -5544,6 +5549,7 @@ zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
REQUIRE(VALID_RBTDB(rbtdb));
REQUIRE(type != dns_rdatatype_any);
+ INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
if (rbtversion == NULL) {
currentversion(db, (dns_dbversion_t **) (void *)(&rbtversion));
@@ -5732,6 +5738,8 @@ allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
else {
unsigned int refs;
+ INSIST(rbtversion->rbtdb == rbtdb);
+
isc_refcount_increment(&rbtversion->references,
&refs);
INSIST(refs > 1);
@@ -6122,6 +6130,19 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
addedrdataset);
return (ISC_R_SUCCESS);
}
+ /*
+ * If we have will be replacing a NS RRset force its TTL
+ * to be no more than the current NS RRset's TTL. This
+ * ensures the delegations that are withdrawn are honoured.
+ */
+ if (IS_CACHE(rbtdb) && header->rdh_ttl > now &&
+ header->type == dns_rdatatype_ns &&
+ !header_nx && !newheader_nx &&
+ header->trust <= newheader->trust) {
+ if (newheader->rdh_ttl > header->rdh_ttl) {
+ newheader->rdh_ttl = header->rdh_ttl;
+ }
+ }
if (IS_CACHE(rbtdb) && header->rdh_ttl > now &&
(header->type == dns_rdatatype_a ||
header->type == dns_rdatatype_aaaa) &&
@@ -6401,6 +6422,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
isc_boolean_t cache_is_overmem = ISC_FALSE;
REQUIRE(VALID_RBTDB(rbtdb));
+ INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
if (rbtdb->common.methods == &zone_methods)
REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 &&
@@ -6417,8 +6439,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
now = 0;
result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
- &region,
- sizeof(rdatasetheader_t));
+ &region, sizeof(rdatasetheader_t));
if (result != ISC_R_SUCCESS)
return (result);
@@ -6591,6 +6612,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
rbtdb_changed_t *changed;
REQUIRE(VALID_RBTDB(rbtdb));
+ REQUIRE(rbtversion != NULL && rbtversion->rbtdb == rbtdb);
if (rbtdb->common.methods == &zone_methods)
REQUIRE(((rbtnode->nsec == DNS_RBT_NSEC_NSEC3 &&
@@ -6771,6 +6793,7 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
rdatasetheader_t *newheader;
REQUIRE(VALID_RBTDB(rbtdb));
+ INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
if (type == dns_rdatatype_any)
return (ISC_R_NOTIMPLEMENTED);
@@ -7064,10 +7087,12 @@ static isc_result_t
dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
dns_masterformat_t masterformat) {
dns_rbtdb_t *rbtdb;
+ rbtdb_version_t *rbtversion = version;
rbtdb = (dns_rbtdb_t *)db;
REQUIRE(VALID_RBTDB(rbtdb));
+ INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
#ifdef BIND9
return (dns_master_dump2(rbtdb->common.mctx, db, version,
@@ -7206,6 +7231,7 @@ getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash,
rbtdb = (dns_rbtdb_t *)db;
REQUIRE(VALID_RBTDB(rbtdb));
+ INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
@@ -7335,11 +7361,16 @@ resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version)
REQUIRE(VALID_RBTDB(rbtdb));
REQUIRE(rdataset != NULL);
+ REQUIRE(rdataset->methods == &rdataset_methods);
REQUIRE(rbtdb->future_version == rbtversion);
+ REQUIRE(rbtversion != NULL);
REQUIRE(rbtversion->writer);
+ REQUIRE(rbtversion->rbtdb == rbtdb);
node = rdataset->private2;
+ INSIST(node != NULL);
header = rdataset->private3;
+ INSIST(header != NULL);
header--;
RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
@@ -7750,6 +7781,7 @@ dns_rbtdb_create
free_rbtdb(rbtdb, ISC_FALSE, NULL);
return (ISC_R_NOMEMORY);
}
+ rbtdb->current_version->rbtdb = rbtdb;
rbtdb->current_version->secure = dns_db_insecure;
rbtdb->current_version->havensec3 = ISC_FALSE;
rbtdb->current_version->flags = 0;
@@ -8480,7 +8512,7 @@ dbiterator_last(dns_dbiterator_t *iterator) {
static isc_result_t
dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
- isc_result_t result;
+ isc_result_t result, tresult;
rbtdb_dbiterator_t *rbtdbiter = (rbtdb_dbiterator_t *)iterator;
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)iterator->db;
dns_name_t *iname, *origin;
@@ -8523,13 +8555,14 @@ dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
DNS_RBTFIND_EMPTYDATA, NULL, NULL);
if (result == DNS_R_PARTIALMATCH) {
dns_rbtnode_t *node = NULL;
- result = dns_rbt_findnode(rbtdb->nsec3, name, NULL,
+ tresult = dns_rbt_findnode(rbtdb->nsec3, name, NULL,
&node, &rbtdbiter->nsec3chain,
DNS_RBTFIND_EMPTYDATA,
NULL, NULL);
- if (result == ISC_R_SUCCESS) {
+ if (tresult == ISC_R_SUCCESS) {
rbtdbiter->node = node;
rbtdbiter->current = &rbtdbiter->nsec3chain;
+ result = tresult;
}
}
}