打洞之我见

来源:互联网 发布:湖北大学网络课程 编辑:程序博客网 时间:2024/06/01 10:07

两个处在不同内网的机器上的应用要想直接通信(不通过第三方来交换数据),由于互相并不知道彼此的外网IP,是做不到的。

当然如果是人为干预,你知道了彼此机器的外网IP,并做好端口映射的设置,两个是能够互相通信的,而这里说的,是在互不相知的情况下如何建立通信(这也符合生活常理,因为你较少的关注过你自己的外网IP,一些P2P应用也从来没要求过你先设置好端口映射才能够使用)。

为了能够让这样的两台不同内网中的P2P应用直接通信,首先能想到的就是,可以通过第三方的帮助来让着两台机器建立直接的通信。

如,有A、B、C三台机器

    A机器

      内网IP:10.10.0.123

      外网IP:123.0.0.123

    B机器:

      内网IP:192.168.0.2

      外网IP:211.0.0.211

    C机器:222.0.0.222

那么A、B建立连接的过程应该为,A、B机器先与C机器建立会话,这样C就知道了A、B两台机器各自的外网IP,然后,A、B再利用对方的外网IP来互相连接。

上述过程假设很有道理,但实际上并没有想象的那么简单,因为,真正的映射不简简单单地是IP的映射,NAT所做是:将内网某个端口发出的会话映射为外网的一个端口,并且,不允许第三方插足这个会话,例如:A机器访问C机器的5000端口,即:

A机器: 10.10.1.123:1234 ---映射为---> 123.0.0.123:60000  会话到  C机器: 222.0.0.222:5000

那么,这个NAT之后,逆过程只允许C机器的5000端口到123.0.0.123:60000的通信,然后再由NAT到A机器的1234,第三方就无法再插足了。于是,上面的过程貌似行不通了。

然而,由于一个端口可以向多个服务端发出请求(建立多个对外的会话),而绝大多数NAT的实现都是映射端口而不是映射会话,让这个想法变得可以实现了,当然,有些NAT是映射会话的,这种情况下就实现不了上面的方法了。

所谓的映射端口而不是映射会话的意思是,映射端口只会为内网的某个端口分配一个外网端口来映射,而不管这个端口上建立的多少个会话。而映射会话的意思是,如果内网的一个端口建立了多个会话连接,那么NAT会为每一个会话都分配一个端口,如下图:

映射端口:

  A:10.10.1.123:1234   ----映射为---->   123.0.0.123:60000  | ---会话到---> C机器

                                                                                                 \ ---会话到---->B机器


映射会话:

A:10.10.1.123:1234  | ----映射为---->  123.0.0.123:60000    ----会话到---->C机器

                                    \-----映射为---->  123.0.0.123:60001   ----会话到---->B机器

如果是这样,那么就可以借助于C机器来建立A和B的连接了。

A和B都连接到C,再由C告诉A、B对方的外网IP和端口号,然后A,B再向对方提出通信请求,这个过程就是打洞的过程。

为什么A、B再向对方提出通信请求就可以了呢?因为当A向B提出连接请求时,NAT就会将这个通信的逆过程合法化,即允许B的相应端口回访A的该端口。而此时B也做了同样的操作,导致了A也能够访问B的相应端口。于是A、B间不依赖于第三方的通信就建立了。


由上可知,有两个机制是很重要的,一个是一个端口可以建立多个会话,另一个是NAT映射的是端口而不是会话(只对会话做了不允许第三方插足的通信限制)。

还有,上面的过程显然是适用于UDP的,TCP需要一个客户端和服务端,而上面的过程要求通信的两个端口首先需要是客户端(因为连接了第三方服务端),其中一个再转为服务端是否能行得通呢?进一步,TCP应该如何打洞呢?


0 0