穿越NAT的p2p通信方法研究

日期:2008-12-08 来源:P2P网  作者:未知 字体:大 中 小

<script src="http://www.ppcn.net/ads/baiducpro.js" type="text/javascript"></script>

内容概述:在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连接的思想已经成为了更加通用的“打洞”技术的基本思想。
3 UDP打洞方式
即使两个p2p客户端都位于NAT设备后面,UDP打洞方式也能够通过已知的服务器实现p2p客户端直连。该技术在RFC 3027的第5.1节中曾有所提及,在网络上可以找到对其较模糊的描述,在最近的IP协议实验中得到应用,在多种在线游戏协议中得到了应用。
3.1 集中服务器
打洞技术假定客户端A和B可以与公网内的已知的集中服务器建立UDP连接(可以互发UDP数据包)。当一个客户端在S上登陆的时候,服务器记录 下该客户端的两个endpoints(IP地址,UDP端口),一个是该客户端确信自己是通过该ip和端口与服务器S进行通信的,另一个是服务器S记录下 的由服务器“观察”到的该客户端实际与自己通信所使用的ip和端口。我们可以把前一个endpoint看作是客户端的内网ip和端口,把后一个 endpoint看作是客户端的内网ip和端口经过NAT转换后的公网ip和端口。服务器可以从客户端的登陆消息的消息体中得到该客户端的内网 endpoint相关信息,可以通过对登陆消息的IP或UDP头得到该客户端的公网endpoint。如果该客户端不是位于NAT设备后面,那么采用上述 方法得到的两个endpoint的值应该完全相同。
也有一些“弱智”的NAT设备会扫描UDP数据包的包体,寻找4字节的位域,看上去很像IP地址的位域,并且把它们改为与IP头一样的地址。为了避免这种行为的NAT设备对UDP数据包包体的修改,应用程序可以采用直接对IP地址的值进行加密的方式骗过NAT设备的检查。
3.2 建立p2p的session
假定A要发起对B的直接连接,“打洞”过程如下所示:(endpoint指ip地址和端口的配对)(1)A最初不知道如何向B发起连接,于是A向服务器S发送消息,请求S帮助建立与B的UDP连接。
(2)S将含有B的公网和内网的endpoint发给A,同时,S将含有A的公网和内网的endpoint的用于请求连接的消息也发给B。一旦这些消息顺利到达,A与B就都知道了对方的公网和内网的endpoint。
(3)当A收到由S发来的包含B的公网和内网endpoint的消息,A开始向这些B的endpoint发送UDP数据包,并且A会自动锁定第 一个给出响应的B的endpoint。同理,当B收到由S发来的A的公网和内网endpoint以后,也会开始向A的公网和内网的endpoint发送 UDP数据包,并且自动锁定第一个得到A的回应的endpoint。由于A与B的互相向对方发送UDP数据包的操作是异步的,所以A和B发送数据包的时间 先后并没有严格的时序要求。
下面我们就来看一下这三个角色之间是如何进行UDP“打洞”的。在这里我们分为三种具体情景来讨论:第一种也是最“简单”的一种情景,两个客户 端都位于同一个NAT设备后面,位于同一个内网中;第二种也是最普遍的一种情景,两个客户端分别位于不同的NAT设备后面,分属不同的内网;第三种是客户 端位于两层NAT设备之后,通常最上层的NAT是由ISP网络提供商,第二层的NAT是家用的NAT路由器之类的设备。
通常情况下由应用程序自身确定的网络物理层连接方式是很困难的,有时甚至是不可能的,即使是上述的若干种情景下可以穿越NAT,也只是代表在一 定时期内有效,而不是永久有效的。诸如STUN之类的网络协议或许可以提供必要的NAT信息,但在遇到多层NAT设备的时候,通常这些信息也不是完全完整 和有效的。尽管如此,只要NAT设备的响应是“合理”的,在通常情况下“打洞”技术还是能够在应用程序对网络状况一无所知的前提下自动适用于多数场合。 (“合理”的NAT响应将在第五章中详细讨论)
3.3 p2p客户端位于同一个NAT设备后面
首先假设两个客户端位于同一个NAT设备后面,并且位于相同的内网(相同的私有IP地址域)如图4所示。A与S建立了UDP连接,经过NAT转换后,A的公网端口被映射为62000。B同样与S建立了UDP连接,公网端口映射为62005。
(图4)
假设A想通过服务器S做为介绍人,发起对B的连接。A向S发出消息请求与B进行连接。S将B的公网endpoint(即公网ip和port)以 及内网endpoint(即内网ip和port)发给A,同时把A的公网、内网的endpoints发给B。由A和B发往对方公网endpoint的 UDP数据包能否被对方收到,这取决于当前的NAT是否支持“发夹”转换(hairpin转换,也就是同一台设备,不同端口之间的UDP数据包能否到达, 详见3.5节)。但是A与B往对方内网endpoint发送的UDP数据包是一定可以到达的,无论如何,内网数据包不需要路由,并且速度更快。A与B有很 大的可能性采用内网的endpoint进行常规的p2p通信。
假定NAT设备支持“发夹”转换,应用程序也忽略由内网endpoint的连接,那么A、B会采用公网endpoint做为p2p通信的连接, 这势必会造成数据包无谓地经过NAT设备,这是一种对资源的浪费。我们会在第六节讨论这种情况,毕竟支持“发夹”转换的NAT设备还远没有对“打洞”技术 支持的NAT设备多。就目前的网络情况而言,应用程序在“打洞”的时候,最好还是把公网endpoint和内网endpoint都实验一下。
3.4 p2p客户端位于不同的NAT设备后面
假定A与B在不同的NAT设备后面,分属不同的内网,如图5所示。A与B都经由各自的NAT设备与服务器S建立了UDP连接,A与B的本地端口 号均为4321,服务器S的公网端口号为1234。在“向外”session中,A的公网IP被映射为155.99.25.11,公网端口为62000, B的公网IP被映射为138.76.29.7,公网端口为31000。
如下所示:客户端A-->本地IP:10.0.0.1,本地端口:4321,公网IP:155.99.25.11,公网端口:62000客户端B-->本地IP:10.1.1.3,本地端口:4321,公网IP:138.76.29.7,公网端口:31000
(图 5)
在A向服务器S发送的登陆消息体中,会包含A的内网endpoint信息,即10.0.0.1:4321;服务器S会记录下A的内网 endpoint,同时会把自己观察到的A的公网endpoint记录下来,即155.99.25.11:62000。同理,服务器S会记录下B的内网 endpoint,10.1.1.3:4321和由S观察到的B的公网endpoint,138.76.29.7:31000。无论A与B二者任何一方向 S发送p2p连接请求,服务器都会将其记录下来的上述的公网、内网endpoint发送给A、B。
由于A、B分属不同的内网,它们彼此的内网endpoint无法在公网中路由,所以发往各自内网endpoint的UDP数据包会发送到错误的 主机或者根本不存在的主机。因此应用程序对于收到的消息必须经过授权和过滤,只有通过授权的的消息才能是从对方的endpoint发出来的,例如,可以在 消息中加入对方的程序名称、加密算法,或者至少是一个双方都从服务器S上的预先得到的随机数字。
现在假定A的第一个消息将发往B的公网endpoint,如图5所示。该消息途经A的NAT设备,并在该设备上生成了一个“向外”的 session。新的session源endpoint是10.0.0.1:4321该endpoint和A与服务器S的建立连接的时候NAT生成的源 endpoint一样,但它的目的endpoint不同。如果A的NAT设备给出的响应是“友好”的,那么A的NAT设备将保留A的内网 endpoint,并且所有来自A的源endpoint(10.0.0.1:4321)的数据包都沿用A与S事先建立起来的session,公网 endpoint均为(155.99.25.11:62000)。A向B的公网endpoint发送消息的过程就是“打洞”的过程,从A的内网的角度来看 应为从(10.0.0.1:4321)发往(138.76.29.7:31000),从A的在其NAT设备上建立的session来看,是从 (155.99.25.11:62000)发到(138.76.29.7:31000)。
如果A发给B的公网endpoint的消息包在B向A发送消息包之前到达B的NAT设备,B的NAT会认为A发过来的消息是未经授权的公网消 息,会丢弃掉该数据包。B发往A的消息包根上述的过程一样,会在B的NAT上建立一个(10.1.1.3:4321,155.99.25.11: 62000)的session(通常也会沿用B与S连接时建立的session,只是该session现在不光可以接受由S发给B的消息,还可以接受从A 的NAT设备-155.99.25.11:6200发来的消息)
一旦A与B都向对方的NAT在公网上的endpoint发送了数据包,就打开了A与B之间的“洞”,A与B向对方的公网endpoint发送数 据,等效为向对方的客户端直接发送UDP数据包了。一旦应用程序确认已经可以通过往对方的公网endpoint发送数据包的方式让数据包到达NAT后面的 目的应用程序,程序会自动停止继续发送用于“打洞”的数据包,转而开始真正的p2p数据传输。
3.5 p2p客户端位于多层NAT设备后面
有的网络拓扑结构包含了多个NAT设备,如果没有掌握该拓扑结构的详细信息,两个客户端之间是无法建立“最优化”的p2p路由的。现在我们来讨 论最后一种情况,如图6所示。假定NAT C是由ISP(Internet Service Provider)提供的工业级的NAT设备,NAT C提供将多个下属的用户NAT或用户节点映射到有限的几个公网IP的服务,NAT A和NAT B做为NAT C的内网节点将把用户的家庭网络或内部网络接入NAT C的内网,然后用户的内部网络就可以经由NAT C访问公网了。从这种拓扑结构上来看,只有服务器S与NAT C是真正拥有公网可路由IP地址的设备,而NAT A和NAT B所使用的“公网”IP地址,实际上是由ISP服务提供商设定的(相对于NAT C而言)内网地址(本位的后续部分我把这个由ISP提供的内网地址相对于NAT A和NAT B称之为“伪”公网地址),同理隶属于NAT A与NAT B的客户端,相对与NAT A,NAT B而言,它们处于NAT A,NAT B的内网,以此类推,客户端可以放到到多层NAT设备后面。客户端A和客户端B发起对服务器S的连接的时候,就会依次在NAT A和NAT B上建立向外的session,而NAT A、NAT B要联入公网的时候,会在NAT C上再建立向外的session。
(图 6)
现在假定客户端A和B希望通过UDP“打洞”完成两个客户端的p2p直连。最优化的路由策略是客户端A向客户端B的“伪公网”IP上发送数据 包,即ISP服务提供商指定的内网IP,NAT B的“伪”公网endpoint,10.0.1.2:55000。由于从服务器S的角度只能观察到真正的公网地址,也就是NAT A,NAT B在NAT C建立的session的真正的公网地址155.99.25.11:62000以及155.99.25.11:62005,所以非常不幸,客户端A与客户 端B是无法通过服务器S知道这些“伪”公网的地址的。而且即使客户端A和B通过某种手段可以得到NAT A和NAT B的“伪”公网地址,我们仍然不建议采用上述的“最优化”的打洞方式,这是因为这些地址是由ISP服务提供商提供的或许会存在与客户端本身所在的内网地址 重复的可能性。(例如:NAT A的内网的IP地址域恰好与NAT A在NAT C的“伪”公网IP地址域重复,这样就会导致打洞数据包无法发出的问题)
因此客户端别无选择,只能使用由公网服务器S观察到的A,B的公网endpoint进行“打洞”操作,用于“打洞”的数据包将由NAT C进行转发,这里NAT C是否支持“发夹”转换或“环路”转换非常重要,否则数据包将无法由NAT C转发给NAT A和NAT B,进而无法到达客户端A和B。当客户端A向客户端B的公网endpoint(155.99.25.11:62005)发送UDP数据包的时候,NAT A首先把数据包的源endpoint由A的内网endpoint(10.0.0.1:4321)转换为“伪”公网endpoint(10.0.1.1: 45000),现在数据包到了NAT C,NAT C应该可以识别出来该数据包是要发往自身转换过的公网endpoint,如果NAT C可以给出“合理”响应的话,NAT C将把该数据包的源endpoint改为155.99.25.11:62000,目的endpoint改为10.0.1.2:55000,即NAT B的“伪”公网endpoint,NAT B最后会将收到的数据包发往客户端B。同样,由B发往A的数据包也会经过类似的过程。也有很多NAT设备不支持类似这样的“发夹”转换,但是已经有越来越 多的NAT设备生产厂商开始加入对该转换的支持。
3.6 UDP在空闲状态下的超时问题
由于UDP转换协议提供的“洞”不是绝对可靠的,多数NAT设备内部都有一个UDP转换的空闲状态计时器,如果在一段时间内没有UDP数据通 信,NAT设备会关掉由“打洞”操作打出来的“洞”,做为应用程序来讲如果想要做到与设备无关,就最好在穿越NAT的以后设定一个穿越的有效期。很遗憾目 前没有标准有效期,这个有效期与NAT设备内部的配置有关,最短的只有20秒左右。在这个有效期内,即使没有p2p数据包需要传输,应用程序为了维持该 “洞”可以正常工作,也必须向对方发送“打洞”维持包。这个维持包是需要双方应用都发送的,只有一方发送不会维持另一方的session正常工作。除了频 繁发送“打洞”维持包以外,还有一个方法就是在当前的“洞”有效期过期之前,p2p客户端双方重新“打洞”,丢弃原有的“洞”,这也不失为一个有效的方 法。

