{ lib, config, pkgs, ... }: let cfg = config.networking.vpn-netns; netnsName = cfg.interfaceNamespace; vethOuterName = cfg.vethInterfaceName; vethEncapsulatedName = vethOuterName + "0"; outerIP = cfg.vethOuterIP + "/32"; encapsulatedIP = cfg.vethIP + "/32"; in { config = lib.mkIf (cfg.restrictedServices != [ ]) { systemd.services = builtins.listToAttrs ( builtins.map (name: { inherit name; value = { after = [ "wireguard.target" ]; # preStart = "sleep 3"; serviceConfig.NetworkNamespacePath = "/var/run/netns/${netnsName}"; }; }) cfg.restrictedServices ); networking = { wireguard.interfaces.${cfg.wireguardInterface} = let ip = "${pkgs.iproute2}/bin/ip"; in { preSetup = '' # clean interfaces ${ip} netns delete "${netnsName}" 2> /dev/null || true ${ip} link delete ${vethOuterName} 2> /dev/null || true rm -rf /etc/netns/${netnsName} # add a namespace-specific resolv.conf mkdir -p "/etc/netns/${netnsName}" sed '/nameserver /d' /etc/resolv.conf > "/etc/netns/${netnsName}/resolv.conf" echo "nameserver ${cfg.nameserver}" >> "/etc/netns/${netnsName}/resolv.conf" # create the network namespace ${ip} netns add "${netnsName}" ${ip} -n "${netnsName}" link set lo up # Add a custom link between netns ${ip} link add ${vethOuterName} type veth peer name ${vethEncapsulatedName} ${ip} link set ${vethEncapsulatedName} netns ${netnsName} ${ip} addr add ${outerIP} dev ${vethOuterName} ${ip} link set ${vethOuterName} up ${ip} route add ${encapsulatedIP} dev ${vethOuterName} ${ip} -n ${netnsName} addr add ${encapsulatedIP} dev ${vethEncapsulatedName} ${ip} -n ${netnsName} link set ${vethEncapsulatedName} up ${ip} -n ${netnsName} route add ${outerIP} dev ${vethEncapsulatedName} ''; postShutdown = '' ${ip} netns delete "${netnsName}" || true ${ip} link delete ${vethOuterName} || true rm -rf /etc/netns/${netnsName} ''; inherit (cfg) interfaceNamespace; } // cfg.wireguardOptions; firewall.trustedInterfaces = [ cfg.vethInterfaceName ]; }; }; }