NAT技术及穿透原理解析

NAT技术及穿透原理解析随着因特网规模的飞速发展,联网设备数量不断增加,地址空间大小只有2^32的IPv4地址正面临着枯竭,而作为下一代网络层协议的IPv6虽然拥有巨大的地址数量,但面对庞大的历史遗留问题也显得力不从心。在这种情况下,NAT(NetworkAddressTranslation,网络地址转换)技术应运而生

大家好,欢迎来到IT知识分享网。NAT技术及穿透原理解析

随着因特网规模的飞速发展,联网设备数量不断增加,地址空间大小只有2^32的IPv4地址正面临着枯竭,而作为下一代网络层协议的IPv6虽然拥有巨大的地址数量,但面对庞大的历史遗留问题也显得力不从心。在这种情况下,NAT(Network Address Translation,网络地址转换)技术应运而生。NAT的作用,是让多个拥有独立内网IP的设备,能够共用一个外网IP和外部进行通信。由于不同内网IP互不干涉,不同内网下的设备可以使用同一个内网IP,这样一来,IP地址的短缺现象就大大缓解了。

NAT基本原理和大致流程

NAT技术搭载在路由器上,通过修改经由该路由器转发的数据报来达到目的。众所周知,无论是TCP还是UDP传输协议,都涉及到四个属性:源地址、源端口、目标地址和目标端口。假设设备HostA要向设备HostB发送数据,它会把自己的地址,以及HostB的IP地址放入IP数据报的首部。在没有NAT存在的情况下,两个设备之间的路由器会根据这个首部信息和自身的路由表,将数据报转发向另一个更接近HostB的路由器,直至数据报最终到达HostB。在这个过程中,虽然数据报经过了多个路由器的转发,但它的IP数据报首部是不变的。
然而,使用了NAT技术的路由器(以下称它为Nat)会打破这个规则。Nat会把自己的管理的网段分为内外两侧,位于两侧的主机进行的一切通信都要经过N的转发。在每个外侧网段,Nat都需要一个全球唯一的外网IP地址,除非这个网段位于另一个NAT设备的内部网段,这种情况下,外网IP只需在该网段内唯一即可。而在内侧网段,所有主机,包括Nat自身的IP都可以任意决定,但为了避免和已有的外网IP冲突导致分不清内外侧的主机,一般都会是一些特殊格式,例如我们常见的“192.168.x.x”。
假设HostA位于Nat的内侧,那么在HostA第一次用自己的端口PortA向位于外部网段的HostB发送数据的时候,Nat首先会遵循传统路由器的行为,根据路由表找出HostB位于哪个外侧网段上。然后,它会在自身的内存中新建一对映射关系 (HostA, PortA) <-> (HostX, PortX),其中 HostX 是Nat在对应外侧网段的IP地址,而 PortX 是为此关系动态分配的一个空闲端口。建立映射后,Nat会偷偷修改IP数据报的首部,把源地址从 HostA 改成 HostX,还会修改数据报的内容,把源端口从 PortA 改成 PortX(注意“端口”是传输层的概念,位于TCP或UDP数据包的首部,不属于IP数据报的首部)。最后,它又会像一个传统路由器那样,把数据报转发向下一跳路由器。这样一来,由于数据报的源地址和端口都被改成了Nat的,位于外侧网段的HostB不会意识到HostA的存在,而所有来自HostA的通信都像是由Nat发起的。于是,它会被“蒙在鼓里”,将属于Nat的 (HostX, PortX) 作为目标地址和目标端口来发送响应。Nat在收到响应后,会利用数据报中的 (HostX, PortX) 作为 key,从映射表中查找出 (HostA, PortA),然后根据条目内容再一次修改数据报,把目的地址改成HostA,目的端口改成PortA,最后把数据报转发给内网的HostA。HostA也不会意识到Nat对这个数据报动的手脚,因为Nat只改动了目的地址,而没有改动源地址。在HostA看来,这个数据报的来源就是 (HostB, PortB),没有任何异常之处。于是,它就高兴地接受了这个数据报。在后续的通信中,这个映射关系也会一直保留下去,直到一段时间没有使用后被Nat删除(这也是TCP长连接需要发送心跳包保活的主要原因)。
以上就是NAT的完整工作流程了。从上面的描述中可以看出,NAT是一种跨越网络层和传输层的,对通信双方和中间路由透明的外网地址复用手段。由于内网中的所有IP经NAT转换后,都只对应着一个由NAT设备持有,和它们毫不相干的外网IP,自然就不用考虑为每个内网设备分配一个在外网中唯一的IP了。

NAT的固有缺陷

