Nat Hope Punch(P2P)

Nat和Natp

网络地址转换(Nat,全称NetWork Address Translation),早期的的Nat指的是静态Nat,它在技术上比较简单一点,仅支持地址转换,而不支持端口映射。这种Nat在同一时刻为Nat后的客户端提供上网能力的数量是有限的,所以再后来对端口也做了映射,这样就可以支持更多的主机了


支持端口转换的NAT又可以分为两类:


Nat打洞技术(Hope Pubching)

Hope Pubching技术是工作在传输层的技术,可以屏蔽上层应用层的差异,并且不需要Nat网关特定的支持

Hope Pubching原理

为描述方便我们将一对IP和端口的组合称为一个EndPoint


Hope Pubch的过程

所以总体上要实现Nat穿透,就必须知道Nat的EndPoint映射规则和对外来数据包是如何过滤的

Nat行为类型与侦测方法
早期的STUN协议是由RFC3489(经典的STUN)来描述,其定义的NAT行为类型如下:

所有从同一个内网IP和端口号Endpoint1发送过来的请求都会被映射成同一个外网IP和端口号Endpoint2,并且任何一个外网主机都可以通过这个映射的Endpoint2向这台内网主机发送包。也就是外网所有发往Endpoint2的数据包都会被NAT转发给Endpoint1。由于对外部请求的来源无任何限制,因此这种方式虽然足够简单,但却不安全。

它是Full Cone的受限版本:所有来自同一个内网Endpoint1的请求均被NAT映射成同一个外网Endpoint2,这与Full Cone相同。但不同的是,只有当内网Endpoint1曾经发送过报文给外部主机(假设其IP地址为IP3)后,外部主机IP3发往Endpoint2的数据包才会被NAT转发给Endpoint1。这意味着,NAT设备只向内转发那些来自于当前已知的外部主机的数据包,从而保障了外部请求来源的安全性

它是Restricted Cone NAT的进一步受限版,与限制锥形NAT很相似,只不过它包括端口号PORT。只有当内网Endpoint1曾经发送过报文给外部Endpoint3(包括IP和端口了),Endpoint3发往Endpoint2的数据包才会被NAT转发给Endpoint1。端口号PORT这一要求进一步强化了对外部报文请求来源的限制,从而较Restrictd Cone更具安全性。

上面的所有的Cone NAT中,映射关系只和内网的源Endpoint1相关,只要源Endpoint1不变其都会被映射成同一个Endpoint2。而对称NAT的映射关系不只与源Endpoint1相关,还与目的Endpoint3相关。也就是源Endpoint1发往目的Endpoint30的请求被映射为Endpoint20,而源Endpoint1发往目的Endpoint31的请求,则被映射为Endpoint21了。此外,只有收到过内网主机发送的数据的外网主机才可以反过来向内网主机发送数据包。

对于映射规则(Mapping Behavior )和过滤规则(Filtering Behavior) 如下

映射规则

对于一个内网的 EndPointP ,其映射的外网 EndPointG 是基本固定的,不会随着外部主机而变化

对于一个内网的 EndPointP,如果与之通信的外部为EndPointGB1,那么EndPointP就会被NAT映射为EndPointG1;如果与之通信的外部为EndPointGB2EndPointGB2EndPointGB1的IP地址相同),那么EndPointGB2同样会被NAT映射为EndPointG1,否则就会被NAT映射称为EndPoint2。也就是只要与之通信的外部为EndPointGB的IP发生变化,那么映射的外网EndPointG就会发生变化

对于一个内网的EndpointP,如果与之通信的外部为EndpointGB1,那么EndpointP就会被NAT映射成EndpointG1;如果与之通信的外部为EndpointGB2(即使它们IP相同但是如果端口不同),那么EndpointP就会被NAT映射成EndpointG2。也就是只要之通信的外部为EndpointGB发生变化,那么映射的外网EndpointG就会变化。

过滤规则

对于这种过滤类型,NAT在在自己的一个外网EndpointG1收到数据包,只要找到与之对应的内网EndpointP1,NAT就会转发这个数据包给相应的内网EndpointP1,不管这个数据包的来源是那里。(一般来说,这样过滤规则的NAT是比较少的,因为这样的安全系数比较低)

对于这种过滤类型,NAT在自己的一个外网EndpointG1收到来源是EndpointGA1数据包,这个时候NAT要判断自己是否曾经通过自己的EndpointG1给和EndpointGA1的IP相同的机器发送过数据包(这里会忽略端口),如果曾经发过,那么NAT就允许该数据包通过NAT并路由给内网与之对于的内网EndpointP1;如果没发过,那么NAT会不允许该数据包通过NAT。

对于这种过滤类型,NAT在自己的一个外网EndpointG1收到来源是EndpointGA1数据包,这个时候NAT要判断自己是否曾经通过自己的EndpointG1EndpointGA1发送过数据包,如果曾经发过,那么NAT就允许该数据包通过NAT并路由给内网与之对于的内网EndpointP1;如果没发过,那么NAT会不允许该数据包通过NAT。

将Nat映射和过滤规则组合起来就形成了9种不同的的Nat行为,但是RFC3489只描述了9种NAT组合行为类型中的4种。
     


对于两端是Symmetric NAT来说,目前是无法来进行Nat穿透的。因为连接不同的目标对应的Nat EndPoint是不同的,

Udp打洞的具体分类

Nat类型

1 <-> Full Cone NAT
2 <-> Restricted Cone NAT
3 <-> Port Restricted Cone NAT
4 <-> Symmetric NAT

1,2,3之间连接方式:
通过中间服务端服务端交换双方的外网映射地址,然后双方得到对方的二元组后同时发起与对方的连接

由于4对于不同的,目标都会映射出不同的二元组,所以4<->4目前是无法直接连接,必须通过中间服务器来中转

下面是常见的三种情况

Nat类型为4的一端主动连接Nat类型为1的一端,然后1记录4的地址后双方就可以进行互相通信

2类型限制为只有向对方IP发送过数据后,才可以接收对方发来的数据,所以如果为4与2类型连接,2必须先向4的IP任意端口上发送一个数据包,然后4再开始主动连接2

3类型的限制为只有向对方的IP端口发送过数据后,对方才可以主动给3发送数据,由于4对于不同的目标有着不同的映射,所以就必须使用暴力解决的办法,先开始3向4的10000-65535内发送数据包,发送完后,4再给3发送数据,如果4映射出来的端口刚才3已经给这个端口发送过数据了,那么3就可以接收到4发来的数据包,然后两端就可以知道彼此信息,就可以互相通信,不过3给对端发送完数据后,这个等待的有效期是多长,还需要进一步测试,还可以对端口进行分批发送数据,这样就可以降低等待时间,还有一个问题就是udp丢包的问题还需优化

在整个打洞过程中必须中转服务端节点必须和所以节点之间互相建立心跳关系,以维持整个nat映射端口的有效率