]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
implement "rndc showconf"
authorEvan Hunt <each@isc.org>
Fri, 24 Oct 2025 07:42:33 +0000 (00:42 -0700)
committerColin Vidal <colin@isc.org>
Wed, 29 Oct 2025 22:49:49 +0000 (23:49 +0100)
add a new rndc command to dump server configuration info:
- "rndc showconf -user" dumps the contents of named.conf
- "rndc showconf -builtin" dumps named_g_defaltconfig
- "rndc showconf -effective" dumps the effective configuration,
  i.e., the merger of the builtin and the user configurations.

bin/named/control.c
bin/named/include/named/control.h
bin/named/include/named/server.h
bin/named/server.c
bin/rndc/rndc.rst

index aa2b9d39303d0c80bb47fa0d106acdaa70abca10..ba6001bac84aecb32d530899a5a2014e1fae3482 100644 (file)
@@ -276,6 +276,8 @@ named_control_docommand(isccc_sexpr_t *message, bool readonly,
                result = named_server_dumpsecroots(named_g_server, lex, text);
        } else if (command_compare(command, NAMED_COMMAND_SERVESTALE)) {
                result = named_server_servestale(named_g_server, lex, text);
+       } else if (command_compare(command, NAMED_COMMAND_SHOWCONF)) {
+               result = named_server_showconf(named_g_server, lex, text);
        } else if (command_compare(command, NAMED_COMMAND_SHOWZONE)) {
                result = named_server_showzone(named_g_server, lex, text);
        } else if (command_compare(command, NAMED_COMMAND_SIGNING)) {
index 343d41a272aca24c36d896cb4c26a26c2e046314..82e9d4621e634d34d98753e6f8d9bbc41ff60d88 100644 (file)
@@ -61,6 +61,7 @@
 #define NAMED_COMMAND_SCAN        "scan"
 #define NAMED_COMMAND_SECROOTS    "secroots"
 #define NAMED_COMMAND_SERVESTALE   "serve-stale"
+#define NAMED_COMMAND_SHOWCONF    "showconf"
 #define NAMED_COMMAND_SHOWZONE    "showzone"
 #define NAMED_COMMAND_SIGN        "sign"
 #define NAMED_COMMAND_SIGNING     "signing"
index d22c943d1abe7818b3d5fbfdc2cf4d8ac320c1f8..8da065e4b99b462d8b407a49876b7e04d98c3d34 100644 (file)
@@ -110,7 +110,8 @@ struct named_server {
        isc_signal_t *sigusr1;
 
        cfg_aclconfctx_t *aclctx;
-       cfg_obj_t        *config;
+       cfg_obj_t        *userconfig;
+       cfg_obj_t        *effectiveconfig;
 };
 
 #define NAMED_SERVER_MAGIC    ISC_MAGIC('S', 'V', 'E', 'R')
@@ -325,6 +326,13 @@ isc_result_t
 named_server_showzone(named_server_t *server, isc_lex_t *lex,
                      isc_buffer_t **text);
 
+/*%
+ * Show the full current user configuration.
+ */
+isc_result_t
+named_server_showconf(named_server_t *server, isc_lex_t *lex,
+                     isc_buffer_t **text);
+
 /*%
  * Lists the status of the signing records for a given zone.
  */
index 1b3767467bd99eda62cb40ae59e948a3f71fb01d..2be9f4f999923a782138de802a5de33e65f44dc6 100644 (file)
@@ -2459,9 +2459,10 @@ catz_addmodzone_cb(void *arg) {
        isc_loopmgr_pause();
        dns_view_thaw(view);
        result = configure_zone(
-               cz->cbd->server->config, zoneobj, view->newzone.vconfig, view,
-               &cz->cbd->server->viewlist, &cz->cbd->server->kasplist,
-               cz->cbd->server->aclctx, true, false, true, cz->mod);
+               cz->cbd->server->effectiveconfig, zoneobj,
+               view->newzone.vconfig, view, &cz->cbd->server->viewlist,
+               &cz->cbd->server->kasplist, cz->cbd->server->aclctx, true,
+               false, true, cz->mod);
        dns_view_freeze(view);
        isc_loopmgr_resume();
 
@@ -7888,8 +7889,9 @@ configure_kasplist(const cfg_obj_t *config, dns_kasplist_t *kasplist,
 }
 
 static isc_result_t
-apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
-                   named_server_t *server, bool first_time) {
+apply_configuration(cfg_obj_t *effectiveconfig, cfg_obj_t *userconfig,
+                   cfg_obj_t *bindkeys, named_server_t *server,
+                   bool first_time) {
        const cfg_obj_t *maps[3];
        const cfg_obj_t *obj = NULL;
        const cfg_obj_t *options = NULL;
@@ -7942,7 +7944,7 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
         */
        i = 0;
        options = NULL;
-       result = cfg_map_get(config, "options", &options);
+       result = cfg_map_get(effectiveconfig, "options", &options);
        if (result == ISC_R_SUCCESS) {
                maps[i++] = options;
        }
@@ -7954,17 +7956,17 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
                goto cleanup_aclctx;
        }
 
-       result = configure_keystores(config, &keystorelist);
+       result = configure_keystores(effectiveconfig, &keystorelist);
        if (result != ISC_R_SUCCESS) {
                goto cleanup_keystorelist;
        }
 
-       result = configure_kasplist(config, &kasplist, &keystorelist);
+       result = configure_kasplist(effectiveconfig, &kasplist, &keystorelist);
        if (result != ISC_R_SUCCESS) {
                goto cleanup_kasplist;
        }
 
-       result = create_views(config, &viewlist);
+       result = create_views(effectiveconfig, &viewlist);
        if (result != ISC_R_SUCCESS) {
                goto cleanup_viewlist;
        }
@@ -8079,7 +8081,7 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
        result = named_config_get(maps, "sig0checks-quota-exempt", &obj);
        if (result == ISC_R_SUCCESS) {
                result = cfg_acl_fromconfig(
-                       obj, config, aclctx, isc_g_mctx, 0,
+                       obj, effectiveconfig, aclctx, isc_g_mctx, 0,
                        &server->sctx->sig0checksquota_exempt);
                INSIST(result == ISC_R_SUCCESS);
        }
@@ -8088,8 +8090,9 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
         * Set "blackhole". Only legal at options level; there is
         * no default.
         */
-       result = configure_view_acl(NULL, config, "blackhole", NULL, aclctx,
-                                   isc_g_mctx, &server->sctx->blackholeacl);
+       result = configure_view_acl(NULL, effectiveconfig, "blackhole", NULL,
+                                   aclctx, isc_g_mctx,
+                                   &server->sctx->blackholeacl);
        if (result != ISC_R_SUCCESS) {
                goto cleanup_tls;
        }
@@ -8341,7 +8344,8 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
        if (named_g_port != 0) {
                listen_port = named_g_port;
        } else {
-               result = named_config_getport(config, "port", &listen_port);
+               result = named_config_getport(effectiveconfig, "port",
+                                             &listen_port);
                if (result != ISC_R_SUCCESS) {
                        goto cleanup_portsets;
                }
@@ -8390,7 +8394,7 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
                        goto cleanup_portsets;
                }
                result = listenlist_fromconfig(
-                       clistenon, config, aclctx, isc_g_mctx, AF_INET,
+                       clistenon, effectiveconfig, aclctx, isc_g_mctx, AF_INET,
                        server->tlsctx_server_cache, &listenon);
                if (result != ISC_R_SUCCESS) {
                        goto cleanup_portsets;
@@ -8414,8 +8418,8 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
                        goto cleanup_portsets;
                }
                result = listenlist_fromconfig(
-                       clistenon, config, aclctx, isc_g_mctx, AF_INET6,
-                       server->tlsctx_server_cache, &listenon);
+                       clistenon, effectiveconfig, aclctx, isc_g_mctx,
+                       AF_INET6, server->tlsctx_server_cache, &listenon);
                if (result != ISC_R_SUCCESS) {
                        goto cleanup_portsets;
                }
