解决阿里云与 Tailscale 网段冲突
省流——快速解决方案
1 | # 写入脚本 |
问题现象
在阿里云 ECS(VPC 网络)上安装并启动 Tailscale 后,服务器出现”失联”:SSH 能连但 curl、apt update 全部超时,ping 外网 IP 却通。
原理
RFC 6598 与 CGNAT
100.64.0.0/10 是 RFC 6598 保留的运营商级 NAT(CGNAT)地址段,ISP 用于大规模 NAT 时避免与内网冲突。
冲突根源
Tailscale:启动后在 iptables 的
ts-input链插入一条规则:1
-A ts-input -s 100.64.0.0/10 ! -i tailscale0 -j DROP
含义:源地址落在 CGNAT 段、但不从
tailscale0虚拟网卡进入的流量,全部丢弃。这是合规范的防御策略。阿里云:VPC 内网将
100.100.2.0/24网段用作内部服务地址,包括:- DNS 服务器:
100.100.2.136、100.100.2.138 - 镜像源:
100.100.2.158(mirrors.cloud.aliyuncs.com)
- DNS 服务器:
100.100.x.x 正好落在 100.64.0.0/10 范围内,阿里云内网服务的所有回复数据包都被 Tailscale 防火墙误杀。
为什么 ping 外网 IP 通但 curl 不通
ping 8.8.8.8 是 ICMP 协议,源 IP 是公网地址,不在 100.64.0.0/10 范围内,不被拦截。
而 curl / apt 需要先做 DNS 解析 —— 阿里云 DNS 回复的 UDP 包源地址是 100.100.2.136,被 Tailscale 丢弃,DNS 超时导致整个请求失败。
踩坑过程:为什么 DNS 白名单不够
查了一些资料后,第一版方案是只放行两台 DNS 服务器的 IP:
1 | iptables -I ts-input 1 -s 100.100.2.136/32 -j ACCEPT |
结果如下:
1 | # DNS 解析恢复了 |
只救了 DNS 解析,但镜像源返回的 TCP 数据包(HTTP 80/443)同样来自 100.100.2.0/24 网段,照样被 ts-input 的 DROP 规则丢掉。只放行 DNS IP 不够,镜像源一样被卡。
最终方案:子网白名单 + systemd 守护
将白名单从两个精确 IP 扩展到整个 /24 子网,一次性放通阿里云 VPC 内网所有服务(DNS + 镜像源 + OSS + RDS 内网地址等),同时 Tailscale 防火墙对其他 CGNAT 流量仍然有效,安全无损。
第 1 步:创建守护脚本
/usr/local/bin/fix-ts-dns.sh
1 |
|
如果网卡名不是
eth0(极少数机型),先执行ip addr确认后替换。
脚本每 30 秒检查 ts-input 链顶部是否存在白名单规则,不存在就自动插入。即使 tailscaled 重启或更新后删除规则,最多 30 秒就能自动修复。
限定 -i eth0 确保仅放行从 VPC 内网网卡进入的 100.100.2.0/24 流量。如果某台 Tailscale 节点恰好也分配了该网段的 IP,其从其他接口进入的流量不受影响,仍走 Tailscale 原有的安全策略。
第 2 步:创建 systemd 服务
/etc/systemd/system/fix-ts-dns.service
1 | [Unit] |
依赖 tailscaled.service,确保 Tailscale 先启动、脚本后启动。Restart=always 保证脚本异常退出后自动拉起。
第 3 步:部署
1 | chmod +x /usr/local/bin/fix-ts-dns.sh |
第 4 步:验证
1 | # DNS 解析 |
为什么这个方案是安全的
- 仅放行
100.100.2.0/24(阿里云 VPC 内网段),其余100.64.0.0/10范围内的流量仍被 Tailscale 拦截 - 限定
-i eth0,即使某台 Tailscale 节点恰好分配了该网段 IP,其从非 VPC 网卡进入的流量不会被白名单误放行 - 未关闭 Tailscale 防火墙(
--netfilter-mode=off),子网路由和 exit-node 功能保留 - 未改用公共 DNS,阿里云内网域名(OSS、RDS 等)解析不受影响,不产生额外公网流量费用
- systemd 守护机制保证重启不丢失规则