WebRTC DTLS | 使用自定义扩展传递信息

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
日志服务 SLS,月写入数据量 50GB 1个月
简介: 协议离不开扩展,很多时候我们都忽视了扩展的价值。比如通过 DTLS 自定义扩展传递客户端 ID 信息,解决了日志系统展示日志的问题。扩展能够扩展我们的思路,能够带来创新,比如 AliRTC 的 GRTN 协议(链接),就是对 RTCP APP 的扩展。希望大家以后在学习协议时,在工程实战时能够重视协议的扩展,让它发挥出该有的光和热。

要解决的问题

假设存在这样一种 RTC 建连场景:客户端和服务器在 DTLS 握手完成之后才开始信令交互和媒体数据传输。这种建连场景使得客户端的信息(比如各种 ID 和 SDP)要等到 DTLS 握手成功之后才能被服务器知晓。

某次建连失败(DTLS 握手失败,但是你不知道是这个原因)。你很自然的使用日志系统去排查问题,但是却尴尬的发现日志系统没有展示任何日志(DTLS 握手失败导致客户端的 ID 体系没有在服务器建立,而日志系统需要依赖这些 ID 才能展示服务器日志)。

也就是说:

  1. 如果建连的第一步 DTLS 握手失败了,那么日志系不会展示任何服务器日志。
  2. 无论 DTLS 握手成功还是失败,日志系统都不会展示任何 DTLS 握手这个阶段的日志。

因此只好:

  1. 去日志存储数据库查询这次建连的日志。
  2. 手动登服务器查询这次建连的日志。

这两种查询方式很麻烦,而且如果是服务集群挂载在 SLB 后面,难不成要挨个登录服务器去查询日志在哪台机器上?

最后你使出九牛二虎之力,终于定位到建连失败的原因是 DTLS 握手失败。你开始思考,如果日志系统能展示 DTLS 握手阶段的日志,那不就一眼定位到 DTLS 失败的问题了吗?

是的,只要能在 DTLS 握手阶段知道客户端的 ID,那么 DTLS 相关的埋点就能在日志系统展示!

那么,如何才能做到这一点呢?解铃还需系铃人,DTLS 的问题 DTLS 来解。我们通过使用 DTLS 扩展来传递客户端 ID 信息,就能轻松搞定这个问题。

DTLS 扩展

DTLS 的扩展在 Hello 消息(Client Hello 或者 Server Hello)中携带,也叫做 Hello Extensions。扩展的格式为 TLV 格式,即 Type、Length、Value。Type 取值范围是 0 ~ 65535,0 ~ 59 是已定义的扩展类型,其余基本为保留和未分配。

如果我们要自定义扩展类型,则可以从未分配的扩展类型(比如 60 ~ 2569)中选取。

下图展示了 ClientHello 中的各个扩展。

下面展示了 ServerHello 中的各个扩展。

关于这些 Extensions,有以下几点规则:

  1. ServerHello 中不能出现 ClientHello 中没有携带的扩展,否则握手必须被取消。
  2. 当 Hello 消息中有多个不同类型的扩展时,这些扩展的顺序可能是任意的。
  3. 同一类型的扩展只能有一个。

增加自定义扩展

下面,我们看下如何在客户端增加自定义扩展类型,来传递客户端 ID。

其实很简单,只需要在 ssl context 创建好之后调用这个 API 即可。

int SSL_CTX_add_client_custom_ext(
  SSL_CTX *ctx, unsigned int ext_type,
  custom_ext_add_cb add_cb,
  custom_ext_free_cb free_cb, void *add_arg,
  custom_ext_parse_cb parse_cb,
  void *parse_arg);

客户端要增加自定义扩展,因此只要传入 ctx,ext_type,add_arg,实现 add_cb 和 free_cb 即可。

unsigned int ext_type = 323;
char* add_arg = "taiyi0323";
SSL_CTX_add_client_custom_ext(
  ctx,
  ext_type,
  ext_add_cb,
  ext_free_cb, 
  add_arg,
  NULL,
  NULL);

可以按照上述方式调用,返回 1 代表成功,0 代表失败。

下图展示了我们自己增加的自定义扩展。

解析自定义扩展

使用 API 解析

服务器收到 Client Hello 后,就需要解析自定义扩展,拿到客户端的 ID,服务器需要调用下面的 API。

int SSL_CTX_add_server_custom_ext(
  SSL_CTX *ctx, unsigned int ext_type,
  custom_ext_add_cb add_cb,
  custom_ext_free_cb free_cb, void *add_arg,
  custom_ext_parse_cb parse_cb,
  void *parse_arg);

服务端只需要解析自定义扩展,因此只要传入 ctx,ext_type,parse_arg,实现 parse_cb 即可。

char* parse_arg = NULL;
SSL_CTX_add_server_custom_ext(
  ctx,
  823,
  NULL,
  NULL, 
  NULL, 
  parse_cb,
  parse_arg);

可以按照上述方式调用,返回 1 代表成功,0 代表失败。

自己实现解析

