]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
findzonecut: helper function to choose zone or cache
authorColin Vidal <colin@isc.org>
Tue, 16 Dec 2025 13:24:41 +0000 (14:24 +0100)
committerColin Vidal <colin@isc.org>
Thu, 8 Jan 2026 19:26:32 +0000 (20:26 +0100)
When a delegation is found at a zone level, the cache is also looked up,
in case a more specific delegation is found. If it is, then the records
from the zone are disassociated and then associated with those from the
cache.

There is no return value, because even if the cache lookup fails, there
is a valid delegation from the zone, so this is a success either way.

The main function `dns_view_findzonecut()` is also strongly refactored,
as `findzonecut_zoneorcache()` allows a sequential flow between the
various DB lookup attempts, instead of jumping back to the begining of
the lookup code using `goto`.

From the caller's point of view, the API is slightly simplified: the
return value can only be ISC_R_SUCCESS (a delegation is found) or
DNS_R_NXDOMAIN (no delegation is found). Also, if no delegation is
found, this guarantees that the rdatasets passed as parameter are
disassociated.

lib/dns/view.c

index c6deb0696a2c0f2d9254dc808e131899060c8092..db8a01ffa07587e4a19b686dbac3e39c9dc083e3 100644 (file)
@@ -998,16 +998,19 @@ findzonecut_zone(dns_view_t *view, const dns_name_t *name, dns_name_t *fname,
 
        result = dns_view_findzone(view, name, ztoptions, &zone);
        if (result != ISC_R_SUCCESS && result != DNS_R_PARTIALMATCH) {
+               /*
+                * There is no matching zone configured locally.
+                */
                CLEANUP(DNS_R_NXDOMAIN);
        }
 
        result = dns_zone_getdb(zone, &db);
        if (result != ISC_R_SUCCESS) {
                /*
-                * The zone exists, but there is no DB (likely not loaded yet),
-                * as for the case below (no delegation), ISC_R_NOTFOUND is used
-                * to differentiate from the case where there is no zone at all,
-                * so the caller won't attempt to hit the cache or hints.
+                * A matching zone is configured locally, but its database
+                * isn't loaded. We return ISC_R_NOTFOUND to differentiate
+                * from the case where the zone doesn't exist, so the
+                * caller won't try the cache or hints.
                 */
                CLEANUP(ISC_R_NOTFOUND);
        }
@@ -1016,9 +1019,9 @@ findzonecut_zone(dns_view_t *view, const dns_name_t *name, dns_name_t *fname,
                             NULL, fname, rdataset, sigrdataset);
        if (result != DNS_R_DELEGATION && result != ISC_R_SUCCESS) {
                /*
-                * The zone exists, but there is no delegation. Using
-                * ISC_R_NOTFOUND enable to differentiate from the case where
-                * there is no zone at all.
+                * The zone exists, but there is no delegation. Here again
+                * we use ISC_R_NOTFOUND, to differentiate from the case where
+                * the zone doesn't exist.
                 */
                CLEANUP(ISC_R_NOTFOUND);
        }
@@ -1080,6 +1083,45 @@ findzonecut_cache(dns_view_t *view, const dns_name_t *name, dns_name_t *fname,
        return result;
 }
 
+static void
+findzonecut_zoneorcache(dns_view_t *view, const dns_name_t *name,
+                       dns_name_t *fname, dns_name_t *dcname,
+                       isc_stdtime_t now, unsigned int options,
+                       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
+       isc_result_t result;
+       dns_rdataset_t crdataset = DNS_RDATASET_INIT;
+       dns_rdataset_t csigrdataset = DNS_RDATASET_INIT;
+       dns_fixedname_t f, dc;
+       dns_name_t *cfname = dns_fixedname_initname(&f);
+       dns_name_t *cdcname = dns_fixedname_initname(&dc);
+
+       CHECK(findzonecut_cache(view, name, cfname, cdcname, now, options,
+                               &crdataset, &csigrdataset));
+
+       bool cacheclosest = dns_name_issubdomain(cfname, fname);
+       bool staticstub = rdataset->attributes.staticstub &&
+                         dns_name_equal(fname, cfname);
+
+       if (cacheclosest && !staticstub) {
+               dns_rdataset_cleanup(rdataset);
+               dns_rdataset_cleanup(sigrdataset);
+
+               dns_rdataset_clone(&crdataset, rdataset);
+               if (sigrdataset != NULL) {
+                       dns_rdataset_clone(&csigrdataset, sigrdataset);
+               }
+
+               dns_name_copy(cfname, fname);
+               if (dcname != NULL) {
+                       dns_name_copy(cdcname, dcname);
+               }
+       }
+
+cleanup:
+       dns_rdataset_cleanup(&crdataset);
+       dns_rdataset_cleanup(&csigrdataset);
+}
+
 static isc_result_t
 findzonecut_hints(dns_view_t *view, dns_name_t *fname, dns_name_t *dcname,
                  isc_stdtime_t now, dns_rdataset_t *rdataset) {
@@ -1103,169 +1145,43 @@ findzonecut_hints(dns_view_t *view, dns_name_t *fname, dns_name_t *dcname,
 isc_result_t
 dns_view_findzonecut(dns_view_t *view, const dns_name_t *name,
                     dns_name_t *fname, dns_name_t *dcname, isc_stdtime_t now,
-                    unsigned int options, bool use_hints, bool use_cache,
+                    unsigned int options, bool usehints, bool usecache,
                     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
        isc_result_t result;
-       dns_db_t *db = NULL;
-       bool is_cache, use_zone = false, try_hints = false;
-       dns_zone_t *zone = NULL;
-       dns_name_t *zfname = NULL;
-       dns_zt_t *zonetable = NULL;
-       dns_rdataset_t zrdataset, zsigrdataset;
-       dns_fixedname_t zfixedname;
-       unsigned int ztoptions = DNS_ZTFIND_MIRROR;
 
        REQUIRE(DNS_VIEW_VALID(view));
        REQUIRE(view->frozen);
 
-       /*
-        * Initialize.
-        */
-       dns_fixedname_init(&zfixedname);
-       dns_rdataset_init(&zrdataset);
-       dns_rdataset_init(&zsigrdataset);
+       result = findzonecut_zone(view, name, fname, dcname, now, options,
+                                 rdataset, sigrdataset);
 
-       /*
-        * Find the right database.
-        */
-       if ((options & DNS_DBFIND_NOEXACT) != 0) {
-               ztoptions |= DNS_ZTFIND_NOEXACT;
-       }
-       rcu_read_lock();
-       zonetable = rcu_dereference(view->zonetable);
-       if (zonetable != NULL) {
-               result = dns_zt_find(zonetable, name, ztoptions, &zone);
-       } else {
-               result = ISC_R_SHUTTINGDOWN;
-       }
-       rcu_read_unlock();
-       if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
-               result = dns_zone_getdb(zone, &db);
-       }
-       if (result == ISC_R_NOTFOUND) {
+       if (result == DNS_R_NXDOMAIN && usecache) {
                /*
-                * We're not directly authoritative for this query name, nor
-                * is it a subdomain of any zone for which we're
-                * authoritative.
+                * No local zone matches `name`, but the cache might have a
+                * delegation.
                 */
-               if (use_cache && view->cachedb != NULL) {
-                       /*
-                        * We have a cache; try it.
-                        */
-                       dns_db_attach(view->cachedb, &db);
-               } else if (use_hints && view->hints != NULL) {
-                       /*
-                        * Maybe we have hints...
-                        */
-                       try_hints = true;
-                       goto finish;
-               } else {
-                       CLEANUP(DNS_R_NXDOMAIN);
-               }
-       } else if (result != ISC_R_SUCCESS) {
+               result = findzonecut_cache(view, name, fname, dcname, now,
+                                          options, rdataset, sigrdataset);
+       } else if (result == ISC_R_SUCCESS && usecache) {
                /*
-                * Something is broken.
+                * A zone with a (possibly partial) delegation match but the
+                * cache can have a more precise delegation.
                 */
-               goto cleanup;
+               findzonecut_zoneorcache(view, name, fname, dcname, now, options,
+                                       rdataset, sigrdataset);
        }
-       is_cache = dns_db_iscache(db);
 
-db_find:
        /*
-        * Look for the zonecut.
+        * No local zone nor cache match. Last attempt with the hints.
         */
-       if (!is_cache) {
-               result = findzonecut_zone(view, name, fname, NULL, now, options,
-                                         rdataset, sigrdataset);
-               if (result != ISC_R_SUCCESS) {
-                       goto cleanup;
-               }
-
-               if (use_cache && view->cachedb != NULL && db != view->hints) {
-                       /*
-                        * We found an answer, but the cache may be better.
-                        */
-                       zfname = dns_fixedname_name(&zfixedname);
-                       dns_name_copy(fname, zfname);
-                       dns_rdataset_clone(rdataset, &zrdataset);
-                       dns_rdataset_disassociate(rdataset);
-                       if (sigrdataset != NULL &&
-                           dns_rdataset_isassociated(sigrdataset))
-                       {
-                               dns_rdataset_clone(sigrdataset, &zsigrdataset);
-                               dns_rdataset_disassociate(sigrdataset);
-                       }
-                       dns_db_detach(&db);
-                       dns_db_attach(view->cachedb, &db);
-                       is_cache = true;
-                       goto db_find;
-               }
-       } else {
-               result = findzonecut_cache(view, name, fname, dcname, now,
-                                          options, rdataset, sigrdataset);
-               if (result == ISC_R_SUCCESS) {
-                       if (zfname != NULL &&
-                           (!dns_name_issubdomain(fname, zfname) ||
-                            (dns_zone_gettype(zone) == dns_zone_staticstub &&
-                             dns_name_equal(fname, zfname))))
-                       {
-                               /*
-                                * We found a zonecut in the cache, but our
-                                * zone delegation is better.
-                                */
-                               use_zone = true;
-                       }
-               } else if (result == DNS_R_NXDOMAIN) {
-                       if (zfname != NULL) {
-                               /*
-                                * We didn't find anything in the cache, but we
-                                * have a zone delegation, so use it.
-                                */
-                               use_zone = true;
-                               result = ISC_R_SUCCESS;
-                       } else if (use_hints && view->hints != NULL) {
-                               /*
-                                * Maybe we have hints...
-                                */
-                               try_hints = true;
-                               result = ISC_R_SUCCESS;
-                       }
-               } else {
-                       /*
-                        * Something bad happened.
-                        */
-                       goto cleanup;
-               }
+       if (result == DNS_R_NXDOMAIN && usehints) {
+               result = findzonecut_hints(view, fname, dcname, now, rdataset);
        }
 
-finish:
-       if (use_zone) {
+       if (result != ISC_R_SUCCESS) {
+               result = DNS_R_NXDOMAIN;
                dns_rdataset_cleanup(rdataset);
                dns_rdataset_cleanup(sigrdataset);
-
-               dns_name_copy(zfname, fname);
-               if (dcname != NULL) {
-                       dns_name_copy(zfname, dcname);
-               }
-               dns_rdataset_clone(&zrdataset, rdataset);
-               if (sigrdataset != NULL &&
-                   dns_rdataset_isassociated(&zrdataset))
-               {
-                       dns_rdataset_clone(&zsigrdataset, sigrdataset);
-               }
-       } else if (try_hints) {
-               result = findzonecut_hints(view, fname, dcname, now, rdataset);
-       }
-
-cleanup:
-       dns_rdataset_cleanup(&zrdataset);
-       dns_rdataset_cleanup(&zsigrdataset);
-
-       if (db != NULL) {
-               dns_db_detach(&db);
-       }
-       if (zone != NULL) {
-               dns_zone_detach(&zone);
        }
 
        return result;