From 4dc5378b3e7d507aee1ce81dc9bc0104ad9bd562 Mon Sep 17 00:00:00 2001 From: Colin Date: Tue, 30 May 2023 12:00:30 +0000 Subject: [PATCH] dns: give different results based on which port the request arrives from WAN and VPN requests are served by local port 1053 and `wan.uninsane.org`. LAN requests are served by port 53 and `servo.lan.uninsane.org`. i'm not *super* fond of this. a recursive resolver of uninsane.org via the VPN will only ever get WAN addresses (broken). we may prefer to do IP-based responses, maybe via the same Linux firewall rules that forward from VPN namespace to root namespace --- hosts/by-name/servo/net.nix | 4 +- hosts/by-name/servo/services/ejabberd.nix | 10 ++-- hosts/by-name/servo/services/trust-dns.nix | 66 ++++++++++++++++------ modules/services/trust-dns.nix | 37 ++++++++++-- 4 files changed, 87 insertions(+), 30 deletions(-) diff --git a/hosts/by-name/servo/net.nix b/hosts/by-name/servo/net.nix index a034107b..9e9d433a 100644 --- a/hosts/by-name/servo/net.nix +++ b/hosts/by-name/servo/net.nix @@ -153,9 +153,9 @@ # we also bridge DNS traffic ${in-ns} ${iptables} -A PREROUTING -t nat -p udp --dport 53 -m iprange --dst-range ${vpn-ip} \ - -j DNAT --to-destination ${veth-host-ip}:53 + -j DNAT --to-destination ${veth-host-ip}:1053 ${in-ns} ${iptables} -A PREROUTING -t nat -p tcp --dport 53 -m iprange --dst-range ${vpn-ip} \ - -j DNAT --to-destination ${veth-host-ip}:53 + -j DNAT --to-destination ${veth-host-ip}:1053 # in order to access DNS in this netns, we need to route it to the VPN's nameservers # - alternatively, we could fix DNS servers like 1.1.1.1. diff --git a/hosts/by-name/servo/services/ejabberd.nix b/hosts/by-name/servo/services/ejabberd.nix index 57445bfa..effef734 100644 --- a/hosts/by-name/servo/services/ejabberd.nix +++ b/hosts/by-name/servo/services/ejabberd.nix @@ -78,7 +78,7 @@ sane.services.trust-dns.zones."uninsane.org".inet = { # XXX: SRV records have to point to something with a A/AAAA record; no CNAMEs - A."xmpp" = "%NATIVE%"; + A."xmpp" = "%ANATIVE%"; CNAME."muc.xmpp" = "xmpp"; CNAME."pubsub.xmpp" = "xmpp"; CNAME."upload.xmpp" = "xmpp"; @@ -235,7 +235,7 @@ use_turn: true turn_min_port: 49152 turn_max_port: 65535 - turn_ipv4_address: %NATIVE% + turn_ipv4_address: %ANATIVE% - # STUN+TURN UDP port: 3478 @@ -244,7 +244,7 @@ use_turn: true turn_min_port: 49152 turn_max_port: 65535 - turn_ipv4_address: %NATIVE% + turn_ipv4_address: %ANATIVE% - # STUN+TURN TLS over TCP port: 5349 @@ -255,7 +255,7 @@ use_turn: true turn_min_port: 49152 turn_max_port: 65535 - turn_ipv4_address: %NATIVE% + turn_ipv4_address: %ANATIVE% # TODO: enable mod_fail2ban # TODO(low): look into mod_http_fileserver for serving macros? @@ -388,7 +388,7 @@ # config is 444 (not 644), so we want to write out-of-place and then atomically move # TODO: factor this out into `sane-woop` helper? rm -f /var/lib/ejabberd/ejabberd.yaml.new - ${sed} "s/%NATIVE%/$ip/" ${config-in} > /var/lib/ejabberd/ejabberd.yaml.new + ${sed} "s/%ANATIVE%/$ip/" ${config-in} > /var/lib/ejabberd/ejabberd.yaml.new mv /var/lib/ejabberd/ejabberd.yaml{.new,} ''; diff --git a/hosts/by-name/servo/services/trust-dns.nix b/hosts/by-name/servo/services/trust-dns.nix index 8e61eaa8..d8592b14 100644 --- a/hosts/by-name/servo/services/trust-dns.nix +++ b/hosts/by-name/servo/services/trust-dns.nix @@ -30,17 +30,20 @@ 7d ; Expire 5m) ; Negative response TTL ''; - TXT."rev" = "2022122101"; + TXT."rev" = "2023052901"; + + CNAME."native" = "%CNAMENATIVE%"; + A."@" = "%ANATIVE%"; + A."wan" = "%AWAN%"; + A."servo.lan" = config.sane.hosts.by-name."servo".lan-ip; # XXX NS records must also not be CNAME # it's best that we keep this identical, or a superset of, what org. lists as our NS. # so, org. can specify ns2/ns3 as being to the VPN, with no mention of ns1. we provide ns1 here. - A."ns1" = "%NATIVE%"; + A."ns1" = "%ANATIVE%"; A."ns2" = "185.157.162.178"; A."ns3" = "185.157.162.178"; A."ovpns" = "185.157.162.178"; - A."native" = "%NATIVE%"; - A."@" = "%NATIVE%"; NS."@" = [ "ns1.uninsane.org." "ns2.uninsane.org." @@ -48,20 +51,49 @@ ]; }; - sane.services.trust-dns.zones."uninsane.org".file = - "/var/lib/trust-dns/uninsane.org.zone"; + sane.services.trust-dns.zones."uninsane.org".file = "uninsane.org.zone"; + sane.services.trust-dns.zonedir = null; - systemd.services.trust-dns.preStart = let - sed = "${pkgs.gnused}/bin/sed"; - zone-dir = "/var/lib/trust-dns"; - zone-out = "${zone-dir}/uninsane.org.zone"; - zone-template = pkgs.writeText "uninsane.org.zone.in" config.sane.services.trust-dns.generatedZones."uninsane.org"; - in '' - # make WAN records available to trust-dns - mkdir -p ${zone-dir} - ip=$(cat '${config.sane.services.dyn-dns.ipPath}') - ${sed} s/%NATIVE%/$ip/ ${zone-template} > ${zone-out} - ''; + sane.services.trust-dns.package = + let + sed = "${pkgs.gnused}/bin/sed"; + zone-dir = "/var/lib/trust-dns"; + zone-wan = "${zone-dir}/wan/uninsane.org.zone"; + zone-lan = "${zone-dir}/lan/uninsane.org.zone"; + zone-template = pkgs.writeText "uninsane.org.zone.in" config.sane.services.trust-dns.generatedZones."uninsane.org"; + in pkgs.writeShellScriptBin "named" '' + # compute wan/lan values + mkdir -p ${zone-dir}/{ovpn,wan,lan} + wan=$(cat '${config.sane.services.dyn-dns.ipPath}') + lan=${config.sane.hosts.by-name."servo".lan-ip} + + # create specializations that resolve native.uninsane.org to different CNAMEs + ${sed} s/%AWAN%/$wan/ ${zone-template} \ + | ${sed} s/%CNAMENATIVE%/wan/ \ + | ${sed} s/%ANATIVE%/$wan/ \ + > ${zone-wan} + ${sed} s/%AWAN%/$wan/ ${zone-template} \ + | ${sed} s/%CNAMENATIVE%/servo.lan/ \ + | ${sed} s/%ANATIVE%/$lan/ \ + > ${zone-lan} + + # launch the different interfaces, separately + ${pkgs.trust-dns}/bin/named --port 1053 --zonedir ${zone-dir}/wan/ $@ & + WANPID=$! + ${pkgs.trust-dns}/bin/named --zonedir ${zone-dir}/lan/ $@ & + LANPID=$! + + # wait until any of the processes exits, then kill them all and exit error + while kill -0 $WANPID $LANPID ; do + sleep 5 + done + kill $WANPID $LANPID + exit 1 + ''; sane.services.dyn-dns.restartOnChange = [ "trust-dns.service" ]; + + # for WAN visibility + networking.firewall.allowedUDPPorts = [ 1053 ]; + networking.firewall.allowedTCPPorts = [ 1053 ]; } diff --git a/modules/services/trust-dns.nix b/modules/services/trust-dns.nix index 531fc8f9..64b0a7d3 100644 --- a/modules/services/trust-dns.nix +++ b/modules/services/trust-dns.nix @@ -80,6 +80,14 @@ in default = false; type = types.bool; }; + package = mkOption { + type = types.package; + default = pkgs.trust-dns; + description = '' + trust-dns package to use. + should provide bin/named, which will be invoked with --config x and --zonedir d and maybe -q. + ''; + }; listenAddrsIPv4 = mkOption { type = types.listOf types.str; default = []; @@ -89,6 +97,13 @@ in type = types.bool; default = false; }; + zonedir = mkOption { + type = types.nullOr types.str; + default = "/"; + description = '' + where the `file` option in zones.* is relative to. + ''; + }; # reference zones = mkOption { type = types.attrsOf (types.submodule { @@ -154,7 +169,9 @@ in file = mkOption { type = types.nullOr types.str; default = null; - description = "instead of using the generated zone file, use the specified path"; + description = '' + instead of using the generated zone file, use the specified path (user should populate the file specified here). + ''; }; }; }); @@ -171,19 +188,27 @@ in config = mkIf cfg.enable { sane.services.trust-dns.generatedZones = mapAttrs (zone: zcfg: genZone zcfg) cfg.zones; - sane.services.wan-ports.tcp = [ 53 ]; - sane.services.wan-ports.udp = [ 53 ]; + + # TODO: we need the UPnP port to map WAN 53 -> LAN 1053 + # else we'll be giving LAN IPs to WAN requests. + # until then, manage forwards manually. + # sane.services.wan-ports.tcp = [ 53 ]; + # sane.services.wan-ports.udp = [ 53 ]; + networking.firewall.allowedUDPPorts = [ 53 ]; + networking.firewall.allowedTCPPorts = [ 53 ]; systemd.services.trust-dns = { description = "trust-dns DNS server"; serviceConfig = { ExecStart = let - flags = lib.optionalString cfg.quiet "-q"; + flags = lib.optional cfg.quiet "-q" ++ + lib.optionals (cfg.zonedir != null) [ "--zonedir" cfg.zonedir ]; + flagsStr = builtins.concatStringsSep " " flags; in '' - ${pkgs.trust-dns}/bin/named \ + ${cfg.package}/bin/named \ --config ${configFile} \ - --zonedir / ${flags} + ${flagsStr} ''; Type = "simple"; Restart = "on-failure";