From d55b0463b2537874feca70e3c4c419b4f8831444 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 29 Sep 2017 21:19:54 +0200 Subject: [PATCH] resolved: add support for explicitly forgetting everything we learnt about DNS server feature levels This adds "systemd-resolve --reset-server-features" for explicitly forgetting what we learnt. This might be useful for debugging purposes, and to force systemd-resolved to restart its learning logic for all DNS servers. --- NEWS | 6 +++ man/systemd-resolve.xml | 13 +++++- man/systemd-resolved.service.xml | 30 ++++++++++--- src/resolve/resolve-tool.c | 77 +++++++++++++++++++++++--------- src/resolve/resolved-bus.c | 12 +++++ src/resolve/resolved-manager.c | 13 ++++++ src/resolve/resolved-manager.h | 1 + src/resolve/resolved.c | 2 +- 8 files changed, 126 insertions(+), 28 deletions(-) diff --git a/NEWS b/NEWS index ac6f23c37df..bc1a77bf122 100644 --- a/NEWS +++ b/NEWS @@ -209,6 +209,12 @@ CHANGES WITH 235: too. Note that while the other databases are world-readable (i.e. 0644), btmp is not and remains more restrictive. + * The systemd-resolve tool gained a new --reset-server-features + switch. When invoked like this systemd-resolved will forget + everything it learnt about the features supported by the configured + upstream DNS servers, and restarts the feature probing logic on the + next resolver look-up for them at the highest feature level again. + Contributions from: Abdó Roig-Maranges, Alan Jenkins, Alexander Kuleshov, Andreas Rammhold, Andrew Jeddeloh, Andrew Soutar, Ansgar Burchardt, b1tninja, bengal, Benjamin Berg, Benjamin Robin, Charles diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index 47c90f2e482..53f843ff938 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -299,7 +299,18 @@ - Flushes all DNS resource record caches the service maintains locally. + Flushes all DNS resource record caches the service maintains locally. This is mostly equivalent + to sending the SIGUSR2 to the systemd-resolved + service. + + + + + + Flushes all feature level information the resolver learnt about specific servers, and ensures + that the server feature probing logic is started from the beginning with the next look-up request. This is + mostly equivalent to sending the SIGRTMIN+1 to the systemd-resolved + service. diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index fd717e4963e..1ad9500d78b 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -202,19 +202,37 @@ SIGUSR1 - Upon reception of the SIGUSR1 process signal systemd-resolved will dump the - contents of all DNS resource record caches it maintains into the system logs. + Upon reception of the SIGUSR1 process signal + systemd-resolved will dump the contents of all DNS resource record caches it maintains into + the system logs. SIGUSR2 - Upon reception of the SIGUSR2 process signal systemd-resolved will flush all - caches it maintains. Note that it should normally not be necessary to request this explicitly – except for - debugging purposes – as systemd-resolved flushes the caches automatically anyway any time - the host's network configuration changes. + Upon reception of the SIGUSR2 process signal + systemd-resolved will flush all caches it maintains. Note that it should normally not be + necessary to request this explicitly – except for debugging purposes – as systemd-resolved + flushes the caches automatically anyway any time the host's network configuration changes. Sending this signal + to systemd-resolved is equivalent to the systemd-resolve --flush-caches + command, however the latter is recommended since it operates in a synchronous way. + + + + SIGRTMIN+1 + + Upon reception of the SIGRTMIN+1 process signal + systemd-resolved will forget everything it learnt about the configured DNS + servers. Specifically any information about server feature support is flushed out, and the server feature + probing logic is restarted on the next request, starting with the most fully featured level. Note that it + should normally not be necessary to request this explicitly – except for debugging purposes – as + systemd-resolved automatically forgets learnt information any time the DNS server + configuration changes. Sending this signal to systemd-resolved is equivalent to the + systemd-resolve --reset-server-features command, however the latter is recommended since it + operates in a synchronous way. + diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 195555c3c0a..708378573fc 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -72,6 +72,7 @@ static enum { MODE_STATISTICS, MODE_RESET_STATISTICS, MODE_FLUSH_CACHES, + MODE_RESET_SERVER_FEATURES, MODE_STATUS, } arg_mode = MODE_RESOLVE_HOST; @@ -1055,6 +1056,24 @@ static int flush_caches(sd_bus *bus) { return 0; } +static int reset_server_features(sd_bus *bus) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + r = sd_bus_call_method(bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "ResetServerFeatures", + &error, + NULL, + NULL); + if (r < 0) + return log_error_errno(r, "Failed to reset server features: %s", bus_error_message(&error, r)); + + return 0; +} + static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { char ***l = userdata; int r; @@ -1588,6 +1607,8 @@ static void help(void) { " --reset-statistics Reset resolver statistics\n" " --status Show link and server status\n" " --flush-caches Flush all local DNS caches\n" + " --reset-server-features\n" + " Forget learnt DNS server feature levels\n" , program_invocation_short_name); } @@ -1607,30 +1628,32 @@ static int parse_argv(int argc, char *argv[]) { ARG_RESET_STATISTICS, ARG_STATUS, ARG_FLUSH_CACHES, + ARG_RESET_SERVER_FEATURES, ARG_NO_PAGER, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "type", required_argument, NULL, 't' }, - { "class", required_argument, NULL, 'c' }, - { "legend", required_argument, NULL, ARG_LEGEND }, - { "interface", required_argument, NULL, 'i' }, - { "protocol", required_argument, NULL, 'p' }, - { "cname", required_argument, NULL, ARG_CNAME }, - { "service", no_argument, NULL, ARG_SERVICE }, - { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, - { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, - { "openpgp", no_argument, NULL, ARG_OPENPGP }, - { "tlsa", optional_argument, NULL, ARG_TLSA }, - { "raw", optional_argument, NULL, ARG_RAW }, - { "search", required_argument, NULL, ARG_SEARCH }, - { "statistics", no_argument, NULL, ARG_STATISTICS, }, - { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, - { "status", no_argument, NULL, ARG_STATUS }, - { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "type", required_argument, NULL, 't' }, + { "class", required_argument, NULL, 'c' }, + { "legend", required_argument, NULL, ARG_LEGEND }, + { "interface", required_argument, NULL, 'i' }, + { "protocol", required_argument, NULL, 'p' }, + { "cname", required_argument, NULL, ARG_CNAME }, + { "service", no_argument, NULL, ARG_SERVICE }, + { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, + { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, + { "openpgp", no_argument, NULL, ARG_OPENPGP }, + { "tlsa", optional_argument, NULL, ARG_TLSA }, + { "raw", optional_argument, NULL, ARG_RAW }, + { "search", required_argument, NULL, ARG_SEARCH }, + { "statistics", no_argument, NULL, ARG_STATISTICS, }, + { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, + { "status", no_argument, NULL, ARG_STATUS }, + { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES }, + { "reset-server-features", no_argument, NULL, ARG_RESET_SERVER_FEATURES }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, {} }; @@ -1814,6 +1837,10 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = MODE_FLUSH_CACHES; break; + case ARG_RESET_SERVER_FEATURES: + arg_mode = MODE_RESET_SERVER_FEATURES; + break; + case ARG_STATUS: arg_mode = MODE_STATUS; break; @@ -1999,6 +2026,16 @@ int main(int argc, char **argv) { r = flush_caches(bus); break; + case MODE_RESET_SERVER_FEATURES: + if (argc > optind) { + log_error("Too many arguments."); + r = -EINVAL; + goto finish; + } + + r = reset_server_features(bus); + break; + case MODE_STATUS: if (argc > optind) { diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index bf822d3aaa5..c6f14eb416c 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1569,6 +1569,17 @@ static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_b return sd_bus_reply_method_return(message, NULL); } +static int bus_method_reset_server_features(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + assert(message); + assert(m); + + manager_reset_server_features(m); + + return sd_bus_reply_method_return(message, NULL); +} + static const sd_bus_vtable resolve_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0), @@ -1587,6 +1598,7 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0), SD_BUS_METHOD("FlushCaches", NULL, NULL, bus_method_flush_caches, 0), + SD_BUS_METHOD("ResetServerFeatures", NULL, NULL, bus_method_reset_server_features, 0), SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0), SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0), diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 3765d74cee3..50d32d37e9a 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -552,6 +552,17 @@ static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si return 0; } +static int manager_sigrtmin1(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { + Manager *m = userdata; + + assert(s); + assert(si); + assert(m); + + manager_reset_server_features(m); + return 0; +} + int manager_new(Manager **ret) { _cleanup_(manager_freep) Manager *m = NULL; int r; @@ -616,6 +627,7 @@ int manager_new(Manager **ret) { (void) sd_event_add_signal(m->event, &m->sigusr1_event_source, SIGUSR1, manager_sigusr1, m); (void) sd_event_add_signal(m->event, &m->sigusr2_event_source, SIGUSR2, manager_sigusr2, m); + (void) sd_event_add_signal(m->event, &m->sigrtmin1_event_source, SIGRTMIN+1, manager_sigrtmin1, m); manager_cleanup_saved_user(m); @@ -679,6 +691,7 @@ Manager *manager_free(Manager *m) { sd_event_source_unref(m->sigusr1_event_source); sd_event_source_unref(m->sigusr2_event_source); + sd_event_source_unref(m->sigrtmin1_event_source); sd_event_unref(m->event); diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index bb45ecc1d60..32a0e5fe0f8 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -126,6 +126,7 @@ struct Manager { sd_event_source *sigusr1_event_source; sd_event_source *sigusr2_event_source; + sd_event_source *sigrtmin1_event_source; unsigned n_transactions_total; unsigned n_dnssec_verdict[_DNSSEC_VERDICT_MAX]; diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index 8fd81956b83..2eb7bfd0307 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -80,7 +80,7 @@ int main(int argc, char *argv[]) { goto finish; } - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, -1) >= 0); + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0); r = manager_new(&m); if (r < 0) {