解决 OpenClash 与 Tailscale/EasyTier 的路由冲突:nftables 规则注入实战
10/3/2025 / 2 minutes to read / Tags: network, technical
在 OpenWrt 环境下同时运行 OpenClash 与虚拟组网工具(如 Tailscale, EasyTier)时,经常会遇到一种尴尬的情况:虚拟链路显示已连接(Pinned),但无论如何都无法访问对方的子网资源。
逻辑复盘:为什么路由会“失踪”?
经过对 nftables 链的分析,可以确认问题的核心在于 OpenClash 对防火墙规则(fw4)的重写机制:
- 全局拦截:OpenClash 为了实现透明代理,会在
inet fw4中插入优先级极高的拦截规则。 - 回程路由死循环:当来自虚拟网卡(如
tun0)的流量尝试访问本地子网时,包的源地址(如 192.168.99.x)可能被 OpenClash 错误拦截并重定向,导致回程路由失效。 - 同接口转发(Hairpin)限制:在某些旁路组网场景下,报文需要从同一个接口(如
eth0)进出,但防火墙默认的 Forward 规则往往会丢弃这类未经伪装的流量。
解决方案:在 OpenClash 启动前注入规则
为了确保虚拟组网流量的优先级,我们需要在 OpenClash 的规则生效前,手动将特定的转发与伪装(SNAT)规则注入到 nftables 中。
以下规则建议加入到 OpenClash 的 “开发者选项 -> 防火墙自定义规则” 中:
# 1. 插入新的 Forward 规则,确保在全局拦截之前强制 acceptnft insert rule inet fw4 forward iifname "eth0" oifname "tun0" ip daddr 192.168.99.0/24 counter acceptnft insert rule inet fw4 forward iifname "tun0" oifname "eth0" ip saddr 192.168.99.0/24 counter accept
# 2. 物理封口:针对虚拟网段开启伪装,解决移动设备回程路由问题nft add rule inet fw4 srcnat oifname "tun0" ip saddr 192.168.99.0/24 counter masquerade
# 3. 允许 eth0 同接口转发 (Hairpin NAT)# 确保包从 [PC -> eth0 -> 路由器 -> eth0 -> 目标设备] 的路径不被丢弃nft insert rule inet fw4 forward iifname "eth0" oifname "eth0" ip daddr 100.64.0.0/10 counter accept comment "Allow Hairpin for Tailscale on eth0"
# 4. 终结路由循环:开启目标 SNAT (伪装)# 核心逻辑:强制让目标设备认为请求来自主路由,从而规避复杂的子网回程路由查找nft add rule inet fw4 srcnat oifname "eth0" ip daddr 192.168.1.7 counter masquerade comment "Prevent Routing Loop via SNAT"
# 5. 放行虚拟网段流量,绕过 OpenClash 拦截nft insert rule inet fw4 forward ip daddr 100.64.0.0/10 counter accept技术细节解析
nft insertvsnft add: 在该场景下,必须优先使用insert将规则插入到链的首位。因为add是追加到尾部,在 OpenClash 的全局规则生效后,尾部规则将永远无法被匹配到。- SNAT (Masquerade): 通过伪装源地址,我们将原本可能跨网段的复杂路由查找,简化为了二层网络内的点对点通信,有效终结了因网段重叠或路由指向错误导致的死循环。
- Tailscale 段 (100.64.0.0/10): 显式放行该段流量,是为了防止 OpenClash 的 DNS 解析或 TProxy 逻辑介入虚拟私有链路。
折腾虚拟组网,本质上就是在一层层剥离防火墙的“防守意识”。保持理性的规则优先级,是多网互联稳定的基石。
祝折腾愉快!
← Back to blog