auto_redirect: the mark rule overwrites marks set by other programs, such as Tailscale
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 70/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- go
- Domain
- networking
Research direction
Read redirect_nftables_rules.go at nftablesCreateMark and inspect the output_prematch, output, and output_udp_icmp chains, especially where meta mark is written. Reproduce the Linux setup with auto_redirect and Tailscale, then verify that existing policy-routing marks survive sing-box rules. Done means Tailscale peer traffic uses its direct path while sing-box traffic remains redirected.
Written by the indexing model from the issue text.
Description
With auto_redirect on Linux, nftablesCreateMark replaces the whole packet mark. A mark that another program set for its own policy routing is lost. Tailscale is one case: its peer traffic goes into the TUN, and two Tailscale nodes connect through the proxy instead of directly.
Where
nftablesCreateMark (redirect_nftables_rules.go#L729) loads AutoRedirectInputMark with Immediate and writes it to meta mark with no mask. In output_udp_icmp this is the last rule:
meta mark set 0x00002023 ct mark set meta mark counter return
tailscaled marks its sockets with 0x80000 (mask 0xff0000) and adds ip rule entries that send this mark to the main table, before other policy routes. After the rule above, the packet carries 0x2023 only. It does not match the Tailscale rule and goes to the TUN table. TCP to DERP takes the same route through the output chain.
The tailnet ranges are not the problem. route_exclude_address keeps 100.64.0.0/10 out. The traffic that is lost is WireGuard UDP to the peers' public addresses.
Reproduction
sing-box 1.14.1, Linux, a TUN inbound with auto_route, auto_redirect, and route_exclude_address for the tailnet ranges; tailscaled running on the same host and on a second host.
- With sing-box running,
tailscale ping <peer>answersvia <the proxy server's address>with the proxy's round trip: 225 ms in my case - Insert the rules under "Workaround" below.
tailscale ping <peer>now answersvia <the peer's own address>: 11 ms
Expected
A mark that is already on the packet stays, or the rule returns for it. Two possible forms:
- return before the mark rule when
meta mark & 0xffff0000 != 0, so that the TUN does not take traffic another program routes on its own - set only the bits sing-box owns:
meta mark set meta mark & 0xffff0000 | 0x2023
Workaround
nft insert rule inet sing-box output_prematch meta mark & 0x00ff0000 == 0x00080000 return
nft insert rule inet sing-box output meta mark & 0x00ff0000 == 0x00080000 return
nft insert rule inet sing-box output_udp_icmp meta mark & 0x00ff0000 == 0x00080000 return
after sing-box creates the table. With these rules, and ct direction reply return from #95, tailscale ping showed the direct path again. I did not test the mark rules without the reply rule.
- Dominant language
- Go
- Stars
- 241
- Forks
- 243
- PR merge metrics
- No merged PRs in 30d
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from SagerNet/sing-tun
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
gvisor: LinkEndpointFilter.Attach never forwards nil, so GVisor.Close leaks all inbound dispatcher goroutines and fdsPossibly taken @arpitjain099 claimed this 54 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
Darwin: utun process UUID headers are parsed as IP payloadPossibly taken @d3pre5s claimed this 8 days ago. Open
Difficulty 4/5 3-5 days Newbie friendliness 25/100
-
Difficulty 3/5 1-2 days Newbie friendliness 68/100
-
TUN `mixed` stack: TCP never re-injected into tun0 on Linux kernel 7.1 (UDP works, `gvisor` works)Open
Difficulty 4/5 1-2 days Newbie friendliness 45/100
All issues in SagerNet/sing-tun
Similar issues
-
enhancement runtime:claude
Difficulty 2/5 1-3 hours Newbie friendliness 79/100
FootprintAI/Containarium#3214 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
eugenioenko/ttt#1251 ·
Maintainers usually reply within 1 day
-
`compute.Service` client getters never cache their clientPossibly taken @jay23606 claimed this today. Openkind/bug
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
kubernetes-sigs/cluster-api-provider-openstack#3441 ·
Maintainers usually reply within 1 day