router: add sit tunnel option

This commit is contained in:
chayleaf 2024-07-03 22:49:28 +07:00
parent 0cc911f974
commit d40bdb7415
Signed by: chayleaf
GPG key ID: 78171AD46227E68E
4 changed files with 46 additions and 17 deletions

View file

@ -510,11 +510,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1718217962, "lastModified": 1720021052,
"narHash": "sha256-bVKwJdVeo6wMN6xMOFx3Um3x7ebijyCG5iGCIXAtDXA=", "narHash": "sha256-tu8IQn8Kj7S0xRg0L2ej7S65FzXqSX7LI7M2pbLdQJU=",
"owner": "chayleaf", "owner": "chayleaf",
"repo": "nixos-router", "repo": "nixos-router",
"rev": "f25509e55a06f1dfa089556b28b9402c13e18aa4", "rev": "4c132c4c5fc09b3c3317b960ec1533c4a5ebe41f",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -86,7 +86,7 @@
if dev.${name} or false then if dev.${name} or false then
(if input._type or null == "flake" (if input._type or null == "flake"
then let inputs = input.inputs // { self = (import /${devPath}/${name}/flake.nix).outputs inputs; }; then let inputs = input.inputs // { self = (import /${devPath}/${name}/flake.nix).outputs inputs; };
in { __toString = _: "/${devPath}/${name}"; } // inputs.self in { __toString = _: "/${toString devPath}/${name}"; } // inputs.self
else /${devPath}/${name}) else /${devPath}/${name})
else input) else input)
base-inputs; base-inputs;

View file

