summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--man/systemd-resolved.service.xml10
-rw-r--r--src/resolve/resolved-bus.c1
-rw-r--r--src/resolve/resolved-conf.c2
-rw-r--r--src/resolve/resolved-conf.h8
-rw-r--r--src/resolve/resolved-dns-server.c15
-rw-r--r--src/resolve/resolved-dns-server.h9
-rw-r--r--src/resolve/resolved-dnssd.c10
-rw-r--r--src/resolve/resolved-dnssd.h5
-rw-r--r--src/resolve/resolved-link-bus.c2
-rw-r--r--src/resolve/resolved-link.c2
-rw-r--r--src/resolve/resolved-manager.c78
-rwxr-xr-xtest/units/testsuite-75.sh47
-rw-r--r--units/systemd-resolved.service.in2
13 files changed, 167 insertions, 24 deletions
diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml
index 8520a97e42..13c0da987f 100644
--- a/man/systemd-resolved.service.xml
+++ b/man/systemd-resolved.service.xml
@@ -421,6 +421,16 @@ search foobar.com barbar.com
<xi:include href="version-info.xml" xpointer="v235"/></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><constant>SIGHUP</constant></term>
+
+ <listitem><para>Upon reception of the <constant>SIGHUP</constant> process signal
+ <command>systemd-resolved</command> will flush all caches it maintains, drop all open TCP
+ connections (if any), and reload its configuration files.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index be2fdca21f..986a90f9f2 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -1890,6 +1890,7 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
if (r < 0)
return r;
service->originator = euid;
+ service->config_source = RESOLVE_CONFIG_SOURCE_DBUS;
r = sd_bus_message_read(message, "sssqqq", &name, &name_template, &type,
&service->port, &service->priority,
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index 504da9ebca..4441ee27c8 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -55,7 +55,7 @@ static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, cons
return 0;
}
- return dns_server_new(m, NULL, type, NULL, family, &address, port, ifindex, server_name);
+ return dns_server_new(m, NULL, type, NULL, family, &address, port, ifindex, server_name, RESOLVE_CONFIG_SOURCE_FILE);
}
int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
diff --git a/src/resolve/resolved-conf.h b/src/resolve/resolved-conf.h
index ca768bb2d9..5eea6bd54b 100644
--- a/src/resolve/resolved-conf.h
+++ b/src/resolve/resolved-conf.h
@@ -3,6 +3,14 @@
#include "conf-parser.h"
+typedef enum ResolveConfigSource {
+ RESOLVE_CONFIG_SOURCE_FILE,
+ RESOLVE_CONFIG_SOURCE_NETWORKD,
+ RESOLVE_CONFIG_SOURCE_DBUS,
+ _RESOLVE_CONFIG_SOURCE_MAX,
+ _RESOLVE_CONFIG_SOURCE_INVALID = -EINVAL,
+} ResolveConfigSource;
+
#include "resolved-dns-server.h"
int manager_parse_config_file(Manager *m);
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 957e6618b4..340f11f4f4 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -28,7 +28,8 @@ int dns_server_new(
const union in_addr_union *in_addr,
uint16_t port,
int ifindex,
- const char *server_name) {
+ const char *server_name,
+ ResolveConfigSource config_source) {
_cleanup_free_ char *name = NULL;
DnsServer *s;
@@ -67,6 +68,7 @@ int dns_server_new(
.port = port,
.ifindex = ifindex,
.server_name = TAKE_PTR(name),
+ .config_source = config_source,
};
dns_server_reset_features(s);
@@ -794,6 +796,17 @@ void dns_server_unlink_all(DnsServer *first) {
dns_server_unlink_all(next);
}
+void dns_server_unlink_on_reload(DnsServer *server) {
+ while (server) {
+ DnsServer *next = server->servers_next;
+
+ if (server->config_source == RESOLVE_CONFIG_SOURCE_FILE)
+ dns_server_unlink(server);
+
+ server = next;
+ }
+}
+
bool dns_server_unlink_marked(DnsServer *server) {
bool changed = false;
diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h
index ed6560fa9d..ef76bbc878 100644
--- a/src/resolve/resolved-dns-server.h
+++ b/src/resolve/resolved-dns-server.h
@@ -24,6 +24,8 @@ typedef enum DnsServerType {
_DNS_SERVER_TYPE_INVALID = -EINVAL,
} DnsServerType;
+#include "resolved-conf.h"
+
const char* dns_server_type_to_string(DnsServerType i) _const_;
DnsServerType dns_server_type_from_string(const char *s) _pure_;
@@ -100,6 +102,9 @@ struct DnsServer {
/* If linked is set, then this server appears in the servers linked list */
bool linked:1;
LIST_FIELDS(DnsServer, servers);
+
+ /* Servers registered via D-Bus are not removed on reload */
+ ResolveConfigSource config_source;
};
int dns_server_new(
@@ -111,7 +116,8 @@ int dns_server_new(
const union in_addr_union *address,
uint16_t port,
int ifindex,
- const char *server_string);
+ const char *server_string,
+ ResolveConfigSource config_source);
DnsServer* dns_server_ref(DnsServer *s);
DnsServer* dns_server_unref(DnsServer *s);
@@ -145,6 +151,7 @@ void dns_server_warn_downgrade(DnsServer *server);
DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, uint16_t port, int ifindex, const char *name);
void dns_server_unlink_all(DnsServer *first);
+void dns_server_unlink_on_reload(DnsServer *server);
bool dns_server_unlink_marked(DnsServer *first);
void dns_server_mark_all(DnsServer *first);
diff --git a/src/resolve/resolved-dnssd.c b/src/resolve/resolved-dnssd.c
index 8790755d3b..7f8f99717c 100644
--- a/src/resolve/resolved-dnssd.c
+++ b/src/resolve/resolved-dnssd.c
@@ -57,6 +57,16 @@ DnssdService *dnssd_service_free(DnssdService *service) {
return mfree(service);
}
+void dnssd_service_clear_on_reload(Hashmap *services) {
+ DnssdService *service;
+
+ HASHMAP_FOREACH(service, services)
+ if (service->config_source == RESOLVE_CONFIG_SOURCE_FILE) {
+ hashmap_remove(services, service->name);
+ dnssd_service_free(service);
+ }
+}
+
static int dnssd_service_load(Manager *manager, const char *filename) {
_cleanup_(dnssd_service_freep) DnssdService *service = NULL;
_cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
diff --git a/src/resolve/resolved-dnssd.h b/src/resolve/resolved-dnssd.h
index 970f2ba3c8..e7f2add397 100644
--- a/src/resolve/resolved-dnssd.h
+++ b/src/resolve/resolved-dnssd.h
@@ -3,6 +3,7 @@
#pragma once
#include "list.h"
+#include "resolved-conf.h"
typedef struct DnssdService DnssdService;
typedef struct DnssdTxtData DnssdTxtData;
@@ -44,6 +45,9 @@ struct DnssdService {
Manager *manager;
+ /* Services registered via D-Bus are not removed on reload */
+ ResolveConfigSource config_source;
+
bool withdrawn:1;
uid_t originator;
};
@@ -51,6 +55,7 @@ struct DnssdService {
DnssdService *dnssd_service_free(DnssdService *service);
DnssdTxtData *dnssd_txtdata_free(DnssdTxtData *txt_data);
DnssdTxtData *dnssd_txtdata_free_all(DnssdTxtData *txt_data);
+void dnssd_service_clear_on_reload(Hashmap *services);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdService*, dnssd_service_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdTxtData*, dnssd_txtdata_free);
diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c
index 65562dc933..656bdd9d8e 100644
--- a/src/resolve/resolved-link-bus.c
+++ b/src/resolve/resolved-link-bus.c
@@ -274,7 +274,7 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi
if (s)
dns_server_move_back_and_unmark(s);
else {
- r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name);
+ r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name, RESOLVE_CONFIG_SOURCE_DBUS);
if (r < 0) {
dns_server_unlink_all(l->dns_servers);
goto finalize;
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index dd5daddce4..bb43a73de4 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -273,7 +273,7 @@ static int link_update_dns_server_one(Link *l, const char *str) {
return 0;
}
- return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, port, 0, name);
+ return dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a, port, 0, name, RESOLVE_CONFIG_SOURCE_NETWORKD);
}
static int link_update_dns_servers(Link *l) {
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 5a14e64fe5..568ee00280 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -11,6 +11,7 @@
#include "af-list.h"
#include "alloc-util.h"
#include "bus-polkit.h"
+#include "daemon-util.h"
#include "dirent-util.h"
#include "dns-domain.h"
#include "event-util.h"
@@ -565,6 +566,73 @@ static int manager_memory_pressure_listen(Manager *m) {
return 0;
}
+static void manager_set_defaults(Manager *m) {
+ assert(m);
+
+ m->llmnr_support = DEFAULT_LLMNR_MODE;
+ m->mdns_support = DEFAULT_MDNS_MODE;
+ m->dnssec_mode = DEFAULT_DNSSEC_MODE;
+ m->dns_over_tls_mode = DEFAULT_DNS_OVER_TLS_MODE;
+ m->enable_cache = DNS_CACHE_MODE_YES;
+ m->dns_stub_listener_mode = DNS_STUB_LISTENER_YES;
+ m->read_etc_hosts = true;
+ m->resolve_unicast_single_label = false;
+ m->cache_from_localhost = false;
+ m->stale_retention_usec = 0;
+}
+
+static int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *m = ASSERT_PTR(userdata);
+ int r;
+
+ (void) notify_reloading();
+
+ manager_set_defaults(m);
+
+ dns_server_unlink_on_reload(m->dns_servers);
+ dns_server_unlink_on_reload(m->fallback_dns_servers);
+ m->dns_extra_stub_listeners = ordered_set_free(m->dns_extra_stub_listeners);
+ dnssd_service_clear_on_reload(m->dnssd_services);
+ m->unicast_scope = dns_scope_free(m->unicast_scope);
+
+ dns_trust_anchor_flush(&m->trust_anchor);
+
+ r = dns_trust_anchor_load(&m->trust_anchor);
+ if (r < 0)
+ return r;
+
+ r = manager_parse_config_file(m);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse config file on reload: %m");
+ else
+ log_info("Config file reloaded.");
+
+ r = dnssd_load(m);
+ if (r < 0)
+ log_warning_errno(r, "Failed to load DNS-SD configuration files: %m");
+
+ /* The default scope configuration is influenced by the manager's configuration (modes, etc.), so
+ * recreate it on reload. */
+ r = dns_scope_new(m, &m->unicast_scope, NULL, DNS_PROTOCOL_DNS, AF_UNSPEC);
+ if (r < 0)
+ return r;
+
+ /* The configuration has changed, so reload the per-interface configuration too in order to take
+ * into account any changes (e.g.: enable/disable DNSSEC). */
+ r = on_network_event(/* sd_event_source= */ NULL, -EBADF, /* revents= */ 0, m);
+ if (r < 0)
+ log_warning_errno(r, "Failed to update network information: %m");
+
+ /* We have new configuration, which means potentially new servers, so close all connections and drop
+ * all caches, so that we can start fresh. */
+ (void) dns_stream_disconnect_all(m);
+ manager_flush_caches(m, LOG_INFO);
+ manager_verify_all(m);
+
+ (void) sd_notify(/* unset= */ false, NOTIFY_READY);
+ return 0;
+}
+
int manager_new(Manager **ret) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
@@ -584,21 +652,16 @@ int manager_new(Manager **ret) {
.mdns_ipv6_fd = -EBADF,
.hostname_fd = -EBADF,
- .llmnr_support = DEFAULT_LLMNR_MODE,
- .mdns_support = DEFAULT_MDNS_MODE,
- .dnssec_mode = DEFAULT_DNSSEC_MODE,
- .dns_over_tls_mode = DEFAULT_DNS_OVER_TLS_MODE,
- .enable_cache = DNS_CACHE_MODE_YES,
- .dns_stub_listener_mode = DNS_STUB_LISTENER_YES,
.read_resolv_conf = true,
.need_builtin_fallbacks = true,
.etc_hosts_last = USEC_INFINITY,
- .read_etc_hosts = true,
.sigrtmin18_info.memory_pressure_handler = manager_memory_pressure,
.sigrtmin18_info.memory_pressure_userdata = m,
};
+ manager_set_defaults(m);
+
r = dns_trust_anchor_load(&m->trust_anchor);
if (r < 0)
return r;
@@ -619,6 +682,7 @@ int manager_new(Manager **ret) {
(void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
(void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
+ (void) sd_event_add_signal(m->event, NULL, SIGHUP | SD_EVENT_SIGNAL_PROCMASK, manager_dispatch_reload_signal, m);
(void) sd_event_set_watchdog(m->event, true);
diff --git a/test/units/testsuite-75.sh b/test/units/testsuite-75.sh
index 7bfc067e05..275bf296b8 100755
--- a/test/units/testsuite-75.sh
+++ b/test/units/testsuite-75.sh
@@ -102,12 +102,21 @@ assert_in '_localdnsproxy' "$(dig @127.0.0.53 -x 127.0.0.54)"
mkdir -p /run/systemd/resolved.conf.d
{
echo "[Resolve]"
- echo "MulticastDNS=yes"
- echo "LLMNR=yes"
+ echo "MulticastDNS=no"
+ echo "LLMNR=no"
} >/run/systemd/resolved.conf.d/mdns-llmnr.conf
restart_resolved
# make sure networkd is not running.
systemctl stop systemd-networkd.service
+assert_in 'no' "$(resolvectl mdns hoge)"
+assert_in 'no' "$(resolvectl llmnr hoge)"
+# Tests that reloading works
+{
+ echo "[Resolve]"
+ echo "MulticastDNS=yes"
+ echo "LLMNR=yes"
+} >/run/systemd/resolved.conf.d/mdns-llmnr.conf
+systemctl reload systemd-resolved.service
# defaults to yes (both the global and per-link settings are yes)
assert_in 'yes' "$(resolvectl mdns hoge)"
assert_in 'yes' "$(resolvectl llmnr hoge)"
@@ -130,7 +139,7 @@ assert_in 'no' "$(resolvectl llmnr hoge)"
echo "MulticastDNS=resolve"
echo "LLMNR=resolve"
} >/run/systemd/resolved.conf.d/mdns-llmnr.conf
-restart_resolved
+systemctl reload systemd-resolved.service
# set per-link setting
resolvectl mdns hoge yes
resolvectl llmnr hoge yes
@@ -150,7 +159,7 @@ assert_in 'no' "$(resolvectl llmnr hoge)"
echo "MulticastDNS=no"
echo "LLMNR=no"
} >/run/systemd/resolved.conf.d/mdns-llmnr.conf
-restart_resolved
+systemctl reload systemd-resolved.service
# set per-link setting
resolvectl mdns hoge yes
resolvectl llmnr hoge yes
@@ -180,13 +189,13 @@ fd00:dead:beef:cafe::1 ns1.unsigned.test
127.128.0.5 localhost5 localhost5.localdomain localhost5.localdomain4 localhost.localdomain5 localhost5.localdomain5
EOF
-mkdir -p /etc/systemd/network
-cat >/etc/systemd/network/10-dns0.netdev <<EOF
+mkdir -p /run/systemd/network
+cat >/run/systemd/network/10-dns0.netdev <<EOF
[NetDev]
Name=dns0
Kind=dummy
EOF
-cat >/etc/systemd/network/10-dns0.network <<EOF
+cat >/run/systemd/network/10-dns0.network <<EOF
[Match]
Name=dns0
@@ -197,12 +206,12 @@ DNSSEC=allow-downgrade
DNS=10.0.0.1
DNS=fd00:dead:beef:cafe::1
EOF
-cat >/etc/systemd/network/10-dns1.netdev <<EOF
+cat >/run/systemd/network/10-dns1.netdev <<EOF
[NetDev]
Name=dns1
Kind=dummy
EOF
-cat >/etc/systemd/network/10-dns1.network <<EOF
+cat >/run/systemd/network/10-dns1.network <<EOF
[Match]
Name=dns1
@@ -254,7 +263,8 @@ ln -svf /etc/bind.keys /etc/bind/bind.keys
# Start the services
systemctl unmask systemd-networkd
systemctl start systemd-networkd
-restart_resolved
+/usr/lib/systemd/systemd-networkd-wait-online --interface=dns1:routable --timeout=60
+systemctl reload systemd-resolved
systemctl start resolved-dummy-server
# Create knot's runtime dir, since from certain version it's provided only by
# the package and not created by tmpfiles/systemd
@@ -720,7 +730,7 @@ if command -v nft >/dev/null; then
echo "StaleRetentionSec=1d"
} >/run/systemd/resolved.conf.d/test.conf
ln -svf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
- restart_resolved
+ systemctl reload systemd-resolved.service
run dig stale1.unsigned.test -t A
grep -qE "NOERROR" "$RUN_OUT"
@@ -850,6 +860,21 @@ test "$(resolvectl --json=short query -t A localhost)" == '{"key":{"class":1,"ty
test "$(varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveRecord '{"name":"localhost","type":1}' --json=short)" == '{"rrs":[{"ifindex":1,"rr":{"key":{"class":1,"type":1,"name":"localhost"},"address":[127,0,0,1]},"raw":"CWxvY2FsaG9zdAAAAQABAAAAAAAEfwAAAQ=="}],"flags":786945}'
test "$(varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveRecord '{"name":"localhost","type":28}' --json=short)" == '{"rrs":[{"ifindex":1,"rr":{"key":{"class":1,"type":28,"name":"localhost"},"address":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]},"raw":"CWxvY2FsaG9zdAAAHAABAAAAAAAQAAAAAAAAAAAAAAAAAAAAAQ=="}],"flags":786945}'
+# Ensure that reloading keeps the manually configured address
+{
+ echo "[Resolve]"
+ echo "DNS=8.8.8.8"
+} >/run/systemd/resolved.conf.d/reload.conf
+resolvectl dns dns0 1.1.1.1
+systemctl reload systemd-resolved.service
+resolvectl status
+resolvectl dns dns0 | grep -qF "1.1.1.1"
+# For some reason piping this last command to grep fails with:
+# 'resolvectl[1378]: Failed to print table: Broken pipe'
+# so use an intermediate file in /tmp/
+resolvectl >/tmp/output
+grep -qF "DNS Servers: 8.8.8.8" /tmp/output
+
# Check if resolved exits cleanly.
restart_resolved
diff --git a/units/systemd-resolved.service.in b/units/systemd-resolved.service.in
index 820aecfef6..717f572bc5 100644
--- a/units/systemd-resolved.service.in
+++ b/units/systemd-resolved.service.in
@@ -48,7 +48,7 @@ RuntimeDirectoryPreserve=yes
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service
-Type=notify
+Type=notify-reload
User=systemd-resolve
ImportCredential=network.dns
ImportCredential=network.search_domains