- 什么是NAT。
NAT(Network Address Translation),网络地址转换协议。NAT是1994年提出的,当在专用网内部的一些主机本来已经分配到了本地IP地址(即仅在本专用网内使用的专用地址),但现在又想和因特网上的主机通信时,就可以使用NAT技术。
比如说内网ip地址192.168.1.155与外网ip地址150.158.106.96是无法直接通信,如果想要让这两个ip能够直接通信,就需要用到NAT技术将ip地址192.168.1.155先转换成公网ip地址和端口之后就可以进行通信了。
NAT的出现主要是因为IP4地址耗尽,理论上当全球IP6全面普及使用之后,NAT是可以退出历史舞台的。可见NAT的本质就是让一群机器公用同一个IP,这样就暂时解决了IP短缺的问题。
NAT的出现还有一个出于网络安全的原因,外网的主机要想攻击内网的主机,必须要经过防火墙,经过NAT转换才能找到内网的主机。
- 路由器种类
- 基本型(没用)
当一个内网设备要访问外网时,路由器为这个内网ip分配一个外网ip完全供这个设备使用,通常需要路由器有多个外网ip。
- 对称型(无法穿透)
当一个内网设备要访问外网时,根据源地址,源端口,目的地址,目的端口的不同映射成外网ip下不同的端口进行会话。所以只要(源地址,源端口,目的地址,目的端口)其中的一个不同,会话的端口就会改变,所以无法穿透。
- 完全克隆型(最容易穿透)
当一个内网设备要访问外网时,根据源地址,源端口的不同映射成外网ip下不同的端口进行会话。
- 端口限制克隆型(可以穿透)
当一个内网设备要访问外网时,根据源地址,源端口的不同映射成外网ip下不同的端口进行会话。但路由器只接受目的端口返回的udp数据。
- 端口地址限制克隆型(可以穿透)
当一个内网设备要访问外网时,根据源地址,源端口的不同映射成外网ip下不同的端口进行会话。但路由器只接受目的端口且目的ip返回的udp数据。
以上3,4,5类路由器只要源地址和源端口相同,无论访问外网哪一个地址,映射成的端口都相同,这是这3种类型能穿墙的原因。
- 如何判断是哪一种网络。
通过使用STUN服务器检测设备所处网络的NAT类型,STUN服务器需要两个公网IP。
我们假定client是要检测的设备,server是STUN服务器,并假设server的两公网SOCKET的IP地址和端口号分别是IP1:port和IP2:port。
步骤1:
client向server IP1:port发送请求,server使用IP1:port将收到请求的源IP和port(即设备的公网IP地址和端口号)回复给client,如果得到的公网IP和设备自身的IP一样,则判定设备自身处在公网,无NAT,检测结束,否则进行下一步。
步骤2:
client向server IP1:port发送请求,server使用IP2:port来回复,如果设备能收到回复,则判定client的NAT为完全锥形(Full Cone NAT),检测结束,否则进行下一步。
步骤3:
client向server IP2:port发送请求,server使用IP2:port将收到的源IP和port回复给client,client判断此port和步骤1得到的port是否一样,如果不一样,则为对称型(Symmetric NAT),检测结束;
如果一样,则为限制型(Restricted Cone NAT),这时候需要进一步检查是地址限制型NAT还是端口限制型NAT。
步骤4:
client向server IP2:port发送请求,要求server使用该IP的另一个端口来回复,server使用IP2:port2回复请求,如果client能收到回复,则判断为地址限制型(Address Restricted Cone) NAT,否则为端口限制型(Port Restricted Cone) NAT
- udp打洞过程
- 网络拓扑图
外S1,外S2为假设在外部的两个辅助穿墙的server
PC1为子网1下想要连接PS1的client
PS1,为子网2下的,提供数据的server
- 打洞流程
- PS1 用udp向 外S1,S2 发送 注册登记请求,请求登记成功之后,外S1,S2
持有了PS1用于注册的名称(假设为“manager”)、外部的IP、外部的port、以及server
分配给PS1的session(由于udp不是长链接,所以,需要一个session区分对端是否断线重连)。由S1,S2持续向PS1发送心跳保活。
- 接着PC1 在 外S1上注册登记(假设为”client”)
- PC1创建两个子socket,一个用于send,一个用于recv,在S1上登记两个子sock,此时,
S1上有PC1 的三个外网ip+port,一个用于通讯,另外两个用于和PS1打洞
- PC1 请求 S1向 manager 发送 连接请求 (附带了client的session,client的两个sock外网ip+port)
- PS1 收到 S1 来的连接请求之后,创建两个sock,一个用于发送,一个用于接收,并通过S1发给PC1,并向PC1,的两个端口发送心跳包(第一次打洞,由于PC1从来没有给PS1发过数据,这些心跳包可能PC1收不到),
- PC1收到S1传来的PS1的两个端口之后,也向PS1发送心跳(第二次打洞,如果打洞成功,此时PS1应该能收到数据)
- PS1 检测到 PC1有发过来的数据,回两个心跳,并callback给其他逻辑(server端建立完成)
- PC1只要收到了PS1发过来的任何数据,直接返回connect连接成功,如果超时,则打洞失败,
- PC1 注销在S1的登记
PS:整个逻辑下来,PS1 和 PC1的socket中可能残存有未处理的心跳包(用于打洞用的数据)p