俗话说“没有银弹”,看似美好的NAT技术也有着一个致命的缺陷:NAT内侧的设备无法作为连接的接受方,换句话说,不能作为服务器。理由很显然:在HostA没有主动向外侧发起连接的情况下,NAT设备中根本没有对应的映射关系,无论外网设备访问Nat的哪个端口,都没办法让Nat将数据转发给A,除非在Nat中手动配置一个静态的关系(家用路由器中的“端口映射”设置就是做这个的)。这个问题在传统的C/S模式下还没那么严重,因为服务器一般都有自己的公网IP;但在P2P网络中,每个主机都需要扮演服务器的角色,被动接受其他主机的连接。因此,NAT后的主机根本无法成为有效的P2P节点。例如,P2P下载速度在国内很慢的主要原因,就是国内的ISP大量使用了NAT技术,导致用户只能从他人处下载数据,而无法接受他人的下载请求,长久一来,其他下载者也不愿意向用户提供数据了。因此,人们对P2P应用的需求,催生了各种NAT穿透技术。

NAT类型

在讲解NAT穿透的各种方式前,首先有必要了解NAT的不同类型,以便 “逐个击破”。总的来说,NAT主要分为两大类:

  • 锥型(Cone)
  • 对称型(Symmetric)(D类)

其中锥形NAT还分为以下三个子类:

  • 完全(Full)(A类)
  • 地址受限型(Address Restricted)(B类)
  • 端口受限型(Port Restricted)(C类)

习惯上,还可以用后面括号中的字母代指NAT类型。

锥型NAT vs 对称型NAT

锥型NAT和对称型NAT的主要区别,在于内部主机向不同的外部地址发送数据时,NAT设备的行为。下面我们假设Nat中已经存在了映射关系 (HostA, PortA) <-> (HostX, PortX),而这个关系是HostA通过访问 (HostB, PortB) 建立的。

  • 在锥型NAT中,只要HostA继续用PortA发送数据,不管发送给谁,这个数据的外网侧源端口都会被转换成PortX。
  • 在对称型NAT中,只要 (HostB, PortB) 中的任意一项发生了变化,哪怕源端口依然是PortA,路由器也会建立一个新的映射关系,分配一个新的外网端口向这个目标进行转发。

用形式化的说法来总结的话,锥型NAT的映射函数是 (内网源IP, 源端口) <-> (外网IP, 外网端口),而对称型NAT的映射函数是 (内网源IP, 源端口, 目标IP, 目标端口) <-> (外网IP, 外网端口)。显然,对称型NAT对内网设备的限制更大,穿透难度也更大。
此外,一个NAT设备在同一外网网段中还可能会拥有多个IP,在建立映射关系的过程中,NAT设备会根据实际的网络使用情况,从IP地址池中为每条映射关系分配一个合适的外网IP。为简略起见,在之后的讨论中,我们忽略外网IP的选择和后续路由过程,直接假设NAT设备只有唯一一个外网IP,也就是将映射右侧的 (HostX, PortX) 简化为 (PortX)。

锥型NAT的三个子类

锥型NAT三个子类的主要区别,在于外部主机向Nat上已经建立过映射关系的端口发送数据时,NAT设备的行为。下面我们依然假设存在映射关系 (HostA, PortA) <-> (PortX),而这个关系是HostA通过访问 (HostB, PortB) 建立的。

  • 在完全锥型NAT中,NAT设备会无条件将PortX收到的数据报转发给 (HostA, PortA),不论数据报来自何处。
  • 在地址受限型NAT中,只有来自HostB的数据报才会被转发,但不限制来自HostB的哪个端口。
  • 在端口受限型NAT中,只有来自 (HostB, PortB) 的数据报才会被转发。
  • 对称型NAT在这方面的行为和端口受限型NAT一致。
    可见,三个子类的限制依次加强,穿透难度也依次增加。

NAT穿透

首先给出(笔者个人)对NAT穿透的定义:一种在外网中继节点的帮助下,让两个位于各自NAT后的主机建立点对点连接的手段。从以上定义中可以看出:

  • 只有通信双方都位于NAT后面时,才需要进行穿透。如果任意一方拥有外网地址,只需让该主机作为连接接受方,另一方作为连接发起方即可。
  • NAT穿透必须有一个拥有外网IP的中继节点的帮助,但连接建立后发送的数据并不经过中继节点,否则就和流量转发没有区别了。

接下来,我们将通信双方的NAT类型分为三种情况,分别讨论对应的穿透手段。下面我们假设HostA和HostB之间要建立连接,它们所属的NAT设备分别为NatA(外网地址为 HostNA)和NatB(外网地址为 HostNB),中继节点为Relay。

