暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

NAT穿透

贝贝猫技术分享 2019-10-17
312

引言

之前在WebRTC 简介中,我们简单地讲了 WebRTC 中是如何进行 NAT 穿透的,但是我觉得当时讲的还不够详细,所以打算通过此文更加深入的总结 NAT 穿透技术,其中涉及到 NAT,STUN 协议,TURN 协议,ICE 协议。

NAT

NAT 概念

在计算机网络中,网络地址转换(Network Address Translation,缩写为 NAT),也叫做网络掩蔽或者 IP 掩蔽(IP masquerading),是一种在 IP 数据包通过路由器或防火墙时重写来源 IP 地址或目的 IP 地址的技术。这种技术被普遍使用在有多台主机但只通过一个公有 IP 地址访问因特网的私有网络中。1990 年代中期,NAT 是作为一种解决 IPv4 地址短缺以避免保留 IP 地址困难的方案而流行起来的。

NAPT 概念

NAT 虽然名为网络地址转换,但是常见的工作模式实际上是 NAPT(网络地址端口转换)。这种方式支持端口的映射,并允许多台主机共享一个公网 IP 地址。支持端口转换的 NAT 又可以分为两类:源地址转换和目的地址转换。前一种情形下发起连接的计算机的 IP 地址将会被重写,使得内网主机发出的数据包能够到达外网主机。后一种情况下被连接计算机的 IP 地址将被重写,使得外网主机发出的数据包能够到达内网主机。实际上,以上两种方式通常会一起被使用以支持双向通信。NAPT 维护一个带有 IP 以及端口号的 NAT 表,结构如下:

内网 IP&Port外网 IP&Port
192.168.1.55:5566219.152.168.222:9200
192.168.1.59:80219.152.168.222:9201
192.168.1.59:4465219.152.168.222:9202

不同类型的 NAT

完全圆锥形 NAT

Full cone NAT(即一对一 NAT): 一旦一个内部地址(iAddr:iPort)映射到外部地址(eAddr:ePort),所有发自(iAddr:iPort)的包都经由(eAddr:ePort)向外发送。任意外部主机都能通过给(eAddr:ePort)发包到达(iAddr:iPort)。总结:同一个内部地址(iAddr:iPort)只会映射相同的外部地址(eAddr:ePort),映射完成后,目标 IP 端口都无限制。

受限圆锥形 NAT

Address-Restricted cone NAT:内部客户端必须首先发送数据包到对方(IP=X.X.X.X),然后才能接收来自(IP=X.X.X.X)的数据包。在限制方面,唯一的要求是数据包是来自(IP=X.X.X.X)。内部地址(iAddr:iPort)映射到外部地址(eAddr:ePort),所有发自(iAddr:iPort)的包都经由(eAddr:ePort)向外发送。外部主机(hostAddr:any)能通过给(eAddr:ePort)发包到达(iAddr:iPort)。注:any 指外部主机源端口不受限制,只有发给 NAT 转换地址(eAddr:ePort)的数据包才被放行总结:同一个内部地址(iAddr:iPort)只会映射相同的外部地址(eAddr:ePort),映射完成后,必须先发一个包给目标,然后才能收到目标回发的包,目标端口无限制。

端口受限圆锥形 NAT

Port-Restricted cone NAT:类似受限制锥形 NAT(Restricted cone NAT),但是还有端口限制。一旦一个内部地址(iAddr:iPort)映射到外部地址(eAddr:ePort),所有发自(iAddr:iPort)的包都经由(eAddr:ePort)向外发送。在受限圆锥型 NAT 基础上增加了外部主机源端口必须是固定的。总结:同一个内部地址(iAddr:iPort)只会映射相同的外部地址(eAddr:ePort),映射完成后,必须先发一个包给目标(tAddr:tPort),然后才能收到目标(tAddr:tPort)回发的包,有目标端口限制。

对称 NAT

