在Janus中抓取WebRTC流量

抓取WebRTC流量看起来相对简单,大多数情况下确实是这样:你只需要在其中一人的机器上安装类似tcpdumpwireshark的抓包工具,然后查看产生的文件,大多数情况会是.pcap或.pcapng文件。这些活动对于诊断连接问题或其它与WebRTC相关的问题很有用:实际上,wireshark可以自动检测出STUN,DTLS之类的标准协议,这些是WebRTC PeerConnections所关注的。

本文关键是什么?

抓取WebRTC流量的唯一问题就是,媒体内容会被加密。当检查了STUN连接或DTLS握手之后,这不是一个问题,但是当你想要查看RTP或RTCP包的时候,这将会成为一个问题,它将会被加密成SRTP和SRTCP。实际上,尽管SRTP标题没有被加密,你可以任何形式抓取流量,但是SRTP负载不是,意味着你不能查看它的内容。

大多数情况下你不需要查看内容。正如期待的那样,你依然可以查看加密RTP包的标题,也就是最常被用到的信息。不管怎样,对于RTCP并不能这样说:实际上,一条RTCP信息可能实际上包含不止一个包,并且不存在一个共享的标题。除此之外,查看RTP负载可能会有效。

这意味着抓取加密流量是可行的,但是为了诊断目的抓取无加密数据效果可能更好。不幸的是,无其它帮助下这是不可能的:实际上,WebRTC情况下浏览器经常发送加密数据,即使有一些允许你抓取无加密数据进行测试,但是你还是需要依靠其它工具来获取媒体流,才能进行这项工作。

进入Janus!

作为一个WebRTC媒体服务器,Janus确实发挥了它的效果:实际上,它存在于PeerConnection的每一条媒体路径上。除此之外,由于它为每个PeerConnections分别建立了安全环境,它可以获得输入和输出的未加密的RTP和RTCP包。

我们一年前就是这样想的,被Firefox所激励,我们首先添加了text2pcap dump的支持,采取的方法很直接:

1.使用Admin API,开始抓取Janus处理文件的信息。
2.所有输入输出的RTP/RTCP包都被转化为文本格式,保存到相关文件中。
3.抓取结束后,使用text2pcap App 将抓取文件转化为与Wiresharak或其它工具兼容的格式。

请求的语法很简单:

POST /admin/sessionId/handleId
{
        "janus" : "start_text2pcap",
        "folder" : "<folder to save the dump to; optional, current folder if missing>",
        "filename" : "<filename of the dump; optional, random filename if missing>",
        "truncate" : "<number of bytes to truncate at; optional, won't truncate if 0 or missing>",
        "transaction" : "<random alphanumeric string>",
        "admin_secret" : "<password specified in janus.cfg, if any>"
}


如果已知了相关session和handle Id,可以轻易生成一句代码来对handle开始抓取:

curl -X POST -H "Content-Type: application/json" -d '{"janus": "start_text2pcap", "folder": "/tmp", "filename": "my-test2pcap-dump.txt", "transaction": "123", "admin_secret": "janusoverlord"}' http://localhost:7088/admin/8412133783240844/2377476017639045

 

最终,你将会以类似的文本文件结束:

I 18:47:14.126004 000000  80 e0 6c 5d [..] JANUS_TEXT2PCAP_RTP [session=3740061776621518][handle=3149681776118503]
O 18:47:14.128251 000000  80 e0 04 83 [..] JANUS_TEXT2PCAP_RTP [session=3740061776621518][handle=3149681776118503]
I 18:47:14.136577 000000  80 6f 54 8d [..] JANUS_TEXT2PCAP_RTP [session=3740061776621518][handle=3149681776118503]
O 18:47:14.136659 000000  80 6f 03 9f [..] JANUS_TEXT2PCAP_RTP [session=3740061776621518][handle=3149681776118503]


你对此文件不能做太多:我们看到一些输入输出包,在某个时间被保存,还可以看到16进制的负载值,每一行结尾有一些环境信息。你需要把它传给其它工具,例如text2pcap,将它转化为你可以读懂的文件:

text2pcap -D -n -l 1 -i 17 -u 1000,2000 -t '%H:%M:%S.' /tmp/my-test2pcap-dump.txt /tmp/my-test2pcap-dump.pcapng

 

你可以参考说明书详细学习应该怎样做和工具提供的功能,上面的一行基本可以遍历文本文件,将每个包转化为pcapng格式,使用不同IP和端口供两方交流,更容易区分彼此。

但是文本序列化不是应该效率低下么?

我很高兴你问了这个问题!

那是对的:尽管上述方法简单易行,并且出色的完成了它的工作,但是耗费了大量的CPU。这意味着,尽管看起来不错,你不能将此方法应用于产品环境中,因为这样做会影响你机器的性能。

