pcap 数据包长度值似乎不正确
我正在编写一个 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 port 80”) 。这给出了很多数据包长度“1514”,我认为这与 MTU 值 1500 有关,但总数仍然太低。
I'm writing a C application which uses the pcap library to log how much data (matching various packet filters) has passed through a network card. The values that I'm getting seem much too low to be correct, but I'm not sure what I'm doing wrong.
The test code below exhibits the same behavior (error checking omitted for clarity):
#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;
}
I'm working on OSX, compiling with gcc, and I've tried downloading over wi-fi and wired ethernet. I expect the code above to print out the number of bytes that have matched the filter (in this case all HTTP traffic) but when I download a test file 4,357,017 bytes in size I get a value of only 95,133. My test file was a zip archive so I don't think HTTP compression can account for the difference.
Update: I've modified the code to print out the size of each packet, as well as the running total, and also to report only the incoming packets (changed the filter to "src port 80"). This gives lots of packet lengths of '1514' which I think is related to the MTU value of 1500, however the total remains far too low.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这里不能保证您的程序能够看到所有数据包;如果它没有看到它们,则无法对它们进行计数,在这种情况下,捕获的数据包长度之和小于传输的数据量也就不足为奇了。
首先,你不应该使用非阻塞模式,除非你的程序正在做的不仅仅是捕获数据包 - 轮询在这里并不能更好地工作,它可能会工作得更糟。使用您的代码,如果一秒钟内到达的数据包数量超出了缓冲区的容量,系统将耗尽 BPF 缓冲区空间,这意味着数据包将被丢弃,您的程序将永远不会看到它们,因此不会对它们进行计数。在 Lion 之前,默认缓冲区大小约为 32K 左右,这意味着系统很有可能会耗尽 BPF 缓冲区空间; Lion 采用了 libpcap 1.1 更改,使 BPF 系统的默认缓冲区大小为 512K,因此这种情况发生的可能性较小,但您仍然不应该使用非阻塞模式,除非您确实需要它。
此外,您根本不应该在 Snow Leopard 上使用非阻塞模式,因为 Snow Leopard 中的 BPF 内核代码中存在一个错误(该错误的 FreeBSD 版本为 PR 143855);它在 Leopard 或之前版本中不存在(它是在 Snow Leopard 中修复的错误的修复中引入的),并且在 Lion 中已修复。
因此,我要做的第一件事就是摆脱
pcap_setnonblock(adhandle, 1, errbuf);
调用和sleep(1);
调用,以便您的程序会尽快处理数据包。此外,如果它不必在 Leopard 上运行(Leopard 具有旧版本的 libpcap,不支持
pcap_create()
或pcap_activate()
),我可以通过以下操作将缓冲区大小提高到 512K(为了清楚起见,删除了错误检查):最后,我会让您的程序以某种方式提供一种方式来告知何时停止捕获,并在停止时调用它
pcap_stats()
并报告丢弃的数据包数量,以便您可以确定是否丢弃了任何数据包。There is no guarantee here that your program is seeing all the packets; if it doesn't see them, it can't count them, in which case it wouldn't be surprising that the sum of the captured packet lengths was less than the amount of data transferred.
First of all, you shouldn't use non-blocking mode unless your program is doing something more than just capturing packets - polling doesn't work better here, it can work worse. With your code, the system would run out of the BPF buffer space if more packets than fit in the buffer arrive in a second, meaning packets would be dropped and your program would never see them and would thus not count them. Prior to Lion, the default buffer size is about 32K or so, meaning there's a very good chance that the system can run out of the BPF buffer space; Lion picks up the libpcap 1.1 change to make the default buffer size for BPF systems 512K, so that's less likely to happen, but you still shouldn't use non-blocking mode unless you really need it.
In addition, you shouldn't use non-blocking mode at all on Snow Leopard, as there's a bug in the BPF kernel code in Snow Leopard (the FreeBSD version of the bug is PR 143855); it's not present in Leopard or before (it was introduced in a fix to a bug fixed in Snow Leopard), and it's fixed in Lion.
So the first thing I'd do would be to get rid of the
pcap_setnonblock(adhandle, 1, errbuf);
call and thesleep(1);
call, so that your program processes packets as fast as it can.In addition, if it doesn't have to run on Leopard (which had an older version of libpcap that didn't support
pcap_create()
orpcap_activate()
), I'd raise the buffer size to 512K by doing (error checking removed for clarity):Finally, I'd have your program somehow provide a way to be told when to stop capturing and, when it stops, have it call
pcap_stats()
and report the number of dropped packets, so that you can determine whether it dropped any packets.