Implement dns_dbiterator_seek3

This is a new seek function for dbiterator that is meant to find an
NSEC3 node in a zone database. The difference with dns_dbiterator_seek
is that if the node does not exist, this seek function will point the
iterator to the next NSEC3 name.

(cherry picked from commit 41159e9062)
This commit is contained in:
Matthijs Mekking 2025-12-09 12:37:20 +01:00
parent 71c991d592
commit 63262fd0f4
7 changed files with 228 additions and 21 deletions

View file

@ -68,6 +68,14 @@ dns__dbiterator_seek(dns_dbiterator_t *iterator,
return iterator->methods->seek(iterator, name DNS__DB_FLARG_PASS);
}
isc_result_t
dns__dbiterator_seek3(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG) {
REQUIRE(DNS_DBITERATOR_VALID(iterator));
return iterator->methods->seek3(iterator, name DNS__DB_FLARG_PASS);
}
isc_result_t
dns__dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) {
/*

View file

@ -73,6 +73,8 @@ typedef struct dns_dbiteratormethods {
isc_result_t (*last)(dns_dbiterator_t *iterator DNS__DB_FLARG);
isc_result_t (*seek)(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG);
isc_result_t (*seek3)(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG);
isc_result_t (*prev)(dns_dbiterator_t *iterator DNS__DB_FLARG);
isc_result_t (*next)(dns_dbiterator_t *iterator DNS__DB_FLARG);
isc_result_t (*current)(dns_dbiterator_t *iterator,
@ -176,6 +178,30 @@ dns__dbiterator_seek(dns_dbiterator_t *iterator,
*\li Other results are possible, depending on the DB implementation.
*/
#define dns_dbiterator_seek3(iterator, name) \
dns__dbiterator_seek3(iterator, name DNS__DB_FILELINE)
isc_result_t
dns__dbiterator_seek3(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG);
/*%<
* Move the node cursor to the node with NSEC3 name 'name'.
* If not found, the iterator is set to the next name.
*
* Requires:
*\li 'iterator' is a valid iterator.
*
*\li 'name' is a valid name.
*
* Returns:
*\li #ISC_R_SUCCESS
*\li #ISC_R_NOTFOUND
*\li #ISC_R_NOMORE There are no NSEC3 nodes in the database.
*\li #ISC_R_NOTIMPLEMENTED
* (this function is only implemented for NSEC3 only iterators)
*
*\li Other results are possible, depending on the DB implementation.
*/
#define dns_dbiterator_prev(iterator) \
dns__dbiterator_prev(iterator DNS__DB_FILELINE)
isc_result_t

View file

@ -417,6 +417,9 @@ static isc_result_t
dbiterator_seek(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG);
static isc_result_t
dbiterator_seek3(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG);
static isc_result_t
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG);
static isc_result_t
dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG);
@ -429,9 +432,10 @@ static isc_result_t
dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
static dns_dbiteratormethods_t dbiterator_methods = {
dbiterator_destroy, dbiterator_first, dbiterator_last,
dbiterator_seek, dbiterator_prev, dbiterator_next,
dbiterator_current, dbiterator_pause, dbiterator_origin
dbiterator_destroy, dbiterator_first, dbiterator_last,
dbiterator_seek, dbiterator_seek3, dbiterator_prev,
dbiterator_next, dbiterator_current, dbiterator_pause,
dbiterator_origin
};
/*
@ -4098,6 +4102,12 @@ dbiterator_seek(dns_dbiterator_t *iterator,
return result;
}
static isc_result_t
dbiterator_seek3(dns_dbiterator_t *iterator ISC_ATTR_UNUSED,
const dns_name_t *name ISC_ATTR_UNUSED DNS__DB_FLARG) {
return ISC_R_NOTIMPLEMENTED;
}
static isc_result_t
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) {
isc_result_t result;

View file

@ -350,6 +350,9 @@ static isc_result_t
dbiterator_seek(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG);
static isc_result_t
dbiterator_seek3(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG);
static isc_result_t
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG);
static isc_result_t
dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG);
@ -362,9 +365,10 @@ static isc_result_t
dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
static dns_dbiteratormethods_t dbiterator_methods = {
dbiterator_destroy, dbiterator_first, dbiterator_last,
dbiterator_seek, dbiterator_prev, dbiterator_next,
dbiterator_current, dbiterator_pause, dbiterator_origin
dbiterator_destroy, dbiterator_first, dbiterator_last,
dbiterator_seek, dbiterator_seek3, dbiterator_prev,
dbiterator_next, dbiterator_current, dbiterator_pause,
dbiterator_origin
};
typedef struct qpdb_dbiterator {
@ -4379,6 +4383,53 @@ dbiterator_seek(dns_dbiterator_t *iterator,
return result;
}
static isc_result_t
dbiterator_seek3(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG) {
isc_result_t result;
qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
if (qpdbiter->result != ISC_R_SUCCESS &&
qpdbiter->result != ISC_R_NOTFOUND &&
qpdbiter->result != DNS_R_PARTIALMATCH &&
qpdbiter->result != ISC_R_NOMORE)
{
return qpdbiter->result;
}
if (qpdbiter->nsec3mode != nsec3only) {
return ISC_R_NOTIMPLEMENTED;
}
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
qpdbiter->current = &qpdbiter->nsec3iter;
result = dns_qp_lookup(qpdbiter->nsnap, name, NULL, qpdbiter->current,
NULL, (void **)&qpdbiter->node, NULL);
switch (result) {
case ISC_R_SUCCESS:
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
break;
case DNS_R_PARTIALMATCH:
/* dbiterator_next() will dereference the node */
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
result = dbiterator_next(iterator);
if (result == ISC_R_NOMORE) {
result = dbiterator_first(iterator);
}
break;
case ISC_R_NOTFOUND:
default:
break;
}
qpdbiter->result = result;
return qpdbiter->result;
}
static isc_result_t
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) {
isc_result_t result;

View file

@ -199,6 +199,9 @@ static isc_result_t
dbiterator_seek(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG);
static isc_result_t
dbiterator_seek3(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG);
static isc_result_t
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG);
static isc_result_t
dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG);
@ -211,9 +214,10 @@ static isc_result_t
dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
static dns_dbiteratormethods_t dbiterator_methods = {
dbiterator_destroy, dbiterator_first, dbiterator_last,
dbiterator_seek, dbiterator_prev, dbiterator_next,
dbiterator_current, dbiterator_pause, dbiterator_origin
dbiterator_destroy, dbiterator_first, dbiterator_last,
dbiterator_seek, dbiterator_seek3, dbiterator_prev,
dbiterator_next, dbiterator_current, dbiterator_pause,
dbiterator_origin
};
/*
@ -4658,6 +4662,90 @@ dbiterator_seek(dns_dbiterator_t *iterator,
return result;
}
static isc_result_t
dbiterator_seek3(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG) {
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 = NULL, *origin = NULL;
if (rbtdbiter->result != ISC_R_SUCCESS &&
rbtdbiter->result != ISC_R_NOTFOUND &&
rbtdbiter->result != DNS_R_PARTIALMATCH &&
rbtdbiter->result != ISC_R_NOMORE)
{
return rbtdbiter->result;
}
if (rbtdbiter->nsec3mode != nsec3only) {
return ISC_R_NOTIMPLEMENTED;
}
if (rbtdbiter->paused) {
resume_iteration(rbtdbiter);
}
dereference_iter_node(rbtdbiter DNS__DB_FLARG_PASS);
iname = dns_fixedname_name(&rbtdbiter->name);
origin = dns_fixedname_name(&rbtdbiter->origin);
dns_rbtnodechain_reset(&rbtdbiter->chain);
dns_rbtnodechain_reset(&rbtdbiter->nsec3chain);
rbtdbiter->current = &rbtdbiter->nsec3chain;
result = dns_rbt_findnode(rbtdb->nsec3, name, NULL, &rbtdbiter->node,
rbtdbiter->current, DNS_RBTFIND_EMPTYDATA,
NULL, NULL);
if (result == ISC_R_SUCCESS) {
tresult = dns_rbtnodechain_current(rbtdbiter->current, iname,
origin, NULL);
reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS);
if (tresult == ISC_R_SUCCESS) {
rbtdbiter->new_origin = true;
} else {
result = tresult;
rbtdbiter->node = NULL;
}
} else if (result == DNS_R_PARTIALMATCH) {
tresult = dns_rbtnodechain_current(rbtdbiter->current, iname,
origin, NULL);
/* dbiterator_next() will dereference the node */
reference_iter_node(rbtdbiter DNS__DB_FLARG_PASS);
if (tresult == ISC_R_SUCCESS) {
rbtdbiter->new_origin = true;
result = dbiterator_next(iterator);
if (result == ISC_R_NOMORE) {
result = dbiterator_first(iterator);
}
tresult = dns_rbtnodechain_current(rbtdbiter->current,
iname, origin, NULL);
if (tresult == ISC_R_SUCCESS) {
rbtdbiter->new_origin = true;
} else {
result = tresult;
rbtdbiter->node = NULL;
}
} else {
result = tresult;
rbtdbiter->node = NULL;
}
} else {
rbtdbiter->node = NULL;
}
rbtdbiter->result = result;
return result;
}
static isc_result_t
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) {
isc_result_t result;

View file

@ -201,6 +201,9 @@ static isc_result_t
dbiterator_seek(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG);
static isc_result_t
dbiterator_seek3(dns_dbiterator_t *iterator,
const dns_name_t *name DNS__DB_FLARG);
static isc_result_t
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG);
static isc_result_t
dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG);
@ -213,9 +216,10 @@ static isc_result_t
dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
static dns_dbiteratormethods_t dbiterator_methods = {
dbiterator_destroy, dbiterator_first, dbiterator_last,
dbiterator_seek, dbiterator_prev, dbiterator_next,
dbiterator_current, dbiterator_pause, dbiterator_origin
dbiterator_destroy, dbiterator_first, dbiterator_last,
dbiterator_seek, dbiterator_seek3, dbiterator_prev,
dbiterator_next, dbiterator_current, dbiterator_pause,
dbiterator_origin
};
/*
@ -1243,6 +1247,12 @@ dbiterator_seek(dns_dbiterator_t *iterator,
return ISC_R_NOTFOUND;
}
static isc_result_t
dbiterator_seek3(dns_dbiterator_t *iterator ISC_ATTR_UNUSED,
const dns_name_t *name ISC_ATTR_UNUSED DNS__DB_FLARG) {
return ISC_R_NOTIMPLEMENTED;
}
static isc_result_t
dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) {
sdlz_dbiterator_t *sdlziter = (sdlz_dbiterator_t *)iterator;

View file

@ -182,10 +182,10 @@ ISC_RUN_TEST_IMPL(reverse_nsec3) {
/* seek: walk database starting at a particular node */
static void
test_seek_node(const char *filename, int flags, int nodes) {
isc_result_t result;
test_seek_node(const char *filename, bool nsec3, int flags, int nodes) {
isc_result_t result, result3;
dns_db_t *db = NULL;
dns_dbiterator_t *iter = NULL;
dns_dbiterator_t *iter = NULL, *iter3 = NULL;
dns_dbnode_t *node = NULL;
dns_name_t *name, *seekname;
dns_fixedname_t f1, f2;
@ -200,6 +200,9 @@ test_seek_node(const char *filename, int flags, int nodes) {
result = dns_db_createiterator(db, flags, &iter);
assert_int_equal(result, ISC_R_SUCCESS);
result3 = dns_db_createiterator(db, flags, &iter3);
assert_int_equal(result3, ISC_R_SUCCESS);
result = make_name("c." TEST_ORIGIN, seekname);
assert_int_equal(result, ISC_R_SUCCESS);
@ -207,6 +210,14 @@ test_seek_node(const char *filename, int flags, int nodes) {
if (flags == DNS_DB_NSEC3ONLY) {
/* "c" isn't in the NSEC3 tree but the origin node is */
assert_int_equal(result, DNS_R_PARTIALMATCH);
/* NSEC3 iterator */
result3 = dns_dbiterator_seek3(iter3, seekname);
if (nsec3) {
assert_int_equal(result3, ISC_R_SUCCESS);
} else {
assert_int_equal(result3, ISC_R_NOMORE);
}
} else {
assert_int_equal(result, ISC_R_SUCCESS);
}
@ -244,26 +255,29 @@ test_seek_node(const char *filename, int flags, int nodes) {
assert_int_equal(i, nodes);
dns_dbiterator_destroy(&iter);
dns_dbiterator_destroy(&iter3);
dns_db_detach(&db);
}
ISC_RUN_TEST_IMPL(seek_node) {
UNUSED(state);
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone1.data", 0, 9);
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone1.data",
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone1.data", false, 0,
9);
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone1.data", false,
DNS_DB_NONSEC3, 9);
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone1.data",
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone1.data", false,
DNS_DB_NSEC3ONLY, 0);
}
ISC_RUN_TEST_IMPL(seek_node_nsec3) {
UNUSED(state);
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone2.data", 0, 29);
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone2.data",
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone2.data", true, 0,
29);
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone2.data", true,
DNS_DB_NONSEC3, 9);
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone2.data",
test_seek_node(TESTS_DIR "/testdata/dbiterator/zone2.data", true,
DNS_DB_NSEC3ONLY, 0);
}