networking/netns: clean up
This commit is contained in:
parent
b7566b7975
commit
85cd4e61e5
|
@ -1,473 +0,0 @@
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
mylib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib;
|
|
||||||
let
|
|
||||||
allNetns = config.networking.netns;
|
|
||||||
nonDefaultNetns = filterAttrs (_name: cfg: cfg.netns != "default") allNetns;
|
|
||||||
|
|
||||||
mkService =
|
|
||||||
cfg:
|
|
||||||
let
|
|
||||||
inherit (cfg)
|
|
||||||
netns
|
|
||||||
interface
|
|
||||||
address
|
|
||||||
;
|
|
||||||
enableIPv4Forwarding = if cfg.enableIPv4Forwarding then "1" else "0";
|
|
||||||
enableIPv6Forwarding = if cfg.enableIPv6Forwarding then "1" else "0";
|
|
||||||
in
|
|
||||||
{
|
|
||||||
path = with pkgs; [
|
|
||||||
coreutils
|
|
||||||
iproute2
|
|
||||||
procps
|
|
||||||
];
|
|
||||||
script = ''
|
|
||||||
ip netns add ${netns}
|
|
||||||
ip -n ${netns} link add ${interface} type dummy
|
|
||||||
ip -n ${netns} link set lo up
|
|
||||||
ip -n ${netns} link set ${interface} up
|
|
||||||
ip netns exec ${netns} sysctl -w net.ipv4.conf.default.forwarding=${enableIPv4Forwarding}
|
|
||||||
ip netns exec ${netns} sysctl -w net.ipv4.conf.all.forwarding=${enableIPv4Forwarding}
|
|
||||||
ip netns exec ${netns} sysctl -w net.ipv6.conf.default.forwarding=${enableIPv6Forwarding}
|
|
||||||
ip netns exec ${netns} sysctl -w net.ipv6.conf.all.forwarding=${enableIPv6Forwarding}
|
|
||||||
${concatMapStringsSep "\n" (addr: "ip -n ${netns} addr add ${addr} dev ${interface}") address}
|
|
||||||
'';
|
|
||||||
preStop = ''
|
|
||||||
ip netns del ${netns}
|
|
||||||
'';
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
};
|
|
||||||
after = [ "network.target" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
# https://flokli.de/posts/2022-11-18-nsncd
|
|
||||||
mkNscdService =
|
|
||||||
cfg:
|
|
||||||
let
|
|
||||||
inherit (cfg) netns netnsPath;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
serviceConfig = mylib.misc.serviceHardened // {
|
|
||||||
NetworkNamespacePath = netnsPath;
|
|
||||||
BindReadOnlyPaths = [
|
|
||||||
"/etc/netns/${netns}/resolv.conf:/etc/resolv.conf:norbind"
|
|
||||||
"/etc/netns/${netns}/nsswitch.conf:/etc/nsswitch.conf:norbind"
|
|
||||||
];
|
|
||||||
BindPaths = [ "/run/netns-${netns}/nscd:/run/nscd:norbind" ];
|
|
||||||
Type = "notify";
|
|
||||||
Restart = "always";
|
|
||||||
RestartSec = 5;
|
|
||||||
DynamicUser = true;
|
|
||||||
RuntimeDirectory = "netns-${netns}/nscd";
|
|
||||||
ExecStart = "${pkgs.nsncd}/bin/nsncd";
|
|
||||||
};
|
|
||||||
environment.LD_LIBRARY_PATH = config.system.nssModules.path;
|
|
||||||
after = [
|
|
||||||
"netns-${netns}.service"
|
|
||||||
"network.target"
|
|
||||||
];
|
|
||||||
partOf = [ "netns-${netns}.service" ];
|
|
||||||
wantedBy = [
|
|
||||||
"multi-user.target"
|
|
||||||
"netns-${netns}.service"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
mkAuxMntnsService =
|
|
||||||
cfg:
|
|
||||||
let
|
|
||||||
inherit (cfg)
|
|
||||||
netns
|
|
||||||
mntnsPath
|
|
||||||
;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
path = with pkgs; [
|
|
||||||
coreutils
|
|
||||||
util-linux
|
|
||||||
];
|
|
||||||
script = ''
|
|
||||||
touch ${mntnsPath} || echo "${mntnsPath} already exists"
|
|
||||||
unshare --mount=${mntnsPath} --propagation slave mount --bind --read-only /etc/netns/${netns}/resolv.conf /etc/resolv.conf
|
|
||||||
nsenter --mount=${mntnsPath} mount --bind --read-only /etc/netns/${netns}/nsswitch.conf /etc/nsswitch.conf
|
|
||||||
nsenter --mount=${mntnsPath} mount --bind --read-only /run/netns-${netns}/nscd /run/nscd
|
|
||||||
'';
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
};
|
|
||||||
after = [
|
|
||||||
"netns-${netns}.service"
|
|
||||||
"netns-${netns}-nscd.service"
|
|
||||||
"network.target"
|
|
||||||
];
|
|
||||||
partOf = [ "netns-${netns}.service" ];
|
|
||||||
wantedBy = [
|
|
||||||
"multi-user.target"
|
|
||||||
"netns-${netns}.service"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
mkPortForwardService =
|
|
||||||
cfg: fp:
|
|
||||||
let
|
|
||||||
inherit (fp) protocol source target;
|
|
||||||
sourceNetns = fp.netns;
|
|
||||||
sourceNetnsPath = config.networking.netns.${sourceNetns}.netnsPath;
|
|
||||||
targetNetns = cfg.netns;
|
|
||||||
targetNetnsConfig = cfg.serviceConfig;
|
|
||||||
serviceDeps = map (ns: "netns-${ns}.service") (
|
|
||||||
filter (ns: ns != "default") [
|
|
||||||
sourceNetns
|
|
||||||
targetNetns
|
|
||||||
]
|
|
||||||
);
|
|
||||||
in
|
|
||||||
{
|
|
||||||
serviceConfig =
|
|
||||||
mylib.misc.serviceHardened
|
|
||||||
// targetNetnsConfig
|
|
||||||
// {
|
|
||||||
Type = "simple";
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = 5;
|
|
||||||
DynamicUser = true;
|
|
||||||
ExecStart = "${pkgs.netns-proxy}/bin/netns-proxy ${sourceNetnsPath} ${source} -b ${target} -p ${protocol} -v";
|
|
||||||
ProtectProc = false;
|
|
||||||
RestrictNamespaces = "net";
|
|
||||||
AmbientCapabilities = [
|
|
||||||
"CAP_SYS_ADMIN"
|
|
||||||
"CAP_SYS_PTRACE"
|
|
||||||
];
|
|
||||||
CapabilityBoundingSet = [
|
|
||||||
"CAP_SYS_ADMIN"
|
|
||||||
"CAP_SYS_PTRACE"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
after = [
|
|
||||||
"network.target"
|
|
||||||
] ++ serviceDeps;
|
|
||||||
partOf = serviceDeps;
|
|
||||||
wantedBy = [
|
|
||||||
"multi-user.target"
|
|
||||||
] ++ serviceDeps;
|
|
||||||
};
|
|
||||||
|
|
||||||
mkExtraVethService =
|
|
||||||
cfg: ev:
|
|
||||||
let
|
|
||||||
inherit (ev)
|
|
||||||
sourceInterface
|
|
||||||
targetInterface
|
|
||||||
;
|
|
||||||
sourceNetns = cfg.netns;
|
|
||||||
sourceNetnsPath = cfg.netnsPath;
|
|
||||||
targetNetns = ev.netns;
|
|
||||||
targetNetnsPath = config.networking.netns.${targetNetns}.netnsPath;
|
|
||||||
serviceDeps = map (ns: "netns-${ns}.service") (
|
|
||||||
filter (ns: ns != "default") [
|
|
||||||
sourceNetns
|
|
||||||
targetNetns
|
|
||||||
]
|
|
||||||
);
|
|
||||||
mkSetup =
|
|
||||||
netns: _netnsPath: interface:
|
|
||||||
if netns == "default" then "ip link set ${interface} up" else "ip -n ${netns} link set ${interface} up";
|
|
||||||
mkDrop =
|
|
||||||
netns: _netnsPath: interface:
|
|
||||||
if netns == "default" then "ip link del ${interface}" else "ip -n ${netns} link del ${interface}";
|
|
||||||
in
|
|
||||||
{
|
|
||||||
path = with pkgs; [
|
|
||||||
coreutils
|
|
||||||
iproute2
|
|
||||||
procps
|
|
||||||
];
|
|
||||||
script = ''
|
|
||||||
ip link add ${sourceInterface} mtu 1400 address 02:00:00:00:00:01 netns ${sourceNetnsPath} type veth \
|
|
||||||
peer ${targetInterface} mtu 1400 address 02:00:00:00:00:00 netns ${targetNetnsPath}
|
|
||||||
${mkSetup sourceNetns sourceNetnsPath sourceInterface}
|
|
||||||
${mkSetup targetNetns targetNetnsPath targetInterface}
|
|
||||||
'';
|
|
||||||
preStop = ''
|
|
||||||
${mkDrop sourceNetns sourceNetnsPath sourceInterface}
|
|
||||||
'';
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
};
|
|
||||||
after = [
|
|
||||||
"network.target"
|
|
||||||
] ++ serviceDeps;
|
|
||||||
partOf = serviceDeps;
|
|
||||||
wantedBy = [
|
|
||||||
"multi-user.target"
|
|
||||||
] ++ serviceDeps;
|
|
||||||
};
|
|
||||||
|
|
||||||
defaultResolv = pkgs.writeText "netns-default-resolv-conf" ''
|
|
||||||
nameserver 2606:4700:4700::1111
|
|
||||||
nameserver 2001:4860:4860::8888
|
|
||||||
nameserver 1.1.1.1
|
|
||||||
nameserver 8.8.8.8
|
|
||||||
'';
|
|
||||||
|
|
||||||
defaultNsswitch = pkgs.writeText "netns-default-nsswitch-conf" ''
|
|
||||||
passwd: ${concatStringsSep " " config.system.nssDatabases.passwd}
|
|
||||||
group: ${concatStringsSep " " config.system.nssDatabases.group}
|
|
||||||
shadow: ${concatStringsSep " " config.system.nssDatabases.shadow}
|
|
||||||
sudoers: ${concatStringsSep " " config.system.nssDatabases.sudoers}
|
|
||||||
|
|
||||||
hosts: ${concatStringsSep " " (remove "resolve [!UNAVAIL=return]" config.system.nssDatabases.hosts)}
|
|
||||||
networks: files
|
|
||||||
|
|
||||||
ethers: files
|
|
||||||
services: ${concatStringsSep " " config.system.nssDatabases.services}
|
|
||||||
protocols: files
|
|
||||||
rpc: files
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.networking.netns = mkOption {
|
|
||||||
type = types.attrsOf (
|
|
||||||
types.submodule (
|
|
||||||
{ name, config, ... }:
|
|
||||||
let
|
|
||||||
netnsConfig = config;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
netns = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = name;
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Name of the network namespace.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
netnsPath = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = if name == "default" then "/proc/1/ns/net" else "/run/netns/${name}";
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Path to the network namespace.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
mntnsPath = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = if name == "default" then "/proc/1/ns/mnt" else "/run/netns-${name}/mntns";
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Path to the auxiliary mount namespace.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
serviceConfig = mkOption {
|
|
||||||
type = types.attrs;
|
|
||||||
default =
|
|
||||||
if config.netns == "default" then
|
|
||||||
{ }
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NetworkNamespacePath = config.netnsPath;
|
|
||||||
BindReadOnlyPaths = [
|
|
||||||
"/etc/netns/${config.netns}/resolv.conf:/etc/resolv.conf:norbind"
|
|
||||||
"/etc/netns/${config.netns}/nsswitch.conf:/etc/nsswitch.conf:norbind"
|
|
||||||
"/run/netns-${config.netns}/nscd:/run/nscd:norbind"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Systemd service configuration for entering the network namespace.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
interface = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = name;
|
|
||||||
description = ''
|
|
||||||
Name of the dummy interface to add the address.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
address = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [ ];
|
|
||||||
description = ''
|
|
||||||
Address to be added into the network namespace as source address.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
enableIPv4Forwarding = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
Whether to enable IPv4 packet forwarding in the network namespace.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
enableIPv6Forwarding = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
Whether to enable IPv6 packet forwarding in the network namespace.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
forwardPorts = mkOption {
|
|
||||||
type = types.listOf (
|
|
||||||
types.submodule {
|
|
||||||
options = {
|
|
||||||
protocol = mkOption {
|
|
||||||
type = types.enum [
|
|
||||||
"tcp"
|
|
||||||
"udp"
|
|
||||||
];
|
|
||||||
default = "tcp";
|
|
||||||
description = ''
|
|
||||||
The protocol specifier for port forwarding between network namespaces.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
netns = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "default";
|
|
||||||
description = ''
|
|
||||||
The network namespace to forward ports from.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
source = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
The source endpoint in the specified network namespace to forward.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
target = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
The target endpoint in the current network namespace to listen on.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
default = [ ];
|
|
||||||
description = ''
|
|
||||||
List of forwarded ports from another network namespace to this
|
|
||||||
network namespace.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
extraVeths = mkOption {
|
|
||||||
type = types.listOf (
|
|
||||||
types.submodule (
|
|
||||||
{ config, ... }:
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
netns = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "default";
|
|
||||||
description = ''
|
|
||||||
The network namespace to connect to.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
sourceInterface = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = if config.netns == "default" then "host" else config.netns;
|
|
||||||
description = ''
|
|
||||||
The interface name in current network namespace;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
targetInterface = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = if netnsConfig.netns == "default" then "host" else netnsConfig.netns;
|
|
||||||
description = ''
|
|
||||||
The interface name in the other network namespace;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
default = [ ];
|
|
||||||
description = ''
|
|
||||||
Extra veth-pairs to be created for enabling link-scope connectivity
|
|
||||||
between inter-network namespaces.
|
|
||||||
Note that a veth-pair only needs to be defined on one end.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
description = ''
|
|
||||||
Network namespace configuration.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
networking.netns.default = { };
|
|
||||||
|
|
||||||
systemd.services = listToAttrs (
|
|
||||||
mapAttrsToList (_name: cfg: nameValuePair "netns-${cfg.netns}" (mkService cfg)) nonDefaultNetns
|
|
||||||
++ mapAttrsToList (
|
|
||||||
_name: cfg: nameValuePair "netns-${cfg.netns}-nscd" (mkNscdService cfg)
|
|
||||||
) nonDefaultNetns
|
|
||||||
++ mapAttrsToList (
|
|
||||||
_name: cfg: nameValuePair "netns-${cfg.netns}-mntns" (mkAuxMntnsService cfg)
|
|
||||||
) nonDefaultNetns
|
|
||||||
++ flatten (
|
|
||||||
mapAttrsToList (
|
|
||||||
_name: cfg:
|
|
||||||
(imap (
|
|
||||||
index: fp:
|
|
||||||
nameValuePair "netns-${cfg.netns}-port-forward-${toString index}-${fp.netns}-${fp.protocol}" (
|
|
||||||
mkPortForwardService cfg fp
|
|
||||||
)
|
|
||||||
) cfg.forwardPorts)
|
|
||||||
) allNetns
|
|
||||||
)
|
|
||||||
++ flatten (
|
|
||||||
mapAttrsToList (
|
|
||||||
_name: cfg:
|
|
||||||
(imap (
|
|
||||||
index: ev:
|
|
||||||
nameValuePair "netns-${cfg.netns}-extra-veth-${toString index}-${ev.netns}" (
|
|
||||||
mkExtraVethService cfg ev
|
|
||||||
)
|
|
||||||
) cfg.extraVeths)
|
|
||||||
) allNetns
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
environment.etc = listToAttrs (
|
|
||||||
mapAttrsToList (
|
|
||||||
_name: cfg:
|
|
||||||
nameValuePair "netns/${cfg.netns}/resolv.conf" {
|
|
||||||
source = mkDefault defaultResolv;
|
|
||||||
}
|
|
||||||
) nonDefaultNetns
|
|
||||||
++ mapAttrsToList (
|
|
||||||
_name: cfg:
|
|
||||||
nameValuePair "netns/${cfg.netns}/nsswitch.conf" {
|
|
||||||
source = mkDefault defaultNsswitch;
|
|
||||||
}
|
|
||||||
) nonDefaultNetns
|
|
||||||
);
|
|
||||||
|
|
||||||
environment.systemPackages = mapAttrsToList (
|
|
||||||
name: cfg:
|
|
||||||
let
|
|
||||||
inherit (cfg) netns netnsPath mntnsPath;
|
|
||||||
in
|
|
||||||
pkgs.writeShellApplication {
|
|
||||||
name = "netns-run-${netns}";
|
|
||||||
runtimeInputs = with pkgs; [ util-linux ];
|
|
||||||
text = ''
|
|
||||||
pkexec nsenter -t $$ -e --mount=${mntnsPath} --net=${netnsPath} -S "$(id -u)" -G "$(id -g)" --wdns="$PWD" "$@"
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
) allNetns;
|
|
||||||
};
|
|
||||||
}
|
|
187
nixos/modules/networking/netns/common.nix
Normal file
187
nixos/modules/networking/netns/common.nix
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
allNetns = config.networking.netns;
|
||||||
|
nonDefaultNetns = filterAttrs (name: _cfg: name != "default") allNetns;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.networking.netns = mkOption {
|
||||||
|
type = types.attrsOf (
|
||||||
|
types.submodule (
|
||||||
|
{ name, config, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
netnsPath = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = if name == "default" then "/proc/1/ns/net" else "/run/netns/${name}";
|
||||||
|
readOnly = true;
|
||||||
|
description = ''
|
||||||
|
Path to the network namespace.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
mntnsPath = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = if name == "default" then "/proc/1/ns/mnt" else "/run/netns-${name}/mntns/${name}";
|
||||||
|
readOnly = true;
|
||||||
|
description = ''
|
||||||
|
Path to the auxiliary mount namespace.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
interface = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = name;
|
||||||
|
description = ''
|
||||||
|
Name of the dummy interface to add the address.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
address = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
Address to be added into the network namespace as source address.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
enableIPv4Forwarding = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Whether to enable IPv4 packet forwarding in the network namespace.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
enableIPv6Forwarding = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Whether to enable IPv6 packet forwarding in the network namespace.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
serviceConfig = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
default =
|
||||||
|
if name == "default" then
|
||||||
|
{ }
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NetworkNamespacePath = config.netnsPath;
|
||||||
|
BindReadOnlyPaths = optionals config.enableDNSIsolation [
|
||||||
|
"/etc/netns/${name}/resolv.conf:/etc/resolv.conf:norbind"
|
||||||
|
"/etc/netns/${name}/nsswitch.conf:/etc/nsswitch.conf:norbind"
|
||||||
|
"/run/netns-${name}/nscd:/run/nscd:norbind"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
readOnly = true;
|
||||||
|
description = ''
|
||||||
|
Systemd service configuration for entering the network namespace.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
description = ''
|
||||||
|
Network namespace configuration.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
networking.netns.default = { };
|
||||||
|
|
||||||
|
systemd.services = listToAttrs (
|
||||||
|
mapAttrsToList (
|
||||||
|
name: cfg:
|
||||||
|
let
|
||||||
|
inherit (cfg) interface address;
|
||||||
|
enableIPv4Forwarding = if cfg.enableIPv4Forwarding then "1" else "0";
|
||||||
|
enableIPv6Forwarding = if cfg.enableIPv6Forwarding then "1" else "0";
|
||||||
|
in
|
||||||
|
nameValuePair "netns-${name}" {
|
||||||
|
path = with pkgs; [
|
||||||
|
coreutils
|
||||||
|
iproute2
|
||||||
|
procps
|
||||||
|
];
|
||||||
|
script = ''
|
||||||
|
ip netns add ${name}
|
||||||
|
ip -n ${name} link add ${interface} type dummy
|
||||||
|
ip -n ${name} link set lo up
|
||||||
|
ip -n ${name} link set ${interface} up
|
||||||
|
ip netns exec ${name} sysctl -w net.ipv4.conf.default.forwarding=${enableIPv4Forwarding}
|
||||||
|
ip netns exec ${name} sysctl -w net.ipv4.conf.all.forwarding=${enableIPv4Forwarding}
|
||||||
|
ip netns exec ${name} sysctl -w net.ipv6.conf.default.forwarding=${enableIPv6Forwarding}
|
||||||
|
ip netns exec ${name} sysctl -w net.ipv6.conf.all.forwarding=${enableIPv6Forwarding}
|
||||||
|
${concatMapStringsSep "\n" (addr: "ip -n ${name} addr add ${addr} dev ${interface}") address}
|
||||||
|
'';
|
||||||
|
preStop = ''
|
||||||
|
ip netns del ${name}
|
||||||
|
'';
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
}
|
||||||
|
) nonDefaultNetns
|
||||||
|
++ mapAttrsToList (
|
||||||
|
name: cfg:
|
||||||
|
let
|
||||||
|
inherit (cfg) mntnsPath enableDNSIsolation;
|
||||||
|
in
|
||||||
|
nameValuePair "netns-${name}-mntns" {
|
||||||
|
path = with pkgs; [
|
||||||
|
coreutils
|
||||||
|
util-linux
|
||||||
|
];
|
||||||
|
script = ''
|
||||||
|
touch ${mntnsPath} || echo "${mntnsPath} already exists"
|
||||||
|
unshare --mount=${mntnsPath} --propagation slave true
|
||||||
|
${optionalString enableDNSIsolation ''
|
||||||
|
nsenter --mount=${mntnsPath} mount --bind --read-only /etc/netns/${name}/resolv.conf /etc/resolv.conf
|
||||||
|
nsenter --mount=${mntnsPath} mount --bind --read-only /etc/netns/${name}/nsswitch.conf /etc/nsswitch.conf
|
||||||
|
nsenter --mount=${mntnsPath} mount --bind --read-only /run/netns-${name}/nscd /run/nscd
|
||||||
|
''}
|
||||||
|
'';
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
RuntimeDirectory = "netns-${name}/mntns";
|
||||||
|
};
|
||||||
|
after =
|
||||||
|
[
|
||||||
|
"netns-${name}.service"
|
||||||
|
"network.target"
|
||||||
|
]
|
||||||
|
++ optionals enableDNSIsolation [
|
||||||
|
"netns-${name}-nscd.service"
|
||||||
|
];
|
||||||
|
partOf = [ "netns-${name}.service" ];
|
||||||
|
wantedBy = [
|
||||||
|
"multi-user.target"
|
||||||
|
"netns-${name}.service"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
) nonDefaultNetns
|
||||||
|
);
|
||||||
|
|
||||||
|
environment.systemPackages = mkIf (nonDefaultNetns != { }) (
|
||||||
|
mapAttrsToList (
|
||||||
|
name: cfg:
|
||||||
|
let
|
||||||
|
inherit (cfg) netnsPath mntnsPath;
|
||||||
|
in
|
||||||
|
pkgs.writeShellApplication {
|
||||||
|
name = "netns-run-${name}";
|
||||||
|
runtimeInputs = with pkgs; [ util-linux ];
|
||||||
|
text = ''
|
||||||
|
pkexec nsenter -t $$ -e --mount=${mntnsPath} --net=${netnsPath} -S "$(id -u)" -G "$(id -g)" --wdns="$PWD" "$@"
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
) allNetns
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
127
nixos/modules/networking/netns/extra-veth.nix
Normal file
127
nixos/modules/networking/netns/extra-veth.nix
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
allNetns = config.networking.netns;
|
||||||
|
allExtraVeths = flatten (mapAttrsToList (_name: cfg: cfg.extraVeths) allNetns);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.networking.netns = mkOption {
|
||||||
|
type = types.attrsOf (
|
||||||
|
types.submodule (
|
||||||
|
{ name, ... }:
|
||||||
|
{
|
||||||
|
options.extraVeths = mkOption {
|
||||||
|
type = types.listOf (
|
||||||
|
types.submodule (
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
sourceNetns = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = name;
|
||||||
|
readOnly = true;
|
||||||
|
description = ''
|
||||||
|
The current network namespace.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
targetNetns = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
The network namespace to connect to.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
sourceInterface = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = if config.targetNetns == "default" then "host" else config.targetNetns;
|
||||||
|
description = ''
|
||||||
|
The interface name in the current network namespace;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
targetInterface = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = if config.sourceNetns == "default" then "host" else config.sourceNetns;
|
||||||
|
description = ''
|
||||||
|
The interface name in the other network namespace;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
Extra veth-pairs to be created for enabling link-scope connectivity
|
||||||
|
between inter-network namespaces.
|
||||||
|
Note that a veth-pair only needs to be defined on one end.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
systemd.services = listToAttrs (
|
||||||
|
map (
|
||||||
|
ev:
|
||||||
|
let
|
||||||
|
inherit (ev)
|
||||||
|
sourceNetns
|
||||||
|
targetNetns
|
||||||
|
sourceInterface
|
||||||
|
targetInterface
|
||||||
|
;
|
||||||
|
sourceNetnsPath = config.networking.netns.${sourceNetns}.netnsPath;
|
||||||
|
targetNetnsPath = config.networking.netns.${targetNetns}.netnsPath;
|
||||||
|
serviceDeps = map (ns: "netns-${ns}.service") (
|
||||||
|
filter (ns: ns != "default") [
|
||||||
|
sourceNetns
|
||||||
|
targetNetns
|
||||||
|
]
|
||||||
|
);
|
||||||
|
mkSetup =
|
||||||
|
netns: _netnsPath: interface:
|
||||||
|
if netns == "default" then
|
||||||
|
"ip link set ${interface} up"
|
||||||
|
else
|
||||||
|
"ip -n ${netns} link set ${interface} up";
|
||||||
|
mkDrop =
|
||||||
|
netns: _netnsPath: interface:
|
||||||
|
if netns == "default" then "ip link del ${interface}" else "ip -n ${netns} link del ${interface}";
|
||||||
|
in
|
||||||
|
nameValuePair "netns-extra-veth-1-${sourceNetns}-${targetNetns}" {
|
||||||
|
path = with pkgs; [
|
||||||
|
coreutils
|
||||||
|
iproute2
|
||||||
|
procps
|
||||||
|
];
|
||||||
|
script = ''
|
||||||
|
ip link add ${sourceInterface} mtu 1400 address 02:00:00:00:00:01 netns ${sourceNetnsPath} type veth \
|
||||||
|
peer ${targetInterface} mtu 1400 address 02:00:00:00:00:00 netns ${targetNetnsPath}
|
||||||
|
${mkSetup sourceNetns sourceNetnsPath sourceInterface}
|
||||||
|
${mkSetup targetNetns targetNetnsPath targetInterface}
|
||||||
|
'';
|
||||||
|
preStop = ''
|
||||||
|
${mkDrop sourceNetns sourceNetnsPath sourceInterface}
|
||||||
|
'';
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
after = [
|
||||||
|
"network.target"
|
||||||
|
] ++ serviceDeps;
|
||||||
|
partOf = serviceDeps;
|
||||||
|
wantedBy = [
|
||||||
|
"multi-user.target"
|
||||||
|
] ++ serviceDeps;
|
||||||
|
}
|
||||||
|
) allExtraVeths
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
115
nixos/modules/networking/netns/nscd.nix
Normal file
115
nixos/modules/networking/netns/nscd.nix
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
mylib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
allNetns = config.networking.netns;
|
||||||
|
dnsIsolatedNetns = filterAttrs (name: cfg: name != "default" && cfg.enableDNSIsolation) allNetns;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.networking.netns = mkOption {
|
||||||
|
type = types.attrsOf (
|
||||||
|
types.submodule (
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
options.enableDNSIsolation = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Whether to enable DNS isolation between network namespaces. When disabled,
|
||||||
|
DNS requests in this namespace may be exposed to other namespaces.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
# https://flokli.de/posts/2022-11-18-nsncd
|
||||||
|
systemd.services = mapAttrs' (
|
||||||
|
name: cfg:
|
||||||
|
let
|
||||||
|
inherit (cfg) netnsPath;
|
||||||
|
in
|
||||||
|
nameValuePair "netns-${name}-nscd" {
|
||||||
|
serviceConfig = mylib.misc.serviceHardened // {
|
||||||
|
NetworkNamespacePath = netnsPath;
|
||||||
|
BindReadOnlyPaths = [
|
||||||
|
"/etc/netns/${name}/resolv.conf:/etc/resolv.conf:norbind"
|
||||||
|
"/etc/netns/${name}/nsswitch.conf:/etc/nsswitch.conf:norbind"
|
||||||
|
];
|
||||||
|
BindPaths = [ "/run/netns-${name}/nscd:/run/nscd:norbind" ];
|
||||||
|
Type = "notify";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 5;
|
||||||
|
User = "${name}-nscd";
|
||||||
|
RuntimeDirectory = "netns-${name}/nscd";
|
||||||
|
RuntimeDirectoryPreserve = true;
|
||||||
|
ExecStart = "${pkgs.nsncd}/bin/nsncd";
|
||||||
|
};
|
||||||
|
environment.LD_LIBRARY_PATH = config.system.nssModules.path;
|
||||||
|
after = [
|
||||||
|
"netns-${name}.service"
|
||||||
|
"network.target"
|
||||||
|
];
|
||||||
|
partOf = [ "netns-${name}.service" ];
|
||||||
|
wantedBy = [
|
||||||
|
"multi-user.target"
|
||||||
|
"netns-${name}.service"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
) dnsIsolatedNetns;
|
||||||
|
|
||||||
|
users.users = mapAttrs' (
|
||||||
|
name: _cfg:
|
||||||
|
nameValuePair "${name}-nscd" {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "${name}-nscd";
|
||||||
|
}
|
||||||
|
) dnsIsolatedNetns;
|
||||||
|
|
||||||
|
users.groups = mapAttrs' (name: _cfg: nameValuePair "${name}-nscd" { }) dnsIsolatedNetns;
|
||||||
|
|
||||||
|
environment.etc = listToAttrs (
|
||||||
|
mapAttrsToList (
|
||||||
|
name: _cfg:
|
||||||
|
nameValuePair "netns/${name}/resolv.conf" {
|
||||||
|
source = mkDefault (
|
||||||
|
pkgs.writeText "netns-default-resolv-conf" ''
|
||||||
|
nameserver 2606:4700:4700::1111
|
||||||
|
nameserver 2001:4860:4860::8888
|
||||||
|
nameserver 1.1.1.1
|
||||||
|
nameserver 8.8.8.8
|
||||||
|
''
|
||||||
|
);
|
||||||
|
}
|
||||||
|
) dnsIsolatedNetns
|
||||||
|
++ mapAttrsToList (
|
||||||
|
name: _cfg:
|
||||||
|
nameValuePair "netns/${name}/nsswitch.conf" {
|
||||||
|
source = mkDefault (
|
||||||
|
pkgs.writeText "netns-default-nsswitch-conf" ''
|
||||||
|
passwd: ${concatStringsSep " " config.system.nssDatabases.passwd}
|
||||||
|
group: ${concatStringsSep " " config.system.nssDatabases.group}
|
||||||
|
shadow: ${concatStringsSep " " config.system.nssDatabases.shadow}
|
||||||
|
sudoers: ${concatStringsSep " " config.system.nssDatabases.sudoers}
|
||||||
|
|
||||||
|
hosts: ${concatStringsSep " " (remove "resolve [!UNAVAIL=return]" config.system.nssDatabases.hosts)}
|
||||||
|
networks: files
|
||||||
|
|
||||||
|
ethers: files
|
||||||
|
services: ${concatStringsSep " " config.system.nssDatabases.services}
|
||||||
|
protocols: files
|
||||||
|
rpc: files
|
||||||
|
''
|
||||||
|
);
|
||||||
|
}
|
||||||
|
) dnsIsolatedNetns
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
122
nixos/modules/networking/netns/port-forward.nix
Normal file
122
nixos/modules/networking/netns/port-forward.nix
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
mylib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
allNetns = config.networking.netns;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.networking.netns = mkOption {
|
||||||
|
type = types.attrsOf (
|
||||||
|
types.submodule (
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
options.forwardPorts = mkOption {
|
||||||
|
type = types.listOf (
|
||||||
|
types.submodule {
|
||||||
|
options = {
|
||||||
|
protocol = mkOption {
|
||||||
|
type = types.enum [
|
||||||
|
"tcp"
|
||||||
|
"udp"
|
||||||
|
];
|
||||||
|
default = "tcp";
|
||||||
|
description = ''
|
||||||
|
The protocol specifier for port forwarding between network namespaces.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
netns = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "default";
|
||||||
|
description = ''
|
||||||
|
The network namespace to forward ports from.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
source = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
The source endpoint in the specified network namespace to forward.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
target = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
The target endpoint in the current network namespace to listen on.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
default = [ ];
|
||||||
|
description = ''
|
||||||
|
List of forwarded ports from another network namespace to this
|
||||||
|
network namespace.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
systemd.services = listToAttrs (
|
||||||
|
flatten (
|
||||||
|
mapAttrsToList (
|
||||||
|
name: cfg:
|
||||||
|
(imap (
|
||||||
|
index: fp:
|
||||||
|
let
|
||||||
|
inherit (fp)
|
||||||
|
protocol
|
||||||
|
source
|
||||||
|
target
|
||||||
|
netns
|
||||||
|
;
|
||||||
|
netnsPath = config.networking.netns.${netns}.netnsPath;
|
||||||
|
serviceDeps = map (ns: "netns-${ns}.service") (
|
||||||
|
filter (ns: ns != "default") [
|
||||||
|
name
|
||||||
|
netns
|
||||||
|
]
|
||||||
|
);
|
||||||
|
in
|
||||||
|
nameValuePair "netns-${name}-port-forward-${toString index}" {
|
||||||
|
serviceConfig =
|
||||||
|
mylib.misc.serviceHardened
|
||||||
|
// cfg.serviceConfig
|
||||||
|
// {
|
||||||
|
Type = "simple";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 5;
|
||||||
|
DynamicUser = true;
|
||||||
|
User = "${name}-port-forward-${toString index}";
|
||||||
|
ExecStart = "${pkgs.netns-proxy}/bin/netns-proxy ${netnsPath} ${source} -b ${target} -p ${protocol} -v";
|
||||||
|
ProtectProc = false;
|
||||||
|
RestrictNamespaces = "net";
|
||||||
|
AmbientCapabilities = [
|
||||||
|
"CAP_SYS_ADMIN"
|
||||||
|
"CAP_SYS_PTRACE"
|
||||||
|
];
|
||||||
|
CapabilityBoundingSet = [
|
||||||
|
"CAP_SYS_ADMIN"
|
||||||
|
"CAP_SYS_PTRACE"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
after = [
|
||||||
|
"network.target"
|
||||||
|
] ++ serviceDeps;
|
||||||
|
partOf = serviceDeps;
|
||||||
|
wantedBy = [
|
||||||
|
"multi-user.target"
|
||||||
|
] ++ serviceDeps;
|
||||||
|
}
|
||||||
|
) cfg.forwardPorts)
|
||||||
|
) allNetns
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
|
@ -8,13 +8,17 @@ in
|
||||||
options.networking.ports = mkOption {
|
options.networking.ports = mkOption {
|
||||||
type = with types; attrsOf port;
|
type = with types; attrsOf port;
|
||||||
default = {
|
default = {
|
||||||
|
# standard ports
|
||||||
http = 80;
|
http = 80;
|
||||||
https = 443;
|
https = 443;
|
||||||
|
socks = 1080;
|
||||||
ssh = 2222;
|
ssh = 2222;
|
||||||
|
|
||||||
# enthalpy
|
# local ports
|
||||||
|
enthalpy-gost = 3000;
|
||||||
|
|
||||||
|
# public ports
|
||||||
enthalpy-ipsec = 13000;
|
enthalpy-ipsec = 13000;
|
||||||
enthalpy-gost = 1080;
|
|
||||||
};
|
};
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
description = ''
|
description = ''
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
|
mylib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
with lib;
|
with lib;
|
||||||
|
@ -15,7 +16,7 @@ in
|
||||||
enable = mkEnableOption "bird for site-scope connectivity";
|
enable = mkEnableOption "bird for site-scope connectivity";
|
||||||
socket = mkOption {
|
socket = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "/run/enthalpy/bird2/bird.ctl";
|
default = "/run/netns-${cfg.netns}/bird/bird.ctl";
|
||||||
description = ''
|
description = ''
|
||||||
Path to the bird control socket.
|
Path to the bird control socket.
|
||||||
'';
|
'';
|
||||||
|
@ -42,50 +43,54 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf (cfg.enable && cfg.bird.enable) {
|
config = mkIf (cfg.enable && cfg.bird.enable) {
|
||||||
environment.etc."enthalpy/bird2.conf".source = pkgs.writeTextFile {
|
environment.etc."netns/${cfg.netns}/bird.conf".source = pkgs.writeTextFile {
|
||||||
name = "bird2";
|
name = "bird";
|
||||||
text = cfg.bird.config;
|
text = cfg.bird.config;
|
||||||
checkPhase = optionalString cfg.bird.checkConfig ''
|
checkPhase = optionalString cfg.bird.checkConfig ''
|
||||||
ln -s $out bird2.conf
|
ln -s $out bird.conf
|
||||||
${pkgs.buildPackages.bird}/bin/bird -d -p -c bird2.conf
|
${pkgs.buildPackages.bird}/bin/bird -d -p -c bird.conf
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.enthalpy-bird2 = {
|
systemd.services.enthalpy-bird = {
|
||||||
serviceConfig = {
|
serviceConfig =
|
||||||
Type = "forking";
|
mylib.misc.serviceHardened
|
||||||
Restart = "on-failure";
|
// config.networking.netns.${cfg.netns}.serviceConfig
|
||||||
RestartSec = 5;
|
// {
|
||||||
DynamicUser = true;
|
Type = "forking";
|
||||||
RuntimeDirectory = "enthalpy/bird2";
|
Restart = "on-failure";
|
||||||
ExecStart = "${pkgs.bird}/bin/bird -s ${cfg.bird.socket} -c /etc/enthalpy/bird2.conf";
|
RestartSec = 5;
|
||||||
ExecReload = "${pkgs.bird}/bin/birdc -s ${cfg.bird.socket} configure";
|
DynamicUser = true;
|
||||||
ExecStop = "${pkgs.bird}/bin/birdc -s ${cfg.bird.socket} down";
|
RuntimeDirectory = "netns-${cfg.netns}/bird";
|
||||||
CapabilityBoundingSet = [
|
ExecStart = "${pkgs.bird}/bin/bird -s ${cfg.bird.socket} -c /etc/netns/${cfg.netns}/bird.conf";
|
||||||
"CAP_NET_ADMIN"
|
ExecReload = "${pkgs.bird}/bin/birdc -s ${cfg.bird.socket} configure";
|
||||||
"CAP_NET_BIND_SERVICE"
|
ExecStop = "${pkgs.bird}/bin/birdc -s ${cfg.bird.socket} down";
|
||||||
"CAP_NET_RAW"
|
CapabilityBoundingSet = [
|
||||||
];
|
"CAP_NET_ADMIN"
|
||||||
AmbientCapabilities = [
|
"CAP_NET_BIND_SERVICE"
|
||||||
"CAP_NET_ADMIN"
|
"CAP_NET_RAW"
|
||||||
"CAP_NET_BIND_SERVICE"
|
];
|
||||||
"CAP_NET_RAW"
|
AmbientCapabilities = [
|
||||||
];
|
"CAP_NET_ADMIN"
|
||||||
ProtectSystem = "full";
|
"CAP_NET_BIND_SERVICE"
|
||||||
ProtectHome = "yes";
|
"CAP_NET_RAW"
|
||||||
ProtectKernelTunables = true;
|
];
|
||||||
ProtectControlGroups = true;
|
RestrictAddressFamilies = [
|
||||||
PrivateTmp = true;
|
"AF_UNIX"
|
||||||
PrivateDevices = true;
|
"AF_INET"
|
||||||
SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
|
"AF_INET6"
|
||||||
MemoryDenyWriteExecute = "yes";
|
"AF_NETLINK"
|
||||||
};
|
];
|
||||||
wantedBy = [ "multi-user.target" ];
|
};
|
||||||
reloadTriggers = [ config.environment.etc."enthalpy/bird2.conf".source ];
|
after = [ "netns-${cfg.netns}.service" ];
|
||||||
|
partOf = [ "netns-${cfg.netns}.service" ];
|
||||||
|
wantedBy = [
|
||||||
|
"multi-user.target"
|
||||||
|
"netns-${cfg.netns}.service"
|
||||||
|
];
|
||||||
|
reloadTriggers = [ config.environment.etc."netns/${cfg.netns}/bird.conf".source ];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.enthalpy.services.enthalpy-bird2 = { };
|
|
||||||
|
|
||||||
services.enthalpy.bird.config = mkBefore ''
|
services.enthalpy.bird.config = mkBefore ''
|
||||||
router id ${toString cfg.bird.routerId};
|
router id ${toString cfg.bird.routerId};
|
||||||
ipv6 sadr table sadr6;
|
ipv6 sadr table sadr6;
|
||||||
|
|
|
@ -11,6 +11,7 @@ with lib;
|
||||||
let
|
let
|
||||||
inherit (mylib.network) cidr;
|
inherit (mylib.network) cidr;
|
||||||
cfg = config.services.enthalpy;
|
cfg = config.services.enthalpy;
|
||||||
|
interface = config.networking.netns.${cfg.netns}.interface;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.enthalpy.clat = {
|
options.services.enthalpy.clat = {
|
||||||
|
@ -38,7 +39,7 @@ in
|
||||||
];
|
];
|
||||||
preStart = ''
|
preStart = ''
|
||||||
ip -6 route replace 64:ff9b::/96 from ${cfg.clat.address} encap seg6 mode encap \
|
ip -6 route replace 64:ff9b::/96 from ${cfg.clat.address} encap seg6 mode encap \
|
||||||
segs ${concatStringsSep "," cfg.clat.segment} dev enthalpy mtu 1280
|
segs ${concatStringsSep "," cfg.clat.segment} dev ${interface} mtu 1280
|
||||||
'';
|
'';
|
||||||
script = ''
|
script = ''
|
||||||
exec tayga --config ${pkgs.writeText "tayga.conf" ''
|
exec tayga --config ${pkgs.writeText "tayga.conf" ''
|
||||||
|
@ -56,28 +57,32 @@ in
|
||||||
'';
|
'';
|
||||||
preStop = ''
|
preStop = ''
|
||||||
ip -6 route del 64:ff9b::/96 from ${cfg.clat.address} encap seg6 mode encap \
|
ip -6 route del 64:ff9b::/96 from ${cfg.clat.address} encap seg6 mode encap \
|
||||||
segs ${concatStringsSep "," cfg.clat.segment} dev enthalpy mtu 1280
|
segs ${concatStringsSep "," cfg.clat.segment} dev ${interface} mtu 1280
|
||||||
'';
|
'';
|
||||||
serviceConfig = {
|
serviceConfig =
|
||||||
Type = "forking";
|
mylib.misc.serviceHardened
|
||||||
Restart = "on-failure";
|
// config.networking.netns.${cfg.netns}.serviceConfig
|
||||||
RestartSec = 5;
|
// {
|
||||||
DynamicUser = true;
|
Type = "forking";
|
||||||
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
|
Restart = "on-failure";
|
||||||
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
|
RestartSec = 5;
|
||||||
ProtectSystem = "full";
|
DynamicUser = true;
|
||||||
ProtectHome = "yes";
|
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
|
||||||
ProtectKernelTunables = true;
|
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
|
||||||
ProtectControlGroups = true;
|
RestrictAddressFamilies = [
|
||||||
PrivateTmp = true;
|
"AF_UNIX"
|
||||||
SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
|
"AF_INET"
|
||||||
MemoryDenyWriteExecute = "yes";
|
"AF_INET6"
|
||||||
};
|
"AF_NETLINK"
|
||||||
wants = [ "network.target" ];
|
];
|
||||||
after = [ "network.target" ];
|
PrivateDevices = false;
|
||||||
wantedBy = [ "multi-user.target" ];
|
};
|
||||||
|
after = [ "netns-${cfg.netns}.service" ];
|
||||||
|
partOf = [ "netns-${cfg.netns}.service" ];
|
||||||
|
wantedBy = [
|
||||||
|
"multi-user.target"
|
||||||
|
"netns-${cfg.netns}.service"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
services.enthalpy.services.enthalpy-clat = { };
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
|
||||||
mylib,
|
mylib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
cfg = config.services.enthalpy;
|
cfg = config.services.enthalpy;
|
||||||
gostPort = config.networking.ports.enthalpy-gost;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.enthalpy.gost = {
|
options.services.enthalpy.gost = {
|
||||||
|
@ -21,22 +20,24 @@ in
|
||||||
systemd.services.enthalpy-gost = {
|
systemd.services.enthalpy-gost = {
|
||||||
serviceConfig = mylib.misc.serviceHardened // {
|
serviceConfig = mylib.misc.serviceHardened // {
|
||||||
Type = "simple";
|
Type = "simple";
|
||||||
Restart = "always";
|
Restart = "on-failure";
|
||||||
RestartSec = 5;
|
RestartSec = 5;
|
||||||
DynamicUser = true;
|
DynamicUser = true;
|
||||||
ExecStart = "${pkgs.gost}/bin/gost -L=socks5://[::1]:${toString gostPort}";
|
ExecStart = "${pkgs.gost}/bin/gost -L=socks5://[::1]:${toString config.networking.ports.enthalpy-gost}";
|
||||||
};
|
};
|
||||||
after = [ "network-online.target" ];
|
after = [ "netns-${cfg.netns}.service" ];
|
||||||
wantedBy = [ "network-online.target" ];
|
partOf = [ "netns-${cfg.netns}.service" ];
|
||||||
|
wantedBy = [
|
||||||
|
"multi-user.target"
|
||||||
|
"netns-${cfg.netns}.service"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
networking.netns."${cfg.netns}".forwardPorts = [
|
networking.netns."${cfg.netns}".forwardPorts = singleton {
|
||||||
{
|
protocol = "tcp";
|
||||||
protocol = "tcp";
|
netns = "default";
|
||||||
netns = "default";
|
source = "[::1]:${toString config.networking.ports.enthalpy-gost}";
|
||||||
source = "[::1]:${toString gostPort}";
|
target = "[::1]:${toString config.networking.ports.socks}";
|
||||||
target = "[::1]:${toString gostPort}";
|
};
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
with lib;
|
with lib;
|
||||||
|
|
Loading…
Reference in a new issue