4 关于TCP打洞技术建立穿越NAT设备的p2p的TCP连接只比UDP复杂一点点,TCP协议的“打洞”从协议层来看是与UDP的“打洞”过程非常相似 的。尽管如此,基于TCP协议的打洞至今为止还没有被很好的理解,这也造成了对其提供支持的NAT设备不是很多。在NAT设备支持的前提下,基于TCP的 “打洞”技术实际上与基于UDP的“打洞”技术一样快捷、可靠。实际上,只要NAT设备支持的话,基于TCP的p2p技术的健壮性将比基于UDP的技术的 更强一些,因为TCP协议的状态机给出了一种标准的方法来精确的获取某个TCP session的生命期,而UDP协议则无法做到这一点。4.1 套接字和TCP端口的重用实现基于TCP协议的p2p“打洞”过程中,最主要的问题不是来自于TCP协议,而是来自于来自于应用程序的API接口。这是由 于标准的伯克利(Berkeley)套接字的API是围绕着构建客户端/服务器程序而设计的,API允许TCP流套接字通过调用connect()函数来 建立向外的连接,或者通过listen()和accept函数接受来自外部的连接,但是,API不提供类似UDP那样的,同一个端口既可以向外连接,又能 够接受来自外部的连接。而且更糟的是,TCP的套接字通常仅允许建立1对1的响应,即应用程序在将一个套接字绑定到本地的一个端口以后,任何试图将第二个 套接字绑定到该端口的操作都会失败。为了让TCP“打洞”能够顺利工作,我们需要使用一个本地的TCP端口来监听来自外部的TCP连接,同时建立多个向外 的TCP连接。幸运的是,所有的主流操作系统都能够支持特殊的TCP套接字参数,通常叫做“SO_REUSEADDR”,该参数允许应用程序将多个套接字 绑定到本地的一个endpoint(只要所有要绑定的套接字都设置了SO_REUSEADDR参数即可)。BSD系统引入了SO_REUSEPORT参 数,该参数用于区分端口重用还是地址重用,在这样的系统里面,上述所有的参数必须都设置才行。4.2 打开p2p的TCP流假定客户端A希望建立与B的TCP连接。我们像通常一样假定A和B已经与公网上的已知服务器S建立了TCP连接。服务器记录下来每个 联入的客户端的公网和内网的endpoints,如同为UDP服务的时候一样。从协议层来看,TCP“打洞”与UDP“打洞”是几乎完全相同的过程。1、 客户端A使用其与服务器S的连接向服务器发送请求,要求服务器S协助其连接客户端B。2、S将B的公网和内网的TCP endpoint返回给A,同时,S将A的公网和内网的endpoint发送给B。3、客户端A和B使用连接S的端口异步地发起向对方的公网、内网 endpoint的TCP连接,同时监听各自的本地TCP端口是否有外部的连接联入。4、A和B开始等待向外的连接是否成功,检查是否有新连接联入。如果 向外的连接由于某种网络错误而失败,如:“连接被重置”或者“节点无法访问”,客户端只需要延迟一小段时间(例如延迟一秒钟),然后重新发起连接即可,延 迟的时间和重复连接的次数可以由应用程序编写者来确定。5、TCP连接建立起来以后,客户端之间应该开始鉴权操作,确保目前联入的连接就是所希望的连接。 如果鉴权失败,客户端将关闭连接,并且继续等待新的连接联入。客户端通常采用“先入为主”的策略,只接受第一个通过鉴权操作的客户端,然后将进入p2p通 信过程不再继续等待是否有新的连接联入。

(图 7)

