p2p nat穿透详解
nat一般分为snat和dnat,dnat一般用作负载均衡,如nginx的反向代理。
snat一般是为了解决公网ip过少的问题,企业内部机器有自己的数据中心,数据中心中有成千上万的服务器,而公网ip是稀少的资源,不能为每台服务器分配一个公网地址,这时候就需要做snat,内部机器访问外网上行报文要做snat,回路报文做dnat。
这样如果一台服务器只在8080端口提供服务,那么只添加一条映射ip:8080端口的nat规则,那么外部网络访问这台机器理论上能直接访问的只有8080端口提供的服务,这样就能有效的保护这台服务器避免外部网络的威胁。
nat类型一般分为两种 NAT (Network Address Translation)
NAPT(Network Address/Port Translator)
NAT分为两大类,基本的NAT和NAPT(Network Address/Port Translator)。
基本的NAT,它仅将内网主机的私有IP地址转换成公网IP地址,但并不将TCP/UDP端口信息进行转换,有动态与静态之区分。由于现在大部分都属于另一种类型,即NAPT,故这里不详细讨论基础NAT。 另外一种NAT叫做NAPT(Network Address/Port Translator),从名称上我们也可以看得出,NAPT不但会改变经过这个NAT设备的IP数据报的IP地址,还会改变IP数据报的TCP/UDP端口。
NAPT又分为锥型(Cone)和对称型(Symmetric),它们的区别在于如果client a使用1235端口和外部机器b的8080端口互联互通,在NAT已分配端口号62000给Client A的情况下,如果Client A继续用1235端口与另一外网服务器通讯,锥型NAT还会继续用原来62000端口,即所分配的端口号不变。而对于对等型NAT,NAT将会分配另一端口号(如62001)给Client A的1235端口。也就是说,同一内网主机同一端口号,对于锥型NAT,无论与哪一外网主机通讯,都不改变所分配的端口号;而对于对等型NAT,同一内网主机同一端口号,每一次与不同的外网主机通讯,就重新分配另一个端口号。
锥形nat又区分为 full cone nat 完全锥形nat 在上面的例子中,如果另外一台机器c,如果想要和client a的外网ip和60000端口通信的话,nat设备也会放过的 restricted cone nat 限制锥形nat 在上面的例子中,只有机器b才能跟client a的外网ip和60000端口通信 port restricted cone nat 端口限制形nat 在上面的例子中,只有机器b的8080端口才能跟client a的外网ip和60000端口通信
不知道对端ip
不知道对端port(现在的nat策略大多都是napt)
client和服务器进行tcp连接,并协商tls
如果成功发送共享私密请求,用作捆绑请求和捆绑响应中的密匙
捆绑请求和响应为udp连接,附带共享私密,作为安全密钥。
client a监听8080端口,向stun server发送捆绑请求,源ip为ipa,源port为pa。
经过client a的nat后,stun server收到请求后,发现这是来自ipfa,端口为pfa的报文,stun server构造响应,将ipfa:pfa封在响应包体中, 并返回给client a
client 收到stun server发来的响应包,进行比对
如果ipfa和ipa,pa和pfa相同的话,那么client a和stun server之间没有nat设备
如果如果ipfa和ip,pa和pfa不同的话,那么client a和stun server之间至少有一个nat设备
如果有nat,确定nat的类型
client a监听8080端口,向stun server b发送捆绑请求,源ip为ipa,源port为pa。
经过client a的nat后,stun server b收到请求后,发现这是来自ipfa1,端口为pfa1的报文,stun server b构造响应,将ipfa1:pfa1封在响应包体中
client 收到stun server发来的响应包,进行比对
如果ipfa和ipfa1,pfa和pfa1相同的话,那么client a和stun server之间的nat类型为cone nat
如果ipfa和ipfa1,pfa和pfa1不同的话,那么client a和stun server之间的nat类型为对称型nat
如果是cone nat,确定cone nat的类型
client a可以发送一个带有标志的捆绑请求,这个标志告诉服务器使用另一个IP地址和端口发送捆绑响应
如果client a使X/Y的IP地址端口对向 stun server A/B的IP地址端口对发送捆绑请求,服务器就会使用源IP地址和源端口号为C/D的地址端口对向X/Y发送捆绑响应
如果客户端收到了这个响应,它就知道它是在一个Full-Cone NAT前面
STUN协议允许客户端请求服务器从收到捆绑请求的IP地址往回发捆绑响应,但是要使用不同的端口号。
这可以用来检查客户端是否在Port Restricted Cone NAT的前面还是在Restricted Cone NAT的前面。
如果能收到捆绑响应,nat类型为Restricted Cone NAT
如果不能收到捆绑响应,nat类型为Port Restricted Cone NAT
通信一方是动态nat或者静态nat
client a是动态nat或者静态natclient a监听8080端口
client a给stun 服务器s发送一条报文 ipa-> ips,这时nat设备上多了一条上行的nat规则ipa => ipf 同时对于下行的目的ipf的报文都dnat为ipa,并执行accept
服务器收到源为ipf,目的为ips的报文
这时不管client b是任何一种类型的nat,服务器发送一个candicate给client b让client b连接 ipf:8080端口
client a的nat设备收到报文后,发现匹配ipf的报文dnat为ipa
client a收到报文后,返回给client b,由于client b事先给client a发送过报文,所以无论是任何类型的nat,报文都可以通过。
通信一方是完全锥形napt
client a是完全锥形client a监听8080端口
client a给stun 服务器s发送一条报文 ipa:8080 -> ips:8081,stun server监听8081端口
这时nat设备上多了一条上行的nat规则ipa:8080 => ipf : 60001,同时对于任何dip为ipf:60001的报文都dnat后,执行accept
服务器收到源为ipf:60001,目的为ips:8081的报文
这时不管client b是任何一种类型的nat,服务器发送一个candicate给client b让client b连接 ipf:60001端口
client a的nat设备收到报文后,发现匹配ipf:60001的报文dnat为ipa:8080
client a收到报文后,返回给client b,由于client b事先给client a发送过报文,所以无论是任何类型的nat,报文都可以通过。
通信双方都是端口受限制锥形napt
假设client a监听8080端口
client a给stun服务器ips发送一条ipa:8080 -> ips:8081报文
client a经过nat后变成 ipf1:60001 -> ips:8081报文,stun server监听8081端口。
这时server知道了ipa nat为ipfa:60001,并发送candicate给client b
假设client b监听8082端口,给stun服务器 ips发送一条 ipb:8082->ips:8081报文,这时server知道了ipa nat为ipfb:60002,并发送candicate给client a
client a收到b的candicate后,发送一条报文ipa:8080 -> ipfb:60002, 经过nat设备后,变成ipfa:60001-> ipfb:60002,同时只允许下行报文为ipfb:60002->ipfa:60001的报文通过
由于在第三步,stun server已经告知client b,要连接client a的ipfa:60001端口,client发送报文 ipfb:8082->ipfa:60001,经过nat后,变成ipfb:60002->ipfa:60001 ,client a的nat已经有了这条下行匹配的规则,允许通过
通信一方是ip限制napt,另一方为ip限制或者端口限制
假设client a是ip限制napt,监听8080端口
client a给stun服务器ips发送一条ipa:8080 -> ips:8081报文
client a经过nat后变成 ipf1:60001 -> ips:8081报文,stun server监听8081端口。这时server知道了ipa nat为ipfa:60001,并发送candicate给client b
假设client b监听8082端口,给stun服务器 ips发送一条 ipb:8082->ips:8081报文,这时server知道了ipa nat为ipfb:60002,并发送candicate给client a
client a收到b的candicate后,发送一条报文ipa:8080 -> ipfb:60002, 经过nat设备后,变成ipfa:60001-> ipfb:60002,同时只允许下行报文为ipfb:any->ipfa:60001的报文通过
由于在第三步,stun server已经告知client b,要连接client a的ipfa:60001端口,client发送报文 ipfb:8082->ipfa:60001,经过nat后,变成ipfb:60002->ipfa:60001 ,client a的nat已经有了这条下行匹配的规则,允许通过
通信一方是对称型napt
假设client a是对称型napt,并监听8080端口
client a给stun server ips发送一条ipa:8080 ->ips:8081报文,stun server监听8081端口,stun server收到源为ipfa:60001的报文
stun server给client b发送一条candicate报文,告知client a的floating ip为 ipfa
client b监听8082端口,给stun server发送一条报文,ipb:8082 ->ips:8081,stun server收到源为ipfb:60002的报文
stun server给client a发送一条candicate报文,告知client b的floating ip为 ipfb:60002
client a给b发送一条ipa:8080->ipfb:60002的报文,由于a是对称型nat,经过nat后会变成ipfa :60003 ->ipfb:60002
ipfa :60003 ->ipfb:60002到达client b的nat后,如果b是ip受限,这条报文可以通过,p2p连接可以建立
如果b的nat是ip和端口受限,那么p2p连接会拒绝,因为client b的下行报文的源端口是60003
有一个笨方法可以解决这个问题,在a给b发报文之前,b给ipfa的0-65535端口都发送报文,这样,ipfa的报文就可以经过,不过这种办法太耗费资源,一般不会去用
通信双方都是对称型nat
1. 借助笨方法,互发ipf(0-65535)报文,这种方法一般也不会使用
2. 借助relay,同时去连turn服务器,turn服务器作为一个relay,所有流量经过turn服务器,对turn服务器的带宽要求比较高
所以,能打洞,最好打洞。
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: NAT映射和代理服务器
- 下一篇: 基于域名的7层转发的实现(NAT+反向代理)