基于netcat的NAT后UDP打洞实验:反向映射原理疑问
UDP NAT打洞P2P通信原理疑问
最近我了解到一个用netcat实现NAT后两台机器UDP打洞进行P2P通信的实验,但没完全搞懂原理。实验步骤如下(修正原文疑似笔误,否则逻辑不成立):
假设有两台机器1和2,它们的公网IP分别为IPa和IPb。 # 在机器1执行 echo '在NAT表中打洞' | nc -u -p 50001 IPb 50002 # 从私有端口50001发UDP包到机器2的公网IP:50002 nc -u -l 50001 # 启动UDP监听,监听私有端口50001 # 在机器2执行 echo '在NAT表中打洞' | nc -u -p 50001 IPa 50002 # 从私有端口50001发UDP包到机器1的公网IP:50002 nc -u -l 50001 # 启动UDP监听,监听私有端口50001 # 在机器1执行 echo 'hello' | nc -u -p 50002 IPb 50001 # 从私有端口50002发UDP包到机器2的公网IP:50001 # 在机器2执行 echo 'hello' | nc -u -p 50002 IPa 50001 # 从私有端口50002发UDP包到机器1的公网IP:50001
我理解前两步操作会在两台机器的NAT表中生成如下映射条目:
机器1的NAT条目
| 私有IP | 私有端口 | 公网IP | 公网端口 |
|---|---|---|---|
| PrivateIPa | 50001 | IPa | PublicPorta |
机器2的NAT条目
| 私有IP | 私有端口 | 公网IP | 公网端口 |
|---|---|---|---|
| PrivateIPb | 50001 | IPb | PublicPortb |
我现在的疑问是:当从机器1的50002端口向机器2的50001端口发送"hello"时,数据包会到达机器2的NAT,目标端口是50001,但机器2的NAT条目对应的是IPb:PublicPortb,请问此时反向映射是如何实现的?
问题解答
首先要明确:这个实验能成的核心前提是两台机器的NAT都是「锥型NAT(Cone NAT)」——这是家用路由器最常见的NAT类型,也是UDP打洞的基础。
1. 第一步打洞操作的实际作用
机器1/2执行的nc -u -p 50001 [对方公网IP] 50002,本质是让私有机器从固定私有端口50001主动发起UDP请求到对方公网IP的某个端口。NAT收到这个出站请求后,会生成一条双向映射规则:
- 私有端口50001 ↔ 公网端口(比如PublicPorta/PublicPortb)
- 同时,锥型NAT会放开规则:任何来自外部的、发往这个公网映射端口的UDP包,都会被转发到对应的私有端口50001。
2. 关键的"hello"发送步骤的映射逻辑
当机器1从50002端口发UDP包到机器2的公网IP:50001时:
- 首先,机器1的NAT会为私有端口50002生成一条临时映射(比如
PrivateIPa:50002 ↔ IPa:PublicPorta_2),并把这个包转发到机器2的NAT。 - 机器2的NAT收到这个包时,会检查两条规则:
① 因为机器2之前已经从私有端口50001主动发起过出站请求,NAT已经生成了PrivateIPb:50001 ↔ IPb:PublicPortb的映射,锥型NAT允许反向的、来自任何外部IP的流量发往这个映射对应的私有端口——这里的关键点是,NAT不会死卡目标端口必须是PublicPortb,而是会关联「私有端口发起过请求」这个行为,只要外部包的目的IP是机器2的公网IP,并且机器2的私有端口50001有过出站记录,NAT就会尝试把包转发到50001。
② 同时,当机器2几乎同时从50002端口发hello到机器1的公网IP:50001时,两台NAT会互相把对方的IP:临时端口加入到允许列表中,完成双向端口的打通——这就是UDP打洞的核心:同时发起双向请求,让两台NAT互相认可对方的流量来源。
简单说,不是目标端口50001直接对应私有端口50001,而是因为私有端口50001有过主动出站行为,NAT会放行所有发往本机公网IP的、指向该私有端口对应的流量,哪怕这个流量的目标端口看起来和公网映射端口不一致(本质是NAT会关联私有端口的行为,而不是只看公网端口的匹配)。
内容的提问来源于stack exchange,提问作者Aritra Sur Roy
相关产品推荐
相关产品推荐

