tcpdump mailing list archives
libpcap BPF implementation issue
From: Aaron Lehmann <aaronl () vitelus com>
Date: Tue, 2 Sep 2014 13:39:12 -0700
Hello, A few weeks ago, I reported a problem with TPACKET v3 missing packets when using libpcap in nonblocking mode. I managed to work around this reliably, but I continued seeing missed packets on platforms which don't support TPACKET v3. The problem seems to be due to the way libpcap sometimes filters the first few packets in the ring: /* run filter on received packet * If the kernel filtering is enabled we need to run the * filter until all the frames present into the ring * at filter creation time are processed. * In this case, blocks_to_filter_in_userland is used * as a counter for the packet we need to filter. * Note: alternatively it could be possible to stop applying * the filter when the ring became empty, but it can possibly * happen a lot later... */ bp = frame + tp_mac; if (handlep->filter_in_userland && handle->fcode.bf_insns && (bpf_filter(handle->fcode.bf_insns, bp, tp_len, tp_snaplen) == 0)) return 0; I found that the packets being missed were passing the kernel filter, but bpf_filter() was returning 0 on these packets. My filter string is generated as follows: /* We have a somewhat complicated filter string to handle fragmented packets. Handle the following cases: * port %d: Unfragmented packet with the port number of interest (IPv4 or IPv6, TCP or UDP). * ip[6:2] & 0x3fff != 0: Fragmented IPv4 packet * Fragmented IPv6 packet: no direct check because the kernel BPF implementation can't iterate over the optional headers. Check for the following "next header" values in the fixed header: - 0: Hop-by hop options (may precede fragment header) - 60: Destination options (may precede fragment header) - 43: Routing (may precede fragment header) - 44: Fragment */ snprintf(filter_str, sizeof(filter_str), "port %d or ip[6:2] & 0x3fff != 0 or ip6 proto 0 or ip6 proto 60 or ip6 proto 43 or ip6 proto 44", port); Patching libpcap to always set blocks_to_filter_in_userland and filter_in_userland to 0 successfully works around the problem. It seems that libpcap's BPF implementation mishandles this filter string somehow. I haven't been able to figure out what exactly goes wrong, but I'd happy to do more debugging or provide packet captures if that would be helpful. The packets involved are completely normal IPv4 UDP packets with the destination port set to the port specified at the beginning of the filter string. Aaron _______________________________________________ tcpdump-workers mailing list tcpdump-workers () lists tcpdump org https://lists.sandelman.ca/mailman/listinfo/tcpdump-workers
Current thread:
- libpcap BPF implementation issue Aaron Lehmann (Sep 02)