8

我有一个程序将一组 TCP SYN 数据包发送到主机(使用原始套接字)并使用libpcap(使用过滤器)来获取响应。我正在尝试在异步 I/O 框架中实现这一点,但似乎缺少一些响应(即当它在 TCP SYN 和响应之间libpcap花费的时间少于一系列的第一个数据包时)。100 microsecondspcap 句柄设置如下:

pcap_t* pcap = pcap_open_live(NULL, -1, false, -1, errorBuffer);
pcap_setnonblock(pcap, true, errorBuffer);

然后我添加一个过滤器(包含在 filterExpression 字符串中):

struct bpf_program filter;
pcap_compile(pcap, &filter, filterExpression.c_str(), false, 0);
pcap_setfilter(pcap, &filter);
pcap_freecode(&filter);

在一个循环中,在发送每个数据包后,我使用 select 来知道我是否可以从 libpcap 中读取:

int pcapFd = pcap_get_selectable_fd(pcap);
fd_set fdRead;
FD_ZERO(&fdRead);
FD_SET(pcapFd, &fdRead);
select(pcapFd + 1, &fdRead, NULL, NULL, &selectTimeout);

并阅读它:

if (FD_ISSET(pcapFd, &fdRead)) {
     struct pcap_pkthdr* pktHeader;
     const u_char* pktData;
     if (pcap_next_ex(pcap, &pktHeader, &pktData) > 0) {
         // Process received response.
     }
     else {
         // Nothing to receive (or error).
     }
}

正如我之前所说,一些数据包被遗漏(落入“没有收到”的其他情况)。我知道这些数据包在那里,因为我可以以同步方式(使用tcpdump或正在运行的线程pcap_loop)捕获它们。我在这里遗漏了一些细节吗?或者这是一个问题libpcap

4

2 回答 2

3

如果 FDpcap_tselect()(或poll()您正在使用的任何调用/机制)报告为可读,则不能保证这意味着只能读取一个数据包而不会阻塞。

如果使用pcap_next_ex(),则只会读取一个数据包;如果有多个数据包可供读取,那么,如果你执行另一个select(),它应该立即返回,报告 FD 再次可读,在这种情况下你可能会pcap_next_ex()再次调用,依此类推。这意味着每个数据包至少有一个系统调用(select()),可能还有更多调用,具体取决于您正在执行的操作系统版本以及您拥有的 libpcap 版本。

相反,如果您要pcap_dispatch()使用 -1 的数据包计数参数调用 ,则该调用将返回可以通过单个读取操作获得的所有数据包并处理所有这些数据包,因此,在大多数平台上,您可能会得到如果有多个数据包可用,则具有一个或两个系统调用的多个数据包(如果您正在使用 SYN 洪水测试您的程序,可能会遇到高网络流量,很可能就是这种情况)。

此外,在支持内存映射数据包捕获的 Linux 系统上(我认为所有 2.6 及更高版本的内核都支持,如果不是所有 2.4 内核也支持),并且使用较新版本的 libpcap,pcap_next_ex()必须复制数据包以避免让内核从处理数据包的代码下更改数据包,并避免无限期地“锁定”环形缓冲区中的插槽,因此涉及额外的副本。

于 2012-07-25T00:49:38.060 回答
2

这似乎是 libpcap 在 Linux 下使用内存映射的问题。有关详细信息,请参阅我的另一个问题

于 2012-07-30T23:20:57.520 回答