diff --git a/CHANGES b/CHANGES index 0f7ed65ff9..5a036e684b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +5662. [bug] Views with recursion disabled are now configured with a + default cache size of 2 MB, unless "max-cache-size" is + explicitly set. This prevents cache RBT hash tables from + being needlessly preallocated for such views. [GL #2777] + 5661. [bug] A deadlock was introduced when fixing [GL #1875] because when locking the key file mutex for each zone structure that is in a different view, "in-view" logic was not diff --git a/bin/named/config.c b/bin/named/config.c index 7e4757a4fe..10087b47f3 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -263,6 +263,7 @@ view \"_bind\" chaos {\n\ recursion no;\n\ notify no;\n\ allow-new-zones no;\n\ + max-cache-size 2M;\n\ \n\ # Prevent use of this zone in DNS amplified reflection DoS attacks\n\ rate-limit {\n\ diff --git a/bin/named/server.c b/bin/named/server.c index ba0757348e..b426c94be2 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -3971,6 +3971,42 @@ register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj, return (result); } +/* + * Determine if a minimal-sized cache can be used for a given view, according + * to 'maps' (implicit defaults, global options, view options) and 'optionmaps' + * (global options, view options). This is only allowed for views which have + * recursion disabled and do not have "max-cache-size" set explicitly. Using + * minimal-sized caches prevents a situation in which all explicitly configured + * and built-in views inherit the default "max-cache-size 90%;" setting, which + * could lead to memory exhaustion with multiple views configured. + */ +static bool +minimal_cache_allowed(const cfg_obj_t *maps[4], + const cfg_obj_t *optionmaps[3]) { + const cfg_obj_t *obj; + + /* + * Do not use a minimal-sized cache for a view with recursion enabled. + */ + obj = NULL; + (void)named_config_get(maps, "recursion", &obj); + INSIST(obj != NULL); + if (cfg_obj_asboolean(obj)) { + return (false); + } + + /* + * Do not use a minimal-sized cache if a specific size was requested. + */ + obj = NULL; + (void)named_config_get(optionmaps, "max-cache-size", &obj); + if (obj != NULL) { + return (false); + } + + return (true); +} + /* * Configure 'view' according to 'vconfig', taking defaults from * 'config' where values are missing in 'vconfig'. @@ -4236,6 +4272,12 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, */ if (named_g_maxcachesize != 0) { max_cache_size = named_g_maxcachesize; + } else if (minimal_cache_allowed(maps, optionmaps)) { + /* + * dns_cache_setcachesize() will adjust this to the smallest + * allowed value. + */ + max_cache_size = 1; } else if (cfg_obj_isstring(obj)) { str = cfg_obj_asstring(obj); INSIST(strcasecmp(str, "unlimited") == 0);