libpcap setfilter()函数和丢包

时间:2010-12-02 13:58:55

标签: linux sip rtp pcap libpcap

这是我在这里的第一个问题@stackoverflow。

我正在为一些VoIP生产服务器编写一个监控工具,特别是一个允许使用Perl中的pcap库捕获与给定模式匹配的所有流量(VoIP调用)的嗅探工具。

我不能使用差的选择性过滤器,例如“udp”,然后在我的应用程序代码中进行所有过滤,因为这会涉及太多流量,内核无法应对报告数据包丢失。

然后我要做的是在捕获过程中迭代地构建更具选择性的滤波器。在开始时我只捕获(所有)SIP信令流量和IP片段(模式匹配必须在应用程序级别完成)然后当我发现有关RTP的一些信息到SIP数据包时,我添加'或'子句到具有特定IP和PORT的实际filter-string,并使用setfilter()重新设置过滤器。

所以基本上是这样的:

  1. 初始过滤器:“(udp和端口5060)或(udp和ip [6:2]& 0x1fff!= 0)” - >捕获所有SIP流量和IP片段

  2. 更新过滤器:“(udp和端口5060)或(udp和ip [6:2]& 0x1fff!= 0)或(主机IP和端口PORT)” - >捕获特定IP上的RTP,PORT

  3. 更新过滤器:“(udp和端口5060)或(udp和ip [6:2]& 0x1fff!= 0)或(主机IP和端口PORT)或(主机IP2和端口PORT2)” - >同时捕获第二个RTP流

  4. 等等。

    这非常有效,因为我能够为监控目的获得RTP流的“真正”数据包丢失,而对于我的工具的选择性过滤器版本,RTP数据包丢失百分比不可靠,因为那里由于内核丢包导致一些数据包丢失。

    但是让我们来看看这种方法的缺点。

    在捕获时调用setfilter()涉及这样一个事实:libpcap将“在更改过滤器时”收到的数据包丢弃,如函数set_kernel_filter()的代码注释中所述,进入pcap-linux.c(检查了libpcap版本0.9和1.1)。

    所以当我调用setfilter()并且一些数据包到达IP片段时,我确实丢失了一些片段,最后libpcap统计数据没有报告:我发现它正在挖掘痕迹。

    现在,我理解为什么这个动作是由libpcap完成的,但在我的情况下,我绝对不需要丢包(我不关心获得一些不相关的流量)。

    您是否知道如何解决不修改libpcap代码的问题?

3 个答案:

答案 0 :(得分:1)

如何使用更具体的过滤器启动新流程。你可以同时进行两次并行的pcap捕获。一段时间后(或检查两者都收到相同的数据包)你可以停止原来的。

答案 1 :(得分:1)

您能捕获所有RTP流量吗?

capture filters开始,有关RTP流量的建议是:

udp[1] & 1 != 1 && udp[3] & 1 != 1 && udp[8] & 0x80 == 0x80 && length < 250

正如链接指出的那样,你会得到一些误报,其中DNS和可能的其他UDP数据包偶尔包含RTP数据包使用的头字节0x80,但数量应该可以忽略不计并且不足以导致内核丢弃。 / p>

答案 2 :(得分:1)

圆孔,方形钉。

你有一个不太适合你需要的工具。

另一个选择是执行第一级过滤器(如上所述,捕获比想要的更多)并将其传输到另一个实现所需更精细过滤器的工具(直到每次调用的情况)。如果由于RTP流量过大而导致内核的第一级过滤器过多,那么您可能需要执行其他操作,例如保持稳定的进程以捕获单个调用(因此您不需要更改“主”上的过滤器过程;它只是指示其他人如何设置他们的过滤器。)

是的,这可能意味着合并捕获,无论是动态捕获(将它们全部传递给“保存捕获”过程)还是事后。

如果您没有安装过滤器 fast ,您确实意识到您可能会错过RTP数据包。不要忘记RTP数据包可以在200 OK进入(或一起)之前进入发起者,并且它们可以在ACK之前(或在它之上)返回应答者。另外不要忘记没有SDP的INVITE(在200 OK中提供,在ACK中回答)。等等: - )