]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Delegations have a minimal TTL of 60 seconds
authorColin Vidal <colin@isc.org>
Tue, 26 May 2026 13:58:44 +0000 (15:58 +0200)
committerColin Vidal <colin@isc.org>
Wed, 1 Jul 2026 06:40:05 +0000 (08:40 +0200)
Delegations are now stored in delegdb with a TTL of at least 60 seconds
by default. A new configuration option `min-delegation-ttl` allows
overriding this value or disabling entirely it with `0`.

This hardens the resolver against misconfigured glue or NS records
with very low TTLs, which would otherwise trigger delegation refetches
too often.

A new option `max-delegation-ttl` (which default to `0`) is also added,
enabling an operator to enforce a maximum TTL check for delegations.

13 files changed:
bin/include/defaultconfig.h
bin/named/server.c
bin/tests/system/cacheclean/ns2/named.conf.j2
bin/tests/system/checkconf/bad-delegation-ttl-1.conf [new file with mode: 0644]
bin/tests/system/checkconf/bad-delegation-ttl-2.conf [new file with mode: 0644]
bin/tests/system/checkconf/good-delegation-ttl-1.conf [new file with mode: 0644]
bin/tests/system/checkconf/good-delegation-ttl-2.conf [new file with mode: 0644]
bin/tests/system/qmin/ns5/named.conf.j2
bin/tests/system/resolver/ns5/named.conf.j2
doc/arm/reference.rst
doc/misc/options
lib/isccfg/check.c
lib/isccfg/namedconf.c

