Tailscale 非对称路由导致 LAN 设备无法访问同网段 Tailscale 节点
前置问题
本文是 Tailscale 子网路由劫持本地流量排查与修复 的后续。解决了路由劫持之后,又发现了一个新问题。
发生了什么
Windows 关闭 Tailscale 后(纯 LAN 设备),ping 其他 Tailscale 节点:
tracert 显示: 第一跳到 192.168.1.3(iStoreOS),第二跳就超时——说明请求到了,回复丢了。
为什么偏偏是 dbroot?
因为 dbroot 和 Windows 在同一个物理局域网里。
| |
回复从 tailscale0 进来,却从 LAN 口出去——Linux 内核的 rp_filter(反向路径过滤) 认为这不正常,直接丢包。
为什么开启 Tailscale 就没问题
开启 Tailscale 后,Windows 的源 IP 从 192.168.1.10 变成了 100.80.0.6:
源 IP 不同,回复路径不同,就这么简单。
为什么 ZeroTier 没这问题
ZeroTier 是二层虚拟交换机,所有设备共享一个虚拟网段。同网段通信直接走虚拟交换机,不经过网关,没有非对称路径。Tailscale 是三层的,每个节点独立路由,旁路由转发时就埋下了非对称的坑。
怎么修
方案一:在 iStoreOS 上做 SNAT(已实施)
思路: 让 LAN 发往 Tailscale 的流量在 iStoreOS 上转换源地址,对外伪装成 100.80.0.1。这样回复路径永远对称,rp_filter 不触发。
实施:
在 iStoreOS 上创建 nftables 规则文件 /usr/share/nftables.d/chain-post/srcnat/30-tailscale-masq.nft:
| |
重启防火墙生效:
| |
验证:
方案二:在 dbroot 上关闭 rp_filter
思路: 直接告诉内核不要检查 tailscale0 接口的反向路径。
持久化:
两个方案对比
| 方案一:iStoreOS SNAT | 方案二:关 rp_filter | |
|---|---|---|
| 配置位置 | 只在 iStoreOS 上一处 | 每台同局域网的 Tailscale 节点都要配 |
| 新增节点 | 自动生效 | 新节点需要手动配 |
| 安全性 | 不降低内核安全策略 | 关闭了反向路径检查,降低了安全性 |
| 源 IP 可见性 | 远程节点看到的是 100.80.0.1(iStoreOS) | 远程节点能看到真实源 IP |
| 适用场景 | 不需要区分 LAN 内具体设备 | 需要区分来源(比如日志审计) |
| 维护成本 | 低,一次配完 | 中,每台都要配 |
为什么选了方案一:
这个网络里 LAN 设备访问 Tailscale 节点时,不需要区分"请求来自哪台设备"。就算需要区分,LAN 设备也可以直接通过 Tailscale 客户端用 100.80.0.x 身份访问,那时的源 IP 就是真实的。方案一一次配置解决所有问题,更省心。
为什么不两全其美
两个方案本质上是冲突的——做了 SNAT 就不需要关 rp_filter,关了 rp_filter 就不需要 SNAT。如果两个都做,反而多了一层 NAT 的性能开销,且没有额外收益。
最终效果
修完之后,整个网络的访问逻辑:
知识点
- rp_filter: Linux 内核的安全机制,检查包的入接口和路由表决定的出接口是否一致,不一致就丢
- 非对称路由: 请求和回复走不同路径,在网络拓扑复杂(旁路由 + VPN + 同网段)时容易触发
- SNAT/MASQUERADE: 不仅能解决"外网访问内网"的问题,也能解决"非对称路由"的问题——本质上都是让回复路径和请求路径一致