@ -414,6 +414,21 @@ in {
}; };
*/ */
# ethernet wan # ethernet wan
router.tunnels.sittun0 = lib.mkIf (cfg.vpn.tunnel.mode == "sit") {
mode = "sit";
remote = cfg.vpn.tunnel.ip;
local = cfg.vpn.tunnel.localIp;
ttl = 255;
};
router.interfaces.sittun0 = lib.mkIf (cfg.vpn.tunnel.mode == "sit") {
dependentServices = [
(lib.mkIf cfg.vpn.wireguard.enable { service = "wireguard-${vpn_iface}"; inNetns = false; })
(lib.mkIf cfg.vpn.openvpn.enable { service = "openvpn-client"; inNetns = false; })
];
ipv6.addresses = [ (router-lib.parseCidr cfg.vpn.tunnel.ifaceAddr) ];
ipv6.routes = [ { extraArgs = [ "::/0" "dev" "sittun0" ]; } ];
networkNamespace = "wan";
};
router.interfaces.wan = { router.interfaces.wan = {
dependentServices = [ dependentServices = [
(lib.mkIf cfg.vpn.wireguard.enable { service = "wireguard-${vpn_iface}"; inNetns = false; }) (lib.mkIf cfg.vpn.wireguard.enable { service = "wireguard-${vpn_iface}"; inNetns = false; })
@ -703,11 +718,13 @@ in {
}; };
router.networkNamespaces.wan = { router.networkNamespaces.wan = {
# this is the even more boring nftables config # this is the even more boring nftables config
nftables.jsonRules = mkRules { nftables.jsonRules = let
wans = [ "wan" ] ++ lib.optional (cfg.vpn.tunnel.mode == "sit") "sittun0";
in mkRules {
selfIp4 = netAddresses.netnsWan4; selfIp4 = netAddresses.netnsWan4;
selfIp6 = netAddresses.netnsWan6; selfIp6 = netAddresses.netnsWan6;
inherit wans;
lans = [ "veth-wan-b" ]; lans = [ "veth-wan-b" ];
wans = [ "wan" ];
netdevIngressWanRules = with notnft.dsl; with payload; [ netdevIngressWanRules = with notnft.dsl; with payload; [
[(is.eq (fib (f: with f; [ saddr mark iif ]) (f: f.oif)) missing) (log "wan oif missing ") drop] [(is.eq (fib (f: with f; [ saddr mark iif ]) (f: f.oif)) missing) (log "wan oif missing ") drop]
]; ];
@ -718,10 +735,10 @@ in {
rule4 = rule.target4; rule6 = rule.target6; rule4 = rule.target4; rule6 = rule.target6;
in with notnft.dsl; with payload; in with notnft.dsl; with payload;
lib.optionals (rule4 != null) [ lib.optionals (rule4 != null) [
[ (is.eq meta.iifname "wan") (is.eq ip.protocol protocols) (is.eq th.dport rule.port) [ (is.eq meta.iifname (setIfNeeded wans)) (is.eq ip.protocol protocols) (is.eq th.dport rule.port)
(if rule4.port == null then dnat.ip rule4.address else dnat.ip rule4.address rule4.port) ] (if rule4.port == null then dnat.ip rule4.address else dnat.ip rule4.address rule4.port) ]
] ++ lib.optionals (rule6 != null) [ ] ++ lib.optionals (rule6 != null) [
[ (is.eq meta.iifname "wan") (is.eq ip6.nexthdr protocols) (is.eq th.dport rule.port) [ (is.eq meta.iifname (setIfNeeded wans)) (is.eq ip6.nexthdr protocols) (is.eq th.dport rule.port)
(if rule6.port == null then dnat.ip6 rule6.address else dnat.ip6 rule6.address rule6.port) ] (if rule6.port == null then dnat.ip6 rule6.address else dnat.ip6 rule6.address rule6.port) ]
]) ])
(builtins.filter (x: !x.inVpn && (x.tcp || x.udp)) cfg.dnatRules)); (builtins.filter (x: !x.inVpn && (x.tcp || x.udp)) cfg.dnatRules));
@ -734,10 +751,10 @@ in {
rule4 = rule.target4; rule6 = rule.target6; rule4 = rule.target4; rule6 = rule.target6;
in with notnft.dsl; with payload; in with notnft.dsl; with payload;
lib.optionals (rule4 != null) [ lib.optionals (rule4 != null) [
[ (is.eq meta.iifname "wan") (is.eq meta.oifname "veth-wan-b") (is.eq ip.protocol protocols) [ (is.eq meta.iifname (setIfNeeded wans)) (is.eq meta.oifname "veth-wan-b") (is.eq ip.protocol protocols)
(is.eq th.dport (if rule4.port != null then rule4.port else rule.port)) (is.eq ip.daddr rule4.address) masquerade ] (is.eq th.dport (if rule4.port != null then rule4.port else rule.port)) (is.eq ip.daddr rule4.address) masquerade ]
] ++ lib.optionals (rule6 != null) [ ] ++ lib.optionals (rule6 != null) [
[ (is.eq meta.iifname "wan") (is.eq meta.oifname "veth-wan-b") (is.eq ip6.nexthdr protocols) [ (is.eq meta.iifname (setIfNeeded wans)) (is.eq meta.oifname "veth-wan-b") (is.eq ip6.nexthdr protocols)
(is.eq th.dport (if rule6.port != null then rule6.port else rule.port)) (is.eq ip6.daddr rule6.address) masquerade ] (is.eq th.dport (if rule6.port != null then rule6.port else rule.port)) (is.eq ip6.daddr rule6.address) masquerade ]
]) ])
(builtins.filter (x: !x.inVpn && (x.tcp || x.udp) && dnatRuleMode x == "snat") cfg.dnatRules)); (builtins.filter (x: !x.inVpn && (x.tcp || x.udp) && dnatRuleMode x == "snat") cfg.dnatRules));
@ -764,12 +781,13 @@ in {
# vpn socket is in wan namespace, meaning traffic gets sent through the wan namespace # vpn socket is in wan namespace, meaning traffic gets sent through the wan namespace
# vpn interface is in default namespace, meaning it can be used in the default namespace # vpn interface is in default namespace, meaning it can be used in the default namespace
# networking.wireguard.interfaces.${vpn_iface} = cfg.vpn.wireguard.config // { networking.wireguard.interfaces.${vpn_iface} = lib.mkIf cfg.vpn.wireguard.enable
# socketNamespace = "wan"; (cfg.vpn.wireguard.config // {
# interfaceNamespace = "init"; socketNamespace = "wan";
# }; interfaceNamespace = "init";
});
systemd.services.vpn-tunnel = { systemd.services.vpn-tunnel = lib.mkIf (cfg.vpn.tunnel.mode == "ssh") {
description = "VPN Tunnel"; description = "VPN Tunnel";
wantedBy = [ wantedBy = [
"multi-user.target" "multi-user.target"

View file

@ -7,7 +7,18 @@
options.router-settings = { options.router-settings = {
vpn = { vpn = {
tunnel = { tunnel = {
enable = lib.mkEnableOption "VPN tunnel"; mode = lib.mkOption {
description = "tunnel mode";
type = with lib.types; nullOr (enum [ "ssh" "sit" ]);
};
ifaceAddr = lib.mkOption {
description = "interface cidr";
type = router-lib.types.cidr;
};
localIp = lib.mkOption {
description = "local ip";
type = router-lib.types.ip;
};
localPort = lib.mkOption { localPort = lib.mkOption {
description = "local port"; description = "local port";
type = lib.types.port; type = lib.types.port;
@ -18,7 +29,7 @@
}; };
ip = lib.mkOption { ip = lib.mkOption {
description = "remote ip"; description = "remote ip";
type = router-lib.types.ipv4; type = router-lib.types.ip;
}; };
port = lib.mkOption { port = lib.mkOption {
description = "SSH port"; description = "SSH port";