Ethereal-dev: [Ethereal-dev] Patches for capture.c and tethereal.c (0.9.0)

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Graeme Hewson <ghewson@xxxxxxxxxxxxxxxxxxx>
Date: Sun, 30 Dec 2001 19:11:19 +0000
Ethereal and tethereal ignore errors from pcap_dispatch.  This means
they can look as if they're capturing packets even if the interface
(such as a dial-up PPP link) is down.  Someone might think he could
start capturing with the interface down, bring up the interface, and
ethereal/tethereal would then start recording data.  That won't work,
though.

The attached patches add checks for pcap_dispatch, and stop capturing if
the call fails.  The patch for tethereal also fixes a couple of other
problems:

1. A misplaced period in a message.

2. SIGTERM and SIGINT are ignored until pcap_dispatch next returns. 
This could be a problem if a capture filter is defined, for instance. 
My patch uses setjmp and longjmp, so I hope there are no portability
issues.


Graeme Hewson
--- capture.c.orig	Sun Dec  9 15:16:38 2001
+++ capture.c	Sat Dec 29 18:51:52 2001
@@ -209,6 +209,7 @@
   int            err;          /* if non-zero, error seen while capturing */
   gint           linktype;
   gint           sync_packets;
+  gboolean       pcap_err;     /* TRUE if error from pcap */
   gboolean       from_pipe;    /* TRUE if we are capturing data from a pipe */
   gboolean       modified;     /* TRUE if data in the pipe uses modified pcap headers */
   gboolean       byte_swapped; /* TRUE if data in the pipe is byte swapped */
@@ -1303,6 +1304,7 @@
   ld.max            = cfile.count;
   ld.err            = 0;	/* no error seen yet */
   ld.linktype       = WTAP_ENCAP_UNKNOWN;
+  ld.pcap_err       = FALSE;
   ld.from_pipe      = FALSE;
   ld.sync_packets   = 0;
   ld.counts.sctp    = 0;
@@ -1639,10 +1641,18 @@
 	 * it.
 	 */
 	inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
+	if (inpkts < 0) {
+	  ld.pcap_err = TRUE;
+	  ld.go = FALSE;
+	}
       } else
 	inpkts = 0;
 #else
       inpkts = pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld);
+      if (inpkts < 0) {
+        ld.pcap_err = TRUE;
+        ld.go = FALSE;
+      }
 #endif
     }
     if (inpkts > 0)
@@ -1703,6 +1713,20 @@
   /* delete stop conditions */
   cnd_delete(cnd_stop_capturesize);
   cnd_delete(cnd_stop_timeout);
+
+  if (ld.pcap_err) {
+    snprintf(errmsg, sizeof(errmsg), "Error while capturing packets: %s",
+      pcap_geterr(pch));
+    if (capture_child) {
+      /* Tell the parent, so that they can pop up the message;
+         we're going to exit, so if we try to pop it up, either
+         it won't pop up or it'll disappear as soon as we exit. */
+      send_errmsg_to_parent(errmsg);
+    } else {
+     /* Just pop up the message ourselves. */
+     simple_dialog(ESD_TYPE_WARN, NULL, "%s", errmsg);
+    }
+  }
 
   if (ld.err != 0) {
     get_capture_file_io_error(errmsg, sizeof(errmsg), cfile.save_file, ld.err,


--- tethereal.c.orig	Fri Dec 21 22:26:49 2001
+++ tethereal.c	Sun Dec 30 17:06:24 2001
@@ -57,6 +57,7 @@
 
 #ifdef HAVE_LIBPCAP
 #include <pcap.h>
+#include <setjmp.h>
 #endif
 
 #ifdef HAVE_LIBZ
@@ -125,6 +126,7 @@
   gint           linktype;
   pcap_t        *pch;
   wtap_dumper   *pdh;
+  jmp_buf        stopenv;
   gboolean       go;
 } loop_data;
 
@@ -755,14 +757,15 @@
 /* Do the low-level work of a capture.
    Returns TRUE if it succeeds, FALSE otherwise. */
 static int
-capture(int packet_count, int out_file_type)
+capture(volatile int packet_count, int out_file_type)
 {
   gchar       open_err_str[PCAP_ERRBUF_SIZE];
   gchar       lookup_net_err_str[PCAP_ERRBUF_SIZE];
   bpf_u_int32 netnum, netmask;
   struct bpf_program fcode;
   void        (*oldhandler)(int);
-  int         err, inpkts;
+  int         err;
+  volatile int inpkts = 0;
   char        errmsg[1024+1];
   condition *cnd_stop_capturesize;
   condition *cnd_stop_timeout;
@@ -848,7 +851,7 @@
        * we just warn the user, and punt and use 0.
        */
       fprintf(stderr, 
-        "Warning:  Couldn't obtain netmask info (%s)\n.", lookup_net_err_str);
+        "Warning:  Couldn't obtain netmask info (%s).\n", lookup_net_err_str);
       netmask = 0;
     }
     if (pcap_compile(ld.pch, &fcode, cfile.cfilter, 1, netmask) < 0) {
@@ -923,12 +926,15 @@
 
   if (packet_count == 0)
     packet_count = -1; /* infinite capturng */
-  ld.go = TRUE;
+  if (!setjmp(ld.stopenv))
+    ld.go = TRUE;
+  else
+    ld.go = FALSE;
   while (ld.go) {
     if (packet_count > 0)
       packet_count--;
     inpkts = pcap_dispatch(ld.pch, 1, capture_pcap_cb, (u_char *) &ld);
-    if (packet_count == 0) {
+    if (packet_count == 0 || inpkts < 0) {
       ld.go = FALSE;
     } else if (cnd_eval(cnd_stop_timeout) == TRUE) {
       /* The specified capture time has elapsed; stop the capture. */
@@ -1038,9 +1044,7 @@
 static void
 capture_cleanup(int signum)
 {
-  /* Just set the loop flag to false. This will initiate 
-     a proper termination. */
-  ld.go = FALSE;
+  longjmp(ld.stopenv, 1);
 }
 #endif /* HAVE_LIBPCAP */