mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
Fix DNS resolution on Ubuntu 22 with systemd-resolved (#77)
On Ubuntu 22 (systemd 249), systemd-resolved applies interface-scoped routing to per-link DNS servers. Configuring `resolvectl dns fips0 127.0.0.1:5354` caused resolved to attempt reaching 127.0.0.1 through fips0 (a TUN with only fd00::/8 routes), silently failing. The DNS responder never received queries. Newer systemd versions (250+) have explicit handling for loopback servers on non-loopback interfaces. Changes: - DNS responder default bind_addr changed from "127.0.0.1" to "::" so it listens on all interfaces, including fips0. Bind logic in lifecycle.rs now parses bind_addr as IpAddr and constructs a SocketAddr, handling IPv6 literal formatting. Factored into Node::bind_dns_socket with explicit IPV6_V6ONLY=0 via socket2, so IPv4 clients on 127.0.0.1:5354 still reach the responder regardless of the kernel's net.ipv6.bindv6only sysctl. - fips-dns-setup resolvectl backend now waits for fips0 to have a global IPv6 address, then configures resolved with [<fips0-addr>]:5354. That address is locally delivered by the kernel regardless of which interface resolved tries to route through. The dnsmasq and NetworkManager backends still use 127.0.0.1 (they don't have the interface-scoping issue). - Dropped hardcoded `bind_addr: "127.0.0.1"` from the packaged fips.yaml (Debian + OpenWrt). The shipped config was overriding the new default. - DNS queries are only accepted from the localhost. Verified end-to-end in a privileged Ubuntu 22.04 systemd container: dig @127.0.0.53 AAAA <npub>.fips resolves cleanly through systemd-resolved. The dns-delegate backend (systemd 258+) still uses 127.0.0.1; it has not been verified whether that backend has the same routing issue.
This commit is contained in:
@@ -43,6 +43,22 @@ wait_for_interface() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# Wait for fips0 to have a global IPv6 address assigned (up to 30s).
|
||||
# Returns the address on stdout, or empty string if timeout.
|
||||
wait_for_fips_addr() {
|
||||
for i in $(seq 1 30); do
|
||||
local addr
|
||||
addr=$(ip -6 -o addr show dev "$FIPS_INTERFACE" scope global 2>/dev/null \
|
||||
| awk '{print $4}' | cut -d/ -f1 | head -1)
|
||||
if [ -n "$addr" ]; then
|
||||
echo "$addr"
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Get systemd version number.
|
||||
systemd_version() {
|
||||
systemctl --version 2>/dev/null | head -1 | grep -oE '[0-9]+' | head -1
|
||||
@@ -74,12 +90,26 @@ EOF
|
||||
}
|
||||
|
||||
# Backend 2: resolvectl
|
||||
#
|
||||
# systemd-resolved applies interface-scoped routing to per-link DNS servers.
|
||||
# On Ubuntu 22 (systemd 249), configuring `resolvectl dns fips0 127.0.0.1:5354`
|
||||
# causes resolved to route the DNS query through fips0 and fail (127.0.0.1 is
|
||||
# not reachable via a TUN with only fd00::/8 routes). We must use fips0's own
|
||||
# global IPv6 address, which is locally delivered by the kernel regardless of
|
||||
# which interface resolved tries to route through.
|
||||
try_resolvectl() {
|
||||
command -v resolvectl >/dev/null 2>&1 || return 1
|
||||
is_active systemd-resolved.service || return 1
|
||||
|
||||
log "Configuring via resolvectl"
|
||||
resolvectl dns "$FIPS_INTERFACE" "${FIPS_DNS_ADDR}:${FIPS_DNS_PORT}"
|
||||
local fips_addr
|
||||
fips_addr=$(wait_for_fips_addr)
|
||||
if [ -z "$fips_addr" ]; then
|
||||
log "ERROR: $FIPS_INTERFACE has no global IPv6 address after 30s"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log "Configuring via resolvectl (DNS=[${fips_addr}]:${FIPS_DNS_PORT})"
|
||||
resolvectl dns "$FIPS_INTERFACE" "[${fips_addr}]:${FIPS_DNS_PORT}"
|
||||
resolvectl domain "$FIPS_INTERFACE" "~fips"
|
||||
save_backend "resolvectl"
|
||||
return 0
|
||||
|
||||
@@ -18,7 +18,10 @@ tun:
|
||||
|
||||
dns:
|
||||
enabled: true
|
||||
bind_addr: "127.0.0.1"
|
||||
# bind_addr defaults to "::" (all interfaces, dual-stack). Required so
|
||||
# systemd-resolved can reach the responder via fips0 when resolvectl
|
||||
# configures per-interface DNS forwarding.
|
||||
# bind_addr: "::"
|
||||
port: 5354
|
||||
|
||||
transports:
|
||||
|
||||
@@ -23,7 +23,8 @@ tun:
|
||||
|
||||
dns:
|
||||
enabled: true
|
||||
bind_addr: "127.0.0.1"
|
||||
# bind_addr defaults to "::" (all interfaces, dual-stack).
|
||||
# bind_addr: "::"
|
||||
port: 5354
|
||||
|
||||
transports:
|
||||
|
||||
Reference in New Issue
Block a user