我想在Linux上使用C语言编写一个使用Libpcap的小应用程序。
目前,它开始嗅探并等待数据包。 但这不是我实际需要的。 我想要等待N秒钟,然后停止收听。
我怎样才能做到这一点?
这是我的代码:
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { printf("got packet\n); } int main() { int ret = 0; char *dev = NULL; /* capture device name */ char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */ pcap_t *handle; /* packet capture handle */ char filter_exp[] = "udp dst port 1500"; /* filter expression */ struct bpf_program fp; /* compiled filter program (expression) */ bpf_u_int32 mask; /* subnet mask */ bpf_u_int32 net; /* ip */ int num_packets = 10; /* number of packets to capture */ /* get network number and mask associated with capture device */ if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) { fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf); net = 0; mask = 0; } /* print capture info */ printf("Device: %s\n", dev); printf("Number of packets: %d\n", num_packets); printf("Filter expression: %s\n", filter_exp); /* open capture device */ handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf); if (handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf); exit(EXIT_FAILURE); } /* compile the filter expression */ if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) { fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle)); exit(EXIT_FAILURE); } /* apply the compiled filter */ if (pcap_setfilter(handle, &fp) == -1) { fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle)); exit(EXIT_FAILURE); } /* now we can set our callback function */ pcap_loop(handle, num_packets, got_packet, NULL); /* cleanup */ pcap_freecode(&fp); pcap_close(handle); }
当你想停止监听时,你应该调用pcap_breakloop()
。 所以一种方法是:
SIGALRM
信号安装信号处理程序, pcap_breakloop()
来返回pcap_loop()
。 码:
void alarm_handler(int sig) { pcap_breakloop(handle); } int main() { ... alarm(N); signal(SIGALRM, alarm_handler); /* now we can set our callback function */ pcap_loop(handle, num_packets, got_packet, NULL); /* cleanup */ pcap_freecode(&fp); pcap_close(handle); }
注:至于使用libpcap的读取超时来做到这一点,它不会也不会工作,man pcap明确警告:
读取超时不能用于导致读取数据包的调用在有限的时间内返回[…]这意味着读取超时不应该使用,例如,在交互式应用程序中允许数据包捕获循环定期轮询用户输入,因为即使没有数据包到达,也不能保证读取数据包的呼叫将在超时过期后返回。
如果你从tcpdump网站上看到这个页面,你可以看到如下的信息:
打开嗅探设备
创建嗅探会话的任务非常简单。 为此,我们使用pcap_open_live()。 这个函数的原型(来自pcap手册页)如下:
pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
第一个参数是我们在前一节中指定的设备。 snaplen是一个整数,它定义了pcap要捕获的最大字节数。 promisc设置为true时,将界面变为混杂模式(但是,即使设置为false,也可能在特定情况下使界面处于混杂模式)。 to_ms是以毫秒为单位的读取超时(值为0意味着没有超时;至少在某些平台上,这意味着您可能要等到足够数量的数据包到达才会看到数据包,因此您应该使用非零超时) 。 最后,ebuf是一个字符串,我们可以在其中存储任何错误信息(就像我们上面用errbuf所做的那样)。 该函数返回我们的会话处理器。
如果这不起作用,请告诉我们。
我一直在研究和测试这些代码片段。 在某处,我注意到了一个观察,即当你退出pcap_loop时,虽然你可能看过数据包,但退出条件表明你没有看到数据包。 我从这里假设,所有的数据包处理必须发生在回调函数的范围内。 所以如果我想快速重置并为其他数据包做好准备,我将需要产生另一个进程来处理每个数据包。
旧帖子,但我正在研究,并遇到这一点。
在pcap_loop()的手册页中特别指出:“在发生实时读取超时时不会返回,而是尝试读取更多的数据包。
但是pcap_dispatch()和pcap_next()的手册页都表明它们超时。