NAT
在RFC3489协议中,将NAT分成4种类型,即完全锥型、IP限制锥型、端口限制锥型以及对称型。在这4种类型中,越往后的NAT类型穿越难度越大。
我们一般处于下面这样的NAT网络环境:
NAT会在无感知的情况下帮我们自动进行内外网地址映射:

NAT类型
完全锥型NAT
特点:一旦打洞成功,所有知道该洞的主机都可以通过它与内网主机进行通信。
可以理解为每一个NAT“洞”的组成结构为:{内网IP、内网端口、外网IP、外网端口}
IP限制锥型NAT
特点:NAT打洞成功后,只有与之打洞成功的外网主机才能通过该洞与内网主机通信,而其他外网主机即使知道洞口也不能与之通信。
可以理解为每一个NAT“洞”的组成结构为:{内网IP、内网端口、外网IP、外网端口、【{被访问主机的IP}】}
端口限制锥型NAT
特点:除了像IP限制锥型NAT一样需要对IP地址进行检测外,还需要对端口进行检测。
可以理解为每一个NAT“洞”的组成结构为:{内网IP、内网端口、外网IP、外网端口、【{被访问主机的IP,被访问主机的端口}】}
对称型NAT
对称型NAT是4种NAT类型中对数据包检测最严格的。
特点:内网主机每次访问不同的外网主机时,都会生成一个新洞,而不像前面3种NAT类型使用的是同一个洞。
它与端口限制型NAT最大的不同是当host主机访问外网主机A时,它与主机A之间会新建一个洞,而不是复用访问主机B时的洞。
可以理解为每一个NAT“洞”的组成结构为:{内网IP、内网端口、外网IP、外网端口、{被访问主机的IP,被访问主机的端口}}

NAT类型推断
主机向STUN服务器发送请求,请求内部带有内网源IP/PORT信息,stun可借此得知内外网映射关系。
- 如果内/外网地址相同,则说明主机具有公网ip,非nat环境
- 如果stun用另一个ip/port向主机的这个源外网ip/port发送请求能正确得到响应,则说明是完全锥形NAT
- 如果stun用同一个ip不同port向主机的这个源外网ip/port发送请求能正确得到响应,则说明是IP限制型NAT
- 如果主机用同一个内网ip/port向stun的不同端口连续发送两个请求,这两个请求的外网port不同,则说明是完全对称NAT,否则是ip/port限制型NAT
各NAT之间可穿越表
| NAT类型 | NAT类型 | 能否穿越 |
|---|---|---|
| 完全锥型NAT | 完全锥型NAT | 可以 |
| 完全锥型NAT | IP限制型NAT | 可以 |
| 完全锥型NAT | 端口限制型NAT | 可以 |
| 完全锥型NAT | 对称型限制型NAT | 可以 |
| IP限制型NAT | IP限制型NAT | 可以 |
| IP限制型NAT | 端口限制型NAT | 可以 |
| IP限制型NAT | 对称型限制型NAT | 可以 |
| 端口限制型NAT | 端口限制型NAT | 可以 |
| 端口限制型NAT | 对称型限制型NAT | 有可行性 |
| 对称型限制型NAT | 对称型限制型NAT | 不可以 |
NAT互通
下面针对几种特定组合分别给出解释,权当抛砖引玉,相信其他组合读者也不难推断。
IP限制型NAT与对称型NAT互通
设IP限制型NAT主机为X,设对称型NAT主机为A。
X和A通过STUN服务器交换双方信息。
X向A的外网地址发送数据,虽然会失败但是将会在X的NAT侧留下A的外网IP
A向X的外网地址发送数据即可正常通行(因为A的外网IP已经在白名单里了)
X与A正常通信

端口限制型NAT与对称型NAT互通
设端口限制型NAT主机为A,设对称型NAT主机为B。
即使再和之前一样,也很难准确地把B的端口加入白名单。
有两种可行的方案,一种方式是预测式,一种方式是枚举。
预测式:能预测内网和外网端口的映射规律,那么就能准确将B的端口加入白名单
枚举:A多次向B发送很多请求,这样就能把B的多个IP/Port对加入白名单,这样B往回发送的请求有可能命中。
端口限制型NAT与端口限制型NAT互通
- A/B与stun交换信息,从而有了双方已经生成的洞的信息
- A向B发送一个请求,由于A的IP/Port未在B的NAT侧的白名单中,故请求失败,但是此后A侧NAT就加入了B的外网IP/Port
- B向A的外网IP/Port发送请求即可成功
对称型NAT与对称型NAT互通
通过双向预测机制。
比如A向STUN服务器多次发送请求,因为每个请求都具备内网ip/port与外网ip/port的映射信息,从而有可能推导出内外网ip/port的映射关系。这样,就能预测式打洞成功,一个示例如下:
- 通过A和STUN多次交互获取并计算映射关系
- 通过第1步得到的映射关系有意构造一个请求,设内网ip/port为(x1,y1),则能够计算出外网ip/port将为(a1,b1),同时将该请求发送给B的(a2,b2)地址。这次请求会失败,但是会在A的NAT侧形成一个洞。
- B通过(a2,b2)反向推导出应使用的(x2,y2)内网源地址,于是以(x2,y2)为src,(a1,b1)为dst,即可成功请求。
参考
- 《WebRTC音视频实时互动技术:原理、实战与源码分析》
- RFC3489——classic STUN
- RFC5389