diff options
-rw-r--r-- | capture.c | 86 | ||||
-rw-r--r-- | capture.h | 16 | ||||
-rw-r--r-- | capture_loop.c | 142 | ||||
-rw-r--r-- | capture_loop.h | 14 | ||||
-rw-r--r-- | capture_sync.c | 89 | ||||
-rw-r--r-- | capture_sync.h | 8 | ||||
-rw-r--r-- | dumpcap.c | 98 | ||||
-rw-r--r-- | tethereal.c | 126 |
8 files changed, 358 insertions, 221 deletions
@@ -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) { @@ -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 */ @@ -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 */ - - |