2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 06:25:31 +00:00

preserve cache across reload when using attach-cache

when the attach-cache option is used in the options block
with an arbitrary name, it causes all views to use the same
cache. however, previously, this could cause the cache to be
deleted and a new cache created every time the server was
reconfigured. this did *not* occur when attach-cache was
used at the view level to refer back to another view's cache.

in this commit we correct the problem by checking for
pre-existing caches during reconfiguration, and moving
them from the old server cache list to the new cache list
before cleaning up and freeing the old cache list.
This commit is contained in:
Evan Hunt
2024-11-27 00:35:16 -08:00
parent de6f199f4d
commit f3af8a7dc3
3 changed files with 109 additions and 73 deletions

View File

@@ -1827,9 +1827,7 @@ setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
static named_cache_t *
cachelist_find(named_cachelist_t *cachelist, const char *cachename,
dns_rdataclass_t rdclass) {
named_cache_t *nsc;
for (nsc = ISC_LIST_HEAD(*cachelist); nsc != NULL;
for (named_cache_t *nsc = ISC_LIST_HEAD(*cachelist); nsc != NULL;
nsc = ISC_LIST_NEXT(nsc, link))
{
if (nsc->rdclass == rdclass &&
@@ -1847,12 +1845,13 @@ cache_reusable(dns_view_t *originview, dns_view_t *view,
bool new_zero_no_soattl) {
if (originview->rdclass != view->rdclass ||
originview->checknames != view->checknames ||
dns_resolver_getzeronosoattl(originview->resolver) !=
new_zero_no_soattl ||
originview->acceptexpired != view->acceptexpired ||
originview->enablevalidation != view->enablevalidation ||
originview->maxcachettl != view->maxcachettl ||
originview->maxncachettl != view->maxncachettl)
originview->maxncachettl != view->maxncachettl ||
originview->resolver == NULL ||
dns_resolver_getzeronosoattl(originview->resolver) !=
new_zero_no_soattl)
{
return false;
}
@@ -3807,9 +3806,9 @@ static const char *const response_synonyms[] = { "response", NULL };
static isc_result_t
configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
cfg_obj_t *vconfig, named_cachelist_t *cachelist,
dns_kasplist_t *kasplist, dns_keystorelist_t *keystores,
const cfg_obj_t *bindkeys, isc_mem_t *mctx,
cfg_aclconfctx_t *actx, bool need_hints) {
named_cachelist_t *oldcachelist, dns_kasplist_t *kasplist,
dns_keystorelist_t *keystores, const cfg_obj_t *bindkeys,
isc_mem_t *mctx, cfg_aclconfctx_t *actx, bool need_hints) {
const cfg_obj_t *maps[4];
const cfg_obj_t *cfgmaps[3];
const cfg_obj_t *optionmaps[3];
@@ -3861,7 +3860,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
isc_stats_t *resstats = NULL;
dns_stats_t *resquerystats = NULL;
bool auto_root = false;
named_cache_t *nsc;
named_cache_t *nsc = NULL;
bool zero_no_soattl;
dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
unsigned int query_timeout;
@@ -3870,6 +3869,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
dns_ntatable_t *ntatable = NULL;
const char *qminmode = NULL;
dns_adb_t *adb = NULL;
bool oldcache = false;
REQUIRE(DNS_VIEW_VALID(view));
@@ -4419,81 +4419,94 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
} else {
cachename = view->name;
}
cache = NULL;
nsc = cachelist_find(cachelist, cachename, view->rdclass);
if (result == ISC_R_SUCCESS && nsc == NULL) {
/*
* If we're using 'attach-cache' but didn't find the
* specified cache in the cache list already, check
* the old list.
*/
nsc = cachelist_find(oldcachelist, cachename, view->rdclass);
oldcache = true;
}
if (nsc != NULL) {
if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
max_cache_size, max_stale_ttl,
stale_refresh_time))
{
isc_log_write(NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
"views %s and %s can't share the cache "
"due to configuration parameter mismatch",
nsc->primaryview->name, view->name);
result = ISC_R_FAILURE;
NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
"view %s can't use existing cache %s due "
"to configuration parameter mismatch",
view->name,
dns_cache_getname(nsc->cache));
nsc = NULL;
} else {
if (oldcache) {
ISC_LIST_UNLINK(*oldcachelist, nsc, link);
ISC_LIST_APPEND(*cachelist, nsc, link);
nsc->primaryview = view;
}
dns_cache_attach(nsc->cache, &cache);
shared_cache = true;
}
} else if (strcmp(cachename, view->name) == 0) {
result = dns_viewlist_find(&named_g_server->viewlist, cachename,
view->rdclass, &pview);
if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
goto cleanup;
}
dns_cache_attach(nsc->cache, &cache);
shared_cache = true;
} else {
if (strcmp(cachename, view->name) == 0) {
result = dns_viewlist_find(&named_g_server->viewlist,
cachename, view->rdclass,
&pview);
if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
{
goto cleanup;
}
if (pview != NULL) {
if (!cache_reusable(pview, view,
zero_no_soattl))
{
isc_log_write(NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER,
ISC_LOG_DEBUG(1),
"cache cannot be reused "
"for view %s due to "
"configuration parameter "
"mismatch",
view->name);
} else {
INSIST(pview->cache != NULL);
isc_log_write(NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER,
ISC_LOG_DEBUG(3),
"reusing existing cache");
dns_cache_attach(pview->cache, &cache);
}
dns_resolver_getstats(pview->resolver,
&resstats);
dns_resolver_getquerystats(pview->resolver,
&resquerystats);
dns_view_detach(&pview);
if (pview != NULL) {
if (!cache_reusable(pview, view, zero_no_soattl)) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER,
ISC_LOG_DEBUG(1),
"cache cannot be reused "
"for view %s due to "
"configuration parameter "
"mismatch",
view->name);
} else {
INSIST(pview->cache != NULL);
isc_log_write(NAMED_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER,
ISC_LOG_DEBUG(3),
"reusing existing cache");
dns_cache_attach(pview->cache, &cache);
}
dns_resolver_getstats(pview->resolver, &resstats);
dns_resolver_getquerystats(pview->resolver,
&resquerystats);
dns_view_detach(&pview);
}
}
if (nsc == NULL) {
/*
* Create a cache with the desired name. This normally
* equals the view name, but may also be a forward
* reference to a view that share the cache with this
* view but is not yet configured. If it is not the
* view name but not a forward reference either, then it
* is simply a named cache that is not shared.
*/
if (cache == NULL) {
/*
* Create a cache with the desired name. This normally
* equals the view name, but may also be a forward
* reference to a view that share the cache with this
* view but is not yet configured. If it is not the
* view name but not a forward reference either, then it
* is simply a named cache that is not shared.
*/
CHECK(dns_cache_create(named_g_loopmgr, view->rdclass,
cachename, mctx, &cache));
}
nsc = isc_mem_get(mctx, sizeof(*nsc));
nsc->cache = NULL;
*nsc = (named_cache_t){
.primaryview = view,
.rdclass = view->rdclass,
.link = ISC_LINK_INITIALIZER,
};
dns_cache_attach(cache, &nsc->cache);
nsc->primaryview = view;
nsc->needflush = false;
nsc->adbsizeadjusted = false;
nsc->rdclass = view->rdclass;
ISC_LINK_INIT(nsc, link);
ISC_LIST_APPEND(*cachelist, nsc, link);
}
dns_view_setcache(view, cache, shared_cache);
dns_cache_setcachesize(cache, max_cache_size);
@@ -7944,8 +7957,7 @@ load_configuration(const char *filename, named_server_t *server,
dns_keystore_t *keystore = NULL;
dns_keystore_t *keystore_next = NULL;
dns_keystorelist_t tmpkeystorelist, keystorelist;
const cfg_obj_t *views;
const cfg_obj_t *views = NULL;
dns_view_t *view_next = NULL;
dns_viewlist_t tmpviewlist;
dns_viewlist_t viewlist, builtin_viewlist;
@@ -7963,7 +7975,7 @@ load_configuration(const char *filename, named_server_t *server,
uint32_t send_tcp_buffer_size;
uint32_t recv_udp_buffer_size;
uint32_t send_udp_buffer_size;
named_cache_t *nsc;
named_cache_t *nsc = NULL;
named_cachelist_t cachelist, tmpcachelist;
ns_altsecret_t *altsecret;
ns_altsecretlist_t altsecrets, tmpaltsecrets;
@@ -8819,7 +8831,8 @@ load_configuration(const char *filename, named_server_t *server,
}
result = configure_view(view, &viewlist, config, vconfig,
&cachelist, &server->kasplist,
&cachelist, &server->cachelist,
&server->kasplist,
&server->keystorelist, bindkeys,
named_g_mctx, named_g_aclconfctx, true);
if (result != ISC_R_SUCCESS) {
@@ -8841,7 +8854,8 @@ load_configuration(const char *filename, named_server_t *server,
goto cleanup_cachelist;
}
result = configure_view(view, &viewlist, config, NULL,
&cachelist, &server->kasplist,
&cachelist, &server->cachelist,
&server->kasplist,
&server->keystorelist, bindkeys,
named_g_mctx, named_g_aclconfctx, true);
if (result != ISC_R_SUCCESS) {
@@ -8871,8 +8885,9 @@ load_configuration(const char *filename, named_server_t *server,
result = configure_view(
view, &viewlist, config, vconfig, &cachelist,
&server->kasplist, &server->keystorelist, bindkeys,
named_g_mctx, named_g_aclconfctx, false);
&server->cachelist, &server->kasplist,
&server->keystorelist, bindkeys, named_g_mctx,
named_g_aclconfctx, false);
if (result != ISC_R_SUCCESS) {
dns_view_detach(&view);
goto cleanup_cachelist;

View File

@@ -73,6 +73,13 @@ view "default" {
};
};
view "alternative" {
zone "." {
type hint;
file "root.hint";
};
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;

View File

@@ -985,5 +985,19 @@ grep "response: should.not.be.logged" ns6/named.run >/dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
n=$((n + 1))
echo_i "check that attach-cache with arbitrary cache name is preserved across reload ($n)"
ret=0
# send a query, wait a second, reload the configuration, and query again.
# the TTL should indicate that the cache was still populated.
dig_with_opts +noall +answer @10.53.0.1 www.example.org >/dev/null || ret=1
sleep 1
rndc_reload ns1 10.53.0.1
dig_with_opts +noall +answer @10.53.0.1 www.example.org >dig.ns1.out.${n} || ret=1
ttl=$(awk '{print $2}' dig.ns1.out.${n})
[ $ttl -lt 300 ] || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1