summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--capture.c86
-rw-r--r--capture.h16
-rw-r--r--capture_loop.c142
-rw-r--r--capture_loop.h14
-rw-r--r--capture_sync.c89
-rw-r--r--capture_sync.h8
-rw-r--r--dumpcap.c98
-rw-r--r--tethereal.c126
8 files changed, 358 insertions, 221 deletions
diff --git a/capture.c b/capture.c
index 18158aec46..4ddf910acd 100644
--- a/capture.c
+++ b/capture.c
@@ -240,7 +240,7 @@ guint32 drops)
}
-/* capture child tells us, we have a new (or the first) capture file */
+/* capture child tells us we have a new (or the first) capture file */
gboolean
capture_input_new_file(capture_options *capture_opts, gchar *new_file)
{
@@ -308,7 +308,7 @@ capture_input_new_file(capture_options *capture_opts, gchar *new_file)
}
-/* capture child tells us, we have new packets to read */
+/* capture child tells us we have new packets to read */
void
capture_input_new_packets(capture_options *capture_opts, int to_read)
{
@@ -353,7 +353,7 @@ capture_input_new_packets(capture_options *capture_opts, int to_read)
}
-/* Capture child told us, how many dropped packets it counted.
+/* Capture child told us how many dropped packets it counted.
*/
void
capture_input_drops(capture_options *capture_opts, int dropped)
@@ -367,21 +367,91 @@ capture_input_drops(capture_options *capture_opts, int dropped)
}
-/* Capture child told us, that an error has occurred while starting/running the capture. */
+/* Capture child told us that an error has occurred while starting/running
+ the capture.
+ The buffer we're handed has *two* null-terminated strings in it - a
+ primary message and a secondary message, one right after the other.
+ The secondary message might be a null string.
+ */
void
-capture_input_error_message(capture_options *capture_opts, char *error_message)
+capture_input_error_message(capture_options *capture_opts, char *error_msg)
{
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\"", error_message);
+ char *secondary_error_msg = strchr(error_msg, '\0') + 1;
+ gchar *safe_error_msg;
+ gchar *safe_secondary_error_msg;
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\", \"%s\"",
+ error_msg, secondary_error_msg);
g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", error_message);
+ safe_error_msg = simple_dialog_format_message(error_msg);
+ if (*secondary_error_msg != '\0') {
+ /* We have both primary and secondary messages. */
+ safe_secondary_error_msg = simple_dialog_format_message(secondary_error_msg);
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n\n%s",
+ simple_dialog_primary_start(), safe_error_msg,
+ simple_dialog_primary_end(), safe_secondary_error_msg);
+ g_free(safe_secondary_error_msg);
+ } else {
+ /* We have only a primary message. */
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s",
+ simple_dialog_primary_start(), safe_error_msg,
+ simple_dialog_primary_end());
+ }
+ g_free(safe_error_msg);
+
+ /* the capture child will close the sync_pipe if required, nothing to do for now */
+}
+
+
+
+/* Capture child told us that an error has occurred while parsing a
+ capture filter when starting/running the capture.
+ */
+void
+capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message)
+{
+ dfilter_t *rfcode = NULL;
+ gchar *safe_cfilter = simple_dialog_format_message(capture_opts->cfilter);
+ gchar *safe_cfilter_error_msg = simple_dialog_format_message(error_message);
+
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture filter error message from child: \"%s\"", error_message);
+
+ g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
+
+ /* Did the user try a display filter? */
+ if (dfilter_compile(capture_opts->cfilter, &rfcode) && rfcode != NULL) {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "%sInvalid capture filter: \"%s\"!%s\n"
+ "\n"
+ "That string looks like a valid display filter; however, it isn't a valid\n"
+ "capture filter (%s).\n"
+ "\n"
+ "Note that display filters and capture filters don't have the same syntax,\n"
+ "so you can't use most display filter expressions as capture filters.\n"
+ "\n"
+ "See the User's Guide for a description of the capture filter syntax.",
+ simple_dialog_primary_start(), safe_cfilter,
+ simple_dialog_primary_end(), safe_cfilter_error_msg);
+ dfilter_free(rfcode);
+ } else {
+ simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+ "%sInvalid capture filter: \"%s\"!%s\n"
+ "\n"
+ "That string isn't a valid capture filter (%s).\n"
+ "See the User's Guide for a description of the capture filter syntax.",
+ simple_dialog_primary_start(), safe_cfilter,
+ simple_dialog_primary_end(), safe_cfilter_error_msg);
+ }
+ g_free(safe_cfilter_error_msg);
+ g_free(safe_cfilter);
/* the capture child will close the sync_pipe if required, nothing to do for now */
}
-/* capture child closed it's side ot the pipe, do the required cleanup */
+/* capture child closed its side of the pipe, do the required cleanup */
void
capture_input_closed(capture_options *capture_opts)
{
diff --git a/capture.h b/capture.h
index 671fe281e0..f36dd50348 100644
--- a/capture.h
+++ b/capture.h
@@ -51,27 +51,33 @@ extern void capture_restart(capture_options *capture_opts);
extern void capture_kill_child(capture_options *capture_opts);
/**
- * Capture child told us, we have a new (or the first) capture file.
+ * Capture child told us we have a new (or the first) capture file.
*/
extern gboolean capture_input_new_file(capture_options *capture_opts, gchar *new_file);
/**
- * Capture child told us, we have new packets to read.
+ * Capture child told us we have new packets to read.
*/
extern void capture_input_new_packets(capture_options *capture_opts, int to_read);
/**
- * Capture child told us, how many dropped packets it counted.
+ * Capture child told us how many dropped packets it counted.
*/
extern void capture_input_drops(capture_options *capture_opts, int dropped);
/**
- * Capture child told us, that an error has occurred while starting the capture.
+ * Capture child told us that an error has occurred while starting the capture.
*/
extern void capture_input_error_message(capture_options *capture_opts, char *error_message);
/**
- * Capture child closed it's side ot the pipe, do the required cleanup.
+ * Capture child told us that an error has occurred while parsing a
+ * capture filter when starting/running the capture.
+ */
+extern void capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message);
+
+/**
+ * Capture child closed its side of the pipe, do the required cleanup.
*/
extern void capture_input_closed(capture_options *capture_opts);
diff --git a/capture_loop.c b/capture_loop.c
index dc4eb74c51..492f6011c3 100644
--- a/capture_loop.c
+++ b/capture_loop.c
@@ -87,7 +87,11 @@
#include "capture_loop.h"
-
+/*
+ * Standard secondary message for unexpected errors.
+ */
+static const char please_report[] =
+ "Please report this to the Ethereal developers";
/*
* This needs to be static, so that the SIGUSR1 handler can clear the "go"
@@ -429,7 +433,11 @@ cap_pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr,
/* open the capture input file (pcap or capture pipe) */
-gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, char *errmsg, int errmsg_len) {
+gboolean
+capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
+ char *errmsg, size_t errmsg_len,
+ char *secondary_errmsg, size_t secondary_errmsg_len)
+{
gchar open_err_str[PCAP_ERRBUF_SIZE];
gchar *sync_msg_str;
const char *set_linktype_err_str;
@@ -489,6 +497,7 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
"Couldn't initialize Windows Sockets: error %d", err);
break;
}
+ g_snprintf(secondary_errmsg, secondary_errmsg_len, please_report);
return FALSE;
}
#endif
@@ -509,16 +518,15 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
#ifdef _WIN32
/* try to set the capture buffer size */
if (pcap_setbuff(ld->pcap_h, capture_opts->buffer_size * 1024 * 1024) != 0) {
- sync_msg_str = g_strdup_printf(
- "%sCouldn't set the capture buffer size!%s\n"
- "\n"
+ sync_secondary_msg_str = g_strdup_printf(
"The capture buffer size of %luMB seems to be too high for your machine,\n"
"the default of 1MB will be used.\n"
"\n"
"Nonetheless, the capture is started.\n",
- simple_dialog_primary_start(), simple_dialog_primary_end(), capture_opts->buffer_size);
- sync_pipe_errmsg_to_parent(sync_msg_str);
- g_free(sync_msg_str);
+ capture_opts->buffer_size);
+ sync_pipe_errmsg_to_parent("Couldn't set the capture buffer size!",
+ sync_secondary_msg_str);
+ g_free(sync_secondary_msg_str);
}
#endif
@@ -528,7 +536,9 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
capture_opts->linktype);
if (set_linktype_err_str != NULL) {
g_snprintf(errmsg, errmsg_len, "Unable to set data link type (%s).",
- set_linktype_err_str);
+ set_linktype_err_str);
+ g_snprintf(secondary_errmsg, secondary_errmsg_len,
+ "Please report this to the Ethereal developers");
return FALSE;
}
}
@@ -543,9 +553,9 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
Do, however, warn about the lack of 64-bit support, and warn that
WAN devices aren't supported. */
g_snprintf(errmsg, errmsg_len,
-"%sThe capture session could not be initiated!%s\n"
-"\n"
-"(%s)\n"
+"The capture session could not be initiated (%s).",
+ open_err_str);
+ g_snprintf(secondary_errmsg, secondary_errmsg_len,
"\n"
"Please check that \"%s\" is the proper interface.\n"
"\n"
@@ -555,7 +565,7 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
" %shttp://wiki.ethereal.com/CaptureSetup%s\n"
"\n"
"64-bit Windows:\n"
-"WinPcap does not support 64-bit Windows, you will have to use some other\n"
+"WinPcap does not support 64-bit Windows; you will have to use some other\n"
"tool to capture traffic, such as netcap.\n"
"For netcap details see: http://support.microsoft.com/?id=310875\n"
"\n"
@@ -565,10 +575,7 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
"Server 2003.\n"
"WinPcap 3.1 has support for it on Windows 2000 / XP / Server 2003, but has no\n"
"support for it on Windows NT 4.0 or Windows Vista (Beta 1).",
- simple_dialog_primary_start(), simple_dialog_primary_end(),
- open_err_str,
- capture_opts->iface,
- simple_dialog_primary_start(), simple_dialog_primary_end());
+ open_err_str, capture_opts->iface);
return FALSE;
#else
/* try to open iface as a pipe */
@@ -599,10 +606,10 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
else
libpcap_warn = "";
g_snprintf(errmsg, errmsg_len,
- "The capture session could not be initiated (%s).\n"
- "Please check to make sure you have sufficient permissions, and that\n"
- "you have the proper interface or pipe specified.%s", open_err_str,
- libpcap_warn);
+ "The capture session could not be initiated (%s).", open_err_str);
+ g_snprintf(secondary_errmsg, secondary_errmsg_len,
+"Please check to make sure you have sufficient permissions, and that\n"
+"you have the proper interface or pipe specified.%s", libpcap_warn);
}
/*
* Else pipe (or file) does exist and cap_pipe_open_live() has
@@ -631,7 +638,7 @@ gboolean capture_loop_open_input(capture_options *capture_opts, loop_data *ld, c
returned a warning; print it, but keep capturing. */
if (open_err_str[0] != '\0') {
sync_msg_str = g_strdup_printf("%s.", open_err_str);
- sync_pipe_errmsg_to_parent(sync_msg_str);
+ sync_pipe_errmsg_to_parent(sync_msg_str, "");
g_free(sync_msg_str);
}
@@ -666,7 +673,7 @@ static void capture_loop_close_input(loop_data *ld) {
/* init the capture filter */
-gboolean capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const gchar * iface, gchar * cfilter, char *errmsg, int errmsg_len) {
+initfilter_status_t capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const gchar * iface, gchar * cfilter) {
bpf_u_int32 netnum, netmask;
gchar lookup_net_err_str[PCAP_ERRBUF_SIZE];
struct bpf_program fcode;
@@ -692,56 +699,23 @@ gboolean capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const
netmask = 0;
}
if (pcap_compile(pcap_h, &fcode, cfilter, 1, netmask) < 0) {
- dfilter_t *rfcode = NULL;
- gchar *safe_cfilter = simple_dialog_format_message(cfilter);
- gchar *safe_cfilter_error_msg = simple_dialog_format_message(
- pcap_geterr(pcap_h));
-
- /* filter string invalid, did the user tried a display filter? */
-#ifndef DUMPCAP
- if (dfilter_compile(cfilter, &rfcode) && rfcode != NULL) {
- g_snprintf(errmsg, errmsg_len,
- "%sInvalid capture filter: \"%s\"!%s\n"
- "\n"
- "That string looks like a valid display filter; however, it isn't a valid\n"
- "capture filter (%s).\n"
- "\n"
- "Note that display filters and capture filters don't have the same syntax,\n"
- "so you can't use most display filter expressions as capture filters.\n"
- "\n"
- "See the User's Guide for a description of the capture filter syntax.",
- simple_dialog_primary_start(), safe_cfilter,
- simple_dialog_primary_end(), safe_cfilter_error_msg);
- dfilter_free(rfcode);
- } else
-#endif
- {
- g_snprintf(errmsg, errmsg_len,
- "%sInvalid capture filter: \"%s\"!%s\n"
- "\n"
- "That string isn't a valid capture filter (%s).\n"
- "See the User's Guide for a description of the capture filter syntax.",
- simple_dialog_primary_start(), safe_cfilter,
- simple_dialog_primary_end(), safe_cfilter_error_msg);
- }
- g_free(safe_cfilter_error_msg);
- g_free(safe_cfilter);
- return FALSE;
+ /* Treat this specially - our caller might try to compile this
+ as a display filter and, if that succeeds, warn the user that
+ the display and capture filter syntaxes are different. */
+ return INITFILTER_BAD_FILTER;
}
if (pcap_setfilter(pcap_h, &fcode) < 0) {
- g_snprintf(errmsg, errmsg_len, "Can't install filter (%s).",
- pcap_geterr(pcap_h));
#ifdef HAVE_PCAP_FREECODE
pcap_freecode(&fcode);
#endif
- return FALSE;
+ return INITFILTER_OTHER_ERROR;
}
#ifdef HAVE_PCAP_FREECODE
pcap_freecode(&fcode);
#endif
}
- return TRUE;
+ return INITFILTER_NO_ERROR;
}
@@ -850,7 +824,7 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
if (sel_ret < 0 && errno != EINTR) {
g_snprintf(errmsg, errmsg_len,
"Unexpected error from select: %s", strerror(errno));
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, please_report);
ld->go = FALSE;
}
} else {
@@ -930,7 +904,7 @@ capture_loop_dispatch(capture_options *capture_opts _U_, loop_data *ld,
if (sel_ret < 0 && errno != EINTR) {
g_snprintf(errmsg, errmsg_len,
"Unexpected error from select: %s", strerror(errno));
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, please_report);
ld->go = FALSE;
}
}
@@ -1106,7 +1080,9 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
guint32 autostop_files = 0;
gboolean write_ok;
gboolean close_ok;
+ gboolean cfilter_error = FALSE;
char errmsg[4096+1];
+ char secondary_errmsg[4096+1];
int save_file_fd;
@@ -1147,21 +1123,38 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
/* open the output file (temporary/specified name/ringbuffer) */
if (!capture_loop_open_output(capture_opts, &save_file_fd, errmsg, sizeof(errmsg))) {
+ *secondary_errmsg = '\0';
goto error;
}
/* open the "input file" from network interface or capture pipe */
- if (!capture_loop_open_input(capture_opts, &ld, errmsg, sizeof(errmsg))) {
+ if (!capture_loop_open_input(capture_opts, &ld, errmsg, sizeof(errmsg),
+ secondary_errmsg, sizeof(secondary_errmsg))) {
goto error;
}
/* init the input filter from the network interface (capture pipe will do nothing) */
- if (!capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts->iface, capture_opts->cfilter, errmsg, sizeof(errmsg))) {
+ switch (capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts->iface, capture_opts->cfilter)) {
+
+ case INITFILTER_NO_ERROR:
+ break;
+
+ case INITFILTER_BAD_FILTER:
+ cfilter_error = TRUE;
+ g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(ld.pcap_h));
+ *secondary_errmsg = '\0';
+ goto error;
+
+ case INITFILTER_OTHER_ERROR:
+ g_snprintf(errmsg, sizeof(errmsg), "Can't install filter (%s).",
+ pcap_geterr(ld.pcap_h));
+ g_snprintf(secondary_errmsg, sizeof(secondary_errmsg), "%s", please_report);
goto error;
}
/* set up to write to the already-opened capture output file/files */
if (!capture_loop_init_output(capture_opts, save_file_fd, &ld, errmsg, sizeof(errmsg))) {
+ *secondary_errmsg = '\0';
goto error;
}
@@ -1344,11 +1337,11 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
if (ld.pcap_err) {
g_snprintf(errmsg, sizeof(errmsg), "Error while capturing packets: %s",
pcap_geterr(ld.pcap_h));
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, please_report);
}
#ifndef _WIN32
else if (ld.from_cap_pipe && ld.cap_pipe_err == PIPERR)
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, "");
#endif
/* did we had an error while capturing? */
@@ -1357,7 +1350,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
} else {
capture_loop_get_errmsg(errmsg, sizeof(errmsg), capture_opts->save_file, ld.err,
FALSE);
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, please_report);
write_ok = FALSE;
}
@@ -1376,7 +1369,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
if (!close_ok && write_ok) {
capture_loop_get_errmsg(errmsg, sizeof(errmsg), capture_opts->save_file, err_close,
TRUE);
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, "");
}
/*
@@ -1401,7 +1394,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
g_snprintf(errmsg, sizeof(errmsg),
"Can't get packet-drop statistics: %s",
pcap_geterr(ld.pcap_h));
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, please_report);
}
}
@@ -1418,7 +1411,7 @@ error:
/* cleanup ringbuffer */
ringbuf_error_cleanup();
} else {
- /* We can't use the save file, and we have no wtap_dump stream
+ /* We can't use the save file, and we have no FILE * for the stream
to close in order to close it, so close the FD directly. */
eth_close(save_file_fd);
@@ -1428,7 +1421,10 @@ error:
g_free(capture_opts->save_file);
}
capture_opts->save_file = NULL;
- sync_pipe_errmsg_to_parent(errmsg);
+ if (cfilter_error)
+ sync_pipe_cfilter_error_to_parent(capture_opts->cfilter, errmsg);
+ else
+ sync_pipe_errmsg_to_parent(errmsg, secondary_errmsg);
/* close the input file (pcap or cap_pipe) */
capture_loop_close_input(&ld);
diff --git a/capture_loop.h b/capture_loop.h
index bfdf734388..73aafdab60 100644
--- a/capture_loop.h
+++ b/capture_loop.h
@@ -129,8 +129,14 @@ typedef struct _loop_data {
/** init the capture filter */
-extern gboolean
-capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const gchar * iface, gchar * cfilter, char *errmsg, int errmsg_len);
+typedef enum {
+ INITFILTER_NO_ERROR,
+ INITFILTER_BAD_FILTER,
+ INITFILTER_OTHER_ERROR
+} initfilter_status_t;
+
+extern initfilter_status_t
+capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const gchar * iface, gchar * cfilter);
/** Take care of byte order in the libpcap headers read from pipes. */
extern void
@@ -148,7 +154,9 @@ cap_pipe_dispatch(int, loop_data *, struct pcap_hdr *, \
#endif
extern gboolean
-capture_loop_open_input(capture_options *capture_opts, loop_data *ld, char *errmsg, int errmsg_len);
+capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
+ char *errmsg, size_t errmsg_len,
+ char *secondary_errmsg, size_t secondary_errmsg_len);
extern gboolean
capture_loop_open_output(capture_options *capture_opts, int *save_file_fd, char *errmsg, int errmsg_len);
diff --git a/capture_sync.c b/capture_sync.c
index 2a34f79375..45dc5ff7d4 100644
--- a/capture_sync.c
+++ b/capture_sync.c
@@ -120,25 +120,42 @@ static void sync_pipe_wait_for_child(capture_options *capture_opts);
#define SP_MAX_MSG_LEN 4096
- /* write a message to the recipient pipe in the standard format
+/* write a message to the recipient pipe in the standard format
(3 digit message length (excluding length and indicator field),
- 1 byte message indicator and the rest is the message) */
+ 1 byte message indicator and the rest is the message).
+ If msg is NULL, the message has only a length and indicator.
+ Otherwise, if secondary_msg isn't NULL, send both msg and
+ secondary_msg as null-terminated strings, otherwise just send
+ msg as a null-terminated string and follow it with an empty string. */
static void
-pipe_write_block(int pipe, char indicator, int len, const char *msg)
+pipe_write_block(int pipe, char indicator, const char *msg,
+ const char *secondary_msg)
{
guchar header[3+1]; /* indicator + 3-byte len */
int ret;
+ size_t len, secondary_len, total_len;
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "write %d enter", pipe);
+ len = 0;
+ secondary_len = 0;
+ total_len = 0;
+ if(msg != NULL) {
+ len = strlen(msg) + 1; /* include the terminating '\0' */
+ total_len = len;
+ if(secondary_msg == NULL)
+ secondary_msg = ""; /* default to an empty string */
+ secondary_len = strlen(secondary_msg) + 1;
+ total_len += secondary_len;
+ }
g_assert(indicator < '0' || indicator > '9');
- g_assert(len <= SP_MAX_MSG_LEN);
+ g_assert(total_len <= SP_MAX_MSG_LEN);
/* write header (indicator + 3-byte len) */
header[0] = indicator;
- header[1] = (len >> 16) & 0xFF;
- header[2] = (len >> 8) & 0xFF;
- header[3] = (len >> 0) & 0xFF;
+ header[1] = (total_len >> 16) & 0xFF;
+ header[2] = (total_len >> 8) & 0xFF;
+ header[3] = (total_len >> 0) & 0xFF;
ret = write(pipe, header, sizeof header);
if(ret == -1) {
@@ -150,14 +167,21 @@ pipe_write_block(int pipe, char indicator, int len, const char *msg)
/* write value (if we have one) */
if(len) {
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
- "write %d indicator: %c value len: %u msg: %s", pipe, indicator,
- len, msg);
+ "write %d indicator: %c value len: %lu msg: \"%s\" secondary len: %lu secondary msg: \"%s\"", pipe, indicator,
+ (unsigned long)len, msg, (unsigned long)secondary_len,
+ secondary_msg);
ret = write(pipe, msg, len);
if(ret == -1) {
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING,
"write %d value: error %s", pipe, strerror(errno));
return;
}
+ ret = write(pipe, msg, secondary_len);
+ if(ret == -1) {
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_WARNING,
+ "write %d value: error %s", pipe, strerror(errno));
+ return;
+ }
} else {
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
"write %d indicator: %c no value", pipe, indicator);
@@ -169,11 +193,12 @@ pipe_write_block(int pipe, char indicator, int len, const char *msg)
#ifndef _WIN32
void
-sync_pipe_errmsg_to_parent(const char *errmsg)
+sync_pipe_errmsg_to_parent(const char *error_msg,
+ const char *secondary_error_msg)
{
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_errmsg_to_parent: %s", errmsg);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_errmsg_to_parent: %s", error_msg);
- pipe_write_block(1, SP_ERROR_MSG, strlen(errmsg)+1, errmsg);
+ pipe_write_block(1, SP_ERROR_MSG, error_msg, secondary_error_msg);
}
#endif
@@ -185,7 +210,7 @@ signal_pipe_capquit_to_child(capture_options *capture_opts)
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "signal_pipe_capquit_to_child");
- pipe_write_block(capture_opts->signal_pipe_write_fd, SP_QUIT, 0, NULL);
+ pipe_write_block(capture_opts->signal_pipe_write_fd, SP_QUIT, NULL, NULL);
}
#endif
@@ -602,7 +627,7 @@ sync_pipe_start(capture_options *capture_opts) {
execv(exename, argv);
g_snprintf(errmsg, sizeof errmsg, "Couldn't run %s in child process: %s",
exename, strerror(errno));
- sync_pipe_errmsg_to_parent(errmsg);
+ sync_pipe_errmsg_to_parent(errmsg, NULL);
/* Exit with "_exit()", so that we don't close the connection
to the X server (and cause stuff buffered up by our parent but
@@ -694,21 +719,21 @@ sync_pipe_input_cb(gint source, gpointer user_data)
switch(indicator) {
case SP_FILE:
- if(!capture_input_new_file(capture_opts, buffer)) {
- g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: file failed, closing capture");
-
- /* We weren't able to open the new capture file; user has been
- alerted. Close the sync pipe. */
- eth_close(source);
-
- /* the child has send us a filename which we couldn't open.
- this probably means, the child is creating files faster than we can handle it.
- this should only be the case for very fast file switches
- we can't do much more than telling the child to stop
- (this is the "emergency brake" if user e.g. wants to switch files every second) */
- sync_pipe_stop(capture_opts);
- }
- break;
+ if(!capture_input_new_file(capture_opts, buffer)) {
+ g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: file failed, closing capture");
+
+ /* We weren't able to open the new capture file; user has been
+ alerted. Close the sync pipe. */
+ eth_close(source);
+
+ /* the child has send us a filename which we couldn't open.
+ this probably means, the child is creating files faster than we can handle it.
+ this should only be the case for very fast file switches
+ we can't do much more than telling the child to stop
+ (this is the "emergency brake" if user e.g. wants to switch files every second) */
+ sync_pipe_stop(capture_opts);
+ }
+ break;
case SP_PACKET_COUNT:
nread = atoi(buffer);
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: new packets %u", nread);
@@ -718,11 +743,15 @@ sync_pipe_input_cb(gint source, gpointer user_data)
capture_input_error_message(capture_opts, buffer);
/* the capture child will close the sync_pipe, nothing to do for now */
break;
+ case SP_BAD_FILTER:
+ capture_input_cfilter_error_message(capture_opts, buffer);
+ /* the capture child will close the sync_pipe, nothing to do for now */
+ break;
case SP_DROPS:
capture_input_drops(capture_opts, atoi(buffer));
break;
default:
- g_assert_not_reached();
+ g_assert_not_reached();
}
return TRUE;
diff --git a/capture_sync.h b/capture_sync.h
index 2e08588839..aecb8f00d1 100644
--- a/capture_sync.h
+++ b/capture_sync.h
@@ -44,6 +44,7 @@
*/
#define SP_FILE 'F' /* the name of the recently opened file */
#define SP_ERROR_MSG 'E' /* error message */
+#define SP_BAD_FILTER 'B' /* error message for bad capture filter */
#define SP_PACKET_COUNT 'P' /* count of packets captured since last message */
#define SP_DROPS 'D' /* count of packets dropped in capture */
/*
@@ -89,9 +90,14 @@ sync_pipe_packet_count_to_parent(int packet_count);
extern void
sync_pipe_drops_to_parent(int drops);
+/** the child encountered an error with a capture filter, notify the parent */
+extern void
+sync_pipe_cfilter_error_to_parent(const char *cfilter, const char *errmsg);
+
/** the child encountered an error, notify the parent */
extern void
-sync_pipe_errmsg_to_parent(const char *errmsg);
+sync_pipe_errmsg_to_parent(const char *error_msg,
+ const char *secondary_error_msg);
/** does the parent signalled the child to stop */
diff --git a/dumpcap.c b/dumpcap.c
index a5222655af..268f32615e 100644
--- a/dumpcap.c
+++ b/dumpcap.c
@@ -512,25 +512,42 @@ console_log_handler(const char *log_domain, GLogLevelFlags log_level,
#define SP_MAX_MSG_LEN 4096
- /* write a message to the recipient pipe in the standard format
+/* write a message to the recipient pipe in the standard format
(3 digit message length (excluding length and indicator field),
- 1 byte message indicator and the rest is the message) */
+ 1 byte message indicator and the rest is the message).
+ If msg is NULL, the message has only a length and indicator.
+ Otherwise, if secondary_msg isn't NULL, send both msg and
+ secondary_msg as null-terminated strings, otherwise just send
+ msg as a null-terminated string and follow it with an empty string. */
static void
-pipe_write_block(int pipe, char indicator, int len, const char *msg)
+pipe_write_block(int pipe, char indicator, const char *msg,
+ const char *secondary_msg)
{
guchar header[3+1]; /* indicator + 3-byte len */
int ret;
+ size_t len, secondary_len, total_len;
/*g_warning("write %d enter", pipe);*/
+ len = 0;
+ secondary_len = 0;
+ total_len = 0;
+ if(msg != NULL) {
+ len = strlen(msg) + 1; /* include the terminating '\0' */
+ total_len = len;
+ if(secondary_msg == NULL)
+ secondary_msg = ""; /* default to an empty string */
+ secondary_len = strlen(secondary_msg) + 1;
+ total_len += secondary_len;
+ }
g_assert(indicator < '0' || indicator > '9');
- g_assert(len <= SP_MAX_MSG_LEN);
+ g_assert(total_len <= SP_MAX_MSG_LEN);
/* write header (indicator + 3-byte len) */
header[0] = indicator;
- header[1] = (len >> 16) & 0xFF;
- header[2] = (len >> 8) & 0xFF;
- header[3] = (len >> 0) & 0xFF;
+ header[1] = (total_len >> 16) & 0xFF;
+ header[2] = (total_len >> 8) & 0xFF;
+ header[3] = (total_len >> 0) & 0xFF;
ret = write(pipe, header, sizeof header);
if(ret == -1) {
@@ -544,6 +561,10 @@ pipe_write_block(int pipe, char indicator, int len, const char *msg)
if(ret == -1) {
return;
}
+ ret = write(pipe, secondary_msg, secondary_len);
+ if(ret == -1) {
+ return;
+ }
} else {
/*g_warning("write %d indicator: %c no value", pipe, indicator);*/
}
@@ -562,7 +583,7 @@ sync_pipe_packet_count_to_parent(int packet_count)
if(capture_child) {
g_snprintf(tmp, sizeof(tmp), "%d", packet_count);
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Packets: %s", tmp);
- pipe_write_block(1, SP_PACKET_COUNT, strlen(tmp)+1, tmp);
+ pipe_write_block(1, SP_PACKET_COUNT, tmp, NULL);
} else {
count += packet_count;
fprintf(stderr, "\rPackets: %u ", count);
@@ -579,18 +600,33 @@ sync_pipe_filename_to_parent(const char *filename)
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "File: %s", filename);
if(capture_child) {
- pipe_write_block(1, SP_FILE, strlen(filename)+1, filename);
+ pipe_write_block(1, SP_FILE, filename, NULL);
+ }
+}
+
+
+void
+sync_pipe_cfilter_error_to_parent(const char *cfilter _U_, const char *errmsg)
+{
+
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Capture filter error: %s", errmsg);
+
+ if (capture_child) {
+ pipe_write_block(1, SP_BAD_FILTER, errmsg, NULL);
}
}
void
-sync_pipe_errmsg_to_parent(const char *errmsg)
+sync_pipe_errmsg_to_parent(const char *error_msg, const char *secondary_error_msg)
{
- g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "Error: %s", errmsg);
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "Error: %s", error_msg);
+ if (secondary_error_msg != NULL)
+ g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "Secondary error: %s",
+ secondary_error_msg);
if(capture_child) {
- pipe_write_block(1, SP_ERROR_MSG, strlen(errmsg)+1, errmsg);
+ pipe_write_block(1, SP_ERROR_MSG, error_msg, secondary_error_msg);
}
}
@@ -604,7 +640,7 @@ sync_pipe_drops_to_parent(int drops)
g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_MESSAGE, "Packets dropped: %s", tmp);
if(capture_child) {
- pipe_write_block(1, SP_DROPS, strlen(tmp)+1, tmp);
+ pipe_write_block(1, SP_DROPS, tmp, NULL);
}
}
@@ -648,43 +684,7 @@ signal_pipe_check_running(void)
/****************************************************************************************************************/
-/* simple_dialog stubs */
-
-
-char *simple_dialog_primary_start(void)
-{
- return "";
-}
-
-char *simple_dialog_primary_end(void)
-{
- return "";
-}
-
-char *
-simple_dialog_format_message(const char *msg)
-{
- char *str;
-
- if (msg) {
-#if GTK_MAJOR_VERSION < 2
- str = g_strdup(msg);
-#else
- str = xml_escape(msg);
-#endif
- } else {
- str = NULL;
- }
- return str;
-}
-
-
-/****************************************************************************************************************/
/* Stub functions */
const char *netsnmp_get_version(void) { return ""; }
-
-gboolean dfilter_compile(const gchar *text, dfilter_t **dfp) { (void)text; (void)dfp; return FALSE; }
-
-void dfilter_free(dfilter_t *df) { (void)df; }
diff --git a/tethereal.c b/tethereal.c
index b0775b0625..176607996b 100644
--- a/tethereal.c
+++ b/tethereal.c
@@ -136,6 +136,12 @@ static guint32 cum_bytes = 0;
static print_format_e print_format = PR_FMT_TEXT;
static print_stream_t *print_stream;
+/*
+ * Standard secondary message for unexpected errors.
+ */
+static const char please_report[] =
+ "Please report this to the Ethereal developers";
+
#ifdef HAVE_LIBPCAP
/*
* TRUE if we're to print packet counts to keep track of captured packets.
@@ -1499,7 +1505,6 @@ capture(void)
int volatile volatile_err = 0;
int volatile inpkts = 0;
int pcap_cnt;
- char errmsg[1024+1];
condition *volatile cnd_autostop_size = NULL;
condition *volatile cnd_autostop_duration = NULL;
char *descr;
@@ -1510,6 +1515,9 @@ capture(void)
struct pcap_stat stats;
gboolean write_ok;
gboolean close_ok;
+ gboolean cfilter_error = FALSE;
+ char errmsg[1024+1];
+ char secondary_errmsg[4096+1];
int save_file_fd;
/* Initialize all data structures used for dissection. */
@@ -1521,8 +1529,8 @@ capture(void)
/* open the "input file" from network interface or capture pipe */
- if (!capture_loop_open_input(&capture_opts, &ld, errmsg, sizeof(errmsg)))
- {
+ if (!capture_loop_open_input(&capture_opts, &ld, errmsg, sizeof(errmsg),
+ secondary_errmsg, sizeof(secondary_errmsg))) {
goto error;
}
@@ -1542,20 +1550,33 @@ capture(void)
/* open the output file (temporary/specified name/ringbuffer/named pipe/stdout) */
if (!capture_loop_open_output(&capture_opts, &save_file_fd, errmsg, sizeof(errmsg))) {
+ *secondary_errmsg = '\0';
goto error;
}
/* init the input filter from the network interface (capture pipe will do nothing) */
- if(!capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe,
- capture_opts.iface, capture_opts.cfilter, errmsg, sizeof errmsg))
- {
- goto error;
+ switch (capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts.iface, capture_opts.cfilter)) {
+
+ case INITFILTER_NO_ERROR:
+ break;
+
+ case INITFILTER_BAD_FILTER:
+ cfilter_error = TRUE;
+ g_snprintf(errmsg, sizeof(errmsg), "%s", pcap_geterr(ld.pcap_h));
+ *secondary_errmsg = '\0';
+ goto error;
+
+ case INITFILTER_OTHER_ERROR:
+ g_snprintf(errmsg, sizeof(errmsg), "Can't install filter (%s).",
+ pcap_geterr(ld.pcap_h));
+ g_snprintf(secondary_errmsg, sizeof(secondary_errmsg), "%s", please_report);
+ goto error;
}
/* set up to write to the already-opened capture output file/files */
- if(!capture_loop_init_output(&capture_opts, save_file_fd, &ld, errmsg, sizeof errmsg))
- {
- goto error;
+ if(!capture_loop_init_output(&capture_opts, save_file_fd, &ld, errmsg, sizeof errmsg)) {
+ *secondary_errmsg = '\0';
+ goto error;
}
ld.wtap_linktype = wtap_pcap_encap_to_wtap_encap(ld.linktype);
@@ -1793,7 +1814,36 @@ error:
}
g_free(capture_opts.save_file);
capture_opts.save_file = NULL;
- cmdarg_err("%s", errmsg);
+ if (cfilter_error) {
+ dfilter_t *rfcode = NULL;
+ if (dfilter_compile(capture_opts.cfilter, &rfcode) && rfcode != NULL) {
+ cmdarg_err(
+ "Invalid capture filter: \"%s\"!\n"
+ "\n"
+ "That string looks like a valid display filter; however, it isn't a valid\n"
+ "capture filter (%s).\n"
+ "\n"
+ "Note that display filters and capture filters don't have the same syntax,\n"
+ "so you can't use most display filter expressions as capture filters.\n"
+ "\n"
+ "See the User's Guide for a description of the capture filter syntax.",
+ capture_opts.cfilter, errmsg);
+ dfilter_free(rfcode);
+ } else {
+ cmdarg_err(
+ "Invalid capture filter: \"%s\"!\n"
+ "\n"
+ "That string isn't a valid capture filter (%s).\n"
+ "See the User's Guide for a description of the capture filter syntax.",
+ capture_opts.cfilter, errmsg);
+ }
+ } else {
+ cmdarg_err("%s", errmsg);
+ if (*secondary_errmsg != '\0') {
+ fprintf(stderr, "\n");
+ cmdarg_err_cont("%s", secondary_errmsg);
+ }
+ }
#ifndef _WIN32
if (ld.from_cap_pipe) {
if (ld.cap_pipe_fd >= 0)
@@ -2971,6 +3021,19 @@ sync_pipe_drops_to_parent(int drops)
g_assert(0);
}
+/** the child encountered an error with a capture filter, notify the parent */
+void
+sync_pipe_cfilter_error_to_parent(const char *cfilter, const char *errmsg)
+{
+
+ cmdarg_err(
+ "Invalid capture filter: \"%s\"!\n"
+ "\n"
+ "That string isn't a valid capture filter (%s).\n"
+ "See the User's Guide for a description of the capture filter syntax.",
+ cfilter, errmsg);
+}
+
/** the child encountered an error, notify the parent */
void
sync_pipe_errmsg_to_parent(const char *errmsg)
@@ -2996,44 +3059,3 @@ signal_pipe_check_running(void)
#endif /* _WIN32 */
#endif /* HAVE_LIBPCAP */
-
-
-/****************************************************************************************************************/
-/* simple_dialog "dummies", needed for capture_loop.c */
-
-
-#ifdef HAVE_LIBPCAP
-
-char *simple_dialog_primary_start(void)
-{
- return "";
-}
-
-char *simple_dialog_primary_end(void)
-{
- return "";
-}
-
-
-/* XXX - do we need to convert the string for the console? */
-char *
-simple_dialog_format_message(const char *msg)
-{
- char *str;
-
-
- if (msg) {
-#if GTK_MAJOR_VERSION < 2
- str = g_strdup(msg);
-#else
- str = xml_escape(msg);
-#endif
- } else {
- str = NULL;
- }
- return str;
-}
-
-#endif /* HAVE_LIBPCAP */
-
-