services/enthalpy: refactor for better network isolation and usability
This commit is contained in:
parent
4b2dcb5541
commit
a746646d5e
|
@ -5,14 +5,13 @@
|
||||||
];
|
];
|
||||||
|
|
||||||
services.enthalpy = {
|
services.enthalpy = {
|
||||||
|
users.rebmit = { };
|
||||||
ipsec.interfaces = [ "enp14s0" ];
|
ipsec.interfaces = [ "enp14s0" ];
|
||||||
sing-box = {
|
clat = {
|
||||||
enable = true;
|
enable = true;
|
||||||
clat = {
|
segment = lib.singleton "fde3:3be3:a244:2676::2";
|
||||||
enable = true;
|
|
||||||
segment = lib.singleton "fde3:3be3:a244:2676::2";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
gost.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.network = {
|
systemd.network = {
|
||||||
|
|
|
@ -5,17 +5,16 @@
|
||||||
];
|
];
|
||||||
|
|
||||||
services.enthalpy = {
|
services.enthalpy = {
|
||||||
|
users.rebmit = { };
|
||||||
ipsec = {
|
ipsec = {
|
||||||
interfaces = [ "wlan0" ];
|
interfaces = [ "wlan0" ];
|
||||||
whitelist = [ "rebmit's edge network" ];
|
whitelist = [ "rebmit's edge network" ];
|
||||||
};
|
};
|
||||||
sing-box = {
|
clat = {
|
||||||
enable = true;
|
enable = true;
|
||||||
clat = {
|
segment = lib.singleton "fde3:3be3:a244:2676::2";
|
||||||
enable = true;
|
|
||||||
segment = lib.singleton "fde3:3be3:a244:2676::2";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
gost.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.network = {
|
systemd.network = {
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
{ profiles, ... }:
|
{
|
||||||
|
profiles,
|
||||||
|
data,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
{
|
{
|
||||||
imports = with profiles; [
|
imports = with profiles; [
|
||||||
services.enthalpy
|
services.enthalpy
|
||||||
|
@ -8,7 +13,13 @@
|
||||||
ipsec.interfaces = [ "enp3s0" ];
|
ipsec.interfaces = [ "enp3s0" ];
|
||||||
exit = {
|
exit = {
|
||||||
enable = true;
|
enable = true;
|
||||||
prefix = [ "::/0" ];
|
prefix = [
|
||||||
|
{
|
||||||
|
type = "bird";
|
||||||
|
destination = "::/0";
|
||||||
|
source = data.enthalpy_network_prefix;
|
||||||
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
srv6.enable = true;
|
srv6.enable = true;
|
||||||
nat64.enable = true;
|
nat64.enable = true;
|
||||||
|
@ -46,6 +57,12 @@
|
||||||
dhcpV6Config.RouteMetric = 1024;
|
dhcpV6Config.RouteMetric = 1024;
|
||||||
ipv6AcceptRAConfig.RouteMetric = 1024;
|
ipv6AcceptRAConfig.RouteMetric = 1024;
|
||||||
};
|
};
|
||||||
|
"50-enthalpy" = {
|
||||||
|
routes = lib.singleton {
|
||||||
|
Destination = data.enthalpy_network_prefix;
|
||||||
|
Gateway = "fe80::ff:fe00:0";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
8
nixos/modules/networking/ids.nix
Normal file
8
nixos/modules/networking/ids.nix
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
ids.uids = {
|
||||||
|
rebmit = 1000;
|
||||||
|
};
|
||||||
|
|
||||||
|
ids.gids = { };
|
||||||
|
}
|
|
@ -13,8 +13,8 @@ in
|
||||||
ssh = 2222;
|
ssh = 2222;
|
||||||
|
|
||||||
# enthalpy
|
# enthalpy
|
||||||
sing-box = 1080;
|
|
||||||
enthalpy-ipsec = 13000;
|
enthalpy-ipsec = 13000;
|
||||||
|
enthalpy-gost = 1080;
|
||||||
};
|
};
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
description = ''
|
description = ''
|
||||||
|
|
|
@ -28,7 +28,6 @@ in
|
||||||
# enthalpy
|
# enthalpy
|
||||||
localsid = 300;
|
localsid = 300;
|
||||||
nat64 = 301;
|
nat64 = 301;
|
||||||
sing-box = 302;
|
|
||||||
};
|
};
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
description = ''
|
description = ''
|
||||||
|
@ -37,10 +36,7 @@ in
|
||||||
};
|
};
|
||||||
routingMarks = mkOption {
|
routingMarks = mkOption {
|
||||||
type = with types; attrsOf int;
|
type = with types; attrsOf int;
|
||||||
default = {
|
default = { };
|
||||||
# enthalpy
|
|
||||||
sing-box = 1300;
|
|
||||||
};
|
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
description = ''
|
description = ''
|
||||||
A mapping of routing marks, each identified by a unique name.
|
A mapping of routing marks, each identified by a unique name.
|
||||||
|
@ -56,7 +52,6 @@ in
|
||||||
|
|
||||||
# enthalpy
|
# enthalpy
|
||||||
localsid = 500;
|
localsid = 500;
|
||||||
sing-box = 13000;
|
|
||||||
};
|
};
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
description = ''
|
description = ''
|
||||||
|
|
|
@ -53,7 +53,6 @@ in
|
||||||
|
|
||||||
systemd.services.enthalpy-bird2 = {
|
systemd.services.enthalpy-bird2 = {
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
NetworkNamespacePath = "/run/netns/${cfg.netns}";
|
|
||||||
Type = "forking";
|
Type = "forking";
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
RestartSec = 5;
|
RestartSec = 5;
|
||||||
|
@ -81,14 +80,12 @@ in
|
||||||
SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
|
SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
|
||||||
MemoryDenyWriteExecute = "yes";
|
MemoryDenyWriteExecute = "yes";
|
||||||
};
|
};
|
||||||
partOf = [ "enthalpy.service" ];
|
|
||||||
after = [ "enthalpy.service" ];
|
|
||||||
requires = [ "enthalpy.service" ];
|
|
||||||
requiredBy = [ "enthalpy.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
reloadTriggers = [ config.environment.etc."enthalpy/bird2.conf".source ];
|
reloadTriggers = [ config.environment.etc."enthalpy/bird2.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;
|
||||||
|
|
84
nixos/modules/services/enthalpy/clat.nix
Normal file
84
nixos/modules/services/enthalpy/clat.nix
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
# Portions of this file are sourced from
|
||||||
|
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/nixos/mainframe/gravity.nix
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
mylib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
inherit (mylib.network) cidr;
|
||||||
|
cfg = config.services.enthalpy;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.enthalpy.clat = {
|
||||||
|
enable = mkEnableOption "464XLAT for IPv4 connectivity";
|
||||||
|
address = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = cidr.host 2 cfg.prefix;
|
||||||
|
description = ''
|
||||||
|
IPv6 address used for 464XLAT as the mapped source address.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
segment = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
description = ''
|
||||||
|
SRv6 segments used for NAT64.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (cfg.enable && cfg.clat.enable) {
|
||||||
|
systemd.services.enthalpy-clat = {
|
||||||
|
path = with pkgs; [
|
||||||
|
iproute2
|
||||||
|
tayga
|
||||||
|
];
|
||||||
|
preStart = ''
|
||||||
|
ip -6 route replace 64:ff9b::/96 from ${cfg.clat.address} encap seg6 mode encap \
|
||||||
|
segs ${concatStringsSep "," cfg.clat.segment} dev enthalpy mtu 1280
|
||||||
|
'';
|
||||||
|
script = ''
|
||||||
|
exec tayga --config ${pkgs.writeText "tayga.conf" ''
|
||||||
|
tun-device clat
|
||||||
|
prefix 64:ff9b::/96
|
||||||
|
ipv4-addr 192.0.0.1
|
||||||
|
map 192.0.0.2 ${cfg.clat.address}
|
||||||
|
''}
|
||||||
|
'';
|
||||||
|
postStart = ''
|
||||||
|
ip link set clat up
|
||||||
|
ip -4 addr add 192.0.0.2/32 dev clat
|
||||||
|
ip -6 route add ${cfg.clat.address} dev clat
|
||||||
|
ip -4 route add 0.0.0.0/0 dev clat src 192.0.0.2
|
||||||
|
'';
|
||||||
|
preStop = ''
|
||||||
|
ip -6 route del 64:ff9b::/96 from ${cfg.clat.address} encap seg6 mode encap \
|
||||||
|
segs ${concatStringsSep "," cfg.clat.segment} dev enthalpy mtu 1280
|
||||||
|
'';
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "forking";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 5;
|
||||||
|
DynamicUser = true;
|
||||||
|
RuntimeDirectory = "enthalpy";
|
||||||
|
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
|
||||||
|
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
|
||||||
|
ProtectSystem = "full";
|
||||||
|
ProtectHome = "yes";
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
|
||||||
|
MemoryDenyWriteExecute = "yes";
|
||||||
|
};
|
||||||
|
wants = [ "network.target" ];
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.enthalpy.services.enthalpy-clat = { };
|
||||||
|
};
|
||||||
|
}
|
|
@ -18,21 +18,21 @@ in
|
||||||
prefix = mkOption {
|
prefix = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = ''
|
description = ''
|
||||||
Prefix to be announced for the local node.
|
Prefix to be announced for the local node in the enthalpy network.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
address = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = cidr.host 1 cfg.prefix;
|
||||||
|
description = ''
|
||||||
|
Address to be added into the enthalpy network as source address.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
netns = mkOption {
|
netns = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "enthalpy";
|
default = "enthalpy";
|
||||||
description = ''
|
description = ''
|
||||||
Name of the network namespace for interfaces.
|
Name of the network namespace for enthalpy interfaces.
|
||||||
'';
|
|
||||||
};
|
|
||||||
interface = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "enthalpy";
|
|
||||||
description = ''
|
|
||||||
Name of the interface to connect to the network namespace.
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
network = mkOption {
|
network = mkOption {
|
||||||
|
@ -44,6 +44,11 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
systemd.network.networks."50-enthalpy" = {
|
||||||
|
matchConfig.Name = "enthalpy";
|
||||||
|
linkConfig.RequiredForOnline = false;
|
||||||
|
};
|
||||||
|
|
||||||
systemd.services.enthalpy = {
|
systemd.services.enthalpy = {
|
||||||
path = with pkgs; [
|
path = with pkgs; [
|
||||||
iproute2
|
iproute2
|
||||||
|
@ -52,34 +57,29 @@ in
|
||||||
];
|
];
|
||||||
script = ''
|
script = ''
|
||||||
ip netns add ${cfg.netns}
|
ip netns add ${cfg.netns}
|
||||||
ip link add ${cfg.interface} mtu 1400 address 02:00:00:00:00:01 type veth peer enthalpy mtu 1400 address 02:00:00:00:00:00 netns ${cfg.netns}
|
ip link add enthalpy mtu 1400 address 02:00:00:00:00:01 type veth peer enthalpy mtu 1400 address 02:00:00:00:00:00 netns ${cfg.netns}
|
||||||
ip link set ${cfg.interface} up
|
|
||||||
ip -n ${cfg.netns} link set lo up
|
ip -n ${cfg.netns} link set lo up
|
||||||
ip -n ${cfg.netns} link set enthalpy up
|
ip -n ${cfg.netns} link set enthalpy up
|
||||||
ip -n ${cfg.netns} addr add ${cidr.host 0 cfg.prefix}/127 dev enthalpy
|
ip -n ${cfg.netns} addr add ${cfg.address}/128 dev enthalpy
|
||||||
ip netns exec ${cfg.netns} sysctl -w net.ipv6.conf.default.forwarding=1
|
ip netns exec ${cfg.netns} sysctl -w net.ipv6.conf.default.forwarding=1
|
||||||
ip netns exec ${cfg.netns} sysctl -w net.ipv6.conf.all.forwarding=1
|
ip netns exec ${cfg.netns} sysctl -w net.ipv6.conf.all.forwarding=1
|
||||||
|
ip netns exec ${cfg.netns} sysctl -w net.ipv4.conf.default.forwarding=0
|
||||||
|
ip netns exec ${cfg.netns} sysctl -w net.ipv4.conf.all.forwarding=0
|
||||||
'';
|
'';
|
||||||
preStop = ''
|
preStop = ''
|
||||||
ip link del ${cfg.interface}
|
|
||||||
ip netns del ${cfg.netns}
|
ip netns del ${cfg.netns}
|
||||||
'';
|
'';
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
RemainAfterExit = true;
|
RemainAfterExit = true;
|
||||||
};
|
};
|
||||||
wants = [ "network-online.target" ];
|
wants = [ "network.target" ];
|
||||||
after = [ "network-online.target" ];
|
after = [ "network.target" ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.network.networks."50-enthalpy" = {
|
environment.etc."netns/enthalpy/resolv.conf".text = lib.mkDefault ''
|
||||||
matchConfig.Name = cfg.interface;
|
nameserver 2606:4700:4700::1111
|
||||||
networkConfig.Address = "${cidr.host 1 cfg.prefix}/127";
|
'';
|
||||||
routes = singleton {
|
|
||||||
Destination = cfg.network;
|
|
||||||
Gateway = "fe80::ff:fe00:0";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,21 +4,39 @@
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
mylib,
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
inherit (mylib.network) cidr;
|
|
||||||
cfg = config.services.enthalpy;
|
cfg = config.services.enthalpy;
|
||||||
internalPrefix = filter (p: cidr.child p cfg.prefix) cfg.exit.prefix;
|
birdPrefix = filter (p: p.type == "bird") cfg.exit.prefix;
|
||||||
externalPrefix = subtractLists internalPrefix cfg.exit.prefix;
|
staticPrefix = subtractLists birdPrefix cfg.exit.prefix;
|
||||||
|
staticRoutes = map (
|
||||||
|
p: "${p.destination} from ${p.source} via fe80::ff:fe00:1 dev enthalpy"
|
||||||
|
) staticPrefix;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.enthalpy.exit = {
|
options.services.enthalpy.exit = {
|
||||||
enable = mkEnableOption "netns route leaking";
|
enable = mkEnableOption "netns route leaking";
|
||||||
prefix = mkOption {
|
prefix = mkOption {
|
||||||
type = types.listOf types.str;
|
type = types.listOf (
|
||||||
|
types.submodule {
|
||||||
|
options = {
|
||||||
|
type = mkOption {
|
||||||
|
type = types.enum [
|
||||||
|
"bird"
|
||||||
|
"static"
|
||||||
|
];
|
||||||
|
default = "static";
|
||||||
|
};
|
||||||
|
destination = mkOption { type = types.str; };
|
||||||
|
source = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "::/0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
default = [ ];
|
default = [ ];
|
||||||
description = ''
|
description = ''
|
||||||
Prefixes to be announced from the default netns to the enthalpy network.
|
Prefixes to be announced from the default netns to the enthalpy network.
|
||||||
|
@ -32,32 +50,24 @@ in
|
||||||
ipv6 sadr;
|
ipv6 sadr;
|
||||||
${
|
${
|
||||||
concatMapStringsSep "\n" (p: ''
|
concatMapStringsSep "\n" (p: ''
|
||||||
route ${p} from ${cfg.network} via fe80::ff:fe00:1 dev "enthalpy";
|
route ${p.destination} from ${p.source} via fe80::ff:fe00:1 dev "enthalpy";
|
||||||
'') externalPrefix
|
'') birdPrefix
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
systemd.services.enthalpy-exit =
|
systemd.services.enthalpy-exit = mkIf (staticRoutes != [ ]) {
|
||||||
let
|
serviceConfig = {
|
||||||
routes = map (p: "${p} via fe80::ff:fe00:1 dev enthalpy") internalPrefix;
|
Type = "oneshot";
|
||||||
in
|
RemainAfterExit = true;
|
||||||
mkIf (routes != [ ]) {
|
ExecStart = builtins.map (route: "${pkgs.iproute2}/bin/ip -6 route add ${route}") staticRoutes;
|
||||||
serviceConfig = {
|
ExecStop = builtins.map (route: "${pkgs.iproute2}/bin/ip -6 route del ${route}") staticRoutes;
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
ExecStart = builtins.map (route: "${pkgs.iproute2}/bin/ip -n ${cfg.netns} -6 r a ${route}") routes;
|
|
||||||
ExecStop = builtins.map (route: "${pkgs.iproute2}/bin/ip -n ${cfg.netns} -6 r d ${route}") routes;
|
|
||||||
};
|
|
||||||
partOf = [ "enthalpy.service" ];
|
|
||||||
after = [
|
|
||||||
"enthalpy.service"
|
|
||||||
"network-online.target"
|
|
||||||
];
|
|
||||||
requires = [ "enthalpy.service" ];
|
|
||||||
requiredBy = [ "enthalpy.service" ];
|
|
||||||
wants = [ "network-online.target" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
};
|
};
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wants = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.enthalpy.services.enthalpy-exit = mkIf (staticRoutes != [ ]) { };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
57
nixos/modules/services/enthalpy/gost.nix
Normal file
57
nixos/modules/services/enthalpy/gost.nix
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# Portions of this file are sourced from
|
||||||
|
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/nixos/mainframe/gravity.nix
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.services.enthalpy;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.enthalpy.gost = {
|
||||||
|
enable = mkEnableOption "simple tunnel for accessing the underlay network";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (cfg.enable && cfg.gost.enable) {
|
||||||
|
systemd.network.networks."50-enthalpy" = {
|
||||||
|
address = singleton "fc00::";
|
||||||
|
routes = singleton { Destination = cfg.address; };
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.enthalpy-gost = {
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 5;
|
||||||
|
DynamicUser = true;
|
||||||
|
RuntimeDirectory = "enthalpy";
|
||||||
|
ExecStart = "${pkgs.gost}/bin/gost -L=socks5://[fc00::]:${toString config.networking.ports.enthalpy-gost}";
|
||||||
|
ProtectSystem = "full";
|
||||||
|
ProtectHome = "yes";
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
PrivateDevices = true;
|
||||||
|
SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
|
||||||
|
MemoryDenyWriteExecute = "yes";
|
||||||
|
};
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
after = [
|
||||||
|
"enthalpy.service"
|
||||||
|
"network-online.target"
|
||||||
|
];
|
||||||
|
requires = [ "enthalpy.service" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.enthalpy.exit.enable = true;
|
||||||
|
services.enthalpy.exit.prefix = singleton {
|
||||||
|
type = "static";
|
||||||
|
destination = "fc00::/128";
|
||||||
|
source = "${cfg.address}/128";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -60,21 +60,34 @@ in
|
||||||
|
|
||||||
systemd.services.enthalpy-nat64 = {
|
systemd.services.enthalpy-nat64 = {
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${pkgs.tayga}/bin/tayga -d --config ${pkgs.writeText "tayga.conf" ''
|
Type = "forking";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 5;
|
||||||
|
DynamicUser = true;
|
||||||
|
RuntimeDirectory = "enthalpy";
|
||||||
|
ExecStart = "${pkgs.tayga}/bin/tayga --config ${pkgs.writeText "tayga.conf" ''
|
||||||
tun-device nat64
|
tun-device nat64
|
||||||
ipv6-addr fc00::
|
ipv6-addr fc00::
|
||||||
ipv4-addr 100.127.0.1
|
ipv4-addr 100.127.0.1
|
||||||
prefix ${cfg.nat64.prefix}
|
prefix ${cfg.nat64.prefix}
|
||||||
dynamic-pool ${cfg.nat64.dynamicPool}
|
dynamic-pool ${cfg.nat64.dynamicPool}
|
||||||
''}";
|
''}";
|
||||||
|
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
|
||||||
|
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
|
||||||
|
ProtectSystem = "full";
|
||||||
|
ProtectHome = "yes";
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
|
||||||
|
MemoryDenyWriteExecute = "yes";
|
||||||
};
|
};
|
||||||
partOf = [ "enthalpy.service" ];
|
wants = [ "network.target" ];
|
||||||
after = [
|
after = [
|
||||||
"enthalpy.service"
|
"enthalpy.service"
|
||||||
"network.target"
|
"network.target"
|
||||||
];
|
];
|
||||||
requires = [ "enthalpy.service" ];
|
requires = [ "enthalpy.service" ];
|
||||||
requiredBy = [ "enthalpy.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
57
nixos/modules/services/enthalpy/services.nix
Normal file
57
nixos/modules/services/enthalpy/services.nix
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# Portions of this file are sourced from
|
||||||
|
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/modules/gravity/default.nix
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.services.enthalpy;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.enthalpy = {
|
||||||
|
services = mkOption {
|
||||||
|
type = types.attrsOf (
|
||||||
|
types.submodule {
|
||||||
|
options = {
|
||||||
|
overrideStrategy = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "asDropinIfExists";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Services that need to run inside the enthalpy network namespace.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
users = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule { });
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Users utilizing the enthalpy network namespace.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
systemd.services = mapAttrs (_name: value: {
|
||||||
|
inherit (value) overrideStrategy;
|
||||||
|
serviceConfig = {
|
||||||
|
NetworkNamespacePath = "/run/netns/${cfg.netns}";
|
||||||
|
BindReadOnlyPaths = "/etc/netns/${cfg.netns}/resolv.conf:/etc/resolv.conf:norbind";
|
||||||
|
};
|
||||||
|
after = [ "enthalpy.service" ];
|
||||||
|
requires = [ "enthalpy.service" ];
|
||||||
|
}) cfg.services;
|
||||||
|
|
||||||
|
services.enthalpy.services = mapAttrs' (
|
||||||
|
name: _value:
|
||||||
|
nameValuePair "user@${toString config.users.users.${name}.uid}" {
|
||||||
|
overrideStrategy = "asDropin";
|
||||||
|
}
|
||||||
|
) cfg.users;
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,232 +0,0 @@
|
||||||
# Portions of this file are sourced from
|
|
||||||
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/nixos/mainframe/gravity.nix
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
mylib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib;
|
|
||||||
let
|
|
||||||
inherit (mylib.network) cidr;
|
|
||||||
cfg = config.services.enthalpy;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.services.enthalpy.sing-box = {
|
|
||||||
enable = mkEnableOption "sing-box universal proxy platform";
|
|
||||||
tableName = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "sing-box";
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Routing table used for sing-box.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
table = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = config.networking.routingTables."${cfg.sing-box.tableName}";
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Routing table ID associated with the sing-box routing table.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
priority = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = config.networking.routingPolicyPriorities."${cfg.sing-box.tableName}";
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Routing priority assigned to the sing-box routing table.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
fwmark = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = config.networking.routingMarks."${cfg.sing-box.tableName}";
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Firewall mark designated for the sing-box routing table.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
port = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = config.networking.ports.sing-box;
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Port for the mixed proxy to listen on.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
clat = {
|
|
||||||
enable = mkEnableOption "464XLAT for IPv4 connectivity";
|
|
||||||
address = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = cidr.host 2 cfg.prefix;
|
|
||||||
description = ''
|
|
||||||
IPv6 address used for 464XLAT as the mapped source address.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
segment = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
description = ''
|
|
||||||
SRv6 segments used for NAT64.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf (cfg.enable && cfg.sing-box.enable) (mkMerge [
|
|
||||||
# IPv6
|
|
||||||
{
|
|
||||||
systemd.network.networks."50-enthalpy" = {
|
|
||||||
routes = [
|
|
||||||
{
|
|
||||||
Destination = "::/0";
|
|
||||||
Gateway = "fe80::ff:fe00:0";
|
|
||||||
Table = cfg.sing-box.table;
|
|
||||||
Metric = 1024;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Destination = "::0/0";
|
|
||||||
Type = "blackhole";
|
|
||||||
Table = cfg.sing-box.table;
|
|
||||||
Metric = 4096;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
routingPolicyRules = lib.singleton {
|
|
||||||
Family = "both";
|
|
||||||
FirewallMark = cfg.sing-box.fwmark;
|
|
||||||
Priority = cfg.sing-box.priority;
|
|
||||||
Table = cfg.sing-box.table;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.sing-box = {
|
|
||||||
enable = true;
|
|
||||||
settings = {
|
|
||||||
log = {
|
|
||||||
level = "info";
|
|
||||||
};
|
|
||||||
dns = {
|
|
||||||
servers = [
|
|
||||||
{
|
|
||||||
tag = "cloudflare";
|
|
||||||
address = "https://[2606:4700:4700::1111]/dns-query";
|
|
||||||
strategy = "prefer_ipv6";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
tag = "local";
|
|
||||||
address = "local";
|
|
||||||
strategy = "prefer_ipv4";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
rules = [
|
|
||||||
{
|
|
||||||
geosite = [ "cn" ];
|
|
||||||
server = "local";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
final = "cloudflare";
|
|
||||||
};
|
|
||||||
inbounds = [
|
|
||||||
{
|
|
||||||
type = "mixed";
|
|
||||||
tag = "inbound";
|
|
||||||
listen = "127.0.0.1";
|
|
||||||
listen_port = cfg.sing-box.port;
|
|
||||||
sniff = true;
|
|
||||||
sniff_override_destination = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
outbounds = [
|
|
||||||
{
|
|
||||||
type = "direct";
|
|
||||||
tag = "enthalpy";
|
|
||||||
routing_mark = cfg.sing-box.fwmark;
|
|
||||||
domain_strategy = "prefer_ipv6";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
type = "direct";
|
|
||||||
tag = "direct";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
route = {
|
|
||||||
rules = [
|
|
||||||
{
|
|
||||||
geosite = [ "cn" ];
|
|
||||||
geoip = [ "cn" ];
|
|
||||||
ip_cidr = [ "10.0.0.0/8" ];
|
|
||||||
outbound = "direct";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
final = "enthalpy";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [ gg ];
|
|
||||||
|
|
||||||
environment.etc."ggconfig.toml".source = (pkgs.formats.toml { }).generate "ggconfig.toml" {
|
|
||||||
allow_insecure = false;
|
|
||||||
no_udp = false;
|
|
||||||
node = "socks5://127.0.0.1:${toString cfg.sing-box.port}";
|
|
||||||
proxy_private = false;
|
|
||||||
test_node_before_use = false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
# IPv4 (464XLAT)
|
|
||||||
(mkIf cfg.sing-box.clat.enable {
|
|
||||||
systemd.network.config = {
|
|
||||||
networkConfig = {
|
|
||||||
IPv6Forwarding = true;
|
|
||||||
ManageForeignRoutes = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.network.networks."50-clat" = {
|
|
||||||
name = "clat";
|
|
||||||
linkConfig = {
|
|
||||||
MTUBytes = "1400";
|
|
||||||
RequiredForOnline = false;
|
|
||||||
};
|
|
||||||
addresses = singleton { Address = "192.0.0.2/32"; };
|
|
||||||
routes = [
|
|
||||||
{
|
|
||||||
Destination = "0.0.0.0/0";
|
|
||||||
Table = cfg.sing-box.table;
|
|
||||||
PreferredSource = "192.0.0.2";
|
|
||||||
Metric = 1024;
|
|
||||||
}
|
|
||||||
{ Destination = cfg.sing-box.clat.address; }
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
services.enthalpy.exit.enable = true;
|
|
||||||
services.enthalpy.exit.prefix = singleton "${cfg.sing-box.clat.address}/128";
|
|
||||||
|
|
||||||
systemd.services.enthalpy-clatd = {
|
|
||||||
path = with pkgs; [
|
|
||||||
iproute2
|
|
||||||
tayga
|
|
||||||
];
|
|
||||||
script = ''
|
|
||||||
ip r replace 64:ff9b::/96 from ${cfg.sing-box.clat.address} encap seg6 mode encap \
|
|
||||||
segs ${concatStringsSep "," cfg.sing-box.clat.segment} dev ${cfg.interface} mtu 1280
|
|
||||||
exec tayga -d --config ${pkgs.writeText "tayga.conf" ''
|
|
||||||
tun-device clat
|
|
||||||
prefix 64:ff9b::/96
|
|
||||||
ipv4-addr 192.0.0.1
|
|
||||||
map 192.0.0.2 ${cfg.sing-box.clat.address}
|
|
||||||
''}
|
|
||||||
'';
|
|
||||||
partOf = [ "enthalpy.service" ];
|
|
||||||
after = [
|
|
||||||
"enthalpy.service"
|
|
||||||
"network.target"
|
|
||||||
];
|
|
||||||
requires = [ "enthalpy.service" ];
|
|
||||||
requiredBy = [ "enthalpy.service" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
};
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
}
|
|
|
@ -15,30 +15,6 @@ in
|
||||||
{
|
{
|
||||||
options.services.enthalpy.srv6 = {
|
options.services.enthalpy.srv6 = {
|
||||||
enable = mkEnableOption "segment routing over IPv6";
|
enable = mkEnableOption "segment routing over IPv6";
|
||||||
tableName = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "localsid";
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Routing table designated for SRv6 SID.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
table = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = config.networking.routingTables."${cfg.srv6.tableName}";
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Routing table ID associated with the localsid routing table.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
priority = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = config.networking.routingPolicyPriorities."${cfg.srv6.tableName}";
|
|
||||||
readOnly = true;
|
|
||||||
description = ''
|
|
||||||
Routing priority assigned to the localsid routing table.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
prefix = mkOption {
|
prefix = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = cidr.subnet 4 6 cfg.prefix;
|
default = cidr.subnet 4 6 cfg.prefix;
|
||||||
|
@ -49,8 +25,8 @@ in
|
||||||
actions = mkOption {
|
actions = mkOption {
|
||||||
type = types.listOf types.str;
|
type = types.listOf types.str;
|
||||||
default = [
|
default = [
|
||||||
"${cidr.host 1 cfg.srv6.prefix} encap seg6local action End.DT6 table main dev ${cfg.interface} table ${cfg.srv6.tableName}"
|
"${cidr.host 1 cfg.srv6.prefix} encap seg6local action End.DT6 table main dev enthalpy table localsid"
|
||||||
"${cidr.host 2 cfg.srv6.prefix} encap seg6local action End.DT6 table nat64 dev ${cfg.interface} table ${cfg.srv6.tableName}"
|
"${cidr.host 2 cfg.srv6.prefix} encap seg6local action End.DT6 table nat64 dev enthalpy table localsid"
|
||||||
];
|
];
|
||||||
description = ''
|
description = ''
|
||||||
List of SRv6 actions configured in the default network namespace.
|
List of SRv6 actions configured in the default network namespace.
|
||||||
|
@ -70,12 +46,12 @@ in
|
||||||
routes = singleton {
|
routes = singleton {
|
||||||
Destination = "::/0";
|
Destination = "::/0";
|
||||||
Type = "blackhole";
|
Type = "blackhole";
|
||||||
Table = cfg.srv6.table;
|
Table = config.networking.routingTables.localsid;
|
||||||
};
|
};
|
||||||
routingPolicyRules = singleton {
|
routingPolicyRules = singleton {
|
||||||
Priority = cfg.srv6.priority;
|
Priority = config.networking.routingPolicyPriorities.localsid;
|
||||||
Family = "ipv6";
|
Family = "ipv6";
|
||||||
Table = cfg.srv6.table;
|
Table = config.networking.routingTables.localsid;
|
||||||
From = cfg.network;
|
From = cfg.network;
|
||||||
To = cfg.srv6.prefix;
|
To = cfg.srv6.prefix;
|
||||||
};
|
};
|
||||||
|
@ -95,13 +71,11 @@ in
|
||||||
"${pkgs.iproute2}/bin/ip -n ${cfg.netns} -6 r d ${cfg.srv6.prefix} from ${cfg.network} via fe80::ff:fe00:1 dev enthalpy"
|
"${pkgs.iproute2}/bin/ip -n ${cfg.netns} -6 r d ${cfg.srv6.prefix} from ${cfg.network} via fe80::ff:fe00:1 dev enthalpy"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
partOf = [ "enthalpy.service" ];
|
|
||||||
after = [
|
after = [
|
||||||
"enthalpy.service"
|
"enthalpy.service"
|
||||||
"network-online.target"
|
"network-online.target"
|
||||||
];
|
];
|
||||||
requires = [ "enthalpy.service" ];
|
requires = [ "enthalpy.service" ];
|
||||||
requiredBy = [ "enthalpy.service" ];
|
|
||||||
wants = [ "network-online.target" ];
|
wants = [ "network-online.target" ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
let
|
let
|
||||||
|
uid = config.ids.uids.rebmit;
|
||||||
homeDirectory = "/home/rebmit";
|
homeDirectory = "/home/rebmit";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
programs.fish.enable = true;
|
programs.fish.enable = true;
|
||||||
|
|
||||||
users.users.rebmit = {
|
users.users.rebmit = {
|
||||||
|
inherit uid;
|
||||||
hashedPasswordFile = config.sops.secrets."user-password/rebmit".path;
|
hashedPasswordFile = config.sops.secrets."user-password/rebmit".path;
|
||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
shell = pkgs.fish;
|
shell = pkgs.fish;
|
||||||
|
|
Loading…
Reference in a new issue