STUN 协议
- [深入浅出 STUN 协议:从 NAT 困境到抓包实战](#深入浅出 STUN 协议:从 NAT 困境到抓包实战)
- [一、NAT 带来的困扰:你不知道你长什么样](#一、NAT 带来的困扰:你不知道你长什么样)
- [二、STUN 是什么?](#二、STUN 是什么?)
- [三、STUN 的工作流程,一句话概括](#三、STUN 的工作流程,一句话概括)
- [四、一个最简 STUN 抓包分析](#四、一个最简 STUN 抓包分析)
-
-
- [4.1 绑定请求(客户端 → STUN 服务器)](#4.1 绑定请求(客户端 → STUN 服务器))
- [4.2 绑定成功响应(STUN 服务器 → 客户端)](#4.2 绑定成功响应(STUN 服务器 → 客户端))
- [4.3 XOR 解码:还原真实公网地址](#4.3 XOR 解码:还原真实公网地址)
-
- [五、STUN 并非万能:TURN 与 ICE 的配合](#五、STUN 并非万能:TURN 与 ICE 的配合)
- [六、 安全与使用须知](#六、 安全与使用须知)
- 七、总结
深入浅出 STUN 协议:从 NAT 困境到抓包实战
我们在日常上网中,几乎都躲不开 NAT(网络地址转换)。家里的手机、电脑、平板共享一个公网 IP,NAT 让 IPv4 地址短缺问题得以缓解,但同时也给 P2P 通信(比如 WebRTC 视频通话、游戏联机)出了一道难题:"藏在 NAT 后面的设备,怎么告诉对方自己的'真实'地址?"
今天就来聊聊这道题的解法之一------STUN 协议。
一、NAT 带来的困扰:你不知道你长什么样
假设你的电脑在局域网里的地址是 192.168.1.10:5000,你想和一个远方的朋友进行 P2P 视频聊天。你把自己的私有地址告诉对方,对方肯定连不上,因为这个地址只在你的局域网内有效。
真正让双方相连的,是你的设备经过 NAT 后得到的公网 IP 和端口。但问题是,你的设备自己并不知道这个公网映射地址是多少------NAT 设备默默地做了转换,也没有主动通知你。
就像你住在一栋大楼里,你只知道自己的房间号,却不知道大楼在街道上的门牌号。你需要一个"门牌号查询服务",STUN 就是这个服务。
二、STUN 是什么?
STUN(Session Traversal Utilities for NAT,NAT 会话穿越工具)是一个轻量级的网络协议,定义在 RFC 5389。它的核心作用就两个:
- 帮助位于 NAT 后面的设备发现自己的公网 IP 和端口(即映射地址)。
- 帮助判断当前 NAT 的类型(完全锥形、受限锥形、端口受限锥形、对称型),从而评估进行 P2P 打洞的可行性。
STUN 本身不负责数据中转,它只是一个"地址发现"的工具,是建立 P2P 连接的第一步。
三、STUN 的工作流程,一句话概括
客户端向公共 STUN 服务器发一个请求,服务器收到后,看到请求来自某个公网 IP 和端口,就把这个地址原封不动地告诉客户端。
这个过程在协议里叫 Binding Request / Binding Response(绑定请求/响应)。如果你用 Wireshark 抓包,就能看到下面的经典交互。
四、一个最简 STUN 抓包分析
为了让大家有直观感受,下面给出一个真实的 IPv4 + UDP 下的 STUN 绑定请求和响应样例(十六进制),并逐字段拆解。无论你用 Google 的公共 STUN 服务器 stun.l.google.com:19302,还是自己搭的,看到的包结构都一样,只是事务 ID 和属性有区别。
4.1 绑定请求(客户端 → STUN 服务器)
客户端的内网地址是 192.168.1.10:5000,STUN 服务器地址 203.0.113.100:3478。请求非常简单,可以不带任何属性,头部固定 20 字节。
原始十六进制:
00 01 00 00 21 12 A4 42 B7 E7 A7 01 3B C8 F4 A2
D1 E2 A3 B4 C5 D6 E7 F8
字段拆解:
| 偏移 | 长度 | 字段 | 值 | 含义 |
|---|---|---|---|---|
| 0 | 2 | Message Type | 0x0001 |
Binding Request(绑定请求) |
| 2 | 2 | Message Length | 0x0000 |
后续没有属性,长度为 0 |
| 4 | 4 | Magic Cookie | 0x2112A442 |
固定魔数,用于区分 STUN 和其他协议 |
| 8 | 12 | Transaction ID | B7E7A7013BC8F4A2 D1E2A3B4C5D6E7F8 |
随机生成,用于匹配请求和响应 |
4.2 绑定成功响应(STUN 服务器 → 客户端)
服务器收到请求时,会记下这个 UDP 包来源的公网地址(由你路由器 NAT 转换出来的),假设是 203.0.113.5:45000,然后把这个地址放在 XOR-MAPPED-ADDRESS 属性里返回。
原始十六进制:
01 01 00 0C 21 12 A4 42 B7 E7 A7 01 3B C8 F4 A2
D1 E2 A3 B4 C5 D6 E7 F8 00 20 00 08 00 01 8E DA
AA 12 D5 47
逐字段解析:
- 头部(20 字节)
| 字段 | 值 | 说明 |
|---|---|---|
| Message Type | 0x0101 |
Binding Success Response(绑定成功响应) |
| Message Length | 0x000C (12) |
后面携带的属性总长度为 12 字节 |
| Magic Cookie | 0x2112A442 |
同上 |
| Transaction ID | 与请求完全相同 | 用于客户端匹配到对应的请求 |
- 属性:XOR-MAPPED-ADDRESS(本次响应唯一属性,12 字节)
| 偏移 | 长度 | 子字段 | 值 | 说明 |
|---|---|---|---|---|
| 0 | 2 | Attribute Type | 0x0020 |
XOR-MAPPED-ADDRESS |
| 2 | 2 | Attribute Length | 0x0008 |
属性值长度为 8 字节 |
| 4 | 1 | Reserved | 0x00 |
固定保留 |
| 5 | 1 | Address Family | 0x01 |
IPv4 |
| 6 | 2 | X-Port | 0x8EDA |
经过 XOR 混淆的端口 |
| 8 | 4 | X-Address | 0xAA12D547 |
经过 XOR 混淆的 IPv4 地址 |
为什么要 XOR?
以前的
MAPPED-ADDRESS属性是明文传递公网地址,容易被一些行为不端的 NAT 或应用层网关(ALG)误修改,导致地址错误。XOR 后的地址对中间设备没有意义,避免了此类篡改问题。
4.3 XOR 解码:还原真实公网地址
XOR 混淆所用的密钥就是 Magic Cookie(0x2112A442)。规则如下:
-
端口还原 :
X-PortXOR Magic Cookie 的高 16 位
0x8EDA XOR 0x2112 = 0xAFC8→ 十进制是 45000 -
IP 还原 :
X-AddressXOR Magic Cookie
0xAA12D547 XOR 0x2112A442 = 0xCB007105转成点分十进制:
0xCB = 203,0x00 = 0,0x71 = 113,0x05 = 5→ 203.0.113.5
最终,客户端成功解读出自己的公网映射地址:203.0.113.5:45000。现在它就可以把这个地址通过信令服务器告诉通话对方,尝试直接 P2P 连接了。
五、STUN 并非万能:TURN 与 ICE 的配合
有了 STUN 只是拿到了"候选地址",但如果你的 NAT 是对称型(Symmetric NAT) ,每次向不同目标发送请求时分配的端口都不一样,这时单纯的 STUN 打洞就很可能失败。怎么办呢?于是就有了更完整的框架 ICE(Interactive Connectivity Establishment),它综合使用三种候选地址:
- 主机候选(本地地址)
- 服务器反射候选(通过 STUN 获取的公网地址)
- 中继候选(通过 TURN 服务器中转的地址)
TURN(Traversal Using Relays around NAT)是一个实实在在的中继服务器,当 P2P 直连失败时,数据会通过 TURN 服务器转发。TURN 走的是"有保证但消耗服务器资源"的路子,STUN 走的是"免费但可能不成功"的路子。
所以现实中的 WebRTC 应用,一般会同时配置 STUN 和 TURN 服务器,由 ICE 自动尝试各种连接方式,选出最优路径。
六、 安全与使用须知
- STUN 本身不提供加密:它只做地址发现,实际通信安全需要靠上层协议(比如 DTLS、SRTP)。
- 反射放大攻击风险:攻击者可能伪造源 IP 向公共 STUN 服务器发请求,让响应指向受害者 IP。因此公开的 STUN 服务器通常会做速率限制和源地址校验。
- 生产环境中莫滥用公共 STUN 服务器:免费的 Google STUN 适合测试,但严肃的线上业务最好部署自己的 STUN 服务。
七、总结
STUN 协议小巧而精悍,它用最朴素的方式解决了"我是谁"的问题。理解它的请求响应结构是深入掌握 P2P 通信、排查 WebRTC 连接问题的第一步。