This commit is contained in:
root 2026-03-16 12:19:11 -03:00
commit 73ff9ee8ee
No known key found for this signature in database
31 changed files with 4906 additions and 0 deletions

166
wireguard.nix Normal file
View file

@ -0,0 +1,166 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.services.wireguard-netns;
vpnOptions =
{ name, ... }:
{
options = {
name = mkOption {
type = types.str;
default = name;
description = "Name of the network namespace and WireGuard interface";
};
dns = mkOption {
type = types.str;
description = "Network DNS";
example = "1.1.1.1";
};
address = mkOption {
type = types.str;
description = "Address";
example = "10.2.0.1/32";
};
conf = mkOption {
type = types.str;
description = "Path to sops secret containing WireGuard configuration";
example = "wg0/conf";
};
};
};
in
{
options.services.wireguard-netns = {
enable = mkEnableOption "WireGuard network namespaces";
namespaces = mkOption {
type = types.attrsOf (types.submodule vpnOptions);
default = { };
description = "WireGuard VPN configurations in separate network namespaces";
example = literalExpression ''
{
wg0ns = {
dns = "10.2.0.1";
address = "10.2.0.2/32";
conf = "wg0/conf";
};
wg1ns = {
dns = "10.3.0.1";
address = "10.3.0.2/32";
conf = "wg1/conf";
};
}
'';
};
};
config = mkIf cfg.enable {
systemd.services = listToAttrs (
flatten (
imap1 (
index: elem:
let
name = elem.name;
vpnCfg = elem.value;
ns = "${name}ns";
nsIP = "10.200.${toString index}.2/24";
hostIP = "10.200.${toString index}.1/24";
vethHost = "veth-${name}";
vethNS = "veth-${name}-ns";
proxyIP = "10.200.${toString index}.2"; # IP without CIDR for binding
proxyPort = 1080;
in
[
{
name = "netns@${ns}";
value = {
description = "${ns} network namespace";
before = [ "network.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = pkgs.writers.writeBash "${ns}-up" ''
${pkgs.coreutils}/bin/mkdir -p /etc/netns/${ns}
echo "nameserver ${vpnCfg.dns}" > /etc/netns/${ns}/resolv.conf
${pkgs.iproute2}/bin/ip netns add ${ns}
${pkgs.iproute2}/bin/ip link add ${vethHost} type veth peer name ${vethNS}
${pkgs.iproute2}/bin/ip link set ${vethNS} netns ${ns}
${pkgs.iproute2}/bin/ip addr add ${hostIP} dev ${vethHost}
${pkgs.iproute2}/bin/ip link set ${vethHost} up
${pkgs.iproute2}/bin/ip -n ${ns} addr add ${nsIP} dev ${vethNS}
${pkgs.iproute2}/bin/ip -n ${ns} link set ${vethNS} up
'';
ExecStop = pkgs.writers.writeBash "${ns}-down" ''
${pkgs.iproute2}/bin/ip link del ${vethHost} || true
${pkgs.iproute2}/bin/ip netns del ${ns}
'';
};
};
}
{
name = name;
value = {
description = "${name} network interface";
bindsTo = [ "netns@${ns}.service" ];
requires = [ "network-online.target" ];
after = [ "netns@${ns}.service" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = pkgs.writers.writeBash "${name}-up" ''
${pkgs.iproute2}/bin/ip link add ${name} type wireguard
${pkgs.iproute2}/bin/ip link set ${name} netns ${ns}
${pkgs.iproute2}/bin/ip -n ${ns} address add ${vpnCfg.address} dev ${name}
${pkgs.iproute2}/bin/ip netns exec ${ns} \
${pkgs.wireguard-tools}/bin/wg setconf ${name} ${config.sops.secrets.${vpnCfg.conf}.path}
${pkgs.iproute2}/bin/ip -n ${ns} link set lo up
${pkgs.iproute2}/bin/ip -n ${ns} link set ${name} up
${pkgs.iproute2}/bin/ip -n ${ns} route add default dev ${name}
'';
ExecStop = pkgs.writers.writeBash "${name}-down" ''
${pkgs.iproute2}/bin/ip -n ${ns} route del default dev ${name} || true
${pkgs.iproute2}/bin/ip -n ${ns} link del ${name} || true
'';
};
};
}
{
name = "socks-${name}";
value = {
description = "SOCKS5 proxy for ${name} namespace";
after = [ "${name}.service" ];
requires = [ "${name}.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
Restart = "always";
RestartSec = "5s";
ExecStart = "${pkgs.iproute2}/bin/ip netns exec ${ns} ${pkgs.microsocks}/bin/microsocks -i ${proxyIP} -p ${toString proxyPort}";
};
};
}
]
) (lib.attrsToList cfg.namespaces)
)
);
};
}