与UDP 不同的是,使用UDP协议的每个客户端只需要一个套接字即可完成与服务器S通信,并同时与多个p2p客户端通信的任务,而TCP客户端必须处理多个套接字 绑定到同一个本地TCP端口的问题,如图7所示。现在来看更加实际的一种情景,A与B分别位于不同的NAT设备后面,如图5所示,并且假定图中的端口号是 TCP协议的端口号,而不是UDP的端口号。图中向外的连接代表A和B向对方的内网endpoint发起的连接,这些连接或许会失败或者无法连接到对方。 如同使用UDP协议进行“打洞”操作遇到的问题一样,TCP的“打洞”操作也会遇到内网的IP与“伪”公网IP重复造成连接失败或者错误连接之类的问题。 客户端向彼此公网endpoint发起连接的操作,会使得各自的NAT设备打开新的“洞”允许A与B的TCP数据通过。如果NAT设备支持TCP“打洞” 操作的话,一个在客户端之间的基于TCP协议的流通道就会自动建立起来。如果A向B发送的第一个SYN包发到了B的NAT设备,而B在此前没有向A发送 SYN包,B的NAT设备会丢弃这个包,这会引起A的“连接失败”或“无法连接”问题。而此时,由于A已经向B发送过SYN包,B发往A的SYN包将被看 作是由A发往B的包的回应的一部分,所以B发往A的SYN包会顺利地通过A的NAT设备,到达A,从而建立起A与B的p2p连接。4.3 从应用程序的角度来看TCP“打洞”从应用程序的角度来看,在进行TCP“打洞”的时候都发生了什么呢?假定A首先向B发出SYN包,该包发往B的公网 endpoint,并且被B的NAT设备丢弃,但是B发往A的公网endpoint的SYN包则通过A的NAT到达了A,然后,会发生以下的两种结果中的 一种,具体是哪一种取决于操作系统对TCP协议的实现:(1)A的TCP实现会发现收到的SYN包就是其发起连接并希望联入的B的SYN包,通俗一点来说 就是“说曹操,曹操到”的意思,本来A要去找B,结果B自己找上门来了。A的TCP协议栈因此会把B做为A向B发起连接connect的一部分,并认为连 接已经成功。程序A调用的异步connect()函数将成功返回,A的listen()等待从外部联入的函数将没有任何反映。此时,B联入A的操作在A程 序的内部被理解为A联入B连接成功,并且A开始使用这个连接与B开始p2p通信。由于收到的SYN包中不包含A需要的ACK数据,因此,A的TCP将用 SYN-ACK包回应B的公网endpoint,并且将使用先前A发向B的SYN包一样的序列号。一旦B的TCP收到由A发来的SYN-ACK包,则把自 己的ACK包发给A,然后两端建立起TCP连接。简单的说,第一种,就是即使A发往B的SYN包被B的NAT丢弃了,但是由于B发往A的包到达了A。结果 是,A认为自己连接成功了,B也认为自己连接成功了,不管是谁成功了,总之连接是已经建立起来了。(2)另外一种结果是,A的TCP实现没有像(1)中所 讲的那么“智能”,它没有发现现在联入的B就是自己希望联入的。就好比在机场接人,明明遇到了自己想要接的人却不认识,误认为是其它的人,安排别人给接走 了,后来才知道是自己错过了机会,但是无论如何,人已经接到了任务已经完成了。然后,A通过常规的listen()函数和accept()函数得到与B的 连接,而由A发起的向B的公网endpoint的连接会以失败告终。尽管A向B的连接失败,A仍然得到了B发起的向A的连接,等效于A与B之间已经联通, 不管中间过程如何,A与B已经连接起来了,结果是A和B的基于TCP协议的p2p连接已经建立起来了。第一种结果适用于基于BSD的操作系统对于TCP的 实现,而第二种结果更加普遍一些,多数linux和windows系统都会按照第二种结果来处理。

Peer-to-Peer Communication Across Network Address Translators

Bryan Ford
Massachusetts Institute of Technology
baford (at) mit.edu

Pyda Srisuresh
Caymas Systems, Inc.
srisuresh (at) yahoo.com

Dan Kegel
dank (at) kegel.com

J'fais des trous, des petits trous
toujours des petits trous

     - S. Gainsbourg

Abstract:

Network Address Translation (NAT) causes well-known difficulties for peer-to-peer (P2P) communication, since the peers involved may not be reachable at any globally valid IP address. Several NAT traversal techniques are known, but their documentation is slim, and data about their robustness or relative merits is slimmer. This paper documents and analyzes one of the simplest but most robust and practical NAT traversal techniques, commonly known as “hole punching.” Hole punching is moderately well-understood for UDP communication, but we show how it can be reliably used to set up peer-to-peer TCP streams as well. After gathering data on the reliability of this technique on a wide variety of deployed NATs, we find that about 82% of the NATs tested support hole punching for UDP, and about 64% support hole punching for TCP streams. As NAT vendors become increasingly conscious of the needs of important P2P applications such as Voice over IP and online gaming protocols, support for hole punching is likely to increase in the future.

1 Introduction

The combined pressures of tremendous growth and massive security challenges have forced the Internet to evolve in ways that make life difficult for many applications. The Internet's original uniform address architecture, in which every node has a globally unique IP address and can communicate directly with every other node, has been replaced with a new de facto Internet address architecture, consisting of a global address realm and many private address realms interconnected by Network Address Translators (NAT). In this new address architecture, illustrated in Figure 1 , only nodes in the “main,” global address realm can be easily contacted from anywhere in the network, because only they have unique, globally routable IP addresses. Nodes on private networks can connect to other nodes on the same private network, and they can usually open TCP or UDP connections to “well-known” nodes in the global address realm. NATs on the path allocate temporary public endpoints for outgoing connections, and translate the addresses and port numbers in packets comprising those sessions, while generally blocking all incoming traffic unless otherwise specifically configured.

Figure 1: Public and private IP address domains

The Internet's new de facto address architecture is suitable for client/server communication in the typical case when the client is on a private network and the server is in the global address realm. The architecture makes it difficult for two nodes on different private networks to contact each other directly, however, which is often important to the “peer-to-peer” communication protocols used in applications such as teleconferencing and online gaming. We clearly need a way to make such protocols function smoothly in the presence of NAT.

One of the most effective methods of establishing peer-to-peer communication between hosts on different private networks is known as “hole punching.” This technique is widely used already in UDP-based applications, but essentially the same technique also works for TCP. Contrary to what its name may suggest, hole punching does not compromise the security of a private network. Instead, hole punching enables applications to function within the the default security policy of most NATs, effectively signaling to NATs on the path that peer-to-peer communication sessions are “solicited” and thus should be accepted. This paper documents hole punching for both UDP and TCP, and details the crucial aspects of both application and NAT behavior that make hole punching work.

Unfortunately, no traversal technique works with all existing NATs, because NAT behavior is not standardized. This paper presents some experimental results evaluating hole punching support in current NATs. Our data is derived from results submitted by users throughout the Internet by running our “NAT Check” tool over a wide variety of NATs by different vendors. While the data points were gathered from a “self-selecting” user community and may not be representative of the true distribution of NAT implementations deployed on the Internet, the results are nevertheless generally encouraging.

While evaluating basic hole punching, we also point out variations that can make hole punching work on a wider variety of existing NATs at the cost of greater complexity. Our primary focus, however, is on developing the simplest hole punching technique that works cleanly and robustly in the presence of “well-behaved” NATs in any reasonable network topology. We deliberately avoid excessively clever tricks that may increase compatibility with some existing “broken” NATs in the short term, but which only work some of the time and may cause additional unpredictability and network brittleness in the long term.

Although the larger address space of IPv6 [3 ] may eventually reduce the need for NAT, in the short term IPv6 is increasing the demand for NAT, because NAT itself provides the easiest way to achieve interoperability between IPv4 and IPv6 address domains [24 ]. Further, the anonymity and inaccessibility of hosts on private networks has widely perceived security and privacy benefits. Firewalls are unlikely to go away even when there are enough IP addresses: IPv6 firewalls will still commonly block unsolicited incoming traffic by default, making hole punching useful even to IPv6 applications.

The rest of this paper is organized as follows. Section 2 introduces basic terminology and NAT traversal concepts. Section 3 details hole punching for UDP, and Section 4 introduces hole punching for TCP. Section 5 summarizes important properties a NAT must have in order to enable hole punching. Section 6 presents our experimental results on hole punching support in popular NATs, Section 7 discusses related work, and Section 8 concludes.

2 General Concepts

This section introduces basic NAT terminology used throughout the paper, and then outlines general NAT traversal techniques that apply equally to TCP and UDP.

2.1 NAT Terminology

This paper adopts the NAT terminology and taxonomy defined in RFC 2663 [21 ], as well as additional terms defined more recently in RFC 3489 [19 ].

Of particular importance is the notion of session. A session endpoint for TCP or UDP is an (IP address, port number) pair, and a particular session is uniquely identified by its two session endpoints. From the perspective of one of the hosts involved, a session is effectively identified by the 4-tuple (local IP, local port, remote IP, remote port). The direction of a session is normally the flow direction of the packet that initiates the session: the initial SYN packet for TCP, or the first user datagram for UDP.

Of the various flavors of NAT, the most common type is traditional or outbound NAT, which provides an asymmetric bridge between a private network and a public network. Outbound NAT by default allows only outbound sessions to traverse the NAT: incoming packets are dropped unless the NAT identifies them as being part of an existing session initiated from within the private network. Outbound NAT conflicts with peer-to-peer protocols because when both peers desiring to communicate are “behind” (on the private network side of) two different NATs, whichever peer tries to initiate a session, the other peer's NAT rejects it. NAT traversal entails making P2P sessions look like “outbound” sessions to both NATs.

Outbound NAT has two sub-varieties: Basic NAT , which only translates IP addresses, and Network Address/Port Translation (NAPT), which translates entire session endpoints. NAPT, the more general variety, has also become the most common because it enables the hosts on a private network to share the use of a single public IP address. Throughout this paper we assume NAPT, though the principles and techniques we discuss apply equally well (if sometimes trivially) to Basic NAT.

2.2 Relaying

The most reliable--but least efficient--method of P2P communication across NAT is simply to make the communication look to the network like standard client/server communication, through relaying. Suppose two client hosts and have each initiated TCP or UDP connections to a well-known server , at 's global IP address 18.181.0.31 and port number 1234. As shown in Figure 2 , the clients reside on separate private networks, and their respective NATs prevent either client from directly initiating a connection to the other. Instead of attempting a direct connection, the two clients can simply use the server to relay messages between them. For example, to send a message to client , client simply sends the message to server along its already-established client/server connection, and server forwards the message on to client using its existing client/server connection with .

Figure 2: NAT Traversal by Relaying

