#define KEEPSTALE(rbtdb) ((rbtdb)->common.serve_stale_ttl > 0)
+#define RBTDBITER_NSEC3_ORIGIN_NODE(rbtdb, iterator) \
+ ((iterator)->current == &(iterator)->nsec3chain && \
+ (iterator)->node == (rbtdb)->nsec3_origin_node)
+
/*%
* Number of buckets for cache DB entries (locks, LRU lists, TTL heaps).
* There is a tradeoff issue about configuring this value: if this is too
dns_rbtnodechain_t nsec3chain;
dns_rbtnodechain_t *current;
dns_rbtnode_t *node;
- bool nsec3only;
- bool nonsec3;
+ enum { full, nonsec3, nsec3only } nsec3mode;
} rbtdb_dbiterator_t;
static void
rbtdb_dbiterator_t *rbtdbiter = NULL;
REQUIRE(VALID_RBTDB(rbtdb));
+ REQUIRE((options & (DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3)) !=
+ (DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3));
rbtdbiter = isc_mem_get(rbtdb->common.mctx, sizeof(*rbtdbiter));
dns_fixedname_init(&rbtdbiter->name);
dns_fixedname_init(&rbtdbiter->origin);
rbtdbiter->node = NULL;
- rbtdbiter->nsec3only = ((options & DNS_DB_NSEC3ONLY) != 0);
- rbtdbiter->nonsec3 = ((options & DNS_DB_NONSEC3) != 0);
+ if ((options & DNS_DB_NSEC3ONLY) != 0) {
+ rbtdbiter->nsec3mode = nsec3only;
+ } else if ((options & DNS_DB_NONSEC3) != 0) {
+ rbtdbiter->nsec3mode = nonsec3;
+ } else {
+ rbtdbiter->nsec3mode = full;
+ }
dns_rbtnodechain_init(&rbtdbiter->chain);
dns_rbtnodechain_init(&rbtdbiter->nsec3chain);
- if (rbtdbiter->nsec3only) {
+ if (rbtdbiter->nsec3mode == nsec3only) {
rbtdbiter->current = &rbtdbiter->nsec3chain;
} else {
rbtdbiter->current = &rbtdbiter->chain;
dns_rbtnodechain_reset(&rbtdbiter->chain);
dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
- if (rbtdbiter->nsec3only) {
+ switch (rbtdbiter->nsec3mode) {
+ case nsec3only:
rbtdbiter->current = &rbtdbiter->nsec3chain;
result = dns_rbtnodechain_first(rbtdbiter->current,
rbtdb->nsec3, name, origin);
- } else {
+ break;
+ case nonsec3:
+ rbtdbiter->current = &rbtdbiter->chain;
+ result = dns_rbtnodechain_first(rbtdbiter->current, rbtdb->tree,
+ name, origin);
+ break;
+ case full:
rbtdbiter->current = &rbtdbiter->chain;
result = dns_rbtnodechain_first(rbtdbiter->current, rbtdb->tree,
name, origin);
- if (!rbtdbiter->nonsec3 && result == ISC_R_NOTFOUND) {
+ if (result == ISC_R_NOTFOUND) {
rbtdbiter->current = &rbtdbiter->nsec3chain;
result = dns_rbtnodechain_first(
rbtdbiter->current, rbtdb->nsec3, name, origin);
}
+ break;
+ default:
+ UNREACHABLE();
}
+
if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
NULL, &rbtdbiter->node);
+
+ /* If we're in the NSEC3 tree, skip the origin */
+ if (RBTDBITER_NSEC3_ORIGIN_NODE(rbtdb, rbtdbiter)) {
+ rbtdbiter->node = NULL;
+ result = dns_rbtnodechain_next(rbtdbiter->current, name,
+ origin);
+ if (result == ISC_R_SUCCESS ||
+ result == DNS_R_NEWORIGIN)
+ {
+ result = dns_rbtnodechain_current(
+ rbtdbiter->current, NULL, NULL,
+ &rbtdbiter->node);
+ }
+ }
if (result == ISC_R_SUCCESS) {
rbtdbiter->new_origin = true;
reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS);
dns_rbtnodechain_reset(&rbtdbiter->chain);
dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
- result = ISC_R_NOTFOUND;
- if (rbtdbiter->nsec3only && !rbtdbiter->nonsec3) {
+ switch (rbtdbiter->nsec3mode) {
+ case nsec3only:
rbtdbiter->current = &rbtdbiter->nsec3chain;
result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->nsec3,
name, origin);
- }
- if (!rbtdbiter->nsec3only && result == ISC_R_NOTFOUND) {
+ break;
+ case nonsec3:
rbtdbiter->current = &rbtdbiter->chain;
result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->tree,
name, origin);
+ break;
+ case full:
+ rbtdbiter->current = &rbtdbiter->nsec3chain;
+ result = dns_rbtnodechain_last(rbtdbiter->current, rbtdb->nsec3,
+ name, origin);
+ if (result == ISC_R_NOTFOUND) {
+ rbtdbiter->current = &rbtdbiter->chain;
+ result = dns_rbtnodechain_last(
+ rbtdbiter->current, rbtdb->tree, name, origin);
+ }
+ break;
+ default:
+ UNREACHABLE();
}
+
if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
NULL, &rbtdbiter->node);
+ if (RBTDBITER_NSEC3_ORIGIN_NODE(rbtdb, rbtdbiter)) {
+ /*
+ * NSEC3 tree only has an origin node.
+ */
+ rbtdbiter->node = NULL;
+ switch (rbtdbiter->nsec3mode) {
+ case nsec3only:
+ result = ISC_R_NOMORE;
+ break;
+ case nonsec3:
+ case full:
+ rbtdbiter->current = &rbtdbiter->chain;
+ result = dns_rbtnodechain_last(
+ rbtdbiter->current, rbtdb->tree, name,
+ origin);
+ if (result == ISC_R_SUCCESS ||
+ result == DNS_R_NEWORIGIN)
+ {
+ result = dns_rbtnodechain_current(
+ rbtdbiter->current, NULL, NULL,
+ &rbtdbiter->node);
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
if (result == ISC_R_SUCCESS) {
rbtdbiter->new_origin = true;
reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS);
dns_rbtnodechain_reset(&rbtdbiter->chain);
dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
- if (rbtdbiter->nsec3only) {
+ switch (rbtdbiter->nsec3mode) {
+ case nsec3only:
rbtdbiter->current = &rbtdbiter->nsec3chain;
result = dns_rbt_findnode(rbtdb->nsec3, name, NULL,
&rbtdbiter->node, rbtdbiter->current,
DNS_RBTFIND_EMPTYDATA, NULL, NULL);
- } else if (rbtdbiter->nonsec3) {
+ break;
+ case nonsec3:
rbtdbiter->current = &rbtdbiter->chain;
result = dns_rbt_findnode(rbtdb->tree, name, NULL,
&rbtdbiter->node, rbtdbiter->current,
DNS_RBTFIND_EMPTYDATA, NULL, NULL);
- } else {
+ break;
+ case full:
/*
* Stay on main chain if not found on either chain.
*/
result = tresult;
}
}
+ break;
+ default:
+ UNREACHABLE();
}
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
resume_iteration(rbtdbiter);
}
+ dereference_iter_node(rbtdbiter DNS__DB_FLARG_PASS);
+
name = dns_fixedname_name(&rbtdbiter->name);
origin = dns_fixedname_name(&rbtdbiter->origin);
result = dns_rbtnodechain_prev(rbtdbiter->current, name, origin);
- if (result == ISC_R_NOMORE && !rbtdbiter->nsec3only &&
- !rbtdbiter->nonsec3 && &rbtdbiter->nsec3chain == rbtdbiter->current)
+ if (rbtdbiter->current == &rbtdbiter->nsec3chain &&
+ (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN))
+ {
+ /*
+ * If we're in the NSEC3 tree, it's empty or we've
+ * reached the origin, then we're done with it.
+ */
+ result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
+ NULL, &rbtdbiter->node);
+ if (result == ISC_R_NOTFOUND ||
+ RBTDBITER_NSEC3_ORIGIN_NODE(rbtdb, rbtdbiter))
+ {
+ rbtdbiter->node = NULL;
+ result = ISC_R_NOMORE;
+ }
+ }
+ if (result == ISC_R_NOMORE && rbtdbiter->nsec3mode != nsec3only &&
+ &rbtdbiter->nsec3chain == rbtdbiter->current)
{
rbtdbiter->current = &rbtdbiter->chain;
dns_rbtnodechain_reset(rbtdbiter->current);
}
}
- dereference_iter_node(rbtdbiter DNS__DB_FLARG_PASS);
-
if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
rbtdbiter->new_origin = (result == DNS_R_NEWORIGIN);
result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
name = dns_fixedname_name(&rbtdbiter->name);
origin = dns_fixedname_name(&rbtdbiter->origin);
result = dns_rbtnodechain_next(rbtdbiter->current, name, origin);
- if (result == ISC_R_NOMORE && !rbtdbiter->nsec3only &&
- !rbtdbiter->nonsec3 && &rbtdbiter->chain == rbtdbiter->current)
+ if (result == ISC_R_NOMORE && rbtdbiter->nsec3mode != nonsec3 &&
+ &rbtdbiter->chain == rbtdbiter->current)
{
rbtdbiter->current = &rbtdbiter->nsec3chain;
dns_rbtnodechain_reset(rbtdbiter->current);
dereference_iter_node(rbtdbiter DNS__DB_FLARG_PASS);
if (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
+ /*
+ * If we've just started the NSEC3 tree,
+ * skip over the origin.
+ */
rbtdbiter->new_origin = (result == DNS_R_NEWORIGIN);
result = dns_rbtnodechain_current(rbtdbiter->current, NULL,
NULL, &rbtdbiter->node);
+ if (RBTDBITER_NSEC3_ORIGIN_NODE(rbtdb, rbtdbiter)) {
+ rbtdbiter->node = NULL;
+ result = dns_rbtnodechain_next(rbtdbiter->current, name,
+ origin);
+ if (result == ISC_R_SUCCESS ||
+ result == DNS_R_NEWORIGIN)
+ {
+ result = dns_rbtnodechain_current(
+ rbtdbiter->current, NULL, NULL,
+ &rbtdbiter->node);
+ }
+ }
}
if (result == ISC_R_SUCCESS) {
reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS);
/* walk: walk a database */
static void
-test_walk(const char *filename, int nodes) {
+test_walk(const char *filename, int flags, int nodes) {
isc_result_t result;
dns_db_t *db = NULL;
dns_dbiterator_t *iter = NULL;
result = dns_test_loaddb(&db, dns_dbtype_zone, TEST_ORIGIN, filename);
assert_int_equal(result, ISC_R_SUCCESS);
- result = dns_db_createiterator(db, 0, &iter);
+ result = dns_db_createiterator(db, flags, &iter);
assert_int_equal(result, ISC_R_SUCCESS);
for (result = dns_dbiterator_first(iter); result == ISC_R_SUCCESS;
ISC_RUN_TEST_IMPL(walk) {
UNUSED(state);
- test_walk(TESTS_DIR "/testdata/dbiterator/zone1.data", 13);
+ test_walk(TESTS_DIR "/testdata/dbiterator/zone1.data", 0, 12);
+ test_walk(TESTS_DIR "/testdata/dbiterator/zone1.data", DNS_DB_NONSEC3,
+ 12);
+ test_walk(TESTS_DIR "/testdata/dbiterator/zone1.data", DNS_DB_NSEC3ONLY,
+ 0);
}
ISC_RUN_TEST_IMPL(walk_nsec3) {
UNUSED(state);
- test_walk(TESTS_DIR "/testdata/dbiterator/zone2.data", 33);
+ test_walk(TESTS_DIR "/testdata/dbiterator/zone2.data", 0, 32);
+ test_walk(TESTS_DIR "/testdata/dbiterator/zone2.data", DNS_DB_NONSEC3,
+ 12);
+ test_walk(TESTS_DIR "/testdata/dbiterator/zone2.data", DNS_DB_NSEC3ONLY,
+ 20);
}
/* reverse: walk database backwards */
static void
-test_reverse(const char *filename) {
+test_reverse(const char *filename, int flags, int nodes) {
isc_result_t result;
dns_db_t *db = NULL;
dns_dbiterator_t *iter = NULL;
result = dns_test_loaddb(&db, dns_dbtype_zone, TEST_ORIGIN, filename);
assert_int_equal(result, ISC_R_SUCCESS);
- result = dns_db_createiterator(db, 0, &iter);
+ result = dns_db_createiterator(db, flags, &iter);
assert_int_equal(result, ISC_R_SUCCESS);
for (result = dns_dbiterator_last(iter); result == ISC_R_SUCCESS;
i++;
}
- assert_int_equal(i, 12);
+ assert_int_equal(i, nodes);
dns_dbiterator_destroy(&iter);
dns_db_detach(&db);
ISC_RUN_TEST_IMPL(reverse) {
UNUSED(state);
- test_reverse(TESTS_DIR "/testdata/dbiterator/zone1.data");
+ test_reverse(TESTS_DIR "/testdata/dbiterator/zone1.data", 0, 12);
+ test_reverse(TESTS_DIR "/testdata/dbiterator/zone1.data",
+ DNS_DB_NONSEC3, 12);
+ test_reverse(TESTS_DIR "/testdata/dbiterator/zone1.data",
+ DNS_DB_NSEC3ONLY, 0);
}
ISC_RUN_TEST_IMPL(reverse_nsec3) {
UNUSED(state);
- test_reverse(TESTS_DIR "/testdata/dbiterator/zone2.data");
+ test_reverse(TESTS_DIR "/testdata/dbiterator/zone2.data", 0, 32);
+ test_reverse(TESTS_DIR "/testdata/dbiterator/zone2.data",
+ DNS_DB_NONSEC3, 12);
+ test_reverse(TESTS_DIR "/testdata/dbiterator/zone2.data",
+ DNS_DB_NSEC3ONLY, 20);
}
/* seek: walk database starting at a particular node */
static void
-test_seek_node(const char *filename, int nodes) {
+test_seek_node(const char *filename, int flags, int nodes) {
isc_result_t result;
dns_db_t *db = NULL;
dns_dbiterator_t *iter = NULL;
result = dns_test_loaddb(&db, dns_dbtype_zone, TEST_ORIGIN, filename);
assert_int_equal(result, ISC_R_SUCCESS);
- result = dns_db_createiterator(db, 0, &iter);
+ result = dns_db_createiterator(db, flags, &iter);
assert_int_equal(result, ISC_R_SUCCESS);
result = make_name("c." TEST_ORIGIN, seekname);
assert_int_equal(result, ISC_R_SUCCESS);
result = dns_dbiterator_seek(iter, seekname);
- assert_int_equal(result, ISC_R_SUCCESS);
+ if (flags == DNS_DB_NSEC3ONLY) {
+ /* "c" isn't in the NSEC3 tree but the origin node is */
+ assert_int_equal(result, DNS_R_PARTIALMATCH);
+ } else {
+ assert_int_equal(result, ISC_R_SUCCESS);
+ }
while (result == ISC_R_SUCCESS) {
result = dns_dbiterator_current(iter, &node, name);
assert_int_equal(i, nodes);
+ /* now reset the iterator and walk backwards */
+ i = 0;
+ result = dns_dbiterator_seek(iter, seekname);
+ if (flags == DNS_DB_NSEC3ONLY) {
+ /* "c" isn't in the NSEC3 tree but the origin node is */
+ assert_int_equal(result, DNS_R_PARTIALMATCH);
+ nodes = 0;
+ } else {
+ assert_int_equal(result, ISC_R_SUCCESS);
+ nodes = 4;
+ }
+
+ while (result == ISC_R_SUCCESS) {
+ result = dns_dbiterator_current(iter, &node, name);
+ if (result == DNS_R_NEWORIGIN) {
+ result = ISC_R_SUCCESS;
+ }
+ assert_int_equal(result, ISC_R_SUCCESS);
+ dns_db_detachnode(db, &node);
+ result = dns_dbiterator_prev(iter);
+ i++;
+ }
+
+ assert_int_equal(i, nodes);
+
dns_dbiterator_destroy(&iter);
dns_db_detach(&db);
}
ISC_RUN_TEST_IMPL(seek_node) {
UNUSED(state);
- test_seek_node(TESTS_DIR "/testdata/dbiterator/zone1.data", 10);
+ test_seek_node(TESTS_DIR "/testdata/dbiterator/zone1.data", 0, 9);
+ test_seek_node(TESTS_DIR "/testdata/dbiterator/zone1.data",
+ DNS_DB_NONSEC3, 9);
+ test_seek_node(TESTS_DIR "/testdata/dbiterator/zone1.data",
+ DNS_DB_NSEC3ONLY, 0);
}
ISC_RUN_TEST_IMPL(seek_node_nsec3) {
UNUSED(state);
- test_seek_node(TESTS_DIR "/testdata/dbiterator/zone2.data", 30);
+ test_seek_node(TESTS_DIR "/testdata/dbiterator/zone2.data", 0, 29);
+ test_seek_node(TESTS_DIR "/testdata/dbiterator/zone2.data",
+ DNS_DB_NONSEC3, 9);
+ test_seek_node(TESTS_DIR "/testdata/dbiterator/zone2.data",
+ DNS_DB_NSEC3ONLY, 0);
}
/*