From 0452b1d52091beffde0e1404e245d8f4ec42244b Mon Sep 17 00:00:00 2001 From: Oliver Ford Date: Sun, 4 Jan 2026 19:36:53 +0000 Subject: [PATCH] util/linuxfw: fix only implicitly accepted forward pkts This rule appears intended to `ACCEPT` the packets `MARK`ed in the rule immediately prior; for that to work though the `MARK` rule would need to be in the `mangle` table, as it's here in the `filter` table it doesn't match, the chain continues, and the packets happen to be accepted once they fall-through and hit (rely on) the `FORWARD` table's default `ACCEPT` policy. This commit changes the `ACCEPT` rule to explicitly match the same as `MARK`ed above, so as not to rely on this implicit behaviour (and have a misleading no-op rule). Note also - I have not found it documented - that for devices behind the subnet router to be able to reach the tailnet (as opposed to vice versa), there will need to be an additional rule added by the user, such as: -t mangle -A FORWARD -s 192.168.88.0/24 -i veth-tailscale -o tailscale0 -j MARK --set-xmark 0x40000/0xff0000 where `192.168.88.0/24` is the subnet behind the subnet router (that should be able to access the tailnet; not necessarily equivalent to the advertised routes) and `veth-tailscale` is the LAN interface - or else to ensure that these packets are equivalently accepted and masqueraded as if marked. A better fix (it would preserve the ability to handle LAN-initiated routing with a single `MARK` rule as above) might be to instead move the `MARK` rule to a (new) `ts-forward` chain in the `mangle` table, so that it can be matched here with the existing rule. Signed-off-by: Oliver Ford --- util/linuxfw/iptables_runner.go | 4 ++-- util/linuxfw/iptables_runner_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/util/linuxfw/iptables_runner.go b/util/linuxfw/iptables_runner.go index 4443a9071..d936cd8b5 100644 --- a/util/linuxfw/iptables_runner.go +++ b/util/linuxfw/iptables_runner.go @@ -250,7 +250,7 @@ func (i *iptablesRunner) addBase4(tunname string) error { if err := i.ipt4.Append("filter", "ts-forward", args...); err != nil { return fmt.Errorf("adding %v in v4/filter/ts-forward: %w", args, err) } - args = []string{"-m", "mark", "--mark", subnetRouteMark + "/" + fwmarkMask, "-j", "ACCEPT"} + args = []string{"-i", tunname, "-j", "ACCEPT"} if err := i.ipt4.Append("filter", "ts-forward", args...); err != nil { return fmt.Errorf("adding %v in v4/filter/ts-forward: %w", args, err) } @@ -356,7 +356,7 @@ func (i *iptablesRunner) addBase6(tunname string) error { if err := i.ipt6.Append("filter", "ts-forward", args...); err != nil { return fmt.Errorf("adding %v in v6/filter/ts-forward: %w", args, err) } - args = []string{"-m", "mark", "--mark", subnetRouteMark + "/" + fwmarkMask, "-j", "ACCEPT"} + args = []string{"-i", tunname, "-j", "ACCEPT"} if err := i.ipt6.Append("filter", "ts-forward", args...); err != nil { return fmt.Errorf("adding %v in v6/filter/ts-forward: %w", args, err) } diff --git a/util/linuxfw/iptables_runner_test.go b/util/linuxfw/iptables_runner_test.go index ce905aef3..4907630fe 100644 --- a/util/linuxfw/iptables_runner_test.go +++ b/util/linuxfw/iptables_runner_test.go @@ -134,7 +134,7 @@ func TestAddAndDeleteBase(t *testing.T) { tsRulesCommon := []fakeRule{ // table/chain/rule {"filter", "ts-input", []string{"-i", tunname, "-j", "ACCEPT"}}, {"filter", "ts-forward", []string{"-i", tunname, "-j", "MARK", "--set-mark", tsconst.LinuxSubnetRouteMark + "/" + tsconst.LinuxFwmarkMask}}, - {"filter", "ts-forward", []string{"-m", "mark", "--mark", tsconst.LinuxSubnetRouteMark + "/" + tsconst.LinuxFwmarkMask, "-j", "ACCEPT"}}, + {"filter", "ts-forward", []string{"-i", tunname, "-j", "ACCEPT"}}, {"filter", "ts-forward", []string{"-o", tunname, "-j", "ACCEPT"}}, }