diff --git a/hosts/common/net/dns.nix b/hosts/common/net/dns.nix index 175bb339..98082f18 100644 --- a/hosts/common/net/dns.nix +++ b/hosts/common/net/dns.nix @@ -23,26 +23,36 @@ # - this is fixed by either `firejail --blacklist=/var/run/nscd/socket`, or disabling nscd altogether. { lib, ... }: { - # use systemd's stub resolver. - # /etc/resolv.conf isn't sophisticated enough to use different servers per net namespace (or link). - # instead, running the stub resolver on a known address in the root ns lets us rewrite packets - # in servo's ovnps namespace to use the provider's DNS resolvers. - # a weakness is we can only query 1 NS at a time (unless we were to clone the packets?) - # TODO: rework servo's netns to use `firejail`, which is capable of spoofing /etc/resolv.conf. - services.resolved.enable = true; #< to disable, set ` = lib.mkForce false`, as other systemd features default to enabling `resolved`. - # without DNSSEC: - # - dig matrix.org => works - # - curl https://matrix.org => works - # with default DNSSEC: - # - dig matrix.org => works - # - curl https://matrix.org => fails - # i don't know why. this might somehow be interfering with the DNS run on this device (trust-dns) - services.resolved.dnssec = "false"; + # # use systemd's stub resolver. + # # /etc/resolv.conf isn't sophisticated enough to use different servers per net namespace (or link). + # # instead, running the stub resolver on a known address in the root ns lets us rewrite packets + # # in servo's ovnps namespace to use the provider's DNS resolvers. + # # a weakness is we can only query 1 NS at a time (unless we were to clone the packets?) + # # TODO: rework servo's netns to use `firejail`, which is capable of spoofing /etc/resolv.conf. + # services.resolved.enable = true; #< to disable, set ` = lib.mkForce false`, as other systemd features default to enabling `resolved`. + # # without DNSSEC: + # # - dig matrix.org => works + # # - curl https://matrix.org => works + # # with default DNSSEC: + # # - dig matrix.org => works + # # - curl https://matrix.org => fails + # # i don't know why. this might somehow be interfering with the DNS run on this device (trust-dns) + # services.resolved.dnssec = "false"; + # networking.nameservers = [ + # # use systemd-resolved resolver + # # full resolver (which understands /etc/hosts) lives on 127.0.0.53 + # # stub resolver (just forwards upstream) lives on 127.0.0.54 + # "127.0.0.53" + # ]; + + services.resolved.enable = lib.mkForce false; + sane.services.trust-dns.enable = true; + sane.services.trust-dns.instances.localhost = { + listenAddrs = [ "127.0.0.1" ]; + enableRecursiveResolver = true; + }; networking.nameservers = [ - # use systemd-resolved resolver - # full resolver (which understands /etc/hosts) lives on 127.0.0.53 - # stub resolver (just forwards upstream) lives on 127.0.0.54 - "127.0.0.53" + "127.0.0.1" ]; # nscd -- the Name Service Caching Daemon -- caches DNS query responses diff --git a/modules/services/trust-dns.nix b/modules/services/trust-dns.nix index fb509780..90cddc03 100644 --- a/modules/services/trust-dns.nix +++ b/modules/services/trust-dns.nix @@ -3,7 +3,7 @@ let cfg = config.sane.services.trust-dns; dns = config.sane.dns; toml = pkgs.formats.toml { }; - instanceModule = with lib; types.submodule { + instanceModule = with lib; types.submodule ({ config, ...}: { options = { port = mkOption { type = types.port; @@ -11,7 +11,7 @@ let }; listenAddrs = mkOption { type = types.listOf types.str; - default = []; + default = [ "127.0.0.1" ]; description = '' IP addresses to serve requests from. ''; @@ -27,17 +27,46 @@ let "%AWAN%" = ''"$(cat /var/www/wan.txt)"''; }; }; + enableRecursiveResolver = mkOption { + type = types.bool; + default = false; + description = '' + act as a recursive resolver + ''; + }; extraConfig = mkOption { type = types.attrs; default = {}; }; }; - }; - mkSystemdService = flavor: { port, listenAddrs, substitutions, extraConfig }: let + + config = { + extraConfig = lib.mkIf config.enableRecursiveResolver { + zones = [ + { + zone = "."; + zone_type = "Hint"; + stores = { + type = "recursor"; + # contains the list of toplevel DNS servers, from which to recursively resolve entries. + roots = "${pkgs.dns-root-data}/root.hints"; + + # dnssec, see: + # probably not needed: the default seems to be that dnssec is disabled + # enable_dnssec = false; + # + # defaults, untuned + # ns_cache_size = 1024; + # record_cache_size = 1048576; + }; + } + ]; + }; + }; + }); + + mkSystemdService = flavor: { port, listenAddrs, substitutions, extraConfig, ... }: let sed = "${pkgs.gnused}/bin/sed"; - zoneTemplate = pkgs.writeText - "uninsane.org.zone.in" - config.sane.dns.zones."uninsane.org".rendered; configTemplate = toml.generate "trust-dns-${flavor}.toml" ( ( lib.filterAttrsRecursive (_: v: v != null) config.services.trust-dns.settings @@ -51,8 +80,8 @@ let in { description = "trust-dns Domain Name Server (serving ${flavor})"; unitConfig.Documentation = "https://trust-dns.org/"; - - wantedBy = [ "default.target" ]; + after = [ "network.target" ]; + wantedBy = [ "network.target" ]; preStart = lib.concatStringsSep "\n" ( ['' @@ -66,7 +95,7 @@ let serviceConfig = config.systemd.services.trust-dns.serviceConfig // { ExecStart = lib.escapeShellArgs ([ - "${pkgs.trust-dns}/bin/${pkgs.trust-dns.meta.mainProgram}" + "${config.services.trust-dns.package}/bin/${config.services.trust-dns.package.meta.mainProgram}" "--port" (builtins.toString port) "--zonedir" "/var/lib/trust-dns/${flavor}" "--config" "${configPath}" @@ -75,7 +104,10 @@ let ] ++ lib.optionals config.services.trust-dns.quiet [ "--quiet" ]); - ReadOnlyPaths = [ "/var/lib/uninsane" ]; # for dyn-dns (wan.txt) + # servo/dyn-dns needs /var/lib/uninsane/wan.txt. + # this might not exist on other systems, + # so just bind the deepest path which is guaranteed to exist. + ReadOnlyPaths = [ "/var/lib" ]; }; }; in @@ -97,6 +129,7 @@ in # enable nixpkgs' trust-dns so that i get its config generation # but don't actually enable the systemd service... i'll instantiate *multiple* instances per interface further below services.trust-dns.enable = true; + services.trust-dns.settings.zones = []; #< TODO: remove once upstreamed (bad default) # don't bind to IPv6 until i explicitly test that stack services.trust-dns.settings.listen_addrs_ipv6 = []; @@ -105,6 +138,25 @@ in # - see: # services.trust-dns.debug = true; + services.trust-dns.package = pkgs.trust-dns.override { + rustPlatform.buildRustPackage = args: pkgs.rustPlatform.buildRustPackage (args // { + buildFeatures = [ + "recursor" + ]; + + # fix enough bugs inside the recursive resolver that it's compatible with my infra. + # TODO: upstream these patches! + src = pkgs.fetchFromGitea { + domain = "git.uninsane.org"; + owner = "colin"; + repo = "hickory-dns"; + rev = "67649863faf2e08f63963a96a491a4025aaf8ed6"; + hash = "sha256-vmVY8C0cCCFxy/4+g1vKZsAD5lMaufIExnFaSVVAhGM="; + }; + cargoHash = "sha256-FEjNxv1iu27SXQhz1+Aehs4es8VxT1BPz5uZq8TcG/k="; + }); + }; + users.groups.trust-dns = {}; users.users.trust-dns = { group = "trust-dns"; diff --git a/pkgs/default.nix b/pkgs/default.nix index dd7e5e49..eac68958 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -146,8 +146,6 @@ let python3 = unpatched.python3.override { packageOverrides = pythonPackagesOverlayFor final'; }; - - trust-dns = callPackage ./patched/trust-dns { inherit (unpatched) trust-dns; }; }; sane-overlay = { sane = lib.recurseIntoAttrs (sane-additional // sane-patched); diff --git a/pkgs/patched/trust-dns/default.nix b/pkgs/patched/trust-dns/default.nix deleted file mode 100644 index a41813ea..00000000 --- a/pkgs/patched/trust-dns/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ trust-dns -, fetchFromGitea -}: -trust-dns.overrideAttrs (_: { - # patched so that the recursive resolver is compatible with my infra. - src = fetchFromGitea { - domain = "git.uninsane.org"; - owner = "colin"; - repo = "hickory-dns"; - rev = "67649863faf2e08f63963a96a491a4025aaf8ed6"; - hash = "sha256-FRnFmCJI/1f92DOI1VXSPivSBzIR371gmgLUfLLiuPc="; - }; -})