Relaying always works as long as both clients can connect to the server. Its disadvantages are that it consumes the server's processing power and network bandwidth, and communication latency between the peering clients is likely increased even if the server is well-connected. Nevertheless, since there is no more efficient technique that works reliably on all existing NATs, relaying is a useful fall-back strategy if maximum robustness is desired. The TURN protocol [18 ] defines a method of implementing relaying in a relatively secure fashion.

2.3 Connection Reversal

Some P2P applications use a straightforward but limited technique, known as connection reversal , to enable communication when both hosts have connections to a well-known rendezvous server and only one of the peers is behind a NAT, as shown in Figure 3 . If wants to initiate a connection to , then a direct connection attempt works automatically, because is not behind a NAT and 's NAT interprets the connection as an outgoing session. If wants to initiate a connection to , however, any direct connection attempt to is blocked by 's NAT. can instead relay a connection request to through a well-known server , asking to attempt a “reverse” connection back to . Despite the obvious limitations of this technique, the central idea of using a well-known rendezvous server as an intermediary to help set up direct peer-to-peer connections is fundamental to the more general hole punching techniques described next.

Figure 3: NAT Traversal by Connection Reversal

3 UDP Hole Punching

UDP hole punching enables two clients to set up a direct peer-to-peer UDP session with the help of a well-known rendezvous server, even if the clients are both behind NATs. This technique was mentioned in section 5.1 of RFC 3027 [10 ], documented more thoroughly elsewhere on the Web [13 ], and used in recent experimental Internet protocols [17 ,11 ]. Various proprietary protocols, such as those for on-line gaming, also use UDP hole punching.

3.1 The Rendezvous Server

Hole punching assumes that the two clients, and , already have active UDP sessions with a rendezvous server . When a client registers with , the server records two endpoints for that client: the (IP address, UDP port) pair that the client believes itself to be using to talk with , and the (IP address, UDP port) pair that the server observes the client to be using to talk with it. We refer to the first pair as the client's private endpoint and the second as the client's public endpoint. The server might obtain the client's private endpoint from the client itself in a field in the body of the client's registration message, and obtain the client's public endpoint from the source IP address and source UDP port fields in the IP and UDP headers of that registration message. If the client is not behind a NAT, then its private and public endpoints should be identical.

A few poorly behaved NATs are known to scan the body of UDP datagrams for 4-byte fields that look like IP addresses, and translate them as they would the IP address fields in the IP header. To be robust against such behavior, applications may wish to obfuscate IP addresses in messages bodies slightly, for example by transmitting the one's complement of the IP address instead of the IP address itself. Of course, if the application is encrypting its messages, then this behavior is not likely to be a problem.

3.2 Establishing Peer-to-Peer Sessions

Suppose client wants to establish a UDP session directly with client . Hole punching proceeds as follows:

  1. initially does not know how to reach , so asks for help establishing a UDP session with .
  2. replies to with a message containing 's public and private endpoints. At the same time, uses its UDP session with to send a connection request message containing 's public and private endpoints. Once these messages are received, and know each other's public and private endpoints.
  3. When receives 's public and private endpoints from , starts sending UDP packets to both of these endpoints, and subsequently “locks in” whichever endpoint first elicits a valid response from . Similarly, when receives 's public and private endpoints in the forwarded connection request, starts sending UDP packets to at each of 's known endpoints, locking in the first endpoint that works. The order and timing of these messages are not critical as long as they are asynchronous.

We now consider how UDP hole punching handles each of three specific network scenarios. In the first situation, representing the “easy” case, the two clients actually reside behind the same NAT, on one private network. In the second, most common case, the clients reside behind different NATs. In the third scenario, the clients each reside behind two levels of NAT: a common “first-level” NAT deployed by an ISP for example, and distinct “second-level” NATs such as consumer NAT routers for home networks.

It is in general difficult or impossible for the application itself to determine the exact physical layout of the network, and thus which of these scenarios (or the many other possible ones) actually applies at a given time. Protocols such as STUN [19 ] can provide some information about the NATs present on a communication path, but this information may not always be complete or reliable, especially when multiple levels of NAT are involved. Nevertheless, hole punching works automatically in all of these scenarios without the application having to know the specific network organization, as long as the NATs involved behave in a reasonable fashion. (“Reasonable” behavior for NATs will be described later in Section 5 .)

3.3 Peers Behind a Common NAT

First consider the simple scenario in which the two clients (probably unknowingly) happen to reside behind the same NAT, and are therefore located in the same private IP address realm, as shown in Figure 4 . Client has established a UDP session with server , to which the common NAT has assigned its own public port number 62000. Client has similarly established a session with , to which the NAT has assigned public port number 62005.

Figure 4: UDP Hole Punching, Peers Behind a Common NAT

Suppose that client uses the hole punching technique outlined above to establish a UDP session with , using server as an introducer. Client sends a message requesting a connection to . responds to with 's public and private endpoints, and also forwards 's public and private endpoints to . Both clients then attempt to send UDP datagrams to each other directly at each of these endpoints. The messages directed to the public endpoints may or may not reach their destination, depending on whether or not the NAT supports hairpin translation as described below in Section 3.5 . The messages directed at the private endpoints do reach their destinations, however, and since this direct route through the private network is likely to be faster than an indirect route through the NAT anyway, the clients are most likely to select the private endpoints for subsequent regular communication.

By assuming that NATs support hairpin translation, the application might dispense with the complexity of trying private as well as public endpoints, at the cost of making local communication behind a common NAT unnecessarily pass through the NAT. As our results in Section 6 show, however, hairpin translation is still much less common among existing NATs than are other “P2P-friendly” NAT behaviors. For now, therefore, applications may benefit substantially by using both public and private endpoints.

3.4 Peers Behind Different NATs

Suppose clients and have private IP addresses behind different NATs, as shown in Figure 5 . and have each initiated UDP communication sessions from their local port 4321 to port 1234 on server . In handling these outbound sessions, NAT has assigned port 62000 at its own public IP address, 155.99.25.11, for the use of 's session with , and NAT has assigned port 31000 at its IP address, 138.76.29.7, to 's session with .

Figure 5: UDP Hole Punching, Peers Behind Different NATs

In 's registration message to , reports its private endpoint to as 10.0.0.1:4321, where 10.0.0.1 is 's IP address on its own private network. records 's reported private endpoint, along with 's public endpoint as observed by itself. 's public endpoint in this case is 155.99.25.11:62000, the temporary endpoint assigned to the session by the NAT. Similarly, when client registers, records 's private endpoint as 10.1.1.3:4321 and 's public endpoint as 138.76.29.7:31000.

Now client follows the hole punching procedure described above to establish a UDP communication session directly with . First, sends a request message to asking for help connecting with . In response, sends 's public and private endpoints to , and sends 's public and private endpoints to . and each start trying to send UDP datagrams directly to each of these endpoints.

Since and are on different private networks and their respective private IP addresses are not globally routable, the messages sent to these endpoints will reach either the wrong host or no host at all. Because many NATs also act as DHCP servers, handing out IP addresses in a fairly deterministic way from a private address pool usually determined by the NAT vendor by default, it is quite likely in practice that 's messages directed at 's private endpoint will reach some (incorrect) host on 's private network that happens to have the same private IP address as does. Applications must therefore authenticate all messages in some way to filter out such stray traffic robustly. The messages might include application-specific names or cryptographic tokens, for example, or at least a random nonce pre-arranged through .

Now consider 's first message sent to 's public endpoint, as shown in Figure 5 . As this outbound message passes through 's NAT, this NAT notices that this is the first UDP packet in a new outgoing session. The new session's source endpoint (10.0.0.1:4321) is the same as that of the existing session between and , but its destination endpoint is different. If NAT is well-behaved, it preserves the identity of 's private endpoint, consistently translating all outbound sessions from private source endpoint 10.0.0.1:4321 to the corresponding public source endpoint 155.99.25.11:62000. 's first outgoing message to 's public endpoint thus, in effect, “punches a hole” in 's NAT for a new UDP session identified by the endpoints (10.0.0.1:4321, 138.76.29.7:31000) on 's private network, and by the endpoints (155.99.25.11:62000, 138.76.29.7:31000) on the main Internet.

If 's message to 's public endpoint reaches 's NAT before 's first message to has crossed 's own NAT, then 's NAT may interpret 's inbound message as unsolicited incoming traffic and drop it. 's first message to 's public address, however, similarly opens a hole in 's NAT, for a new UDP session identified by the endpoints (10.1.1.3:4321, 155.99.25.11:62000) on 's private network, and by the endpoints (138.76.29.7:31000, 155.99.25.11:62000) on the Internet. Once the first messages from and have crossed their respective NATs, holes are open in each direction and UDP communication can proceed normally. Once the clients have verified that the public endpoints work, they can stop sending messages to the alternative private endpoints.

3.5 Peers Behind Multiple Levels of NAT

In some topologies involving multiple NAT devices, two clients cannot establish an “optimal” P2P route between them without specific knowledge of the topology. Consider a final scenario, depicted in Figure 6 . Suppose NAT is a large industrial NAT deployed by an internet service provider (ISP) to multiplex many customers onto a few public IP addresses, and NATs and are small consumer NAT routers deployed independently by two of the ISP's customers to multiplex their private home networks onto their respective ISP-provided IP addresses. Only server and NAT have globally routable IP addresses; the “public” IP addresses used by NAT and NAT are actually private to the ISP's address realm, while client 's and 's addresses in turn are private to the addressing realms of NAT and NAT , respectively. Each client initiates an outgoing connection to server as before, causing NATs and each to create a single public/private translation, and causing NAT to establish a public/private translation for each session.

