打洞复盘
咖啡馆里的ssh连接问题
今日在市里的咖啡馆,我测试mac与mini pc(n100)的ssh连接效果。结果我成功实现ssh连接,但是延迟特别高,我很疑惑,而且如果在外面想要使用我家里的设备,当延迟特别高时肯定会影响我的使用,我决定弄清楚为什么ssh连接的延迟很高以及如何降低延迟。至于[[ssh到底是什么?]],我目前理解它是一种实现远程操作设备的方式,它与共享屏幕都是远程操作的方式,但是在ssh中设备之间只会传输文字,因此速度极快且延迟低。
在外面的mac连接的是公网,而mini pc连接的是内网(路由器分配的LAN)。它们两者是一般是不通的,只能内网向外,而不能公网向内。我不在内网,需要解决从公网向内网的问题,解决该问题的简单方式之一是在两个设备上都装上tailscale。Tailscale在设备群之间创建了一个虚拟的、加密的、点对点的网络,每个设备都有一个独立的地址空间。
另外补充:我之所以在mini pc上装上了tailscale是因为这篇介绍exit node的文章。我在mini pc里将其刷机为proxmox系统,并且创建了一个lxc(虚拟机),大概这样理解:mini pc是一栋楼,它能提供很多房间,而proxmox是管家,它负责房间的分配,而lxc是其中的房间之一,专门用来作为exit node。
再赘述一次我当前情况:
- mac在外
- mini pc在家
- 它们都装了tailscale 想要解决的问题:ssh的连接延迟太高
过程--都是ai教的
和ai聊了一会之后才发现tailscale 走的是 DERP连接模式,不是direct连接模式,所以延迟很高。
tailscale ping node # node是我在tailscale给mini pc取的名字
pong from node (100.64.107.85) via DERP(hkg) in 953ms
DERP模式是tailscale尝试其他方式且失败时的兜底方案,tailscale在一些地方有免费中继站,当流量遇见无法穿透NAT(对于什么是NAT很快就会提到)、防火墙限制、对称NAT问题时,tailscale会引导流量走最近的中继站,从而实现设备之间的连接。可以看到shell输出中”hkg“是Tailscale在香港建立的DERP服务器。以下指令可以看到tailscale的全部DERP服务器:
tailscale netcheck
到目前为止,问题从延迟太高变为tailscale连接模式是DERP而不是direct连接。接着我试图让ai教我如何实现直连。tailscale实现直连的方式是当IPv6无法连接时,在IPv4中实现打洞。想象一下DERP连接模式,北京到美国没有直接连通的航线,而只有北京当香港,香港到美国的航线,因此你只能从北京飞到香港转机到美国,而代价是需要花更多的时间,而在direct模式中,Tailscale帮你打通了一条北京到美国的航线,你能从北京直飞美国,时间会快很多。
要了解具体如何打洞,需要补充一些知识:公网、内网和NAT。路由器会给每台连接它的设备分配一个局域网IP(如192.168.1.x)和端口,局域网形成的网络是内网。而连接到局域网的设备为了实现上网,它需要被路由器将内网ip和端口翻译为公网ip(如120.83.12.45)。端口是用来区分不同连接的设备,例如你的iPhone连接路由器后ip是192.168.1.5:54321,你的mac连接后的ip是192.168.1.5:54320。当你google github.com时,路由器会做一次”翻译“,这整个流程被称为NAT,流程如下:
google github.com(内网 IP:端口) --> 路由器翻译 --> 公网 IP:端口
路由器在翻译时会将每次的翻译记录为一张映射表,因为翻译一次后,第二次直接查表即可,就不需要再翻译了,映射表如下:
内网 IP:端口 ←→ 公网 IP:端口
192.168.1.5:54321 ←→ 120.83.12.45:54321
192.168.1.8:60000 ←→ 120.83.12.45:60000
打洞的本质是在路由器里面写入一条映射规则。当你的设备主动向公网时,路由器会写入一条记录,并凭此放行对方的响应放行。打洞正是利用该机制:通过主动发送一个包,在自己的路由器里面写入一条映射规则,让之后进来的包被路由器认成”熟人“从而放行、
IP分为IPv4和IPv6,后者的出现是因为前者数量不够用了,实际的设备数量大于IPv4提供的数量。IPv6是直接暴露在公网的,而IPv4则是在内网,由于地址数量不够,所以才需要一层NAT,用来将内网映射为公网。如果双方设备都有IPv6,能够直接实现点对点连接。一方没有或者都没有IPv6,则只剩下两种路径:
- IPv4 + 打洞 (需要穿透NAT)
- 走DERP 中继服务器(延迟高)
结果
我的路由器是作为学校wifi的中继器,没有开启IPv6的权限,加上我通过监听学校wifi发现它并没有开启I开发Pv6的权限,因此要实现直连我只能走IPv4。在咖啡馆我连接是我的热点,虽然热点为mac提供了IPv6地址,但是mini pc并没有IPv6地址,并且走IPv4时热点的NAT是CGNAT技术(多层NAT),其NAT太厚,tailscale很难穿透它,只能走DERP。最后我试图用公共 wifi 来做到打洞,目前是成功了:
tailscale ping node pong from node (100.64.107.85) via 111.198.122.248:41641 in 18ms
这也侧面印证了一个事实是学校wifi的NAT并不是那种难以打穿的NAT。