Symmetric NAT:每一个来自相同内部 IP 与端口,到一个特定目的地地址和端口的请求,都映射到一个独特的外部 IP 地址和端口。同一内部 IP 与端口发到不同的目的地和端口的信息包,都使用不同的映射。只有曾经收到过内部主机数据的外部主机,才能够把数据包发回。总结:同一个内部地址(iAddr:iPort)对不同目标(tAddr1:tPort1)(tAddr2:tPort2)会映射出不同的外部地址(eAddr1:ePort1)(eAddr2:ePort2),必须先发一个包给目标(iAddr:iPort)->(eAddr1:ePort1)->(tAddr1:tPort1),才能收到回发的包(tAddr1:tPort1)->(eAddr1:ePort1)->(iAddr:iPort1)。

简单的 NAT 穿透思路

期待的效果

NAT 穿透,简单地讲就是要让处于不同 NAT 网络下的两个节点(Peer)建立直接连接,只知道自己的内网地址是肯定不行的,他们需要知道对方的公网 IP 和端口,然后双方互相向对方发送数据包,从而建立起连接。整个流程可以看做两个关键步骤:

  1. 发现自己的公网 IP 和 Port

  2. 将自己的 IP 和 Port 共享给对方

其中,第二步,我们可以简单地通过一个第三方服务器来交换双方的 IP 和 Port,但是第一步就比较困难,我们不妨根据不同类型的 NAT 的特点,分别看看在不同的 NAT 类型下,怎样才能拿到一个可供通讯的公网 IP 和 Port。

不同 NAT 类型下的方案

注意:下面方案介绍时,都假设要通讯的双方处于同一 NAT 类型下,不同类型下的 NAT 穿透方案,我相信各位读者在理解各个方案之后,自然就能类推出来。

完全圆锥形 NAT

前面提过,完全锥形 NAT 下的节点(Client)只要建立起(iAddr:iPort)<->(eAddr:ePort)的映射关系之后,就能收到任何 IP 和端口发送的数据。所以基本思路如下:

  1. 搭建一个具有公网 IP 和 Port 的服务(Server 1)

  2. (Client)发送一个数据包给这个公网服务(Server1)

  3. (Service1)通过解析 IP 协议包,就能得知(Client)的公网地址(eAddr:ePort)

  4. (Server1)将该公网地址(eAddr:ePort)回传给(Client)

  5. 两个不同的节点 Client1 和 Client2 通过第三方服务器交换公网地址(eAddr1:ePort1)(eAddr2:ePort2)

  6. 自由地进行通讯

Full-cone-NAT
受限圆锥形 NAT

受限圆锥形 NAT 获取自己公网地址的方式和上一步完全一致,但是因为受限圆锥形 NAT 需要先发送一个数据包之后才能收到目标传来的包。所以基本思路如下:

  1. 搭建一个具有公网 IP 和 Port 的服务(Server 1)

  2. (Client)发送一个数据包给这个公网服务(Server1)

  3. (Service1)通过解析 IP 协议包,就能得知(Client)的公网地址(eAddr:ePort)

  4. (Server1)将该公网地址(eAddr:ePort)回传给(Client)

  5. 两个不同的节点 Client1 和 Client2 通过第三方服务器交换公网地址(eAddr1:ePort1)(eAddr2:ePort2)

  6. 连接双方 Client1 和 Client2 先向对方地址发送一个数据包

  7. 自由地进行通讯

Address-Restricted-cone-NAT
受限圆锥形 NAT

和受限圆锥形 NAT 完全一致。

对称 NAT

因为对称型 NAT 对不同的目标(Server1)(Server2)会映射出不同的外网地址(eAddr1:ePort1)(eAddr2:ePort2),也就是说,我们通过前面用到的公网服务(Server1),获取的公网地址(eAddr1:ePort1),没办法共享给别人使用,他只能用来和(Server1)通讯。那我们不妨,将(Server1)作为一个代理,如果其他人想和(Client)进行通讯,可以通过(Server1)转发。基于这个思路,我们的做法如下:

  1. 搭建一个具有公网 IP 和 Port 的服务(Server 1)

  2. (Client)发送一个数据包给这个公网服务(Server1)

  3. (Service1)通过解析 IP 协议包,就能得知(Client)的公网地址(eAddr:ePort)

  4. (Server1)保存(Client)的公网地址(eAddr:ePort),并生成一个代理地址(pAddr:pPort)

  5. 凡是代理地址(pAddr:pPort)收到的数据都转发给 Client 的公网地址(eAddr:ePort)

  6. (Service1)将 Client 的代理地址(pAddr:pPort)告知 Client

  7. 两个不同的节点 Client1 和 Client2 通过第三方服务器交换代理地址(pAddr1:pPort1)(pAddr2:pPort2)

  8. 连接双方 Client1 和 Client2 先向对方的代理地址(pAddr1:pPort1)(pAddr2:pPort2)发送一个数据包

  9. 双方通过代理地址(pAddr1:pPort1)(pAddr2:pPort2)进行通讯

