shinobu/router: Fix VPN bypass

This now actually works and I have a better understanding of nftables.
Some of my learnings are documented as comments in the rules.
This commit is contained in:
Simon Bruder 2023-09-21 12:56:36 +02:00
parent caac620ea6
commit 9c42cb0903
Signed by: simon
GPG key ID: 8D3C82F9F309F8EC

View file

@ -29,7 +29,7 @@
let let
domain = "home.sbruder.de"; domain = "home.sbruder.de";
noVpnFwMark = 10000; vpnBypassFwMark = 10000;
in in
{ {
sops.secrets.wg-upstream-private-key = { sops.secrets.wg-upstream-private-key = {
@ -61,6 +61,7 @@ in
define VUEKO_PORT = 51820 define VUEKO_PORT = 51820
define WG_UPSTREAM_ENDPOINT = ${lib.elemAt (lib.splitString ":" (lib.elemAt config.systemd.network.netdevs.wg-upstream.wireguardPeers 0).wireguardPeerConfig.Endpoint) 0} define WG_UPSTREAM_ENDPOINT = ${lib.elemAt (lib.splitString ":" (lib.elemAt config.systemd.network.netdevs.wg-upstream.wireguardPeers 0).wireguardPeerConfig.Endpoint) 0}
define PLASTIC_ROUTER_V4 = 192.168.0.1 define PLASTIC_ROUTER_V4 = 192.168.0.1
define VPN_BYPASS_MARK = ${toString vpnBypassFwMark}
table inet filter { table inet filter {
chain forward { chain forward {
@ -75,14 +76,16 @@ in
iifname $NAT_LAN_IFACES oifname $NAT_WAN_IFACES counter accept iifname $NAT_LAN_IFACES oifname $NAT_WAN_IFACES counter accept
iifname $NAT_WAN_IFACES oifname $NAT_LAN_IFACES ct state established,related counter accept iifname $NAT_WAN_IFACES oifname $NAT_LAN_IFACES ct state established,related counter accept
# accept responses on physical wan
iifname $PHYSICAL_WAN oifname $NAT_LAN_IFACES ct state established,related counter accept
# allow selected destinations via physical wan
# plastic router # plastic router
iifname $NAT_LAN_IFACES oifname $PHYSICAL_WAN ip daddr $PLASTIC_ROUTER_V4 counter accept iifname $NAT_LAN_IFACES oifname $PHYSICAL_WAN ip daddr $PLASTIC_ROUTER_V4 counter accept
iifname $PHYSICAL_WAN oifname $NAT_LAN_IFACES ip saddr $PLASTIC_ROUTER_V4 ct state established,related counter accept
iifname $NAT_LAN_IFACES oifname $PHYSICAL_WAN ip daddr $VUEKO_V4 udp dport $VUEKO_PORT counter accept # all destinations configured via policy based routing
iifname $PHYSICAL_WAN oifname $NAT_LAN_IFACES ip saddr $VUEKO_V4 udp sport $VUEKO_PORT ct state established,related counter accept oifname $PHYSICAL_WAN mark $VPN_BYPASS_MARK counter accept
iifname $NAT_LAN_IFACES oifname $PHYSICAL_WAN ip6 daddr $VUEKO_V6 udp dport $VUEKO_PORT counter accept
iifname $PHYSICAL_WAN oifname $NAT_LAN_IFACES ip6 saddr $VUEKO_V6 udp sport $VUEKO_PORT ct state established,related counter accept
} }
} }
@ -97,13 +100,28 @@ in
} }
} }
table inet mangle { # Bypass VPN by setting mark.
# This acts in two places that are handled separatly by nftables:
# Packets from the local host (output hook) and forwared packets (prerouting hook).
# To simplify the handling,
# there is a single chain that handles both,
# which is jumped to from the specific chains.
table inet vpn-bypass {
# This must be of type route, otherwise no route lookup will be performed
chain output { chain output {
type route hook output priority mangle type route hook output priority mangle
jump common
}
# Add fwmark noVpnMark to packets to vueko, so it will get routed correctly # This does not need to be of type route
ip daddr $VUEKO_V4 udp dport $VUEKO_PORT mark set ${toString noVpnFwMark} counter chain prerouting {
ip6 daddr $VUEKO_V6 udp dport $VUEKO_PORT mark set ${toString noVpnFwMark} counter type filter hook prerouting priority mangle
jump common
}
chain common {
ip daddr $VUEKO_V4 udp dport $VUEKO_PORT mark set $VPN_BYPASS_MARK counter
ip6 daddr $VUEKO_V6 udp dport $VUEKO_PORT mark set $VPN_BYPASS_MARK counter
} }
} }
@ -112,27 +130,35 @@ in
table inet restrict-wan { table inet restrict-wan {
# Priorities must be higher than filter (0), # Priorities must be higher than filter (0),
# which the NixOS firewall uses. # which the NixOS firewall uses.
chain input { chain input {
type filter hook input priority -50; policy accept type filter hook input priority -50; policy accept
# accept responses # accept responses
iifname $PHYSICAL_WAN ct state established,related counter accept iifname $PHYSICAL_WAN ct state established,related counter accept
# accept icmpv6 # accept icmpv6
iifname $PHYSICAL_WAN icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept iifname $PHYSICAL_WAN icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
# drop everything else # drop everything else
iifname $PHYSICAL_WAN counter drop iifname $PHYSICAL_WAN counter drop
} }
chain output { # This handles all packets (local and forwarded)
type filter hook output priority -50; policy accept chain postrouting {
type filter hook postrouting priority 0; policy accept
# accept connections to plastic router # accept connections to plastic router
oifname $PHYSICAL_WAN ip daddr $PLASTIC_ROUTER_V4 accept oifname $PHYSICAL_WAN ip daddr $PLASTIC_ROUTER_V4 counter accept
# accept icmpv6 # accept icmpv6
oifname $PHYSICAL_WAN icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept oifname $PHYSICAL_WAN icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
# accept connections to selected endpoints # accept connections to selected endpoints
oifname $PHYSICAL_WAN ip daddr $WG_UPSTREAM_ENDPOINT counter accept # VPN (wg-upstream)
oifname $PHYSICAL_WAN ip daddr $VUEKO_V4 counter accept oifname $PHYSICAL_WAN ip daddr $WG_UPSTREAM_ENDPOINT counter accept # only this is used
oifname $PHYSICAL_WAN ip6 daddr $VUEKO_V6 counter accept # destinations configured in VPN bypass
oifname $PHYSICAL_WAN mark $VPN_BYPASS_MARK counter accept
# drop all other packets # drop all other packets
oifname $PHYSICAL_WAN counter drop oifname $PHYSICAL_WAN counter drop
} }
@ -260,12 +286,11 @@ in
Priority = 9; Priority = 9;
}; };
} }
# vueko (v4) for wg-home # VPN bypass
{ {
routingPolicyRuleConfig = { routingPolicyRuleConfig = {
To = "168.119.176.53"; Family = "both"; # welcome in the year 2023, where ipv4 is the default
FirewallMark = vpnBypassFwMark;
FirewallMark = noVpnFwMark;
Priority = 9; Priority = 9;
}; };
} }