From ec5e8a3269eddb2173103e677dd35fa6f6dacc2c Mon Sep 17 00:00:00 2001 From: Colin Date: Mon, 11 Nov 2024 11:02:42 +0000 Subject: [PATCH] netns: simplify the host -> netns response tunneling i don't actually need any route table that's higher priority than 'local' --- hosts/by-name/servo/services/hickory-dns.nix | 5 ++++ modules/netns.nix | 30 +++++++++----------- modules/vpn.nix | 2 ++ 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/hosts/by-name/servo/services/hickory-dns.nix b/hosts/by-name/servo/services/hickory-dns.nix index 22d50d978..d72954eb8 100644 --- a/hosts/by-name/servo/services/hickory-dns.nix +++ b/hosts/by-name/servo/services/hickory-dns.nix @@ -141,5 +141,10 @@ in # }; }; + systemd.services.hickory-dns-doof.after = [ + # service will fail to bind the veth, otherwise + "netns-doof-veth.service" + ]; + sane.services.dyn-dns.restartOnChange = lib.map (c: "${c.service}.service") (builtins.attrValues config.sane.services.hickory-dns.instances); } diff --git a/modules/netns.nix b/modules/netns.nix index 681ff5dd6..cd1e53649 100644 --- a/modules/netns.nix +++ b/modules/netns.nix @@ -61,8 +61,7 @@ let in { systemd.targets."netns-${name}" = { description = "create a network namespace which will selectively bridge traffic with the init namespace"; - wantedBy = [ "default.target" "network-pre.target" ]; - before = [ "network-pre.target" ]; #< TODO: this is probably not needed anymore + wantedBy = [ "default.target" ]; }; systemd.services."netns-${name}" = { description = "create an empty network namespace for ${name}"; @@ -101,26 +100,17 @@ let ${in-ns} ${ip} link set ${name}-veth-b up # make it so traffic originating from the host side of the veth - # is sent over the veth no matter its destination. + # is sent over the veth no matter its destination (well, unless it's to another interface that exists on the host). ${ip} rule add from ${veth.initns.ipv4} lookup ${name} pref 50 || echo "${name} already has ip rules (pref 50)" - - # for traffic originating at the host veth to the WAN, use the veth as our gateway - # not sure if the metric 1002 matters. - ${ip} route add default via ${veth.netns.ipv4} dev ${name}-veth-a proto kernel src ${veth.initns.ipv4} metric 1002 table ${name} || \ + ${ip} route add default via ${veth.netns.ipv4} dev ${name}-veth-a proto kernel src ${veth.initns.ipv4} table ${name} || \ echo "${name} already has default route" - # give the default route lower priority - ${ip} rule add from all lookup local pref 100 || echo "${name}: already has ip rules (pref 100)" - ${ip} rule del from all lookup local pref 0 || echo "${name}: already removed ip rule of default lookup (pref 0)" ''; serviceConfig.ExecStopPost = [ "-${in-ns} ${ip} link del ${name}-veth-b" "-${ip} link del ${name}-veth-a" # restore rules/routes "-${ip} rule del from ${veth.initns.ipv4} lookup ${name} pref 50" - "-${ip} route del default via ${veth.netns.ipv4} dev ${name}-veth-a proto kernel src ${veth.initns.ipv4} metric 1002 table ${name}" - # FIXME: if there are other net namespaces active, changing the prefs here may break those! - "-${ip} rule add from all lookup local pref 0" - "-${ip} rule del from all lookup local pref 100" + "-${ip} route del default via ${veth.netns.ipv4} dev ${name}-veth-a proto kernel src ${veth.initns.ipv4} table ${name}" ]; }; systemd.services."netns-${name}-forwards" = { @@ -221,9 +211,15 @@ let systemd.targets.network-pre.wantedBy = [ "network.target" ]; systemd.targets.network-pre.before = [ "network.target" ]; - # create a new routing table that we can use to proxy traffic out of the root namespace - # through the wireguard namespaces, and to the WAN via VPN. - # i think the numbers here aren't particularly important. + # i want IP routes such that any packets sent from the initns veth -- regardless of destination -- are tunneled through the VPN. + # that's source policy routing. normal `ip route` only allows routing based on the destination address. + # + # to achieve source policy routing: + # - create a new routing table. + # - `ip rule` which assigns every packet with matching source into that routing table. + # - within the routing table, use ordinary destination policy routing. + # + # each routing table has a numeric ID associated with it. i think the number doesn't impact anything, it just needs to be unique. networking.iproute2.rttablesExtraConfig = '' ${builtins.toString routeTable} ${name} ''; diff --git a/modules/vpn.nix b/modules/vpn.nix index 31a7c9547..007014671 100644 --- a/modules/vpn.nix +++ b/modules/vpn.nix @@ -190,6 +190,8 @@ let # XXX: all my wireguard DNS endpoints are static at the moment, so refresh logic isn't needed. # re-enable this should that ever change. + # N.B.: systemd will still bring up the device and even the peer if it fails to resolve the endpoint. + # but it seems that it'll try to re-resolve the endpoint again later (unclear how to configure this better). # systemd.services."${name}-refresh" = { # # periodically re-apply peers, to ensure DNS mappings stay fresh # # borrowed from