我正在构建一个网络嗅探器,它将在PFSense上运行以监控IPsec VPN。我正在FreeBSD 8.4下编译。
我选择在C中使用libpcap作为数据包捕获引擎,使用Redis作为存储系统。 每秒将有数百个数据包来处理,系统将全天运行。
目标是让网页显示有关网络活动的图表,如果可能的话,每隔几分钟或几秒钟更新一次。 当我的嗅探器捕获一个数据包时,它将确定它的大小,谁(一个地理站点,在我们的VPN上下文中)发送它,谁和何时。然后,这些信息需要存储在数据库中。
我已经做了很多研究,但是我对libpcap有点失落,特别是我应该捕获数据包的方式。
1)我应该使用什么功能来检索数据包? pcap_loop? pcap_dispatch?还是pcap_next_ex?根据我在网上看到的,循环和调度是阻塞执行,所以pcap_next_ex似乎是解决方案。
2)我们什么时候应该使用pcap_setnonblock?我的意思是哪个捕捉功能? pcap_loop?那么如果我使用pcap_loop,执行将不会被阻止?
3)多线程是实现这一目标的吗?一个线程一直在运行捕获数据包,分析它们并将一些数据存储在一个数组中,另一个线程每隔几分钟就会清空这个数组?
我想的越多,我就越迷茫,所以如果我不清楚请不要犹豫,请原谅我。
欢迎任何帮助。
编辑:
我目前正在尝试实现一个工作池,回调函数只在作业队列中放置一个新作业。任何帮助仍然欢迎。我稍后会发布更多细节。
答案 0 :(得分:1)
1)我应该使用什么功能来检索数据包? pcap_loop? pcap_dispatch?还是pcap_next_ex?根据我在网上看到的,循环和调度是阻塞执行,所以pcap_next_ex似乎是解决方案。
如果没有准备好数据包,那么这些功能的所有都会阻止等待数据包,并且您无法将pcap_t
置于非阻塞模式。
pcap_loop()
包含一个无限运行的循环(或直到pcap_breakloop()
被调用,并且发生错误,或者,如果指定了计数,则计数用完)。因此,它可能会等待不止一次。
pcap_dispatch()
阻止等待一批数据包到达,如果没有可用的数据包,则循环处理批处理,然后返回,因此它最多只等待一次。
pcap_next()
和pcap_next_ex()
等待数据包可用,然后返回。
2)我们什么时候应该使用pcap_setnonblock?我的意思是哪个捕捉功能? pcap_loop?所以,如果我使用pcap_loop,执行不会被阻止?
不,它不会,但这意味着对pcap_loop()
的调用可能会在不处理任何数据包的情况下返回;您必须再次调用它来处理稍后到达的任何数据包。非阻塞和pcap_loop()
并非真正有用;您也可以使用pcap_dispatch()
或pcap_next_ex()
。
3)多线程是实现这一目标的吗?一个线程一直运行捕获数据包,分析它们并将一些数据存储在一个数组中,第二个线程每隔几分钟就会清空这个数组?
(该数组可能是一个队列,第一个线程将数据包附加到队列的末尾,第二个线程从队列的头部删除数据包并将其放入数据库。)
这是一种可能性,虽然我不确定它是否应该基于计时器。鉴于许多数据包捕获机制 - 包括* BSD和OS X使用的BPF - 分批传送数据包,也许你应该有一个类似
的循环for (;;) {
pcap_dispatch(p, -1, callback);
wake up dumper thread;
}
(简化了 - 你可能想要检查来自pcap_dispatch()
的返回值中的错误。)
回调会将传递给它的数据包添加到队列的末尾。
转储程序线程将从队列头部提取数据包并将其添加到数据库中。
这不需要pcap_t
无阻塞。在单CPU核心机器上,它将依赖于调度程序对时间进行切片的线程。
我目前正在尝试实现一个工作池,回调函数只在作业队列中放置一个新作业。
请注意,一旦回调函数返回,第二个参数指向的const struct pcap_pkthdr
结构和第三个参数指向的原始数据包数据都不会有效,所以如果要处理它们在这项工作中,您必须复制它们 - 包括您将在该工作中处理的所有数据包数据的副本。您可能想要考虑在回调例程中进行一些处理,即使它只计算需要保存的数据包数据(例如,IP源和目标地址)并复制它,因为这可能比复制更便宜整个数据包。