在p2p通信领域中,由NAT(Network Address Translation,网络地址转换)引起的问题已经众所周知了,
它会导致在NAT内部的p2p客户端在无论以何种有效的公网ip都无法访问的问题。虽然目前已经发展出
多种穿越NAT的技术,但相关的技术文档却很少,用来证明这些技术的稳定性和优点的实际数据更少。
本文的目的在于描述和分析在实际中运用得最广泛、最可靠同时也是最简单的一种NAT穿越技术,该
技术通常被称为“打洞”技术。目前,“打洞”技术已经在UDP通信领域中得到了广泛的理解和应用,在此,
也将讨论如何利用它实现可靠的p2p的TCP流通信。在收集了大量的“打洞”技术可以穿越的NAT设备和
网络的数据以后,我们发现82%的已测NAT设备支持UDP形式的“打洞”穿越,64%的已测NAT设备支持TCP
流形式的“打洞”穿越。由于重量级p2p应用程序(如,VOIP、BT、在线游戏等)的用户需求量持续上升,
并且该事实也已经引起了NAT设备生产厂商的广泛关注,因此,我们认为未来会有越来越多的NAT设备
提供对“打洞”穿越技术的支持。
1、介绍
用户量高速增长以及大量安全问题的巨大压力迫使Internet技术不断向前发展,但是这些新兴的技术
很大程度地增加了应用程序开发的成本和复杂性。Internet最初的地址体系是每个节点有一个唯一不变
的全局地址,可以通过该地址直接与任何其它的节点进行通信,而现如今,该地址体系已经被新的实际
上广泛使用的地址体系所替换,新的地址体系是由全局地址域和通过NAT接入全局地址域的大量私有地址
域组成。在新的地址体系中(如图1所示),只有在“main”全局地址域中的节点可以在网络中很容易地与
任何其它的拥有全局地址的节点通信,因为该节点拥有全局的、唯一的、可路由的地址。在私有网络中的
节点可以与在同一个私有网络中的其它节点进行通信,并且在通常情况下可以向全局地址中的某个“著名”
的节点发起TCP连接或发送UDP数据包。NAT设备在此扮演的角色就是为从内网向公网发起的连接的节点
分配临时的转发session,将来自内网的数据包的地址和端口转换为公网的地址和端口,将来自公网的
数据包的地址和端口转换为内网的端口和地址,同时NAT将屏蔽所有未经授权的来自公网的数据包。
新的Internet地址体系非常适合于“客户端/服务器”这样的通信模式,一个典型的C/S通信模式是:
客户端在内网(私有地址域),服务器在公网(全局地址域),通过NAT将内网和公网连接起来。
这种地址体系使得在不同内网(私有地址域)中的两个节点很难直接通信,而这恰恰是p2p应用
(如,电话会议或在线游戏)中最基本的要求。很显然,我们需要一种方法即使在NAT设备存在的
前提下,仍然能够无障碍地实现p2p通信。
在不同内网的两个节点之间建立p2p连接的最有效的方法就是“打洞”。该技术在基于UDP的应用程序
中得到了广泛的应用,同样的,该技术也可以用于基于TCP的应用程序。有趣的是,与“打洞”字面
上的意思刚好相反,该技术不会影响到内网的安全。事实上,“打洞”技术使得p2p软件的绝大部分
功能都在NAT设备默认的安全策略的控制之下,这些都由NAT设备建立的session来管理。本文阐述
了适用于UDP和TCP的“打洞”技术,并详细描述了重要“打洞”过程中,应用程序和NAT设备之间的行为。
不幸的是,由于NAT设备的响应和行为不是标准的,所以没有任何技术可以穿越现有的所有NAT设备。
本文提供了一些在现有NAT设备上进行“打洞”的实验结果。我们收集的数据来自于互联网上使用了
“NAT Check”工具并在大量不同生产厂商的NAT设备上进行“打洞”实验的用户。由于数据是来自于
一个叫做“self-selecting”的用户社区,或许不会完全代表在Internet上真正部署和使用的NAT设备,
但是结果无论如何还是很令人兴奋的。
在做基本的“打洞”操作评估的时候,我们应该指出在现有的NAT设备“打洞”的复杂度上,不同的复杂度
会有不同的结果。但目前我们把讨论的重点集中于开发最简单的,可以应用于任何网络拓扑结构的、
稳定的、有正确NAT响应的NAT设备上的“打洞”技术。我们有意避免使用一些“聪明的小把戏”通过
欺骗某些NAT设备来达到短期内穿越较多的NAT设备,但从长期来看会引起网络未知错误的技术。
尽管引入IPv6会极大地增加互联网的地址空间,从而减少对于NAT设备的需求量,但短期内IPv6确实
增加了对NAT设备的需求量,因为NAT设备本身提供了一种方便的方法进行IPv4与IPv6地址域转换。
另外私有网络上建立匿名和加密访问节点也有利于组织机构的安全性以及不受外界干扰,这些都
意味着NAT还将存在相当长的一段时间。同样,防火墙技术也不会由于有了足够的ip地址而消失,
IPv6的防火墙仍然会默认丢掉所有未经授权的数据包,仍然可以让在IPv6环境下工作的应用程序
“打洞”。
本文接下来的部分按照如下的方式组织:
第二章介绍基本的NAT穿越概念和术语;第三章介绍UDP“打洞”过程;第四章介绍TCP“打洞”过程;
第五章介绍支持“打洞”的NAT设备必须具有那些特性;第六章介绍我们在目前流行的NAT设备上的
“打洞”实验结果;第七章讨论相关的网络问题;第八章全文总结以及结束语。
2、基本概念
本节介绍了本文使用到的基本的NAT术语,着重描述了适用于UDP和TCP两种协议的通用的NAT穿越技术。
2.1、NAT术语
本文绝大部分术语和分类来自于RFC 2663定义,另外一些来自于较新的RFC 3489中的定义。
理解session是很重要的。一个TCP或UDP的session endpoint是由一个IP地址,端口号组成,
每个session是由两个session endpoint构成。从内网节点的角度来看,一个session由4部分组成
分别为:本地IP,本地端口,远端IP,远端端口。session的方向通常代表了数据包的初始流动
的方向;对于TCP来说就是SYN包的流向,对于UDP来说就是第一个用户数据包的流向。
NAT有很多种,但最普遍的一种类型叫做“传统”NAT,或者“向外”NAT。他们在内网和公网之间提供了
一个“不对称”桥的映射。“向外”NAT在默认情况下只允许向外的session穿越NAT:
从外向内的的数据包都会被丢弃掉,除非NAT设备事先已经定义了这些从外向内的数据包是已存在的内网session的一部分。
“外向”NAT会造成p2p协议的混乱,因为当p2p的双方决定向在不同NAT后面的对方开始通信的时候,
无论哪一方试图初始化一个session,另一方的NAT都会拒绝这个请求。NAT穿越的核心思想就是让
p2p的双方的NAT看上去都是“向外”的NAT。
“向外”NAT有两种类型:
(1)“基础”NAT,该NAT只转换IP地址,不转换端口号。
(2)NAPT(Network Address/Port Translation)
NAPT转换整个session endpoints。由于NAPT允许内网的多个节点通过共享的方式使用同一个的公共
的IP地址,因此,支持NAPT的NAT设备才会越来越多。尽管本文通篇讨论的内容都是基于支持NAPT的
NAT设备的,但这些规律和技术同样适用于“基础”NAT。
2.2 转发方式
最可靠但同时也是效率最低的p2p穿越NAT进行通信的方法是采用类似C/S方式的转发。假定两个节点
A和B每个节点都有向外的TCP或UDP连接,联入公共的已知服务器S,S的公网IP地址是18.181.0.31,
端口号是1234(如图2所示),每个客户端位于不同的私有内网中,并且它们的NAT设备妨碍了客户
端之间直接的p2p连接。做为对直连方案的替代方案,两个客户端可以利用公共的服务器S进行
消息的转发。例如,A为了将消息送给B,A只需将消息发给S,然后由S转发给B,这一过程将使用A与
B事先与S建立好的连接。
转发方式通常只能在双方客户端都连接到服务器的时候有效。这种方式的缺点在于,它假定服务
器的处理能力和网络带宽以及通信延迟都是理想的情况下,不会受到客户端个数的影响。但是,由于
没有其它的方法能够像转发方式那样,可以穿越现存的所有NAT设备,因此在构建高可靠性的p2p系统
的时候,通过服务器转发的方式依旧是一个非常有用的保证系统可靠性的方法。TURN协议定义了如何
实现安全的转发方式。
2.3 反向连接方式
一些p2p的应用程序采用了直接但是有所限制的技术来实现NAT穿越,该技术叫做“反向连接”,这是用于
当两个节点联入服务器S的时候,只有一个一个节点在NAT设备的后面(如图3所示)。如果A希望建立与
B的连接,那么A可以直接联入B,因为B是在公网中存在的,没有经过NAT转换,而且A的NAT设备也允许
A直接由内网发起向外网的连接。如果B希望建立与A的连接,很不幸,A的NAT设备会阻止该操作,此时,
B可以借助于转发服务器S,向A发送“反向连接”请求,由A“主动”连接B,从而达到A与B的p2p通信的目的。
尽管该技术的局限性非常明显,但是使用已知的服务器做为中介辅助p2p客户端双方进行p2p连接的思想已经成为了更加通用的“打洞”技术的基本思想。