我正在使用select(2)
函数来监视pcap_get_selectable_fd
获取的文件描述符的更改。当select(2)
在看起来是指定为超时的时间量之后返回时,返回等于fdset中文件描述符数量的值。对pcap_next_ex
的后续调用返回0(表示没有可用的数据包)。我检查了是否使用pcap_stats
丢弃了一些数据包,但'drop'和'ifdrop'计数器都是空的。
我还在pcap资源句柄上应用Berkeley Packet Filter,根据pcap_get_selectable_fd
的文档在BSD和Mac OS X上引起了一些问题。即使我正在运行Linux,它是否会以某种方式相关?
我的测试机运行Linux内核3.13.3-1-ARCH并使用libpcap-1.6.2。在我的开发机器上,一切都按照我的预期运行(内核3.17.7-200.fc20.x86_64,libpcap-1.5.3)。
for ( i = 0; i < etherpoke_conf->filter_cnt; i++ ){
struct bpf_program bpf_prog;
session_data_init (&(pcap_session[i]));
pcap_session[i].handle = pcap_create (etherpoke_conf->filter[i].interface, pcap_errbuff);
rval = pcap_set_promisc (pcap_session[i].handle, !etherpoke_conf->filter[i].rfmon);
if ( etherpoke_conf->filter[i].rfmon ){
rval = pcap_can_set_rfmon (pcap_session[i].handle);
if ( rval == 1 ){
rval = pcap_set_rfmon (pcap_session[i].handle, 1);
} else {
fprintf (stderr, "%s: cannot enable monitor mode on interface '%s': %s\n", argv[0], etherpoke_conf->filter[i].interface, pcap_geterr (pcap_session[i].handle));
exitno = EXIT_FAILURE;
goto cleanup;
}
}
rval = pcap_set_timeout (pcap_session[i].handle, SELECT_TIMEOUT_MS);
rval = pcap_setnonblock (pcap_session[i].handle, 1, pcap_errbuff);
rval = pcap_activate (pcap_session[i].handle);
rval = pcap_compile (pcap_session[i].handle, &bpf_prog, etherpoke_conf->filter[i].match, 0, PCAP_NETMASK_UNKNOWN);
rval = pcap_setfilter (pcap_session[i].handle, &bpf_prog);
pcap_freecode (&bpf_prog);
pcap_session[i].fd = pcap_get_selectable_fd (pcap_session[i].handle);
}
while ( main_loop ){
time_t current_time;
struct pcap_pkthdr *pkt_header;
const u_char *pkt_data;
struct timeval timeout;
fd_set fdset_read;
int last_fd;
FD_ZERO (&fdset_read);
last_fd = 0;
timeout.tv_sec = 0;
timeout.tv_usec = SELECT_TIMEOUT_MS * 1000;
for ( i = 0; i < etherpoke_conf->filter_cnt; i++ ){
if ( pcap_session[i].fd == -1 )
continue;
FD_SET (pcap_session[i].fd, &fdset_read);
last_fd = pcap_session[i].fd;
}
if ( last_fd == 0 ){
syslog (LOG_ERR, "no more applicable filters left to use. Dying!");
break;
}
rval = select (last_fd + 1, &fdset_read, NULL, NULL, &timeout);
if ( rval == -1 ){
if ( errno != EINTR )
syslog (LOG_ERR, "select system call failed: %s", strerror (errno));
break;
}
time (¤t_time);
for ( i = 0; i < etherpoke_conf->filter_cnt; i++ ){
if ( FD_ISSET (pcap_session[i].fd, &fdset_read) ){
rval = pcap_next_ex (pcap_session[i].handle, &pkt_header, &pkt_data);
if ( rval < 0 ){
syslog (LOG_ERR, "could not obtain packet from the queue: %s", pcap_geterr (pcap_session[i].handle));
main_loop = 0;
break;
} else if ( rval == 0 ){
continue;
}
}
if ( (pcap_session[i].ts > 0)
&& (difftime (current_time, pcap_session[i].ts) >= etherpoke_conf->filter[i].session_timeout) ){
pcap_session[i].evt_flag = FILTER_EVENT_END;
}
}
}