index 469429711992817e2f2fa2c5342faa89feb8639c..a66ec87a8f22b44b33d3a7b594d9d262524d8c48 100644 (file)
@@ -143,6 +143,7 @@ options {\n\
        lmdb-mapsize 32M;\n\
        max-cache-size default;\n\
        max-cache-ttl 604800; /* 1 week */\n\
+       max-delegation-ttl 0; /* disabled */\n\
        max-clients-per-query 100;\n\
        max-delegation-servers 13;\n\
        max-ncache-ttl 10800; /* 3 hours */\n\
@@ -154,6 +155,7 @@ options {\n\
        message-compression yes;\n\
        min-ncache-ttl 0; /* 0 hours */\n\
        min-cache-ttl 0; /* 0 seconds */\n\
+       min-delegation-ttl 60; /* 1 minute */\n\
        minimal-any yes;\n\
        minimal-responses no-auth-recursive;\n\
        notify-source *;\n\
index e5ffb7ede2aa1280b3cb4c26fd5ee63172d42e5a..ae03bb151c280cf1ebdf66cba207a05cd2429dc2 100644 (file)
@@ -3680,6 +3680,51 @@ configure_max_cache_size(dns_view_t *view, const cfg_obj_t *maps[4]) {
        }
 }
 
+static isc_result_t
+configure_view_delegdb(const cfg_obj_t **maps, dns_view_t *pview,
+                      dns_view_t *view, size_t cachesz) {
+       isc_result_t result;
+       const cfg_obj_t *obj;
+       uint32_t minttl, maxttl;
+
+       /*
+        * The deleg DB cache is preserved if reconfiguring/reloading the
+        * server.
+        */
+       if (pview != NULL) {
+               dns_delegdb_attach(pview->deleg, &view->deleg);
+       } else {
+               dns_delegdb_create(&view->deleg);
+       }
+
+       obj = NULL;
+       result = named_config_get(maps, "min-delegation-ttl", &obj);
+       INSIST(result == ISC_R_SUCCESS);
+       minttl = cfg_obj_asduration(obj);
+
+       obj = NULL;
+       result = named_config_get(maps, "max-delegation-ttl", &obj);
+       INSIST(result == ISC_R_SUCCESS);
+       maxttl = cfg_obj_asduration(obj);
+
+       if (minttl != 0 && maxttl != 0 && minttl >= maxttl) {
+               isc_log_write(
+                       NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
+                       ISC_LOG_ERROR,
+                       "When 'min-delegation-ttl' and 'max-delegation-ttl' "
+                       "are both positive, 'min-delegation-ttl' must be "
+                       "strictly less than 'max-delegation-ttl'");
+               result = ISC_R_RANGE;
+       } else {
+               dns_delegdb_config_t config = { .dbsize = cachesz,
+                                               .minttl = minttl,
+                                               .maxttl = maxttl };
+               dns_delegdb_setconfig(view->deleg, &config);
+       }
+
+       return result;
+}
+
 static const char *const response_synonyms[] = { "response", NULL };
 
 /*
@@ -4321,24 +4366,14 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
                                      dispatch4, dispatch6));
 
        /*
-        * The deleg DB cache is preserved if reconfiguring/reloading the
-        * server.
-        */
-       if (pview != NULL) {
-               dns_delegdb_attach(pview->deleg, &view->deleg);
-       } else {
-               dns_delegdb_create(&view->deleg);
-       }
-       dns_delegdb_setconfig(
-               view->deleg,
-               &(dns_delegdb_config_t){ .dbsize = cache_size_slice });
-
-       /*
-        * The previous view isn't needed anymore.
+        * Configure delegdb and detatch the previous viw which isn't needed
+        * afterwards.
         */
+       result = configure_view_delegdb(maps, pview, view, cache_size_slice);
        if (pview != NULL) {
                dns_view_detach(&pview);
        }
+       CHECK(result);
 
        if (resstats == NULL) {
                isc_stats_create(mctx, &resstats, dns_resstatscounter_max);
index e940b27003bc096ee3ab69ae70478a8dd85e4727..b6dd7f7429c53e16c7628551b1bc65820fe81d7e 100644 (file)
@@ -10,6 +10,10 @@ options {
        disable-empty-zone 127.IN-ADDR.ARPA;
        recursion yes;
        dnssec-validation no;
+
+       // lame-and-expire-soon domain NS has a TTL of 2 seconds,
+       // so let's use a lower value here.
+       min-delegation-ttl 1;
 };
 
 
diff --git a/bin/tests/system/checkconf/bad-delegation-ttl-1.conf b/bin/tests/system/checkconf/bad-delegation-ttl-1.conf
new file mode 100644 (file)
index 0000000..38d9708
--- /dev/null
@@ -0,0 +1,3 @@
+options {
+       min-delegation-ttl "0";
+};
diff --git a/bin/tests/system/checkconf/bad-delegation-ttl-2.conf b/bin/tests/system/checkconf/bad-delegation-ttl-2.conf
new file mode 100644 (file)
index 0000000..f05e6b5
--- /dev/null
@@ -0,0 +1,4 @@
+options {
+       min-delegation-ttl 6;
+       max-delegation-ttl 5;
+};
diff --git a/bin/tests/system/checkconf/good-delegation-ttl-1.conf b/bin/tests/system/checkconf/good-delegation-ttl-1.conf
new file mode 100644 (file)
index 0000000..0d02851
--- /dev/null
@@ -0,0 +1,9 @@
+options {
+       min-delegation-ttl 50;
+       max-delegation-ttl 60;
+};
+
+view foo {
+       min-delegation-ttl 4;
+       max-delegation-ttl 5;
+};
diff --git a/bin/tests/system/checkconf/good-delegation-ttl-2.conf b/bin/tests/system/checkconf/good-delegation-ttl-2.conf
new file mode 100644 (file)
index 0000000..6d997cb
--- /dev/null
@@ -0,0 +1,9 @@
+options {
+       min-delegation-ttl 50;
+       max-delegation-ttl 0;
+};
+
+view foo {
+       min-delegation-ttl 4;
+       max-delegation-ttl 0;
+};
index cbcc8b8145a4b09c3eb0c3ebb6893ac71d5133eb..3b536d05f6f811908a9fdfe9d03ee0a92abc6edc 100644 (file)
@@ -15,6 +15,10 @@ options {
        dnssec-validation no;
        disable-empty-zone 10.in-addr.arpa;
        fetches-per-zone 40;
+
+       // Some domains in this tests have TTL of 2, so let's pick
+       // a value below it.
+       min-delegation-ttl 1;
 };
 
 key rndc_key {
index 9e9ced09354088ef3aa63ed72aa7058de435b0e2..ad62661284068cad39470ea0d51ca25b5ad17a98 100644 (file)
@@ -16,6 +16,11 @@ options {
        request-nsid yes;
        request-zoneversion yes;
        minimal-any no;
+
+       // "checking that removal of a delegation is honoured"
+       // test has a delegation with a TTL of 5 seconds, so let's
+       // min a min below it.
+       min-delegation-ttl 3;
 };
 
 // Don't break tests which depend on ans10 by requesting
index e28b83c7f0cde868053f21033a6aeefd6004a814..8009fffd81c002cbbdaf161c1fbb2ddafe7deabb 100644 (file)
@@ -4199,6 +4199,18 @@ Tuning
    exceed 90 seconds and is truncated to 90 seconds if set to a greater
    value.
 
+.. namedconf:statement:: min-delegation-ttl
+   :tags: server
+   :short: Configure the minimum time (in seconds) that the server caches delegations.
+
+   This sets the minimum time for which the server caches nameserver names and
+   glues for a delegation, in seconds. For convenience, TTL-style time-unit
+   suffixes may be used to specify the value. It also accepts ISO 8601 duration
+   formats.
+
+   Setting a value of ``0`` disable the minimum check TTL for delegations. The
+   default :any:`min-delegation-ttl` is ``60`` seconds.
+
 .. namedconf:statement:: max-delegation-servers
    :tags: server
    :short: Configure the maximum number of nameservers considered for a delegation
@@ -4259,6 +4271,18 @@ Tuning
    all queries to return SERVFAIL, because of lost caches of intermediate RRsets
    (such as NS and glue AAAA/A records) in the resolution process.
 
+.. namedconf:statement:: max-delegation-ttl
+   :tags: server
+   :short: Configure the maximum time (in seconds) that the server caches delegations.
+
+   This sets the maximum time for which the server caches nameserver names and
+   glues for a delegation, in seconds. For convenience, TTL-style time-unit
+   suffixes may be used to specify the value. It also accepts ISO 8601 duration
+   formats.
+
+   Setting a value of ``0`` disable the maximum TTL check for delegations. The
+   default :any:`max-delegation-ttl` is ``0``.
+
 .. namedconf:statement:: max-stale-ttl
    :tags: server
    :short: Specifies the maximum time that the server retains records past their normal expiry, to return them as stale records.
index 8303cdf98cdc60494d6e87cc26b0d570b4c61fd2..db0242d286e00da53007b2fb122732ff6a2cb4c2 100644 (file)
@@ -174,6 +174,7 @@ options {
        max-cache-ttl <duration>;
        max-clients-per-query <integer>;
        max-delegation-servers <integer>; // experimental
+       max-delegation-ttl <duration>;
        max-ixfr-ratio ( unlimited | <percentage> );
        max-journal-size ( default | unlimited | <sizeval> );
        max-ncache-ttl <duration>;
@@ -200,6 +201,7 @@ options {
        memstatistics-file <quoted_string>;
        message-compression <boolean>;
        min-cache-ttl <duration>;
+       min-delegation-ttl <duration>;
        min-ncache-ttl <duration>;
        min-refresh-time <integer>;
        min-retry-time <integer>;
@@ -569,6 +571,7 @@ view <string> [ <class> ] {
        max-cache-ttl <duration>;
        max-clients-per-query <integer>;
        max-delegation-servers <integer>; // experimental
+       max-delegation-ttl <duration>;
        max-ixfr-ratio ( unlimited | <percentage> );
        max-journal-size ( default | unlimited | <sizeval> );
        max-ncache-ttl <duration>;
@@ -592,6 +595,7 @@ view <string> [ <class> ] {
        max-zone-ttl ( unlimited | <duration> ); // deprecated
        message-compression <boolean>;
        min-cache-ttl <duration>;
+       min-delegation-ttl <duration>;
        min-ncache-ttl <duration>;
        min-refresh-time <integer>;
        min-retry-time <integer>;
index edcf039ab531284d961096963901aeeaf5895786..5f11fc0f3e4e97c0ccb0f2f1154366a01461a31a 100644 (file)
@@ -1178,6 +1178,34 @@ check_port(const cfg_obj_t *options, const char *type, in_port_t *portp) {
        return ISC_R_SUCCESS;
 }
 
+static isc_result_t
+check_delegation_ttl(const cfg_obj_t *options) {
+       uint32_t min = 0, max = 0;
+       const cfg_obj_t *obj = NULL;
+
+       (void)cfg_map_get(options, "min-delegation-ttl", &obj);
+       if (obj != NULL) {
+               min = cfg_obj_asduration(obj);
+       }
+
+       obj = NULL;
+       (void)cfg_map_get(options, "max-delegation-ttl", &obj);
+       if (obj != NULL) {
+               max = cfg_obj_asduration(obj);
+       }
+
+       if (min != 0 && max != 0 && min >= max) {
+               cfg_obj_log(
+                       obj, ISC_LOG_ERROR,
+                       "When 'min-delegation-ttl' and 'max-delegation-ttl' "
+                       "are both positive, 'min-delegation-ttl' must be "
+                       "strictly less than 'max-delegation-ttl'");
+               return ISC_R_RANGE;
+       }
+
+       return ISC_R_SUCCESS;
+}
+
 static isc_result_t
 check_options(const cfg_obj_t *options, const cfg_obj_t *config,
              bool check_algorithms, isc_mem_t *mctx, optlevel_t optlevel) {
@@ -1282,6 +1310,11 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config,
                                }
                        }
                }
+
+               tresult = check_delegation_ttl(options);
+               if (tresult != ISC_R_SUCCESS) {
+                       result = tresult;
+               }
        }
 
        /*
index 30c3a7857e16c016a942c602c8b39aa2a87718e1..d96f66fc5055c9d45e74c4777802627bb112628c 100644 (file)
@@ -2393,6 +2393,7 @@ static cfg_clausedef_t view_clauses[] = {
        { "max-acache-size", NULL, CFG_CLAUSEFLAG_ANCIENT, NULL },
        { "max-cache-size", &cfg_type_maxcachesize, 0, NULL },
        { "max-cache-ttl", &cfg_type_duration, 0, NULL },
+       { "max-delegation-ttl", &cfg_type_duration, 0, NULL },
        { "max-clients-per-query", &cfg_type_uint32, 0, NULL },
        { "max-delegation-servers", &cfg_type_uint32,
          CFG_CLAUSEFLAG_EXPERIMENTAL, NULL },
@@ -2409,6 +2410,7 @@ static cfg_clausedef_t view_clauses[] = {
          CFG_CLAUSEFLAG_EXPERIMENTAL, NULL },
        { "message-compression", &cfg_type_boolean, 0, NULL },
        { "min-cache-ttl", &cfg_type_duration, 0, NULL },
+       { "min-delegation-ttl", &cfg_type_duration, 0, NULL },
        { "min-ncache-ttl", &cfg_type_duration, 0, NULL },
        { "min-roots", NULL, CFG_CLAUSEFLAG_ANCIENT, NULL },
        { "minimal-any", &cfg_type_boolean, 0, NULL },