NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

bin/46729: tcpdump does not read all buffered packets on Ctrl-C



>Number:         46729
>Category:       bin
>Synopsis:       tcpdump does not read all buffered packets on Ctrl-C
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jul 20 17:55:00 +0000 2012
>Originator:     Darren Reed
>Release:        NetBSD 5.99.59
>Organization:
NetBSD
>Environment:
>Description:
When tcpdump is termined with SIGINT(^C), it is possible for packets
that have been buffered between the last call to read() and the 1 second
timeout expiring to be left in the buffer unread. In testing, this leads
to unpredictable behaviour by tcpdump as it is hard to know when the SIGINT
arrives relative to the packets that have been buffered but not yet read.
For example, "tcpdump -lo0 icmp & sleep 1; ping localhost; kill -SIGINT %1"
should result in tcpdump always seeing all packets from the ping command
because the signal is delivered after the ping command has completed and
thus all packets sent and buffered. This patch endevours to ensure that
behaviour by effectively doing one more loop iteration.

This patch has been submitted via slashdot to the tcpdump project.
>How-To-Repeat:
        
>Fix:
https://sourceforge.net/tracker/?func=detail&aid=3546396&group_id=53067&atid=469579

*** src/external/bsd/libpcap/dist/pcap.c.orig Fri Jul 20 18:24:07 2012
--- src/external/bsd/libpcap/dist/pcap.c      Fri Jul 20 18:31:16 2012
***************
*** 429,434 ****
--- 429,456 ----
                        do {
                                n = p->read_op(p, cnt, callback, user);
                        } while (n == 0);
+ 
+                       /*
+                        * If we received EINTR, try once more to read
+                        * packet data from the kernel in non-blocking
+                        * mode. The goal here is to try and pull out
+                        * any remaining data that would otherwise have
+                        * been discarded when, for example, the user
+                        * pressed ^C whilst running tcpdump, packets
+                        * have accumulated in the buffer but the read
+                        * timeout has not expired. After doing all of
+                        * that, it is necessary to restore errno to
+                        * enable the pcap_loop() caller to correctly
+                        * diagnose what happened.
+                        */
+                       if (n == PCAP_ERROR_BREAK && errno == EINTR) {
+                               if ((pcap_getnonblock(p, NULL) >= 0) &&
+                                   (pcap_setnonblock(p, 1, NULL) == 0)) {
+                                       (void) p->read_op(p, cnt, callback,
+                                                         user);
+                               }
+                               errno = EINTR;
+                       }
                }
                if (n <= 0)
                        return (n);



Home | Main Index | Thread Index | Old Index