util/linuxfw,wgengine/router: add connmark rules for rp_filter workaround (#18860)
When a Linux system acts as an exit node or subnet router with strict reverse path filtering (rp_filter=1), reply packets may be dropped because they fail the RPF check. Reply packets arrive on the WAN interface but the routing table indicates they should have arrived on the Tailscale interface, causing the kernel to drop them. This adds firewall rules in the mangle table to save outbound packet marks to conntrack and restore them on reply packets before the routing decision. When reply packets have their marks restored, the kernel uses the correct routing table (based on the mark) and the packets pass the rp_filter check. Implementation adds two rules per address family (IPv4/IPv6): - mangle/OUTPUT: Save packet marks to conntrack for NEW connections with non-zero marks in the Tailscale fwmark range (0xff0000) - mangle/PREROUTING: Restore marks from conntrack to packets for ESTABLISHED,RELATED connections before routing decision and rp_filter check The workaround is automatically enabled when UseConnmarkForRPFilter is set in the router configuration, which happens when subnet routes are advertised on Linux systems. Both iptables and nftables implementations are provided, with automatic backend detection. Fixes #3310 Fixes #14409 Fixes #12022 Fixes #15815 Fixes #9612 Signed-off-by: Mike O'Driscoll <mikeo@tailscale.com>
This commit is contained in:
@@ -86,6 +86,7 @@ type linuxRouter struct {
|
||||
localRoutes map[netip.Prefix]bool
|
||||
snatSubnetRoutes bool
|
||||
statefulFiltering bool
|
||||
connmarkEnabled bool // whether connmark rules are currently enabled
|
||||
netfilterMode preftype.NetfilterMode
|
||||
netfilterKind string
|
||||
magicsockPortV4 uint16
|
||||
@@ -370,6 +371,12 @@ func (r *linuxRouter) Close() error {
|
||||
r.unregNetMon()
|
||||
}
|
||||
r.eventClient.Close()
|
||||
|
||||
// Clean up connmark rules
|
||||
if err := r.nfr.DelConnmarkSaveRule(); err != nil {
|
||||
r.logf("warning: failed to delete connmark rules: %v", err)
|
||||
}
|
||||
|
||||
if err := r.downInterface(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -479,6 +486,35 @@ func (r *linuxRouter) Set(cfg *router.Config) error {
|
||||
r.statefulFiltering = cfg.StatefulFiltering
|
||||
r.updateStatefulFilteringWithDockerWarning(cfg)
|
||||
|
||||
// Connmark rules for rp_filter compatibility.
|
||||
// Always enabled when netfilter is ON to handle all rp_filter=1 scenarios
|
||||
// (normal operation, exit nodes, subnet routers, and clients using exit nodes).
|
||||
netfilterOn := cfg.NetfilterMode == netfilterOn
|
||||
switch {
|
||||
case netfilterOn == r.connmarkEnabled:
|
||||
// state already correct, nothing to do.
|
||||
case netfilterOn:
|
||||
r.logf("enabling connmark-based rp_filter workaround")
|
||||
if err := r.nfr.AddConnmarkSaveRule(); err != nil {
|
||||
r.logf("warning: failed to add connmark rules (rp_filter workaround may not work): %v", err)
|
||||
errs = append(errs, fmt.Errorf("enabling connmark rules: %w", err))
|
||||
} else {
|
||||
// Only update state on success to keep it in sync with actual rules
|
||||
r.connmarkEnabled = true
|
||||
}
|
||||
default:
|
||||
r.logf("disabling connmark-based rp_filter workaround")
|
||||
if err := r.nfr.DelConnmarkSaveRule(); err != nil {
|
||||
// Deletion errors are only logged, not returned, because:
|
||||
// 1. Rules may not exist (e.g., first run or after manual deletion)
|
||||
// 2. Failure to delete is less critical than failure to add
|
||||
// 3. We still want to update state to attempt re-add on next enable
|
||||
r.logf("warning: failed to delete connmark rules: %v", err)
|
||||
}
|
||||
// Always clear state when disabling, even if delete failed
|
||||
r.connmarkEnabled = false
|
||||
}
|
||||
|
||||
// Issue 11405: enable IP forwarding on gokrazy.
|
||||
advertisingRoutes := len(cfg.SubnetRoutes) > 0
|
||||
if getDistroFunc() == distro.Gokrazy && advertisingRoutes {
|
||||
|
||||
@@ -124,6 +124,8 @@ v4/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v4/filter/ts-input -i lo -s 100.101.102.104 -j ACCEPT
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.115.92.0/23 -j RETURN
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/nat/POSTROUTING -j ts-postrouting
|
||||
v4/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
v6/filter/FORWARD -j ts-forward
|
||||
@@ -132,6 +134,8 @@ v6/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v6/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v6/filter/ts-forward -o tailscale0 -m conntrack ! --ctstate ESTABLISHED,RELATED -j DROP
|
||||
v6/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v6/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/nat/POSTROUTING -j ts-postrouting
|
||||
v6/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
`,
|
||||
@@ -160,6 +164,8 @@ v4/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v4/filter/ts-input -i lo -s 100.101.102.104 -j ACCEPT
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.115.92.0/23 -j RETURN
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/nat/POSTROUTING -j ts-postrouting
|
||||
v4/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
v6/filter/FORWARD -j ts-forward
|
||||
@@ -167,6 +173,8 @@ v6/filter/INPUT -j ts-input
|
||||
v6/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v6/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v6/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v6/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/nat/POSTROUTING -j ts-postrouting
|
||||
v6/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
`,
|
||||
@@ -192,12 +200,16 @@ v4/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v4/filter/ts-input -i lo -s 100.101.102.104 -j ACCEPT
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.115.92.0/23 -j RETURN
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/nat/POSTROUTING -j ts-postrouting
|
||||
v6/filter/FORWARD -j ts-forward
|
||||
v6/filter/INPUT -j ts-input
|
||||
v6/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v6/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v6/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v6/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/nat/POSTROUTING -j ts-postrouting
|
||||
`,
|
||||
},
|
||||
@@ -225,12 +237,16 @@ v4/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v4/filter/ts-input -i lo -s 100.101.102.104 -j ACCEPT
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.115.92.0/23 -j RETURN
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/nat/POSTROUTING -j ts-postrouting
|
||||
v6/filter/FORWARD -j ts-forward
|
||||
v6/filter/INPUT -j ts-input
|
||||
v6/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v6/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v6/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v6/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/nat/POSTROUTING -j ts-postrouting
|
||||
`,
|
||||
},
|
||||
@@ -255,12 +271,16 @@ v4/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v4/filter/ts-input -i lo -s 100.101.102.104 -j ACCEPT
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.115.92.0/23 -j RETURN
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/nat/POSTROUTING -j ts-postrouting
|
||||
v6/filter/FORWARD -j ts-forward
|
||||
v6/filter/INPUT -j ts-input
|
||||
v6/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v6/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v6/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v6/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/nat/POSTROUTING -j ts-postrouting
|
||||
`,
|
||||
},
|
||||
@@ -310,12 +330,16 @@ v4/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v4/filter/ts-input -i lo -s 100.101.102.104 -j ACCEPT
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.115.92.0/23 -j RETURN
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/nat/POSTROUTING -j ts-postrouting
|
||||
v6/filter/FORWARD -j ts-forward
|
||||
v6/filter/INPUT -j ts-input
|
||||
v6/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v6/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v6/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v6/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/nat/POSTROUTING -j ts-postrouting
|
||||
`,
|
||||
},
|
||||
@@ -342,12 +366,16 @@ v4/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v4/filter/ts-input -i lo -s 100.101.102.104 -j ACCEPT
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.115.92.0/23 -j RETURN
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/nat/POSTROUTING -j ts-postrouting
|
||||
v6/filter/FORWARD -j ts-forward
|
||||
v6/filter/INPUT -j ts-input
|
||||
v6/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v6/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v6/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v6/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/nat/POSTROUTING -j ts-postrouting
|
||||
`,
|
||||
},
|
||||
@@ -367,6 +395,120 @@ ip route add 100.100.100.100/32 dev tailscale0 table 52
|
||||
ip route add throw 10.0.0.0/8 table 52
|
||||
ip route add throw 192.168.0.0/24 table 52` + basic,
|
||||
},
|
||||
{
|
||||
name: "subnet routes with connmark for rp_filter",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32"),
|
||||
SubnetRoutes: mustCIDRs("10.0.0.0/16"),
|
||||
SNATSubnetRoutes: true,
|
||||
NetfilterMode: netfilterOn,
|
||||
},
|
||||
want: `
|
||||
up
|
||||
ip addr add 100.101.102.104/10 dev tailscale0
|
||||
ip route add 100.100.100.100/32 dev tailscale0 table 52` + basic +
|
||||
`v4/filter/FORWARD -j ts-forward
|
||||
v4/filter/INPUT -j ts-input
|
||||
v4/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v4/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v4/filter/ts-forward -o tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v4/filter/ts-input -i lo -s 100.101.102.104 -j ACCEPT
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.115.92.0/23 -j RETURN
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/nat/POSTROUTING -j ts-postrouting
|
||||
v4/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
v6/filter/FORWARD -j ts-forward
|
||||
v6/filter/INPUT -j ts-input
|
||||
v6/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v6/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v6/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v6/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/nat/POSTROUTING -j ts-postrouting
|
||||
v6/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "subnet routes (connmark always enabled)",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32"),
|
||||
SubnetRoutes: mustCIDRs("10.0.0.0/16"),
|
||||
SNATSubnetRoutes: true,
|
||||
NetfilterMode: netfilterOn,
|
||||
},
|
||||
want: `
|
||||
up
|
||||
ip addr add 100.101.102.104/10 dev tailscale0
|
||||
ip route add 100.100.100.100/32 dev tailscale0 table 52` + basic +
|
||||
`v4/filter/FORWARD -j ts-forward
|
||||
v4/filter/INPUT -j ts-input
|
||||
v4/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v4/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v4/filter/ts-forward -o tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v4/filter/ts-input -i lo -s 100.101.102.104 -j ACCEPT
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.115.92.0/23 -j RETURN
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/nat/POSTROUTING -j ts-postrouting
|
||||
v4/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
v6/filter/FORWARD -j ts-forward
|
||||
v6/filter/INPUT -j ts-input
|
||||
v6/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v6/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v6/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v6/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/nat/POSTROUTING -j ts-postrouting
|
||||
v6/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "connmark with stateful filtering",
|
||||
in: &Config{
|
||||
LocalAddrs: mustCIDRs("100.101.102.104/10"),
|
||||
Routes: mustCIDRs("100.100.100.100/32"),
|
||||
SubnetRoutes: mustCIDRs("10.0.0.0/16"),
|
||||
SNATSubnetRoutes: true,
|
||||
StatefulFiltering: true,
|
||||
NetfilterMode: netfilterOn,
|
||||
},
|
||||
want: `
|
||||
up
|
||||
ip addr add 100.101.102.104/10 dev tailscale0
|
||||
ip route add 100.100.100.100/32 dev tailscale0 table 52` + basic +
|
||||
`v4/filter/FORWARD -j ts-forward
|
||||
v4/filter/INPUT -j ts-input
|
||||
v4/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v4/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v4/filter/ts-forward -o tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/filter/ts-forward -o tailscale0 -m conntrack ! --ctstate ESTABLISHED,RELATED -j DROP
|
||||
v4/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v4/filter/ts-input -i lo -s 100.101.102.104 -j ACCEPT
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.115.92.0/23 -j RETURN
|
||||
v4/filter/ts-input ! -i tailscale0 -s 100.64.0.0/10 -j DROP
|
||||
v4/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v4/nat/POSTROUTING -j ts-postrouting
|
||||
v4/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
v6/filter/FORWARD -j ts-forward
|
||||
v6/filter/INPUT -j ts-input
|
||||
v6/filter/ts-forward -i tailscale0 -j MARK --set-mark 0x40000/0xff0000
|
||||
v6/filter/ts-forward -m mark --mark 0x40000/0xff0000 -j ACCEPT
|
||||
v6/filter/ts-forward -o tailscale0 -m conntrack ! --ctstate ESTABLISHED,RELATED -j DROP
|
||||
v6/filter/ts-forward -o tailscale0 -j ACCEPT
|
||||
v6/mangle/OUTPUT -m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/mangle/PREROUTING -m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000
|
||||
v6/nat/POSTROUTING -j ts-postrouting
|
||||
v6/nat/ts-postrouting -m mark --mark 0x40000/0xff0000 -j MASQUERADE
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
bus := eventbus.New()
|
||||
@@ -426,20 +568,24 @@ func newIPTablesRunner(t *testing.T) linuxfw.NetfilterRunner {
|
||||
return &fakeIPTablesRunner{
|
||||
t: t,
|
||||
ipt4: map[string][]string{
|
||||
"filter/INPUT": nil,
|
||||
"filter/OUTPUT": nil,
|
||||
"filter/FORWARD": nil,
|
||||
"nat/PREROUTING": nil,
|
||||
"nat/OUTPUT": nil,
|
||||
"nat/POSTROUTING": nil,
|
||||
"filter/INPUT": nil,
|
||||
"filter/OUTPUT": nil,
|
||||
"filter/FORWARD": nil,
|
||||
"nat/PREROUTING": nil,
|
||||
"nat/OUTPUT": nil,
|
||||
"nat/POSTROUTING": nil,
|
||||
"mangle/PREROUTING": nil,
|
||||
"mangle/OUTPUT": nil,
|
||||
},
|
||||
ipt6: map[string][]string{
|
||||
"filter/INPUT": nil,
|
||||
"filter/OUTPUT": nil,
|
||||
"filter/FORWARD": nil,
|
||||
"nat/PREROUTING": nil,
|
||||
"nat/OUTPUT": nil,
|
||||
"nat/POSTROUTING": nil,
|
||||
"filter/INPUT": nil,
|
||||
"filter/OUTPUT": nil,
|
||||
"filter/FORWARD": nil,
|
||||
"nat/PREROUTING": nil,
|
||||
"nat/OUTPUT": nil,
|
||||
"nat/POSTROUTING": nil,
|
||||
"mangle/PREROUTING": nil,
|
||||
"mangle/OUTPUT": nil,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -775,6 +921,38 @@ func (n *fakeIPTablesRunner) DelMagicsockPortRule(port uint16, network string) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *fakeIPTablesRunner) AddConnmarkSaveRule() error {
|
||||
// PREROUTING rule: restore mark from conntrack
|
||||
prerouteRule := "-m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000"
|
||||
for _, ipt := range []map[string][]string{n.ipt4, n.ipt6} {
|
||||
if err := insertRule(n, ipt, "mangle/PREROUTING", prerouteRule); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// OUTPUT rule: save mark to conntrack for NEW connections
|
||||
outputRule := "-m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000"
|
||||
for _, ipt := range []map[string][]string{n.ipt4, n.ipt6} {
|
||||
if err := insertRule(n, ipt, "mangle/OUTPUT", outputRule); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *fakeIPTablesRunner) DelConnmarkSaveRule() error {
|
||||
prerouteRule := "-m conntrack --ctstate ESTABLISHED,RELATED -j CONNMARK --restore-mark --nfmask 0xff0000 --ctmask 0xff0000"
|
||||
for _, ipt := range []map[string][]string{n.ipt4, n.ipt6} {
|
||||
deleteRule(n, ipt, "mangle/PREROUTING", prerouteRule) // ignore errors
|
||||
}
|
||||
|
||||
outputRule := "-m conntrack --ctstate NEW -m mark ! --mark 0x0/0xff0000 -j CONNMARK --save-mark --nfmask 0xff0000 --ctmask 0xff0000"
|
||||
for _, ipt := range []map[string][]string{n.ipt4, n.ipt6} {
|
||||
deleteRule(n, ipt, "mangle/OUTPUT", outputRule) // ignore errors
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *fakeIPTablesRunner) HasIPV6() bool { return true }
|
||||
func (n *fakeIPTablesRunner) HasIPV6NAT() bool { return true }
|
||||
func (n *fakeIPTablesRunner) HasIPV6Filter() bool { return true }
|
||||
|
||||
Reference in New Issue
Block a user