迷失在 libpcap 中 - 如何使用 setnonblock() / 我应该实时使用 pcap_dispatch() 还是 pcap_next_ex()?

Lost in libpcap - how to use setnonblock() / should I use pcap_dispatch() or pcap_next_ex() for realtime?

我正在构建一个网络嗅探器,它将 运行 在 PFSense 上监控 IPsec VPN。我在 FreeBSD 8.4 下编译。

我选择使用 C 中的 libpcap 作为数据包捕获引擎,使用 Redis 作为存储系统。 每秒将处理数百个数据包,系统将 运行 一整天。

目标是让网页显示有关网络的图表 activity,如果可能的话,每分钟或几秒更新一次。 当我的嗅探器捕获一个数据包时,它会确定它的大小、谁(在我们的 VPN 环境中是一个地理站点)将它发送给谁以及何时发送。然后这些信息需要存储在数据库中。

我做了很多研究,但我对 libpcap 有点迷茫,特别是我应该捕获数据包的方式。

1) 我应该使用什么函数来检索数据包? pcap_loop ? pcap_dispatch ?还是 pcap_next_ex ?根据我在网上看到的,loop 和 dispatch 是阻塞执行的,所以 pcap_next_ex 似乎是解决方案。

2) 我们应该什么时候使用 pcap_setnonblock ?我的意思是使用哪个捕获功能? pcap_loop ?所以如果我使用 pcap_loop 执行不会被阻止?

3) 多线程是实现这个的方法吗?一个线程 运行 一直捕获数据包,分析它们并将一些数据存储在一个数组中,第二个线程每分钟触发一次清空这个数组?

越想越迷茫,如有不明之处还请多多包涵,不吝赐教。

欢迎任何帮助。

编辑:

我目前正在尝试实现一个工作池,回调函数只将一个新作业放入作业队列。仍然欢迎任何帮助。稍后我会 post 更多详细信息。

1) What function should I use to retrieve packets ? pcap_loop ? pcap_dispatch ? Or pcap_next_ex ? According to what I read online, loop and dispatch are blocking execution, so pcap_next_ex seems to be the solution.

所有 如果没有准备好数据包并且您没有将 pcap_t 置于非阻塞模式,这些函数将阻塞等待数据包。

pcap_loop() 包含无限期运行的循环(或直到调用 pcap_breakloop() 并发生错误,或者,如果指定了计数,则计数用完)。因此,它可能会等待不止一次。

pcap_dispatch()块等待一批数据包到达,如果没有数据包可用,循环处理这批数据,然后returns,所以它最多只等待一次。

pcap_next()pcap_next_ex() 等待数据包可用,然后 return 发送它。

2) When are we supposed to use pcap_setnonblock ? I mean with which capture function ? pcap_loop ? So if I use pcap_loop the execution won't be blocked ?

不,不会,但这意味着调用 pcap_loop() 可能 return 不处理任何数据包;您将不得不再次调用它来处理稍后到达的任何数据包。非阻塞和 pcap_loop() 并不是很有用;你不妨使用 pcap_dispatch()pcap_next_ex().

3) Is multi-threading the way to achieve this ? One thread running all the time capturing packets, analyzing them and storing some data in an array, and a second thread firing every minutes emptying this array ?

(数组可能是一个队列,第一个线程将数据包数据附加到队列的末尾,第二个线程从队列的头部移除数据包数据并将其放入数据库。)

这是一种可能性,尽管我不确定它是否应该基于计时器。考虑到许多数据包捕获机制——包括 BPF,如 *BSD 和 OS X 使用的那样——分批传送数据包,也许你应该有一个循环来做类似

的事情
for (;;) {
    pcap_dispatch(p, -1, callback);
    wake up dumper thread;
}

(这很简单 - 您可能想检查 pcap_dispatch() 中的 return 值是否有错误)。

回调会将传递给它的数据包添加到队列的末尾。

dumper 线程将从队列的头部提取数据包并将它们添加到数据库中。

这不需要 pcap_t 是非阻塞的。在单 CPU 核机器上,它将依赖于调度程序对线程进行时间分割。

I'm currently trying to implement a worker pool, with the callback function only putting a new job in the job queue.

请注意,一旦回调函数returns,其第二个参数指向的const struct pcap_pkthdr结构和第三个参数指向的原始数据包数据都将无效,因此如果你想在工作中处理它们,你将不得不制作它们的副本 - 包括你将在该工作中处理的所有数据包数据的副本。您可能需要考虑在回调例程中进行一些处理,即使它只是找出需要保存的数据包数据(例如,IP 源和目标地址)并复制它,因为这可能比复制整个数据包更便宜。