Figure 6: UDP Hole Punching, Peers Behind Multiple Levels of NAT

Now suppose and attempt to establish a direct peer-to-peer UDP connection via hole punching. The optimal routing strategy would be for client to send messages to client 's “semi-public” endpoint at NAT , 10.0.1.2:55000 in the ISP's addressing realm, and for client to send messages to 's “semi-public” endpoint at NAT , namely 10.0.1.1:45000. Unfortunately, and have no way to learn these addresses, because server only sees the truly global public endpoints of the clients, 155.99.25.11:62000 and 155.99.25.11:62005 respectively. Even if and had some way to learn these addresses, there is still no guarantee that they would be usable, because the address assignments in the ISP's private address realm might conflict with unrelated address assignments in the clients' private realms. (NAT 's IP address in NAT 's realm might just as easily have been 10.1.1.3, for example, the same as client 's private address in NAT 's realm.)

The clients therefore have no choice but to use their global public addresses as seen by for their P2P communication, and rely on NAT providing hairpin or loopback translation. When sends a UDP datagram to 's global endpoint, 155.99.25.11:62005, NAT first translates the datagram's source endpoint from 10.0.0.1:4321 to 10.0.1.1:45000. The datagram now reaches NAT , which recognizes that the datagram's destination address is one of NAT 's own translated public endpoints. If NAT is well-behaved, it then translates both the source and destination addresses in the datagram and “loops” the datagram back onto the private network, now with a source endpoint of 155.99.25.11:62000 and a destination endpoint of 10.0.1.2:55000. NAT finally translates the datagram's destination address as the datagram enters 's private network, and the datagram reaches . The path back to works similarly. Many NATs do not yet support hairpin translation, but it is becoming more common as NAT vendors become aware of this issue.

3.6 UDP Idle Timeouts

Since the UDP transport protocol provides NATs with no reliable, application-independent way to determine the lifetime of a session crossing the NAT, most NATs simply associate an idle timer with UDP translations, closing the hole if no traffic has used it for some time period. There is unfortunately no standard value for this timer: some NATs have timeouts as short as 20 seconds. If the application needs to keep an idle UDP session active after establishing the session via hole punching, the application must send periodic keep-alive packets to ensure that the relevant translation state in the NATs does not disappear.

Unfortunately, many NATs associate UDP idle timers with individual UDP sessions defined by a particular pair of endpoints, so sending keep-alives on one session will not keep other sessions active even if all the sessions originate from the same private endpoint. Instead of sending keep-alives on many different P2P sessions, applications can avoid excessive keep-alive traffic by detecting when a UDP session no longer works, and re-running the original hole punching procedure again “on demand.”

4 TCP Hole Punching

Establishing peer-to-peer TCP connections between hosts behind NATs is slightly more complex than for UDP, but TCP hole punching is remarkably similar at the protocol level. Since it is not as well-understood, it is currently supported by fewer existing NATs. When the NATs involved do support it, however, TCP hole punching is just as fast and reliable as UDP hole punching. Peer-to-peer TCP communication across well-behaved NATs may in fact be more robust than UDP communication, because unlike UDP, the TCP protocol's state machine gives NATs on the path a standard way to determine the precise lifetime of a particular TCP session.

4.1 Sockets and TCP Port Reuse

The main practical challenge to applications wishing to implement TCP hole punching is not a protocol issue but an application programming interface (API) issue. Because the standard Berkeley sockets API was designed around the client/server paradigm, the API allows a TCP stream socket to be used to initiate an outgoing connection via connect() , or to listen for incoming connections via listen() and accept() , but not both . Further, TCP sockets usually have a one-to-one correspondence to TCP port numbers on the local host: after the application binds one socket to a particular local TCP port, attempts to bind a second socket to the same TCP port fail.

For TCP hole punching to work, however, we need to use a single local TCP port to listen for incoming TCP connections and to initiate multiple outgoing TCP connections concurrently. Fortunately, all major operating systems support a special TCP socket option, commonly named SO_REUSEADDR , which allows the application to bind multiple sockets to the same local endpoint as long as this option is set on all of the sockets involved. BSD systems have introduced a SO_REUSEPORT option that controls port reuse separately from address reuse; on such systems both of these options must be set.

4.2 Opening Peer-to-Peer TCP Streams

Suppose that client wishes to set up a TCP connection with client . We assume as usual that both and already have active TCP connections with a well-known rendezvous server . The server records each registered client's public and private endpoints, just as for UDP. At the protocol level, TCP hole punching works almost exactly as for UDP:

  1. Client uses its active TCP session with to ask for help connecting to .
  2. replies to with 's public and private TCP endpoints, and at the same time sends 's public and private endpoints to .
  3. From the same local TCP ports that and used to register with , and each asynchronously make outgoing connection attempts to the other's public and private endpoints as reported by , while simultaneously listening for incoming connections on their respective local TCP ports.
  4. and wait for outgoing connection attempts to succeed, and/or for incoming connections to appear. If one of the outgoing connection attempts fails due to a network error such as “connection reset” or “host unreachable,” the host simply re-tries that connection attempt after a short delay (e.g., one second), up to an application-defind maximum timeout period.
  5. When a TCP connection is made, the hosts authenticate each other to verify that they connected to the intended host. If authentication fails, the clients close that connection and continue waiting for others to succeed. The clients use the first successfully authenticated TCP stream resulting from this process.

Unlike with UDP, where each client only needs one socket to communicate with both and any number of peers simultaneously, with TCP each client application must manage several sockets bound to a single local TCP port on that client node, as shown in Figure 7 . Each client needs a stream socket representing its connection to , a listen socket on which to accept incoming connections from peers, and at least two additional stream sockets with which to initiate outgoing connections to the other peer's public and private TCP endpoints.

Figure 7: Sockets versus Ports for TCP Hole Punching

Consider the common-case scenario in which the clients and are behind different NATs, as shown in Figure 5 , and assume that the port numbers shown in the figure are now for TCP rather than UDP ports. The outgoing connection attempts and make to each other's private endpoints either fail or connect to the wrong host. As with UDP, it is important that TCP applications authenticate their peer-to-peer sessions, due of the likelihood of mistakenly connecting to a random host on the local network that happens to have the same private IP address as the desired host on a remote private network.

The clients' outgoing connection attempts to each other's public endpoints, however, cause the respective NATs to open up new “holes” enabling direct TCP communication between and . If the NATs are well-behaved, then a new peer-to-peer TCP stream automatically forms between them. If 's first SYN packet to reaches 's NAT before 's first SYN packet to reaches 's NAT, for example, then 's NAT may interpret 's SYN as an unsolicited incoming connection attempt and drop it. 's first SYN packet to should subsequently get through, however, because 's NAT sees this SYN as being part of the outbound session to that 's first SYN had already initiated.

4.3 Behavior Observed by the Application

What the client applications observe to happen with their sockets during TCP hole punching depends on the timing and the TCP implementations involved. Suppose that 's first outbound SYN packet to 's public endpoint is dropped by NAT , but 's first subsequent SYN packet to 's public endpoint gets through to before 's TCP retransmits its SYN. Depending on the operating system involved, one of two things may happen:

  • 's TCP implementation notices that the session endpoints for the incoming SYN match those of an outbound session was attempting to initiate. 's TCP stack therefore associates this new session with the socket that the local application on was using to connect() to 's public endpoint. The application's asynchronous connect() call succeeds, and nothing happens with the application's listen socket.

    Since the received SYN packet did not include an ACK for 's previous outbound SYN, 's TCP replies to 's public endpoint with a SYN-ACK packet, the SYN part being merely a replay of 's original outbound SYN, using the same sequence number. Once 's TCP receives 's SYN-ACK, it responds with its own ACK for 's SYN, and the TCP session enters the connected state on both ends.

  • Alternatively, 's TCP implementation might instead notice that has an active listen socket on that port waiting for incoming connection attempts. Since 's SYN looks like an incoming connection attempt, 's TCP creates a new stream socket with which to associate the new TCP session, and hands this new socket to the application via the application's next accept() call on its listen socket. 's TCP then responds to with a SYN-ACK as above, and TCP connection setup proceeds as usual for client/server-style connections.

    Since 's prior outbound connect() attempt to used a combination of source and destination endpoints that is now in use by another socket, namely the one just returned to the application via accept() , 's asynchronous connect() attempt must fail at some point, typically with an “address in use” error. The application nevertheless has the working peer-to-peer stream socket it needs to communicate with , so it ignores this failure.

The first behavior above appears to be usual for BSD-based operating systems, whereas the second behavior appears more common under Linux and Windows.

4.4 Simultaneous TCP Open

Suppose that the timing of the various connection attempts during the hole punching process works out so that the initial outgoing SYN packets from both clients traverse their respective local NATs, opening new outbound TCP sessions in each NAT, before reaching the remote NAT. In this “lucky” case, the NATs do not reject either of the initial SYN packets, and the SYNs cross on the wire between the two NATs. In this case, the clients observe an event known as a simultaneous TCP open : each peer's TCP receives a “raw” SYN while waiting for a SYN-ACK. Each peer's TCP responds with a SYN-ACK, whose SYN part essentially “replays” the peer's previous outgoing SYN, and whose ACK part acknowledges the SYN received from the other peer.

