fix several bugs in the RBTDB dbiterator implementation

- the DNS_DB_NSEC3ONLY and DNS_DB_NONSEC3 flags are mutually
  exclusive; it never made sense to set both at the same time.
  to enforce this, it is now a fatal error to do so.  the
  dbiterator implementation has been cleaned up to remove
  code that treated the two as independent: if nonsec3 is
  true, we can be certain nsec3only is false, and vice versa.
- previously, iterating a database backwards omitted
  NSEC3 records even if DNS_DB_NONSEC3 had not been set. this
  has been corrected.
- when an iterator reaches the origin node of the NSEC3 tree, we
  need to skip over it and go to the next node in the sequence.
  the NSEC3 origin node is there for housekeeping purposes and
  never contains data.
- the dbiterator_test unit test has been expanded, several
  incorrect expectations have been fixed. (for example, the
  expected number of iterations has been reduced by one; we were
  previously counting the NSEC3 origin node and we should not
  have been doing so.)
This commit is contained in:
Evan Hunt
2024-02-14 12:58:01 -08:00
parent 88c56e25a1
commit e40fd4ed06
4 changed files with 207 additions and 35 deletions

View File

@@ -74,7 +74,7 @@ ISC_RUN_TEST_IMPL(create_nsec3) {
/* 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;
@@ -88,7 +88,7 @@ test_walk(const char *filename, int nodes) {
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;
@@ -112,18 +112,26 @@ test_walk(const char *filename, int nodes) {
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;
@@ -137,7 +145,7 @@ test_reverse(const char *filename) {
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;
@@ -152,7 +160,7 @@ test_reverse(const char *filename) {
i++;
}
assert_int_equal(i, 12);
assert_int_equal(i, nodes);
dns_dbiterator_destroy(&iter);
dns_db_detach(&db);
@@ -161,18 +169,26 @@ test_reverse(const char *filename) {
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;
@@ -187,14 +203,19 @@ test_seek_node(const char *filename, int nodes) {
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);
@@ -209,6 +230,31 @@ test_seek_node(const char *filename, int nodes) {
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);
}
@@ -216,13 +262,21 @@ test_seek_node(const char *filename, int nodes) {
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);
}
/*