NAT 和 STUN
| 缩写 | 全称 |
|---|---|
| NAT | Network Address Translation |
| STUN | Session Traversal Utilities for NAT |
一、NAT1~NAT4 通俗解释
先设定一个相同的场景方便对比:
- 你家内网电脑 A:IP
192.168.1.10,用 UDP 端口4000对外通信。 - 你家路由器公网 IP:
1.2.3.4。 - 路由器给这个内网会话分配的公网端口,假设第一次是
8000。
下面的“外部主机”,我随便起名叫 B,IP 为 5.6.7.8。
1. NAT1(完全圆锥形 / Full Cone NAT)
一句话:只要开了门,全世界的任何人都可以进来。
- 建立映射:
电脑 A192.168.1.10:4000→ 经过路由器,映射为公网1.2.3.4:8000。 - 规则:
现在,任何外部主机,只要是往1.2.3.4:8000发数据包,路由器都会原样转给内网 A。- 外部主机 B
5.6.7.8:9999可以直接发数据给1.2.3.4:8000,A 能收到。 - 另一台主机 C
9.9.9.9:12345也直接发过来,A 一样能收到。 - A 自己有没有先给 B、C 发过数据,都无所谓。
- 外部主机 B
比喻:
你告诉了全世界一个公共信箱号 1.2.3.4:8000,任何人把信扔进去,都会直接送到你手里。
2. NAT2(受限圆锥形 / Restricted Cone NAT)
一句话:我只接收我主动联系过的人的回信,具体是谁我无所谓,只要是那个人所在的公司就行。
- 建立映射:
同样映射1.2.3.4:8000。 - 规则:
只有当内网 A 先主动向某个外部 IP 发送过数据,这个外部 IP 的所有端口才能回包给1.2.3.4:8000。
举例:
- A 从
4000主动发给外部主机 B5.6.7.8:53一个数据包。 - 此时,B 的 IP
5.6.7.8被允许回信。- B 从
53端口回包 → 通过。 - B 从
8080端口回包 → 也能通过(只要 IP 是5.6.7.8就行)。
- B 从
- 但如果主机 C
9.9.9.9:7777直接往1.2.3.4:8000发数据,因为 A 从未主动给9.9.9.9发过东西,所以数据被路由器丢弃。
比喻:
你主动给“B 公司”打了个电话,之后只要来电显示是 B 公司的总机号码(IP 相同),无论他们用哪个分机(端口)打回来,你都会接。但陌生人打来的一律不接。
3. NAT3(端口受限圆锥形 / Port Restricted Cone NAT)
一句话:我只接收我主动联系过的那个人、用那个特定的分机打回来的电话。
- 建立映射:
映射1.2.3.4:8000。 - 规则:
只有当内网 A 先主动向某个外部 IP:端口 发送过数据,这个固定的 IP 和端口 才能回包。
举例:
- A 主动发给 B
5.6.7.8:53。 - 此时,只有
5.6.7.8:53回包到1.2.3.4:8000才能被 A 收到。5.6.7.8:8080回包 → 被丢弃(端口不对)。- 其他 IP 发来的更不用想。
- A 如果想收
5.6.7.8:8080的数据,必须先主动给5.6.7.8:8080发个包。
比喻:
你打给 B 公司的张三(分机 53),之后就只接张三用他座机(端口 53)打回来的电话。李四用分机 8080 打过来,你不认识,不接。
4. NAT4(对称型 / Symmetric NAT)
一句话:每次给不同的人打电话,前台就给你换一个陌生的外线号码。别人只能打回那个特定的外线号码才能找到你。
- 映射特点:
同一个内网192.168.1.10:4000,给不同的目标发数据,路由器分配的对外端口都不一样。
举例:
- A 发给主机 B
5.6.7.8:53,路由器分配映射1.2.3.4:8000,且只有5.6.7.8:53回复到8000才有效。 - A 又发给主机 C
9.9.9.9:1234,路由器会另开一个新端口,比如1.2.3.4:8001。
这时 C 必须回复到8001才能被 A 收到;B 如果错发到8001,会被丢弃;C 发到8000也是丢弃。
比喻:
这就像一个极其严格的电话总机:
你给张三打电话,总机显示的来电号码是 8000;
你给李四打电话,总机换了个号码显示成 8001。
张三只能用 8000 回拨,李四只能用 8001 回拨,两个人用错号码都找不着你。
二、STUN 内网穿透到底在干什么?
STUN 就是“公网镜子”,帮你查出:你在互联网上看起来长什么样(公网 IP + 端口),以及你的 NAT 是什么脾气。
1. 基本流程(配合实际 IP/端口)
设定:
- STUN 服务器:
3.3.3.3:3478 - 内网电脑 A:家里,通过路由器,公网 IP
1.2.3.4 - 内网电脑 B:另一个地方,公网 IP
5.6.7.8
第 1 步:照镜子
A 向 3.3.3.3:3478 发一个查询包。
STUN 服务器告诉 A:
“你在公网上的地址是 1.2.3.4:8000,你的 NAT 类型是 XXX。”
B 也去照,得到自己的公网地址:5.6.7.8:9000。
第 2 步:交换地址
A 和 B 通过某个聊天服务器(信令服务器)互相告诉对方:
“我的公网地址是 1.2.3.4:8000”
“我的公网地址是 5.6.7.8:9000”
第 3 步:互相打洞
A 和 B 同时向对方的公网地址发 UDP 数据包:
- A 往
5.6.7.8:9000发。 - B 往
1.2.3.4:8000发。
这个动作的目的,是让各自的 NAT 路由器“以为”双方正在通信,从而允许后续对方的数据进入。这就是常说的 UDP 打洞。
三、针对 NAT1~NAT4,STUN 打洞的结果如何?
仍然用上面的 A (1.2.3.4:8000) 和 B (5.6.7.8:9000)。
✅ NAT1(完全圆锥型)
- 场景:A 是 NAT1,或者双方都是 NAT1。
- 过程:A 通过 STUN 拿到
1.2.3.4:8000告诉 B。B 完全不需要做什么打洞准备,直接往1.2.3.4:8000发数据,A 就能收到。因为 NAT1 无论谁来都能进。 - 结果:直接穿透成功,最容易。
✅ NAT2(受限圆锥型)
- 过程:
- A、B 交换地址后,如果 B 直接往
1.2.3.4:8000发数据,会被 A 的路由器丢掉(因为 A 还没给 B 发过包)。 - 于是执行打洞:A 主动往
5.6.7.8:9000发送一个“打洞包”。这个包到了 B 的路由器虽然会被丢弃,但 A 的路由器已经记录了“允许 IP5.6.7.8的数据进入”。 - 紧接着 B 往
1.2.3.4:8000发数据包,这一次 A 的路由器看到源 IP 是5.6.7.8,就放行了。 - 此时 B 的数据成功进入 A,双向通道建立。
- A、B 交换地址后,如果 B 直接往
- 结果:可以通过打洞穿透成功。
NAT2 只检查 IP,B 用任意端口回复都可以。
✅ NAT3(端口受限圆锥型)
- 过程:和 NAT2 类似,但对端口有要求。
- A 先往
5.6.7.8:9000(注意必须是 B 告知的端口)发一个打洞包。 - A 的路由器这时只允许
5.6.7.8:9000回复。 - B 再用
5.6.7.8:9000往1.2.3.4:8000发数据,刚好符合“IP+端口都匹配”,打洞成功。
- A 先往
- 关键:B 使用的源端口必须是 A 发送时的目标端口。而 B 一般就拿自己的公网映射端口作为源端口,所以打洞时天然满足这个条件。
- 结果:同样可以打洞穿透成功。
❌ NAT4(对称型)
- 场景:假设 A 是 NAT4(或双方都是)。
- 过程:
- A 向 STUN 查询,获得专用于与 STUN 通信的地址
1.2.3.4:8000。 - A 把这个
8000告诉 B。 - A 为了打洞,向 B 的地址
5.6.7.8:9000发了一个包。
因为 A 是 NAT4,目标变了,路由器立刻为“与 B 通信”分配了一个新端口,比如1.2.3.4:8001。 - B 只知道
8000,所以它的打洞包依然发往1.2.3.4:8000。 - A 的路由器收到后一看,
8000这个映射只允许 STUN 服务器的 IP 进来,或者根本就不接受 B 的数据;而且真正留给 B 的通道是8001。结果包被丢弃。 - B 无法猜到
8001,穿透失败。
- A 向 STUN 查询,获得专用于与 STUN 通信的地址
- 结果:STUN 打洞基本无效。
如果双方都是 NAT4,更不可能打通;即便只有一方是 NAT4,通常也无法穿透。这种情况只能借助 TURN 中继服务器 来转发数据。
四、一句话总结
- NAT1~NAT3 都属于“圆锥形”NAT,只要 A、B 都不是 NAT4,STUN 打洞几乎必成。
- NAT4(对称型) 每次换目标就换外网端口,让对方无法猜到,STUN 无能为力,必须用中转服务器。