11_NAT和打洞
约 2634 字大约 9 分钟
2026-07-13
NAT (Network Address Translation)
一个常见的网络数据从网络流量角度来看可以分为五部分:源IP、源端口、协议、目的IP、目的端口;这就是常说的五元组,IP通信能正常运行的关键就是这五元组。
为了解决公网IPv4地址耗尽的问题,NAT技术出现,NAPT也称为PAT,即端口转换。
NAPT是一种IP地址复用技术,由于大多数网络流量都基于TCP和UDP,这种传输层协议的寻址使用端口,端口号为1~65535,端口号是充裕的,“复用IP地址”+“改写端口号”是PAT技术的理论基础。
设想两台内网电脑复用一个公网地址访问某一网站server的80端口:
PC1: 内网IP1-port1-tcp-Server-80
PC2: 内网IP2-port2-tcp-Server-80但是内网地址是无法在公网路由,NAT设备(一般是路由器)需要将内网IP转换为公网IP,并配合修改端口号以达成复用公网IP目的:
NAT设备内部维护了一张 NAT映射表 (记录了内网IP:端口 和 出网IP:端口)的映射关系,从而进行数据表的修改。
|内网IP1-port1|公网IP-portA| |内网IP2-port2|公网IP-portB|
PC1:公网IP-portA-tcp-Server-80
PC2:公网IP-portB-tcp-Server-80此时NAT设备就能使用 公网IP:portA 和 公网IP:PortB 对回包数据进行区分,并分别转发给内网的PC1和PC2;
但是这样也引发了一些问题,NAT打破了IP地址的点对点可达性,导致处于NAT设备后的终端只能主动向外发起网络通信,无法由外向内主动访问。
(因为外界无法直接访问内网地址,需要先由内网的设备发一条请求过去,外界设备才能获得其对应的出口IP,进行后续的通信)
NAT 技术的具体分类(玩法不明)
NAT技术目前有四种分类:FullCone、Restricted、Port-Restricted、Symmetric四种;有时候也会叫做NAT1/2/3/4; 这些叫法是根据NAT路由器对"外来数据包"的拦截严格程度,划分出来的四种不通的工作模式。
NAT1: 全锥形(Full Cone NAT): 内网IP1:port1 经过NAT 转发位 公网IP:portA 后, NAT 设备就会记住这个映射关系,之后外界无论什么设备访问 公网IP:portA 这个端口, NAT设备都会把流量包全部转给 内网IP1:port1
NAT2: 受限锥形 / IP受限锥形 (Address Restricted Cone NAT): 内网IP1:port1 经过NAT 转发位 公网IP:portA 后, NAT 设备就会记住这个映射关系,但是 NAT 设备只会转发 已经有建立过连接的服务器。
比如说,内网设备访问了google,完成了一次交互,此时NAT设备会把google的IP地址标记为安全的IP,之后google主动推数据(天气信息)这些,NAT设备会把对应的数据包放行。但是如果有事先未建立建立的IP地址,往NAT的对应端口发数据,NAT设备会直接丢弃该数据包。
NAT 3:端口受限锥形(Port Restricted Cone NAT): 内网IP1:port1 经过NAT 转发位 公网IP:portA 后, NAT 设备就会记住这个映射关系,但是现在NAT设备不仅要维护 受信IP表,还要在表里面添加上端口。 比如内网设备刚刚访问的是google的80端口,此时google换成90端口回消息,NAT设备也会直接丢弃90端口发来的数据包。
NAT 4:对称型(Symmetric NAT): 最安全,也最复杂的。之前的例子里面,内网到NAT设备的端口映射都是1对1的,但是在NAT4里面,每当内网设备访问一个公网IP的时候,NAT设备就会开一个端口做映射,并且校验对端的IP和端口。
之所以对NAT做这么多手段,归根结底还是为了安全问题
⚠️ NAT 1(全锥形)的安全问题:端口劫持与恶意扫描 在 NAT 1 模式下,只要你的内网设备(比如你的电脑)往外发了一个包,路由器就会在公网上永久(或长时间)开放一个端口对应你。 风险: 此时,全世界任何一个黑客只要扫描到你路由器的这个公网端口,就可以直接把恶意攻击流量源源不断地倒进你的内网电脑。这等于是在你家防盗门上直接开了一个无防备的狗洞。
⚠️ NAT 2(IP受限锥形)的安全问题:IP 伪造(SPOOFING) NAT 2 比 NAT 1 聪明一点,它只允许你访问过的那个服务器 IP 给你回包。 但在网络世界里,伪造数据包的源 IP(IP Spoofing)并不是一件很难的事。如果黑客知道了你正在和某个服务器(比如 IP 是 1.1.1.1)通信,黑客就可以伪造一个来自 1.1.1.1 的数据包发给你,路由器也会直接把这段流量送入内网。
⚠️ NAT 3(端口受限锥形)的安全问题:依然存在针对特定端口的攻击 NAT 3 要求 IP 和端口必须同时对上,安全级别已经很高了,但如果黑客控制了你正在连接的那个远程服务器,或者黑客成功预测/截获了通信的端口号,依然可以通过这个狭窄的通道把恶意包送进来。
- 为什么 NAT 4(对称型)最安全?
NAT 4 之所以被企业内网奉为圭臬,就是因为它把安全做到了极致。即使黑客伪造了服务器的 IP 和端口,或者黑客在公网上蹲守,他也根本无法猜出你的路由器下一次会用哪个随机公网端口去跟别人通信。因为你每换一个连接对象,公网端口就变一次。这种“打一枪换一个地方”的策略,让外部主动发起的端口扫描和劫持变得几乎不可能。
NAT打洞
虽然安全问题得到了解决,但是两个在内网的设备进行通信的需求还是存在的。简单来说,你和你的 Homie 两个人想一起玩 MC, 又不想连接到垃圾的公网服务器上,使用NAT直接打通双方的网络情况,建立一条所谓的专线,还是蛮有必要的。
因此 NAT打洞 就是在通信双方都处于NAT后面时候,使用某种方式使得通信双方可以正常端到端通信。
这里简单讲一下 NAT 打洞的玩法(并且使用NAT3,NAT4太难搞了),这里的关键在于 Stun 服务器
利用挂在公网上的“中间人”(STUN 服务器),欺骗各自的 NAT 路由器,在坚固的防火墙墙体上,“骗”出一条双向互通的通道。
这里AI提供的“传达室大爷”比喻,理解起来非常轻松:
第一步:找公网中间人“对暗号” 假设你在内网 A 别名“张三”,队友在内网 B 别名“李四”。你们俩都不知道自己的公网 IP 和端口是什么。 这时候,你们同时给公网上的一个固定服务器(STUN 服务器,也就是中间人大爷)发了一封信。
张三给中间人发信。张三的 NAT 路由器(A大爷)在公网上开了一个洞:公网 IP-A : 端口 7777。 李四给中间人发信。李四的 NAT 路由器(B大爷)在公网上开了一个洞:公网 IP-B : 端口 9999。
中间人收到信后,把两人的“公网五元组”记录下来,然后做一件促成姻缘的好事:
他给张三回信说:“李四的公网地址是 IP-B:9999”; 同时给李四回信说:“张三的公网地址是 IP-A:7777”。
第二步:张三率先“盲打”第一枪(打左边的洞)
拿到地址后,张三迫不及待地直接往李四的 IP-B:9999 发包。 张三的 A 大爷: 看到张三往 IP-B:9999 发包了,于是大爷在自己的黑板上记下:“允许 IP-B:9999 发回包给张三。” (张三这边的洞,打通了!)
然而,李四的 B 大爷: 当张三的这个包辛辛苦苦跑到李四家门口时,B 大爷翻了翻黑板:“嗯?李四之前只给中间人发过信,没给 IP-A:7777 发过信啊!” 根据 NAT 3 的严格规则,B 大爷觉得这是恶意流量,无情地把张三的第一个包丢弃了。
张三这第一枪虽然被李四家的大爷拦了,但它完成了历史使命:张三成功在自己家的路由器上,给李四留了一扇门。
第三步:李四反手“补一枪”(打右边的洞,奇迹发生) 几乎在同一时间,李四也根据中间人给的地址,往张三的 IP-A:7777 发包。 李四的 B 大爷: 看到李四往 IP-A:7777 发包了,立刻在黑板上记下:“允许 IP-A:7777 发回包给李四。” (李四这边的洞,也通了!)
重点来了!张三的 A 大爷: 当李四的这个包跑到张三家门口时,A 大爷翻了翻黑板:“哎呀,刚才张三正好给 IP-B:9999 发过信,这不就是回包吗?放行!”
于是,李四的包成功送到了张三的手里!
第四步:双向通车,告别中间人 既然张三已经收到了李四的包,张三立刻顺着原路再回一个包。 这时候,李四的 B 大爷翻黑板: “李四刚刚确实给 IP-A:7777 发过包,这又是回包,放行!”
轰隆一声,两边的洞彻底贯通! 从此以后,张三和李四之间就可以直接疯狂对发数据(P2P),那个公网的中间人已经没用了,可以退场喝茶了。
--- 玩一下Stun服务器是啥样的 测试 NAT 映射行为 (-m) 和过滤行为 (-f) debian:~#: turnutils_natdiscovery -m -f -p 19302 stun.l.google.com
-= Mapping Behavior Discovery =- 0: : IPv4. UDP reflexive addr: 14.238.110.186:47544 0: : IPv4. UDP reflexive addr: 14.238.110.186:47544 0: : IPv4. Local addr: : 0.0.0.0:47544
-= Filtering Behavior Discovery =- 0: : IPv4. UDP reflexive addr: 14.238.110.186:37195 0: : IPv4. Local addr: : 0.0.0.0:37195 debian:~#: hostname -I 14.238.110.186 172.17.0.1 245.10.10.10
