UDP打洞技术依赖于由公共防火墙和cone NAT,允许适当的有计划的端对端应用程序通过
NAT“打洞”,即使当双方的主机都处于NAT之后。这种技术在 RFC3027的5.1节[NAT PROT]
中进行了重点介绍,并且在Internet[KEGEL]中进行了非正式的描叙,还应用到了最新的一些协
议,例如[TEREDO,ICE]协议中。不过,我们要注意的是,“术”如其名,UDP打洞技术的可靠
性全都要依赖于UDP。
这里将考虑两种典型场景,来介绍连接的双方应用程序如何按照计划的进行通信的,第一
种场景,我们假设两个客户端都处于不同的NAT之后;第二种场景,我们假设两个客户端都处
于同一个NAT之后,但是它们彼此都不知道(他们在同一个NAT中)。
3.3.1. Peers behind different NATs 处于不同NAT之后的客户端通信
我们假设 Client A 和 Client B 都拥有自己的私有IP地址,并且都处在不同的NAT之后,端对端
的程序运行于 CLIENT A,CLIENT B,S之间,并且它们都开放了UDP端口1234。 CLIENT A和
CLIENT B首先分别与S建立通信会话,这时NAT A把它自己的UDP端口62000分配给CLIENT A
与S的会话,NAT B也把自己的UDP端口31000分配给CLIENT B与S的会话。
假如这个时候 CLIENT A 想与 CLIENT B建立一条UDP通信直连,如果 CLIENT A只是简单的
发送一个UDP信息到CLIENT B的公网地址138.76.29.7:31000的话,NAT B会不加考虑的将这个
信息丢弃(除非NAT B是一个 full cone NAT),因为 这个UDP信息中所包含的地址信息,与
CLIENT B和服务器S建立连接时存储在NAT B中的服务器S的地址信息不符。同样的,CLIENT
B如果做同样的事情,发送的UDP信息也会被 NAT A 丢弃。
假如 CLIENT A 开始发送一个 UDP 信息到 CLIENT B 的公网地址上,与此同时,他又通
过S中转发送了一个邀请信息给CLIENT B,请求CLIENT B也给CLIENT A发送一个UDP信息到
CLIENT A的公网地址上。这时CLIENT A向CLIENT B的公网IP(138.76.29.7:31000)发送的信息
导致 NAT A 打开一个处于 CLIENT A的私有地址和CLIENT B的公网地址之间的新的通信会
话,与此同时,NAT B 也打开了一个处于CLIENT B的私有地址和CLIENT A的公网地址
(155.99.25.11:62000)之间的新的通信会话。一旦这个新的UDP会话各自向对方打开了,CLIENT
A和CLIENT B之间就可以直接通信,而无需S来牵线搭桥了。(这就是所谓的打洞技术)!
UDP打洞技术有很多实用的地方:第一,一旦这种处于NAT之后的端对端的直连建立之
后,连接的双方可以轮流担任 对方的“媒人”,把对方介绍给其他的客户端,这样就极大的
降低了服务器S的工作量;第二,应用程序不用关心这个NAT是属于cone还是symmetric,即便
要,如果连接的双方有一方或者双方都恰好不处于NAT之后,基于上叙的步骤,他们之间还是
可以建立很好的通信通道;第三,打洞技术能够自动运作在多重NAT之后,不论连接的双方经
过多少层NAT才到达Internet,都可以进行通信。
3.3.2. Peers behind the same NAT 客户端都处于相同的NAT之后
现在让我们来考虑一下两个客户端(很有可能不知不觉的就会)同时位于相同的NAT之后,
而且是在同一个子网内部的情况, Client A与S之间的会话使用了NAT的62000端口,Client B与
S之间的会话使用了62001端口
我们假设,Client A 和 Client B 要使用上一节我们所描述的“UDP打洞技术”,并通过服
务器S这个“媒人”来认识,这样Client A 和Client B首先从服务端S得到了彼此的公网IP地址和
端口,然后就往对方的公网IP地址和端口上发送消息。在这种情况下,如果NAT 仅仅允许在内
部网主机与其他内部网主机(处于同一个NAT之后的网络主机)之间打开UDP会话通信通道,
而内部网主机与其他外部网主机就不允许的话,那么Client A 和Client B就可以通话了。我们把
这种情形叫做“loopback translation”(“回环转换”),因为数据包首先从局域网的私有IP发送到
NAT转换,然后“绕一圈”,再回到局域网中来,但是这样总比这些数据通过公网传送好。举
例来说,当 Client A发送了一个UDP数据包到 Client B的公网IP地址,这个数据包的报头中就会
有一个源地址10.0.0.1:124和一个目标地址155.99.25.11:62001。NAT接收到这个包以后,就会
(进行地址转换)解析出这个包中有一个公网地址源地址155.99.25.11:62000和一个目标地址
10.1.1.3:1234,然后再发送给B,虽说NAT支持“loopback translation”,我们也发现,在这种情形
下,这个解析和发送的过程有些多余,并且这个Client A 和Client B 之间的对话可能潜在性地给
NAT增加了负担。
其实,解决这个问题的方案是显而易见的。当 Client A和ClientB 最初通过服务器S交换彼此
的地址信息时,它们应该发现了自己的IP地址和端口,也就是自己的 Local IP,同时,加上
Server S发现的它们的公网地址和端口(即NAT分配给它们的) 。两个客户端同时的发送数据
包到对方的公网地址和私有地址上,然后选择首先使得通信成功的那个地址就可以了。如果两
个客户端都位于同一个NAT之后,那么发往私有地址的数据包应该先于发往公网地址的数据包
到达,这样就建立了一个不包括NAT的直连通信通道。如果两个客户端位于不同NAT之后,虽
然发送到对方私有地址的数据包会毫无疑问的发送失败,但还是很有可能使用他们各自的公网
IP地址来建立一条通信通道的。所以检测这些数据包的方法和工作就变得非常重要,不论如
何,只要双方都处于不同NAT之后,就完全有可能 Client A 想发送到 Client B 的信息会被发到
别的无关的地方去,反之亦然(Client B 想发送到 Client A的消息也会被发到别的无关的地方
去)。