您的位置:首页 > 理论基础 > 计算机网络

NAT(网络地址转换器)&UDP打洞

2016-07-12 22:57 323 查看
首先我们要认识NAT设备,NAT英文全拼是Network Address Translator(网络地址转换器),说白了就是凡是经过NAT发出去的数据包,都会通过一定的端口转换(而非使用原端口)再发出去,也就是说内网和外网之间的通信不是直接由内网机器与外网NAT进行,而是利用内网对外网的NAT建立起SESSION与外网NAT的SESSION进行。

根据SESSION的不同,NAT主要分成两种:SymmetricNAPT以及CONE NAPT。简单的说,Symmetric NAPT是属于动态端口映射的NAT,而CONE NAPT是属于静态端口映射的NAT。而市场上目前大多属于后者,CONE的意思就是一个端口可以对外部多台NAT设备通信。这个也正是我们做点对点穿透的基本,是我们所希望的,否则现在的大部分点对点软件将无法正常使用。

图中右上角步骤2中的文字“…给NAT211.134.”应该是错误的,正确的应该是“211.133.”,因为是 S 让 B 去连接 A,而 A 的地址是 211.133.*

特别声明,图是从百度文库截图下来的



像上面的例子,NAT211.133.和NAT211.134.之间需要进行通信,但开始不能直接就发数据包,我们需要一个中间人,这个就是外部索引服务器(我们假设是211.135.:7000),当NAT211.133.向211.135.:7000发送数据包,211.135.:7000是可以正常接收到数据,因为它是属于对外型开放的服务端口。当211.135.:7000收到数据包后可以获知NAT211.133.对外通信的临时SESSION信息(这个临时的端口,假设是6000会过期,具体的时间不同,但我个人的测试是每30秒发送一个心跳包keep住连接以保证端口维持住通信连接不断开),索引服务器此时应将此信息保存起来。而同时,NAT211.134.也在时刻向索引服务器发送心跳包,索引服务器就向NAT211.134.发送一个通知,让它向NAT211.133.:6000发送探测包(这个数据包最好多发几个),NAT211.134.在收到通知包之后再向索引服务器发送反馈包,说明自己已经向NAT211.133.:6000发送了探测包,索引服务器在接收到反馈包之后再向NAT211.133.转发反馈包,NAT211.133.在接收到数据包之后再向原本要请求的NAT211.134.发送数据包,此时连接已经打通,实现穿透,NAT211.134.*会将信息转发给192.168.1.88的9000端口。

内网穿透&UDP打洞

首先文章建议 Cone NAPT 还有希望,要是 Symmetri NAPT 就别想了,接着介绍了两种基本情况,一是一台内网机器连接外网通信的情况,二是两台内网之间互联的情况。

第一种,只需要内网主动发起连接就可以了。内网机器A(192.168.1.x:4000)要求连接外网服务端S(60.17.211.x:5000),发出连接请求后被A网所在网关NA(10.11.12.x)获取,NA将A的地址转变为其自身地址,并分配临时端口(6000)用作通讯,于是,当初的 A->S 就变成现在的 A->NA->S。那么S接到请求后看到的并不是A的地址,而是NA的IP和Port,此时S如果照着此地址回复,则NA收到,因为NA此时有通讯临时Session被创建了,所以在一定时间内(貌似根据不同硬件、软件设备而不同)还记得发到6000的信息要转给A,NA就会转发给A。至此,通讯成功。

第二种,两个内网之间就要复杂一些,图与上图一致。

首先,两个内网A和B谁都不能直接连谁,所以第一次,都是给S发送登录、心跳之类的,目的是表明自己的存在,并建立session,当然,这个过程还是通过自身网络的N实现的。那么,如何做到UDP穿透呢?

假设左边的为A(192.168.1.77:8000),A->NA(211.133.*:6000)->S,此时,S记住了 A 的存在,NA也与A建立了对应关系(发到6000的信息就是A的),一样道理,B也与S建立了连接。

A通过S知道了B的存在(只是知道存在),A想连B,于是A告诉S,“让B探测我一下”

S把A的要求发给B,于是B发送“探测”包给A,事实上就是 B->NB->NA,但是因为 NA 不认识 NB(之前没联系过),所以 NA 就不会转发给 A,随之丢弃。但是 NB 上已经建立起了目的是 NA 的 session,这是后面打洞成功的关键一步。

B 发送探测给 A 之后,因为 NA 必定丢弃,所以 B 向 S 发送“反馈包”,就是图中的步骤 4,目的是告诉 S 已经发送过探测包给 A 了。这一步的目的是,借 S 之手告诉 A ,我已经联系过你了,我已经有了关于你的 session 。

S 通知 A:“人家 B 已经联系过你了”。

A 知道之后,发送数据包给 B ,也就是 A->NA->NB->B。当 NA->NB 时,因为 NB 存有当初链接 NA 的信息,所以 NB 认为它自己认识 NA ,会接受 NA 发送的信息,转发给 B,至此,理论上,打洞完成。AB之间可以互通了。还未经过自己试验,不知道对不对。

另外还有几点疑惑和说明的地方

“信息不请自来,NAT 安全起见,是会被丢弃的”——A->NA->S 时,NA 接到请求会创建 session ,分配某端口如6000对应 A ,目的是接到发到 6000 端口上的信息就知道转发给 A,但只会接受当初 A 所请求的远程主机 S 所发过来的信息才会转发给 A,其它地址则会丢弃。这也是为什么两个内网不能直接互发的原因,举个例子就是洞还没打,外界发过来的信息,也会被看门人 NA 给扔掉,因 NA 那有一个记录表,A 曾经要求连接 S,这条记录就会有关于 S 的信息,比如另一台 S2 发过来同样的 6000 端口信息,由于 NA 没有记录不认识 S2 ,是会丢弃不会转发的。

打洞要从内部向外部打,S 想连接 A,A 向 S 打洞(发起连接)。A 想连接 B,要通过 S 告诉 B 让 B 向 A 打洞,B 打完 A 沿此路打回去,才能成功。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: