今天和大家聊一聊NAT穿越


什么是NAT

NAT(Network Address Translation),即网络地址转换,是一种ip数据包的重写技术。

为什么要要有NAT呢?

这是因为现实中公网的ip地址过少,很多单位,学校都不能满足每个主机分配一个公网地址。

因此会通过NAT技术将内网的主机地址映射为同一个公网地址的不同端口,进行外网访问。

image-20200610191434292

NAT的缺点

NAT解决了内网环境下多主机上网的问题,但是也造成了难以从外网访问内网主机的问题。

尤其是在一些p2p应用的场景下(比如现在越来越火的webrtc),NAT穿越成为了需要着重研究的点。

NAT的分类

NAT一共可以分为四种:

  • 圆锥形NAT:相当于在NAT服务器上打了个洞,所有外部主机都可以按照这个公网的IP:port发送数据,并且能够顺利找到内网主机

image-20200610193649234

  • 受限锥型NAT:NAT会记录内网主机访问的外网IP,只有来自同一个IP的请求才能转发到内网主机。

image-20200610193956642

  • 端口受限型NAT:NAT会记录内网主机访问的外网IP和端口,只有来自同一个IP且同一个端口的请求才能转发到内网主机。

image-20200610194411386

  • 对称型NAT:每次请求的连接都会使用不同的公网端口

image-20200611162545987

注意,对称型NAT和其他三个最大的不同点在于每次请求的端口都会变化,这就导致了NAT穿越的难度增加。

NAT穿越

我们如何实现NAT穿越呢?

方式就是在NAT后面的主机向公网指定端口发送一个包,这样就会在NAT服务器上留下一个端口。

其他主机只要知道了这个端口,就可以向内网主机发送数据了。

这个行为形象的称之为“打洞”。

一方是圆锥型NAT

当一方是圆锥型NAT,只要它向某个公网服务器(例如STUN服务器)发送一个包。

这样它在公网的ip和端口就确定了。

无论对端是哪种类型的NAT,只要向这个ip和端口发送数据即可连通。

双方是受限锥型NAT或者端口受限型NAT

那么双方都向公网服务器发送一个包,确定自己的ip和端口,并通过公网服务器发送给对方。

接着双方再向对方地址发送一个包,之后就可以实现通信了。

一方是对称型NAT

  • 当对方是圆锥型NAT:只要让对方先发送请求即可

  • 当对方是受限锥型NAT:需要在双方交换完地址后,对方先发送一个包,确保指定IP的数据可接收;本机再向对方IP和端口发送数据,完成连接。

  • 当对方是端口受限型NAT:需要在双方交换完地址后,本机先发送一个包,在NAT服务器上打洞。

    但是此时对端并不知道本机这次打洞的端口,所以需要向各个端口都进行发包探测。此时本机需要不停的向对端发包,直至某一个包被接收。此时双方都确定了对方的ip和端口,完成通信。

  • 当对方是对称型NAT:没有办法连通。因为其中一个主机在每次探测时,自身的端口都会变化。这样对方无法确定本机端口。因此只能通过公网服务器进行中转(例如TURN服务器)

穿透总结

各个类型的NAT穿透可以总结如下表

image-20200611170741425

当然有同学会觉得这个东西太复杂。

不过没关系,已经有一些现成的方案帮我们做了这些事情。比如webrtc的ice,可以使用简单API的完成NAT的穿越。当遇到无法穿越的对称型NAT时,也会降级为服务器中转。

这样我们开发时,就不需要关注这类问题了。


参考文档:


本文会经常更新,请阅读原文: https://xinyuehtx.github.io/post/%E7%90%86%E8%A7%A3NAT%E7%A9%BF%E8%B6%8A.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名黄腾霄(包含链接: https://xinyuehtx.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系