起因

在我部署完自己的 Headscale 之后,有个朋友和我说 Tailscale 这玩意路由配置有点坑,有个朋友就是因为这个问题而放弃了 Tailscale 选择了 Netbrid,问题就是会强制路由 100.64.0.0/10 网段到 Tailscale,即使使用 Headscale 分配其他网段也是一样会吃

复现

由于这个问题不是我发现的,但是由于我自己用的就是 Tailscale,并且这个网段也的确很有可能后面会在内网用到,尤其是运营商,所以还是选择去尝试解决一下

要复现其实很简单,PING 100.64.0.0/10 网段内的任一 IP 即可,由于我本地没有用到这个网段,所以想了一下,可以通过 PING 阿里云的内网DNS(100.100.2.148 - mirrors.cloud.aliyuncs.com)来测试

的确 PING 不通

(刚好用带学生300优惠券用36R白嫖了一台阿里云HK轻量一年)

排查

由于朋友他们已经抓过包确定排除掉了很多问题,并且确定就是 Tailscale 吃的,所以直接看看 Tailscale 在本地都干了什么,目标很明确

DNS?

由于不只是域名不通,连 IP 也不通所以,不考虑是 DNS 的问题

路由表?

一开始想的可能是 Tailscale 路由了整个 100.64.0.0/10,毕竟我当时给 Headscale 分配的是 100.100.0.0/16,/16依然是/10范围内的,有没有可能是整段都吃了,但

ip route list table all | grep 100

能看到 100.100.0.*/32 的路由,分配的都是/32的单设备地址,不可能把整个/10吃掉,所以路由表也是正常的

而且通过get命令也能看出路由是正常的

ip route get 100.100.2.136

防火墙?

另一个对数据包产生影响的可能就是防火墙了,所以喵了一眼防火墙的规则

nft list ruleset | grep -i tailscale0

由于我使用的是 Alpine v3.22,所以防火墙是 nftables,如果是 iptables 把nft改为iptables即可

在这里看到了一个关键的规则:

iifname != "tailscale0*" ip saddr 100.64.0.0/10 counter packets 6 bytes 568 drop

在iptables应该是-A ts-input -s 100.64.0.0/10 ! -i tailscale0 -j DROP

这条规则丢弃了整个 100.64.0.0/10 的数据包,通过nft delete删除规则就通了,但这是治标不治本

解决

解决起来不难,全局设置 Tailscale 的 netfilter 为 off/nodiver,或者在启动时加上即可

# 全局设置
sudo tailscale set --netfilter-mode=nodivert

#非全局设置 其他参数自行补充
sudo tailscale up --netfilter-mode=nodivert

对于netfilter-mode官方的解释如下(GPT翻译):

--netfilter-mode(仅限 Linux)
这是一个高级功能,用于控制 Tailscale 对防火墙的自动配置程度

  • 可选值:offnodiverton
  • 默认值为 on(除了 Synology,默认是 off)。

各选项说明:

  1. off

    • 禁用所有 netfilter(iptables/nftables)管理。
    • 意味着 Tailscale 不会自动配置防火墙,完全由管理员负责。
  2. nodivert

    • 创建并管理 Tailscale 的子链(sub-chains),
    • 调用这些子链的工作由管理员自己负责
    • 简单说,规则存在,但不会自动生效,需你手动把它们挂到主链上。
  3. on

    • 完全管理 Tailscale 的防火墙规则。
    • Tailscale 会自动创建子链、挂载到主链,并管理允许的流量。
注意:
如果你设置为 offnodivert,你需要自己 确保防火墙安全地允许 Tailscale 流量
官方推荐 --netfilter-mode=on 安装的规则为起点,再根据需要修改。

结论

所以说,引起这个问题的是 Tailscale 设置的一条防火墙规则,但是为什么要设置这个呢?

官方提到是为了防止 VPN 流量从错误的接口泄露,例如 CVE-2019-14899 漏洞,由于tailscale的网段是100.64.0.0/10,所以它选择了强行让所有这个网段的流量都只能走 tailscale0 这个接口

但是 Tailscale用的网段 100.64.0.0/10 同时也是 运营商级NAT(Carrier Grade NAT, CGNAT),它是假设不会被私有网络使用的,一旦内网里面的服务也用了这个网段,就会出现不通的问题,所以我后面也换用了更不容易冲突的 10.12.12.0/23

最后,问题虽然解决了,但是也留下了安全隐患,如果你实在是担心这个漏洞的攻击会影响到你,你可以不设置成 off 而是 nodivert 然后手动按需调用

最后修改:2025 年 11 月 02 日
我很可爱,请给我钱(bushi)