8、DTLS 握手调试:使用 Wireshark 抓包分析 DTLS 握手过程,排查加密协商失败问题。

DTLS 握手,说白了就是给 UDP 通信加了一把锁。WebRTC 里所有音视频数据要加密传输,都得先过这一关。我见过不少开发者,明明信令通了,ICE 也连上了,但媒体就是出不来——最后发现是 DTLS 握手卡住了。

嗯,今天我们就来聊聊怎么用 Wireshark 抓包,一步步拆解这个握手过程。

DTLS 握手到底在做什么?

先简单回顾一下。DTLS 是基于 TLS 改造的,专门给 UDP 这种不可靠传输用的。它俩的核心目标一样:协商加密算法、交换密钥、验证证书。

但 DTLS 多了一个麻烦——UDP 会丢包。所以它加了个简单的重传机制。你想想看,如果握手过程中丢了一个包,整个协商就卡死了。

我在项目中遇到过最典型的情况:客户端发了 ClientHello,服务器没收到,客户端傻等,服务器也傻等,最后超时断开。这种问题,不抓包根本看不出来。

DTLS 握手的核心流程

一个完整的 DTLS 1.2 握手,通常包含以下几步:

  1. ClientHello:客户端发起握手,告诉服务器自己支持的加密套件、DTLS 版本、随机数等。
  2. ServerHello:服务器选好加密套件和版本,发回自己的随机数。
  3. Certificate:服务器把自己的证书发给客户端(可选,但 WebRTC 里通常需要)。
  4. ServerKeyExchange:服务器发送密钥交换参数(比如 ECDHE 的公钥)。
  5. CertificateRequest:服务器要求客户端也发证书(可选)。
  6. ServerHelloDone:服务器说“我发完了”。
  7. Certificate:客户端发自己的证书(如果被要求)。
  8. ClientKeyExchange:客户端发送密钥交换参数。
  9. CertificateVerify:客户端用私钥签名,证明自己持有证书对应的私钥。
  10. ChangeCipherSpec:双方通知对方“接下来要加密通信了”。
  11. 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 FinishedServer 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 握手状态机 客户端 等待 ServerHello 等待 Certificate 等待 ServerHelloDone 发送 ClientKeyExchange 连接已建立 服务器 等待 ClientHello 发送 ServerHello 发送 Certificate 等待 ClientKeyExchange 连接已建立 ClientHello ServerHello Certificate ServerHelloDone ClientKeyExchange Finished / 加密通信

这张图里,左边是客户端的状态,右边是服务器。箭头表示消息的流向。你注意看,如果某个箭头断了,或者消息没到,握手就会卡在对应的状态。

排查步骤总结

最后,我总结一下排查 DTLS 握手问题的步骤:

  1. 抓包:用 Wireshark 抓取 UDP 包,过滤 dtls 协议。
  2. 看握手是否完整:检查是否有 ClientHello、ServerHello、Certificate、Finished 等关键消息。
  3. 检查重传:如果看到大量重传,说明网络有问题。
  4. 检查 Alert 消息:如果握手中断,看有没有 Alert 包,里面会说明原因。
  5. 验证证书:如果是证书问题,检查指纹是否匹配,证书是否过期。
  6. 检查加密套件:确保双方支持的加密套件有交集。

个人经验:我习惯在抓包时同时开启 Wireshark 的 "Statistics" -> "Flow Graph" 功能,它能以图形化的方式展示握手过程,比看原始包列表直观得多。

好了,DTLS 握手调试就聊到这里。记住,大部分问题都出在证书和网络丢包上。下次遇到媒体出不来,先抓个包看看 DTLS 握手是不是卡住了。

公众号:蓝海资料掘金营,微信deep3321