From 0fa188307b1c286e7b86201b1cfb91014b970092 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Tue, 29 Apr 2025 15:14:32 -0400 Subject: [PATCH 1/3] resolved: support socket activation via varlink sockets Add two new socket units, one for each of systemd-resolved's varlink servers: systemd-resolved-varlink.socket systemd-resolved-monitor.socket Add logic to grab socket fds via sd_varlink_server_listen_name(), but fallback to the existing sd_varlink_server_listen_address() calls if no fds were given. This will be used to make systemd-networkd-wait-online --dns more robust against systemd-resolved restarts etc. --- src/resolve/resolved-varlink.c | 18 ++++++++++++++---- units/meson.build | 8 ++++++++ units/systemd-resolved-monitor.socket | 24 ++++++++++++++++++++++++ units/systemd-resolved-varlink.socket | 24 ++++++++++++++++++++++++ units/systemd-resolved.service.in | 5 +++-- 5 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 units/systemd-resolved-monitor.socket create mode 100644 units/systemd-resolved-varlink.socket diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index dd4c137c75..1a50f64a85 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -1423,9 +1423,14 @@ static int varlink_monitor_server_init(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to register varlink disconnect handler: %m"); - r = sd_varlink_server_listen_address(server, "/run/systemd/resolve/io.systemd.Resolve.Monitor", 0666); + r = sd_varlink_server_listen_name(server, "varlink-monitor"); if (r < 0) - return log_error_errno(r, "Failed to bind to varlink socket: %m"); + return log_error_errno(r, "Failed to get varlink listen fd: %m"); + if (r == 0) { + r = sd_varlink_server_listen_address(server, "/run/systemd/resolve/io.systemd.Resolve.Monitor", 0666); + if (r < 0) + return log_error_errno(r, "Failed to bind to varlink socket: %m"); + } r = sd_varlink_server_attach_event(server, m->event, SD_EVENT_PRIORITY_NORMAL); if (r < 0) @@ -1472,9 +1477,14 @@ static int varlink_main_server_init(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to register varlink disconnect handler: %m"); - r = sd_varlink_server_listen_address(s, "/run/systemd/resolve/io.systemd.Resolve", 0666); + r = sd_varlink_server_listen_auto(s); if (r < 0) - return log_error_errno(r, "Failed to bind to varlink socket: %m"); + return log_error_errno(r, "Failed to get varlink listen fd: %m"); + if (r == 0) { + r = sd_varlink_server_listen_address(s, "/run/systemd/resolve/io.systemd.Resolve", 0666); + if (r < 0) + return log_error_errno(r, "Failed to bind to varlink socket: %m"); + } r = sd_varlink_server_attach_event(s, m->event, SD_EVENT_PRIORITY_NORMAL); if (r < 0) diff --git a/units/meson.build b/units/meson.build index cacb1524d6..3dd135942d 100644 --- a/units/meson.build +++ b/units/meson.build @@ -662,6 +662,14 @@ units = [ 'file' : 'systemd-resolved.service.in', 'conditions' : ['ENABLE_RESOLVE'], }, + { + 'file' : 'systemd-resolved-varlink.socket', + 'conditions' : ['ENABLE_RESOLVE'], + }, + { + 'file' : 'systemd-resolved-monitor.socket', + 'conditions' : ['ENABLE_RESOLVE'], + }, { 'file' : 'systemd-rfkill.service.in', 'conditions' : ['ENABLE_RFKILL'], diff --git a/units/systemd-resolved-monitor.socket b/units/systemd-resolved-monitor.socket new file mode 100644 index 0000000000..a778e60dd2 --- /dev/null +++ b/units/systemd-resolved-monitor.socket @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Resolve Monitor Varlink Socket +Documentation=man:systemd-resolved.service(8) +DefaultDependencies=no +Before=sockets.target shutdown.target +Conflicts=shutdown.target + +[Socket] +Service=systemd-resolved.service +ListenStream=/run/systemd/resolve/io.systemd.Resolve.Monitor +FileDescriptorName=varlink-monitor +SocketMode=0666 + +[Install] +WantedBy=sockets.target diff --git a/units/systemd-resolved-varlink.socket b/units/systemd-resolved-varlink.socket new file mode 100644 index 0000000000..7ac83e5ec9 --- /dev/null +++ b/units/systemd-resolved-varlink.socket @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Resolve Service Varlink Socket +Documentation=man:systemd-resolved.service(8) +DefaultDependencies=no +Before=sockets.target shutdown.target +Conflicts=shutdown.target + +[Socket] +Service=systemd-resolved.service +ListenStream=/run/systemd/resolve/io.systemd.Resolve +FileDescriptorName=varlink +SocketMode=0666 + +[Install] +WantedBy=sockets.target diff --git a/units/systemd-resolved.service.in b/units/systemd-resolved.service.in index f18fbd89e8..a9224f09da 100644 --- a/units/systemd-resolved.service.in +++ b/units/systemd-resolved.service.in @@ -15,10 +15,10 @@ Documentation=https://systemd.io/WRITING_NETWORK_CONFIGURATION_MANAGERS Documentation=https://systemd.io/WRITING_RESOLVER_CLIENTS DefaultDependencies=no -After=systemd-sysctl.service systemd-sysusers.service +After=systemd-sysctl.service systemd-sysusers.service systemd-resolved-varlink.socket systemd-resolved-monitor.socket Before=sysinit.target network.target nss-lookup.target shutdown.target initrd-switch-root.target Conflicts=shutdown.target initrd-switch-root.target -Wants=nss-lookup.target +Wants=nss-lookup.target systemd-resolved-varlink.socket systemd-resolved-monitor.socket [Service] AmbientCapabilities=CAP_SETPCAP CAP_NET_RAW CAP_NET_BIND_SERVICE @@ -57,3 +57,4 @@ ImportCredential=network.search_domains [Install] WantedBy=sysinit.target Alias=dbus-org.freedesktop.resolve1.service +Also=systemd-resolved-varlink.socket systemd-resolved-monitor.socket From 5e67cb3bedf65f843a397c7105deeb6b28f549e2 Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Tue, 29 Apr 2025 15:16:45 -0400 Subject: [PATCH 2/3] wait-online: attempt to re-connect after varlink disconnects Now that systemd-resolved has socket activation for it's varlink sockets, this should should be enough to make the DNS configuration logic robust against systemd-resolved stops and restarts. --- src/network/wait-online/manager.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/network/wait-online/manager.c b/src/network/wait-online/manager.c index 597598abc6..511b5299c2 100644 --- a/src/network/wait-online/manager.c +++ b/src/network/wait-online/manager.c @@ -338,6 +338,8 @@ static int manager_network_monitor_listen(Manager *m) { return 0; } +static int manager_dns_configuration_listen(Manager *m); + static int on_dns_configuration_event( sd_varlink *link, sd_json_variant *parameters, @@ -352,6 +354,12 @@ static int on_dns_configuration_event( assert(link); if (error_id) { + if (streq(error_id, SD_VARLINK_ERROR_DISCONNECTED)) { + log_debug("DNS configuration monitor disconnected, reconnecting..."); + + return manager_dns_configuration_listen(m); + } + log_warning("DNS configuration event error, ignoring: %s", error_id); return 0; } @@ -411,6 +419,8 @@ static int manager_dns_configuration_listen(Manager *m) { if (!m->requires_dns) return 0; + m->varlink_client = sd_varlink_unref(m->varlink_client); + r = sd_varlink_connect_address(&vl, "/run/systemd/resolve/io.systemd.Resolve.Monitor"); if (r < 0) return log_error_errno(r, "Failed to connect to io.systemd.Resolve.Monitor: %m"); From 3ea04a943239b612dab72bb22f1bffc4180c21be Mon Sep 17 00:00:00 2001 From: Nick Rosbrook Date: Mon, 28 Apr 2025 12:44:20 -0400 Subject: [PATCH 3/3] test: add a test for resolved and wait-online interactions Specifically, add a test case that ensures systemd-networkd-wait-online --dns is robust against (a) systemd-resolved absence, and (b) systemd-resolved restarts. --- test/units/TEST-75-RESOLVED.sh | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/test/units/TEST-75-RESOLVED.sh b/test/units/TEST-75-RESOLVED.sh index 3889338193..104747e8d1 100755 --- a/test/units/TEST-75-RESOLVED.sh +++ b/test/units/TEST-75-RESOLVED.sh @@ -1241,6 +1241,66 @@ testcase_14_refuse_record_types() { (! run varlinkctl call /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.ResolveService '{"name":"","type":"_mysvc._tcp","domain":"signed.test"}') } +# Test systemd-networkd-wait-online interactions with systemd-resolved +testcase_15_wait_online_dns() { + # Cleanup + # shellcheck disable=SC2317 + cleanup() { + echo "===== journalctl -u $unit =====" + journalctl -b --no-pager --no-hostname --full -u "$unit" + echo "==========" + rm -f "$override" + restart_resolved + resolvectl revert dns0 + } + + trap cleanup RETURN ERR + + local unit + local override + + unit="wait-online-dns-$(systemd-id128 new -u).service" + override="/run/systemd/resolved.conf.d/90-global-dns.conf" + + # Clear global and per-interface DNS before monitoring the configuration change. + mkdir -p "$(dirname "$override")" + { + echo "[Resolve]" + echo "DNS=" + echo "FallbackDNS=" + } > "$override" + systemctl reload systemd-resolved.service + resolvectl dns dns0 "" + resolvectl domain dns0 "" + + # Stop systemd-resolved before calling systemd-networkd-wait-online. It should retry connections. + systemctl stop systemd-resolved.service + + # Begin systemd-networkd-wait-online --dns + systemd-run -u "$unit" -p "Environment=SYSTEMD_LOG_LEVEL=debug" -p "Environment=SYSTEMD_LOG_TARGET=journal" --service-type=exec \ + /usr/lib/systemd/systemd-networkd-wait-online --timeout=20 --dns --interface=dns0 + + # Wait until it blocks waiting for updated DNS config + timeout 10 bash -c "journalctl -b -u $unit -f | grep -q -m1 'dns0: No.*DNS server is accessible'" + + # Update the global configuration. Restart rather than reload systemd-resolved so that + # systemd-networkd-wait-online has to re-connect to the varlink service. + { + echo "[Resolve]" + echo "DNS=10.0.0.1" + } > "$override" + systemctl restart systemd-resolved.service + + # Wait for the monitor to exit gracefully. + timeout 10 bash -c "while systemctl --quiet is-active $unit; do sleep 0.5; done" + + # Check that a disconnect happened, and was handled. + journalctl -b -u "$unit" --grep="DNS configuration monitor disconnected, reconnecting..." > /dev/null + + # Check that dns0 was found to be online. + journalctl -b -u "$unit" --grep="dns0: link is configured by networkd and online." > /dev/null +} + # PRE-SETUP systemctl unmask systemd-resolved.service systemctl enable --now systemd-resolved.service