STUN 协议

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-Port XOR Magic Cookie 的高 16 位
    0x8EDA XOR 0x2112 = 0xAFC8 → 十进制是 45000

  • IP 还原
    X-Address XOR Magic Cookie
    0xAA12D547 XOR 0x2112A442 = 0xCB007105

    转成点分十进制:0xCB = 203, 0x00 = 0, 0x71 = 113, 0x05 = 5203.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 连接问题的第一步。

相关推荐
mzhan0172 小时前
Linux: coredump产生对程序退出的影响
linux·运维·服务器
利来利往2 小时前
ubuntu设置永不休眠
运维·服务器
遇印记2 小时前
软考知识点
运维·服务器·网络
源远流长jerry2 小时前
Linux 网络收包机制:从网卡到 Socket 的完整路径
linux·运维·服务器·网络·网络协议·tcp/ip
qq_364371722 小时前
基于 Docker 容器化环境配置
运维·docker·容器
我命由我123453 小时前
Windows 操作系统 - Windows 查看架构类型
运维·windows·笔记·学习·系统架构·运维开发·系统
goyeer3 小时前
【ITIL4】34服务实践 - 服务请求管理
运维·it·数字化·信息化·itil·信息化企业管理
运维全栈笔记4 小时前
基于Docker的MinIO单机部署与功能测试指南
运维·docker·容器
Gc9umsbL14 小时前
零基础学Linux:21天从“命令小白”到独立部署服务器
linux·运维·服务器