dep0rt 报告 sing-tun 在 OpenWrt 源特定 IPv6 路由下的旁路超时

dep0rt 在 sing-tun #99 中报告,OpenWrt 使用源特定 IPv6 默认路由时,IPv4 bypass 与 direct 正常,但 IPv6 bypass 超时。他将原因归于 mark 模式的 fallback 规则:首次路由查找命中 TUN 默认路由并选用 TUN 的 ULA 源地址,随后打旁路标记重查主路由表时,该地址无法匹配带来源前缀的 IPv6 默认路由。他建议为两个地址族的 fallback 规则增加 SuppressPrefixlen = 0,并称当前可在 OpenWrt 取消勾选「IPv6 源路由」作为解决办法。

作者原文

IPv4 bypass 正常,v6 bypass 超时, 命中后由内核转发但路径不通、IPv4 正常、direct 正常(OpenWrt 源特定 IPv6 路由 + table 2022 的默认路由被当成直连路径)
根因
auto_redirect 的预匹配 bypass 是在 nftables/NFQUEUE 里给包打 fwmark 0x2024 后交给内核转发(nfqueue_linux.go 里 ActionBypass -> NfRepeat + outputMark)。而 IPv6 包在走到这一步之前,路由其实已经选过一次了:
本机进程 connect()/ping 时的第一次路由查找,sk_mark 还是 0;tun_linux.go 里 mark 模式的 fallback 规则是: 32768: not fwmark 0x2024 lookup 2022(tun_linux.go 中 IPRoute2AutoRedirectFallbackRuleIndex 那段);
这条规则没有 suppress_prefixlength,于是 table 2022 里的 ::/0 -> <tun> 默认路由会直接命中,连接被绑到 TUN 的 fdfe:dcba:9876::1 上,甚至先把包送进 TUN。随后预匹配命中 bypass、打上 0x2024,策略路由重查时:9000: fwmark 0x2024 goto 9002(nop)→ 跳过 2022 → 落到 main;
如果 main 里的 IPv6 默认路由是 OpenWrt sourcefilter/DHCPv6-PD 那种 带源前缀的 from <prefix> 路由,此时源地址已经是 TUN 的 ULA,匹配不上任何 from 路由 → 无路由 → 包被丢弃;
IPv4 因为 main 有普通 default,所以正常;direct 正常是因为 sing-box 的 socket 在 connect() 前就 SO_MARK=0x2024,第一次查找就走 main 并选对了源地址。
修复
在 tun_linux.go 的 mark 模式 fallback 规则(32768,两个地址族)上增加 go it.SuppressPrefixlen = 0

目前解决办法是在op上取消勾选 IPv6 源路由