NAT (Network Address Translation) 是一种在 IP 数据包通过路由器或防火墙时,修改 IP 地址信息 (通常是 IP 地址和端口号) 的技术。其主要目的是缓解 IPv4 地址枯竭问题,并为内部网络提供地址隐藏和一定的安全性。然而,NAT 也为点对点 (P2P) 通信带来了挑战,因为不同类型的 NAT 对数据包的转发行为差异巨大。

通过了解 NAT 的不同类型,我们可以选择合适的 NAT 穿越技术 (如 STUN, TURN, ICE) 来实现内网设备间的直接通信。


一、NAT 的基本概念与作用

基本概念: NAT 是将一个 IP 地址空间映射到另一个 IP 地址空间的技术。最常见的是将私有 IP 地址(如 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)映射到公有 IP 地址。

主要作用:

  1. 缓解 IPv4 地址枯竭:允许一个公网 IP 地址被多个内网设备共享,大大减少所需公网 IP 的数量。
  2. 隐藏内部网络拓扑:对外只暴露一个或少数几个公网 IP 地址,内部网络结构对外部透明,增加了一定的安全性。
  3. 连接外部网络:内部设备可以通过 NAT 访问外部互联网资源。

二、NAT 的核心挑战:P2P 通信

虽然 NAT 带来了诸多便利,但对需要直接通信的 P2P 应用(如 VoIP、视频会议、在线游戏、文件共享)而言,却是巨大的障碍。主要原因如下:

  • 地址翻译:外部设备无法直接通过私有 IP 地址定位到内网设备。
  • 不请自来连接的困难:NAT 设备通常只会转发“已建立连接”或“由内网主动发起”的流量。外部设备主动发起的请求,如果没有预先的映射或打洞,通常会被 NAT 丢弃。
  • NAT 类型多样性:不同 NAT 设备对流量的转发规则差异很大,导致 NAT 穿越的复杂性增加。

三、NAT 类型详解

RFC 3489 和后续的 RFC 5780 (更新) 定义了不同类型的 NAT,这些类型决定了 NAT 穿越的难易程度。主要分为四种:

3.1 全锥型 NAT (Full Cone NAT)

  • 定义:一旦内部 IP 地址 (Internal IP) 和端口 (Internal Port) 映射到外部 IP 地址 (External IP) 和端口 (External Port) 后,任何外部主机都可以向这个外部 IP:端口发送数据包,并被 NAT 设备转发到内部主机。原始请求的源地址和端口对后续通信没有影响。
  • 行为特征
    • 映射行为:内部私有 IP:端口 A 总是映射到相同的外部公网 IP:端口 B。
    • 过滤行为:当有数据包从外部流向内部映射端口 B 时,NAT 不会关心是谁发送的,只要目标是 B,就转发给 A。
  • P2P 友好度最友好。一旦打洞成功,任何外部客户端都可以与之通信。
  • 穿越难度最简单。STUN 协议可以轻松应对。
1
2
3
4
5
6
7
8
9
10
11
12
内网客户端 A (192.168.1.10:5000)
↓ 发送数据到 公网主机 X (203.0.113.1:80)
NAT 设备 (公网 IP: 203.0.113.1)
↓ 映射:192.168.1.10:5000 -> 203.0.113.1:PortX (映射固定)
公网主机 X (203.0.113.1:80)
↓ 接收数据
==========
现在,任何公网主机 (如 Y: 198.51.100.1:80)
↓ 都可以发送数据到 203.0.113.1:PortX
NAT 设备
↓ 将数据转发给 192.168.1.10:5000
内网客户端 A (192.168.1.10:5000)

3.2 地址限制锥型 NAT (Address-Restricted Cone NAT)

  • 定义:一旦内部 IP:端口映射到外部 IP:端口,只有当内部主机已经向某个外部主机 IP 发送过数据包后,该外部主机才能向这个外部 IP:端口发送数据包,并被转发。外部主机的端口号不影响转发。
  • 行为特征
    • 映射行为:内部私有 IP:端口 A 总是映射到相同的外部公网 IP:端口 B。
    • 过滤行为:当有数据包从外部流向内部映射端口 B 时,NAT 会检查数据包的源 IP 地址。如果内部主机之前曾向这个源 IP 发送过数据包,则转发;否则丢弃。
  • P2P 友好度中等友好。需要先由内部客户端发起一次通信才能打洞。
  • 穿越难度中等。STUN 协议可以应对,但需要多次探测。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