我们需要另外一种方法,在Janus中直接保存到原始pcap文件中,而不是将其转化为文本文件,之后进行处理。这个方法模拟了文本抓取,但是有轻微的不同之处:
1.就像之前,你使用Admin API开始对Janus中的一个文件进行抓取,但是使用不同的请求
2.Pcap全局标题在抓取之前就被保存。
3.所有的输入输出RTP/RTCP包都被保存为文件,但是首先要建立一些假的以太网/IP/UDP标题,并且都移pcap包标题为前缀。

你可能注意到了这里不包括写入处理:由于我们直接保存到pcap文件中,这意味着,我们一停止抓取,文件就马上被生成,利用,使用适当的工具。除此之外,由于不需要文本序列化,而是直接写入文件,这个过程变得轻量化,影响基本可忽略,并且与Janus中的媒体记录特性很好的契合。

尽管你使用了不同的方法保存为.pcap文件,而且命名为start_pcap,而不是start_text2pcap,它的语法与另一个完全一样:这意味着你可以提供与之前一样的信息,并保存它,无论是否缩短。观察前面的例子,接着,下面是请求的格式:

curl -X POST -H "Content-Type: application/json" -d '{"janus": "start_pcap", "folder": "/tmp", "filename": "my-pcap-dump.pcap", "transaction": "123", "admin_secret": "janusoverlord"}' http://localhost:7088/admin/8412133783240844/2377476017639045


注意,我们只改变了请求名称和目标文件的扩展名。其它完全一样。

所有这些都使人害怕(我太懒了,不想使用curl)

目前为止,我们解释了Jauns对于抓取未加密数据所提供的功能,如何使用Admin API请求利用这个特性。不管怎样,你可能不想手动做这些事,或通过命令行。幸运的是,我准备了一个虚拟接口来做这些事!

Janus报告带来一些可供使用的网络演示,包括了Admin API接口。这个接口在之前的文章中已经详细介绍过,特别是使用它提供的信息达到诊断问题的目的。我们不会重复这些细节,但是我们会关注一点,你应该如何在Janus中开始或停止抓取一个特定文件。当然了,我们假定了你之前在HTTP插件配置中开启了Admin API后端。

如果你有Janus演示的最近的版本,打开Admin API,尝试导航现有session,选择一个特定的handle。你应该在实际处理信息前看到一个叫做开启抓取的勾选框。

1001

点击它,如下:

1002

大多数设置应该清晰易懂,因为当介绍Admin API请求语法时,我们介绍了它们。第一个允许你选择抓取类型,之前讲到过,或者是直接保存到pcap,或者是转化为文本文件之后处理。

1003

接着你被要求设置保存文件的路径:

1004

你应该只关心包的第一个byte,而不是全部,这将会使在保存之前缩短包变得有效。你可以使用缩短选择:

1005

当抓取开始时,网页将会改变相关的勾选框,将其转化为控制信息,让你随时可以暂停正在进行的抓取。

1006

当前的抓取状态也会显示在handle信息中:

1007

一旦抓取完成,不管是否需要text2pcap,使用wireshark,最终你会得到你可以使用的文件。假设使用了Wireshark,抓取界面如下所示:

1008

正如期待,我们可以看到两个不同的IP(10.1.1.1和10.2.2.2)在不同端口相互交流。当Janus抓取流量时,10.1.1.1:1000总是peer的地址,10.2.2.2:2000总是Janus自己的地址。

当然,Wireshark自己并不能分辨这些UDP包的内容是RTP和RTCP信息。这是我们需要告诉它的,将流量信息解码为RTP。

1009

之后,Wireshark显示的信息会变化:

1010

如你所见,Wireshark负责解释RTP标题,使我们可以观察和分析它。对于负载也可以这样说,它将会被解密,并且被我们看到。

Wireshark一个很少被人知道的特性,是它也支持对某些媒体编解码器的解封装。这意味着,如果你告诉Wireshark一个包内含有特定编解码器编码的媒体信息,它将会给你一个具体的编解码信息。VP8和H.264编解码器处于其中,因此,如果在设置中将负载类型96和VP8稳定关联起来,显示的信息将会再一次改变:

1011

尽管这张截图与之前的相似,还是存在一些关键区别:例如, 注意对于敷在类型96的所有包,协议一列如何从RTP转化为VP8。这意味着Wireshark正在使用更高级的解码,也可以观察负载:在VP8情况下,这意味着获取以VP8负载描述为前缀的实际媒体流内容。当然,这些超出了本文的范围,唯一的作用是展示你应该如何获取这些信息:如果你想要学习诊断此类内容的更多细节,你可以参考一篇很棒的文章,它是由Philipp Hancke写的。

原文标题:Capturing WebRTC traffic in Janus
作者:‘Lorenzo Miniero’

填写常用邮箱,接收社区更新

WebRTC 中文社区由

运营