From: Colin Vidal Date: Tue, 26 May 2026 13:58:44 +0000 (+0200) Subject: Delegations have a minimal TTL of 60 seconds X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=ff274e37af36e0d3f93d0e2f9691fde7b0c2ef5c;p=thirdparty%2Fbind9.git Delegations have a minimal TTL of 60 seconds 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. --- diff --git a/bin/include/defaultconfig.h b/bin/include/defaultconfig.h index 46942971199..a66ec87a8f2 100644 --- a/bin/include/defaultconfig.h +++ b/bin/include/defaultconfig.h @@ -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\ diff --git a/bin/named/server.c b/bin/named/server.c index e5ffb7ede2a..ae03bb151c2 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -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); diff --git a/bin/tests/system/cacheclean/ns2/named.conf.j2 b/bin/tests/system/cacheclean/ns2/named.conf.j2 index e940b27003b..b6dd7f7429c 100644 --- a/bin/tests/system/cacheclean/ns2/named.conf.j2 +++ b/bin/tests/system/cacheclean/ns2/named.conf.j2 @@ -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 index 00000000000..38d9708406a --- /dev/null +++ b/bin/tests/system/checkconf/bad-delegation-ttl-1.conf @@ -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 index 00000000000..f05e6b5c312 --- /dev/null +++ b/bin/tests/system/checkconf/bad-delegation-ttl-2.conf @@ -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 index 00000000000..0d028514bd9 --- /dev/null +++ b/bin/tests/system/checkconf/good-delegation-ttl-1.conf @@ -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 index 00000000000..6d997cbac6f --- /dev/null +++ b/bin/tests/system/checkconf/good-delegation-ttl-2.conf @@ -0,0 +1,9 @@ +options { + min-delegation-ttl 50; + max-delegation-ttl 0; +}; + +view foo { + min-delegation-ttl 4; + max-delegation-ttl 0; +}; diff --git a/bin/tests/system/qmin/ns5/named.conf.j2 b/bin/tests/system/qmin/ns5/named.conf.j2 index cbcc8b8145a..3b536d05f6f 100644 --- a/bin/tests/system/qmin/ns5/named.conf.j2 +++ b/bin/tests/system/qmin/ns5/named.conf.j2 @@ -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 { diff --git a/bin/tests/system/resolver/ns5/named.conf.j2 b/bin/tests/system/resolver/ns5/named.conf.j2 index 9e9ced09354..ad626612840 100644 --- a/bin/tests/system/resolver/ns5/named.conf.j2 +++ b/bin/tests/system/resolver/ns5/named.conf.j2 @@ -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 diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index e28b83c7f0c..8009fffd81c 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -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. diff --git a/doc/misc/options b/doc/misc/options index 8303cdf98cd..db0242d286e 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -174,6 +174,7 @@ options { max-cache-ttl ; max-clients-per-query ; max-delegation-servers ; // experimental + max-delegation-ttl ; max-ixfr-ratio ( unlimited | ); max-journal-size ( default | unlimited | ); max-ncache-ttl ; @@ -200,6 +201,7 @@ options { memstatistics-file ; message-compression ; min-cache-ttl ; + min-delegation-ttl ; min-ncache-ttl ; min-refresh-time ; min-retry-time ; @@ -569,6 +571,7 @@ view [ ] { max-cache-ttl ; max-clients-per-query ; max-delegation-servers ; // experimental + max-delegation-ttl ; max-ixfr-ratio ( unlimited | ); max-journal-size ( default | unlimited | ); max-ncache-ttl ; @@ -592,6 +595,7 @@ view [ ] { max-zone-ttl ( unlimited | ); // deprecated message-compression ; min-cache-ttl ; + min-delegation-ttl ; min-ncache-ttl ; min-refresh-time ; min-retry-time ; diff --git a/lib/isccfg/check.c b/lib/isccfg/check.c index edcf039ab53..5f11fc0f3e4 100644 --- a/lib/isccfg/check.c +++ b/lib/isccfg/check.c @@ -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; + } } /* diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 30c3a7857e1..d96f66fc505 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -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 },