mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-30 19:46:15 +00:00
The previous default configured systemd-resolved with `resolvectl dns fips0 [<fips0_addr>]:5354`, intended to bypass an Ubuntu 22 systemd 249 interface-scoping bug. That target collides with the daemon's mesh-interface filter on Linux: when an IPv6 packet's destination belongs to a non-loopback interface, the kernel attributes the packet to that interface in IPV6_PKTINFO (ipi6_ifindex == fips0) even though loopback delivery is used (tcpdump shows lo). The mesh-interface filter sees arrival_ifindex == mesh_ifindex and silently drops every query at trace level — invisible to operators at the default debug level. Net effect on stock deployments: every .fips query on systemd-resolved hosts was silently dropped. Daemon side ----------- - Default `dns.bind_addr` changes from "::" to "::1" (IPv6 loopback only). The mesh-interface filter is then defanged on the default path because loopback isn't reachable from mesh peers. The filter remains in place defensively for operators who explicitly bind "::" to expose a mesh-reachable responder. fips-dns-setup backend unification ---------------------------------- - New `try_global_drop_in` backend writes /etc/systemd/resolved.conf.d/fips.conf with DNS=[::1]:5354 and Domains=~fips. Inserted ahead of `try_resolvectl` in the dispatch chain. The standard loopback path has no interface scoping, so ipi6_ifindex reports lo and the filter passes. - All other backends now target [::1]:5354 to match the daemon's default IPv6-loopback bind: - try_dns_delegate writes DNS=[::1]:5354 - try_dnsmasq writes server=/fips/::1#5354 - try_nm_dnsmasq writes server=/fips/::1#5354 - Fixed dns-delegate file path: was /etc/systemd/dns-delegate/, must be /etc/systemd/dns-delegate.d/ (with .d suffix). systemd-resolved silently ignored the previous path. - fips-dns-teardown handles the new global-drop-in backend in cleanup. - The legacy resolvectl per-link backend stays as a fallback, documented to require careful daemon bind_addr coordination. fips-gateway upstream pairing ----------------------------- - gateway.dns.upstream default changes from 127.0.0.1:5354 to [::1]:5354 to match the daemon's default bind. Linux IPv6 sockets bound to explicit ::1 do not accept v4-mapped traffic, so the old default would have caused the gateway's startup DNS reachability probe to time out and systemd to restart-loop the service. - Operators who set a non-default daemon `dns.bind_addr` must also set `gateway.dns.upstream` to match — documented inline. Documentation ------------- - packaging/common/fips.yaml and packaging/openwrt-ipk fips.yaml examples updated; rationale for the bind_addr choice and the daemon/gateway pairing recorded inline. Test coverage ------------- - testing/dns-resolver/test.sh: real-fipsd end-to-end scenario added. Builds fipsd in a Debian 12 builder image (cached), runs the daemon with a real TUN in a privileged container, configures DNS via the setup script, and asserts `dig @127.0.0.53 AAAA <npub>.fips` returns AAAA. Refactored as a parameterized helper running across Debian 12/13 and Ubuntu 22/24/26 (5 e2e scenarios). Backend-aware assertions: on systemd >= 258 the expected backend is dns-delegate; on older systemd it's global-drop-in. Strict content checks fail CI on any [::1]:5354 drift. fips-gateway also exercised in the debian12 scenario to lock the gateway-upstream pairing. Renamed all "fipsd" references to "fips" (project convention). - testing/deb-install/ (new harness): builds the actual .deb via cargo-deb in a Debian 12 builder image (cached), installs via apt across each target distro, verifies maintainer scripts, conffile placement, binary placement, and end-to-end .fips resolution after start. Also exercises fips-gateway against the installed daemon to verify the gateway/daemon default pairing on a real .deb path. - This is the test layer that was missing — the previous harness only verified config files were written, never that queries reached the daemon. Verified: dns-resolver 78/78 assertions, deb-install 55/55 assertions across all 5 distros (debian:12, debian:trixie, ubuntu:22.04, ubuntu:24.04, ubuntu:26.04).
89 lines
2.4 KiB
Bash
Executable File
89 lines
2.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# fips-dns-teardown — Remove DNS routing for the .fips domain.
|
|
#
|
|
# Reverses whatever fips-dns-setup configured. Reads the backend from
|
|
# the state file, or cleans up all possible backends if state is missing.
|
|
|
|
set -e
|
|
|
|
FIPS_INTERFACE="fips0"
|
|
DNS_DELEGATE_FILE="/etc/systemd/dns-delegate.d/fips.dns-delegate"
|
|
RESOLVED_DROPIN_FILE="/etc/systemd/resolved.conf.d/fips.conf"
|
|
DNSMASQ_CONF="/etc/dnsmasq.d/fips.conf"
|
|
NM_DNSMASQ_CONF="/etc/NetworkManager/dnsmasq.d/fips.conf"
|
|
STATE_FILE="/run/fips/dns-backend"
|
|
|
|
log() { echo "fips-dns: $*"; }
|
|
|
|
is_active() {
|
|
systemctl is-active --quiet "$1" 2>/dev/null
|
|
}
|
|
|
|
teardown_dns_delegate() {
|
|
[ -f "$DNS_DELEGATE_FILE" ] || return 0
|
|
log "Removing dns-delegate config"
|
|
rm -f "$DNS_DELEGATE_FILE"
|
|
is_active systemd-resolved.service && systemctl restart systemd-resolved
|
|
return 0
|
|
}
|
|
|
|
teardown_resolvectl() {
|
|
command -v resolvectl >/dev/null 2>&1 || return 0
|
|
is_active systemd-resolved.service || return 0
|
|
ip link show "$FIPS_INTERFACE" >/dev/null 2>&1 || return 0
|
|
log "Reverting resolvectl config"
|
|
resolvectl revert "$FIPS_INTERFACE" 2>/dev/null || true
|
|
return 0
|
|
}
|
|
|
|
teardown_global_drop_in() {
|
|
[ -f "$RESOLVED_DROPIN_FILE" ] || return 0
|
|
log "Removing global resolved.conf.d drop-in"
|
|
rm -f "$RESOLVED_DROPIN_FILE"
|
|
is_active systemd-resolved.service && systemctl restart systemd-resolved || true
|
|
return 0
|
|
}
|
|
|
|
teardown_dnsmasq() {
|
|
[ -f "$DNSMASQ_CONF" ] || return 0
|
|
log "Removing dnsmasq config"
|
|
rm -f "$DNSMASQ_CONF"
|
|
is_active dnsmasq.service && systemctl reload dnsmasq || true
|
|
return 0
|
|
}
|
|
|
|
teardown_nm_dnsmasq() {
|
|
[ -f "$NM_DNSMASQ_CONF" ] || return 0
|
|
log "Removing NetworkManager dnsmasq config"
|
|
rm -f "$NM_DNSMASQ_CONF"
|
|
is_active NetworkManager.service && nmcli general reload 2>/dev/null || true
|
|
return 0
|
|
}
|
|
|
|
# --- Main ---
|
|
|
|
backend=""
|
|
if [ -f "$STATE_FILE" ]; then
|
|
backend=$(cat "$STATE_FILE")
|
|
fi
|
|
|
|
case "$backend" in
|
|
dns-delegate) teardown_dns_delegate ;;
|
|
global-drop-in) teardown_global_drop_in ;;
|
|
resolvectl) teardown_resolvectl ;;
|
|
dnsmasq) teardown_dnsmasq ;;
|
|
nm-dnsmasq) teardown_nm_dnsmasq ;;
|
|
none) ;; # Nothing was configured
|
|
*)
|
|
# State unknown — clean up everything
|
|
teardown_dns_delegate
|
|
teardown_global_drop_in
|
|
teardown_resolvectl
|
|
teardown_dnsmasq
|
|
teardown_nm_dnsmasq
|
|
;;
|
|
esac
|
|
|
|
rm -f "$STATE_FILE"
|
|
exit 0
|