Asynchronous libpcap: packet loss?

I have a program that sends a set of TCP SYN packets to a host (using the source sockets) and uses libpcap (with a filter) to receive responses. I am trying to implement this in an asynchronous I / O structure, but it seems that some answers are missing in libpcap (namely, the first series packets when less than 100 microseconds between TCP SYN and response are required). The pcap knob is configured as follows:

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

Then I add a filter (contained in the expressionExpression line):

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

And in the loop after sending each package, I use select to find out if I can read from 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); 

And read it:

 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). } } 

As I said, some of the packages are skipped (getting into the "receive nothing"). I know that these packages exist because I can synchronize them synchronously (using tcpdump or the pcap_loop stream). Did I miss some details here? Or is this a problem with libpcap ?

+6
source share
2 answers

This seems like a problem with libpcap using memory mapping on Linux. See my other question for more details.

+1
source

If the FD for pcap_t reported as read by select() (or poll() or any call / mechanism you use), there is no guarantee that this means that only one packet can be read without blocking.

If you use pcap_next_ex() , you will only read one package; if more than one readable package is available, then if you run another select() , it should return immediately, telling FD to be readable again, in which case you will probably call pcap_next_ex() again and so on. This means at least one system call per package ( select() ) and possibly more calls, depending on which version of the operating system you are using and which version of libpcap you have.

If instead you would have to call pcap_dispatch() with a count-count argument of -1, this call will return all the packets that can be received with a single read operation and process them all, so on most platforms you can get multiple packages with one or two system calls, if several packages are available (which with high network traffic, how could you get if you are testing your program with a SYN stream, it will probably take place).

In addition, on Linux systems that support packet capture with memory (I think that all kernels with 2.6 and later, and most, if not all 2.4 kernels), as well as with newer versions of libpcap, pcap_next_ex() should make a copy package, in order to avoid changing the package kernel from under the package processing code and to avoid "blocking" the slot in the ring buffer for an indefinite period of time, therefore an additional copy is involved.

+1
source

Source: https://habr.com/ru/post/921233/


All Articles