Ethereal-dev: [Ethereal-dev] [Fwd: [Bug 54161] New - libpcap hangs if no filter set, pcap_nex
Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.
From: Alexander Dupuy <dupuy@xxxxxxxxxxxxxxx>
Date: Tue, 02 Oct 2001 16:29:48 -0400
I've run into a few pretty annoying bugs with the new Linux 7.1 (and 7.0) libpcap, mostly having to do with the implementation of the TURBO mode supported by the kernel PACKET_RX_RING or PACKET_TRECV socket options. While you can work around some things (always install a default filter), the pcap_next bug is serious and there is no workaround for that. I suspect there aren't many (any?) programs which use that interface, or it would have been reported already. For programs which want non-blocking behavior, the fact that libpcap never calls recvfrom (but rather blocks in calls to poll() with an infinite timeout) makes the trick of setting non-blocking mode on the file descriptor useless, and the fencepost error in packet_ring_recv means that even if, as Guy Harris suggests, you use select or poll before calling pcap_dispatch() and you only ask for one packet, you may end up blocking waiting for the second packet that you didn't ask for. With a narrow filter and/or low traffic, you may block quite a while. Because of the impossibility of working around this blocking glitch, and the desirability of avoiding excessive system calls (now that the captured packets are read directly into user memory), it seemed very worthwhile to make the read timeout parameter to pcap_open_live mean something, and the attached patch not only fixes the fencepost error, but modifies the libpcap source from the tcpdump-3.4-39.src.rpm (as patched by the dif.gz and patch files in the SRPM) so that the read timeout is honoured when TURBO mode is in effect. If TURBO mode doesn't work for any reason, you should get the old behavior (where read timeouts have no effect), but the traditional work arounds of non-blocking mode and/or calls to select/poll will work in the non-TURBO mode. Use of non-blocking mode is probably better, since it has no effect on TURBO mode performance, unlike the select() hack. @alex
--- Begin Message ---From: bugzilla@xxxxxxxxxxDate: Sat, 29 Sep 2001 02:45:32 -0400Please do not reply directly to this email. All additional comments should be made in the comments box of this bug report. https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=54161 --- shadow/54161 Sat Sep 29 02:45:32 2001 +++ shadow/54161.tmp.31534 Sat Sep 29 02:45:32 2001 @@ -0,0 +1,45 @@ +Bug#: 54161 +Product: Red Hat Linux +Version: 7.1 +Platform: All +OS/Version: Linux +Status: NEW +Resolution: +Severity: normal +Priority: normal +Component: tcpdump +AssignedTo: harald@xxxxxxxxxx +ReportedBy: dupuy@xxxxxxxxxxxxxxx +URL: +Summary: libpcap hangs if no filter set, pcap_next loses every other packet + +From Bugzilla Helper: +User-Agent: Mozilla/4.78 [en] (X11; U; Linux 2.4.9 i686) + +Description of problem: +When using the PACKET_RX_RING interface, poll() on the packet fd will never +succeed if there is no kernel BPF filter installed. +Due to a fencepost error in packet_ring_recv, the pcap_dispatch and +pcap_loop interfaces will actually receive one more packet than requested. +The pcap_next function, which only returns one packet, effectively loses +the first one. + +Version-Release number of selected component (if applicable): + + +How reproducible: +Always + +Steps to Reproduce: +1. write a program that uses libpcap but doesn't set a filter +2. write a program that loops calling pcap_next and prints destination +address of packet +3. run the programs and compare output to that of "tcpdump -nes 1" + + +Actual Results: the first program never prints anything +the second program only prints every other packet + +Expected Results: the programs should print lines for every packet + +Additional info:
--- End Message ---
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <pcap/pcap.h> int main() { char ebuf[PCAP_ERRBUF_SIZE]; char *dev; pcap_t *pcap; const int PROMISC = 1; /* put interface in promiscuous mode */ const u_char *packet; time_t stamp; struct pcap_pkthdr hdr; dev = pcap_lookupdev(ebuf); if (!(pcap = pcap_open_live(dev, 96, PROMISC, 0, ebuf))) return 1; /* need to be root */ #ifndef BUG_ONE /* * Linux 2.4 systems support TURBO mode, where the packets can be copied * directly into a receive ring in user memory. This is great for * performance, but typically has a bug that if you do not set a kernel * bpf filter program, select/poll will never succeed, and you will hang * forever trying to receive packets. So we always set a filter program * that just returns snaplen. */ { struct bpf_program prog; struct bpf_insn bpfret; prog.bf_len = 1; prog.bf_insns = &bpfret; bpfret.code = BPF_RET; bpfret.jt = 0; bpfret.jf = 0; bpfret.k = 96; pcap_setfilter(pcap, &prog); } #endif /* !BUG_ONE */ /* * RedHat 7.1 systems have a buggy implementation of packet_ring_recv that * causes every other packet to be lost when using pcap_next, as shown below. */ while ((packet = pcap_next(pcap, &hdr))) { stamp = hdr.ts.tv_sec; strftime(ebuf, PCAP_ERRBUF_SIZE, "%H:%M:%S", localtime(&stamp)); printf ("%s.%06d %s - %x:%x:%x:%x:%x:%x %x:%x:%x:%x:%x:%x\n", ebuf, hdr.ts.tv_usec, dev, packet[6], packet[7], packet[8], packet[9], packet[10], packet[11], packet[0], packet[1], packet[2], packet[3], packet[4], packet[5]); fflush(stdout); } return 0; } #ifdef PATCH_TO_LIBPCAP --- pcap-int.h.ORIG Fri Sep 28 13:53:14 2001 +++ pcap-int.h Fri Sep 28 20:34:58 2001 @@ -65,6 +65,7 @@ unsigned int ringbufsize; unsigned int iovmax; unsigned int iovhead; + int to_ms; char *device; int soft_bpf; unsigned short protocol; --- pcap-linux.c.ORIG Fri Sep 28 13:53:14 2001 +++ pcap-linux.c Sat Sep 29 02:30:33 2001 @@ -203,9 +203,12 @@ { struct iovec *ring = p->md.iovec; int n = 0; + int to_ms = p->md.to_ms; - if (cnt<=0) + if (cnt<=0) { cnt=0x7FFFFFFF; + to_ms = -1; + } for (;;) { while (*(unsigned long*)ring[p->md.iovhead].iov_base) { @@ -257,7 +260,7 @@ h->tp_status = 0; mb(); p->md.iovhead = (p->md.iovhead == p->md.iovmax) ? 0 : p->md.iovhead+1; - if (++n > cnt) + if (++n >= cnt) return n; } @@ -269,8 +272,10 @@ pfd.revents = 0; pfd.events = POLLIN|POLLRDNORM|POLLERR; do { - pres = poll(&pfd, 1, -1); + pres = poll(&pfd, 1, to_ms); } while (pres == -1 && errno == EINTR); + if (pres == 0) + return n; if (pres < 0) { sprintf(p->errbuf, "poll: %s", pcap_strerror(errno)); return n ? : -1; @@ -605,6 +610,7 @@ p->bufsize = ifr.ifr_mtu + 64; } + p->md.to_ms = to_ms > 0 ? to_ms : -1; p->md.protocol = proto; if (snaplen < 0 || snaplen >= 65535) snaplen = 1514; #endif
- Follow-Ups:
- Prev by Date: Re: [Ethereal-dev] ./configure on Windows 2000
- Next by Date: [Ethereal-dev] packet-x11-keysym.h cleanup
- Previous by thread: Re: [Ethereal-dev] ./configure on Windows 2000
- Next by thread: Re: [Ethereal-dev] [Fwd: [Bug 54161] New - libpcap hangs if no filter set, pcap_next loses every other packet]
- Index(es):