Search code examples
c++cpcap

pcap_dispatch stuck with network filter set


When I run my program with the loopback device "lo" and some filter is applied, it hangs in a poll call (see gdb below). It doesn't happen if the pcap_compile() and pcap_setfilter() calls are skipped and this doesn't occur with other network devices either. pcap_dispatch is called in a loop. The program calls these libpcap functions in order:

1. pcap_create("lo", errbuf)
2. pcap_set_promisc(handle, 0)
3. pcap_set_snaplen(handle, 65000)
4. pcap_set_timeout(handle, 1000)
5. pcap_activate(handle)
6. pcap_lookupnet("lo", &localnet, &mask, errbuf)
7. pcap_compile(handle, &fp, "port 12345", 0, mask)
8. pcap_setfilter(handle &fp)
9. pcap_dump_open(handle, file)
10. pcap_dispatch(handle, 5, packet_handler, dumpObject)

It gets stuck at pcap_dispatch and does not return. I have tried to call pcap_breakloop() but that doesn't work. Calling pcap_inject() of a random packet only works if no filter is compiled and set (for the loopback device). Here is the backtrace (some details omitted/changed):

#0  __GI___poll (timeout=-1, nfds=1, fds=[some address]) at .xxxx/poll.c:29
#1  __GI___poll (fds=[some address], nfds=1, timeout=-1) at .xxxx/poll.c:26
#2  in pcap_wait_for_frames_mmap () from /libpcap.so.1
#3  in pcap_read_linux_mmap_v3 () from /libpcap.so.1
#4  in execute() ()

I'm guessing it's waiting for a packet that passes the filter to be available for the poll to end. But is there any way around this problem?


Solution

  • This seems to be an issue in versions before 1.10.0. As of 1.10.0, issuing pcap_breakloop() will force the poll() call to end and cause pcap_dispatch to return with PCAP_ERROR_BREAK.

    If using an older version, a quick solution is to call pcap_setnonblock() after pcap_activate() and then sleep between pcap_dispatch() calls for a set amount of milliseconds/seconds. This helps to not overload the looping of pcap_dispatch(). You can call pcap_dispatch() with "0" or however many packets desired in this case and they should be available the next time the dispatch is made. You can then either cancel the looping with pcap_breakloop() or your own mechanism.