NAT 穿透


title:
date: 2019-02-21 09:30:37
tags:

  • NAT
  • Protocol

categories:

  • WebRTC

引言

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

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:5566 219.152.168.222:9200
192.168.1.59:80 219.152.168.222:9201
192.168.1.59:4465 219.152.168.222:9202

不同类型的NAT

完全圆锥形NAT

Full cone NAT(即一对一NAT): 一旦一个内部地址(iAddr:iPort)映射到外部地址(eAddr:ePort),所有发自(iAddr:iPort)的包都经由(eAddr:ePort)向外发送。任意外部主机都能通过给(eAddr:ePort)发包到达(iAddr:iPort)。
NAT 穿透
总结:同一个内部地址(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)的数据包才被放行
NAT 穿透
总结:同一个内部地址(iAddr:iPort)只会映射相同的外部地址(eAddr:ePort),映射完成后,必须先发一个包给目标,然后才能收到目标回发的包,目标端口无限制。

端口受限圆锥形NAT

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

对称NAT

Symmetric NAT:每一个来自相同内部IP与端口,到一个特定目的地地址和端口的请求,都映射到一个独特的外部IP地址和端口。同一内部IP与端口发到不同的目的地和端口的信息包,都使用不同的映射。只有曾经收到过内部主机数据的外部主机,才能够把数据包发回。
NAT 穿透
总结:同一个内部地址(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. *地进行通讯

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. *地进行通讯

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 穿透
理解了各个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类型发现算法

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穿透方式打穿远程的防火墙。

文章说明

更多有价值的文章均收录于贝贝猫的文章目录

NAT 穿透

版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

创作声明: 本文基于下列所有参考内容进行创作,其中可能涉及复制、修改或者转换,图片均来自网络,如有侵权请联系我,我会第一时间进行删除。

参考内容

[1] 网络地址转换
[2] STUN
[3] TURN
[4] 交互式连接创建

上一篇:函数计算FC助力游戏群采集营销数据滴水不漏


下一篇:在 Java 中使用 WebRTC 传输视频——准备工作