NAT 原理简介
NAT(Network Address Translation,网络地址转换), 用来将内网地址和端口号转换成合法的公网地址和端口号,建立一个会话,与公网主机进行通信。NAT 的使用是为了解决公网 IP 有限及局域网安全性的问题。
实际上 NAT 分为基础型 NAT(静态 NAT 即 Static NAT,动态 NAT 即 Dynamic NAT/Pooled NAT)和NAPT(Network Address Port Translation)两种,但由于基础型 NAT 已不常用,我们通常提到的 NAT 就代指 NAPT。NAPT是指网络地址转换过程中使用了端口复用技术,即 PAT(Port address Translation)。
NAT 概述
NAT 部署:
在内部网络和公网之间,需要有程序完成网络地址转换,这种程序(NAT 网关)可以部署在路由器、防火墙等位置。
注:事实上,NAT 类型的划分是很多混淆的起源。现实中的很多 NAT 设备是将这些转换方式混合在一起工作的,而不单单使用一种,所以 NAT 类型的定义只适合描述一种工作方式,而不是一个设备。比如,很多 NAT 设备对内部发出的连接使用对称型 NAT 方式,而同时支持静态的端口映射,后者可以被看作是全锥型 NAT 方式。而有些情况下,NAT 设备的一个公网地址和端口可以同时映射到内部几个服务器上以实现负载分担,比如一个对外提供 WEB 服务器的站点可能是有成百上千个服务器在提供 HTTP 服务,但是对外却表现为一个或少数几个 IP 地址。
NAT 网络结构:
下图是 NAT 网络结构,仅示意部署在路由器上的 NAT:
NAT 工作原理:
- 网络被分为私网和公网两个部分,NAT 网关设置在私网到公网的路由出口位置,双向流量必须都要经过 NAT 网关;
- 网络访问只能先由私网侧发起,公网无法主动访问私网主机;
- NAT 网关在两个访问方向上完成两次地址的转换或翻译,出方向做源信息替换,入方向做目的信息替换;
- NAT 网关的存在对通信双方是保持透明的;
- NAT 网关为了实现双向翻译的功能,需要维护一张关联表,把会话的信息保存下来。
从上面的特征来看,NAT 将内部网络的信息隐藏和转换,如果要实现隐藏在 NAT 下的设备之间通信(对等网络传输),则必须穿透 NAT;此外,NAT 网关实际上并不能实现对通信双方的全透明,因为用户可以在传输的数据包中携带 ip 和 port 信息(而不是在 IP header 中)。
NAT 引起的问题:
- 对等网络传输需穿透 NAT:IP 协议的定义中,在理论上,具有 IP 地址的每个站点在协议层面有相当的获取服务和提供服务的能力,不同的 IP 地址之间没有差异。但 NAT 工作原理破坏了这个特征,如需实现真正意义上的对等网络传输,则需要穿透 NAT。这是本文重点。
- 应用层需保持 UDP 会话连接:由于 NAT 资源有限,会根据一定规则回收转换出去的资源(即 ip/port 组合),UDP 通信又是无连接的,所以基于 UDP 的应用层协议在无数据传输、但需要保持连接时需要发包以保持会话不过期,就是通常的 heartbeat 之类的。
- 基于 IP 的访问限制策略复杂化
技术点和原理
术语:
- 内部 Tuple:指内部主机的私有地址和端口号所构成的二元组,即内部主机所发送报文的源地址、端口所构成的二元组;
- 外部 Tuple:指内部 Tuple 经过 NAT 的源地址/端口转换之后,所获得的外部地址、端口所构成的二元组,即外部主机收到经 NAT 转换之后的报文时,它所看到的该报文的源地址(通常是 NAT 设备的地址)和源端口;
- 目标 Tuple:指外部主机的地址、端口所构成的二元组,即内部主机所发送报文的目标地址、端口所构成的二元组。
- 打洞 hole punch:穿透 NAT
NAT 类型
基础型 NAT
仅将内网主机的私有 IP 地址一对一地转换成公网的 IP 地址,并不将 TCP/UDP 端口信息进行转换,分为静态 NAT 和动态 NAT。
NAPT
NAPT 不但会改变经过这个 NAT 设备的 IP 数据报的 IP 地址,还会改变 IP 数据报的 TCP/UDP 端口。
-
全锥型(Full Cone NAT)
:所有来自同一个内部 Tuple X 的请求均被 NAT 转换至同一个外部 Tuple Y,而不管这些请求是不是属于同一个应用或者是多个应用的。除此之外,当 X-Y 的转换关系建立之后,任意外部主机均可随时将 Y 中的地址和端口作为目标地址和目标端口,向内部主机发送 UDP 报文,由于对外部请求的来源无任何限制,因此这种方式虽然足够简单,但却不那么安全。
全锥型网络结构 全锥型访问示意图 全锥型 NAT 打洞原理:在不同内网的主机 A 和 B 各自连接到服务器 C,服务器收到 A 和 B 的连接后知道了他们的公网地址和 NAT 分配给他们的端口号,然后把这些 NAT 地址和端口号交叉告诉 B 和 A。
A 和 B 给服务器所打开的“孔”可以给任何主机使用。
-
受限锥型(Restricted Cone NAT)
:Full Cone 的受限版本,亦可认为是 IP 地址受限锥型。所有来自同一个内部 Tuple X 的请求均被 NAT 转换至同一个外部 Tuple Y,这与 Full Cone 相同,但不同的是,
只有当内部主机曾经发送过报文给外部主机(假设其 IP 地址为 Z)后
,外部主机才能以 Y 中的信息作为目标地址和目标端口,向内部 主机发送 UDP 请求报文,这意味着,NAT 设备只向内转发(目标地址/端口转换)那些来自于当前已知的外部主机的 UDP 报文,从而保障了外部请求来源的安 全性。
受限锥型网络结构 受限锥型访问示意图 受限锥型 NAT 打洞原理:主机 A 和 B 同样需要各自连接服务器 C,同时把 A 和 B 的地址告诉 B 和 A,但一般情况下它们只能与服务器通信。要想直接通信需要发送消息给服务器 C,如主机 A 发送一个 UDP 消息到主机 B 的公网地址上,与此同时,A 又通过服务器 C 中转发送一个邀请信息给主机 B,请求主机 B 也给主机 A 发送一个 UDP 消息到主机 A 的公网地址上。这时主机 A 向主机 B 的公网 IP 发送的信息导致 NAT A 打开一个处于主机 A 的和主机 B 之间的会话,与此同时,NAT B 也打开了一个处于主机 B 和主机 A 的会话。一旦这个新的 UDP 会话各自向对方打开了,主机 A 和主机 B 之间才可以直接通信。
IP 相同,port 随便,就能和先前内部节点被映射的外部 Tuple 进行通信
。
-
端口受限锥型(Port Restricted Cone NAT)
:Restricted Cone NAT 的进一步受限版。只有当内部主机曾经发送过报文给外部主机(假设其 IP 地址为 Z 且端口为 P)之后,外部主机才能以 Y 中的信息作为目标地址和目标端 口,向内部主机发送 UDP 报文,同时,其请求报文的源端口必须为 P,这一要求进一步强化了对外部报文请求来源的限制,从而较 Restrictd Cone 更具安全性。
端口受限锥型网络结构 端口受限锥型访问示意图 端口受限锥型 NAT 打洞原理:与受限制锥型类似,与之不同的是还要指定端口号。
IP,port 都得一样;只能用先前内部节点被映射的外部 Tuple 与内部节点进行通信
-
对称型
内部主机的内部 Tuple 与外部 Tuple 的转换映射关系是独立于内部主机所发出的 UDP 报文中的目标地址及端口的,即与目标 Tuple 无关; 在 Symmetric NAT 中,目标 Tuple 则成为了 NAT 设备建立转换关系的一个重要考量:只有来自于同一个内部 Tuple、且针对同一目标 Tuple 的请求才被 NAT 转换至同一个外部 Tuple,否则的话,NAT 将为之分配一个新的外部 Tuple;打个比方,当内部主机以相同的内部 Tuple 对 2 个不同的目标 Tuple 发送 UDP 报文时,此时 NAT 将会为内部主机分配两个不同的外部 Tuple,并且建立起两个不同的内、外部 Tuple 转换关系。与此同时,只有接收到了内部主机所发送的数据包的外部主机才能向内部主机返回 UDP 报文,这里对外部返回报文来源的限制是与 Port Restricted Cone 一致的。不难看出,如果说 Full Cone 是要求最宽松 NAT UDP 转换方式,那么,Symmetric NAT 则是要求最严格的 NAT 方式,其不仅体现在转换关系的建立上,而且还体现在对外部报文来源的限制方面。
对称型网络结构
对称型 NAT 打洞原理:常规的打洞方式都不可用,目前可以尝试的有 TCP+UDP 打洞、UDP 端口预测方法。
NAT 对比:
| NAT 类型 | 复杂度 | 安全性 |
|---|---|---|
| 全锥型 | 最简单 | 低 |
| 受限锥型 | 简单 | 中 |
| 端口受限锥型 | 稍复杂 | 高 |
| 对称型 | 很复杂 | 最高 |
不同 NAT 之间打洞对比:
| Peer A | Peer B | 是否可以打洞 |
|---|---|---|
| 全锥型 | 全锥型 | 是 |
| 全锥型 | 受限锥型 | 是 |
| 全锥型 | 端口受限锥型 | 是 |
| 全锥型 | 对称型 | 是 |
| 受限锥型 | 受限锥型 | 是 |
| 受限锥型 | 端口受限锥型 | 是 |
| 受限锥型 | 对称型 | 是 |
| 端口受限锥型 | 端口受限锥型 | 是 |
| 端口受限锥型 | 对称型 | 一般否 |
| 对称型 | 对称型 | 一般否 |
穿透服务/协议
穿透方式
详情参考NAT 概述
- 应用层网关(ALG):一般都内置在 NAT 装置中,ALG 会随着协议的扩充,不断更新和支持新的协议,但为每个应用协议开发 ALG 代码并跟踪最新标准是不可行的,ALG 只能解决用户最常用的需求。此外,出于安全性需要,有些应用类型报文从源端发出就已经加密,这种报文在网络中间无法进行分析,所以 ALG 无能为力。
- 探针技术——NAT 探测和穿透协议:NAT 网关无需任何修改,通过协议探测 NAT 类型,并对不同类型 NAT 实行穿透,比如 STUN/TURN。当 NAT 可以直接穿透时,服务器协助完成穿透以及连接的建立,当 NAT 无法穿透时,TURN 服务与 STUN 绑定,形成“ip-port”对,将链路中的数据包在 TURN 服务器上转发。相对于 ALG 方式有一定普遍性。但是 TURN 中继服务会成为通信瓶颈。而且在客户端中增加探针功能要求每个应用都要增加代码才能支持。这是本部分重点关注的方式
- 中间件技术:开发通用方法解决 NAT 穿越问题的努力。与前者不同之处是,NAT 网关是这一解决方案的参与者。与 ALG 的不同在于,客户端会参与网关公网映射信息的维护,此时 NAT 网关只要理解客户端的请求并按照要求去分配转换表,不需要自己去分析客户端的应用层数据。其中 UPnP 就是这样一种方法。这种方案需要网关、内部主机和应用程序都支持 UPnP 技术,且组网允许内部主机和 NAT 网关之间可以直接交换 UPnP 信令才能实施。(好像经常有安全性问题)
- 中继代理技术:实际上并非 NAT 穿透,而是 NAT 旁路技术,在 NAT 旁架设一个中继服务器,这个服务器在内部网络和外部公网分别有自己的网络连接。客户端特定的应用产生网络请求时,将定向发送到应用代理服务器。应用代理服务器根据代理协议解析客户端的请求,再从服务器的公网侧发起一个新的请求,把客户端请求的内容中继到外部网络上,返回的相应反方向中继。这项技术和 ALG 有很大的相似性,它要求为每个应用类型部署中继代理业务,中继服务器要理解这些请求。
- 特定协议穿越:所有方法中最复杂也最可靠的就是自己解决自己的问题。比如 IKE 和 IPsec 技术,在设计时就考虑了到如何穿越 NAT 的问题。详情见IPSec 及 IKE 原理
基于 NAT 探测的穿透协议
RTMFP
Adobe 定义的一种 UDP 穿透 NAT 协议,在 flash p2p 中使用,也可以用 openrtfmp 的开源项目实现其他设备上的 nat 穿透。 RTMFP 协议详解
STUN/TURN
IETF 定义的一种 UDP 穿透规范,最为普遍。 STUN/TURN 协议详解
ICE
包括 ALG,STUN,TURN 等各种穿透方式的组合。 ICE 协议详解
花生壳 DDNS 穿透——是指将用户 X 的动态 tuples 绑定到某个域名 A 上,其他用户访问该域名来与用户 X 通信,这种方式显然不适用于大规模对等网络传输。
对称型 NAT 穿透方式
详情见对称型 NAT 穿透方式
同时开放 TCP(SimultaneousTCP open)策略
如果 Client A-1 和 Client B-1 能够彼此正确的预知对方的 NAT 将会给下一个 TCP 连接分配的公网 TCP 端口,并且两个客户端能够同时地发起一个面向对方的“外出”的 TCP 连接请求,并在对方的 SYN 包到达之前,自己刚发送出去的 SYN 包都能顺利的穿过自己的 NAT 的话,一条端对端的 TCP 连接就能成功地建立了。
问题:时钟严格一致,很难做到。
UDP 端口猜测策略
通常,对称 NAT 分配端口有两种策略,一种是按顺序增加,一种是随机分配。如果这里对称 NAT 使用顺序增加策略,那么,ClientB-1 将两次被分配的 Tuples 发送给 Server 后,Server 就可以通知 ClientA-1 在这个端口范围内猜测刚才 ClientB-1 发送给它的 socket-1 中被 NAT 映射后的 Tuples,ClientA-1 很有可能在孔有效期内成功猜测到端口号,从而和 ClientB-1 成功通信。
问题:不能为随机分配端口的对称型 NAT 打洞。
技术细节及流程、方法
NAT 穿透流程
上图是 P2P 传输中节点打洞的基本流程,实际过程会复杂很多。基于本文第二部分中,不同 NAT 类型的打洞原理不一样,不同 NAT 之间的穿透成功率也不一样,所以实际工程经验中,打洞流程会非常复杂。
搭建 NAT 穿透服务器(俗称打洞服务器)
NAT 穿透的基本前提是打洞服务器,该 server 需要部署在公网,并有两个公网 IP。Server 做监听(IP-1,Port-1),(IP-2,Port-2)并根据客户端的要求进行应答。
检测客户端是否有能力进行 UDP 通信以及客户端是否位于 NAT 后
客户端向打洞服务器发起 UDP 请求若干次,如每次超时未返回,即认为该客户端不具备 UDP 通信能力(可能是防火墙或 NAT 阻止 UDP 通信);若收到打洞服务器返回的数据包,且其中携带的客户端(IP,Port)和这个客户端 socket 的 (LocalIP,LocalPort)比较。如果完全相同则客户端不在 NAT 后,这样的客户端具有公网 IP 可以直接监听 UDP 端口接收数据进行通信(检 测停止)。否则客户端在 NAT 后要做进一步的 NAT 类型检测(继续)。
NAT 类型探测
基于本文第二部分中不同 NAT 类型的特征及打洞原理,对于全锥型、受限锥型和端口受限锥型可以较容易实现 P2P 通信,而对称型 NAT 需要额外支持别的穿透方法(且不一定能成功)。
节点间借助打洞服务器提供的信息,尝试打洞连接
打洞不成功,则使用 RELAY 服务
不同 NAT 网络结构下的 peer 打洞示意图
同一个 NAT 设备下
打洞过程如下:
打洞成功取决于 NAT 设备是否支持 hairpin translation(端口回流)。——打开端口回流相当于与 client A 的数据经过 NAT 设备转发后才到达 client B,即从外网 NAT 接口绕了一圈再访问到同一个子网里的 client B。(优点是可以防止内部攻击) 优化方法:同一局域网,当 A 和 B 最初通过 S 交换地址信息时,他们应该包含自身的 IP 地址和端口号(从自己看),同时也包含从服务器看的自己的 地址和端口号。然后客户端同时开始从对方已知的两个的地址中同时开始互相发送数据,并使用第一个成功通信的地址作为对方地址。如果两个客户端在同一个 NAT 后,发送到对方内网地址的数据最有可能先到达,从而可以建立一条不经过 NAT 的通信链路。
不同 NAT 设备下
打洞过程如下:
就是常规的 NAT 穿透
3)多层 NAT 设备下
打洞过程如下:
client A 和 client B 无法通过 NAT A 和 NAT A 进行 P2P 通信,因为它们属于 NAT C 的局域网地址,因此 client A 和 client B 只能通过 NAT C 的 hairpin translation 进行 P2P 通信,如果 NAT C 不支持 hairpin translation,则它们很难进行 P2P 通信。
开源项目
参考
-
No backlinks found.