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.
This commit is contained in:
Lennart Poettering 2017-09-29 21:19:54 +02:00
parent 59c0fd0e17
commit d55b0463b2
8 changed files with 126 additions and 28 deletions

6
NEWS
View File

@ -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

View File

@ -299,7 +299,18 @@
<varlistentry>
<term><option>--flush-caches</option></term>
<listitem><para>Flushes all DNS resource record caches the service maintains locally.</para></listitem>
<listitem><para>Flushes all DNS resource record caches the service maintains locally. This is mostly equivalent
to sending the <constant>SIGUSR2</constant> to the <command>systemd-resolved</command>
service.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--reset-server-features</option></term>
<listitem><para>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 <constant>SIGRTMIN+1</constant> to the <command>systemd-resolved</command>
service.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -202,19 +202,37 @@
<varlistentry>
<term><constant>SIGUSR1</constant></term>
<listitem><para>Upon reception of the SIGUSR1 process signal <command>systemd-resolved</command> will dump the
contents of all DNS resource record caches it maintains into the system logs.</para></listitem>
<listitem><para>Upon reception of the <constant>SIGUSR1</constant> process signal
<command>systemd-resolved</command> will dump the contents of all DNS resource record caches it maintains into
the system logs.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>SIGUSR2</constant></term>
<listitem><para>Upon reception of the SIGUSR2 process signal <command>systemd-resolved</command> will flush all
caches it maintains. Note that it should normally not be necessary to request this explicitly except for
debugging purposes as <command>systemd-resolved</command> flushes the caches automatically anyway any time
the host's network configuration changes.</para></listitem>
<listitem><para>Upon reception of the <constant>SIGUSR2</constant> process signal
<command>systemd-resolved</command> will flush all caches it maintains. Note that it should normally not be
necessary to request this explicitly except for debugging purposes as <command>systemd-resolved</command>
flushes the caches automatically anyway any time the host's network configuration changes. Sending this signal
to <command>systemd-resolved</command> is equivalent to the <command>systemd-resolve --flush-caches</command>
command, however the latter is recommended since it operates in a synchronous way.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>SIGRTMIN+1</constant></term>
<listitem><para>Upon reception of the <constant>SIGRTMIN+1</constant> process signal
<command>systemd-resolved</command> 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
<command>systemd-resolved</command> automatically forgets learnt information any time the DNS server
configuration changes. Sending this signal to <command>systemd-resolved</command> is equivalent to the
<command>systemd-resolve --reset-server-features</command> command, however the latter is recommended since it
operates in a synchronous way.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>

View File

@ -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) {

View File

@ -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),

View File

@ -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);

View File

@ -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];

View File

@ -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) {