@@ -8536,9 +8540,9 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
         */
        (void)configure_session_key(maps, server, isc_g_mctx, first_time);
 
-       result = configure_views(config, bindkeys, aclctx, tlsctx_client_cache,
-                                &viewlist, &cachelist, &kasplist, server,
-                                first_time);
+       result = configure_views(effectiveconfig, bindkeys, aclctx,
+                                tlsctx_client_cache, &viewlist, &cachelist,
+                                &kasplist, server, first_time);
        if (result != ISC_R_SUCCESS) {
                goto cleanup_cachelist;
        }
@@ -8620,7 +8624,7 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
                              "statement for logging due to "
                              "-g option");
 
-               (void)cfg_map_get(config, "logging", &logobj);
+               (void)cfg_map_get(effectiveconfig, "logging", &logobj);
                if (logobj != NULL) {
                        result = named_logconfig(NULL, logobj);
                        if (result != ISC_R_SUCCESS) {
@@ -8639,7 +8643,7 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
                isc_logconfig_create(&logc);
 
                logobj = NULL;
-               (void)cfg_map_get(config, "logging", &logobj);
+               (void)cfg_map_get(effectiveconfig, "logging", &logobj);
                if (logobj != NULL) {
                        result = named_logconfig(logc, logobj);
                        if (result != ISC_R_SUCCESS) {
@@ -8699,7 +8703,7 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
                        ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES,
                                            cfg_obj_asboolean(obj));
                } else {
-                       (void)cfg_map_get(config, "logging", &logobj);
+                       (void)cfg_map_get(effectiveconfig, "logging", &logobj);
                        if (logobj != NULL) {
                                (void)cfg_map_get(logobj, "category",
                                                  &categories);
@@ -8948,10 +8952,18 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
         */
        named_g_defaultconfigtime = isc_time_now();
 
-       if (server->config != NULL) {
-               cfg_obj_detach(&server->config);
+       /*
+        * Set the current effective and user configuration
+        */
+       if (server->effectiveconfig != NULL) {
+               cfg_obj_detach(&server->effectiveconfig);
+       }
+       cfg_obj_attach(effectiveconfig, &server->effectiveconfig);
+
+       if (server->userconfig != NULL) {
+               cfg_obj_detach(&server->userconfig);
        }
-       cfg_obj_attach(config, &server->config);
+       cfg_obj_attach(userconfig, &server->userconfig);
 
        isc_loopmgr_resume();
        exclusive = false;
@@ -8962,8 +8974,8 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
        }
 
        /* Configure the statistics channel(s) */
-       result = named_statschannels_configure(named_g_server, config,
-                                              server->aclctx);
+       result = named_statschannels_configure(
+               named_g_server, server->effectiveconfig, server->aclctx);
        if (result != ISC_R_SUCCESS) {
                isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
                              ISC_LOG_ERROR,
@@ -8975,7 +8987,8 @@ apply_configuration(cfg_obj_t *config, cfg_obj_t *bindkeys,
        /*
         * Bind the control port(s).
         */
-       result = named_controls_configure(named_g_server->controls, config,
+       result = named_controls_configure(named_g_server->controls,
+                                         server->effectiveconfig,
                                          server->aclctx);
        if (result != ISC_R_SUCCESS) {
                isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
@@ -9066,7 +9079,7 @@ cleanup_aclctx:
                      ISC_LOG_DEBUG(1), "apply_configuration: %s",
                      isc_result_totext(result));
 
-       cfg_obj_detach(&config);
+       cfg_obj_detach(&effectiveconfig);
        return result;
 }
 
@@ -9110,8 +9123,10 @@ load_configuration(named_server_t *server, bool first_time) {
                }
        }
 
+       /* Merge and apply */
        effective = cfg_effective_config(config, named_g_defaultconfig);
-       result = apply_configuration(effective, bindkeys, server, first_time);
+       result = apply_configuration(effective, config, bindkeys, server,
+                                    first_time);
 
 cleanup:
        if (bindkeys != NULL) {
@@ -9751,8 +9766,12 @@ named_server_destroy(named_server_t **serverp) {
                isc_tlsctx_cache_detach(&server->tlsctx_client_cache);
        }
 
-       if (server->config != NULL) {
-               cfg_obj_detach(&server->config);
+       if (server->userconfig != NULL) {
+               cfg_obj_detach(&server->userconfig);
+       }
+
+       if (server->effectiveconfig != NULL) {
+               cfg_obj_detach(&server->effectiveconfig);
        }
 
        server->magic = 0;
@@ -13041,10 +13060,10 @@ do_addzone(named_server_t *server, dns_view_t *view, dns_name_t *name,
        if (view->newzone.vconfig != NULL) {
                voptions = cfg_tuple_get(view->newzone.vconfig, "options");
        }
-       result = isccfg_check_zoneconf(zoneobj, voptions, server->config, NULL,
-                                      NULL, NULL, NULL, view->name,
-                                      view->rdclass, BIND_CHECK_PLUGINS,
-                                      server->aclctx, isc_g_mctx);
+       result = isccfg_check_zoneconf(
+               zoneobj, voptions, server->effectiveconfig, NULL, NULL, NULL,
+               NULL, view->name, view->rdclass, BIND_CHECK_PLUGINS,
+               server->aclctx, isc_g_mctx);
        if (result != ISC_R_SUCCESS) {
                isc_loopmgr_resume();
                goto cleanup;
@@ -13052,9 +13071,10 @@ do_addzone(named_server_t *server, dns_view_t *view, dns_name_t *name,
 
        /* Mark view unfrozen and configure zone */
        dns_view_thaw(view);
-       result = configure_zone(server->config, zoneobj, view->newzone.vconfig,
-                               view, &server->viewlist, &server->kasplist,
-                               server->aclctx, true, false, false, false);
+       result = configure_zone(server->effectiveconfig, zoneobj,
+                               view->newzone.vconfig, view, &server->viewlist,
+                               &server->kasplist, server->aclctx, true, false,
+                               false, false);
        dns_view_freeze(view);
 
        isc_loopmgr_resume();
@@ -13236,10 +13256,10 @@ do_modzone(named_server_t *server, dns_view_t *view, dns_name_t *name,
        if (view->newzone.vconfig != NULL) {
                voptions = cfg_tuple_get(view->newzone.vconfig, "options");
        }
-       result = isccfg_check_zoneconf(zoneobj, voptions, server->config, NULL,
-                                      NULL, NULL, NULL, view->name,
-                                      view->rdclass, BIND_CHECK_PLUGINS,
-                                      server->aclctx, isc_g_mctx);
+       result = isccfg_check_zoneconf(
+               zoneobj, voptions, server->effectiveconfig, NULL, NULL, NULL,
+               NULL, view->name, view->rdclass, BIND_CHECK_PLUGINS,
+               server->aclctx, isc_g_mctx);
        if (result != ISC_R_SUCCESS) {
                isc_loopmgr_resume();
                goto cleanup;
@@ -13247,9 +13267,10 @@ do_modzone(named_server_t *server, dns_view_t *view, dns_name_t *name,
 
        /* Reconfigure the zone */
        dns_view_thaw(view);
-       result = configure_zone(server->config, zoneobj, view->newzone.vconfig,
-                               view, &server->viewlist, &server->kasplist,
-                               server->aclctx, true, false, false, true);
+       result = configure_zone(server->effectiveconfig, zoneobj,
+                               view->newzone.vconfig, view, &server->viewlist,
+                               &server->kasplist, server->aclctx, true, false,
+                               false, true);
        dns_view_freeze(view);
 
        isc_loopmgr_resume();
@@ -13287,11 +13308,12 @@ do_modzone(named_server_t *server, dns_view_t *view, dns_name_t *name,
 
        if (!added) {
                if (view->newzone.vconfig == NULL) {
-                       result = delete_zoneconf(view, server->config,
+                       result = delete_zoneconf(view, server->effectiveconfig,
                                                 dns_zone_getorigin(zone),
                                                 NULL);
                } else {
-                       voptions = cfg_tuple_get(server->config, "options");
+                       voptions = cfg_tuple_get(server->effectiveconfig,
+                                                "options");
                        result = delete_zoneconf(
                                view, voptions, dns_zone_getorigin(zone), NULL);
                }
@@ -13579,9 +13601,9 @@ rmzone(void *arg) {
                        result = delete_zoneconf(
                                view, voptions, dns_zone_getorigin(zone), NULL);
                } else {
-                       result = delete_zoneconf(view, dz->server->config,
-                                                dns_zone_getorigin(zone),
-                                                NULL);
+                       result = delete_zoneconf(
+                               view, dz->server->effectiveconfig,
+                               dns_zone_getorigin(zone), NULL);
                }
 
                if (result != ISC_R_SUCCESS) {
@@ -13796,7 +13818,7 @@ cleanup:
 }
 
 static void
-emitzone(void *arg, const char *buf, int len) {
+emit_text(void *arg, const char *buf, int len) {
        ns_dzarg_t *dzarg = arg;
        isc_result_t result;
 
@@ -13839,7 +13861,7 @@ named_server_showzone(named_server_t *server, isc_lex_t *lex,
        dzarg.magic = DZARG_MAGIC;
        dzarg.text = text;
        dzarg.result = ISC_R_SUCCESS;
-       cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, &dzarg);
+       cfg_printx(zconfig, CFG_PRINTER_ONELINE, emit_text, &dzarg);
        CHECK(dzarg.result);
 
        CHECK(putstr(text, ";"));
@@ -13854,6 +13876,54 @@ cleanup:
        return result;
 }
 
+isc_result_t
+named_server_showconf(named_server_t *server, isc_lex_t *lex,
+                     isc_buffer_t **text) {
+       isc_result_t result, tresult;
+       const char *arg = NULL;
+       const cfg_obj_t *config = NULL;
+       ns_dzarg_t dzarg = {
+               .magic = DZARG_MAGIC,
+               .result = ISC_R_SUCCESS,
+               .text = text,
+       };
+
+       REQUIRE(text != NULL && *text != NULL);
+
+       /* Skip the command name */
+       (void)next_token(lex, text);
+
+       arg = next_token(lex, text);
+       if (arg == NULL) {
+               return ISC_R_UNEXPECTEDEND;
+       }
+       if (strcasecmp(arg, "-user") == 0) {
+               config = server->userconfig;
+       } else if (strcasecmp(arg, "-builtin") == 0) {
+               config = named_g_defaultconfig;
+       } else if (strcasecmp(arg, "-effective") == 0) {
+               config = server->effectiveconfig;
+       } else {
+               CHECK(DNS_R_SYNTAX);
+       }
+
+       if (config == NULL) {
+               result = ISC_R_NOTFOUND;
+               TCHECK(putstr(text, "configuration data not found.\n"));
+               goto cleanup;
+       }
+
+       cfg_printx(config, 0, emit_text, &dzarg);
+       result = dzarg.result;
+
+cleanup:
+       if (isc_buffer_usedlength(*text) > 0) {
+               (void)putnull(text);
+       }
+
+       return result;
+}
+
 isc_result_t
 named_server_signing(named_server_t *server, isc_lex_t *lex,
                     isc_buffer_t **text) {
index aaaf33e426dc5bceb6e2fceea6bb038f6730d322..53804fef57061f37f25550bdcd3fb4c930b6cbac 100644 (file)
@@ -545,6 +545,28 @@ Currently supported commands are:
    answers is currently enabled or disabled. It also reports the values of
    ``stale-answer-ttl`` and ``max-stale-ttl``.
 
+.. option:: showconf ( -user | -builtin | -effective )
+
+   This command prints the current running configuration for the server.
+   There are three modes:
+
+     - ``rndc showconf -user`` prints the contents of :iscman:`named.conf`,
+        as of the time the server was most recently configured.
+     - ``rndc showconf -builtin`` prints the built-in default configuration
+       settings (which may be overridden by :iscman:`named.conf`).
+     - ``rndc showconf -effective`` prints the effective configuration
+       of the server. This is the merged combination of the ``-user`` and
+       ``-builtin`` configurations.
+
+   Note that this information is only set or updated when the server is
+   loaded or reconfigured.  Properties that can be dynamically changed
+   during runtime, such as the active root trust anchors, the debugging
+   level (via ``rndc trace``), or DNSSEC validation (via ``rndc
+   valiation``), are shown as configured, not as currently set, and zones that
+   are dynamically added using ``rndc addzone`` are not visible.
+
+   See also :option:`rndc showzone`.
+
 .. option:: showzone zone [class [view]]
 
    This command prints the configuration of a running zone.