RFC3489(STUN)简介
RFC3489(Session Traversal Utilities for NAT,早期称为 Simple Traversal of UDP Through NAT)是最初定义的 STUN 协议,用于帮助客户端在有 NAT(网络地址转换)或防火墙的网络环境中,探测自身在公网上所“呈现”出来的 IP 地址和端口,并推断出 NAT 的类型,从而实现点对点通信(尤其是 UDP 通信)的打洞与穿透。
自 RFC3489 发布后,IETF 又在其基础上进行了修订并发布了 RFC5389,定义了更为通用的 STUN(Session Traversal Utilities for NAT)。但如果我们关注的是 RFC3489 的检测流程,以下内容将对其做一个较为完整的介绍。
RFC3489 检测流程概述
RFC3489 规定了一个通过发送多个 STUN Binding Request 到 STUN 服务器(一般包含至少两个地址或端口)来判断 NAT 类型的流程。它主要基于以下假设:
- 服务器可同时在两个不同地址或端口上侦听(通常称为
Server Reflexive Transport Address #1
和Server Reflexive Transport Address #2
)。 - 客户端可以根据 STUN 服务器返回的结果(Binding Response)来判断自己“看到”的外部 IP 地址及端口,以及基于对不同测试行为结果的分析,推断 NAT 的行为模式。
注意:随着互联网的发展和 NAT 技术的多样化,RFC3489 中的 NAT 类型检测算法在实际环境中并不总是准确;后来才有了更完善的 RFC5389 / ICE(Interactive Connectivity Establishment)等方案。不过理解 RFC3489 的经典检测流程,对于理解 NAT 和 STUN 依然有帮助。
关键概念
- Mapped Address
客户端从 STUN 服务器收到的MAPPED-ADDRESS
属性(在 Binding Response 中),表示服务器看到的源 IP 与端口,即“公网上”映射出的地址。 - Changed Address
STUN 服务器在响应中可能会携带CHANGED-ADDRESS
属性,用于指示另一个可用于测试的 STUN 服务器地址或端口(RFC3489 中常常是同一物理服务器上的另一个端口或 IP)。 - NAT 类型
RFC3489 按照不同的 NAT 行为,将 NAT 分为以下几类:- Full Cone NAT
- Restricted Cone NAT
- Port Restricted Cone NAT
- Symmetric NAT
以及在无 NAT 的情况即“Open Internet”。
RFC3489 检测流程详解
下文给出了经典的 RFC3489 检测流程示例。实际使用中,客户端需要实现一个简单的“状态机”,根据不同测试步骤获得的结果来判断 NAT 类型。
步骤 1: 基础测试 I (Test I)
客户端 → 服务器(IP1:PORT1)
- 客户端向 STUN 服务器(第一个地址/端口,记为
IP1:PORT1
)发送一个 Binding Request,请求返回自身的外部映射地址。
- 客户端向 STUN 服务器(第一个地址/端口,记为
服务器响应
- 服务器收到请求后,将客户端源地址作为
MAPPED-ADDRESS
写入 Binding Response 中。 - 同时在 Binding Response 中携带
CHANGED-ADDRESS
,即服务器可用来进行后续测试的“备用地址/端口” (IP2:PORT2
)。
- 服务器收到请求后,将客户端源地址作为
客户端处理响应
若客户端收到了正确的响应,则可以在返回的消息里读取
MAPPED-ADDRESS
。假设该地址为MappedAddr1
。判断
MappedAddr1
与客户端自身的本地绑定地址是否相同:- 如果相同,说明客户端可能不在 NAT 后(或在一个 Full Cone NAT 中)。继续进行下一步测试以确认具体类型。
- 如果不同,说明客户端在 NAT 后,需要进一步测试确定 NAT 种类。
步骤 2: 基础测试 II (Test II)
- 客户端 → 服务器(IP1:PORT1),但在请求中指定
CHANGE-REQUEST
- 客户端这次仍然向
IP1:PORT1
发送 Binding Request,但是在 STUN 消息的属性中带上CHANGE-REQUEST
,要求服务器使用与之前不同的地址和端口(即IP2:PORT2
)来发送响应。
- 客户端这次仍然向
- 服务器行为
- 如果服务器实现了 RFC3489,则会检查
CHANGE-REQUEST
属性,如果属性中指定要“Change IP 和 Change Port”,那么服务器就会从IP2:PORT2
向客户端发送响应。
- 如果服务器实现了 RFC3489,则会检查
- 客户端的结果判断
- 如果客户端 能收到 服务器从
IP2:PORT2
发来的响应,则意味着客户端的 NAT 不会阻止来自不同地址和端口的 UDP 数据包通过。这通常表明客户端所在网络是 Open Internet 或 Full Cone NAT。 - 如果客户端 收不到 响应,则通常意味着客户端所在的 NAT 会阻止来自不同 IP/端口的响应包,这一现象多与 Symmetric NAT 或者 (Port) Restricted Cone NAT 类型相匹配。为了区分,还需要下一步测试。
- 如果客户端 能收到 服务器从
步骤 3: 备用地址测试(Test III)
- 客户端 → 服务器(IP2:PORT2)
- 这次,客户端直接向服务器的另一个地址和端口
IP2:PORT2
(即CHANGED-ADDRESS
)发送 Binding Request。
- 这次,客户端直接向服务器的另一个地址和端口
- 服务器响应
- 服务器收到请求后,会返回客户端的
MAPPED-ADDRESS
,记为MappedAddr2
。
- 服务器收到请求后,会返回客户端的
- 比较
MappedAddr1
与MappedAddr2
- 如果
MappedAddr1
与MappedAddr2
不同(即,分别是不同的外部端口或 IP),那么通常可以判定为 Symmetric NAT。因为 Symmetric NAT 的映射端口取决于目的地址/端口,对不同目标地址时会出现不同的外部端口。 - 如果
MappedAddr1
与MappedAddr2
相同,则说明 NAT 在面对不同的服务器地址时依旧使用同一个外部映射,即不是 Symmetric NAT。结合之前的结果,可以判断是 Restricted Cone NAT 或 Port Restricted Cone NAT。
- 如果
流程图
常见结果与 NAT 类型判定
以下是根据上述三个测试的可能结果,结合 RFC3489 给出的 NAT 类型划分示例:
- Open Internet
- 在 Test I 中,
MappedAddr1
与本地地址相同; - 在 Test II 中可以收到响应。
- 说明无 NAT 或路由器不进行地址转换。
- 在 Test I 中,
- Full Cone NAT
- Test I 中,
MappedAddr1
≠ 本地地址,表示存在 NAT; - Test II 中可以收到响应,说明对于外部地址/端口的变化并不受限;
- 进一步测试可能仍会得到相同的
MAPPED-ADDRESS
。
- Test I 中,
- Restricted Cone NAT 或 Port Restricted Cone NAT
- Test I 中,
MappedAddr1
≠ 本地地址; - Test II 中收不到响应;
- Test III 中,
MappedAddr1
==MappedAddr2
。 - 说明对于来自外部的地址(或端口)存在一定限制,但对同一外部地址使用相同的映射端口。
- Test I 中,
- Symmetric NAT
- Test I 中,
MappedAddr1
≠ 本地地址; - Test II 中收不到响应;
- Test III 中,
MappedAddr1
与MappedAddr2
不同。 - 说明在不同外部目的地址时,客户端会被 NAT 分配不同的映射端口。
- Test I 中,
小结
- RFC3489 的检测流程主要是依赖一台可以在“两个地址或端口”上提供 STUN 服务的服务器,通过客户端向这两个地址发送请求并观察响应结果来推断 NAT 类型。
- 关键属性包括
MAPPED-ADDRESS
和CHANGED-ADDRESS
,以及CHANGE-REQUEST
选项,用来探测 NAT 对外部流量的限制程度。 - 典型的三个测试(Test I, Test II, Test III)可帮助判断是否有 NAT,以及 NAT 的类型是 Full Cone、Restricted Cone、Port Restricted Cone 还是 Symmetric。
- RFC3489 虽已被 RFC5389 取代,但它所示范的 NAT 探测流程仍然是理解 NAT 行为和 STUN 工作原理的经典参考。