之前在 WireGuard使用记录 里提到 full mesh 网络的组建,但有一个关键之处, NAT的穿透问题,并未展开。
只是在文中提到,用wg set ...
手动更新了 endpoint
后两个NAT
之后的机器可以互相 ping 通。
是什么原理呢,在这里详述一下。
NAT概述
大家知道,NAT的出现是为了应对IPv4地址短缺的问题,顺便也会带来一点安全上的提升。 NAT是IP网络上的一个节点,它会把内部主机发起的连接的IP地址,替换为自己的IP地址, 而端口号,替换为自己的按一定规则生成的端口号。
由此知道,NAT上最重要的资源是65536个端口号,这些端口耗尽了,NAT也就处于不可用状态了(假设此NAT只有一个IP)。
NAT可以分为两类、4种类型,这两类是锥型和对称型,锥型里根据对外部地址和端口的限制,又有3种类型,如下表:
编号 | 名称 |
---|---|
1 | 完全锥型NAT(Full cone NAT) |
2 | 受限锥型NAT((Address-)Restricted cone NAT) |
3 | 端口受限锥型NAT(Port-Restricted cone NAT) |
4 | 对称型NAT(Symmetric NAT) |
顾名思义,锥型和对称型是 NAT 的 形状
,锥型,内部主机经NAT到外部主机的所有连接,
都会通过NAT上面的1个端口,画张图,会看到很多条线汇聚到了一个端点上,也就是锥型的形状;
而对称型,不同的IP地址和端口,会映射到NAT上面的不同端口,画成图形,是很多的平行线。
NAT穿透
有3台主机,如下表,现在需要 A 和 C 直接连接。
名称 | 描述 |
---|---|
A | 锥型NAT之后 |
B | 有公网IP |
C | 锥型NAT之后 |
- A首先连接B,于是B知道了A的NAT的IP地址和A在NAT上映射的端口号;
- 同理,C连接B,B也知道了C的NAT的IP地址和端口号;
- B告诉A,C的NAT的IP地址和端口号,B告诉C,A的NAT的IP地址和端口号;
- 对于NAT1型,即完全锥型,A向C的NAT IP地址和端口号发送数据,C会顺利接收到,C向A发数据同样如此,NAT穿透成功。
- 对于NAT2或NAT3型,C接收不了A发送的数据,原因是A发送到C的数据,
NAT会认为这是一个无效的数据,它的
连接表
里没有A的NAT的IP地址和端口号的记录。 处理也很简单,即C向A的NAT的IP地址和端口号发送一次数据。同理,A接收C发送的数据也是如此,A和C直连成功。 - 对于NAT4型即对称型,A向C的NAT IP地址和端口号发数据,C接收不到,原因是NAT重新分配了端口号。 先假定A的NAT是NAT4型,C的NAT是NAT2或3型,A向B和A向C分别发送数据时,A的NAT上映射的端口号是不同的, A向C发送数据时NAT映射的端口号B和C都不知道,怎么办,暴力猜解!没错,尝试2048次,成功率可以达到99.9%(参见文末"How NAT traversal works"链接)
现实情况
真实的网络情况,要复杂一些,比如A和C之间有多个NAT,如果其中之一是NAT4型,那么穿透的难度将大大增加。 如果A和C处于同一个NAT之后,但是A和C因为各种原因隔离在了不同的网络中,它们之间还是不能直连的。
所以,NAT穿透的备用项就是中继(relay),常见是的 TURN
,当然也可以自己实现。
总结
NAT的穿透,是受限于诸多因素的,要形成一个通用的、高成功率的解决办法,是需要做很多工作的。