8、DTLS 握手调试:使用 Wireshark 抓包分析 DTLS 握手过程,排查加密协商失败问题。
DTLS 握手,说白了就是给 UDP 通信加了一把锁。WebRTC 里所有音视频数据要加密传输,都得先过这一关。我见过不少开发者,明明信令通了,ICE 也连上了,但媒体就是出不来——最后发现是 DTLS 握手卡住了。
嗯,今天我们就来聊聊怎么用 Wireshark 抓包,一步步拆解这个握手过程。
DTLS 握手到底在做什么?
先简单回顾一下。DTLS 是基于 TLS 改造的,专门给 UDP 这种不可靠传输用的。它俩的核心目标一样:协商加密算法、交换密钥、验证证书。
但 DTLS 多了一个麻烦——UDP 会丢包。所以它加了个简单的重传机制。你想想看,如果握手过程中丢了一个包,整个协商就卡死了。
我在项目中遇到过最典型的情况:客户端发了 ClientHello,服务器没收到,客户端傻等,服务器也傻等,最后超时断开。这种问题,不抓包根本看不出来。
DTLS 握手的核心流程
一个完整的 DTLS 1.2 握手,通常包含以下几步:
- ClientHello:客户端发起握手,告诉服务器自己支持的加密套件、DTLS 版本、随机数等。
- ServerHello:服务器选好加密套件和版本,发回自己的随机数。
- Certificate:服务器把自己的证书发给客户端(可选,但 WebRTC 里通常需要)。
- ServerKeyExchange:服务器发送密钥交换参数(比如 ECDHE 的公钥)。
- CertificateRequest:服务器要求客户端也发证书(可选)。
- ServerHelloDone:服务器说“我发完了”。
- Certificate:客户端发自己的证书(如果被要求)。
- ClientKeyExchange:客户端发送密钥交换参数。
- CertificateVerify:客户端用私钥签名,证明自己持有证书对应的私钥。
- ChangeCipherSpec:双方通知对方“接下来要加密通信了”。
- Finished:双方发送握手消息的校验值,确认握手成功。
你看,步骤不少。但 Wireshark 里看,其实就几个关键帧。
关键点:WebRTC 中 DTLS 握手通常使用 ECDSA 证书(自签名),加密套件一般是 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256。如果你看到协商成了别的套件,要小心了。
用 Wireshark 抓包分析
好,理论说完了,咱们动手。假设你已经有了 WebRTC 通信的 pcap 文件,或者正在实时抓包。
第一步,设置过滤条件。DTLS 握手包通常走 UDP,端口取决于你的应用。但更简单的方法是直接用协议过滤:
dtls
或者更精确一点,只看握手消息:
dtls.record.content_type == 22
22 是 Handshake 类型的编号。这样过滤后,你看到的全是握手相关的包。
我个人习惯再叠加一个 IP 过滤,只看两个对等端之间的流量:
ip.addr == 192.168.1.100 && ip.addr == 192.168.1.200 && dtls
如何判断握手是否成功?
最简单的办法:看有没有 Finished 消息。如果两端都发出了 Finished,并且收到了对方的 Finished,握手就成功了。
在 Wireshark 里,你可以这样找:
- 找到 Client Finished 和 Server Finished 两个包。
- 检查它们之间有没有重传。如果有大量重传,说明网络不稳定,或者 MTU 有问题。
我遇到过一种情况:握手包都发出去了,但 Finished 消息一直没收到。后来发现是服务器端的防火墙把 UDP 大包给丢了。DTLS 握手包如果超过 MTU,会被分片,有些防火墙会直接丢弃分片包。
注意:DTLS 握手包可能被分片。Wireshark 里如果看到 "DTLSv1.2 Record Layer: Handshake: Fragment" 这样的描述,说明发生了分片。你需要检查分片是否完整到达。
常见握手失败原因排查
我整理了一个表格,方便你对照排查:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 只有 ClientHello,没有 ServerHello | 服务器没收到 ClientHello,或者服务器不支持 DTLS | 检查 UDP 端口是否通;检查服务器 DTLS 配置 |
| ServerHello 发出后,客户端没反应 | 客户端不认可服务器选的加密套件或版本 | 对比双方支持的加密套件列表 |
| Certificate 消息后握手中断 | 证书验证失败(过期、不信任、域名不匹配) | 检查证书链和有效期 |
| 大量重传,最终超时 | UDP 丢包严重,或者 MTU 问题导致分片丢失 | 检查网络质量,调整 MTU |
| Finished 消息校验失败 | 握手过程中数据被篡改,或者密钥计算不一致 | 检查随机数、密钥交换参数是否一致 |
实战:抓一个失败的握手
我曾经帮一个团队排查问题。他们的 WebRTC 应用在部分用户手机上无法建立通话。抓包后发现,DTLS 握手卡在了 Certificate 阶段。
具体是这样的:
- 客户端发了 ClientHello。
- 服务器回了 ServerHello、Certificate、ServerHelloDone。
- 客户端收到后,发了一个 Alert 消息,内容是 "Bad Certificate"。
嗯,问题很明显了。客户端不认服务器的证书。进一步检查发现,服务器用的是自签名证书,但客户端没有把这个证书加到信任列表里。
解决方案很简单:要么客户端信任这个证书,要么服务器换用已知 CA 签发的证书。WebRTC 里通常用自签名证书,所以客户端需要提前配置好指纹(fingerprint)来验证。
小技巧:在 Wireshark 里,你可以右键点击 DTLS 包,选择 "Follow" -> "UDP Stream",这样能看到同一个 UDP 流里的所有包,方便你按顺序分析握手过程。
DTLS 握手状态机
为了让你更直观地理解握手过程,我画了一张状态机图。它展示了客户端和服务器在握手过程中的状态转换。
这张图里,左边是客户端的状态,右边是服务器。箭头表示消息的流向。你注意看,如果某个箭头断了,或者消息没到,握手就会卡在对应的状态。
排查步骤总结
最后,我总结一下排查 DTLS 握手问题的步骤:
- 抓包:用 Wireshark 抓取 UDP 包,过滤 dtls 协议。
- 看握手是否完整:检查是否有 ClientHello、ServerHello、Certificate、Finished 等关键消息。
- 检查重传:如果看到大量重传,说明网络有问题。
- 检查 Alert 消息:如果握手中断,看有没有 Alert 包,里面会说明原因。
- 验证证书:如果是证书问题,检查指纹是否匹配,证书是否过期。
- 检查加密套件:确保双方支持的加密套件有交集。
个人经验:我习惯在抓包时同时开启 Wireshark 的 "Statistics" -> "Flow Graph" 功能,它能以图形化的方式展示握手过程,比看原始包列表直观得多。
好了,DTLS 握手调试就聊到这里。记住,大部分问题都出在证书和网络丢包上。下次遇到媒体出不来,先抓个包看看 DTLS 握手是不是卡住了。