一次“电脑能上网,路由器却断网”的折腾:OpenClash 与 Tailscale 撞到了一起
本文最后更新于 2026年10月6日 晚上
背景
最近折腾家里的网络,遇到了一个挺别扭的问题。
电脑访问正常,NAS 也正常。偏偏负责转发这些流量的路由器,自己连不上外面。
在线更新检查失败,终端里发起请求一直超时,Tailscale 也在反复报控制服务器连接失败。
它能帮别人把数据送出去,轮到自己就不行。
更让人怀疑人生的是:停掉 OpenClash,马上恢复;重新开启,又开始超时。
当时很自然地把目光放在了 OpenClash 上。是不是核心有问题?是不是本机代理规则写错了?是不是定制版本改坏了什么?
查到最后才发现,锅不能这么简单地扣过去。
这次真正撞到一起的,是三个东西:
运营商分配的 CGNAT 地址、OpenClash 的本机 TCP 重定向,以及 Tailscale 的来源防伪规则。
下面记录一下这次排查过程。设备名称、实际地址和配置信息均已脱敏。
一、最烦的地方:每个现象单独看,都像另一个问题
家里的结构并不复杂:
| 设备 | 用途 |
|---|---|
| OpenWrt 系路由器 | 默认网关,运行 OpenClash |
| 路由器上的 Tailscale | 提供远程访问家庭网段的入口 |
| 常开的 Unraid NAS | 文件服务及其他应用 |
| 电脑、手机等 | 普通局域网客户端 |
故障发生时,局域网设备访问正常,但路由器本机的多个 TCP 请求都超时。
这就很容易往几个方向想:
- 更新源是不是临时不可用?
- DNS 返回的地址是不是有问题?
- Tailscale 是不是连接不稳定?
- 代理节点是不是异常?
- 刚调整过的网络设置是不是留下了什么影响?
麻烦在于,这些猜测都有一点道理。
但有一条证据把范围压了下来:
同一个裸 IP 请求,OpenClash 开启时超时,关闭后立即成功。
目标没有变,也没有经过域名解析。
所以先把 DNS 放到一边。至于目标服务本身不可用,也解释不了这个开关对照。
不过,这时候只能说:
OpenClash 开启后,某条数据包路径出了问题。
还不能直接说核心坏了。
现在回头看,这个区别很重要。要是在这里就开始反复换核心、重装插件,很可能忙了一圈,问题还在。
二、先查规则,两个“看起来很像”的疑点被排除了
第一个疑点是进程身份。
进程列表显示 Clash 以 root 运行,而防回环规则匹配的是:
1 | |
乍一看,很像核心自己的出站连接没有被豁免,又被抓回代理里,绕成了一个圈。
但读取进程状态后,实际情况是:
1 | |
这里被进程列表误导了。
root 是用户身份,65534 是组身份,它们可以同时存在。防火墙按 socket 的组匹配,并不要求用户名也变成别的。
这个方向先划掉。
第二个疑点是本机 TCP 处理链。
当时看到 UDP 有打标规则,TCP 却没有,第一感觉是漏了什么。继续查才确认,当前模式下两者本来就走不同路径:
1 | |
本机 TCP 链完整存在,目标端口也有 Clash 监听。发起测试后,重定向规则计数还增加了。
也就是说:
请求确实被接管了,端口也确实在监听,但连接就是建不起来。
查到这里,问题开始有点意思了。
三、一个很有用的对照:显式代理居然成功了
接着让路由器访问同一个裸 IP 目标,分别走两种方式:
| 方式 | 结果 |
|---|---|
| 普通请求,由透明代理接管 | TCP 建连超时 |
| 显式连接本机 HTTP 代理 | HTTP 200 |
这组结果比“停服务后恢复”更有价值。
同一个核心,能够处理显式代理请求,说明至少这条目标请求的处理和出站能力是正常的。
故障范围进一步缩小到了:
普通本机请求,被透明重定向之后,到底发生了什么?
此时继续盯着更新源或者远端服务器,意义已经不大了。因为失败发生在 TCP 建连阶段,连后面的 TLS 和 HTTP 都还没轮到。
该抓包了。
四、真正的转折:SYN 已经回到本机,却没人回应
短时抓包里出现了一批重复的 SYN。
脱敏后,数据包大致长这样:
1 | |
没有看到 SYN-ACK。
这里最关键的不是端口,而是源地址。
路由器准备访问外部目标时,先选用了 WAN 地址作为来源。随后 OpenClash 把目标改成本机代理端口,但原先的源地址仍然保留着。
于是,一个“路由器自己访问外面”的请求,变成了:
1 | |
这条路径本身并不必然有问题。
但它会经过本机的入站检查。
而家里的路由器上,除了 OpenWrt 的防火墙,还有 Tailscale 安装的规则。
五、终于找到:Tailscale 把这个请求当成了可疑来源
继续读取完整规则集,发现 INPUT 会进入 Tailscale 的 ts-input 链。
里面有一条规则,意思很直接:
1 | |
问题来了。
100.64.0.0/10 是 CGNAT 地址范围,运营商会使用,Tailscale 也使用。
路由器的 WAN 地址,恰好就在这个范围里面。
重定向之后,请求又是从 lo 进入的,当然不是 tailscale0。
两个条件都满足,直接丢弃。
代理端口虽然开着,但 SYN 在到达监听 socket 之前就被挡住了。
这也解释了为什么之前看 OpenWrt 的 fw4,明明有回环放行和 DNAT 放行,还是不通。
因为规则不只存在于 fw4 里。一个基础链放行之后,另一个基础链仍然可以把包丢掉。
Tailscale 官方也有专门的 CGNAT 兼容说明:这种地址重叠下,来源防伪规则可能同时挡住合法流量。
到这里,前面那些零散的现象终于能接起来了。
六、只换一个源地址,结果就变了
为了再确认一次,没有修改防火墙,而是让同一个请求临时绑定路由器的 LAN 地址。
其余条件保持一致。
结果:
| 请求来源 | 结果 |
|---|---|
| 绑定 LAN 地址 | 很快返回 HTTP 200 |
| 使用默认 WAN 地址 | 等待数秒后建连超时 |
这一下就很清楚了。
核心没换,目标没换,透明代理还在。仅仅改变来源地址,结果就从超时变成成功。
再回头看,之前觉得矛盾的地方,其实都说得通:
为什么电脑正常?
电脑的来源是局域网地址,不属于 100.64.0.0/10,不会命中这条规则。
为什么显式代理正常?
显式连接本机代理时,使用的是回环来源,同样不命中。
为什么关掉 OpenClash 就恢复?
请求不再被转送回本机,也就不会经过这条发生冲突的入站路径。
为什么 Tailscale 自己也连不上控制服务器?
它发起的本机 TCP 请求,也可能被透明代理接管,再被它自己的防火墙规则拦住。
这个结果多少有点绕:原本用来保护连接的规则,碰上另一套流量处理机制,最后把自己的连接也挡了。
七、最后怎么处理:把远程入口交给 NAS
找到原因之后,其实可以加一个精确例外。
只允许本机经回环接口访问透明代理端口,并让这类流量避开 Tailscale 的来源丢弃规则。
但临时加一条规则,和以后一直稳定,是两回事。
后面还得考虑:
- Tailscale 重启会不会重建规则?
- 防火墙重载后,例外还在不在?
- WAN 重拨换地址怎么办?
- 代理端口变化后,规则会不会失效?
- 开机时两个服务的启动顺序有没有影响?
能解决,不过家里已经有一台常开的 Unraid NAS,也运行着 Tailscale。
所以最后选择把远程访问家庭网段的入口迁到 NAS:
1 | |
主路由器继续负责默认网关和 OpenClash。
操作顺序也没有直接“一关了之”:
- NAS 通告家庭网段。
- 在 Tailscale 后台批准路由。
- 从外部网络验证能访问其他家庭设备。
- 确认正常后,再停用路由器上的 Tailscale。
- 检查路由器上的相关规则是否清理。
这里验证的重点,是能访问其他局域网设备。只打开 NAS 自己的页面,不能证明子网转发已经正常。
切换之后,使用恢复正常。
代价也很明确:NAS 要保持在线。它关机,远程回家的入口也就暂时没了。对一台原本就常开的设备来说,这个取舍可以接受。
八、这次折腾留下的几个提醒
最开始,确实觉得这像是 OpenClash 的问题。
毕竟开着就坏,关了就好,证据看起来已经很充分。
但沿着连接路径继续查,才发现它只是让数据包走到了另一条规则面前。真正发生冲突的,是源地址、重定向和来源检查组合起来后的行为。
以后再遇到类似情况,可以优先做这几件事:
- 裸 IP 与域名请求分开测。
- 显式代理与透明代理分开测。
- 看清楚失败是在 TCP、TLS,还是 HTTP 阶段。
- 检查所有相关防火墙表,而不只看系统默认那一张。
- 服务共存时,把“它们之间的交互”也列入排查范围。
还有一点:
电脑能上网,只能证明电脑那条路径正常。
路由器自己的请求从 OUTPUT 出发,客户端流量则从 PREROUTING 进入。看起来都经过同一台设备,实际走的规则可以差很多。
这次折腾完,至少下次再看到“电脑正常,路由器超时”,不会先急着换核心了。
先看包从哪里来、被送到哪里,又在哪条规则前停下。
比对着“连接超时”四个字猜来猜去,有用得多。