双方都是ABC类NAT

这是最简单的情况,流程如下:

  1. HostA通过端口PortA,向Relay发送一个数据报,用一个唯一的主机ID进行注册。Relay收到数据报后,可以提取出NatA的外网地址,以及NatA为此次连接新分配的端口号,表示为 (HostNA, PortNA)。
  2. 当HostB希望向HostA发起连接时,首先要通过某种手段获取到HostA的主机ID(一般也是通过中继服务器),然后通过端口PortB,向Relay发出请求查询对应的 (HostNA, PortNA)。此时,NatB也会为HostB分配一个新的端口PortNB。Relay收到请求后,不仅向B返回数据,还会向HostA通知HostB的连接意图,并附带上NatB的对应信息 (HostNB, PortNB)。由于HostA刚刚在NatA上建立了和Relay的映射关系,这个消息可以成功到达HostA。
  3. HostA通过和之前相同的端口PortA,向 (HostNB, PortNB) 发送一个数据报。由于NatB有可能是B类或C类,而HostA(在NatB看来是NatA)之前没有向NatB发送过任何数据,这个数据报不一定会被转发给HostB,但会在NatA上建立一条目的地址是 (HostNB, PortNB) 的映射关系,让所有来自 (HostNB, PortNB) 并且目的端口为 PortNA 的数据都能转发给 HostA 的 PortA。
  4. HostB通过和之前相同的端口PortB,向 (HostNA, PortNA) 发出真正的连接请求。由于第2步中已经建立了PortB到PortNB的映射关系,这个请求在外网的源端口依旧会是PortNB。又由于第3步中HostA已经在NatA上建立了和 (HostNB, PortNB) 相关的映射关系,这个请求以及后续数据会成功地被NatA转发给HostA。
  5. HostA向 (HostNB, PortNB) 发送回复。由于第4步中NatB上已建立好映射关系,回复以及后续数据会成功地被NatB转发给HostB。于是,连接成功建立。

注意:1、3、5步HostA发送信息使用的端口PortA必须是同一个,2、4步HostB的端口PortB也必须是同一个。原因留给大家自行思考,结合锥形NAT的定义就能很快得出答案。
第3步中HostA向NatB发送数据报的过程被形象地称为“打洞”,因为这个数据报虽然不一定被NatB所接受,却可以在NatA上开一个“洞”,来自NatB的后续数据都可以从“洞”里进来到达HostA。退一步来说,假设NatA是一个完全锥型NAT,甚至连打洞都不需要,HostB在第2步从Relay获取到 (HostNA, PortNA) 后,直接向该地址发送连接请求即可。

一方是D类NAT,另一方是AB类NAT

这种情况和上一种差不多,但“打洞”的一方必须是位于AB类NAT后的那方。具体流程和上面相同,只是要把AB类NAT后的一方看成HostA,另一方看成HostB即可。
为什么D类NAT不能打洞?这是因为在第3步中,就算HostA使用了和第1步相同的端口PortA,由于目的地址从Relay变成了HostNB,NatA也会建立一条新的映射关系,不会使用之前PortA对应的端口PortNA。如此一来,这个“洞”的信息除了NatA本人以外,没有任何人知道,HostB也就无从得知应该向NatA上的哪个端口发送数据,才能成功“进洞”到达HostA了。

一方是D类NAT,另一方是CD类NAT

不幸的是,这种情况下NAT穿透是不可行的,只能通过位于外网上的中继服务器来转发HostA和HostB之间的一切流量。
照理说,C类NAT也属于锥形,为何面对D类NAT时却不能成功打洞了?原因很简单,如果对面是D类NAT,就算在NatA上打了洞,第4步HostB发起连接时,就算使用和第2步相同的端口PortB,由于目标地址从Relay变为了HostNA,NatB也会建立一条新的映射关系,不会使用之前PortB对应的端口PortNB。这样一来,由于传入数据报的源端口和之前打洞时约定好的PortNB不同,“端口受限型”的NatA就会拒绝将数据转发给HostA,也就是“进不去洞”。假如NatA是AB类的话,只要传入数据报的源IP保持HostNB不变,数据就可以成功“进洞”。

NAT穿透相关协议

  • 部署STUN协议的服务器可以检测用户的NAT类型,并且告知用户在公网上的IP地址。
  • 部署TURN协议的服务器可以在无法穿透时转发用户的TCP和UDP流量。
  • UPnP协议允许应用主动在(任何类型的)NAT上打洞,并且让这个洞的表现看起来像是完全锥型NAT。

这些协议的具体细节就不再详细叙述了,感兴趣的读者可以自行了解。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/34673.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信