services/enthalpy: refactor for better network isolation and usability
This commit is contained in:
parent
4b2dcb5541
commit
a746646d5e
|
@ -5,14 +5,13 @@
|
|||
];
|
||||
|
||||
services.enthalpy = {
|
||||
users.rebmit = { };
|
||||
ipsec.interfaces = [ "enp14s0" ];
|
||||
sing-box = {
|
||||
clat = {
|
||||
enable = true;
|
||||
clat = {
|
||||
enable = true;
|
||||
segment = lib.singleton "fde3:3be3:a244:2676::2";
|
||||
};
|
||||
segment = lib.singleton "fde3:3be3:a244:2676::2";
|
||||
};
|
||||
gost.enable = true;
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
|
|
|
@ -5,17 +5,16 @@
|
|||
];
|
||||
|
||||
services.enthalpy = {
|
||||
users.rebmit = { };
|
||||
ipsec = {
|
||||
interfaces = [ "wlan0" ];
|
||||
whitelist = [ "rebmit's edge network" ];
|
||||
};
|
||||
sing-box = {
|
||||
clat = {
|
||||
enable = true;
|
||||
clat = {
|
||||
enable = true;
|
||||
segment = lib.singleton "fde3:3be3:a244:2676::2";
|
||||
};
|
||||
segment = lib.singleton "fde3:3be3:a244:2676::2";
|
||||
};
|
||||
gost.enable = true;
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ profiles, ... }:
|
||||
{
|
||||
profiles,
|
||||
data,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = with profiles; [
|
||||
services.enthalpy
|
||||
|
@ -8,7 +13,13 @@
|
|||
ipsec.interfaces = [ "enp3s0" ];
|
||||
exit = {
|
||||
enable = true;
|
||||
prefix = [ "::/0" ];
|
||||
prefix = [
|
||||
{
|
||||
type = "bird";
|
||||
destination = "::/0";
|
||||
source = data.enthalpy_network_prefix;
|
||||
}
|
||||
];
|
||||
};
|
||||
srv6.enable = true;
|
||||
nat64.enable = true;
|
||||
|
@ -46,6 +57,12 @@
|
|||
dhcpV6Config.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;
|
||||
|
||||
# enthalpy
|
||||
sing-box = 1080;
|
||||
enthalpy-ipsec = 13000;
|
||||
enthalpy-gost = 1080;
|
||||
};
|
||||
readOnly = true;
|
||||
description = ''
|
||||
|
|
|
@ -28,7 +28,6 @@ in
|
|||
# enthalpy
|
||||
localsid = 300;
|
||||
nat64 = 301;
|
||||
sing-box = 302;
|
||||
};
|
||||
readOnly = true;
|
||||
description = ''
|
||||
|
@ -37,10 +36,7 @@ in
|
|||
};
|
||||
routingMarks = mkOption {
|
||||
type = with types; attrsOf int;
|
||||
default = {
|
||||
# enthalpy
|
||||
sing-box = 1300;
|
||||
};
|
||||
default = { };
|
||||
readOnly = true;
|
||||
description = ''
|
||||
A mapping of routing marks, each identified by a unique name.
|
||||
|
@ -56,7 +52,6 @@ in
|
|||
|
||||
# enthalpy
|
||||
localsid = 500;
|
||||
sing-box = 13000;
|
||||
};
|
||||
readOnly = true;
|
||||
description = ''
|
||||
|
|
|
@ -53,7 +53,6 @@ in
|
|||
|
||||
systemd.services.enthalpy-bird2 = {
|
||||
serviceConfig = {
|
||||
NetworkNamespacePath = "/run/netns/${cfg.netns}";
|
||||
Type = "forking";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 5;
|
||||
|
@ -81,14 +80,12 @@ in
|
|||
SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
|
||||
MemoryDenyWriteExecute = "yes";
|
||||
};
|
||||
partOf = [ "enthalpy.service" ];
|
||||
after = [ "enthalpy.service" ];
|
||||
requires = [ "enthalpy.service" ];
|
||||
requiredBy = [ "enthalpy.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
reloadTriggers = [ config.environment.etc."enthalpy/bird2.conf".source ];
|
||||
};
|
||||
|
||||
services.enthalpy.services.enthalpy-bird2 = { };
|
||||
|
||||
services.enthalpy.bird.config = mkBefore ''
|
||||
router id ${toString cfg.bird.routerId};
|
||||
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 {
|
||||
type = types.str;
|
||||
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 {
|
||||
type = types.str;
|
||||
default = "enthalpy";
|
||||
description = ''
|
||||
Name of the network namespace for interfaces.
|
||||
'';
|
||||
};
|
||||
interface = mkOption {
|
||||
type = types.str;
|
||||
default = "enthalpy";
|
||||
description = ''
|
||||
Name of the interface to connect to the network namespace.
|
||||
Name of the network namespace for enthalpy interfaces.
|
||||
'';
|
||||
};
|
||||
network = mkOption {
|
||||
|
@ -44,6 +44,11 @@ in
|
|||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.network.networks."50-enthalpy" = {
|
||||
matchConfig.Name = "enthalpy";
|
||||
linkConfig.RequiredForOnline = false;
|
||||
};
|
||||
|
||||
systemd.services.enthalpy = {
|
||||
path = with pkgs; [
|
||||
iproute2
|
||||
|
@ -52,34 +57,29 @@ in
|
|||
];
|
||||
script = ''
|
||||
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 set ${cfg.interface} up
|
||||
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 -n ${cfg.netns} link set lo 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.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 = ''
|
||||
ip link del ${cfg.interface}
|
||||
ip netns del ${cfg.netns}
|
||||
'';
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network.target" ];
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
|
||||
systemd.network.networks."50-enthalpy" = {
|
||||
matchConfig.Name = cfg.interface;
|
||||
networkConfig.Address = "${cidr.host 1 cfg.prefix}/127";
|
||||
routes = singleton {
|
||||
Destination = cfg.network;
|
||||
Gateway = "fe80::ff:fe00:0";
|
||||
};
|
||||
};
|
||||
environment.etc."netns/enthalpy/resolv.conf".text = lib.mkDefault ''
|
||||
nameserver 2606:4700:4700::1111
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,21 +4,39 @@
|
|||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
mylib,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
let
|
||||
inherit (mylib.network) cidr;
|
||||
cfg = config.services.enthalpy;
|
||||
internalPrefix = filter (p: cidr.child p cfg.prefix) cfg.exit.prefix;
|
||||
externalPrefix = subtractLists internalPrefix cfg.exit.prefix;
|
||||
birdPrefix = filter (p: p.type == "bird") 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
|
||||
{
|
||||
options.services.enthalpy.exit = {
|
||||
enable = mkEnableOption "netns route leaking";
|
||||
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 = [ ];
|
||||
description = ''
|
||||
Prefixes to be announced from the default netns to the enthalpy network.
|
||||
|
@ -32,32 +50,24 @@ in
|
|||
ipv6 sadr;
|
||||
${
|
||||
concatMapStringsSep "\n" (p: ''
|
||||
route ${p} from ${cfg.network} via fe80::ff:fe00:1 dev "enthalpy";
|
||||
'') externalPrefix
|
||||
route ${p.destination} from ${p.source} via fe80::ff:fe00:1 dev "enthalpy";
|
||||
'') birdPrefix
|
||||
}
|
||||
}
|
||||
'';
|
||||
|
||||
systemd.services.enthalpy-exit =
|
||||
let
|
||||
routes = map (p: "${p} via fe80::ff:fe00:1 dev enthalpy") internalPrefix;
|
||||
in
|
||||
mkIf (routes != [ ]) {
|
||||
serviceConfig = {
|
||||
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" ];
|
||||
systemd.services.enthalpy-exit = mkIf (staticRoutes != [ ]) {
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = builtins.map (route: "${pkgs.iproute2}/bin/ip -6 route add ${route}") staticRoutes;
|
||||
ExecStop = builtins.map (route: "${pkgs.iproute2}/bin/ip -6 route del ${route}") staticRoutes;
|
||||
};
|
||||
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 = {
|
||||
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
|
||||
ipv6-addr fc00::
|
||||
ipv4-addr 100.127.0.1
|
||||
prefix ${cfg.nat64.prefix}
|
||||
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 = [
|
||||
"enthalpy.service"
|
||||
"network.target"
|
||||
];
|
||||
requires = [ "enthalpy.service" ];
|
||||
requiredBy = [ "enthalpy.service" ];
|
||||
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 = {
|
||||
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 {
|
||||
type = types.str;
|
||||
default = cidr.subnet 4 6 cfg.prefix;
|
||||
|
@ -49,8 +25,8 @@ in
|
|||
actions = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
"${cidr.host 1 cfg.srv6.prefix} encap seg6local action End.DT6 table main dev ${cfg.interface} table ${cfg.srv6.tableName}"
|
||||
"${cidr.host 2 cfg.srv6.prefix} encap seg6local action End.DT6 table nat64 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 enthalpy table localsid"
|
||||
];
|
||||
description = ''
|
||||
List of SRv6 actions configured in the default network namespace.
|
||||
|
@ -70,12 +46,12 @@ in
|
|||
routes = singleton {
|
||||
Destination = "::/0";
|
||||
Type = "blackhole";
|
||||
Table = cfg.srv6.table;
|
||||
Table = config.networking.routingTables.localsid;
|
||||
};
|
||||
routingPolicyRules = singleton {
|
||||
Priority = cfg.srv6.priority;
|
||||
Priority = config.networking.routingPolicyPriorities.localsid;
|
||||
Family = "ipv6";
|
||||
Table = cfg.srv6.table;
|
||||
Table = config.networking.routingTables.localsid;
|
||||
From = cfg.network;
|
||||
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"
|
||||
];
|
||||
};
|
||||
partOf = [ "enthalpy.service" ];
|
||||
after = [
|
||||
"enthalpy.service"
|
||||
"network-online.target"
|
||||
];
|
||||
requires = [ "enthalpy.service" ];
|
||||
requiredBy = [ "enthalpy.service" ];
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
{ config, pkgs, ... }:
|
||||
let
|
||||
uid = config.ids.uids.rebmit;
|
||||
homeDirectory = "/home/rebmit";
|
||||
in
|
||||
{
|
||||
programs.fish.enable = true;
|
||||
|
||||
users.users.rebmit = {
|
||||
inherit uid;
|
||||
hashedPasswordFile = config.sops.secrets."user-password/rebmit".path;
|
||||
isNormalUser = true;
|
||||
shell = pkgs.fish;
|
||||
|
|
Loading…
Reference in a new issue