一次Tailscale网络问题的调试过程




English version: Troubleshooting Tailscale Network – Frank’s Weblog

前文提到,我使用Tailscale将我的所有设备组成了一个Mesh网络,并且将位于阿里云北京的轻量应用服务器作为出口节点用于访问一些限制地理位置的网络服务。

然而我却发现在使用该出口节点时完全无法访问互联网。我本以为是Relay的网络质量问题就没有在意。但是后来陆续发现该服务器上的其他一些服务都出现了问题,于是进行了一番检查,结果发现问题并没有这么简单。

首先我发现从服务器上完全无法访问互联网,但是直接curl IP地址是可以的,这样就基本上将问题定位到了DNS上。resolvectl status显示有两个DNS服务器,因为IP以100.100打头[1],我以为这是Tailscale内网的DNS服务器(实际上不是,请看后文)。

Link 2 (eth0)
......
  Current DNS Server: 100.100.2.136
         DNS Servers: 100.100.2.136
                      100.100.2.138

我试图dig @100.100.2.136 baidu.com来检查DNS服务器的回应,得到connection timed out: no servers could be reached.。关掉Tailscale之后,上述命令的回应则正常。因此我认为问题在于Tailscale从某种形式上影响了系统的DNS解析。

Workaround

要workaround这个问题,只需要修改服务器上的DNS配置即可。编辑/etc/netplan/99-netcfg.yaml,在eth0接口下加入nameserver,配置为国内的公共DNS。

network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: yes
      dhcp6: no
      nameservers:
        addresses: [114.114.114.114]

sudo netplan apply应用新配置,然后dig baidu.com得到正确回应。

然而,虽然修改DNS服务器让服务器能够正常访问互联网,但是阿里云内部的很多服务仍然需要阿里云内网的DNS解析,比如阿里云的内网apt源(mirrors.cloud.aliyuncs.com)以及云数据库等产品。将apt源配置为公共镜像可以workaround apt源问题。

定位问题

要定位问题,我们需要找到IP地址100.100.2.136不能访问的原因。我本以这两个DNS服务器是Tailscale内网中的IP,但是通过各种方式都无法访问。经过搜索发现100.100.2.136和100.100.2.138其实是阿里云提供的内网DNS服务器。还有一些阿里云内部服务也使用类似的IP,例如apt源的IP为100.100.2.148,使用curl访问时也遇到了无法连接的问题。

因此我们可以得出一个初步结论:Tailscale通过某种形式影响了100.100.x.x IP段的访问。

可能性

路由

我的第一反应是Tailscale路由了整个100.100.x.x IP段。然而,根据Tailscale文档,Tailscale只路由了被分配的IP地址而不是整个CIDR。ip route list也证实了这点。

ip route list table 52
100.69.x.x dev tailscale0
100.90.x.x dev tailscale0
100.96.x.x dev tailscale0
100.98.x.x dev tailscale0
100.100.100.100 dev tailscale0
100.104.x.x dev tailscale0
100.121.x.x dev tailscale0
100.127.x.x dev tailscale0

ip route get 100.100.2.136得到如下结果,表示数据包将被路由到eth0接口,这说明路由表是正确的,问题并不在路由上。

100.100.2.136 via 172.24.63.253 dev eth0 src 172.24.4.100 uid 0
    cache

iptables

另一个可能对数据包造成影响的是iptables,iptables -S中和Tailscale相关的有如下几条:

-A ts-forward -i tailscale0 -j MARK --set-xmark 0x40000/0xffffffff
-A ts-forward -m mark --mark 0x40000 -j ACCEPT
-A ts-forward -s 100.64.0.0/10 -o tailscale0 -j DROP
-A ts-forward -o tailscale0 -j ACCEPT
-A ts-input -s 100.92.187.56/32 -i lo -j ACCEPT
-A ts-input -s 100.115.92.0/23 ! -i tailscale0 -j RETURN
-A ts-input -s 100.64.0.0/10 ! -i tailscale0 -j DROP

其中最后一条规则drop掉了整个IP段的数据包,使用iptables -D 删除规则后,问题解决。

经过搜索发现今年早些时候已经有人提出了Issue:

[1] tailscale drops 100.64.0.0/10 on firewall when ipv4 is disabled · Issue #3837 · tailscale/tailscale · GitHub

[2] FR: netfilter CGNAT mode when non-Tailscale CGNAT addresses should be allowed · Issue #3104 · tailscale/tailscale · GitHub

结论

综上所述,引起这个问题的是Tailscale设置的一条屏蔽100.64.0.0/10 IP段的防火墙规则,而正好阿里云内网的一些服务位于这些IP段而被屏蔽。根据Tailscale CLI文档,只需要在启动tailscale时加入--netfilter-mod=off参数,即可避免这条规则被设置。但是,这样会带来一些安全隐患

Tailscale设置这条规则,是因为其用于Tailscale网络的IP段(100.64.0.0/10)[1]运营商级NAT(Carrier Grade NAT, CGNAT),因而假设其不会被通常的私有网络使用,然而阿里云使用了这个IP段用于内网服务,因而引起了冲突。

References

iptables(8) – Linux man page

[1] What are these 100.x.y.z addresses? · Tailscale


One response to “一次Tailscale网络问题的调试过程”

Leave a Reply to Troubleshooting TailScale Network – Frank's Weblog Cancel reply

Your email address will not be published.