在现实Internet网络环境中,大多数计算机主机都位于防火墙或NAT之后,只有少部分主机能够直接接入Internet。很多时候,我们希望网络中的两台主机能够直接进行通信(即所谓的P2P通信),而不需要其它公共服务器的中转。由于主机可能位于防火墙或NAT之后,在进行P2P通信之前,我们需要进行检测以确认它们之间能否进行P2P通信以及如何通信。这种技术通常被称为NAT穿透(NAT Traversal)。最常见的NAT穿透是基于UDP的技术(如下面的RFC3489/STUN),也有基于TCP的穿透技术。NAT穿透技术最重要的是识别目标主机的NAT类型,这也是本文所要介绍的内容。
在RFC3489/STUN[1]中,基于UDP的NAT穿透技术把主机划分为如下七种NAT类型:UDP Blocked、Open Internet、Symmetric Firewall、Full Cone NAT、Restricted Cone NAT、Port Restricted Cone NAT、Symmetric NAT。具体解释如下:
(1)Open Internet:主机具有公网IP,允许主动发起和被动响应两种方式的UDP通信。
(2)UDP Blocked:位于防火墙之后,并且防火墙阻止了UDP通信。
(3)Symmetric Firewall:主机具有公网IP,但位于防火墙之后,且防火墙阻止了外部主机的主动UDP通信。
(4)Full Cone NAT:当内网主机创建一个UDP socket并通过它第一次向外发送UDP数据包时,NAT会为之分配一个固定的公网{IP:端口}。此后,通过这个socket发送的任何UDP数据包都是通过这个公网{IP:端口}发送出去的;同时,任何外部主机都可以使用这个公网{IP:端口}向该socket发送UDP数据包。即是说,NAT维护了一个映射表,内网主机的内网{IP:端口}与公网{IP:端口}是一一对应的关系。一旦这个映射关系建立起来(内部主机向某一外部主机发送一次数据即可),任何外部主机就可以直接向NAT内的这台主机发起UDP通信了,此时NAT透明化了。
(5)Restricted Cone NAT:当内网主机创建一个UDP socket并通过它第一次向外发送UDP数据包时,NAT会为之分配一个公网{IP:端口}。此后,通过这个socket向外发送的任何UDP数据包都是通过这个公网{IP:端口}发送出去的;而任何收到过从这个socket发送来的数据的外部主机(由IP标识),都可以通过这个公网{IP:端口}向该socket发送UDP数据包。即是说,NAT维护了一个内网{IP:端口}到公网{IP:端口}的映射,还维护了一个{外部主机IP, 公网{IP:端口}}到内网{IP:端口}的映射。因此,要想外部主机能够主动向该内部主机发起通信,必须先由该内部主机向这个外部发起一次通信。
(6)Port Restricted Cone NAT:当内网主机创建一个UDP socket并通过它第一次向外发送UDP数据包时,NAT会为之分配一个公网{IP:端口}。此后,通过这个socket向外部发送的任何UDP数据包都是通过这个公网{IP:端口}发送出去的;一旦外部主机在{IP:端口}上收到过从这个socket发送来的数据后,都可以通过这个外部主机{IP:端口}向该socket发送UDP数据包。即是说,NAT维护了一个从内网{IP:端口}到公网{IP:端口}的映射,还维护了一个从{外部主机{IP:端口}, 公网{IP:端口}}到内网{IP:端口}的映射。
(7)Symmetrict NAT:当内网主机创建一个UDP socket并通过它第一次向外部主机1发送UDP数据包时,NAT为其分配一个公网{IP1:端口1},以后内网主机发送给外部主机1的所有UDP数据包都是通过公网{IP1:端口1}发送的;当内网主机通过这个socket向外部主机2发送UDP数据包时,NAT为其分配一个公网{IP2:端口2},以后内网主机发送给外部主机2的所有UDP数据包都是通过公网{IP2:端口2}发送的。公网{IP1:端口1}和公网{IP2:端口2}一定不会完全相同(即要么IP不同,要么端口不同,或者都不同)。这种情况下,外部主机只能在接收到内网主机发来的数据时,才能向内网主机回送数据。
RFC3489/STUN协议过程
STUN协议定义了三类测试过程来检测NAT类型,如下所述:
Test1:STUN Client通过端口{IP-c1:Port-c1}向STUN Server{IP-s1:Port-s1}发送一个Binding Request(没有设置任何属性)。STUN Server收到该请求后,通过端口{IP-s1:Port-s1}把它所看到的STUN Client的IP和端口{IP-m1,Port-m1}作为Binding Response的内容回送给STUN Client。
Test1#2:STUN Client通过端口{IP-c1:Port-c1}向STUN Server{IP-s2:Port-s2}发送一个Binding Request(没有设置任何属性)。STUN Server收到该请求后,通过端口{IP-s2:Port-s2}把它所看到的STUN Client的IP和端口{IP-m1#2,Port-m1#2}作为Binding Response的内容回送给STUN Client。
Test2:STUN Client通过端口{IP-c1:Port-c1}向STUN Server{IP-s1:Port-s1}发送一个Binding Request(设置了Change IP和Change Port属性)。STUN Server收到该请求后,通过端口{IP-s2:Port-s2}把它所看到的STUN Client的IP和端口{IP-m2,Port-m2}作为Binding Response的内容回送给STUN Client。
Test3:STUN Client通过端口{IP-c1:Port-c1}向STUN Server{IP-s1:Port-s1}发送一个Binding Request(设置了Change Port属性)。STUN Server收到该请求后,通过端口{IP-s1:Port-s2}把它所看到的STUN Client的IP和端口{IP-m3,Port-m3}作为Binding Response的内容回送给STUN Client。
NAT类型检测过程如下(在RFC3489中或者在Wiki上都可以找到流程图):
1. 进行Test1。如果STUN Client不能够收到STUN Server的应答(重复多次确认),那么说明该STUN Client是UDP Blocked类型(也有可能是STUN Server不可到达,这里不考虑这种情形);否则,STUN Client把返回的{IP-m1,Port-m1}和本地的{IP-c1:Port-c1}进行比较(只需要比较IP即可),如果相同,说明本机直接连接于公网,否则本机位于NAT之后,但还需要进一步判断具体类型。
1.1. 如果本机直接连接于公网,进行Test2。如果STUN Client不能够收到STUN Server的应答(重复多次确认),那么说明该STUN Client是Symmetric Firewall类型;否则,该STUN Client是Open Internet类型。
1.2. 如果本机位于NAT之后,进行Test2。如果STUN Client能够收到STUN Server的应答,那么说明该STUN Client是Full Cone NAT;否则,需要进一步进行测试。
1.2.1. 进行Test1#2。STUN Client比较IP-m1和IP-m1#2是否相同,如果不相同,那么说明该STUN Client是Symmetric NAT类型;否则,需要进一步进行测试。
1.2.1.1 进行Test3。如果STUN Client能够收到STUN Server的应答,那么说明该STUN Client是Restricted Cone NAT类型;否则,该STUN Client是Port Restricted Cone NAT类型。
一些说明:
1. 只需要进行Test2,即可判断出是否为Open Internet或Full Cone Nat类型。
STUN实现
1.STUN Client and Server
library()
这个库实现了RFC3489中的STUN协议。其中,Client程序输出结果意义如下:
(1)"Open"表示这里的Open Internet
(2)"Independent Mapping, Independent Filter"表示这里的Full Cone NAT
(3)"Independedt Mapping, Address Dependendent Filter"表示这里的Restricted
Core NAT
(4)"Indepndent Mapping, Port Dependent Filter"表示这里的Port Restricted Core
NAT
(5)"Dependent Mapping"表示这里的Symmetric NAT
(6)"Firewall"表示这里的Symmetric Firewall
(7)"Blocked or could not reach STUN server"表示这里的UDP Blocked
2. reTurn ()
实现了RFC5389中的STUN协议和TURN协议。
网上一些可用STUN Server(注意:STUN协议指定默认端口为3478)
(这个STUN Server的实现好像有问题,测试结果与前面三个不相同)
注解
[1] RFC3489中的STUN协议(Simple Traversal of UDP Through
NATs)是一个完整的NAT穿透方案,但其修订版本(RFC5389)把STUN协议(Session Traversal Utilities
for
NAT)定位于为穿透NAT提供工具,并不提供一个完整的解决方案。此外,RFC3489只提供了UDP的NAT穿透,而RFC5389还支持TCP的穿
透)。
Reference
1.
2.
阅读(2418) | 评论(0) | 转发(0) |