# N4 N4 是针对双方均为 “端口递增型 NAT” 的一种打洞测试工具。 > “端口递增型 NAT” 不限制 NAT 种类。 > 也就是说,即使双方均为对称型 NAT(NAT4 - NAT4),只要满足端口递增,也可使用此工具成功打通。 ## 快速开始 公网服务器运行: ```bash python3 n4.py -s ``` 需要打洞的两个 NAT4 客户端运行: ```bash 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 ``` 解释说明: 1. 客户端向服务端发送 Hello 包; 2. 服务端收到两个客户端的 Hello 包后,同时向两方发送 Ready 包; 3. 客户端收到 Ready 包,使用 UDP 向服务器发送 Exchange 包,表示交换两客户端 UDP 公网信息; 4. 服务端收到一客户端的 Exchange 包,向另一客户端发送 Peerinfo 包,携带前者 UDP 公网信息; 5. 客户端收到 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 通信。 ## License GNU General Public License v3.0