wait-online: handle varlink connection errors while waiting for DNS (#37283)
Currently, if systemd-networkd-wait-online is started with --dns, and systemd-resolved is not running, it will exit with an error right away. Similarly, if systemd-resolved is restarted while waiting for DNS configuration, systemd-networkd-wait-online will not attempt to re-connect, and will potentially never see subsequent DNS configurations. Improve this by adding socket units for the systemd-resolved varlink servers, and re-establish the connection in systemd-networkd-wait-online when we receive `SD_VARLINK_ERROR_DISCONNECTED`.
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'],
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user