2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 05:57:52 +00:00

chg: dev: parse user configuration before exclusive mode

Previously, `named.conf` was parsed while the server was in exclusive (i.e., single-threaded) mode and unable to answer queries. This could cause an unnecessary delay in query processing when the file was large. We now delay entry into exclusive mode until after the configuration has been parsed, but before it is applied.

Merge branch 'colin/configparse-before-exclusive' into 'main'

See merge request isc-projects/bind9!10418
This commit is contained in:
Colin Vidal 2025-06-24 10:52:11 +02:00
commit b49f83a3e6
14 changed files with 398 additions and 189 deletions

View File

@ -18,6 +18,8 @@
#include <stdlib.h>
#include <isc/buffer.h>
#include <isc/dir.h>
#include <isc/file.h>
#include <isc/log.h>
#include <isc/mem.h>
#include <isc/netmgr.h>
@ -38,6 +40,7 @@
#include <dst/dst.h>
#include <isccfg/check.h>
#include <isccfg/grammar.h>
#include <isccfg/namedconf.h>
@ -369,6 +372,98 @@ named_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf) {
conf);
}
/*
* This function is called as soon as the 'directory' statement has been
* parsed. This can be extended to support other options if necessary.
*/
static isc_result_t
directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
isc_result_t result;
const char *directory;
REQUIRE(strcasecmp("directory", clausename) == 0);
UNUSED(arg);
UNUSED(clausename);
/*
* Change directory.
*/
directory = cfg_obj_asstring(obj);
if (!isc_file_ischdiridempotent(directory)) {
cfg_obj_log(obj, ISC_LOG_WARNING,
"option 'directory' contains relative path '%s'",
directory);
}
if (!isc_file_isdirwritable(directory)) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_ERROR, "directory '%s' is not writable",
directory);
return ISC_R_NOPERM;
}
result = isc_dir_chdir(directory);
if (result != ISC_R_SUCCESS) {
cfg_obj_log(obj, ISC_LOG_ERROR,
"change directory to '%s' failed: %s", directory,
isc_result_totext(result));
return result;
}
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)) == cwd) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_INFO, "the working directory is now '%s'",
cwd);
}
return ISC_R_SUCCESS;
}
isc_result_t
named_config_parsefile(cfg_parser_t *parser, cfg_obj_t **conf) {
isc_result_t result;
REQUIRE(parser);
REQUIRE(conf && *conf == NULL);
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_INFO, "parsing user configuration from '%s'",
named_g_conffile);
cfg_parser_setcallback(parser, directory_callback, NULL);
result = cfg_parse_file(parser, named_g_conffile, &cfg_type_namedconf,
conf);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
/*
* Check the validity of the configuration.
*
* (Ignore plugin parameters for now; they will be
* checked later when the modules are actually loaded and
* registered.)
*/
result = isccfg_check_namedconf(*conf, BIND_CHECK_ALGORITHMS,
named_g_mctx);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
goto out;
cleanup:
if (*conf) {
cfg_obj_destroy(parser, conf);
}
out:
return result;
}
const char *
named_config_getdefault(void) {
return defaultconf;
@ -890,7 +985,7 @@ named_config_getport(const cfg_obj_t *config, const char *type,
if (options != NULL) {
maps[i++] = options;
}
maps[i++] = named_g_defaults;
maps[i++] = named_g_defaultoptions;
maps[i] = NULL;
result = named_config_get(maps, type, &portobj);

View File

@ -252,7 +252,7 @@ named_control_docommand(isccc_sexpr_t *message, bool readonly,
"query logging",
NS_SERVER_LOGQUERIES, lex);
} else if (command_compare(command, NAMED_COMMAND_RECONFIG)) {
result = named_server_reconfigcommand(named_g_server);
result = named_server_reconfigcommand(named_g_server, *text);
} else if (command_compare(command, NAMED_COMMAND_RECURSING)) {
result = named_server_dumprecursing(named_g_server);
} else if (command_compare(command, NAMED_COMMAND_REFRESH)) {

View File

@ -27,6 +27,9 @@
isc_result_t
named_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf);
isc_result_t
named_config_parsefile(cfg_parser_t *parser, cfg_obj_t **conf);
const char *
named_config_getdefault(void);

View File

@ -64,19 +64,19 @@ EXTERN bool named_g_run_done INIT(false);
* for really short timers, another for client timers, and one
* for zone timers.
*/
EXTERN isc_nm_t *named_g_netmgr INIT(NULL);
EXTERN cfg_parser_t *named_g_parser INIT(NULL);
EXTERN cfg_parser_t *named_g_addparser INIT(NULL);
EXTERN const char *named_g_version INIT(PACKAGE_VERSION);
EXTERN const char *named_g_product INIT(PACKAGE_NAME);
EXTERN const char *named_g_description INIT(PACKAGE_DESCRIPTION);
EXTERN const char *named_g_srcid INIT(PACKAGE_SRCID);
EXTERN const char *named_g_configargs INIT(PACKAGE_CONFIGARGS);
EXTERN const char *named_g_builder INIT(PACKAGE_BUILDER);
EXTERN in_port_t named_g_port INIT(0);
EXTERN in_port_t named_g_tlsport INIT(0);
EXTERN in_port_t named_g_httpsport INIT(0);
EXTERN in_port_t named_g_httpport INIT(0);
EXTERN isc_nm_t *named_g_netmgr INIT(NULL);
EXTERN cfg_parser_t *named_g_parser INIT(NULL);
EXTERN cfg_parser_t *named_g_addparser INIT(NULL);
EXTERN const char *named_g_version INIT(PACKAGE_VERSION);
EXTERN const char *named_g_product INIT(PACKAGE_NAME);
EXTERN const char *named_g_description INIT(PACKAGE_DESCRIPTION);
EXTERN const char *named_g_srcid INIT(PACKAGE_SRCID);
EXTERN const char *named_g_defaultconfigargs INIT(PACKAGE_CONFIGARGS);
EXTERN const char *named_g_builder INIT(PACKAGE_BUILDER);
EXTERN in_port_t named_g_port INIT(0);
EXTERN in_port_t named_g_tlsport INIT(0);
EXTERN in_port_t named_g_httpsport INIT(0);
EXTERN in_port_t named_g_httpport INIT(0);
EXTERN in_port_t named_g_http_listener_clients INIT(0);
EXTERN in_port_t named_g_http_streams_per_conn INIT(0);
@ -91,8 +91,8 @@ EXTERN unsigned int named_g_debuglevel INIT(0);
/*
* Current configuration information.
*/
EXTERN cfg_obj_t *named_g_config INIT(NULL);
EXTERN const cfg_obj_t *named_g_defaults INIT(NULL);
EXTERN cfg_obj_t *named_g_defaultconfig INIT(NULL);
EXTERN const cfg_obj_t *named_g_defaultoptions INIT(NULL);
EXTERN const char *named_g_conffile INIT(NAMED_SYSCONFDIR "/named.conf");
EXTERN const char *named_g_defaultbindkeys INIT(NULL);
EXTERN const char *named_g_keyfile INIT(NAMED_SYSCONFDIR "/rndc.key");
@ -126,7 +126,7 @@ EXTERN const char *named_g_defaultpidfile INIT(NAMED_LOCALSTATEDIR "/run/"
EXTERN const char *named_g_username INIT(NULL);
EXTERN isc_time_t named_g_boottime;
EXTERN isc_time_t named_g_configtime;
EXTERN isc_time_t named_g_defaultconfigtime;
EXTERN bool named_g_memstatistics INIT(false);
EXTERN bool named_g_keepstderr INIT(false);

View File

@ -161,7 +161,7 @@ named_server_resetstatscommand(named_server_t *server, isc_lex_t *lex,
*/
isc_result_t
named_server_reconfigcommand(named_server_t *server);
named_server_reconfigcommand(named_server_t *server, isc_buffer_t *text);
/*%<
* Act on a "reconfig" command from the command channel.
*/

View File

@ -1131,7 +1131,7 @@ configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
}
}
maps[i++] = named_g_defaults;
maps[i++] = named_g_defaultoptions;
maps[i] = NULL;
dns_view_initsecroots(view);
@ -1142,7 +1142,8 @@ configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
/*
* If bind.keys exists and is populated, it overrides
* the trust-anchors clause hard-coded in named_g_config.
* the trust-anchors clause hard-coded in
* named_g_defaultconfig.
*/
if (bindkeys != NULL) {
isc_log_write(DNS_LOGCATEGORY_SECURITY,
@ -1170,8 +1171,8 @@ configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
"using built-in root key for view %s",
view->name);
(void)cfg_map_get(named_g_config, "trust-anchors",
&builtin_keys);
(void)cfg_map_get(named_g_defaultconfig,
"trust-anchors", &builtin_keys);
}
if (builtin_keys != NULL) {
@ -3839,7 +3840,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
optionmaps[j++] = options;
}
maps[i++] = named_g_defaults;
maps[i++] = named_g_defaultoptions;
maps[i] = NULL;
optionmaps[j] = NULL;
if (config != NULL) {
@ -4211,13 +4212,14 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
view->acceptexpired = cfg_obj_asboolean(obj);
obj = NULL;
/* 'optionmaps', not 'maps': don't check named_g_defaults yet */
/* 'optionmaps', not 'maps': don't check named_g_defaultoptions yet */
(void)named_config_get(optionmaps, "dnssec-validation", &obj);
if (obj == NULL) {
/*
* Default to VALIDATION_DEFAULT as set in config.c.
*/
(void)cfg_map_get(named_g_defaults, "dnssec-validation", &obj);
(void)cfg_map_get(named_g_defaultoptions, "dnssec-validation",
&obj);
INSIST(obj != NULL);
}
if (obj != NULL) {
@ -4936,14 +4938,15 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
CHECK(configure_view_acl(vconfig, config, NULL, "allow-query-cache-on",
NULL, actx, named_g_mctx, &view->cacheonacl));
CHECK(configure_view_acl(vconfig, config, named_g_config,
CHECK(configure_view_acl(vconfig, config, named_g_defaultconfig,
"allow-query-on", NULL, actx, named_g_mctx,
&view->queryonacl));
CHECK(configure_view_acl(vconfig, config, named_g_config, "allow-proxy",
NULL, actx, named_g_mctx, &view->proxyacl));
CHECK(configure_view_acl(vconfig, config, named_g_defaultconfig,
"allow-proxy", NULL, actx, named_g_mctx,
&view->proxyacl));
CHECK(configure_view_acl(vconfig, config, named_g_config,
CHECK(configure_view_acl(vconfig, config, named_g_defaultconfig,
"allow-proxy-on", NULL, actx, named_g_mctx,
&view->proxyonacl));
@ -5018,28 +5021,30 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
if (view->recursionacl == NULL) {
/* global default only */
CHECK(configure_view_acl(
NULL, NULL, named_g_config, "allow-recursion",
NULL, actx, named_g_mctx, &view->recursionacl));
NULL, NULL, named_g_defaultconfig,
"allow-recursion", NULL, actx, named_g_mctx,
&view->recursionacl));
}
if (view->recursiononacl == NULL) {
/* global default only */
CHECK(configure_view_acl(NULL, NULL, named_g_config,
"allow-recursion-on", NULL,
actx, named_g_mctx,
&view->recursiononacl));
CHECK(configure_view_acl(
NULL, NULL, named_g_defaultconfig,
"allow-recursion-on", NULL, actx, named_g_mctx,
&view->recursiononacl));
}
if (view->cacheacl == NULL) {
/* global default only */
CHECK(configure_view_acl(
NULL, NULL, named_g_config, "allow-query-cache",
NULL, actx, named_g_mctx, &view->cacheacl));
NULL, NULL, named_g_defaultconfig,
"allow-query-cache", NULL, actx, named_g_mctx,
&view->cacheacl));
}
if (view->cacheonacl == NULL) {
/* global default only */
CHECK(configure_view_acl(NULL, NULL, named_g_config,
"allow-query-cache-on", NULL,
actx, named_g_mctx,
&view->cacheonacl));
CHECK(configure_view_acl(
NULL, NULL, named_g_defaultconfig,
"allow-query-cache-on", NULL, actx,
named_g_mctx, &view->cacheonacl));
}
} else {
/*
@ -5060,7 +5065,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
*/
if (view->queryacl == NULL) {
/* global default only */
CHECK(configure_view_acl(NULL, NULL, named_g_config,
CHECK(configure_view_acl(NULL, NULL, named_g_defaultconfig,
"allow-query", NULL, actx,
named_g_mctx, &view->queryacl));
}
@ -5070,7 +5075,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
* clients. This causes case not always to be preserved,
* and is needed by some broken clients.
*/
CHECK(configure_view_acl(vconfig, config, named_g_config,
CHECK(configure_view_acl(vconfig, config, named_g_defaultconfig,
"no-case-compress", NULL, actx, named_g_mctx,
&view->nocasecompress));
@ -5086,7 +5091,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
/*
* Filter setting on addresses in the answer section.
*/
CHECK(configure_view_acl(vconfig, config, named_g_config,
CHECK(configure_view_acl(vconfig, config, named_g_defaultconfig,
"deny-answer-addresses", "acl", actx,
named_g_mctx, &view->denyansweracl));
CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
@ -5110,12 +5115,12 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
* read from there in zoneconf.c:configure_zone_acl() later.)
*/
if (view->updateacl == NULL) {
CHECK(configure_view_acl(NULL, NULL, named_g_config,
CHECK(configure_view_acl(NULL, NULL, named_g_defaultconfig,
"allow-update", NULL, actx,
named_g_mctx, &view->updateacl));
}
if (view->upfwdacl == NULL) {
CHECK(configure_view_acl(NULL, NULL, named_g_config,
CHECK(configure_view_acl(NULL, NULL, named_g_defaultconfig,
"allow-update-forwarding", NULL, actx,
named_g_mctx, &view->upfwdacl));
}
@ -5125,12 +5130,12 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
* can be inherited by zones.
*/
if (view->transferacl == NULL) {
CHECK(configure_view_acl(vconfig, config, named_g_config,
CHECK(configure_view_acl(vconfig, config, named_g_defaultconfig,
"allow-transfer", NULL, actx,
named_g_mctx, &view->transferacl));
}
if (view->notifyacl == NULL) {
CHECK(configure_view_acl(vconfig, config, named_g_config,
CHECK(configure_view_acl(vconfig, config, named_g_defaultconfig,
"allow-notify", NULL, actx,
named_g_mctx, &view->notifyacl));
}
@ -6728,56 +6733,6 @@ configure_server_quota(const cfg_obj_t **maps, const char *name,
isc_quota_max(quota, cfg_obj_asuint32(obj));
}
/*
* This function is called as soon as the 'directory' statement has been
* parsed. This can be extended to support other options if necessary.
*/
static isc_result_t
directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
isc_result_t result;
const char *directory;
REQUIRE(strcasecmp("directory", clausename) == 0);
UNUSED(arg);
UNUSED(clausename);
/*
* Change directory.
*/
directory = cfg_obj_asstring(obj);
if (!isc_file_ischdiridempotent(directory)) {
cfg_obj_log(obj, ISC_LOG_WARNING,
"option 'directory' contains relative path '%s'",
directory);
}
if (!isc_file_isdirwritable(directory)) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_ERROR, "directory '%s' is not writable",
directory);
return ISC_R_NOPERM;
}
result = isc_dir_chdir(directory);
if (result != ISC_R_SUCCESS) {
cfg_obj_log(obj, ISC_LOG_ERROR,
"change directory to '%s' failed: %s", directory,
isc_result_totext(result));
return result;
}
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)) == cwd) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_INFO, "the working directory is now '%s'",
cwd);
}
return ISC_R_SUCCESS;
}
/*
* This event callback is invoked to do periodic network interface
* scanning.
@ -7332,7 +7287,7 @@ cleanup:
static isc_result_t
setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx) {
cfg_parser_t *config_parser, cfg_aclconfctx_t *actx) {
isc_result_t result = ISC_R_SUCCESS;
bool allow = false;
ns_cfgctx_t *nzcfg = NULL;
@ -7357,7 +7312,7 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
if (result == ISC_R_SUCCESS) {
maps[i++] = options;
}
maps[i++] = named_g_defaults;
maps[i++] = named_g_defaultoptions;
maps[i] = NULL;
result = named_config_get(maps, "allow-new-zones", &nz);
@ -7435,12 +7390,11 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
*nzcfg = (ns_cfgctx_t){ 0 };
/*
* We attach the parser that was used for config as well
* as the one that will be used for added zones, to avoid
* We attach the parser that will be used for added zones to avoid
* a shutdown race later.
*/
isc_mem_attach(view->mctx, &nzcfg->mctx);
cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
cfg_parser_attach(config_parser, &nzcfg->conf_parser);
cfg_parser_attach(named_g_addparser, &nzcfg->add_parser);
cfg_aclconfctx_attach(actx, &nzcfg->actx);
@ -7448,8 +7402,8 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
mapsize);
if (result != ISC_R_SUCCESS) {
cfg_aclconfctx_detach(&nzcfg->actx);
cfg_parser_destroy(&nzcfg->add_parser);
cfg_parser_destroy(&nzcfg->conf_parser);
cfg_parser_destroy(&nzcfg->add_parser);
isc_mem_putanddetach(&nzcfg->mctx, nzcfg, sizeof(*nzcfg));
dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
return result;
@ -7846,10 +7800,10 @@ cleanup:
#endif /* HAVE_LMDB */
static isc_result_t
load_configuration(const char *filename, named_server_t *server,
bool first_time) {
cfg_obj_t *config = NULL, *bindkeys = NULL;
cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
apply_configuration(cfg_parser_t *configparser, cfg_obj_t *config,
named_server_t *server, bool first_time) {
cfg_obj_t *bindkeys = NULL;
cfg_parser_t *bindkeys_parser = NULL;
const cfg_obj_t *builtin_views = NULL;
const cfg_obj_t *maps[3];
const cfg_obj_t *obj = NULL;
@ -7887,6 +7841,9 @@ load_configuration(const char *filename, named_server_t *server,
dns_aclenv_t *env =
ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_DEBUG(1), "apply_configuration");
/*
* Require the reconfiguration to happen always on the main loop
*/
@ -7916,21 +7873,6 @@ load_configuration(const char *filename, named_server_t *server,
*/
dns_dyndb_cleanup();
/*
* Parse the global default pseudo-config file.
*/
if (first_time) {
result = named_config_parsedefaults(named_g_parser,
&named_g_config);
if (result != ISC_R_SUCCESS) {
named_main_earlyfatal("unable to load "
"internal defaults: %s",
isc_result_totext(result));
}
RUNTIME_CHECK(cfg_map_get(named_g_config, "options",
&named_g_defaults) == ISC_R_SUCCESS);
}
/*
* Log the current working directory.
*/
@ -7944,38 +7886,6 @@ load_configuration(const char *filename, named_server_t *server,
}
}
/*
* Parse the configuration file using the new config code.
*/
config = NULL;
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_INFO, "loading configuration from '%s'",
filename);
result = cfg_parser_create(named_g_mctx, &conf_parser);
if (result != ISC_R_SUCCESS) {
goto cleanup_exclusive;
}
cfg_parser_setcallback(conf_parser, directory_callback, NULL);
result = cfg_parse_file(conf_parser, filename, &cfg_type_namedconf,
&config);
if (result != ISC_R_SUCCESS) {
goto cleanup_conf_parser;
}
/*
* Check the validity of the configuration.
*
* (Ignore plugin parameters for now; they will be
* checked later when the modules are actually loaded and
* registered.)
*/
result = isccfg_check_namedconf(config, BIND_CHECK_ALGORITHMS,
named_g_mctx);
if (result != ISC_R_SUCCESS) {
goto cleanup_config;
}
/* Let's recreate the TLS context cache */
if (server->tlsctx_server_cache != NULL) {
isc_tlsctx_cache_detach(&server->tlsctx_server_cache);
@ -8001,7 +7911,7 @@ load_configuration(const char *filename, named_server_t *server,
if (result == ISC_R_SUCCESS) {
maps[i++] = options;
}
maps[i++] = named_g_defaults;
maps[i++] = named_g_defaultoptions;
maps[i] = NULL;
#if HAVE_LIBNGHTTP2
@ -8047,7 +7957,7 @@ load_configuration(const char *filename, named_server_t *server,
result = cfg_parser_create(named_g_mctx,
&bindkeys_parser);
if (result != ISC_R_SUCCESS) {
goto cleanup_config;
goto cleanup_bindkeys_parser;
}
result = cfg_parse_file(bindkeys_parser,
@ -8609,7 +8519,7 @@ load_configuration(const char *filename, named_server_t *server,
* Create the built-in kasp policies ("default", "insecure").
*/
kasps = NULL;
(void)cfg_map_get(named_g_config, "dnssec-policy", &kasps);
(void)cfg_map_get(named_g_defaultconfig, "dnssec-policy", &kasps);
CFG_LIST_FOREACH (kasps, element) {
cfg_obj_t *kconfig = cfg_listelt_value(element);
dns_kasp_t *kasp = NULL;
@ -8684,7 +8594,7 @@ load_configuration(const char *filename, named_server_t *server,
}
INSIST(view != NULL);
result = setup_newzones(view, config, vconfig, conf_parser,
result = setup_newzones(view, config, vconfig, configparser,
named_g_aclconfctx);
dns_view_detach(&view);
@ -8706,7 +8616,7 @@ load_configuration(const char *filename, named_server_t *server,
}
INSIST(view != NULL);
result = setup_newzones(view, config, NULL, conf_parser,
result = setup_newzones(view, config, NULL, configparser,
named_g_aclconfctx);
dns_view_detach(&view);
@ -8770,8 +8680,8 @@ load_configuration(const char *filename, named_server_t *server,
* Create (or recreate) the built-in views.
*/
builtin_views = NULL;
RUNTIME_CHECK(cfg_map_get(named_g_config, "view", &builtin_views) ==
ISC_R_SUCCESS);
RUNTIME_CHECK(cfg_map_get(named_g_defaultconfig, "view",
&builtin_views) == ISC_R_SUCCESS);
CFG_LIST_FOREACH (builtin_views, element) {
cfg_obj_t *vconfig = cfg_listelt_value(element);
dns_view_t *view = NULL;
@ -9184,7 +9094,7 @@ load_configuration(const char *filename, named_server_t *server,
/*
* Record the time of most recent configuration
*/
named_g_configtime = isc_time_now();
named_g_defaultconfigtime = isc_time_now();
isc_loopmgr_resume(named_g_loopmgr);
exclusive = false;
@ -9279,7 +9189,6 @@ cleanup_portsets:
isc_portset_destroy(named_g_mctx, &v4portset);
cleanup_bindkeys_parser:
if (bindkeys_parser != NULL) {
if (bindkeys != NULL) {
cfg_obj_destroy(bindkeys_parser, &bindkeys);
@ -9287,24 +9196,49 @@ cleanup_bindkeys_parser:
cfg_parser_destroy(&bindkeys_parser);
}
cleanup_config:
cfg_obj_destroy(conf_parser, &config);
cleanup_conf_parser:
cfg_parser_destroy(&conf_parser);
cleanup_exclusive:
if (exclusive) {
isc_loopmgr_resume(named_g_loopmgr);
}
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_DEBUG(1), "load_configuration: %s",
ISC_LOG_DEBUG(1), "apply_configuration: %s",
isc_result_totext(result));
return result;
}
static isc_result_t
load_configuration(named_server_t *server, bool first_time) {
isc_result_t result;
cfg_parser_t *parser = NULL;
cfg_obj_t *config = NULL;
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_DEBUG(1), "load_configuration");
result = cfg_parser_create(named_g_mctx, &parser);
if (result != ISC_R_SUCCESS) {
goto out;
}
result = named_config_parsefile(parser, &config);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
result = apply_configuration(parser, config, server, first_time);
cleanup:
if (config) {
cfg_obj_destroy(parser, &config);
}
cfg_parser_destroy(&parser);
out:
return result;
}
static isc_result_t
view_loaded(void *arg) {
isc_result_t result;
@ -9480,11 +9414,18 @@ run_server(void *arg) {
CHECKFATAL(cfg_parser_create(named_g_mctx, &named_g_parser),
"creating default configuration parser");
CHECKFATAL(named_config_parsedefaults(named_g_parser,
&named_g_defaultconfig),
"unable to parse defaults config");
CHECKFATAL(cfg_map_get(named_g_defaultconfig, "options",
&named_g_defaultoptions),
"missing 'options' in default config");
CHECKFATAL(cfg_parser_create(named_g_mctx, &named_g_addparser),
"creating additional configuration parser");
CHECKFATAL(load_configuration(named_g_conffile, server, true),
"loading configuration");
CHECKFATAL(load_configuration(server, true), "loading configuration");
CHECKFATAL(load_zones(server, false), "loading zones");
#ifdef ENABLE_AFL
@ -9535,7 +9476,7 @@ shutdown_server(void *arg) {
cfg_aclconfctx_detach(&named_g_aclconfctx);
}
cfg_obj_destroy(named_g_parser, &named_g_config);
cfg_obj_destroy(named_g_parser, &named_g_defaultconfig);
cfg_parser_destroy(&named_g_parser);
cfg_parser_destroy(&named_g_addparser);
@ -9964,7 +9905,7 @@ fatal(const char *msg, isc_result_t result) {
static isc_result_t
loadconfig(named_server_t *server) {
isc_result_t result;
result = load_configuration(named_g_conffile, server, false);
result = load_configuration(server, false);
if (result == ISC_R_SUCCESS) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_INFO,
@ -9983,8 +9924,16 @@ loadconfig(named_server_t *server) {
static isc_result_t
reload(named_server_t *server) {
isc_result_t result;
int reloadstatus = atomic_exchange(&server->reload_status,
NAMED_RELOAD_IN_PROGRESS);
atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
if (reloadstatus == NAMED_RELOAD_IN_PROGRESS) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_WARNING,
"reload request ignored: already running");
result = ISC_R_ALREADYRUNNING;
goto cleanup;
}
named_os_notify_systemd("RELOADING=1\n"
"MONOTONIC_USEC=%" PRIu64 "\n"
@ -10384,8 +10333,16 @@ named_server_reloadcommand(named_server_t *server, isc_lex_t *lex,
}
if (zone == NULL) {
result = reload(server);
if (result == ISC_R_SUCCESS) {
switch (result) {
case ISC_R_SUCCESS:
msg = "server reload successful";
break;
case ISC_R_ALREADYRUNNING:
msg = "reload request ignored as the server is "
"currently being reloaded or reconfigured";
break;
default:
break;
}
} else {
type = dns_zone_gettype(zone);
@ -10475,9 +10432,21 @@ named_server_resetstatscommand(named_server_t *server, isc_lex_t *lex,
* Act on a "reconfig" command from the command channel.
*/
isc_result_t
named_server_reconfigcommand(named_server_t *server) {
named_server_reconfigcommand(named_server_t *server, isc_buffer_t *text) {
isc_result_t result;
atomic_store(&server->reload_status, NAMED_RELOAD_IN_PROGRESS);
int reloadstatus = atomic_exchange(&server->reload_status,
NAMED_RELOAD_IN_PROGRESS);
if (reloadstatus == NAMED_RELOAD_IN_PROGRESS) {
isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_WARNING,
"reconfig request ignored: already running");
result = ISC_R_ALREADYRUNNING;
isc_buffer_printf(text,
"reconfig request ignored as the server is "
"currently being reloaded or reconfigured");
goto cleanup;
}
named_os_notify_systemd("RELOADING=1\n"
"MONOTONIC_USEC=%" PRIu64 "\n"
@ -11880,7 +11849,7 @@ named_server_status(named_server_t *server, isc_buffer_t **text) {
isc_time_formathttptimestamp(&named_g_boottime, boottime,
sizeof(boottime));
isc_time_formathttptimestamp(&named_g_configtime, configtime,
isc_time_formathttptimestamp(&named_g_defaultconfigtime, configtime,
sizeof(configtime));
snprintf(line, sizeof(line), "version: %s (%s) <id:%s>%s%s%s\n",
@ -13623,7 +13592,7 @@ named_server_changezone(named_server_t *server, char *command,
addzone ? NAMED_COMMAND_ADDZONE : NAMED_COMMAND_MODZONE);
/* Changing a zone counts as reconfiguration */
named_g_configtime = isc_time_now();
named_g_defaultconfigtime = isc_time_now();
cleanup:
if (isc_buffer_usedlength(*text) > 0) {
@ -13934,7 +13903,7 @@ named_server_delzone(named_server_t *server, isc_lex_t *lex,
zonename);
/* Removing a zone counts as reconfiguration */
named_g_configtime = isc_time_now();
named_g_defaultconfigtime = isc_time_now();
result = ISC_R_SUCCESS;

View File

@ -1779,7 +1779,7 @@ generatexml(named_server_t *server, uint32_t flags, int *buflen,
isc_result_t result;
isc_time_formatISO8601ms(&named_g_boottime, boottime, sizeof boottime);
isc_time_formatISO8601ms(&named_g_configtime, configtime,
isc_time_formatISO8601ms(&named_g_defaultconfigtime, configtime,
sizeof configtime);
isc_time_formatISO8601ms(&now, nowstr, sizeof nowstr);
@ -2856,7 +2856,7 @@ generatejson(named_server_t *server, size_t *msglen, const char **msg,
now = isc_time_now();
isc_time_formatISO8601ms(&named_g_boottime, boottime, sizeof(boottime));
isc_time_formatISO8601ms(&named_g_configtime, configtime,
isc_time_formatISO8601ms(&named_g_defaultconfigtime, configtime,
sizeof configtime);
isc_time_formatISO8601ms(&now, nowstr, sizeof(nowstr));

View File

@ -165,7 +165,7 @@ configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
maps[i++] = options;
}
}
maps[i++] = named_g_defaults;
maps[i++] = named_g_defaultoptions;
maps[i] = NULL;
(void)named_config_get(maps, aclname, &aclobj);
@ -946,7 +946,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
}
nodefault[i] = NULL;
maps[i++] = named_g_defaults;
maps[i++] = named_g_defaultoptions;
maps[i] = NULL;
if (vconfig != NULL) {
@ -1808,7 +1808,7 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
dns_name_equal(dns_zone_getorigin(zone), dns_rootname))
{
result = named_config_getremotesdef(
named_g_config, "remote-servers",
named_g_defaultconfig, "remote-servers",
DEFAULT_IANA_ROOT_ZONE_PRIMARIES, &obj);
CHECK(result);
}

View File

@ -0,0 +1,15 @@
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
SPDX-License-Identifier: MPL-2.0
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, you can obtain one at https://mozilla.org/MPL/2.0/.
See the COPYRIGHT file distributed with this work for additional
information regarding copyright ownership.
This test is a "guard/warning" to make sure the named.conf loading (parsing) is
done outside of the exclusive mode (so, named is still able to answer queries
and operating normally in case of configuration reload). It is currently based
on logging, so it's quite brittle.

View File

@ -0,0 +1,21 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; SPDX-License-Identifier: MPL-2.0
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
example. IN SOA mname1. . (
2 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
IN NS ns.example.
ns IN A 10.0.0.1
a IN A 10.0.0.2

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* SPDX-License-Identifier: MPL-2.0
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
// NS2
options {
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.1; };
listen-on-v6 { none; };
recursion no;
};
key rndc_key {
secret "1234abcd8765";
algorithm @DEFAULT_HMAC@;
};
controls {
inet 10.53.0.1 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
zone "example." {
type primary;
file "example.db";
};

View File

@ -0,0 +1,19 @@
#!/bin/sh -e
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# SPDX-License-Identifier: MPL-2.0
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
# shellcheck source=conf.sh
. ../conf.sh
set -e
copy_setports ns1/named.conf.in ns1/named.conf

View File

@ -0,0 +1,47 @@
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# SPDX-License-Identifier: MPL-2.0
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
import pytest
pytestmark = pytest.mark.extra_artifacts(
[
"ns1/managed-keys.bind.jnl",
]
)
def assert_log_sequence(server, fnname, scopefn):
triggers = {
"load_configuration": 0,
"parsing user configuration from ": 1,
"apply_configuration": 2,
"loop exclusive mode: starting": 3,
}
fn = getattr(server, fnname)
for i in range(len(triggers.items())):
with fn() as watcher:
scopefn()
assert watcher.wait_for_lines(dict(list(triggers.items())[i:])) == i
def test_configloading_loading(servers):
server = servers["ns1"]
assert_log_sequence(server, "watch_log_from_start", lambda: ())
def test_configloading_reconfig(servers):
server = servers["ns1"]
assert_log_sequence(server, "watch_log_from_here", lambda: server.rndc("reconfig"))
def test_configloading_reload(servers):
server = servers["ns1"]
assert_log_sequence(server, "watch_log_from_here", lambda: server.rndc("reload"))

View File

@ -17,7 +17,9 @@ import isctest
def test_emptyzones(servers, templates):
# check that switching to automatic empty zones works
ns1 = servers["ns1"]
ns1.rndc("reload")
with ns1.watch_log_from_here() as watcher:
ns1.rndc("reload")
watcher.wait_for_line("all zones loaded")
templates.render("ns1/named.conf", {"automatic_empty_zones": True})
ns1.rndc("reload")
msg = dns.message.make_query("version.bind", "TXT", "CH")