关于 WebRTC、ICE、STUN 与 TURN 检测
WebRTC 支持情况、ICE 候选与 STUN / TURN 检测工具在同一个页面上回答三个彼此独立的问题:当前浏览器是否提供 WebRTC API、你配置的每一个 STUN 或 TURN 服务能否从这个网络上得到应答、以及这台机器此刻能采集到哪些 ICE 候选。每个服务都单独检测、单独给结论,所以被屏蔽或已经下线的主机会表现为一行失败,而不是混进一个笼统的汇总数字里。
WebRTC 连接从来不是「连到你填的那个地址」。两端各自采集候选(也就是数据包有可能抵达的每一个地址),把候选交换给对方,再由 ICE 代理逐对探测,直到某一对通过。STUN 在这个过程中只贡献一件事:告诉你 NAT 把本地套接字映射成了哪个公网地址和端口,这就是服务器反射候选。TURN 贡献的则是中继服务器自身的一个传输地址,当两端都无法被直接触达时,只有这类候选还能用。几乎所有「这里 WebRTC 用不了」的反馈,最终都会落到三层之一:浏览器 API、候选采集、服务可达性。把它们分开检测,就不必再靠猜。
如何使用这个开发者工具
- 先看能力卡片:RTCPeerConnection、RTCDataChannel 和安全上下文。WebRTC 只在 HTTPS 或 localhost 下开放,所以纯 http:// 页面在触及任何网络问题之前就已经失败了。
- 添加你打算使用的服务。可以从内置的公共 STUN 目录里勾选,也可以手动输入自己的地址,例如 turn:turn.example.net:3478?transport=tcp。
- 为每一条 turn: 或 turns: 填写用户名与凭据。没有凭据的 TURN 行会直接判定为凭据缺失,而不会真的去探测。
- 运行服务检测。每一行单独探测、限时 4 秒,返回它产生的候选类型、传输协议、中继协议、映射地址和耗时。
- 运行候选检测,用完整配置一次性采集,然后看各类型的数量:这正是当前浏览器能够提供给对端的全部内容。
- 需要原始 SDP 行时展开候选卡片里的「原始候选」——foundation、优先级、关联地址和 ufrag 都在那一行里。
实例:逐字段读懂一条服务器反射候选
配置了一个 STUN 服务和一个 TURN 服务,在一台位于家用路由器后面的笔记本上运行候选检测,返回三条候选。第二条就是证明 STUN 应答成功的那一行,它的每一个字段都有信息量。
stun:stun.example.org:3478
turn:turn.example.net:3478?transport=udp
username: 1774915200:devtools
credential: q0Zp3rVYbK8n1xS2mE7aQd4Hcandidate:1854123094 1 udp 2122262783 9b8f0a1c-6d3e-42f7-9c0a-7f21b6d5e310.local 54123 typ host generation 0 ufrag Qq7A network-cost 999
candidate:842163049 1 udp 1686052863 203.0.113.44 54123 typ srflx raddr 0.0.0.0 rport 0 generation 0 ufrag Qq7A
candidate:3096142582 1 udp 41885439 198.51.100.7 60112 typ relay raddr 203.0.113.44 rport 54123 generation 0 ufrag Qq7A
逐字段拆解第二条 srflx:
842163049 foundation 标识共享同一基础地址、网卡与服务器的候选,ICE 据此跳过重复的配对探测
1 组件编号 1 表示 RTP;数据通道永远只有组件 1,出现 2 说明同时协商了媒体
udp 传输协议 这条候选与对端通信所用的协议
1686052863 优先级 由类型偏好(srflx 为 100)、本地偏好和组件编号合成,ICE 从高到低依次探测
203.0.113.44 地址 NAT 为该套接字映射出的公网地址,来自 STUN 绑定响应
54123 端口 该映射对外暴露的端口
typ srflx 类型 服务器反射:这条候选之所以存在,完全是因为 STUN 服务器回了包
raddr 0.0.0.0 关联地址 本地基础地址被隐去,因为 host 候选已被 mDNS 混淆
rport 0 关联端口 出于同样原因被隐去
ufrag Qq7A ICE ufrag 把候选绑定到本次采集会话,每次 ICE 重启都会变这条 srflx 就是 STUN 生效的证据:没有绑定响应,浏览器无从得知 203.0.113.44。还要注意它的端口 54123 与 host 候选的端口完全相同——路由器对不同目的地保持同一映射端口,属于端点无关映射,这是点对点连接最友好的情形。
四种 ICE 候选:各自能证明什么、又暴露什么
把结果面板上按类型统计的数量对照这张表来读,缺失的行和存在的行同样有信息量。STUN 只让运营方付出一个小包的代价,TURN 却要承载整场会话的全部流量,这就是为什么公共 STUN 遍地都是、而公共 TURN 基本不存在。只有当没有任何 host 或 srflx 候选对能通过连通性检查时才真正需要中继——典型情况是两端都处在对称 NAT 后面,或者网络彻底丢弃 UDP。
| 类型 | 由什么产生 | 出现它能证明什么 | 它暴露了什么 |
|---|---|---|---|
| host | 本地网卡,不涉及任何服务器,也没有人为流量付费。 | 浏览器成功枚举到网卡并在其上绑定了套接字。 | 你的内网地址——除非浏览器已把它替换成随机的 .local mDNS 名称,这是当前 Chrome 与 Firefox 的默认行为。 |
| srflx | 一次 STUN 绑定请求。STUN 服务器只回一个小包,从不承载业务数据。 | 出站 UDP 能够抵达该 STUN 服务,并且存在一个外部主机可寻址的 NAT 映射。 | 你的公网 IP 以及 NAT 选择的外部端口。STUN 运营方看到的是同一组信息。 |
| prflx | 连通性检查期间,收到了来自双方都没有通告过的地址的包。 | 存在一条采集阶段没有预测到的可用路径。 | 对端 NAT 会按目的地重新映射,这是对称 NAT 的强烈信号。 |
| relay | 一次 TURN 分配。会话的每一个字节都要经过 TURN 服务器,带宽全部由它的所有者承担。 | 凭据被接受,服务器在自身上分配了一个传输地址给你。 | 对端只能看到中继的地址,你自己的地址对对端隐藏,但对 TURN 运营方完全可见。 |
常见问题排查
所有 host 候选显示的都是一串随机的 .local 主机名,看不到内网 IP。
成因 Chrome 与 Firefox 会用 mDNS 名称混淆 host 候选,防止网页借此刻画你的内网结构。这个名称在本地子网内仍可通过多播 DNS 解析,所以同一局域网的两端照样能连上,被蒙住眼睛的只是页面里的 JavaScript。
解决办法 无需修复,这就是设计行为,工具会把这类候选标注为「已掩码」。如果你的目的恰恰是查看哪些本地地址会被泄露,应该用 Browser Leak Check 页面,那才是为这个问题准备的工具。
同一台主机的 STUN 行通过了,TURN 行却报不可达。
成因 从浏览器看,两种成因长得一模一样。时限型 TURN 凭据通常是对 unix 过期时间戳做的 HMAC,过期后在分配阶段被拒绝,返回的错误和服务器已死难以区分。另一种成因是传输:如果中继只在 3478 上提供 UDP,而本地网络丢弃 UDP,分配就永远完不成。
解决办法 重新生成凭据对,核对拿到的过期时间,然后改用 443 端口的 turns: 地址并加上 ?transport=tcp 重试。检测成功时,「中继协议」一列会告诉你实际承载这次分配的是哪种传输。
候选检测只返回 host,既没有 srflx 也没有 relay。
成因 出站 UDP 被丢弃了。企业网、校园网和酒店网络经常只放行 80 与 443 上的 TCP,这会直接掐死 3478 上的 STUN,连带掐死基于 UDP 的 TURN 分配。
解决办法 先试目录里 53 或 443 端口的 STUN 条目,这两个端口往往会被放行。如果仍然拿不到 srflx,说明这个网络根本没有 UDP 出口,只有走 443 的 turns: over TCP 还有机会——在多数中间设备眼里它与普通 TLS 没有区别。
一条 turn: 地址还没发出任何数据包就被判为不支持。
成因 它背后的主机其实是一个公共 STUN 服务,只是被填成了 turn: 协议。公共 STUN 服务器会回应绑定请求,但不做中继,用 relay-only 策略去探测它只会白白耗掉 4 秒预算。
解决办法 把这台主机改填为 stun:,另外单独配置真正的 TURN 服务——自建 coturn 或商业中继。本站不运行也不托管 TURN 中继。
一分钟前还通过的服务,配置没动却失败了。
成因 探测只有一次机会、限时 4 秒。丢一个 UDP 包、公共服务上的限流、或者任播路由把你切到了另一个节点,都会表现为没有任何错误信息的超时。
解决办法 下结论前先重跑一次;任何关键链路都应该使用自己可控的服务。一个会间歇性失败的公共 STUN 条目,无论原因是什么,都不适合放进生产环境。
适合用这个工具的场景
- 在业务团队开始怀疑自家信令之前,先证明新部署的 coturn 确实能发放 relay 候选。
- 把某个 STUN 地址写死进应用之前,先确认它在特定办公室、园区或国家/地区真的可达。
- 对比两端各自能采集到的候选类型,快速缩小「只有一边连不上」的故障范围。
- 确认受管控或被加固的浏览器是否根本就支持数据通道,包括安全上下文这一前置条件。
应该换用别的工具的场景
- 排查浏览器对所访问站点暴露了什么。Browser Leak Check 才是为此设计的,它同时覆盖 WebRTC 地址、IPv4 / IPv6 旁路与 DNS 解析器信号。
- 衡量通话质量、抖动或丢包。这里只是一次性的采集探测,实时质量请用专门的媒体质量工具,或在真实会话上读 getStats。
- 评估整体的 IPv4 与 IPv6 可达性,那件事由 IP Network Check 直接对两个地址族发起探测来回答。
隐私与数据处理
所有检测都在当前浏览器标签页内完成。STUN 绑定请求和 TURN 分配请求由你的浏览器直接发往你填写的主机,因此这些服务的运营方会看到你的公网 IP,TURN 运营方还会看到你提交的凭据;本站不在这条路径上,也从不接收任何候选。服务器列表、用户名和凭据保存在当前浏览器的本地存储中,键名为 devtoys:webrtc-ice,刷新后依然存在——在公用机器上请用「恢复默认」清除。候选行里含有你的公网 IP,在 mDNS 掩码未生效时还含有内网地址,把结果贴进工单前请先脱敏。
相关开发者工具
常见问题
我的候选和 TURN 凭据会发到你们服务器吗?
不会。能力检测、候选采集和每一次探测都在当前浏览器标签页里运行,请求由浏览器直接发往你填写的 STUN 或 TURN 主机。这些服务的运营方必然会看到你的公网 IP,TURN 运营方还会看到你提交的用户名和凭据。配置本身只保存在这个浏览器里。
你们提供 STUN 或 TURN 服务器吗?
不提供。工具内置了一份知名公共 STUN 地址目录,只是方便你找到一个在自己网络下能应答的服务,并且可以逐个复检。本站不运行也不托管 TURN 中继,因为中继意味着为每一个转发字节付费。需要 TURN 时请自建 coturn 或选择商业服务。
STUN 检测通过,是不是就说明我的应用能连上?
不是,它只说明这个浏览器在这个网络下能够获知自己的映射。真正建立连接还需要对端采集到相互兼容的候选,并且两侧 NAT 都放行连通性检查。检测通过能排除一整类故障,但不能证明某一对候选可用。
为什么 TURN 一定要用户名和凭据?
TURN 服务器会为你分配端口并转发会话的每一个字节,开放的中继被发现后几小时内就会被滥用。因此多数部署会基于共享密钥和过期时间戳签发短时效凭据。只有当服务器用你提供的凭据真的回发了 relay 候选时,检测器才判定这条 TURN 可达。
为什么本地 IP 变成了 .local 名称?
新版 Chrome 与 Firefox 会为每个 host 候选生成随机 mDNS 主机名,使页面无法枚举你的内网。同一子网内的对端可以通过多播 DNS 解析这个名称,所以局域网连接不受影响。工具会把这类候选标记为「已掩码」,而不是假装它们不存在。
「仅中继」模式会改变检测行为吗?
会。它把 ICE 传输策略设为 relay,浏览器只采集 relay 候选。这是单独验证 TURN 配置最诚实的方式,否则一条可用的直连路径会把坏掉的中继遮住。它同时也让 host 与服务器反射地址完全不出现在结果里。