内网客户端 A (192.168.1.10:5000)
↓ 发送数据到 公网主机 X (203.0.113.1:P1)
NAT 设备 (公网 IP: 203.0.113.1)
↓ 映射:192.168.1.10:5000 -> 203.0.113.1:PortX (映射固定)
公网主机 X (203.0.113.1:P1)
↓ 接收数据
==========
现在,公网主机 X (203.0.113.1:P2,P2可变)
↓ 可以发送数据到 203.0.113.1:PortX
NAT 设备
↓ 将数据转发给 192.168.1.10:5000 (因为源 IP 203.0.113.1 已被 "允许")
内网客户端 A (192.168.1.10:5000)

但如果公网主机 Y (198.51.100.1:80) 发送数据到 203.0.113.1:PortX,将被 NAT 丢弃,因为 A 从未主动向 Y 发送过数据。

3.3 端口限制锥型 NAT (Port-Restricted Cone NAT)

  • 定义:比地址限制型更严格。只有当内部主机已经向某个外部主机 IP 和端口发送过数据包后,且外部主机从该特定源 IP 和源端口发送数据包时,才能被 NAT 转发。
  • 行为特征
    • 映射行为:内部私有 IP:端口 A 总是映射到相同的外部公网 IP:端口 B。
    • 过滤行为:当有数据包从外部流向内部映射端口 B 时,NAT 会严格检查数据包的源 IP 地址和源端口。只有当内部主机之前曾向这个特定的源 IP 和源端口发送过数据包,才转发;否则丢弃。
  • P2P 友好度较低。需要严格匹配源 IP 和端口才能打洞。
  • 穿越难度较高。STUN 协议可以应对,但打洞成功率取决于双方 NAT 类型组合。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
内网客户端 A (192.168.1.10:5000)
↓ 发送数据到 公网主机 X (203.0.113.1:P1)
NAT 设备 (公网 IP: 203.0.113.1)
↓ 映射:192.168.1.10:5000 -> 203.0.113.1:PortX (映射固定)
公网主机 X (203.0.113.1:P1)
↓ 接收数据
==========
现在,公网主机 X (203.0.113.1:P1)
↓ 可以发送数据到 203.0.113.1:PortX
NAT 设备
↓ 将数据转发给 192.168.1.10:5000 (因为源 IP:Port 203.0.113.1:P1 已被 "允许")
内网客户端 A (192.168.1.10:5000)

如果公网主机 X (203.0.113.1:P2,P2与P1不同) 发送数据到 203.0.113.1:PortX,将被 NAT 丢弃。
如果公网主机 Y (198.51.100.1:80) 发送数据到 203.0.113.1:PortX,也将被 NAT 丢弃。

3.4 对称型 NAT (Symmetric NAT)

  • 定义:每次内部主机向不同的目标 IP 地址或目标端口发送数据包时,NAT 设备都会为其分配一个新的外部端口进行通信。
  • 行为特征
    • 映射行为
      • 内部 IP1:Port1 -> 外部 IPX:PortA (目标 TgtIP1:TgtPort1)
      • 内部 IP1:Port1 -> 外部 IPX:PortB (目标 TgtIP1:TgtPort2) (PortB != PortA)
      • 内部 IP1:Port1 -> 外部 IPX:PortC (目标 TgtIP2:TgtPort1) (PortC != PortA, PortC != PortB)
      • 总之,外部端口号取决于目标地址和端口。
    • 过滤行为:与端口限制型 NAT 类似,只转发来自之前内部主机已与之通信过的特定源 IP 和源端口的数据包。
  • P2P 友好度最不友好。外部端口不固定,无法预测。
  • 穿越难度最高。STUN 协议无法有效穿透,通常需要 TURN 服务器中继。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
内网客户端 A (192.168.1.10:5000)
↓ 发送数据到 公网主机 X (203.0.113.1:P1)
NAT 设备 (公网 IP: 203.0.113.1)
↓ 映射:192.168.1.10:5000 -> 203.0.113.1:PortX (针对 X:P1)
公网主机 X (203.0.113.1:P1)
↓ 接收数据
==========
内网客户端 A (192.168.1.10:5000)
↓ 发送数据到 公网主机 Y (198.51.100.1:P2)
NAT 设备 (公网 IP: 203.0.113.1)
↓ 映射:192.168.1.10:5000 -> 203.0.113.1:PortY (针对 Y:P2,PortY != PortX)
公网主机 Y (198.51.100.1:P2)
↓ 接收数据
==========
此时,即使公网主机 X 想要向 203.0.113.1:PortX 发送数据,也可能无法成功,因为 PortX 只是针对 X:P1 的映射。如果 X 的源端口发生变化,或者 A 再次向 X 发送数据时,NAT 可能会使用一个全新的外部端口。

