公众号旧文
为什么向公网建立连接就可以穿透NAT?
为什么内网设备主动向公网服务器建立连接之后,公网就能访问内网了?
例如:
- Cloudflare Tunnel(cloudflared)
- SSH Reverse Tunnel(ssh -R)
- frp
- RIPE Atlas Probe
- Tailscale DERP 中继
这些都能做到没有公网 IP、没有端口映射、甚至在 NAT 后面,也能让外部访问到内网设备。
核心原理其实并不复杂,只要理解 NAT 的工作方式即可。
一、NAT 在做什么?
假设家里的电脑地址是:
192.168.1.100
家庭宽带公网 IP 为:
1.2.3.4
当电脑访问百度时:
192.168.1.100:52341
↓
路由器 NAT
↓
1.2.3.4:60001
↓
baidu.com:443
此时路由器会创建一条 NAT 映射记录:
公网连接 内网连接
1.2.3.4:60001 ←→ 192.168.1.100:52341
也就是:
发往 1.2.3.4:60001 的数据
转发给 192.168.1.100:52341
路由器会把这条记录保存在 NAT 表中。
二、为什么百度可以回访你?
因为 NAT 表已经存在。
百度收到请求后回复:
baidu.com:443
↓
1.2.3.4:60001
路由器查看 NAT 表:
1.2.3.4:60001
对应
192.168.1.100:52341
于是将数据转发回内网电脑。
因此通信可以正常完成。
三、那为什么陌生人无法直接访问你?
假设这时有另一台主机:
8.8.8.8
尝试访问:
1.2.3.4:22
路由器检查 NAT 表,找不到对应记录。
于是直接丢弃数据包。
因为路由器根本不知道这个请求应该转发给哪个内网设备。
这也是为什么没有做端口映射时,公网无法直接访问家庭网络中的设备。
四、理解一个关键事实
很多人以为 TCP 连接是单向的,实际上并不是。
TCP 连接虽然由一方发起,但建立成功后就是双向通信。
例如:
A ─────► B
连接建立之后:
A ◄────► B
双方都可以发送数据。
这意味着,一旦连接建立完成,后续通信不再区分是谁发起的连接。
这正是各种穿透 NAT 方案能够工作的基础。
五、Cloudflare Tunnel 的工作原理
当执行:
cloudflared tunnel run
时,
你的服务器
│
├────► Cloudflare
├────► Cloudflare
└────► Cloudflare
通常会建立多个长期 TLS 连接。
如果查看网络状态:
ss -ntp
经常可以看到:
本机随机端口
↓
Cloudflare:443
这样的连接。
此时 NAT 表已经存在。
六、用户访问网站时发生了什么?
用户访问:
https://example.com
请求路径实际上是:
浏览器
↓
Cloudflare Edge
↓
已建立的 Tunnel
↓
你的服务器
注意一个关键点:
Cloudflare 没有主动连接你的服务器
因为:
连接早就已经建立好了
Cloudflare 只是把用户请求发送到那条已经存在的 TLS 连接中。
因此没有新的入站连接,自然也不会被 NAT 拦截。
七、那么这算真正的 NAT 穿透吗?
严格来说,Cloudflare Tunnel、SSH Reverse Tunnel、FRP、RIPE Atlas 这类方案并不是教材中定义的 NAT 穿透。
真正的 NAT 穿透通常指:
- STUN
- TURN
- ICE
- UDP Hole Punching
- WebRTC 打洞
例如:
- 微信语音
- QQ 电话
- Teams
- Zoom
- Tailscale 直连模式
这些技术会尝试让两台 NAT 后面的设备直接建立连接。
中间服务器仅负责协助建立连接。
建立成功后流量不再经过中继服务器。
八、运维领域常说的穿透 NAT
从严格定义来说并不属于打洞技术,但在运维领域,人们通常把下面这些方案统称为 NAT 穿透:
- Cloudflare Tunnel
- SSH Reverse Tunnel
- FRP
- RIPE Atlas Probe
- Tailscale DERP 中继
因为最终效果是一致的,只是实现方式不同。
它们依赖的不是打洞,而是由内网设备主动向公网建立一个长期出站连接,然后利用这条已经建立好的连接进行双向通信。