也可以自己实现自定义扩展的解析函数,注意以下几点:

  1. random 字段及之前的 49 字节固定,可以直接跳过,不做解析
  2. 由于多个扩展的顺序是任意的,所以不能按照顺序来解析扩展,而是在循环中解析
  3. 在解析多字节字段的时候注意网络字节序问题,高位字节要放到低地址处
  4. 注意异常判断,比如 buffer 剩下的数据长度不满足待解析的数据长度

总结

协议离不开扩展,很多时候我们都忽视了扩展的价值。比如通过 DTLS 自定义扩展传递客户端 ID 信息,解决了日志系统展示日志的问题。扩展能够扩展我们的思路,能够带来创新,比如 AliRTC 的 GRTN 协议(链接),就是对 RTCP APP 的扩展。希望大家以后在学习协议时,在工程实战时能够重视协议的扩展,让它发挥出该有的光和热。

本文没有展示 DTLS 自定义扩展的代码实现细节,完整的实现细节可以参考我写的 一个简单的 DTLS 握手 demo

谢谢阅读。

参考

  1. https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.1.4
  2. https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_add_client_custom_ext.html
  3. TLS Extensions
  4. https://mp.weixin.qq.com/s/tHW6sWRZUzkOtl2BsRbV1w
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
2月前
|
编解码 Android开发 开发者
如何在轻量级RTSP服务中玩转H.264扩展SEI,实现自定义数据的发送与接收?
【9月更文挑战第4天】本文详细介绍了如何在轻量级RTSP服务中实现H.264标准的扩展SEI功能,包括环境准备、依赖引入、RTSP服务创建、自定义SEI数据发送与接收等步骤,并提供了具体代码示例,帮助开发者更好地利用SEI在视频流中嵌入元数据。
55 2
|
3月前
|
编解码 Android开发
### 揭秘!如何在轻量级RTSP服务中玩转H.264扩展SEI,实现自定义数据的发送与接收?
【8月更文挑战第14天】本文介绍如何在轻量级RTSP服务中实现H.264的SEI功能,允许在视频流中嵌入自定义数据。首先确保环境已安装Android Studio并具备基础开发技能。接着,通过Gradle添加必要依赖如`jrtsp`。创建RTSP服务并配置H.264编码器支持SEI。编码过程中可添加自定义SEI数据,并在客户端解析这些数据。此方案适用于需在视频流中传递元数据的应用场景。
42 0
|
3月前
|
编解码 API 开发工具
Android平台轻量级RTSP服务模块二次封装版调用说明
本文介绍了Android平台上轻量级RTSP服务模块的二次封装实践,旨在简化开发流程,让开发者能更专注于业务逻辑。通过`LibPublisherWrapper`类提供的API,可在应用中轻松初始化RTSP服务、配置视频参数(如分辨率、编码类型)、启动与停止RTSP服务及流发布,并获取RTSP会话数量。此外,还展示了如何处理音频和视频数据的采集与推送。最后,文章提供了从启动服务到销毁资源的完整示例,帮助开发者快速集成实时流媒体功能。
|
5月前
|
Web App开发 JSON JavaScript
Chrome 插件各模块之间的消息传递
Chrome 插件各模块之间的消息传递 一、消息传递 1. 消息传递分类 Chrome 插件的 Action、Background 和 content_script 三个模块之间的信息传输 插件和插件之间的信息传输 网页向插件进行信息传输 与原生应用进行消息传递
193 0
嵌入式开发中自定义协议的解析与组包
嵌入式开发中自定义协议的解析与组包
|
物联网 Android开发
NFC技术的定义通信方式
NFC技术的定义通信方式
|
编解码 Linux 定位技术
如何在轻量级RTSP服务支持H.264扩展SEI发送接收自定义数据?
如何在轻量级RTSP服务支持H.264扩展SEI发送接收自定义数据?
159 0
|
存储 机器学习/深度学习 缓存
二十七、网络层概述和数据交换方式
二十七、网络层概述和数据交换方式
二十七、网络层概述和数据交换方式
|
Web App开发 存储 移动开发
跨浏览器窗口通讯 ,7种方式,你还知道几种呢?
为什么会扯到这个话题,最初是源于听 y.qq.com/ QQ音乐, 播放器处于单独的一个页面 当你在另外的一个页面搜索到你满意的歌曲的时候,点击播放或添加到播放队列 你会发现,播放器页面做出了响应的响应 这里我又联想到了商城的购物车的场景,体验确实有提升。 刚开始,我怀疑的是Web Socket作妖,结果通过分析网络请求和看源码,并没有。 最后发现是localStore的storage事件作妖,哈哈。 回归正题,其实在一般正常的知识储备的情况下,我们会想到哪些方案呢?
1142 0
跨浏览器窗口通讯 ,7种方式,你还知道几种呢?
|
Go 流计算
gRPC双向数据流的交互控制(go语言实现)
gRPC (https://grpc.io) 是一个由Google开发的高性能、开源、跨多种编程语言和通用的远程过程调用协议(RPC) 框架,用于客户端和服务器端之间的通信,使用HTTP/2协议并将 ProtoBuf (https://developers.google.com/protocol-buffers)作为序列化工具。
3776 0
下一篇
无影云桌面