What the respective applications observe in this case again depends on the behavior of the TCP implementations involved, as described in the previous section. If both clients implement the second behavior above, it may be that all of the asynchronous connect() calls made by the application ultimately fail, but the application running on each client nevertheless receives a new, working peer-to-peer TCP stream socket via accept() --as if this TCP stream had magically “created itself” on the wire and was merely passively accepted at the endpoints! As long as the application does not care whether it ultimately receives its peer-to-peer TCP sockets via connect() or accept() , the process results in a working stream on any TCP implementation that properly implements the standard TCP state machine specified in RFC 793 [23 ].

Each of the alternative network organization scenarios discussed in Section 3 for UDP works in exactly the same way for TCP. For example, TCP hole punching works in multi-level NAT scenarios such as the one in Figure 6 as long as the NATs involved are well-behaved.

4.5 Sequential Hole Punching

In a variant of the above TCP hole punching procedure implemented by the NatTrav library [4 ], the clients attempt connections to each other sequentially rather than in parallel. For example: (1) informs via of its desire to communicate, without simultaneously listening on its local port; (2) makes a connect() attempt to , which opens a hole in 's NAT but then fails due to a timeout or RST from 's NAT or a RST from itself; (3) closes its connection to and does a listen() on its local port; (4) in turn closes its connection with , signaling to attempt a connect() directly to .

This sequential procedure may be particularly useful on Windows hosts prior to XP Service Pack 2, which did not correctly implement simultaneous TCP open, or on sockets APIs that do not support the SO_REUSEADDR functionality. The sequential procedure is more timing-dependent, however, and may be slower in the common case and less robust in unusual situations. In step (2), for example, must allow its “doomed-to-fail” connect() attempt enough time to ensure that at least one SYN packet traverses all NATs on its side of the network. Too little delay risks a lost SYN derailing the process, whereas too much delay increases the total time required for hole punching. The sequential hole punching procedure also effectively “consumes” both clients' connections to the server , requiring the clients to open fresh connections to for each new P2P connection to be forged. The parallel hole punching procedure, in contrast, typically completes as soon as both clients make their outgoing connect() attempts, and allows each client to retain and re-use a single connection to indefinitely.

5 Properties of P2P-Friendly NATs

This section describes the key behavioral properties NATs must have in order for the hole punching techniques described above to work properly. Not all current NAT implementations satisfy these properties, but many do, and NATs are gradually becoming more “P2P-friendly” as NAT vendors recognize the demand for peer-to-peer protocols such as voice over IP and on-line gaming.

This section is not meant to be a complete or definitive specification for how NATs “should” behave; we provide it merely for information about the most commonly observed behaviors that enable or break P2P hole punching. The IETF has started a new working group, BEHAVE, to define official “best current practices” for NAT behavior. The BEHAVE group's initial drafts include the considerations outlined in this section and others; NAT vendors should of course follow the IETF working group directly as official behavioral standards are formulated.

5.1 Consistent Endpoint Translation

The hole punching techniques described here only work automatically if the NAT consistently maps a given TCP or UDP source endpoint on the private network to a single corresponding public endpoint controlled by the NAT. A NAT that behaves in this way is referred to as a cone NAT in RFC 3489 [19 ] and elsewhere, because the NAT “focuses” all sessions originating from a single private endpoint through the same public endpoint on the NAT.

Consider again the scenario in Figure 5 , for example. When client initially contacted the well-known server , NAT chose to use port 62000 at its own public IP address, 155.99.25.11, as a temporary public endpoint to representing 's private endpoint 10.0.0.1:4321. When later attempts to establish a peer-to-peer session with by sending a message from the same local private endpoint to 's public endpoint, depends on NAT preserving the identity of this private endpoint, and re-using the existing public endpoint of 155.99.25.11:62000, because that is the public endpoint for to which will be sending its corresponding messages.

A NAT that is only designed to support client/server protocols will not necessarily preserve the identities of private endpoints in this way. Such a NAT is a symmetric NAT in RFC 3489 terminology. For example, after the NAT assigns the public endpoint 155.99.25.11:62000 to client 's session with server , the NAT might assign a different public endpoint, such as 155.99.25.11:62001, to the P2P session that tries to initiate with . In this case, the hole punching process fails to provide connectivity, because the subsequent incoming messages from reach NAT at the wrong port number.

Many symmetric NATs allocate port numbers for successive sessions in a fairly predictable way. Exploiting this fact, variants of hole punching algorithms [9 ,1 ] can be made to work “much of the time” even over symmetric NATs by first probing the NAT's behavior using a protocol such as STUN [19 ], and using the resulting information to “predict” the public port number the NAT will assign to a new session. Such prediction techniques amount to chasing a moving target, however, and many things can go wrong along the way. The predicted port number might already be in use causing the NAT to jump to another port number, for example, or another client behind the same NAT might initiate an unrelated session at the wrong time so as to allocate the predicted port number. While port number prediction can be a useful trick for achieving maximum compatibility with badly-behaved existing NATs, it does not represent a robust long-term solution. Since symmetric NAT provides no greater security than a cone NAT with per-session traffic filtering, symmetric NAT is becoming less common as NAT vendors adapt their algorithms to support P2P protocols.

5.2 Handling Unsolicited TCP Connections

When a NAT receives a SYN packet on its public side for what appears to be an unsolicited incoming connection attempt, it is important that the NAT just silently drop the SYN packet. Some NATs instead actively reject such incoming connections by sending back a TCP RST packet or even an ICMP error report, which interferes with the TCP hole punching process. Such behavior is not necessarily fatal, as long as the applications re-try outgoing connection attempts as specified in step 4 of the process described in Section 4.2 , but the resulting transient errors can make hole punching take longer.

5.3 Leaving Payloads Alone

A few existing NATs are known to scan “blindly” through packet payloads for 4-byte values that look like IP addresses, and translate them as they would the IP address in the packet header, without knowing anything about the application protocol in use. This bad behavior fortunately appears to be uncommon, and applications can easily protect themselves against it by obfuscating IP addresses they send in messages, for example by sending the bitwise complement of the desired IP address.

5.4 Hairpin Translation

Some multi-level NAT situations require hairpin translation support in order for either TCP or UDP hole punching to work, as described in Section 3.5 . The scenario shown in Figure 6 , for example, depends on NAT providing hairpin translation. Support for hairpin translation is unfortunately rare in current NATs, but fortunately so are the network scenarios that require it. Multi-level NAT is becoming more common as IPv4 address space depletion continues, however, so support for hairpin translation is important in future NAT implementations.

6 Evaluation of Existing NATs

To evaluate the robustness of the TCP and UDP hole punching techniques described in this paper on a variety of existing NATs, we implemented and distributed a test program called NAT Check [16 ], and solicited data from Internet users about their NATs.

NAT Check's primary purpose is to test NATs for the two behavioral properties most crucial to reliable UDP and TCP hole punching: namely, consistent identity-preserving endpoint translation (Section 5.1 ), and silently dropping unsolicited incoming TCP SYNs instead of rejecting them with RSTs or ICMP errors (Section 5.2 ). In addition, NAT Check separately tests whether the NAT supports hairpin translation (Section 5.4 ), and whether the NAT filters unsolicited incoming traffic at all. This last property does not affect hole punching, but provides a useful indication the NAT's firewall policy.

NAT Check makes no attempt to test every relevant facet of NAT behavior individually: a wide variety of subtle behavioral differences are known, some of which are difficult to test reliably [12 ]. Instead, NAT Check merely attempts to answer the question, “how commonly can the proposed hole punching techniques be expected to work on deployed NATs, under typical network conditions?”

6.1 Test Method

NAT Check consists of a client program to be run on a machine behind the NAT to be tested, and three well-known servers at different global IP addresses. The client cooperates with the three servers to check the NAT behavior relevant to both TCP and UDP hole punching. The client program is small and relatively portable, currently running on Windows, Linux, BSD, and Mac OS X. The machines hosting the well-known servers all run FreeBSD.

6.1.1 UDP Test

To test the NAT's behavior for UDP, the client opens a socket and binds it to a local UDP port, then successively sends “ping”-like requests to servers 1 and 2, as shown in Figure 8 . These servers each respond to the client's pings with a reply that includes the client's public UDP endpoint: the client's own IP address and UDP port number as observed by the server. If the two servers report the same public endpoint for the client, NAT Check assumes that the NAT properly preserves the identity of the client's private endpoint, satisfying the primary precondition for reliable UDP hole punching.

Figure 8: NAT Check Test Method for UDP

When server 2 receives a UDP request from the client, besides replying directly to the client it also forwards the request to server 3, which in turn replies to the client from its own IP address. If the NAT's firewall properly filters “unsolicited” incoming traffic on a per-session basis, then the client never sees these replies from server 3, even though they are directed at the same public port as the replies from servers 1 and 2.

To test the NAT for hairpin translation support, the client simply opens a second UDP socket at a different local port and uses it to send messages to the public endpoint representing the client's first UDP socket, as reported by server 2. If these messages reach the client's first private endpoint, then the NAT supports hairpin translation.