3.5 运营商级 NAT (Carrier-Grade NAT / CGN)

  • 特殊情况:这是一种特殊的 NAT 实现,通常由 ISP (互联网服务提供商) 在其网络内部部署,为多个用户提供私有 IP 地址,然后这些私有 IP 地址再通过另一层 NAT 映射到 ISP 的公网 IP 地址。
  • 多层 NAT:本质上就是多层 NAT。客户端可能位于两层甚至更多层 NAT 之后。
  • P2P 影响:使得 NAT 穿越变得异常困难,因为需要穿越多层 NAT,每一层 NAT 都可能增加额外的限制。大多数 P2P 直连在 CGN 环境下都会失败,往往需要 TURN 服务器进行中继。

四、如何判断 NAT 类型?

通常使用 STUN 协议来判断 NAT 类型。STUN 客户端通过向 STUN 服务器发送一系列精心设计的请求,并分析服务器的响应以及从不同源地址/端口发来的数据包,来推断出它所处的 NAT 类型。

简化流程:

  1. 客户端向 STUN 服务器发送请求,获取自身公网地址 (External IP:Port A)。
  2. 客户端向 STUN 服务器的不同端口发送请求,如果获取到不同的公网地址 (External IP:Port B != External IP:Port A),则为对称型 NAT。
  3. 如果不是对称型 NAT,STUN 服务器尝试从不同源 IP 向客户端的 External IP:Port A 发送数据。如果能收到,则为全锥型 NAT。
  4. 如果收不到,STUN 服务器尝试从相同源 IP 不同源端口向客户端的 External IP:Port A 发送数据。如果能收到,则为地址限制锥型 NAT。
  5. 如果收不到,则为端口限制锥型 NAT。

五、NAT 穿越机制

根据 NAT 类型的不同,我们采取不同的穿越策略:

  1. UDP 打洞 (UDP Hole Punching)

    • 原理:在对称型 NAT 之外的锥型 NAT 中有效。客户端首先向 STUN 服务器或对方客户端发送 UDP 数据包,让自己的 NAT 打开一个临时的打洞映射。然后,即使对方的 NAT 也在类似锥型 NAT 之后,也可以尝试直接向这个打通的洞发送数据进行连接。
    • 适用类型:全锥型、地址限制锥型、端口限制锥型 NAT。
    • 技术:主要依赖 STUN 协议获取公网地址和 NAT 类型,然后尝试直接连接。
  2. TCP 打洞 (TCP Hole Punching)

    • 原理:比 UDP 打洞复杂得多,因为 TCP 是面向连接的,需要三次握手。但基本思想类似,通过同时发送 SYN 包来“猜测”并打开一个临时的连接。
    • 适用类型:锥型 NAT,成功率不如 UDP。
  3. 中继 (Relaying)

    • 原理:当打洞无法成功时 (最常见于对称型 NAT 或多层 NAT),引入一个第三方服务器 (TURN 服务器) 作为中继,转发两个客户端之间的所有数据。
    • 适用类型:所有 NAT 类型,尤其是对称型 NAT 和 CGN。
    • 代价:增加网络延迟和服务器负载。
    • 技术:主要依赖 TURN 协议。
  4. 端口映射 (Port Mapping Protocols)

    • 原理:通过在内网路由器上配置端口映射规则,将内部端口映射到外部的特定端口,使其对外部可见。
    • 技术:UPnP (Universal Plug and Play) IGD (Internet Gateway Device) 和 NAT-PMP (NAT Port Mapping Protocol)。这些协议允许内网应用程序自动请求 NAT 设备进行端口映射。
    • 限制:需要路由器支持并启用这些功能,且存在一定的安全风险。
  5. ICE (Interactive Connectivity Establishment)

    • 原理:一个综合性的 NAT 穿越框架。它结合了 STUN、TURN 和其他打洞技术,通过收集所有可能的通信路径 (候选地址),然后进行连通性检查,并最终选择最佳的连接路径。
    • 适用类型:所有复杂场景。
    • 地位:WebRTC 等现代 P2P 通信技术中必不可少的组件。

六、总结

NAT 类型是理解和实现 P2P 通信的关键。从最开放的全锥型 NAT 到最严格的对称型 NAT,以及复杂的运营商级 NAT,它们对网络数据包的转发行为各不相同。针对不同的 NAT 类型,我们需要采取相应的 NAT 穿越策略,从简单的 UDP 打洞 (STUN) 到复杂的媒体中继 (TURN) 和智能路径选择 (ICE),以确保 P2P 通信的连通性、效率和可靠性。深入理解这些机制对于开发稳定且高性能的实时通信应用至关重要。