trust-dns: split into separate (restartable) services
This commit is contained in:
parent
00b59f6985
commit
48715546e2
|
@ -1,10 +1,11 @@
|
||||||
|
# TODO: split this file apart into smaller files to make it easier to understand
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
bindLan = config.sane.hosts.by-name."servo".lan-ip;
|
bindLan = config.sane.hosts.by-name."servo".lan-ip;
|
||||||
bindHn = config.sane.hosts.by-name."servo".wg-home.ip;
|
bindHn = config.sane.hosts.by-name."servo".wg-home.ip;
|
||||||
bindOvpn = "10.0.1.5";
|
bindOvpn = "10.0.1.5";
|
||||||
in
|
in lib.mkMerge [
|
||||||
{
|
{
|
||||||
services.trust-dns.enable = true;
|
services.trust-dns.enable = true;
|
||||||
|
|
||||||
|
@ -69,15 +70,55 @@ in
|
||||||
|
|
||||||
services.trust-dns.settings.zones = [ "uninsane.org" ];
|
services.trust-dns.settings.zones = [ "uninsane.org" ];
|
||||||
|
|
||||||
services.trust-dns.package =
|
# 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.extraCommands = ''
|
||||||
|
# redirect incoming DNS requests from LAN addresses
|
||||||
|
# to the LAN-specialized DNS service
|
||||||
|
# N.B.: use the `nixos-*` chains instead of e.g. PREROUTING
|
||||||
|
# because they get cleanly reset across activations or `systemctl restart firewall`
|
||||||
|
# instead of accumulating cruft
|
||||||
|
iptables -t nat -A nixos-nat-pre -p udp --dport 53 \
|
||||||
|
-m iprange --src-range 10.78.76.0-10.78.79.255 \
|
||||||
|
-j DNAT --to-destination :1053
|
||||||
|
iptables -t nat -A nixos-nat-pre -p tcp --dport 53 \
|
||||||
|
-m iprange --src-range 10.78.76.0-10.78.79.255 \
|
||||||
|
-j DNAT --to-destination :1053
|
||||||
|
'';
|
||||||
|
sane.ports.ports."1053" = {
|
||||||
|
# because the NAT above redirects in nixos-nat-pre, LAN requests behave as though they arrived on the external interface at the redirected port.
|
||||||
|
# TODO: try nixos-nat-post instead?
|
||||||
|
# TODO: or, don't NAT from port 53 -> port 1053, but rather nat from LAN addr to a loopback addr.
|
||||||
|
# - this is complicated in that loopback is a different interface than eth0, so rewriting the destination address would cause the packets to just be dropped by the interface
|
||||||
|
protocol = [ "udp" "tcp" ];
|
||||||
|
visibleTo.lan = true;
|
||||||
|
description = "colin-redirected-dns-for-lan-namespace";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
systemd.services =
|
||||||
let
|
let
|
||||||
sed = "${pkgs.gnused}/bin/sed";
|
sed = "${pkgs.gnused}/bin/sed";
|
||||||
zone-dir = "/var/lib/trust-dns";
|
zoneDir = "/var/lib/trust-dns";
|
||||||
zone-wan = "${zone-dir}/wan/uninsane.org.zone";
|
zoneTemplate = pkgs.writeText "uninsane.org.zone.in" config.sane.dns.zones."uninsane.org".rendered;
|
||||||
zone-lan = "${zone-dir}/lan/uninsane.org.zone";
|
hnResolverConfig = pkgs.writeText "hn-resolver-config.toml" ''
|
||||||
zone-hn = "${zone-dir}/hn/uninsane.org.zone";
|
|
||||||
zone-template = pkgs.writeText "uninsane.org.zone.in" config.sane.dns.zones."uninsane.org".rendered;
|
|
||||||
hn-resolver-config = pkgs.writeText "hn-resolver-config.toml" ''
|
|
||||||
# i host a resolver in the wireguard VPN so that clients can resolve DNS through the VPN.
|
# i host a resolver in the wireguard VPN so that clients can resolve DNS through the VPN.
|
||||||
# (that's what this file achieves).
|
# (that's what this file achieves).
|
||||||
#
|
#
|
||||||
|
@ -107,111 +148,68 @@ in
|
||||||
stores = { type = "forward", name_servers = [{ socket_addr = "127.0.0.53:53", protocol = "udp", trust_nx_responses = true }] }
|
stores = { type = "forward", name_servers = [{ socket_addr = "127.0.0.53:53", protocol = "udp", trust_nx_responses = true }] }
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# TODO: rework this shell script to be independent systemd services per trust-dns instance.
|
anativeMap = {
|
||||||
in pkgs.writeShellScriptBin "trust-dns" ''
|
lan = bindLan;
|
||||||
# intercept args meant for the real trust-dns, so i can modify them
|
hn = bindHn;
|
||||||
_arg__config="$1" # --config
|
wan = "$wan"; # evaluated at runtime
|
||||||
shift
|
};
|
||||||
orig_config="$1" # /path/to/config.toml
|
zoneFor = flavor: "${zoneDir}/${flavor}/uninsane.org.zone";
|
||||||
shift
|
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;
|
||||||
|
|
||||||
# compute IP address of self for each interface
|
# TODO: since we compute the config here, we can customize the listen address right here instead of doing a string substitution.
|
||||||
mkdir -p ${zone-dir}/{wan,lan,hn}
|
toml = pkgs.formats.toml { };
|
||||||
wan=$(cat '${config.sane.services.dyn-dns.ipPath}')
|
origConfig = toml.generate "trust-dns.toml" (
|
||||||
lan=${bindLan}
|
lib.filterAttrsRecursive (_: v: v != null) config.services.trust-dns.settings
|
||||||
hn=${bindHn}
|
);
|
||||||
lanAndOvpn='${bindLan}", "${bindOvpn}'
|
|
||||||
|
|
||||||
# create specializations that resolve native.uninsane.org to different CNAMEs
|
configFile = "${zoneDir}/${flavor}-config.toml";
|
||||||
${sed} \
|
anative = anativeMap."${flavor}";
|
||||||
-e s/%AWAN%/$wan/ \
|
listen = opts.listen or anative;
|
||||||
-e s/%CNAMENATIVE%/wan/ \
|
port = opts.port or 53;
|
||||||
-e s/%ANATIVE%/$wan/ \
|
makeConfig = if opts ? config then
|
||||||
${zone-template} > ${zone-wan}
|
"ln -sf ${opts.config} ${configFile}"
|
||||||
# to service WAN, listen both on LAN interface and the OVPN interface
|
else ''
|
||||||
sed "s/%LISTEN%/$lanAndOvpn/" $orig_config > ${zone-dir}/wan-config.toml
|
wan=$(cat '${config.sane.services.dyn-dns.ipPath}')
|
||||||
|
${sed} \
|
||||||
|
-e s/%AWAN%/$wan/ \
|
||||||
|
-e s/%CNAMENATIVE%/servo.${flavor}/ \
|
||||||
|
-e s/%ANATIVE%/${anative}/ \
|
||||||
|
${zoneTemplate} > ${zoneFor flavor}
|
||||||
|
# listen only on the desired interfaces
|
||||||
|
sed 's/%LISTEN%/${listen}/' ${origConfig} > ${configFile}
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
description = "trust-dns Domain Name Server (serving ${flavor})";
|
||||||
|
unitConfig.Documentation = "https://trust-dns.org/";
|
||||||
|
|
||||||
${sed} \
|
preStart = makeConfig;
|
||||||
-e s/%AWAN%/$wan/ \
|
serviceConfig = config.systemd.services.trust-dns.serviceConfig // {
|
||||||
-e s/%CNAMENATIVE%/servo.lan/ \
|
ExecStart = ''
|
||||||
-e s/%ANATIVE%/$lan/ \
|
${pkgs.trust-dns}/bin/trust-dns \
|
||||||
${zone-template} > ${zone-lan}
|
--port ${builtins.toString port} \
|
||||||
# to service LAN, listen only on the LAN
|
--zonedir ${zoneDir}/${flavor}/ \
|
||||||
sed s/%LISTEN%/$lan/ $orig_config > ${zone-dir}/lan-config.toml
|
--config ${configFile} ${flagsStr}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
${sed} \
|
after = [ "network.target" ];
|
||||||
-e s/%AWAN%/$wan/ \
|
wantedBy = [ "multi-user.target" ];
|
||||||
-e s/%CNAMENATIVE%/servo.hn/ \
|
};
|
||||||
-e s/%ANATIVE%/$hn/ \
|
in {
|
||||||
${zone-template} > ${zone-hn}
|
trust-dns-wan = mkTrustDnsService { listen = ''${bindLan}", "${bindOvpn}''; } "wan";
|
||||||
# to service wireguard, listen only on hn
|
trust-dns-lan = mkTrustDnsService { port = 1053; } "lan";
|
||||||
sed s/%LISTEN%/$hn/ $orig_config > ${zone-dir}/hn-config.toml
|
trust-dns-hn = mkTrustDnsService { port = 1053; } "hn";
|
||||||
|
trust-dns-hn-resolver = mkTrustDnsService { config = hnResolverConfig; } "hn-resolver";
|
||||||
# launch the different interfaces, separately
|
};
|
||||||
${pkgs.trust-dns}/bin/trust-dns \
|
|
||||||
--zonedir "${zone-dir}/wan/" --config "${zone-dir}/wan-config.toml" \
|
|
||||||
"$@" &
|
|
||||||
WANPID=$!
|
|
||||||
|
|
||||||
${pkgs.trust-dns}/bin/trust-dns --port 1053 \
|
|
||||||
--zonedir "${zone-dir}/lan/" --config "${zone-dir}/lan-config.toml" \
|
|
||||||
"$@" &
|
|
||||||
LANPID=$!
|
|
||||||
|
|
||||||
ln -sf ${hn-resolver-config} ${zone-dir}/hn-resolver-config.toml
|
|
||||||
${pkgs.trust-dns}/bin/trust-dns \
|
|
||||||
--config "${zone-dir}/hn-resolver-config.toml" \
|
|
||||||
"$@" &
|
|
||||||
HNRESOLVERPID=$!
|
|
||||||
|
|
||||||
${pkgs.trust-dns}/bin/trust-dns --port 1053 \
|
|
||||||
--zonedir "${zone-dir}/hn/" --config "${zone-dir}/hn-config.toml" \
|
|
||||||
"$@" &
|
|
||||||
HNPID=$!
|
|
||||||
|
|
||||||
# wait until any of the processes exits, then kill them all and exit error
|
|
||||||
while kill -0 $WANPID $LANPID $HNRESOLVERPID $HNPID; do
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
kill $WANPID $LANPID $HNRESOLVERPID $HNPID
|
|
||||||
exit 1
|
|
||||||
'';
|
|
||||||
|
|
||||||
systemd.services.trust-dns.serviceConfig = {
|
|
||||||
DynamicUser = lib.mkForce false;
|
|
||||||
User = "trust-dns";
|
|
||||||
Group = "trust-dns";
|
|
||||||
};
|
|
||||||
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.extraCommands = ''
|
|
||||||
# redirect incoming DNS requests from LAN addresses
|
|
||||||
# to the LAN-specialized DNS service
|
|
||||||
# N.B.: use the `nixos-*` chains instead of e.g. PREROUTING
|
|
||||||
# because they get cleanly reset across activations or `systemctl restart firewall`
|
|
||||||
# instead of accumulating cruft
|
|
||||||
iptables -t nat -A nixos-nat-pre -p udp --dport 53 \
|
|
||||||
-m iprange --src-range 10.78.76.0-10.78.79.255 \
|
|
||||||
-j DNAT --to-destination :1053
|
|
||||||
iptables -t nat -A nixos-nat-pre -p tcp --dport 53 \
|
|
||||||
-m iprange --src-range 10.78.76.0-10.78.79.255 \
|
|
||||||
-j DNAT --to-destination :1053
|
|
||||||
'';
|
|
||||||
sane.ports.ports."1053" = {
|
|
||||||
# because the NAT above redirects in nixos-nat-pre, LAN requests behave as though they arrived on the external interface at the redirected port.
|
|
||||||
# TODO: try nixos-nat-post instead?
|
|
||||||
# TODO: or, don't NAT from port 53 -> port 1053, but rather nat from LAN addr to a loopback addr.
|
|
||||||
# - this is complicated in that loopback is a different interface than eth0, so rewriting the destination address would cause the packets to just be dropped by the interface
|
|
||||||
protocol = [ "udp" "tcp" ];
|
|
||||||
visibleTo.lan = true;
|
|
||||||
description = "colin-redirected-dns-for-lan-namespace";
|
|
||||||
};
|
|
||||||
|
|
||||||
|
sane.services.dyn-dns.restartOnChange = [
|
||||||
|
"trust-dns-wan.service"
|
||||||
|
"trust-dns-lan.service"
|
||||||
|
"trust-dns-hn.service"
|
||||||
|
# "trust-dns-hn-resolver.service" # doesn't need restart because it doesn't know about WAN IP
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user