From 6af676816057d63bc78e1accf62821c77c4785fb Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 3 Dec 2024 23:28:16 +0000 Subject: [PATCH] unbound: fix NTP/DNS circular dependency by disabling DNSSEC for pool.ntp.org. --- hosts/common/net/default.nix | 1 + hosts/common/net/dns/unbound.nix | 8 +++++--- hosts/common/net/ntp.nix | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 hosts/common/net/ntp.nix diff --git a/hosts/common/net/default.nix b/hosts/common/net/default.nix index 4143b116d..9ba366e44 100644 --- a/hosts/common/net/default.nix +++ b/hosts/common/net/default.nix @@ -6,6 +6,7 @@ ./hostnames.nix ./modemmanager.nix ./networkmanager.nix + ./ntp.nix ./upnp.nix ./vpn.nix ]; diff --git a/hosts/common/net/dns/unbound.nix b/hosts/common/net/dns/unbound.nix index 24d164b82..7e9d6d7f3 100644 --- a/hosts/common/net/dns/unbound.nix +++ b/hosts/common/net/dns/unbound.nix @@ -11,10 +11,12 @@ # effectively disable DNSSEC, to avoid a circular dependency between DNS resolution and NTP. # without this, if the RTC fails, then both time and DNS are unrecoverable. # if you enable this, make sure to persist the stateful data. + # services.unbound.enableRootTrustAnchor = false; + # alternatively, exempt only pool.ntp.org (and thereby also its children) from DNSSEC chain-of-trust validation. + services.unbound.settings.domain-insecure = "pool.ntp.org"; # alternatively, use services.unbound.settings.trust-anchor = ... (or trusted-keys-file) - services.unbound.enableRootTrustAnchor = false; - # root hints: are compiled-in (iterator/iter_hints.c), but sometimes `dig m.root-servers.net.` can *fail*. - # idk what that is about; hopefully manually specifying the hint triggers a less broken code path? + + # root hints: are compiled-in (iterator/iter_hints.c), but can alternatively use more up-to-date ones should the nixos unbound package become outdated. # services.unbound.settings.server.root-hints = "${pkgs.dns-root-data}/root.hints"; # scenario: net blip; unbound caches that a bunch of NS are unreachable; future queries fail diff --git a/hosts/common/net/ntp.nix b/hosts/common/net/ntp.nix new file mode 100644 index 000000000..d0a8bef97 --- /dev/null +++ b/hosts/common/net/ntp.nix @@ -0,0 +1,32 @@ +# NTP and DNS/DNSSEC have a chicken-and-egg issue: +# - NTP needs to resolve DNS to know how to query the servers (`0.nixos.pool.ntp.org`, etc) +# - DNS needs to have a semi-accurate clock to validate DNSSEC for resolutions +# +# nixos and systemd-timesyncd overcome this in the default installation by: +# - setting `SYSTEMD_NSS_RESOLVE_VALIDATE=0` in the systemd-timesyncd.service unit file +# - systemd nss module which plumbs that to systemd-resolved +# that ONLY WORKS if using systemd-resolved. +# +# my alternative fix here is to hardcode a list of fallback NTP IP addresses, to use when DNS resolution of the primaries fails. +# +# lastly, the clock can be manually set: +# - `systemctl stop systemd-timesyncd` +# - `sudo timedatectl --adjust-system-clock set-time '2024-01-01 00:00:01 UTC'` +# - `systemctl start systemd-timesyncd` +# +# XXX(2024-12-03): i fixed the NTP-DNS circularity by exempting `pool.ntp.org` from DNSSEC validation in unbound conf +{ config, ... }: +{ + # services.timesyncd.servers = config.networking.timeServers; + # services.timesyncd.fallbackServers = [ + # "129.6.15.28" # time-a-g.nist.gov + # "132.163.97.1" # time-a-wwv.nist.gov + # "132.163.96.1" # time-a-b.nist.gov + # "128.138.140.44" # utcnist.colorado.edu + # "162.159.200.1" # time.cloudflare.com + # ]; + + # more feature-complete NTP implementations exist, like `chrony`, should i ever wish to also be a NTP **server**: + # services.chrony.enable = true; + # services.chrony.enableNTS = true; +}