Control: severity -1 grave

On 08/02/15 03:19, Tomasz Buchert wrote:
> [...]

Hi,
I've analyzed my problem and found what follows.

ANALYSIS
=========

First, only the QUERY packets are missing in dnstop, the RESPONSE
packets show (mostly) fine with dns -Q -R <interface>. I say "mostly"
because they can be still lost if there is too much traffic coming to
the card.

Second, the use of "pcap_fileno" is incorrect, it seems that
"pcap_get_selectable_fd" should be used instead. I'm not sure it
changes anything in practice, though.

Third, "pcap_select" in the code is called with 1s of timeout: for
reasons that are unclear to me, this makes the pcap library drop the
packets randomly (verified with "pcap_stats") and these drops are the
reason for this bug. Strangely, making the timeout smaller (say 50ms)
makes the problem go away. Removing the use of "pcap_select"
altogether works as well, however this causes dnstop to eat 100% of
ther CPU due to "pcap_setnonblock".

SOLUTIONS
===========

(1) Changing the "pcap_select" timeout to something like 50ms works
    for me, but this is hardly a real solution.

(2) Removing "pcap_setnonblock" and "pcap_select" from the code solves
    the problem as well. In this case we should probably also increase
    "to_ms" in "pcap_open_live" to something bigger than 1ms (I've set
    it to 50ms - a tolerable time for an interface to freeze).

(3) Increasing the buffer size for the capture could work as well, but
    I haven't tried it.

===========

My preferred solution is (2) and I attach a proof-of-concept
patch. The reason for having (1) in the upstream is a support for
MacOSX which we don't really care about in Debian. However, we have
non-Linux ports (FreeBSD officialy and hurd) and I have no idea
whether (2) will work for them.  For example, while researching this,
I found that there is no promise that "pcap_dispatch" will respect the
timeout given in "pcap_open_live" (it may actually block).

Personally I think this bug is RC (the package does not work
out of the box) and I'm bumping the severity.

Cheers,
Tomasz
From: Tomasz Buchert <[email protected]>
Date: Sun, 15 Feb 2015 20:20:54 +0100
Subject: proof-of-concept patch

---
 dnstop.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/dnstop.c b/dnstop.c
index 57e12cc..e4b8f6d 100644
--- a/dnstop.c
+++ b/dnstop.c
@@ -1901,7 +1901,7 @@ main(int argc, char *argv[])
     if (readfile_state) {
 	pcap = pcap_open_offline(device, errbuf);
     } else {
-	pcap = pcap_open_live(device, PCAP_SNAPLEN, promisc_flag, 1, errbuf);
+	pcap = pcap_open_live(device, PCAP_SNAPLEN, promisc_flag, 50, errbuf);
     }
     if (NULL == pcap) {
 	fprintf(stderr, "pcap_open_*: %s\n", errbuf);
@@ -1934,7 +1934,7 @@ main(int argc, char *argv[])
      * workaround and dnstop does not require non-blocking, we'll won't
      * check the return status.
      */
-    pcap_setnonblock(pcap, 1, errbuf);
+    /* pcap_setnonblock(pcap, 1, errbuf); */
     switch (pcap_datalink(pcap)) {
     case DLT_EN10MB:
 	handle_datalink = handle_ether;
@@ -1993,8 +1993,8 @@ main(int argc, char *argv[])
 		 * packets to process.  Thus, we always ignore its return value
 		 * and just call pcap_dispatch() anyway.
 		 */
-		if (0 == readfile_state)	/* interactive */
-		    pcap_select(pcap, 1, 0);
+		/* if (0 == readfile_state)
+                   pcap_select(pcap, 1, 0); */
 		x = pcap_dispatch(pcap, 50, handle_pcap, NULL);
 	    }
 	    if (0 == x && 1 == readfile_state) {

Reply via email to