我有一个程序将一组TCP SYN数据包发送到主机(使用原始套接字)并使用libpcap
(带过滤器)来获取响应。我试图在异步I / O框架中实现这一点,但似乎libpcap
缺少一些响应(即系列中的第一个数据包,它们之间的时间少于100 microseconds
TCP SYN和响应)。 pcap句柄设置如下:
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
的问题吗?
答案 0 :(得分:1)
如果pcap_t
的FD被select()
(或poll()
或您正在使用的任何呼叫/机制)报告为可读,则无法保证这仅表示可以不受阻塞地读取一个数据包。
如果您使用pcap_next_ex()
,您将只读取一个数据包;如果有多个数据包可供读取,那么,如果你再做一个select()
,它应该立即返回,报告FD再次可读,在这种情况下你可能会再次调用pcap_next_ex()
, 等等。这意味着每个数据包至少有一个系统调用(select()
),可能还有更多调用,具体取决于您正在执行的操作系统版本以及您拥有的libpcap版本。
相反,如果您使用-1的packet-count参数调用pcap_dispatch()
,则该调用将返回所有可通过单个读取操作获取的数据包并处理所有这些数据包,因此在大多数平台上,如果有多个可用数据包(如果你使用SYN泛洪测试你的程案件)。
此外,在支持内存映射数据包捕获的Linux系统上(我认为所有2.6及更高版本的内核都可以,而且大多数情况下都是2.4内核),并且对于更新版本的libpcap,pcap_next_ex()
必须制作数据包的副本,以避免内核在处理数据包的代码下更改数据包,并避免无限期地“锁定”环形缓冲区中的一个插槽,因此需要额外的副本。 / p>
答案 1 :(得分:1)
这似乎是libpcap在Linux下使用内存映射的问题。有关详细信息,请参阅my other question。