NAT类型

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

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

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

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

习惯上,还可以用后面括号中的字母代指NAT类型。在之后的讨论中,为简略起见,我们假设NAT设备只有一个外网IP。

锥型NAT vs 对称型NAT

锥型NAT和对称型NAT的主要区别,在于内部主机向新的外部地址发送数据时,NAT设备的行为。下面我们假设内部主机的端口X已经和NAT设备的外网端口Y建立了映射关系。在两种NAT中,这个关系都会一直保持下去,直到一段时间没有使用后被删除。

  • 在锥型NAT中,只要内部主机继续用端口X发送数据,不管发送给谁,这个数据的外网侧源端口都会被转换成Y。
  • 在对称型NAT中,只要发送目标的IP或者端口发生了变化,哪怕源端口依然是X,路由器也会建立一个新的映射关系,用一个新的外网端口向这个目标进行转发。

用形式化的说法来总结的话,锥型NAT的映射函数是(内网源IP,源端口)-》(外网端口),而对称型NAT的映射函数是(内网源IP,源端口,目标IP,目标端口)-》(外网端口)。显然,对称型NAT对端口资源的消耗更大,对内网设备限制也更大,因此穿透难度也更大。

锥型NAT的三个子类

锥型NAT三个子类的主要区别,在于外部主机向已经建立映射关系的端口发送数据时,NAT设备的行为。下面我们依然假设内部主机A的端口X已经和NAT设备的外网端口Y建立了映射关系。此外,假设这个映射关系是A通过访问外网主机B的端口Z建立起来的。

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

NAT穿透

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

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

接下来,我们将通信双方的NAT类型分为三种情况,对相应的穿透手段分别进行讨论。下面我们假设A和B之间要建立连接,它们的NAT设备分别为NA和NB,中继节点为S。

双方都是ABC类NAT

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

  1. A向S发送一个数据报,S收到的数据报会拥有NA的源地址和一个在NA上新分配的源端口X。
  2. B向S发出请求,获取NA的地址和端口X。S在收到B向A的连接请求后,会把请求中包含的NB源地址和端口Y回传给A。由于A刚刚在NA上建立了和S的映射关系,这个消息可以成功到达A。
  3. A向NB的端口Y发送一个任意数据报,这个数据报依旧拥有端口X(回忆下锥型NAT的定义)。它不会到达B,但会在NA上允许来自NB端口Y的数据由端口X传入并到达A。
  4. B向NA的端口X发出连接请求。由于这个请求依旧拥有端口Y,它会被NA转发给A。
  5. A向NB的端口Y发送回复,回复会被NB转发给B,连接成功建立。

注意:1、3、5步A发送信息使用的端口必须是同一个,2、4步B的端口也必须是同一个。个中原因留给大家自行思考,结合之前的NAT原理就能很快得出答案。
第三步A向NB发送数据报的过程被形象地称为“打洞”,因为这个数据报成功在NA上开了一个“洞”,来自NB的外部连接可以从“洞”里进来到达A。退一步来说,假设NA是一个完全锥型NAT,甚至连打洞都不需要,B在收到NA的地址和端口后,直接向那里发送连接请求即可。

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

这种情况和上一种差不多,但“打洞”的一方必须是位于AB类NAT后的那方。具体流程和上面相同,只是要把AB类NAT后的一方看成A,另一方看成B。
为什么D类不能打洞?因为在第三步中,就算A使用了和第一步相同的端口,在NA上也会被转换为和X不同的另一个端口。这样一来,B还是无法向X发送数据,因为X并没有和NB建立联系。A也没办法把这个新端口告诉B,因为这个端口A不知道,S也不知道。

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

不幸的是,这种情况下NAT穿透是不可行的,只能通过中继服务器来转发A和B之间的一切数据。
那么,为什么C类也不能打洞了?原因很简单,如果对面是D类NAT,就算打了洞,第四步也会失败,因为B无法用之前约定好的端口Y来连接NA,也就是“进不去洞”。如果打洞者换成B类就好说了,这种情况下只要NB的IP不变,连接请求就可以“进洞”。

NAT穿透相关协议

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