【问题标题】:pcap packet length values seem incorrectpcap 数据包长度值似乎不正确
【发布时间】:2012-02-27 06:10:28
【问题描述】:

我正在编写一个 C 应用程序,它使用 pcap 库来记录通过网卡的数据量(匹配各种数据包过滤器)。我得到的值似乎太低而无法正确,但我不确定我做错了什么。

下面的测试代码表现出相同的行为(为清楚起见省略了错误检查):

#include <stdio.h>
#include <pcap.h>

static int total=0;
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data){
    total += header->len;
    printf("%d\n", total);
}

int main(){
    char errbuf[1024];

    pcap_t *adhandle = pcap_open_live("en1", 65535, 0, 0, errbuf);
    pcap_setnonblock(adhandle, 1, errbuf);
    struct bpf_program fcode;
    pcap_compile(adhandle, &fcode, "port 80", 1, 0);
    pcap_setfilter(adhandle, &fcode);

    while(1){
        pcap_dispatch(adhandle, -1, packet_handler, NULL);
        sleep(1);
    }
    return 0;
}

我正在使用 OSX,使用 gcc 进行编译,并且尝试通过 wi-fi 和有线以太网下载。我希望上面的代码打印出与过滤器匹配的字节数(在这种情况下是所有 HTTP 流量),但是当我下载一个大小为 4,357,017 字节的测试文件时,我得到的值只有 95,133。我的测试文件是一个 zip 存档,所以我认为 HTTP 压缩不能解释差异。

更新:我已经修改了代码以打印出每个数据包的大小,以及运行总数,并且只报告传入的数据包(将过滤器更改为“src端口80 英寸)。这给出了很多“1514”的数据包长度,我认为这与 1500 的 MTU 值有关,但是总数仍然太低。

【问题讨论】:

  • 如果您通过 HTTP 下载内容,请确保 HTTP 客户端不使用压缩。
  • int main(char** arcv, int argc){休斯顿,我们遇到了问题!
  • 我看到了两个常规选项。要么你得到错误的数据包,要么错误的大小。要检查数据包,您可以打印源/目标端口 - 您是否将 80 作为 bot 源和目标端口?要检查大小,请更改程序以打印每个大小 - 您应该会看到大量返回的数据包(源端口 80),大小约为 1500。
  • @ugoren 谢谢,我很确定我得到了正确的数据包——当我发送请求时有很多输出,而之前或之后什么都没有。为什么你期望大小在 1500 左右?我的数据包大小大多要小得多(例如,大约 50-60 字节)
  • 也许您只是从客户端获取数据包到服务器?这些主要是 ACK,因此它们的大小为 50-60。来自服务器的数据包尽可能大,这通常意味着 1500 字节(以太网接口的 MTU),有时或多或少(但不少于数百字节)。

标签: c network-programming pcap libpcap


【解决方案1】:

这里不能保证你的程序能看到所有的数据包;如果它没有看到它们,它就无法计算它们,在这种情况下,捕获的数据包长度的总和小于传输的数据量也就不足为奇了。

首先,您不应该使用非阻塞模式,除非您的程序所做的不仅仅是捕获数据包——轮询在这里并不能更好地工作,它可能会更糟糕。使用您的代码,如果一秒钟内到达的数据包超过缓冲区的容量,系统将耗尽 BPF 缓冲区空间,这意味着数据包将被丢弃,您的程序将永远看不到它们,因此不会计算它们。在 Lion 之前,默认缓冲区大小约为 32K 左右,这意味着系统很有可能会耗尽 BPF 缓冲区空间; Lion 采用了 libpcap 1.1 的更改,使 BPF 系统的默认缓冲区大小为 512K,因此这种情况不太可能发生,但您仍然不应该使用非阻塞模式,除非您真的需要它。

此外,您不应该在 Snow Leopard 上使用非阻塞模式根本,因为 Snow Leopard 的 BPF 内核代码中存在一个错误(该错误的 FreeBSD 版本是 @987654321 @);它在 Leopard 或更早版本中不存在(它是在对 Snow Leopard 中修复的错误的修复中引入的),并且在 Lion 中已修复。

所以我要做的第一件事就是去掉pcap_setnonblock(adhandle, 1, errbuf); 调用和sleep(1); 调用,以便您的程序尽可能快地处理数据包。

此外,如果它不必在 Leopard 上运行(它具有不支持 pcap_create()pcap_activate() 的旧版 libpcap),我会通过执行 (为了清楚起见,删除了错误检查):

adhandle = pcap_create("en1", errbuf);
pcap_set_buffer_size(adhandle, 524288);
pcap_activate(adhandle);

最后,我会让你的程序以某种方式提供一种方法来告诉你何时停止捕获,当它停止时,让它调用pcap_stats() 并报告丢弃的数据包数量,以便你可以确定它是否丢弃任何数据包。

【讨论】:

  • 感谢您的出色回答,正如您所说 - 当我删除对 pcap_setnonblock 的调用时,我得到了我预期的总数,非常感谢。不幸的是,我的应用设置了多个过滤器,并且必须定期将每个总数写入数据库,所以如果我需要使用阻塞调用,那么我怀疑我将不得不在单独的线程中启动每个过滤器,这会增加一些复杂性。跨度>
  • 如果您不必必须在 Snow Leopard 上运行,您可以在 pcap_get_selectable_fd() 上的 pcap_ts 上使用 select()重新使用(我假设您正在使用多个pcap_ts)。但是,如果您的机器有多个处理器内核,使用线程会更好,因为程序可以使用多个内核。
猜你喜欢
  • 2012-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-11
  • 2021-02-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多