diff --git a/bin/named/config.c b/bin/named/config.c index 3b15ad2974..039d2632b4 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -174,6 +174,8 @@ options {\n\ max-recursion-queries 75;\n\ max-stale-ttl 604800; /* 1 week */\n\ message-compression yes;\n\ + min-ncache-ttl 0; /* 0 hours */\n\ + min-cache-ttl 0; /* 0 seconds */\n\ # min-roots ;\n\ minimal-any false;\n\ minimal-responses no-auth-recursive;\n\ diff --git a/bin/named/server.c b/bin/named/server.c index ee75c1b3b7..05964c2227 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -4117,8 +4117,16 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, result = named_config_get(maps, "max-ncache-ttl", &obj); INSIST(result == ISC_R_SUCCESS); view->maxncachettl = cfg_obj_asuint32(obj); - if (view->maxncachettl > 7 * 24 * 3600) - view->maxncachettl = 7 * 24 * 3600; + + obj = NULL; + result = named_config_get(maps, "min-cache-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + view->mincachettl = cfg_obj_asuint32(obj); + + obj = NULL; + result = named_config_get(maps, "min-ncache-ttl", &obj); + INSIST(result == ISC_R_SUCCESS); + view->minncachettl = cfg_obj_asuint32(obj); obj = NULL; result = named_config_get(maps, "synth-from-dnssec", &obj); diff --git a/bin/tests/named.conf b/bin/tests/named.conf index 5673e982ca..c9be056e77 100644 --- a/bin/tests/named.conf +++ b/bin/tests/named.conf @@ -46,6 +46,7 @@ options { memstatistics-file "named.memstats"; // _PATH_MEMSTATS max-cache-ttl 999; + min-cache-ttl 66; auth-nxdomain yes; // always set AA on NXDOMAIN. // don't set this to 'no' unless // you know what you're doing -- older @@ -148,6 +149,7 @@ options { min-refresh-time 777; max-ncache-ttl 333; + min-ncache-ttl 22; min-roots 15; serial-queries 34; diff --git a/lib/bind9/check.c b/lib/bind9/check.c index cdbc7270e4..b3098938a6 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -954,15 +954,25 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx, uint32_t lifetime = 3600; const char *ccalg = "aes"; + /* + * { "name", scale, value } + * (scale * value) <= UINT32_MAX + */ static intervaltable intervals[] = { - { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */ - { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */ - { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */ - { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */ - { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */ - { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */ - { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */ - { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */ + { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */ + { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */ + { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */ + { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */ + { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */ + { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */ + { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */ + { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */ + + /* minimum and maximum cache and negative cache TTLs */ + { "min-cache-ttl", 1, MAX_MIN_CACHE_TTL }, /* 90 secs */ + { "max-cache-ttl", 1, UINT32_MAX }, /* no limit */ + { "min-ncache-ttl", 1, MAX_MIN_NCACHE_TTL}, /* 90 secs */ + { "max-ncache-ttl", 1, MAX_MAX_NCACHE_TTL }, /* 7 days */ }; static const char *server_contact[] = { diff --git a/lib/bind9/include/bind9/check.h b/lib/bind9/include/bind9/check.h index f796e268ed..92d4bdda71 100644 --- a/lib/bind9/include/bind9/check.h +++ b/lib/bind9/include/bind9/check.h @@ -20,6 +20,18 @@ #include +#ifndef MAX_MIN_CACHE_TTL +#define MAX_MIN_CACHE_TTL 90 +#endif /* MAX_MIN_CACHE_TTL */ + +#ifndef MAX_MIN_NCACHE_TTL +#define MAX_MIN_NCACHE_TTL 90 +#endif /* MAX_MIN_NCACHE_TTL */ + +#ifndef MAX_MAX_NCACHE_TTL +#define MAX_MAX_NCACHE_TTL 7 * 24 * 3600 +#endif /* MAX_MAX_NCACHE_TTL */ + ISC_LANG_BEGINDECLS isc_result_t diff --git a/lib/dns/include/dns/ncache.h b/lib/dns/include/dns/ncache.h index 2942c26e97..c2e1e7be53 100644 --- a/lib/dns/include/dns/ncache.h +++ b/lib/dns/include/dns/ncache.h @@ -56,12 +56,14 @@ ISC_LANG_BEGINDECLS isc_result_t dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, - dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, + dns_rdatatype_t covers, isc_stdtime_t now, + dns_ttl_t minttl, dns_ttl_t maxttl, dns_rdataset_t *addedrdataset); isc_result_t dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, - isc_stdtime_t now, dns_ttl_t maxttl, + isc_stdtime_t now, + dns_ttl_t minttl, dns_ttl_t maxttl, bool optout, dns_rdataset_t *addedrdataset); /*%< * Convert the authority data from 'message' into a negative cache diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index c8c7f25536..ad626593c0 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -154,6 +154,8 @@ struct dns_view { bool sendcookie; dns_ttl_t maxcachettl; dns_ttl_t maxncachettl; + dns_ttl_t mincachettl; + dns_ttl_t minncachettl; uint32_t nta_lifetime; uint32_t nta_recheck; char *nta_file; diff --git a/lib/dns/ncache.c b/lib/dns/ncache.c index 79bb5f1b76..1f060a4abc 100644 --- a/lib/dns/ncache.c +++ b/lib/dns/ncache.c @@ -45,7 +45,8 @@ static isc_result_t addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, - dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, + dns_rdatatype_t covers, isc_stdtime_t now, + dns_ttl_t minttl, dns_ttl_t maxttl, bool optout, bool secure, dns_rdataset_t *addedrdataset); @@ -95,26 +96,29 @@ copy_rdataset(dns_rdataset_t *rdataset, isc_buffer_t *buffer) { isc_result_t dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, - dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, + dns_rdatatype_t covers, isc_stdtime_t now, + dns_ttl_t minttl, dns_ttl_t maxttl, dns_rdataset_t *addedrdataset) { - return (addoptout(message, cache, node, covers, now, maxttl, + return (addoptout(message, cache, node, covers, now, minttl, maxttl, false, false, addedrdataset)); } isc_result_t dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, - isc_stdtime_t now, dns_ttl_t maxttl, + isc_stdtime_t now, + dns_ttl_t minttl, dns_ttl_t maxttl, bool optout, dns_rdataset_t *addedrdataset) { - return (addoptout(message, cache, node, covers, now, maxttl, + return (addoptout(message, cache, node, covers, now, minttl, maxttl, optout, true, addedrdataset)); } static isc_result_t addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, - dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, + dns_rdatatype_t covers, isc_stdtime_t now, + dns_ttl_t minttl, dns_ttl_t maxttl, bool optout, bool secure, dns_rdataset_t *addedrdataset) { @@ -179,10 +183,15 @@ addoptout(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, if (type == dns_rdatatype_soa || type == dns_rdatatype_nsec || type == dns_rdatatype_nsec3) { - if (ttl > rdataset->ttl) + if (ttl > rdataset->ttl) { ttl = rdataset->ttl; - if (trust > rdataset->trust) + } + if (ttl < minttl) { + ttl = minttl; + } + if (trust > rdataset->trust) { trust = rdataset->trust; + } /* * Copy the owner name to the buffer. */ diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 7ecd6ffbe9..c3f9b39c25 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -592,7 +592,9 @@ static bool fctx_unlink(fetchctx_t *fctx); static isc_result_t ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, - isc_stdtime_t now, dns_ttl_t maxttl, + isc_stdtime_t now, + dns_ttl_t minttl, + dns_ttl_t maxttl, bool optout, bool secure, dns_rdataset_t *ardataset, @@ -5464,8 +5466,10 @@ validated(isc_task_t *task, isc_event_t *event) { ttl = 0; result = ncache_adderesult(fctx->rmessage, fctx->cache, node, - covers, now, ttl, vevent->optout, - vevent->secure, ardataset, &eresult); + covers, now, + fctx->res->view->minncachettl, ttl, + vevent->optout, vevent->secure, + ardataset, &eresult); if (result != ISC_R_SUCCESS) goto noanswer_response; goto answer_response; @@ -5958,6 +5962,13 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, rdataset->ttl = res->view->maxcachettl; } + /* + * Enforce configured minimum cache TTL. + */ + if (rdataset->ttl < res->view->mincachettl) { + rdataset->ttl = res->view->mincachettl; + } + /* * Mark the rdataset as being prefetch eligible. */ @@ -6346,7 +6357,8 @@ cache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, isc_stdtime_t now) */ static isc_result_t ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, - dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, + dns_rdatatype_t covers, isc_stdtime_t now, + dns_ttl_t minttl, dns_ttl_t maxttl, bool optout, bool secure, dns_rdataset_t *ardataset, isc_result_t *eresultp) { @@ -6359,10 +6371,10 @@ ncache_adderesult(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, } if (secure) result = dns_ncache_addoptout(message, cache, node, covers, - now, maxttl, optout, ardataset); + now, minttl, maxttl, optout, ardataset); else result = dns_ncache_add(message, cache, node, covers, now, - maxttl, ardataset); + minttl, maxttl, ardataset); if (result == DNS_R_UNCHANGED || result == ISC_R_SUCCESS) { /* * If the cache now contains a negative entry and we @@ -6537,8 +6549,9 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, ttl = 0; result = ncache_adderesult(fctx->rmessage, fctx->cache, node, - covers, now, ttl, false, - false, ardataset, &eresult); + covers, now, + fctx->res->view->minncachettl, ttl, + false, false, ardataset, &eresult); if (result != ISC_R_SUCCESS) goto unlock; diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 7467b6af39..15ab4e580b 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -1929,6 +1929,8 @@ view_clauses[] = { { "max-stale-ttl", &cfg_type_ttlval, 0 }, { "max-udp-size", &cfg_type_uint32, 0 }, { "message-compression", &cfg_type_boolean, 0 }, + { "min-cache-ttl", &cfg_type_ttlval, 0 }, + { "min-ncache-ttl", &cfg_type_ttlval, 0 }, { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, { "minimal-any", &cfg_type_boolean, 0 }, { "minimal-responses", &cfg_type_minimal, 0 },