From 762dc8b871589ffcaf43f336efb83ed9248fac89 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 3 Oct 2017 01:04:25 -0700 Subject: [PATCH] [master] rndc managed-keys destroy 4750. [func] "rndc managed-keys destroy" shuts down RFC 5011 key maintenance and deletes the managed-keys database. If followed by "rndc reconfig" or a server restart, key maintenance is reinitialized from scratch. This is primarily intended for testing. [RT #32456] --- CHANGES | 6 ++ bin/named/server.c | 144 ++++++++++++++++++++++++++------ bin/rndc/rndc.docbook | 70 +++++++++++++--- bin/tests/system/mkeys/tests.sh | 14 ++++ doc/arm/notes.xml | 17 ++++ 5 files changed, 215 insertions(+), 36 deletions(-) diff --git a/CHANGES b/CHANGES index f5b288231c..bcc9f823d7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +4750. [func] "rndc managed-keys destroy" shuts down RFC 5011 key + maintenance and deletes the managed-keys database. + If followed by "rndc reconfig" or a server restart, + key maintenance is reinitialized from scratch. + This is primarily intended for testing. [RT #32456] + 4749. [func] The ISC DLV service has been shut down, and all DLV records have been removed from dlv.isc.org. - Removed references to ISC DLV in documentation diff --git a/bin/named/server.c b/bin/named/server.c index 2d501d03b8..8d5538d6e2 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -6042,18 +6042,22 @@ add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) { /* See if we can re-use an existing keydata zone. */ result = dns_viewlist_find(&named_g_server->viewlist, - view->name, view->rdclass, - &pview); - if (result != ISC_R_NOTFOUND && - result != ISC_R_SUCCESS) + view->name, view->rdclass, &pview); + if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) { return (result); + } + + if (pview != NULL) { + if (pview->managed_keys != NULL) { + dns_zone_synckeyzone(pview->managed_keys); + dns_zone_attach(pview->managed_keys, + &view->managed_keys); + dns_zone_setview(pview->managed_keys, view); + dns_view_detach(&pview); + return (ISC_R_SUCCESS); + } - if (pview != NULL && pview->managed_keys != NULL) { - dns_zone_attach(pview->managed_keys, &view->managed_keys); - dns_zone_setview(pview->managed_keys, view); dns_view_detach(&pview); - dns_zone_synckeyzone(view->managed_keys); - return (ISC_R_SUCCESS); } /* No existing keydata zone was found; create one */ @@ -6086,8 +6090,9 @@ add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) { dns_zone_setstats(zone, named_g_server->zonestats); CHECK(setquerystats(zone, mctx, dns_zonestat_none)); - if (view->managed_keys != NULL) + if (view->managed_keys != NULL) { dns_zone_detach(&view->managed_keys); + } dns_zone_attach(zone, &view->managed_keys); isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, @@ -6096,10 +6101,12 @@ add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) { view->name, filename); cleanup: - if (zone != NULL) + if (zone != NULL) { dns_zone_detach(&zone); - if (none != NULL) + } + if (none != NULL) { dns_acl_detach(&none); + } return (result); } @@ -8916,8 +8923,7 @@ run_server(isc_task_t *task, isc_event_t *event) { &named_g_addparser), "creating additional configuration parser"); - CHECKFATAL(load_configuration(named_g_conffile, server, - ISC_TRUE), + CHECKFATAL(load_configuration(named_g_conffile, server, ISC_TRUE), "loading configuration"); isc_hash_init(); @@ -14067,6 +14073,78 @@ mkey_refresh(dns_view_t *view, isc_buffer_t **text) { return (result); } +static isc_result_t +mkey_destroy(named_server_t *server, dns_view_t *view, isc_buffer_t **text) { + isc_result_t result; + char msg[DNS_NAME_FORMATSIZE + 500] = ""; + isc_boolean_t exclusive = ISC_FALSE; + const char *file = NULL; + dns_db_t *dbp = NULL; + dns_zone_t *mkzone = NULL; + isc_boolean_t removed = ISC_FALSE; + + if (view->managed_keys == NULL) { + CHECK(ISC_R_NOTFOUND); + } + + snprintf(msg, sizeof(msg), + "destroying managed-keys database for '%s'", view->name); + CHECK(putstr(text, msg)); + + result = isc_task_beginexclusive(server->task); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + exclusive = ISC_TRUE; + + /* Remove and clean up managed keys zone from view */ + mkzone = view->managed_keys; + view->managed_keys = NULL; + (void)dns_zone_flush(mkzone); + + /* Unload zone database */ + if (dns_zone_getdb(mkzone, &dbp) == ISC_R_SUCCESS) { + dns_db_detach(&dbp); + dns_zone_unload(mkzone); + } + + /* Delete files */ + file = dns_zone_getfile(mkzone); + result = isc_file_remove(file); + if (result == ISC_R_SUCCESS) { + removed = ISC_TRUE; + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "file %s not removed: %s", + file, isc_result_totext(result)); + } + + file = dns_zone_getjournal(mkzone); + result = isc_file_remove(file); + if (result == ISC_R_SUCCESS) { + removed = ISC_TRUE; + } else { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING, + "file %s not removed: %s", + file, isc_result_totext(result)); + } + + if (!removed) { + CHECK(putstr(text, "error: no files could be removed")); + CHECK(ISC_R_FAILURE); + } + + dns_zone_detach(&mkzone); + result = ISC_R_SUCCESS; + + cleanup: + if (exclusive) { + isc_task_endexclusive(server->task); + } + return (result); +} + + static isc_result_t mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) { isc_result_t result; @@ -14220,27 +14298,31 @@ named_server_mkeys(named_server_t *server, isc_lex_t *lex, dns_view_t *view = NULL; dns_rdataclass_t rdclass; char msg[DNS_NAME_FORMATSIZE + 500] = ""; - enum { NONE, STATUS, REFRESH, SYNC } opt = NONE; + enum { NONE, STATUS, REFRESH, SYNC, DESTROY } opt = NONE; isc_boolean_t found = ISC_FALSE; isc_boolean_t first = ISC_TRUE; /* Skip rndc command name */ cmd = next_token(lex, text); - if (cmd == NULL) + if (cmd == NULL) { return (ISC_R_UNEXPECTEDEND); + } /* Get managed-keys subcommand */ cmd = next_token(lex, text); - if (cmd == NULL) + if (cmd == NULL) { return (ISC_R_UNEXPECTEDEND); + } - if (strcasecmp(cmd, "status") == 0) + if (strcasecmp(cmd, "status") == 0) { opt = STATUS; - else if (strcasecmp(cmd, "refresh") == 0) + } else if (strcasecmp(cmd, "refresh") == 0) { opt = REFRESH; - else if (strcasecmp(cmd, "sync") == 0) + } else if (strcasecmp(cmd, "sync") == 0) { opt = SYNC; - else { + } else if (strcasecmp(cmd, "destroy") == 0) { + opt = DESTROY; + } else { snprintf(msg, sizeof(msg), "unknown command '%s'", cmd); (void) putstr(text, msg); result = ISC_R_UNEXPECTED; @@ -14282,7 +14364,9 @@ named_server_mkeys(named_server_t *server, isc_lex_t *lex, if (viewtxt != NULL && (rdclass != view->rdclass || strcmp(view->name, viewtxt) != 0)) + { continue; + } if (view->managed_keys == NULL) { if (viewtxt != NULL) { @@ -14290,8 +14374,9 @@ named_server_mkeys(named_server_t *server, isc_lex_t *lex, "view '%s': no managed keys", viewtxt); CHECK(putstr(text, msg)); goto cleanup; - } else + } else { continue; + } } found = ISC_TRUE; @@ -14301,28 +14386,35 @@ named_server_mkeys(named_server_t *server, isc_lex_t *lex, CHECK(mkey_refresh(view, text)); break; case STATUS: - if (!first) + if (!first) { CHECK(putstr(text, "\n\n")); + } CHECK(mkey_status(view, text)); first = ISC_FALSE; break; case SYNC: CHECK(dns_zone_flush(view->managed_keys)); break; + case DESTROY: + CHECK(mkey_destroy(server, view, text)); + break; default: INSIST(0); } - if (viewtxt != NULL) + if (viewtxt != NULL) { break; + } } - if (!found) + if (!found) { CHECK(putstr(text, "no views with managed keys")); + } cleanup: - if (isc_buffer_usedlength(*text) > 0) + if (isc_buffer_usedlength(*text) > 0) { (void) putnull(text); + } return (result); } diff --git a/bin/rndc/rndc.docbook b/bin/rndc/rndc.docbook index 9598645233..5974a522b3 100644 --- a/bin/rndc/rndc.docbook +++ b/bin/rndc/rndc.docbook @@ -450,18 +450,68 @@ - managed-keys (status | refresh | sync) class view + managed-keys (status | refresh | sync | destroy) class view - When run with the "status" keyword, print the current - status of the managed-keys database for the specified - view, or for all views if none is specified. When run - with the "refresh" keyword, force an immediate refresh - of all the managed-keys in the specified view, or all - views. When run with the "sync" keyword, force an - immediate dump of the managed-keys database to disk (in - the file managed-keys.bind or - (viewname.mkeys). + Inspect and control the "managed-keys" database which + handles RFC 5011 DNSSEC trust anchor maintenance. If a view + is specified, these commands are applied to that view; + otherwise they are applied to all views. + + + + + When run with the status keyword, prints + the current status of the managed-keys database. + + + + + When run with the refresh keyword, + forces an immediate refresh query to be sent for all + the managed keys, updating the managed-keys database + if any new keys are found, without waiting the normal + refresh interval. + + + + + When run with the sync keyword, forces an + immediate dump of the managed-keys database to disk + (in the file managed-keys.bind or + (viewname.mkeys). + This synchronizes the database with its journal file, so + that the database's current contents can be inspected + visually. + + + + + When run with the destroy keyword, the + managed-keys database is shut down and deleted, and all key + maintenance is terminated. This command should be used only + with extreme caution. + + + Existing keys that are already trusted are not deleted + from memory; DNSSEC validation can continue after this + command is used. However, key maintenance operations will + cease until named is restarted or + reconfigured, and all existing key maintenance state + will be deleted. + + + Running rndc reconfig>/command> or restarting + named immediately after this command + will cause key maintenance to be reinitialized from scratch, + just as if the server were being started for the first time. + This is primarily intended for testing, but it may also be + used, for example, to jumpstart the acquisition of new keys + in the event of a trust anchor rollover, or as a + brute-force repair for key maintenance problems. + + + diff --git a/bin/tests/system/mkeys/tests.sh b/bin/tests/system/mkeys/tests.sh index cbeff3e1f7..b9806f3431 100644 --- a/bin/tests/system/mkeys/tests.sh +++ b/bin/tests/system/mkeys/tests.sh @@ -548,5 +548,19 @@ grep "query '_ta-[0-9a-f]*/NULL/IN' approved" ns1/named.run > /dev/null || ret=1 if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +n=`expr $n + 1` +echo "I: check 'rndc-managed-keys destroy' ($n)" +ret=0 +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 managed-keys destroy | sed 's/^/I: ns2 /' +sleep 1 +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 managed-keys status > rndc.out.$n 2>&1 +grep "no views with managed keys" rndc.out.$n > /dev/null || ret=1 +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reconfig | sed 's/^/I: ns2 /' +sleep 1 +$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 managed-keys status > rndc.out.$n 2>&1 +grep "name: \." rndc.out.$n > /dev/null || ret=1 +if [ $ret != 0 ]; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I:exit status: $status" [ $status -eq 0 ] || exit 1 diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index 93d912c1bb..11dfa4e861 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -395,6 +395,23 @@ entropy source. [RT #31459] [RT #46047] + + + rndc managed-keys destroy shuts down all + RFC 5011 DNSSEC trust anchor maintenance, and deletes any + existing managed keys database. If immediately followed by + rndc reconfig, this will reinitialize + key maintenance just as if the server was being started for + the first time. + + + This is intended for testing purposes, but can be used -- with + extreme caution -- as a brute-force repair for unrecoverable + problems with a managed keys database, to jumpstart the key + acquisition process if bind.keys is updated, + etc. [RT #32456] + +