穿NAT的方法的核心思想及实现

来源:互联网 发布:关于网络暴力 编辑:程序博客网 时间:2024/04/28 12:43

本来题目是几种,不过写到这里的时候,其中的一些东西已经被其它文章所含概了,所以这里只谈NAT的穿透的核心思想:punch技术,我称之为对穿.

   (1)先来说对穿的工作原理

   在这里我用两个都是在port restrict cone NAT后面的UAC做例子,假设一个是 A,一个是D。两个NAT 分别是B和C。

   先来说对穿的过程

   STEP1:UAC A通过A的porta向STUN服务器发送数据包,得到本socket的NAT的外网IP和端口portnat,注意,此时,这个portnat已经和stun的IP和port绑定在了一起,这个断口将拒绝一切非STUN的IP和对应端口的数据包。

   STEP2:现在,假设另一IP(为E),通过某种方法(如sip server)得到了此IP和portnat,在t1时刻,开始不停通过porte向此IP和portnat发送数据包。很不幸的,根据port restrict cone NAT的原理,这些数据包将被NAT全部拒绝,因为此时,这个portnat已经被绑定给了STUN的IP和port,因此他拒绝一切非stun的IP和port发来的数据包,而E发来这些数据包不符合这个port的通过要求,因此这些数据被NAT全部过滤掉,也更不可能到达A。

   STEP3:在t2时刻A在次通过A的porta向E的IP和端口porte发送了若干个数据包。这是关键,然后如何呢?让我们来分析一下:

   对于NAT来说,A的发送port没有改变,因此根据CONE NAT的原理,它仍然用在step1中打开的端口portnat向E发送数据包。对应的,NAT的此port的帮定也就发生了变化,它允许来自E的porte端口的数据包通过NAT,到达A。这也就意味着,t2时刻以后的来自E的数据包A都可以接收到。

   (2)SIP中RTP流的对穿过程

   应该说,如果你理解了上面穿透过程,以下的东西是很好理解的。

   首先,A通过SIP信令得到D在NAT C的IP和RTP接收端口portd,并且开始向此IP和port发送RTP流。同样的D也随后想A的NAT B的IP和port发送RTP流。

   理想的情况,在A或D发送的RTP流还没有到达对方之前,A,D都已经开始了发送RTP流,这样,A和D发送出来的数据就都不会被对方的NAT拒绝。遗憾的是这是很难做到的,通常都是一方到达,而另一放的数据还没有开始发送,而在现实中,这种情况占了绝大部分。

   假设D发送过来的RTP流已经到达了A所在NAT B的RTP接收端口,而此时,A还没有通过此端口向D发送数据,那么这些包将被无情的拒绝。而一旦A通过这个端口发送了数据,那么以后D发送来的数据,能够全部通过NAT,到达A,这也就完成了RTP的穿越。同样的情况也发生在NAT C,A发送的数据也可以通过C到达D。

   (3)对称NAT下,对穿失败的原因所在

   实际上,对称NAT失去了可以对穿的基础:port不变。下面说下失败过程。

   当A通过本地端口PA向STUN服务器发送数据包,得到本端口在NAT上的影射端口PB,并把此端口作为RTP接收流的port。通过SIP信令,这个port被告之给了D,D随后向这个PORT发送数据包,此时,A通过本地端口PA向D发送数据包。如果是cone NAT,NAT仍然会用A向STUN发送数据的端口发送数据,可是,遗憾的是,对于对称NAT,NAT会重新打开一个新的port,用来发送给D的这些数据。也就是说,A期望这些数据通过最开始得到的影射端口PB来向D发送这些数据包,而NAT却没有这么做。所以,D发来的数据永远能不能满足进入规则,这些包将被永远丢弃。

   (4)额外的一些思考

   前面已经说过,在实际的应用中,一方的数据包都会在另外一放开始发送数据出去之前到达对方,这也就意味着这些数据包将被丢失。所以,在音频RTP传输中,你有可能只听到声音“喂”的后一半,虽然有些不舒服,但毕竟影响不大,还是可以被人接受的。

   然而在视频传输中,为了减少通过网络传输的流量,很多编码采取发一个I贞,然后发N个P贞,再发一个I贞的办法减小数据量。而发送给对方第一个被发送的往往是I贞,而一旦I贞的丢失意味着丢失的一方必须等下一个I贞的到来,这个时间可能很长。因此丢失一方在很长的一段时间内没有视频显示,这对用户来说是很不友好的。甚至是不能容忍的。

   一个解决办法是,在视频开始的时候,传送多个I贞。这样,即使头一个没有到达,后面的I贞也能解决问题。然而,这样的解决办法也带来了一些问题。因为通常I贞都比较大,多发送I贞就意味着增加了网络流量。在环境恶劣的情况下,对方可能一个I贞都没有收完整。

   另一个方法是在开始接通之前,发送冗余数据,直到接收到对方来的数据之后才开始发真正的数据包,但这样又给代码的编写提出了要求,也增加了系统的不稳定因素。

原创粉丝点击