6.1.2 TCP Test

The TCP test follows a similar pattern as for UDP. The client uses a single local TCP port to initiate outbound sessions to servers 1 and 2, and checks whether the public endpoints reported by servers 1 and 2 are the same, the first precondition for reliable TCP hole punching.

The NAT's response to unsolicited incoming connection attempts also impacts the speed and reliability of TCP hole punching, however, so NAT Check also tests this behavior. When server 2 receives the client's request, instead of immediately replying to the client, it forwards a request to server 3 and waits for server 3 to respond with a “go-ahead” signal. When server 3 receives this forwarded request, it attempts to initiate an inbound connection to the client's public TCP endpoint. Server 3 waits up to five seconds for this connection to succeed or fail, and if the connection attempt is still “in progress” after five seconds, server 3 responds to server 2 with the “go-ahead” signal and continues waiting for up to 20 seconds. Once the client finally receives server 2's reply (which server 2 delayed waiting for server 3's “go-ahead” signal), the client attempts an outbound connection to server 3, effectively causing a simultaneous TCP open with server 3.

What happens during this test depends on the NAT's behavior as follows. If the NAT properly just drops server 3's “unsolicited” incoming SYN packets, then nothing happens on the client's listen socket during the five second period before server 2 replies to the client. When the client finally initiates its own connection to server 3, opening a hole through the NAT, the attempt succeeds immediately. If on the other hand the NAT does not drop server 3's unsolicited incoming SYNs but allows them through (which is fine for hole punching but not ideal for security), then the client receives an incoming TCP connection on its listen socket before receiving server 2's reply. Finally, if the NAT actively rejects server 3's unsolicited incoming SYNs by sending back TCP RST packets, then server 3 gives up and the client's subsequent attempt to connect to server 3 fails.

To test hairpin translation for TCP, the client simply uses a secondary local TCP port to attempt a connection to the public endpoint corresponding to its primary TCP port, in the same way as for UDP.

6.2 Test Results

The NAT Check data we gathered consists of 380 reported data points covering a variety of NAT router hardware from 68 vendors, as well as the NAT functionality built into different versions of eight popular operating systems. Only 335 of the total data points include results for UDP hairpin translation, and only 286 data points include results for TCP, because we implemented these features in later versions of NAT Check after we had already started gathering results. The data is summarized by NAT vendor in Table 1 ; the table only individually lists vendors for which at least five data points were available. The variations in the test results for a given vendor can be accounted for by a variety of factors, such as different NAT devices or product lines sold by the same vendor, different software or firmware versions of the same NAT implementation, different configurations, and probably occasional NAT Check testing or reporting errors.

Table 1: User Reports of NAT Support for UDP and TCP Hole Punching
    UDP TCP
    Hole   Hole  
    Punching Hairpin Punching Hairpin
NAT Hardware                
  Linksys 45/46 (98%) 5/42 (12%) 33/38 (87%) 3/38 (8%)
  Netgear 31/37 (84%) 3/35 (9%) 19/30 (63%) 0/30 (0%)
  D-Link 16/21 (76%) 11/21 (52%) 9/19 (47%) 2/19 (11%)
  Draytek 2/17 (12%) 3/12 (25%) 2/7 (29%) 0/7 (0%)
  Belkin 14/14 (100%) 1/14 (7%) 11/11 (100%) 0/11 (0%)
  Cisco 12/12 (100%) 3/9 (33%) 6/7 (86%) 2/7 (29%)
  SMC 12/12 (100%) 3/10 (30%) 8/9 (89%) 2/9 (22%)
  ZyXEL 7/9 (78%) 1/8 (13%) 0/7 (0%) 0/7 (0%)
  3Com 7/7 (100%) 1/7 (14%) 5/6 (83%) 0/6 (0%)
OS-based NAT                
  Windows 31/33 (94%) 11/32 (34%) 16/31 (52%) 28/31 (90%)
  Linux 26/32 (81%) 3/25 (12%) 16/24 (67%) 2/24 (8%)
  FreeBSD 7/9 (78%) 3/6 (50%) 2/3 (67%) 1/1 (100%)
All Vendors 310/380 (82%) 80/335 (24%) 184/286 (64%) 37/286 (13%)

Out of the 380 reported data points for UDP, in 310 cases (82%) the NAT consistently translated the client's private endpoint, indicating basic compatibility with UDP hole punching. Support for hairpin translation is much less common, however: of the 335 data points that include UDP hairpin translation results, only 80 (24%) show hairpin translation support.

Out of the 286 data points for TCP, 184 (64%) show compatibility with TCP hole punching: the NAT consistently translates the client's private TCP endpoint, and does not send back RST packets in response to unsolicited incoming connection attempts. Hairpin translation support is again much less common: only 37 (13%) of the reports showed hairpin support for TCP.

Since these reports were generated by a “self-selecting” community of volunteers, they do not constitute a random sample and thus do not necessarily represent the true distribution of the NATs in common use. The results are nevertheless encouraging: it appears that the majority of commonly-deployed NATs already support UDP and TCP hole punching at least in single-level NAT scenarios.

6.3 Testing Limitations

There are a few limitations in NAT Check's current testing protocol that may cause misleading results in some cases. First, we only learned recently that a few NAT implementations blindly translate IP addresses they find in unknown application payloads, and the NAT Check protocol currently does not protect itself from this behavior by obfuscating the IP addresses it transmits.

Second, NAT Check's current hairpin translation checking may yield unnecessarily pessimistic results because it does not use the full, two-way hole punching procedure for this test. NAT Check currently assumes that a NAT supporting hairpin translation does not filter “incoming” hairpin connections arriving from the private network in the way it would filter incoming connections arriving at the public side of the NAT, because such filtering is unnecessary for security. We later realized, however, that a NAT might simplistically treat any traffic directed at the NAT's public ports as “untrusted” regardless of its origin. We do not yet know which behavior is more common.

Finally, NAT implementations exist that consistently translate the client's private endpoint as long as only one client behind the NAT is using a particular private port number, but switch to symmetric NAT or even worse behaviors if two or more clients with different IP addresses on the private network try to communicate through the NAT from the same private port number. NAT Check could only detect this behavior by requiring the user to run it on two or more client hosts behind the NAT at the same time. Doing so would make NAT Check much more difficult to use, however, and impossible for users who only have one usable machine behind the NAT. Nevertheless, we plan to implement this testing functionality as an option in a future version of NAT Check.

6.4 Corroboration of Results

Despite testing difficulties such as those above, our results are generally corroborated by those of a large ISP, who recently found that of the top three consumer NAT router vendors, representing 86% of the NATs observed on their network, all three vendors currently produce NATs compatible with UDP hole punching [25 ]. Additional independent results recently obtained using the UDP-oriented STUN protocol [12 ], and STUNT, a TCP-enabled extension [8 ,9 ], also appear consistent with our results. These latter studies provide more information on each NAT by testing a wider variety of behaviors individually, instead of just testing for basic hole punching compatibility as NAT Check does. Since these more extensive tests require multiple cooperating clients behind the NAT and thus are more difficult to run, however, these results are so far available on a more limited variety of NATs.

7 Related Work

UDP hole punching was first explored and publicly documented by Dan Kegel [13 ], and is by now well-known in peer-to-peer application communities. Important aspects of UDP hole punching have also been indirectly documented in the specifications of several experimental protocols, such as STUN [19 ], ICE [17 ], and Teredo [11 ]. We know of no existing published work that thoroughly analyzes hole punching, however, or that points out the hairpin translation issue for multi-level NAT (Section 3.5 ).

We also know of no prior work that develops TCP hole punching in the symmetric fashion described here. Even the existence of the crucial SO_REUSEADDR /SO_REUSEPORT options in the Berkeley sockets API appears to be little-known among P2P application developers. NatTrav [4 ] implements a similar but asymmetric TCP hole punching procedure outlined earlier in Section 4.5 . NUTSS [9 ] and NATBLASTER [1 ] implement more complex TCP hole punching tricks that can work around some of the bad NAT behaviors mentioned in Section 5 , but they require the rendezvous server to spoof source IP addresses, and they also require the client applications to have access to “raw” sockets, usually available only at root or administrator privilege levels.

Protocols such as SOCKS [14 ], UPnP [26 ], and MIDCOM [22 ] allow applications to traverse a NAT through explicit cooperation with the NAT. These protocols are not widely or consistently supported by NAT vendors or applications, however, and do not appear to address the increasingly important multi-level NAT scenarios. Explicit control of a NAT further requires the application to locate the NAT and perhaps authenticate itself, which typically involves explicit user configuration. When hole punching works, in contrast, it works with no user intervention.

Recent proposals such as HIP [15 ] and FARA [2 ] extend the Internet's basic architecture by decoupling a host's identity from its location [20 ]. IPNL [7 ], UIP [5 ,6 ], and DOA [27 ] propose schemes for routing across NATs in such an architecture. While such extensions are probably needed in the long term, hole punching enables applications to work over the existing network infrastructure immediately with no protocol stack upgrades, and leaves the notion of “host identity” for applications to define.

8 Conclusion

Hole punching is a general-purpose technique for establishing peer-to-peer connections in the presence of NAT. As long as the NATs involved meet certain behavioral requirements, hole punching works consistently and robustly for both TCP and UDP communication, and can be implemented by ordinary applications with no special privileges or specific network topology information. Hole punching fully preserves the transparency that is one of the most important hallmarks and attractions of NAT, and works even with multiple levels of NAT--though certain corner case situations require hairpin translation, a NAT feature not yet widely implemented.

Acknowledgments

The authors wish to thank Dave Andersen for his crucial support in gathering the results presented in Section 6 . We also wish to thank Henrik Nordstrom, Christian Huitema, Justin Uberti, Mema Roussopoulos, and the anonymous USENIX reviewers for valuable feedback on early drafts of this paper. Finally, we wish to thank the many volunteers who took the time to run NAT Check on their systems and submit the results.

Bibliography

1
Andrew Biggadike, Daniel Ferullo, Geoffrey Wilson, and Adrian Perrig.
NATBLASTER: Establishing TCP connections between hosts behind NATs.
In ACM SIGCOMM Asia Workshop , Beijing, China, April 2005.
2
David Clark, Robert Braden, Aaron Falk, and Venkata Pingali.
FARA: Reorganizing the addressing architecture.
In ACM SIGCOMM FDNA Workshop , August 2003.
3
S. Deering and R. Hinden.
Internet protocol, version 6 (IPv6) specification, December 1998.
RFC 2460.
4
Jeffrey L. Eppinger.
TCP connections for P2P apps: A software approach to solving the NAT problem.
Technical Report CMU-ISRI-05-104, Carnegie Mellon University, January 2005.
5
Bryan Ford.
Scalable Internet routing on topology-independent node identities.
Technical Report MIT-LCS-TR-926, MIT Laboratory for Computer Science, October 2003.
6
Bryan Ford.
Unmanaged internet protocol: Taming the edge network management crisis.
In Second Workshop on Hot Topics in Networks , Cambridge, MA, November 2003.
7
Paul Francis and Ramakrishna Gummadi.
IPNL: A NAT-extended Internet architecture.
In ACM SIGCOMM , August 2002.
8
Saikat Guha and Paul Francis.
Simple traversal of UDP through NATs and TCP too (STUNT).
http://nutss.gforge.cis.cornell.edu/ .
9
Saikat Guha, Yutaka Takeday, and Paul Francis.
NUTSS: A SIP-based approach to UDP and TCP network connectivity.
In SIGCOMM 2004 Workshops , August 2004.
10
M. Holdrege and P. Srisuresh.
Protocol complications with the IP network address translator, January 2001.
RFC 3027.
11
C. Huitema.
Teredo: Tunneling IPv6 over UDP through NATs, March 2004.
Internet-Draft (Work in Progress).
12
C. Jennings.
NAT classification results using STUN, October 2004.
Internet-Draft (Work in Progress).
13
Dan Kegel.
NAT and peer-to-peer networking, July 1999.
http://www.alumni.caltech.edu/~dank/peer-nat.html .
14
M. Leech et al.
SOCKS protocol, March 1996.
RFC 1928.
15
R. Moskowitz and P. Nikander.
Host identity protocol architecture, April 2003.
Internet-Draft (Work in Progress).
16
NAT check.
http://midcom-p2p.sourceforge.net/ .
17
J. Rosenberg.
Interactive connectivity establishment (ICE), October 2003.
Internet-Draft (Work in Progress).
18
J. Rosenberg, C. Huitema, and R. Mahy.
Traversal using relay NAT (TURN), October 2003.
Internet-Draft (Work in Progress).
19
J. Rosenberg, J. Weinberger, C. Huitema, and R. Mahy.
STUN - simple traversal of user datagram protocol (UDP) through network address translators (NATs), March 2003.
RFC 3489.
20
J. Saltzer.
On the naming and binding of network destinations.
In P. Ravasio et al., editor, Local Computer Networks , pages 311-317. North-Holland, Amsterdam, 1982.
RFC 1498.
21
P. Srisuresh and M. Holdrege.
IP network address translator (NAT) terminology and considerations, August 1999.
RFC 2663.
22
P. Srisuresh, J. Kuthan, J. Rosenberg, A. Molitor, and A. Rayhan.
Middlebox communication architecture and framework, August 2002.
RFC 3303.
23
Transmission control protocol, September 1981.
RFC 793.
24
G. Tsirtsis and P. Srisuresh.
Network address translation - protocol translation (NAT-PT), February 2000.
RFC 2766.
25
Justin Uberti.
E-mail on IETF MIDCOM mailing list, February 2004.
Message-ID: <402CEB11.1060906@aol.com> .
26
UPnP Forum.
Internet gateway device (IGD) standardized device control protocol, November 2001.
http://www.upnp.org/ .
27
Michael Walfish, Jeremy Stribling, Maxwell Krohn, Hari Balakrishnan, Robert Morris, and Scott Shenker.
Middleboxes no longer considered harmful.
In USENIX Symposium on Operating Systems Design and Implementation , San Francisco, CA, December 2004.

穿越NAT的p2p通信方法研究相关推荐

  1. P2P通信原理与实现(C++),NAT,网络穿透原理

    1.简介 当今互联网到处存在着一些中间件(MIddleBoxes),如NAT和防火墙,导致两个(不在同一内网)中的客户端无法直接通信.这些问题即便是到了IPV6时代也会存在,因为即使不需要NAT,但还 ...

  2. 内网穿透实现P2P通信

    P2P 通信最大的障碍就是 NAT(网络地址转换),NAT 使得局域网内的设备可以与公网进行通讯,但是不同 NAT 下的设备之间通讯将会变得很困难.UDP 打洞就是用来使得设备间绕过 NAT 进行通讯 ...

  3. P2P通信基本原理与实现

    本文转载自: https://www.pppan.net/blog/detail/2017-12-16-p2p-over-middle-box 如有侵权,通知删除 P2P通信基本原理与实现 #P2P ...

  4. P2P通信原理与实现(C++)

    1.简介 当今互联网到处存在着一些中间件(MIddleBoxes),如NAT和防火墙,导致两个(不在同一内网)中的客户端无法直接通信.这些问题即便是到了IPV6时代也会存在,因为即使不需要NAT,但还 ...

  5. TCP实现P2P通信、TCP穿越NAT的方法、TCP打洞

    原文地址:http://www.vckbase.com/document/viewdoc/?id=1773 这个标题用了两个顿号三个名称,其实说得是同一个东西,只是网上有不同的说法罢了,另外好像还有人 ...

  6. P2P通信中的NAT/FW穿越

    摘要:P2P(Peer-to-Peer)通信的发展极其迅速,形成了很大的影响.和传统通信一样,P2P通信同样受到NAT/FW穿越问题的制约,因此解决好其相关的NAT/FW穿越问题非常重要.和传统通信相 ...

  7. stun turn ice等穿越NAT方法

    STUN(Simple Traversal of User Datagram Protocol through Network Address Translators (NATs),NAT的UDP简单 ...

  8. P2P网络“自由”穿越NAT的“秘密”

    P2P网络"自由"穿越NAT的"秘密"<?xml:namespace prefix = o ns = "urn:schemas-microsof ...

  9. P2P网络穿越 NAT穿越

    http://blog.csdn.net/mazidao2008/article/details/4933730 ------------------------------------------- ...

最新文章

  1. 可遇不可求的BUG之采用MYSQL odbc 3.51访问数据库返回值缺失
  2. jQuery中DOM操作
  3. centos7 mysql安装教程_centos7环境下MySQL安装教程
  4. freebsd java 能用吗_在FreeBSD 4.9下安装JAVA环境
  5. oracle form执行后左上角没出现oracle标记,oracle form学习笔记
  6. 关于Python中的错误与异常,你是否了解的够仔细?
  7. 55.函数模板指针匹配(模板自动匹配*多的)
  8. 验证方式二 html标签验证码,Django标签、转义及验证码生成
  9. JNI读取assets资源文件
  10. 图像处理六:预处理方法
  11. Cocoa中Core Data的简单介绍
  12. 手机 物理分辨率 逻辑分辨率
  13. php多合一安装包,DOXCX多合一小程序系统Sass平台源码分享
  14. Apple账号密码自动填充
  15. JAVA毕设项目html5在线医疗系统(Vue+Mybatis+Maven+Mysql+sprnig+SpringMVC)
  16. 微信最近点赞拿东西服务器,微信朋友圈点赞说明什么?点赞的行为背后隐藏着什么含义呢?...
  17. 你是胡萝卜,是鸡蛋,还是咖啡豆
  18. java计算机毕业设计手机测试管理系统源代码+数据库+系统+lw文档
  19. W10安装NoteBook(一个Python笔记软件)及使用方法
  20. 计算机及相关专业的同学如何规划大学四年?

热门文章

  1. PWM(脉冲宽度调制)信号原理
  2. 用命令提示符打开资源管理器目录
  3. 数据挖掘项目:金融风控-贷款违约预测
  4. 什么软件可以听学业水平测试网课,免费听网课app推荐
  5. Centos7.2安装搜狗拼音
  6. Solr之拼音检索。
  7. 英语六级试卷软件测试,背单词软件_2018年12月英语六级考试真题测试(11)含答案_沪江英语...
  8. 计算广告(一):在线广告概述
  9. 企业群发短信时为什么要找短信平台公司而不是直接找运营商发送
  10. vba 添加outlook 签名_如何在Outlook中使用宏发送邮件,并且使用已有签名?