N4 是针对双方均为 “端口递增型 NAT” 的一种打洞测试工具。
“端口递增型 NAT” 不限制 NAT 种类。
也就是说,即使双方均为对称型 NAT(NAT4 - NAT4),只要满足端口递增,也可使用此工具成功打通。
公网服务器运行:
python3 n4.py -s
需要打洞的两个 NAT4 客户端运行:
python3 n4.py -c -h 服务器IP
客户端日志显示:
[2024-06-01 12:38:56,438] INFO [n4.py:375] ==================
[2024-06-01 12:38:56,439] INFO [n4.py:376] Source port: 30000-30025
[2024-06-01 12:38:56,459] INFO [n4.py:287] <= Hello
[2024-06-01 12:38:56,471] INFO [n4.py:293] => Ready
[2024-06-01 12:38:56,472] INFO [n4.py:302] <= Exchange
[2024-06-01 12:38:56,486] INFO [n4.py:312] => Peer: 203.0.113.12:5793
[2024-06-01 12:38:56,486] INFO [n4.py:313] [ Target: 203.0.113.12:5813 ]
[2024-06-01 12:38:56,487] INFO [n4.py:321] <= Punch
[2024-06-01 12:39:06,498] INFO [n4.py:386] [ LOSE ]
[2024-06-01 12:39:06,500] INFO [n4.py:375] ==================
[2024-06-01 12:39:06,500] INFO [n4.py:376] Source port: 30025-30050
[2024-06-01 12:39:06,514] INFO [n4.py:287] <= Hello
[2024-06-01 12:39:06,526] INFO [n4.py:293] => Ready
[2024-06-01 12:39:06,527] INFO [n4.py:302] <= Exchange
[2024-06-01 12:39:06,541] INFO [n4.py:312] => Peer: 203.0.113.12:5434
[2024-06-01 12:39:06,541] INFO [n4.py:313] [ Target: 203.0.113.12:5454 ]
[2024-06-01 12:39:06,542] INFO [n4.py:321] <= Punch
[2024-06-01 12:39:06,556] INFO [n4.py:334] => Punch from peer
[2024-06-01 12:39:08,559] INFO [n4.py:342] <= Punch
[2024-06-01 12:39:08,560] INFO [n4.py:379] ------
[2024-06-01 12:39:08,560] INFO [n4.py:380] Local port: 30040
[2024-06-01 12:39:08,560] INFO [n4.py:381] Peer address: 203.0.113.12:5454
[2024-06-01 12:39:08,560] INFO [n4.py:382] ------
[2024-06-01 12:39:08,560] INFO [n4.py:383] [ WIN ]
[2024-06-01 12:39:08,560] INFO [n4.py:385] > nc -u -p 30040 203.0.113.12 5454
日志出现 [ WIN ]
字样,表示两者打通。
双方运行日志中提示的 nc
命令,即可互相进行 P2P 通信。
服务端监听 TCP/1721
和 UDP/1721
。
- TCP 端口用于与客户端通信;
- UDP 端口仅用于获取客户端公网上的IP、端口信息,只接收不发送。
打洞过程共有 5 步:
1. Hello client --TCP-> server
2. Ready client <-TCP-- server
3. Exchange client --UDP-> server
4. Peerinfo client <-TCP-- server
5. Punch client <-UDP-> client
解释说明:
- 客户端向服务端发送 Hello 包;
- 服务端收到两个客户端的 Hello 包后,同时向两方发送 Ready 包;
- 客户端收到 Ready 包,使用 UDP 向服务器发送 Exchange 包,表示交换两客户端 UDP 公网信息;
- 服务端收到一客户端的 Exchange 包,向另一客户端发送 Peerinfo 包,携带前者 UDP 公网信息;
- 客户端收到 Peerinfo 包,根据对方地址
IP:PORT
, 预测对方将来的地址会有IP:PORT + peer_port_offset
。 客户端从自身端口src_port_start
~src_port_start + src_port_count
范围, 使用 UDP 逐一向IP:PORT + peer_port_offset
固定地址发送 Punch 包。
如果客户端收到 Punch 包,代表打通。否则,增加源端口值,再次尝试。
下面是一个示例,假设有以下设定值。
src_port_start = 30000
src_port_count = 8
peer_port_offset = 5
括号内为 NAT 转换后的地址。该地址只对目标可见,对来源不可见。
客户端A:
---(Exchange)---
192.168.1.101:30000 --> (198.51.100.3:1801) --> 192.0.2.2:1721
----(Punch)-----
192.168.1.101:30000 --> (198.51.100.3:1803) --> 203.0.113.12:3028
192.168.1.101:30001 --> (198.51.100.3:1804) --> 203.0.113.12:3028
192.168.1.101:30002 --> (198.51.100.3:1807) --> 203.0.113.12:3028
192.168.1.101:30003 --> (198.51.100.3:1806) --> 203.0.113.12:3028 [*]
192.168.1.101:30004 --> (198.51.100.3:1810) --> 203.0.113.12:3028
192.168.1.101:30005 --> (198.51.100.3:1812) --> 203.0.113.12:3028
192.168.1.101:30006 --> (198.51.100.3:1817) --> 203.0.113.12:3028
192.168.1.101:30007 --> (198.51.100.3:1814) --> 203.0.113.12:3028
客户端B:
---(Exchange)---
192.168.0.112:30000 --> (203.0.113.19:3023) --> 192.0.2.2:1721
----(Punch)-----
192.168.0.112:30000 --> (203.0.113.12:3025) --> 198.51.100.3:1806
192.168.0.112:30001 --> (203.0.113.12:3029) --> 198.51.100.3:1806
192.168.0.112:30002 --> (203.0.113.12:2030) --> 198.51.100.3:1806
192.168.0.112:30003 --> (203.0.113.12:3031) --> 198.51.100.3:1806
192.168.0.112:30004 --> (203.0.113.12:3028) --> 198.51.100.3:1806 [*]
192.168.0.112:30005 --> (203.0.113.12:3032) --> 198.51.100.3:1806
192.168.0.112:30006 --> (203.0.113.12:3033) --> 198.51.100.3:1806
192.168.0.112:30007 --> (203.0.113.12:3034) --> 198.51.100.3:1806
在以上打洞组合中,[*]
标记的一对尝试,成功打通。
客户端 A 运行:
nc -u -l 30003
客户端 B 运行:
nc -u -p 30004 198.51.100.3 1806
两者即可 P2P 通信。
GNU General Public License v3.0