NAT穿透
NAT穿透也称为UDP打洞,用于让处在不同内网、被NAT隔离的设备能直接建立点对点(Peer to Peer,P2P)连接。
1、NAT介绍
NAT全称Network Address Translation,即网络地址转换协议。起初网络设计者并没有想到互联网能够如此发达,以至于2^32个IPv4地址不够用。针对该问题,设计者给出了两种解决方案,一种就是推行IPv6,但这需要相应的硬件设备支持,且需要一定过渡时间;另一种方案便是使用NAT协议,将IP分为公网IP和内网IP。
根据RFC 1918规定,将内网IP划分为3类。
| 类别 | CIDR | 地址范围 | 数量 |
|---|---|---|---|
| A | 10.0.0.0/8 | 10.0.0.0 – 10.255.255.255 | 16,777,216 |
| B | 172.16.0.0/12 | 172.16.0.0 – 172.31.255.255 | 1,048,576 |
| C | 192.168.0.0/16 | 192.168.0.0 – 192.168.255.255 | 65,536 |
在局域网中,设备分配内网IP,与外界进行通信时,ISP具有公网IP的路由器会维护一张NAT映射表,最初的NAT只改变IP,而Port不变,但随着发展,出现了PAT(Port Address Translation),即在NAT的基础上添加了端口映射,最终将内网IP:Port映射到路由器公网IP上的某个端口,然后通过这个公网端口与外界进行通信。PAT被视为NAT Overload,通常情况下不会刻意区分这两者,统一称为NAT,具体通信流程如下[1]。

2、NAT穿透与STUN
RFC 3489将NAT分为4类[2],并定义了早期STUN(Simple Traversal of UDP Through NATs)协议,旨在帮助UDP应用穿越NAT,但后续由于实际网络中NAT行为复杂多变、检测结果极易错误。于是便推出了RFC 5389。
| NAT类型 | 特点 |
|---|---|
| Full Cone | 内网IP:Port映射到固定公网IP:Port,任何外部IP都可回包 |
| Restricted Cone | 内网IP:Port映射固定,只有之前通信过的外部IP可以回包 |
| Port Restricted Cone | 内网IP:Port映射固定,只有之前通信过的外部IP:Port可以回包 |
| Symmetric | 内网IP:Port对每个目标IP:Port映射不同公网端口 |
端口限制型与对称型的区别在于,端口限制锥型NAT是所有请求映射到相同的公网IP地址和端口,即改变目的IP:Port时,映射不变,而对称NAT是不同的请求有不同的映射,主要区别是内网源端口映射到公网端口是否随目标地址变化。
判断NAT类型,只需要判断最外层NAT就行。且由于UDP无状态,没有繁杂的ESTABLISHED、LISTENING等状态,UDP端口只要映射出去就能用。

RFC 5389彻底重定义并取代RFC 3489,将STUN定义为Session Traversal Utilities for NAT。它移除所有NAT类型分类逻辑,明确建议应用程序放弃诊断NAT,转而使用ICE协议框架通过实际连通性检查建立连接,从而简化协议、提升可靠性,成为现代WebRTC等P2P系统的基石。但如今涉及到NAT穿透,NAT的四种类型还是会有理论指导作用。
ICE(Interactive Connectivity Establishment,交互式连接建立)是一套“自动试错找路”的协议框架,依赖STUN/TURN,最终让NAT后的两台设备像没NAT一样直连。
RFC 3489的STUN“想太多”,试图诊断NAT类型,结果复杂、错误。
RFC 5389的STUN“回归初心”,只干一件事,安全地告诉你公网映射,然后让ICE去试错选路。
3、NAT穿透与FRP
这里需要区别FRP和NAT打洞的区别,FRP内网穿透是将内网服务映射到公网,而打洞仅仅是想建立两台设备的连接,两种均适用于TCP和UDP,但前者以TCP为主,后者以UDP为主[3]。因为后者即使在Full Cone的情况下,正常情况下,将内网TCP端口映射到公网,其TCP连接状态是ESTABLISHED,也就是以连接发送者的身份出现的,与用frp穿透出去的LISTENING端口不同,其是以服务提供者的身份出现的。而想要将ESTABLISHED状态下的TCP连接目标改变是不可能的,因为TCP连接是有状态的。
针对TCP打洞,有两种方案,第一,协调双方同时交叉发送SYN包,如下图,像极了TCP的彩蛋,理论成立,但现实很难做到。第二种就是通过SO_REUSEADDR实现TCP端口复用,让本地与外部ESTABLISHED的端口同时LISTENING,这样只需要保持ESTABLISHED的连接存活即可,NATMap工具穿透TCP就是利用的这一机制。

References
[1] https://www.networkacademy.io/ccna/network-services/nat-overload-pat
[2] https://info.support.huawei.com/info-finder/encyclopedia/zh/NAT.html
[3] https://blog.csdn.net/dxpqxb/article/details/74942302
[4] https://halc.top/p/bb3a9deb