理解了各个 NAT 类型下的解决简单方案之后,再来看 STUN,TURN 和 ICE,你就会发现这三个协议负责的内容和上述的简单方案非常相似。

STUN

STUN 概念

STUN(Session Traversal Utilities for NAT,NAT 会话穿越应用程序)是一种网络协议,它允许位于 NAT(或多重 NAT)后的客户端找出自己的公网地址,查出自己位于哪种类型的 NAT 之后以及 NAT 为某一个本地端口所绑定的 Internet 端端口。这些信息被用来在两个同时处于 NAT 路由器之后的主机之间创建 UDP 通信。是不是感觉 STUN 干的活儿非常熟悉,没错,STUN 负责的就是前面提到的 Server1 所做的内容。只不过 STUN 协议还具备另一个关键功能,就是确认 Client 的 NAT 类型(网络类型)。至于 STUN 是怎么获取 Client 公网地址这部分内容,我就不赘述了。接下来我会介绍一下 STUN 是如何确定 Client 的 NAT 类型(网络类型)的。

NAT 类型发现算法

一旦路径通过红色箱子的终点时,UDP 的直接沟通是没有可能性的。一旦通过黄色或是绿色的箱子,就有连线的可能。上图中的大部分内容我相信各位童鞋应该都能看懂,其中关于"Public IP is link's IP?"这一步我简单的讲一下:

  1. Client 向 STUN 服务器发送请求

  2. STUN 将检测出的 Client 外网地址(eAddr:ePort)回传

  3. Client 比对创建 Socket 时使用的地址(localAddr:localPort)和(eAddr:ePort)是否一致,如果完全相同,则 Client 在 NAT 后。

TURN

TURN(全名 Traversal Using Relay NAT),是一种数据传输协议(data-transfer protocol)。允许在 TCP 或 UDP 的连接跨越 NAT 或防火墙。TURN 是一个 client-server 协议。TURN 的 NAT 穿透方法与 STUN 类似,都是通过获取应用层中的公有地址达到 NAT 穿透。但实现 TURN client 的终端必须在通信开始前与 TURN server 进行交互,并要求 TURN server 产生"relay port",也就是 relayed-transport-address。这时 TURN server 会创建 peer,即远程端点(remote endpoints),开始进行中继(relay)的动作,TURN client 利用 relay port 将数据发送至 peer,再由 peer 转传到另一方的 TURN client。

ICE

交互式连接创建(Interactive Connectivity Establishment),一种综合性的 NAT 穿越的技术。交互式连接创建是由 IETF 的 MMUSIC 工作组开发出来的一种 framework,可集成各种 NAT 穿透技术,如 STUN、TURN(Traversal Using Relay NAT,中继 NAT 实现的穿透)、RSIP(Realm Specific IP,特定域 IP)等。该 framework 可以让 SIP 的客户端利用各种 NAT 穿透方式打穿远程的防火墙。

参考内容

[1]https://zh.wikipedia.org/wiki/%E7%BD%91%E7%BB%9C%E5%9C%B0%E5%9D%80%E8%BD%AC%E6%8D%A2 

[2]https://zh.wikipedia.org/wiki/STUN 

[3]https://zh.wikipedia.org/wiki/TURN

[4]https://zh.wikipedia.org/wiki/%E4%BA%92%E5%8B%95%E5%BC%8F%E9%80%A3%E6%8E%A5%E5%BB%BA%E7%AB%8B

文章转载自贝贝猫技术分享,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论