解决 OpenClash 与 Tailscale/EasyTier 的路由冲突:nftables 规则注入实战 解决 OpenClash 与 Tailscale/EasyTier 的路由冲突:nftables 规则注入实战

解决 OpenClash 与 Tailscale/EasyTier 的路由冲突:nftables 规则注入实战

在 OpenWrt 环境下同时运行 OpenClash 与虚拟组网工具(如 Tailscale, EasyTier)时,经常会遇到一种尴尬的情况:虚拟链路显示已连接(Pinned),但无论如何都无法访问对方的子网资源。

逻辑复盘:为什么路由会“失踪”?

经过对 nftables 链的分析,可以确认问题的核心在于 OpenClash 对防火墙规则(fw4)的重写机制

  1. 全局拦截:OpenClash 为了实现透明代理,会在 inet fw4 中插入优先级极高的拦截规则。
  2. 回程路由死循环:当来自虚拟网卡(如 tun0)的流量尝试访问本地子网时,包的源地址(如 192.168.99.x)可能被 OpenClash 错误拦截并重定向,导致回程路由失效。
  3. 同接口转发(Hairpin)限制:在某些旁路组网场景下,报文需要从同一个接口(如 eth0)进出,但防火墙默认的 Forward 规则往往会丢弃这类未经伪装的流量。

解决方案:在 OpenClash 启动前注入规则

为了确保虚拟组网流量的优先级,我们需要在 OpenClash 的规则生效前,手动将特定的转发与伪装(SNAT)规则注入到 nftables 中。

以下规则建议加入到 OpenClash 的 “开发者选项 -> 防火墙自定义规则” 中:

Terminal window
# 1. 插入新的 Forward 规则,确保在全局拦截之前强制 accept
nft insert rule inet fw4 forward iifname "eth0" oifname "tun0" ip daddr 192.168.99.0/24 counter accept
nft 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 insert vs nft add: 在该场景下,必须优先使用 insert 将规则插入到链的首位。因为 add 是追加到尾部,在 OpenClash 的全局规则生效后,尾部规则将永远无法被匹配到。
  • SNAT (Masquerade): 通过伪装源地址,我们将原本可能跨网段的复杂路由查找,简化为了二层网络内的点对点通信,有效终结了因网段重叠或路由指向错误导致的死循环。
  • Tailscale 段 (100.64.0.0/10): 显式放行该段流量,是为了防止 OpenClash 的 DNS 解析或 TProxy 逻辑介入虚拟私有链路。

折腾虚拟组网,本质上就是在一层层剥离防火墙的“防守意识”。保持理性的规则优先级,是多网互联稳定的基石。

祝折腾愉快!


← Back to blog