]> 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>
Thu, 11 Dec 2025 12:53:25 +0000 (13:53 +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.

(cherry picked from commit 41159e9062b40495aca6178da54d60bbd2f34378)

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

index 8f202871a67d714b8f93ca265b03be1237b70c0c..23b0abc3bc25daf34768669cbcb8de9cc1d7d27e 100644 (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) {
        /*
index 306b28b91801a6d5558671d6a21513f0086a6bfc..0695a76e292cf3bb10503c7f6f68518542c803d1 100644 (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
index 3f29643f07a5204ede35ccfe0eda36d8dee6fb09..8ceb23acc7097cdd87bcd1718734d693d4523064 100644 (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;
index 9b36982348e9b43d46311fe166058da7c64c23ca..cd576bc33cf82d79479b2d0a2e199ae38190d974 100644 (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;
index 0a90e216c4fd35e571aa5adeec3e556166a5b0b3..2abaab290121d674125d6fb681ce51c83c9ae64d 100644 (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;
index dcd5ab9ecbf86813ff872b1c87a6b8e6633d5e6f..c50790254905b025e37a05be0835e11622dfe28b 100644 (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;
index 30980700b9d955bc3d7a91262cca68891a144964..07a63c680dc0e787084cccd77463fc39825d9182 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);
 }