]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Implement dns_dbiterator_seek3
authorMatthijs Mekking <matthijs@isc.org>
Tue, 9 Dec 2025 11:37:20 +0000 (12:37 +0100)
committerMatthijs Mekking <matthijs@isc.org>
Wed, 10 Dec 2025 13:18:52 +0000 (14:18 +0100)
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.

lib/dns/dbiterator.c
lib/dns/include/dns/dbiterator.h
lib/dns/qpcache.c
lib/dns/qpzone.c
lib/dns/sdlz.c
tests/dns/dbiterator_test.c

index 626e4c454383459ce6a4d888d94581daf6c69099..4732d706c8c88a44f15fb88a0b9b9e9137ad46b3 100644 (file)
@@ -58,6 +58,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) {
        REQUIRE(DNS_DBITERATOR_VALID(iterator));
index 0371401cb230aaf9719f6ce4a4e68daaf0379b3d..c3f92cd687eebaea83b09061ab3dd49d35838873 100644 (file)
@@ -70,6 +70,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,
@@ -189,6 +191,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
index 50218a3e25e097313e49312fded32d4ad14a57b9..94a7c8aed5ffddcdfaab7e77dd857f1f20a5b86c 100644 (file)
@@ -374,6 +374,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);
@@ -386,9 +389,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
 };
 
 /*
@@ -3634,6 +3638,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 ISC_ATTR_UNUSED DNS__DB_FLARG) {
        return ISC_R_NOTIMPLEMENTED;
index fadcd0996d92a76070aa958c02ea2a29e8a3b5f6..9cd5c77c62bfbbb6a8483a7f794373144bf18dbd 100644 (file)
@@ -345,6 +345,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);
@@ -357,9 +360,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 {
@@ -4357,6 +4361,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);
+
+       result = dns_qp_lookup(qpdbiter->snap, name, DNS_DBNAMESPACE_NSEC3,
+                              &qpdbiter->iter, 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;
index 22bd0ee2104cab0e2d9535b4470aa83b94996a67..aa6e58305c7bb9c2e33446b0cb2b0378bdf18ecc 100644 (file)
@@ -210,6 +210,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);
@@ -222,9 +225,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
 };
 
 /*
@@ -1149,6 +1153,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;
index a4593bf945ea3513e206eff8fff25a254f2e0391..c15e460827d1269806c29858cae44a136ba896d7 100644 (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);
 }