trust-dns: split the parts which are generalizable into their own file
i can try to build this into a recursive resolver for *all* my hosts
This commit is contained in:
@@ -2,19 +2,11 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
dyn-dns = config.sane.services.dyn-dns;
|
||||||
nativeAddrs = lib.mapAttrs (_name: builtins.head) config.sane.dns.zones."uninsane.org".inet.A;
|
nativeAddrs = lib.mapAttrs (_name: builtins.head) config.sane.dns.zones."uninsane.org".inet.A;
|
||||||
bindOvpn = "10.0.1.5";
|
bindOvpn = "10.0.1.5";
|
||||||
in lib.mkMerge [
|
in
|
||||||
{
|
{
|
||||||
services.trust-dns.enable = true;
|
|
||||||
|
|
||||||
# don't bind to IPv6 until i explicitly test that stack
|
|
||||||
services.trust-dns.settings.listen_addrs_ipv6 = [];
|
|
||||||
services.trust-dns.quiet = true;
|
|
||||||
# FIXME(2023/11/26): services.trust-dns.debug doesn't log requests: use RUST_LOG=debug env for that.
|
|
||||||
# - see: <https://github.com/hickory-dns/hickory-dns/issues/2082>
|
|
||||||
# services.trust-dns.debug = true;
|
|
||||||
|
|
||||||
sane.ports.ports."53" = {
|
sane.ports.ports."53" = {
|
||||||
protocol = [ "udp" "tcp" ];
|
protocol = [ "udp" "tcp" ];
|
||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
@@ -66,23 +58,6 @@ in lib.mkMerge [
|
|||||||
|
|
||||||
services.trust-dns.settings.zones = [ "uninsane.org" ];
|
services.trust-dns.settings.zones = [ "uninsane.org" ];
|
||||||
|
|
||||||
# TODO: can i transform this into some sort of service group?
|
|
||||||
# have `systemctl restart trust-dns.service` restart all the individual services?
|
|
||||||
systemd.services.trust-dns.serviceConfig = {
|
|
||||||
DynamicUser = lib.mkForce false;
|
|
||||||
User = "trust-dns";
|
|
||||||
Group = "trust-dns";
|
|
||||||
wantedBy = lib.mkForce [];
|
|
||||||
};
|
|
||||||
systemd.services.trust-dns.enable = false;
|
|
||||||
|
|
||||||
users.groups.trust-dns = {};
|
|
||||||
users.users.trust-dns = {
|
|
||||||
group = "trust-dns";
|
|
||||||
isSystemUser = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# sane.services.dyn-dns.restartOnChange = [ "trust-dns.service" ];
|
|
||||||
|
|
||||||
networking.nat.enable = true;
|
networking.nat.enable = true;
|
||||||
networking.nat.extraCommands = ''
|
networking.nat.extraCommands = ''
|
||||||
@@ -107,97 +82,72 @@ in lib.mkMerge [
|
|||||||
visibleTo.lan = true;
|
visibleTo.lan = true;
|
||||||
description = "colin-redirected-dns-for-lan-namespace";
|
description = "colin-redirected-dns-for-lan-namespace";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
sane.services.trust-dns.enable = true;
|
||||||
|
sane.services.trust-dns.instances = let
|
||||||
|
mkSubstitutions = flavor: {
|
||||||
|
"%AWAN%" = "$(cat '${dyn-dns.ipPath}')";
|
||||||
|
"%CNAMENATIVE%" = "servo.${flavor}";
|
||||||
|
"%ANATIVE%" = nativeAddrs."servo.${flavor}";
|
||||||
|
"%AOVPNS%" = "185.157.162.178";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
wan = {
|
||||||
|
substitutions = mkSubstitutions "wan";
|
||||||
|
listenAddrs = [
|
||||||
|
nativeAddrs."servo.lan"
|
||||||
|
bindOvpn
|
||||||
|
];
|
||||||
|
};
|
||||||
|
lan = {
|
||||||
|
substitutions = mkSubstitutions "lan";
|
||||||
|
listenAddrs = [ nativeAddrs."servo.lan" ];
|
||||||
|
port = 1053;
|
||||||
|
};
|
||||||
|
hn = {
|
||||||
|
substitutions = mkSubstitutions "hn";
|
||||||
|
listenAddrs = [ nativeAddrs."servo.hn" ];
|
||||||
|
port = 1053;
|
||||||
|
};
|
||||||
|
hn-resolver = {
|
||||||
|
# don't need %AWAN% here because we forward to the hn instance.
|
||||||
|
listenAddrs = [ nativeAddrs."servo.hn" ];
|
||||||
|
extraConfig = {
|
||||||
|
zones = [
|
||||||
|
{
|
||||||
|
zone = "uninsane.org";
|
||||||
|
zone_type = "Forward";
|
||||||
|
stores = {
|
||||||
|
type = "forward";
|
||||||
|
name_servers = [
|
||||||
|
{
|
||||||
|
socket_addr = "${nativeAddrs."servo.hn"}:1053";
|
||||||
|
protocol = "udp";
|
||||||
|
trust_nx_responses = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
systemd.services =
|
|
||||||
let
|
|
||||||
sed = "${pkgs.gnused}/bin/sed";
|
|
||||||
stateDir = "/var/lib/trust-dns";
|
|
||||||
zoneTemplate = pkgs.writeText "uninsane.org.zone.in" config.sane.dns.zones."uninsane.org".rendered;
|
|
||||||
|
|
||||||
zoneDirFor = flavor: "${stateDir}/${flavor}";
|
|
||||||
zoneFor = flavor: "${zoneDirFor flavor}/uninsane.org.zone";
|
|
||||||
mkTrustDnsService = opts: flavor: let
|
|
||||||
flags = let baseCfg = config.services.trust-dns; in
|
|
||||||
(lib.optional baseCfg.debug "--debug") ++ (lib.optional baseCfg.quiet "--quiet");
|
|
||||||
flagsStr = builtins.concatStringsSep " " flags;
|
|
||||||
|
|
||||||
anative = nativeAddrs."servo.${flavor}";
|
|
||||||
|
|
||||||
toml = pkgs.formats.toml { };
|
|
||||||
configTemplate = opts.config or (toml.generate "trust-dns-${flavor}.toml" (
|
|
||||||
(
|
|
||||||
lib.filterAttrsRecursive (_: v: v != null) config.services.trust-dns.settings
|
|
||||||
) // {
|
|
||||||
listen_addrs_ipv4 = opts.listen or [ anative ];
|
|
||||||
}
|
|
||||||
));
|
|
||||||
configFile = "${stateDir}/${flavor}-config.toml";
|
|
||||||
|
|
||||||
port = opts.port or 53;
|
|
||||||
in {
|
|
||||||
description = "trust-dns Domain Name Server (serving ${flavor})";
|
|
||||||
unitConfig.Documentation = "https://trust-dns.org/";
|
|
||||||
|
|
||||||
preStart = ''
|
|
||||||
wan=$(cat '${config.sane.services.dyn-dns.ipPath}')
|
|
||||||
${sed} s/%AWAN%/$wan/ ${configTemplate} > ${configFile}
|
|
||||||
'' + lib.optionalString (!opts ? config) ''
|
|
||||||
mkdir -p ${zoneDirFor flavor}
|
|
||||||
${sed} \
|
|
||||||
-e s/%CNAMENATIVE%/servo.${flavor}/ \
|
|
||||||
-e s/%ANATIVE%/${anative}/ \
|
|
||||||
-e s/%AWAN%/$wan/ \
|
|
||||||
-e s/%AOVPNS%/185.157.162.178/ \
|
|
||||||
${zoneTemplate} > ${zoneFor flavor}
|
|
||||||
'';
|
|
||||||
serviceConfig = config.systemd.services.trust-dns.serviceConfig // {
|
|
||||||
ExecStart = ''
|
|
||||||
${pkgs.trust-dns}/bin/${pkgs.trust-dns.meta.mainProgram} \
|
|
||||||
--port ${builtins.toString port} \
|
|
||||||
--zonedir ${zoneDirFor flavor}/ \
|
|
||||||
--config ${configFile} ${flagsStr}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
after = [ "network.target" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
trust-dns-wan = mkTrustDnsService { listen = [ nativeAddrs."servo.lan" bindOvpn ]; } "wan";
|
|
||||||
trust-dns-lan = mkTrustDnsService { port = 1053; } "lan";
|
|
||||||
trust-dns-hn = mkTrustDnsService { port = 1053; } "hn";
|
|
||||||
trust-dns-hn-resolver = mkTrustDnsService {
|
|
||||||
config = pkgs.writeText "hn-resolver-config.toml" ''
|
|
||||||
# i host a resolver in the wireguard VPN so that clients can resolve DNS through the VPN.
|
|
||||||
# (that's what this file achieves).
|
|
||||||
#
|
|
||||||
# one would expect this resolver could host the authoritative zone for `uninsane.org`, and then forward everything else to the system resolver...
|
|
||||||
# and while that works for `dig`, it breaks for `nslookup` (and so `ssh`, etc).
|
|
||||||
#
|
|
||||||
# DNS responses include a flag for if the responding server is the authority of the zone queried.
|
|
||||||
# it seems that default Linux stub resolvers either:
|
|
||||||
# - expect DNSSEC when the response includes that bit, or
|
|
||||||
# - expect A records to be in the `answer` section instead of `additional` section.
|
|
||||||
# or perhaps something more nuanced. but for `nslookup` to be reliable, it has to talk to an
|
|
||||||
# instance of trust-dns which is strictly a resolver, with no authority.
|
|
||||||
# hence, this config: a resolver which forwards to the actual authority.
|
|
||||||
|
|
||||||
listen_addrs_ipv4 = ["${nativeAddrs."servo.hn"}"]
|
|
||||||
listen_addrs_ipv6 = []
|
|
||||||
|
|
||||||
[[zones]]
|
|
||||||
zone = "uninsane.org"
|
|
||||||
zone_type = "Forward"
|
|
||||||
stores = { type = "forward", name_servers = [{ socket_addr = "${nativeAddrs."servo.hn"}:1053", protocol = "udp", trust_nx_responses = true }] }
|
|
||||||
|
|
||||||
[[zones]]
|
|
||||||
# forward the root zone to the local DNS resolver
|
# forward the root zone to the local DNS resolver
|
||||||
zone = "."
|
zone = ".";
|
||||||
zone_type = "Forward"
|
zone_type = "Forward";
|
||||||
stores = { type = "forward", name_servers = [{ socket_addr = "127.0.0.53:53", protocol = "udp", trust_nx_responses = true }] }
|
stores = {
|
||||||
'';
|
type = "forward";
|
||||||
} "hn-resolver";
|
name_servers = [
|
||||||
|
{
|
||||||
|
socket_addr = "127.0.0.53:53";
|
||||||
|
protocol = "udp";
|
||||||
|
trust_nx_responses = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
sane.services.dyn-dns.restartOnChange = [
|
sane.services.dyn-dns.restartOnChange = [
|
||||||
@@ -207,4 +157,3 @@ in lib.mkMerge [
|
|||||||
# "trust-dns-hn-resolver.service" # doesn't need restart because it doesn't know about WAN IP
|
# "trust-dns-hn-resolver.service" # doesn't need restart because it doesn't know about WAN IP
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
]
|
|
||||||
|
@@ -7,5 +7,6 @@
|
|||||||
./kiwix-serve.nix
|
./kiwix-serve.nix
|
||||||
./mautrix-signal.nix
|
./mautrix-signal.nix
|
||||||
./nixserve.nix
|
./nixserve.nix
|
||||||
|
./trust-dns.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
131
modules/services/trust-dns.nix
Normal file
131
modules/services/trust-dns.nix
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.sane.services.trust-dns;
|
||||||
|
dns = config.sane.dns;
|
||||||
|
toml = pkgs.formats.toml { };
|
||||||
|
instanceModule = with lib; types.submodule {
|
||||||
|
options = {
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 53;
|
||||||
|
};
|
||||||
|
listenAddrs = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
IP addresses to serve requests from.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
substitutions = mkOption {
|
||||||
|
type = types.attrsOf types.str;
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
text substitutions to make on the config and zone file before starting trust-dns.
|
||||||
|
'';
|
||||||
|
example = {
|
||||||
|
"%CNAMESELF%" = "lappy";
|
||||||
|
"%AWAN%" = ''"$(cat /var/www/wan.txt)"'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
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
|
||||||
|
) // {
|
||||||
|
listen_addrs_ipv4 = listenAddrs;
|
||||||
|
} // extraConfig
|
||||||
|
);
|
||||||
|
configPath = "/var/lib/trust-dns/${flavor}-config.toml";
|
||||||
|
sedArgs = lib.mapAttrsToList (key: value: ''-e "s/${key}/${value}/g"'') substitutions;
|
||||||
|
subs = lib.concatStringsSep " " sedArgs;
|
||||||
|
in {
|
||||||
|
description = "trust-dns Domain Name Server (serving ${flavor})";
|
||||||
|
unitConfig.Documentation = "https://trust-dns.org/";
|
||||||
|
|
||||||
|
preStart = lib.concatStringsSep "\n" (
|
||||||
|
[''
|
||||||
|
mkdir -p "/var/lib/trust-dns/${flavor}"
|
||||||
|
${sed} ${subs} -e "" "${configTemplate}" > "${configPath}"
|
||||||
|
''] ++ lib.mapAttrsToList (zone: { rendered, ... }: ''
|
||||||
|
${sed} ${subs} -e "" ${pkgs.writeText "${zone}.zone.in" rendered} \
|
||||||
|
> "/var/lib/trust-dns/${flavor}/${zone}.zone"
|
||||||
|
'') dns.zones
|
||||||
|
);
|
||||||
|
|
||||||
|
serviceConfig = config.systemd.services.trust-dns.serviceConfig // {
|
||||||
|
ExecStart = lib.escapeShellArgs ([
|
||||||
|
"${pkgs.trust-dns}/bin/${pkgs.trust-dns.meta.mainProgram}"
|
||||||
|
"--port" (builtins.toString port)
|
||||||
|
"--zonedir" "/var/lib/trust-dns/${flavor}"
|
||||||
|
"--config" "${configPath}"
|
||||||
|
] ++ lib.optionals config.services.trust-dns.debug [
|
||||||
|
"--debug"
|
||||||
|
] ++ lib.optionals config.services.trust-dns.quiet [
|
||||||
|
"--quiet"
|
||||||
|
]);
|
||||||
|
ReadOnlyPaths = [ "/var/lib/uninsane" ]; # for dyn-dns (wan.txt)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = with lib; {
|
||||||
|
sane.services.trust-dns = {
|
||||||
|
enable = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
instances = mkOption {
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf instanceModule;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
# 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;
|
||||||
|
|
||||||
|
# don't bind to IPv6 until i explicitly test that stack
|
||||||
|
services.trust-dns.settings.listen_addrs_ipv6 = [];
|
||||||
|
services.trust-dns.quiet = true;
|
||||||
|
# FIXME(2023/11/26): services.trust-dns.debug doesn't log requests: use RUST_LOG=debug env for that.
|
||||||
|
# - see: <https://github.com/hickory-dns/hickory-dns/issues/2082>
|
||||||
|
# services.trust-dns.debug = true;
|
||||||
|
|
||||||
|
users.groups.trust-dns = {};
|
||||||
|
users.users.trust-dns = {
|
||||||
|
group = "trust-dns";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services = lib.mkMerge [
|
||||||
|
{
|
||||||
|
trust-dns.enable = false;
|
||||||
|
trust-dns.serviceConfig = {
|
||||||
|
DynamicUser = lib.mkForce false;
|
||||||
|
User = "trust-dns";
|
||||||
|
Group = "trust-dns";
|
||||||
|
wantedBy = lib.mkForce [];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(lib.mapAttrs'
|
||||||
|
(flavor: instanceConfig: {
|
||||||
|
name = "trust-dns-${flavor}";
|
||||||
|
value = mkSystemdService flavor instanceConfig;
|
||||||
|
})
|
||||||
|
cfg.instances
|
||||||
|
)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
Reference in New Issue
Block a user