From 79217bab2ebb0d2811e130bea6334c8227a88a28 Mon Sep 17 00:00:00 2001 From: Ulf Lamping Date: Tue, 13 Dec 2005 22:48:58 +0000 Subject: [PATCH] HUGE STEP (hopefully toward the right direction): remove a lot of redundant code from tethereal and use (move) stuff from capture_loop.c instead. concentrate common capture related code in capture_opts.c, e.g. trying to find the right interface to capture from (command line option, preference, first usable) instead of duplicating this code over several files. remove redundant code from dumpcap.c this also implements command line option -D (and indexed interfaces at -i) for Ethereal and Dumpcap (as we have it in Tethereal already for a while) svn path=/trunk/; revision=16787 --- Makefile.common | 1 + capture_loop.c | 206 +++++------ capture_loop.h | 110 ++++++ capture_opts.c | 193 +++++++++- capture_opts.h | 23 +- dumpcap.c | 116 ++---- gtk/main.c | 92 ++--- tethereal.c | 922 ++++++++++-------------------------------------- 8 files changed, 633 insertions(+), 1030 deletions(-) diff --git a/Makefile.common b/Makefile.common index 4e4b3abce7..a6f5c7954c 100644 --- a/Makefile.common +++ b/Makefile.common @@ -178,6 +178,7 @@ tethereal_SOURCES = \ $(ETHEREAL_COMMON_SRC) \ $(TETHEREAL_TAP_SRC) \ capture_opts.c \ + capture_loop.c \ tethereal-tap-register.c \ tethereal.c diff --git a/capture_loop.c b/capture_loop.c index 31c0283d73..db0664e454 100644 --- a/capture_loop.c +++ b/capture_loop.c @@ -61,97 +61,41 @@ #include #include +#include #include +#include "wiretap/wtap.h" +#include "wiretap/wtap-capture.h" +#include "wiretap/libpcap.h" + + #include #include "capture-pcap-util.h" #include "capture.h" -#include "capture_loop.h" #include "capture_sync.h" #include "conditions.h" #include "capture_stop_conditions.h" #include "ringbuffer.h" -#include "wiretap/libpcap.h" -#include "wiretap/wtap.h" -#include "wiretap/wtap-capture.h" - #include "simple_dialog.h" #include "util.h" #include "log.h" #include "file_util.h" +#include "capture_loop.h" + /* - * We don't want to do a "select()" on the pcap_t's file descriptor on - * BSD (because "select()" doesn't work correctly on BPF devices on at - * least some releases of some flavors of BSD), and we don't want to do - * it on Windows (because "select()" is something for sockets, not for - * arbitrary handles). (Note that "Windows" here includes Cygwin; - * even in its pretend-it's-UNIX environment, we're using WinPcap, not - * a UNIX libpcap.) - * - * We *do* want to do it on other platforms, as, on other platforms (with - * the possible exception of Ultrix and Digital UNIX), the read timeout - * doesn't expire if no packets have arrived, so a "pcap_dispatch()" call - * will block until packets arrive, causing the UI to hang. - * - * XXX - the various BSDs appear to define BSD in ; we don't - * want to include it if it's not present on this platform, however. + * This needs to be static, so that the SIGUSR1 handler can clear the "go" + * flag. */ -#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && \ - !defined(__bsdi__) && !defined(__APPLE__) && !defined(_WIN32) && \ - !defined(__CYGWIN__) -# define MUST_DO_SELECT -#endif - - -typedef struct _loop_data { - /* common */ - gboolean go; /* TRUE as long as we're supposed to keep capturing */ - int err; /* if non-zero, error seen while capturing */ - gint packets_curr; /* Number of packets we have already captured */ - gint packets_max; /* Number of packets we're supposed to capture - 0 means infinite */ - gint packets_sync_pipe; /* packets not already send out to the sync_pipe */ - - /* pcap "input file" */ - pcap_t *pcap_h; /* pcap handle */ - gboolean pcap_err; /* TRUE if error from pcap */ -#ifdef MUST_DO_SELECT - int pcap_fd; /* pcap file descriptor */ -#endif - - /* capture pipe (unix only "input file") */ - gboolean from_cap_pipe; /* TRUE if we are capturing data from a capture pipe */ -#ifndef _WIN32 - struct pcap_hdr cap_pipe_hdr; - struct pcaprec_modified_hdr cap_pipe_rechdr; - int cap_pipe_fd; /* the file descriptor of the capture pipe */ - gboolean cap_pipe_modified; /* TRUE if data in the pipe uses modified pcap headers */ - gboolean cap_pipe_byte_swapped; /* TRUE if data in the pipe is byte swapped */ - unsigned int cap_pipe_bytes_to_read;/* Used by cap_pipe_dispatch */ - unsigned int cap_pipe_bytes_read; /* Used by cap_pipe_dispatch */ - enum { - STATE_EXPECT_REC_HDR, - STATE_READ_REC_HDR, - STATE_EXPECT_DATA, - STATE_READ_DATA - } cap_pipe_state; - - enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } cap_pipe_err; -#endif - - /* wiretap (output file) */ - wtap_dumper *wtap_pdh; - gint wtap_linktype; - -} loop_data; +static loop_data ld; /* @@ -169,10 +113,10 @@ static void capture_loop_get_errmsg(char *errmsg, int errmsglen, const char *fna #ifndef _WIN32 /* Take care of byte order in the libpcap headers read from pipes. * (function taken from wiretap/libpcap.c) */ -static void -cap_pipe_adjust_header(loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr) +void +cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr) { - if (ld->cap_pipe_byte_swapped) { + if (byte_swapped) { /* Byte-swap the record header fields. */ rechdr->ts_sec = BSWAP32(rechdr->ts_sec); rechdr->ts_usec = BSWAP32(rechdr->ts_usec); @@ -203,7 +147,7 @@ cap_pipe_adjust_header(loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_hdr * * header. * N.B. : we can't read the libpcap formats used in RedHat 6.1 or SuSE 6.3 * because we can't seek on pipes (see wiretap/libpcap.c for details) */ -static int +int cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld, char *errmsg, int errmsgl) { @@ -219,7 +163,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld, g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: %s", pipename); /* - * XXX Ethereal blocks until we return + * XXX (T)Ethereal blocks until we return */ if (strcmp(pipename, "-") == 0) fd = 0; /* read from stdin */ @@ -375,7 +319,7 @@ error: /* We read one record from the pipe, take care of byte order in the record * header, write the record to the capture file, and update capture statistics. */ -static int +int cap_pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr, struct pcaprec_modified_hdr *rechdr, guchar *data, char *errmsg, int errmsgl) @@ -446,10 +390,10 @@ cap_pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr, case PD_REC_HDR_READ: /* We've read the header. Take care of byte order. */ - cap_pipe_adjust_header(ld, hdr, &rechdr->hdr); + cap_pipe_adjust_header(ld->cap_pipe_byte_swapped, hdr, &rechdr->hdr); if (rechdr->hdr.incl_len > WTAP_MAX_PACKET_SIZE) { g_snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)", - ld->packets_curr+1, rechdr->hdr.incl_len); + ld->packet_count+1, rechdr->hdr.incl_len); break; } ld->cap_pipe_state = STATE_EXPECT_DATA; @@ -462,7 +406,7 @@ cap_pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr, phdr.caplen = rechdr->hdr.incl_len; phdr.len = rechdr->hdr.orig_len; - capture_loop_packet_cb((u_char *)ld, &phdr, data); + ld->packet_cb((u_char *)ld, &phdr, data); ld->cap_pipe_state = STATE_EXPECT_REC_HDR; return 1; @@ -487,8 +431,9 @@ cap_pipe_dispatch(int fd, loop_data *ld, struct pcap_hdr *hdr, /* open the capture input file (pcap or capture pipe) */ -static int 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, int errmsg_len) { gchar open_err_str[PCAP_ERRBUF_SIZE]; + gchar *sync_msg_str; const char *set_linktype_err_str; #ifdef _WIN32 int err; @@ -502,6 +447,9 @@ static int capture_loop_open_input(capture_options *capture_opts, loop_data *ld, g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_open_input : %s", capture_opts->iface); + +/* XXX - opening Winsock on tethereal? */ + /* Initialize Windows Socket if we are in a WIN32 OS This needs to be done before querying the interface for network/netmask */ #ifdef _WIN32 @@ -563,7 +511,7 @@ static int capture_loop_open_input(capture_options *capture_opts, loop_data *ld, #ifdef _WIN32 /* try to set the capture buffer size */ if (pcap_setbuff(ld->pcap_h, capture_opts->buffer_size * 1024 * 1024) != 0) { - simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK, + sync_msg_str = g_strdup_printf( "%sCouldn't set the capture buffer size!%s\n" "\n" "The capture buffer size of %luMB seems to be too high for your machine,\n" @@ -571,6 +519,8 @@ static int capture_loop_open_input(capture_options *capture_opts, loop_data *ld, "\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); } #endif @@ -592,13 +542,14 @@ static int capture_loop_open_input(capture_options *capture_opts, loop_data *ld, /* On Win32 OSes, the capture devices are probably available to all users; don't warn about permissions problems. - Do, however, warn that WAN devices aren't supported. */ + 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" "\n" -"Please check that you have the proper interface specified.\n" +"Please check that \"%s\" is the proper interface.\n" "\n" "\n" "Help can be found at:\n" @@ -618,6 +569,7 @@ static int capture_loop_open_input(capture_options *capture_opts, loop_data *ld, "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()); return FALSE; #else @@ -630,16 +582,16 @@ static int capture_loop_open_input(capture_options *capture_opts, loop_data *ld, /* Pipe doesn't exist, so output message for interface */ /* If we got a "can't find PPA for XXX" message, warn the user (who - is running Ethereal on HP-UX) that they don't have a version + is running (T)Ethereal on HP-UX) that they don't have a version of libpcap that properly handles HP-UX (libpcap 0.6.x and later versions, which properly handle HP-UX, say "can't find /dev/dlpi PPA for XXX" rather than "can't find PPA for XXX"). */ if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0) libpcap_warn = "\n\n" - "You are running Ethereal with a version of the libpcap library\n" + "You are running (T)Ethereal with a version of the libpcap library\n" "that doesn't handle HP-UX network devices well; this means that\n" - "Ethereal may not be able to capture packets.\n" + "(T)Ethereal may not be able to capture packets.\n" "\n" "To fix this, you should install libpcap 0.6.2, or a later version\n" "of libpcap, rather than libpcap 0.4 or 0.5.x. It is available in\n" @@ -666,6 +618,7 @@ static int capture_loop_open_input(capture_options *capture_opts, loop_data *ld, #endif } +/* XXX - will this work for tethereal? */ #ifdef MUST_DO_SELECT if (!ld->from_cap_pipe) { #ifdef HAVE_PCAP_GET_SELECTABLE_FD @@ -678,8 +631,11 @@ static int capture_loop_open_input(capture_options *capture_opts, loop_data *ld, /* Does "open_err_str" contain a non-empty string? If so, "pcap_open_live()" returned a warning; print it, but keep capturing. */ - if (open_err_str[0] != '\0') - g_warning("%s.", open_err_str); + if (open_err_str[0] != '\0') { + sync_msg_str = g_strdup_printf("%s.", open_err_str); + sync_pipe_errmsg_to_parent(sync_msg_str); + g_free(sync_msg_str); + } return TRUE; } @@ -712,7 +668,7 @@ static void capture_loop_close_input(loop_data *ld) { /* init the capture filter */ -static int capture_loop_init_filter(loop_data *ld, const gchar * iface, gchar * cfilter, char *errmsg, int errmsg_len) { +gboolean capture_loop_init_filter(pcap_t *pcap_h, gboolean from_cap_pipe, const gchar * iface, gchar * cfilter, char *errmsg, int errmsg_len) { bpf_u_int32 netnum, netmask; gchar lookup_net_err_str[PCAP_ERRBUF_SIZE]; struct bpf_program fcode; @@ -721,7 +677,7 @@ static int capture_loop_init_filter(loop_data *ld, const gchar * iface, gchar * g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_init_filter: %s", cfilter); /* capture filters only work on real interfaces */ - if (cfilter && !ld->from_cap_pipe) { + if (cfilter && !from_cap_pipe) { /* A capture filter was specified; set it up. */ if (pcap_lookupnet(iface, &netnum, &netmask, lookup_net_err_str) < 0) { /* @@ -733,13 +689,15 @@ static int capture_loop_init_filter(loop_data *ld, const gchar * iface, gchar * * a difference (only filters that check for IP broadcast addresses * use the netmask). */ + /*cmdarg_err( + "Warning: Couldn't obtain netmask info (%s).", lookup_net_err_str);*/ netmask = 0; } - if (pcap_compile(ld->pcap_h, &fcode, cfilter, 1, 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(ld->pcap_h)); + pcap_geterr(pcap_h)); /* filter string invalid, did the user tried a display filter? */ #ifndef DUMPCAP @@ -753,7 +711,7 @@ static int capture_loop_init_filter(loop_data *ld, const gchar * iface, gchar * "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 help for a description of the capture filter syntax.", + "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); @@ -764,7 +722,7 @@ static int capture_loop_init_filter(loop_data *ld, const gchar * iface, gchar * "%sInvalid capture filter: \"%s\"!%s\n" "\n" "That string isn't a valid capture filter (%s).\n" - "See the help for a description of the capture filter syntax.", + "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); } @@ -772,9 +730,9 @@ static int capture_loop_init_filter(loop_data *ld, const gchar * iface, gchar * g_free(safe_cfilter); return FALSE; } - if (pcap_setfilter(ld->pcap_h, &fcode) < 0) { + if (pcap_setfilter(pcap_h, &fcode) < 0) { g_snprintf(errmsg, errmsg_len, "Can't install filter (%s).", - pcap_geterr(ld->pcap_h)); + pcap_geterr(pcap_h)); #ifdef HAVE_PCAP_FREECODE pcap_freecode(&fcode); #endif @@ -790,7 +748,7 @@ static int capture_loop_init_filter(loop_data *ld, const gchar * iface, gchar * /* open the wiretap part of the capture output file */ -static int capture_loop_init_wiretap_output(capture_options *capture_opts, int save_file_fd, loop_data *ld, char *errmsg, int errmsg_len) { +gboolean capture_loop_init_wiretap_output(capture_options *capture_opts, int save_file_fd, loop_data *ld, char *errmsg, int errmsg_len) { int pcap_encap; int file_snaplen; int err; @@ -815,7 +773,7 @@ static int capture_loop_init_wiretap_output(capture_options *capture_opts, int s if (ld->wtap_linktype == WTAP_ENCAP_UNKNOWN) { g_snprintf(errmsg, errmsg_len, "The network you're capturing from is of a type" - " that Ethereal doesn't support (data link type %d).", pcap_encap); + " that (T)Ethereal doesn't support (data link type %d).", pcap_encap); return FALSE; } if (capture_opts->multi_files_on) { @@ -828,6 +786,7 @@ static int capture_loop_init_wiretap_output(capture_options *capture_opts, int s if (ld->wtap_pdh == NULL) { /* We couldn't set up to write to the capture file. */ + /* XXX - use cf_open_error_message from tethereal instead? */ switch (err) { case WTAP_ERR_CANT_OPEN: @@ -861,7 +820,7 @@ static int capture_loop_init_wiretap_output(capture_options *capture_opts, int s return TRUE; } -static gboolean capture_loop_close_output(capture_options *capture_opts, loop_data *ld, int *err_close) { +gboolean capture_loop_close_output(capture_options *capture_opts, loop_data *ld, int *err_close) { g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_close_output"); @@ -970,7 +929,7 @@ capture_loop_dispatch(capture_options *capture_opts, loop_data *ld, * "select()" says we can read from it without blocking; go for * it. */ - inpkts = pcap_dispatch(ld->pcap_h, 1, capture_loop_packet_cb, (u_char *)ld); + inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *)ld); if (inpkts < 0) { ld->pcap_err = TRUE; ld->go = FALSE; @@ -993,7 +952,7 @@ capture_loop_dispatch(capture_options *capture_opts, loop_data *ld, #ifdef LOG_CAPTURE_VERBOSE g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_dispatch: from pcap_dispatch"); #endif - inpkts = pcap_dispatch(ld->pcap_h, 1, capture_loop_packet_cb, (u_char *) ld); + inpkts = pcap_dispatch(ld->pcap_h, 1, ld->packet_cb, (u_char *) ld); if (inpkts < 0) { ld->pcap_err = TRUE; ld->go = FALSE; @@ -1015,7 +974,7 @@ capture_loop_dispatch(capture_options *capture_opts, loop_data *ld, inpkts = 0; while( (in = pcap_next_ex(ld->pcap_h, &pkt_header, &pkt_data)) == 1) { - capture_loop_packet_cb( (u_char *) ld, pkt_header, pkt_data); + ld->packet_cb( (u_char *) ld, pkt_header, pkt_data); inpkts++; } @@ -1039,7 +998,7 @@ capture_loop_dispatch(capture_options *capture_opts, loop_data *ld, /* open the output file (temporary/specified name/ringbuffer) */ /* Returns TRUE if the file opened successfully, FALSE otherwise. */ -static gboolean +gboolean capture_loop_open_output(capture_options *capture_opts, int *save_file_fd, char *errmsg, int errmsg_len) { @@ -1141,22 +1100,16 @@ signal_pipe_stopped(void) /*g_warning("check pipe: handle: %x result: %u avail: %u", handle, result, avail);*/ if(!result || avail > 0) { - /* XXX - doesn't work with dumpcap as a command line tool */ - /* as we have no input pipe, need to find a way to circumvent this */ + /* peek failed or some bytes really available */ return TRUE; + } else { + /* pipe ok and no bytes available */ + return FALSE; } - - return FALSE; } #endif -/* - * This needs to be static, so that the SIGUSR1 handler can clear the "go" - * flag. - */ -static loop_data ld; - /* Do the low-level work of a capture. Returns TRUE if it succeeds, FALSE otherwise. */ int @@ -1164,7 +1117,9 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct { time_t upd_time, cur_time; time_t start_time; - int err_close, inpkts; + int err_close; + int inpkts; + gint inpkts_to_sync_pipe = 0; /* packets not already send out to the sync_pipe */ condition *cnd_file_duration = NULL; condition *cnd_autostop_files = NULL; condition *cnd_autostop_size = NULL; @@ -1181,16 +1136,15 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct /* init the loop data */ ld.go = TRUE; - ld.packets_curr = 0; + ld.packet_count = 0; if (capture_opts->has_autostop_packets) - ld.packets_max = capture_opts->autostop_packets; + ld.packet_max = capture_opts->autostop_packets; else - ld.packets_max = 0; /* no limit */ + ld.packet_max = 0; /* no limit */ ld.err = 0; /* no error seen yet */ ld.wtap_linktype = WTAP_ENCAP_UNKNOWN; ld.pcap_err = FALSE; ld.from_cap_pipe = FALSE; - ld.packets_sync_pipe = 0; ld.wtap_pdh = NULL; #ifndef _WIN32 ld.cap_pipe_fd = -1; @@ -1198,6 +1152,8 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct #ifdef MUST_DO_SELECT ld.pcap_fd = 0; #endif + ld.packet_cb = capture_loop_packet_cb; + /* We haven't yet gotten the capture statistics. */ *stats_known = FALSE; @@ -1228,7 +1184,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct } /* init the input filter from the network interface (capture pipe will do nothing) */ - if (!capture_loop_init_filter(&ld, capture_opts->iface, capture_opts->cfilter, errmsg, sizeof(errmsg))) { + if (!capture_loop_init_filter(ld.pcap_h, ld.from_cap_pipe, capture_opts->iface, capture_opts->cfilter, errmsg, sizeof(errmsg))) { goto error; } @@ -1293,7 +1249,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct #endif if (inpkts > 0) { - ld.packets_sync_pipe += inpkts; + inpkts_to_sync_pipe += inpkts; /* check capture size condition */ if (cnd_autostop_size != NULL && cnd_eval(cnd_autostop_size, @@ -1315,7 +1271,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct } wtap_dump_flush(ld.wtap_pdh); sync_pipe_filename_to_parent(capture_opts->save_file); - ld.packets_sync_pipe = 0; + inpkts_to_sync_pipe = 0; } else { /* File switch failed: stop here */ ld.go = FALSE; @@ -1343,15 +1299,15 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct }*/ /* Let the parent process know. */ - if (ld.packets_sync_pipe) { + if (inpkts_to_sync_pipe) { /* do sync here */ wtap_dump_flush(ld.wtap_pdh); - /* Send our parent a message saying we've written out "ld.sync_packets" + /* Send our parent a message saying we've written out "inpkts_to_sync_pipe" packets to the capture file. */ - sync_pipe_packet_count_to_parent(ld.packets_sync_pipe); + sync_pipe_packet_count_to_parent(inpkts_to_sync_pipe); - ld.packets_sync_pipe = 0; + inpkts_to_sync_pipe = 0; } /* check capture duration condition */ @@ -1379,7 +1335,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct cnd_reset(cnd_autostop_size); wtap_dump_flush(ld.wtap_pdh); sync_pipe_filename_to_parent(capture_opts->save_file); - ld.packets_sync_pipe = 0; + inpkts_to_sync_pipe = 0; } else { /* File switch failed: stop here */ ld.go = FALSE; @@ -1575,8 +1531,8 @@ capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr, int err; /* if the user told us to stop after x packets, do we have enough? */ - ld->packets_curr++; - if ((ld->packets_max > 0) && (ld->packets_curr >= ld->packets_max)) + ld->packet_count++; + if ((ld->packet_max > 0) && (ld->packet_count >= ld->packet_max)) { ld->go = FALSE; } diff --git a/capture_loop.h b/capture_loop.h index 1a89d90f5a..4336927c4c 100644 --- a/capture_loop.h +++ b/capture_loop.h @@ -40,4 +40,114 @@ extern int capture_loop_start(capture_options *capture_opts, gboolean *stats_kn extern void capture_loop_stop(void); +/*** the following is internal only (should be moved to capture_loop_int.h) ***/ + + +/* + * We don't want to do a "select()" on the pcap_t's file descriptor on + * BSD (because "select()" doesn't work correctly on BPF devices on at + * least some releases of some flavors of BSD), and we don't want to do + * it on Windows (because "select()" is something for sockets, not for + * arbitrary handles). (Note that "Windows" here includes Cygwin; + * even in its pretend-it's-UNIX environment, we're using WinPcap, not + * a UNIX libpcap.) + * + * We *do* want to do it on other platforms, as, on other platforms (with + * the possible exception of Ultrix and Digital UNIX), the read timeout + * doesn't expire if no packets have arrived, so a "pcap_dispatch()" call + * will block until packets arrive, causing the UI to hang. + * + * XXX - the various BSDs appear to define BSD in ; we don't + * want to include it if it's not present on this platform, however. + */ +#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && \ + !defined(__bsdi__) && !defined(__APPLE__) && !defined(_WIN32) && \ + !defined(__CYGWIN__) +# define MUST_DO_SELECT +#endif + +typedef void (*capture_packet_cb_fct)(u_char *, const struct pcap_pkthdr *, const u_char *); + + +/* moved from capture_loop.c here, so we can combine it (and the related functions) with tethereal */ +/* XXX - should be moved back to capture_loop.c */ +/* E: capture_loop.c only (Ethereal/dumpcap) T: tethereal only */ +typedef struct _loop_data { + /* common */ + gboolean go; /* TRUE as long as we're supposed to keep capturing */ + int err; /* E: if non-zero, error seen while capturing */ + gint packet_count; /* Number of packets we have already captured */ + gint packet_max; /* E: Number of packets we're supposed to capture - 0 means infinite */ + + jmp_buf stopenv; /* T: starting point of loop (jump back this point on SIG...) */ + + char *save_file; /* T: Name of file to which we're writing */ + gboolean output_to_pipe; /* T: output to a pipe, flush outut file immediately */ + capture_packet_cb_fct packet_cb; /* callback for a single captured packet */ + + /* pcap "input file" */ + pcap_t *pcap_h; /* pcap handle */ + gboolean pcap_err; /* E: TRUE if error from pcap */ +#ifdef MUST_DO_SELECT + int pcap_fd; /* pcap file descriptor */ +#endif + + /* capture pipe (unix only "input file") */ + gboolean from_cap_pipe; /* TRUE if we are capturing data from a capture pipe */ +#ifndef _WIN32 + struct pcap_hdr cap_pipe_hdr; /* ? */ + struct pcaprec_modified_hdr cap_pipe_rechdr; /* ? */ + int cap_pipe_fd; /* the file descriptor of the capture pipe */ + gboolean cap_pipe_modified; /* TRUE if data in the pipe uses modified pcap headers */ + gboolean cap_pipe_byte_swapped; /* TRUE if data in the pipe is byte swapped */ + unsigned int cap_pipe_bytes_to_read;/* Used by cap_pipe_dispatch */ + unsigned int cap_pipe_bytes_read; /* Used by cap_pipe_dispatch */ + enum { + STATE_EXPECT_REC_HDR, + STATE_READ_REC_HDR, + STATE_EXPECT_DATA, + STATE_READ_DATA + } cap_pipe_state; + enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } cap_pipe_err; +#endif + + /* wiretap (output file) */ + wtap_dumper *wtap_pdh; + gint wtap_linktype; + +} 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); + +/** Take care of byte order in the libpcap headers read from pipes. */ +extern void +cap_pipe_adjust_header(gboolean byte_swapped, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr); + +#ifdef HAVE_LIBPCAP +#ifndef _WIN32 +extern int +cap_pipe_open_live(char *, struct pcap_hdr *, loop_data *, char *, int); + +extern int +cap_pipe_dispatch(int, loop_data *, struct pcap_hdr *, \ + struct pcaprec_modified_hdr *, guchar *, char *, int); +#endif /* _WIN32 */ +#endif + +extern gboolean +capture_loop_open_input(capture_options *capture_opts, loop_data *ld, char *errmsg, int errmsg_len); + +extern gboolean +capture_loop_open_output(capture_options *capture_opts, int *save_file_fd, char *errmsg, int errmsg_len); + +extern gboolean +capture_loop_init_wiretap_output(capture_options *capture_opts, int save_file_fd, loop_data *ld, char *errmsg, int errmsg_len); + +extern gboolean +capture_loop_close_output(capture_options *capture_opts, loop_data *ld, int *err_close); + #endif /* capture_loop.h */ diff --git a/capture_opts.c b/capture_opts.c index 85b175ee23..b108b59e5a 100644 --- a/capture_opts.c +++ b/capture_opts.c @@ -43,6 +43,11 @@ #include "clopts_common.h" #include "cmdarg_err.h" +#include "capture-pcap-util.h" +#include "capture_ui_utils.h" + + + void capture_opts_init(capture_options *capture_opts, void *cfile) { @@ -282,6 +287,70 @@ get_pipe_arguments(capture_options *capture_opts, const char *arg) #endif +void +capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg) +{ + long adapter_index; + char *p; + GList *if_list; + if_info_t *if_info; + int err; + gchar err_str[PCAP_ERRBUF_SIZE]; + gchar *cant_get_if_list_errstr; + + + /* + * If the argument is a number, treat it as an index into the list + * of adapters, as printed by "tethereal -D". + * + * This should be OK on UNIX systems, as interfaces shouldn't have + * names that begin with digits. It can be useful on Windows, where + * more than one interface can have the same name. + */ + adapter_index = strtol(optarg, &p, 10); + if (p != NULL && *p == '\0') { + if (adapter_index < 0) { + cmdarg_err("The specified adapter index is a negative number"); + exit(1); + } + if (adapter_index > INT_MAX) { + cmdarg_err("The specified adapter index is too large (greater than %d)", + INT_MAX); + exit(1); + } + if (adapter_index == 0) { + cmdarg_err("there is no interface with that adapter index"); + exit(1); + } + if_list = get_interface_list(&err, err_str); + if (if_list == NULL) { + switch (err) { + + case CANT_GET_INTERFACE_LIST: + cant_get_if_list_errstr = + cant_get_if_list_error_message(err_str); + cmdarg_err("%s", cant_get_if_list_errstr); + g_free(cant_get_if_list_errstr); + break; + + case NO_INTERFACES_FOUND: + cmdarg_err("There are no interfaces on which a capture can be done"); + break; + } + exit(2); + } + if_info = g_list_nth_data(if_list, adapter_index - 1); + if (if_info == NULL) { + cmdarg_err("there is no interface with that adapter index"); + exit(1); + } + capture_opts->iface = g_strdup(if_info->name); + free_interface_list(if_list); + } else { + capture_opts->iface = g_strdup(optarg); + } +} + void capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg, gboolean *start_capture) { @@ -317,7 +386,7 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg, capture_opts->show_info = FALSE; break; case 'i': /* Use interface xxx */ - capture_opts->iface = g_strdup(optarg); + capture_opts_add_iface_opt(capture_opts, optarg); break; case 'k': /* Start capture immediately */ *start_capture = TRUE; @@ -369,13 +438,89 @@ capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg, } -void capture_opts_trim(capture_options *capture_opts, int snaplen_min) +void capture_opts_list_link_layer_types(capture_options *capture_opts) +{ + gchar err_str[PCAP_ERRBUF_SIZE]; + GList *lt_list, *lt_entry; + data_link_info_t *data_link_info; + + /* Get the list of link-layer types for the capture device. */ + lt_list = get_pcap_linktype_list(capture_opts->iface, err_str); + if (lt_list == NULL) { + if (err_str[0] != '\0') { + cmdarg_err("The list of data link types for the capture device could not be obtained (%s)." + "Please check to make sure you have sufficient permissions, and that\n" + "you have the proper interface or pipe specified.\n", err_str); + } else + cmdarg_err("The capture device has no data link types."); + exit(2); + } + cmdarg_err_cont("Data link types (use option -y to set):"); + for (lt_entry = lt_list; lt_entry != NULL; + lt_entry = g_list_next(lt_entry)) { + data_link_info = lt_entry->data; + cmdarg_err_cont(" %s", data_link_info->name); + if (data_link_info->description != NULL) + cmdarg_err_cont(" (%s)", data_link_info->description); + else + cmdarg_err_cont(" (not supported)"); + putchar('\n'); + } + free_pcap_linktype_list(lt_list); +} + + +void capture_opts_list_interfaces() +{ + GList *if_list; + GList *if_entry; + if_info_t *if_info; + int err; + gchar err_str[PCAP_ERRBUF_SIZE]; + gchar *cant_get_if_list_errstr; + int i; + + + if_list = get_interface_list(&err, err_str); + if (if_list == NULL) { + switch (err) { + case CANT_GET_INTERFACE_LIST: + cant_get_if_list_errstr = cant_get_if_list_error_message(err_str); + cmdarg_err("%s", cant_get_if_list_errstr); + g_free(cant_get_if_list_errstr); + break; + + case NO_INTERFACES_FOUND: + cmdarg_err("There are no interfaces on which a capture can be done"); + break; + } + exit(2); + } + + i = 1; /* Interface id number */ + for (if_entry = g_list_first(if_list); if_entry != NULL; + if_entry = g_list_next(if_entry)) { + if_info = if_entry->data; + printf("%d. %s", i++, if_info->name); + if (if_info->description != NULL) + printf(" (%s)", if_info->description); + printf("\n"); + } + free_interface_list(if_list); +} + + +void capture_opts_trim_snaplen(capture_options *capture_opts, int snaplen_min) { if (capture_opts->snaplen < 1) capture_opts->snaplen = WTAP_MAX_PACKET_SIZE; else if (capture_opts->snaplen < snaplen_min) capture_opts->snaplen = snaplen_min; +} + +void capture_opts_trim_ring_num_files(capture_options *capture_opts) +{ /* Check the value range of the ring_num_files parameter */ if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES) capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES; @@ -385,4 +530,48 @@ void capture_opts_trim(capture_options *capture_opts, int snaplen_min) #endif } + +gboolean capture_opts_trim_iface(capture_options *capture_opts, const char *capture_device) +{ + GList *if_list; + if_info_t *if_info; + int err; + gchar err_str[PCAP_ERRBUF_SIZE]; + gchar *cant_get_if_list_errstr; + + + /* Did the user specify an interface to use? */ + if (capture_opts->iface == NULL) { + /* No - is a default specified in the preferences file? */ + if (capture_device != NULL) { + /* Yes - use it. */ + capture_opts->iface = g_strdup(capture_device); + } else { + /* No - pick the first one from the list of interfaces. */ + if_list = get_interface_list(&err, err_str); + if (if_list == NULL) { + switch (err) { + + case CANT_GET_INTERFACE_LIST: + cant_get_if_list_errstr = cant_get_if_list_error_message(err_str); + cmdarg_err("%s", cant_get_if_list_errstr); + g_free(cant_get_if_list_errstr); + break; + + case NO_INTERFACES_FOUND: + cmdarg_err("There are no interfaces on which a capture can be done"); + break; + } + return FALSE; + } + if_info = if_list->data; /* first interface */ + capture_opts->iface = g_strdup(if_info->name); + free_interface_list(if_list); + } + } + + return TRUE; +} + + #endif /* HAVE_LIBPCAP */ diff --git a/capture_opts.h b/capture_opts.h index e75535afd1..193866d583 100644 --- a/capture_opts.h +++ b/capture_opts.h @@ -105,13 +105,28 @@ capture_opts_init(capture_options *capture_opts, void *cfile); extern void capture_opts_add_opt(capture_options *capture_opts, int opt, const char *optarg, gboolean *start_capture); -/* trim values after command line finished */ -extern void -capture_opts_trim(capture_options *capture_opts, int snaplen_min); - /* log content of capture_opts */ extern void capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_options *capture_opts); +/* list link layer types */ +extern void +capture_opts_list_link_layer_types(capture_options *capture_opts); + +/* list interfaces */ +extern void +capture_opts_list_interfaces(); + +/* trim the snaplen entry */ +extern void +capture_opts_trim_snaplen(capture_options *capture_opts, int snaplen_min); + +/* trim the ring_num_files entry */ +extern void +capture_opts_trim_ring_num_files(capture_options *capture_opts); + +/* trim the interface entry */ +extern gboolean +capture_opts_trim_iface(capture_options *capture_opts, const char *capture_device); #endif /* capture_opts.h */ diff --git a/dumpcap.c b/dumpcap.c index 1a764a514f..8cc0c13e7d 100644 --- a/dumpcap.c +++ b/dumpcap.c @@ -74,7 +74,7 @@ GString *comp_info_str, *runtime_info_str; gchar *ethereal_path = NULL; #ifdef _WIN32 -static gboolean has_console = TRUE; /* TRUE if app has console */ +static gboolean has_console = TRUE; /* TRUE if app has console */ static void create_console(void); static void destroy_console(void); #endif @@ -109,7 +109,7 @@ print_usage(gboolean print_ver) { fprintf(output, "\nUsage: dumpcap [option] ...\n"); fprintf(output, "\n"); fprintf(output, "Capture interface:\n"); - fprintf(output, " -i name of interface (def: first none loopback)\n"); + fprintf(output, " -i name or idx of interface (def: first none loopback)\n"); fprintf(output, " -f packet filter in libpcap format\n"); fprintf(output, " -s packet snapshot length (def: 65535)\n"); fprintf(output, " -p don't capture in promiscuous mode\n"); @@ -133,6 +133,7 @@ print_usage(gboolean print_ver) { fprintf(output, "Miscellaneous:\n"); fprintf(output, " -v print version information and exit\n"); fprintf(output, " -h display this help and exit\n"); + fprintf(output, " -D print list of interfaces and exit\n"); fprintf(output, " -L print list of link-layer types of iface and exit\n"); fprintf(output, "\n"); fprintf(output, "Example: dumpcap -i eth0 -a duration:60 -w output.pcap\n"); @@ -241,8 +242,6 @@ main(int argc, char *argv[]) gboolean start_capture = TRUE; GList *if_list; if_info_t *if_info; - GList *lt_list, *lt_entry; - data_link_info_t *data_link_info; gchar err_str[PCAP_ERRBUF_SIZE]; gchar *cant_get_if_list_errstr; gboolean stats_known; @@ -250,7 +249,7 @@ main(int argc, char *argv[]) GLogLevelFlags log_flags; gboolean list_link_layer_types = FALSE; -#define OPTSTRING_INIT "a:b:c:f:Hhi:Lps:vW:w:y:" +#define OPTSTRING_INIT "a:b:c:Df:hi:Lps:vw:y:" #ifdef _WIN32 #define OPTSTRING_WIN32 "B:Z:" @@ -345,7 +344,6 @@ main(int argc, char *argv[]) case 'b': /* Ringbuffer option */ case 'c': /* Capture xxx packets */ case 'f': /* capture filter */ - case 'H': /* Hide capture info dialog box */ case 'i': /* Use interface xxx */ case 'p': /* Don't capture in promiscuous mode */ case 's': /* Set the snapshot (capture) length */ @@ -358,14 +356,12 @@ main(int argc, char *argv[]) #endif /* _WIN32 */ capture_opts_add_opt(capture_opts, opt, optarg, &start_capture); break; - /* This is a hidden option supporting Sync mode, so we don't set - * the error flags for the user in the non-libpcap case. - */ - case 'W': /* Write to capture file FD xxx */ - capture_opts_add_opt(capture_opts, opt, optarg, &start_capture); - break; /*** all non capture option specific ***/ + case 'D': /* Print a list of capture devices and exit */ + capture_opts_list_interfaces(); + exit(0); + break; case 'L': /* Print list of link-layer types and exit */ list_link_layer_types = TRUE; break; @@ -450,33 +446,12 @@ if (capture_opts->iface == NULL) { } if (list_link_layer_types) { - /* Get the list of link-layer types for the capture device. */ - lt_list = get_pcap_linktype_list(capture_opts->iface, err_str); - if (lt_list == NULL) { - if (err_str[0] != '\0') { - cmdarg_err("The list of data link types for the capture device could not be obtained (%s)." - "Please check to make sure you have sufficient permissions, and that\n" - "you have the proper interface or pipe specified.\n", err_str); - } else - cmdarg_err("The capture device has no data link types."); - exit_main(2); - } - g_warning("Data link types (use option -y to set):"); - for (lt_entry = lt_list; lt_entry != NULL; - lt_entry = g_list_next(lt_entry)) { - data_link_info = lt_entry->data; - g_warning(" %s", data_link_info->name); - if (data_link_info->description != NULL) - g_warning(" (%s)", data_link_info->description); - else - g_warning(" (not supported)"); - putchar('\n'); - } - free_pcap_linktype_list(lt_list); + capture_opts_list_link_layer_types(capture_opts); exit_main(0); } - capture_opts_trim(capture_opts, MIN_PACKET_SIZE); + capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE); + capture_opts_trim_ring_num_files(capture_opts); /* Now start the capture. */ @@ -547,8 +522,9 @@ static void destroy_console(void) { if (has_console) { - printf("\n\nPress any key to exit\n"); - _getch(); +/* XXX - doesn't make sense while we're linked as a console application */ +/* printf("\n\nPress any key to exit\n"); + _getch();*/ FreeConsole(); } } @@ -637,6 +613,9 @@ pipe_write_block(int pipe, char indicator, int len, const char *msg) { } + +int count = 0; + void sync_pipe_packet_count_to_parent(int packet_count) { @@ -646,6 +625,9 @@ sync_pipe_packet_count_to_parent(int packet_count) /*g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_packet_count_to_parent: %s", tmp);*/ + count += packet_count; + fprintf(stderr, "\rpackets: %u", count); + pipe_write_block(1, SP_PACKET_COUNT, strlen(tmp)+1, tmp); } @@ -684,14 +666,6 @@ sync_pipe_drops_to_parent(int drops) /* simple_dialog "dummies" */ -static gpointer * -display_simple_dialog(gint type, gint btn_mask, char *message) -{ - printf("%s", message); - - return NULL; -} - char *simple_dialog_primary_start(void) { return ""; @@ -702,56 +676,6 @@ char *simple_dialog_primary_end(void) return ""; } -/* Simple dialog function - Displays a dialog box with the supplied message - * text. - * - * Args: - * type : One of ESD_TYPE_*. - * btn_mask : The value passed in determines which buttons are displayed. - * msg_format : Sprintf-style format of the text displayed in the dialog. - * ... : Argument list for msg_format - */ - -gpointer -vsimple_dialog(ESD_TYPE_E type, gint btn_mask, const gchar *msg_format, va_list ap) -{ - gchar *vmessage; - gchar *message; - gpointer *win; -#if GTK_MAJOR_VERSION >= 2 - GdkWindowState state = 0; -#endif - - /* Format the message. */ - vmessage = g_strdup_vprintf(msg_format, ap); - -#if GTK_MAJOR_VERSION >= 2 - /* convert character encoding from locale to UTF8 (using iconv) */ - message = g_locale_to_utf8(vmessage, -1, NULL, NULL, NULL); - g_free(vmessage); -#else - message = vmessage; -#endif - - win = display_simple_dialog(type, btn_mask, message); - - g_free(message); - - return win; -} - -gpointer -simple_dialog(ESD_TYPE_E type, gint btn_mask, const gchar *msg_format, ...) -{ - va_list ap; - gpointer ret; - - va_start(ap, msg_format); - ret = vsimple_dialog(type, btn_mask, msg_format, ap); - va_end(ap); - return ret; -} - char * simple_dialog_format_message(const char *msg) { diff --git a/gtk/main.c b/gtk/main.c index e39144ab28..d075d5373d 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1089,7 +1089,7 @@ print_usage(gboolean print_ver) { output = stderr; } #ifdef HAVE_LIBPCAP - fprintf(output, "\n%s [ -vh ] [ -klLnpQS ] [ -a ] ...\n", PACKAGE); + fprintf(output, "\n%s [ -vh ] [ -DklLnpQS ] [ -a ] ...\n", PACKAGE); fprintf(output, "\t[ -b ] ...\n"); #ifdef _WIN32 fprintf(output, "\t[ -B ]\n"); @@ -1742,12 +1742,6 @@ main(int argc, char *argv[]) int err; #ifdef HAVE_LIBPCAP gboolean start_capture = FALSE; - GList *if_list; - if_info_t *if_info; - GList *lt_list, *lt_entry; - data_link_info_t *data_link_info; - gchar err_str[PCAP_ERRBUF_SIZE]; - gchar *cant_get_if_list_errstr; gboolean stats_known; struct pcap_stat stats; #else @@ -1764,14 +1758,14 @@ main(int argc, char *argv[]) guint go_to_packet = 0; int optind_initial; -#define OPTSTRING_INIT "a:b:c:f:g:Hhi:klLm:nN:o:pQr:R:Ss:t:vw:y:z:" +#define OPTSTRING_INIT "a:b:c:Df:g:Hhi:klLm:nN:o:pQr:R:Ss:t:vw:y:z:" #ifdef HAVE_LIBPCAP #ifdef _WIN32 -#define OPTSTRING_CHILD "W:Z:" +#define OPTSTRING_CHILD "Z:" #define OPTSTRING_WIN32 "B:" #else -#define OPTSTRING_CHILD "W:" +#define OPTSTRING_CHILD "" #define OPTSTRING_WIN32 "" #endif /* _WIN32 */ #else @@ -1958,7 +1952,7 @@ main(int argc, char *argv[]) #endif splash_win = splash_new("Loading Ethereal ..."); - splash_update(splash_win, "Registering dissectors ..."); + splash_update(splash_win, "Init dissectors ..."); /* Register all dissectors; we must do this before checking for the "-G" flag, as the "-G" flag dumps information registered by the @@ -1967,7 +1961,7 @@ main(int argc, char *argv[]) epan_init(PLUGIN_DIR,register_all_protocols,register_all_protocol_handoffs, failure_alert_box,open_failure_alert_box,read_failure_alert_box); - splash_update(splash_win, "Registering tap listeners ..."); + splash_update(splash_win, "Init tap listeners ..."); /* Register all tap listeners; we do this before we parse the arguments, as the "-z" argument can specify a registered tap. */ @@ -2152,16 +2146,17 @@ main(int argc, char *argv[]) arg_error = TRUE; #endif break; -#ifdef HAVE_LIBPCAP - /* This is a hidden option supporting Sync mode, so we don't set - * the error flags for the user in the non-libpcap case. - */ - case 'W': /* Write to capture file FD xxx */ - capture_opts_add_opt(capture_opts, opt, optarg, &start_capture); - break; -#endif /*** all non capture option specific ***/ + case 'D': /* Print a list of capture devices and exit */ +#ifdef HAVE_LIBPCAP + capture_opts_list_interfaces(); + exit(0); +#else + capture_option_specified = TRUE; + arg_error = TRUE; +#endif + break; case 'g': /* Go to packet */ go_to_packet = get_positive_int(optarg, "go to packet"); break; @@ -2383,64 +2378,19 @@ main(int argc, char *argv[]) if (start_capture || list_link_layer_types) { /* Did the user specify an interface to use? */ - if (capture_opts->iface == NULL) { - /* No - is a default specified in the preferences file? */ - if (prefs->capture_device != NULL) { - /* Yes - use it. */ - capture_opts->iface = g_strdup(get_if_name(prefs->capture_device)); - } else { - /* No - pick the first one from the list of interfaces. */ - if_list = get_interface_list(&err, err_str); - if (if_list == NULL) { - switch (err) { - - case CANT_GET_INTERFACE_LIST: - cant_get_if_list_errstr = cant_get_if_list_error_message(err_str); - cmdarg_err("%s", cant_get_if_list_errstr); - g_free(cant_get_if_list_errstr); - break; - - case NO_INTERFACES_FOUND: - cmdarg_err("There are no interfaces on which a capture can be done"); - break; - } - exit(2); - } - if_info = if_list->data; /* first interface */ - capture_opts->iface = g_strdup(if_info->name); - free_interface_list(if_list); - } + if (!capture_opts_trim_iface(capture_opts, + (prefs->capture_device) ? get_if_name(prefs->capture_device) : NULL)) { + exit(2); } } if (list_link_layer_types) { - /* Get the list of link-layer types for the capture device. */ - lt_list = get_pcap_linktype_list(capture_opts->iface, err_str); - if (lt_list == NULL) { - if (err_str[0] != '\0') { - cmdarg_err("The list of data link types for the capture device could not be obtained (%s)." - "Please check to make sure you have sufficient permissions, and that\n" - "you have the proper interface or pipe specified.\n", err_str); - } else - cmdarg_err("The capture device has no data link types."); - exit(2); - } - g_warning("Data link types (use option -y to set):"); - for (lt_entry = lt_list; lt_entry != NULL; - lt_entry = g_list_next(lt_entry)) { - data_link_info = lt_entry->data; - g_warning(" %s", data_link_info->name); - if (data_link_info->description != NULL) - g_warning(" (%s)", data_link_info->description); - else - g_warning(" (not supported)"); - putchar('\n'); - } - free_pcap_linktype_list(lt_list); + capture_opts_list_link_layer_types(capture_opts); exit(0); } - capture_opts_trim(capture_opts, MIN_PACKET_SIZE); + capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE); + capture_opts_trim_ring_num_files(capture_opts); #endif /* HAVE_LIBPCAP */ /* Notify all registered modules that have had any of their preferences diff --git a/tethereal.c b/tethereal.c index 05b8016fed..37571e1ce3 100644 --- a/tethereal.c +++ b/tethereal.c @@ -100,6 +100,7 @@ #include "capture_errs.h" #endif /* _WIN32 */ #include "capture.h" +#include "capture_loop.h" #endif /* HAVE_LIBPCAP */ #include "epan/emem.h" @@ -137,27 +138,6 @@ static print_stream_t *print_stream; */ static gboolean print_packet_counts; -typedef struct _loop_data { - gboolean go; /* TRUE as long as we're supposed to keep capturing */ - gint linktype; - gboolean from_pipe; /* TRUE if we are capturing data from a pipe */ - pcap_t *pch; - char *save_file; /* Name of file to which we're writing */ - wtap_dumper *pdh; - jmp_buf stopenv; - gboolean output_to_pipe; - int packet_count; -#ifndef _WIN32 - gboolean modified; /* TRUE if data in the pipe uses modified pcap headers */ - gboolean byte_swapped; /* TRUE if data in the pipe is byte swapped */ - unsigned int bytes_to_read, bytes_read; /* Used by pipe_dispatch */ - enum { - STATE_EXPECT_REC_HDR, STATE_READ_REC_HDR, - STATE_EXPECT_DATA, STATE_READ_DATA - } pipe_state; - enum { PIPOK, PIPEOF, PIPERR, PIPNEXIST } pipe_err; -#endif -} loop_data; static loop_data ld; @@ -197,14 +177,6 @@ static gboolean print_packet(capture_file *cf, epan_dissect_t *edt); static gboolean write_finale(void); static const char *cf_open_error_message(int err, gchar *err_info, gboolean for_writing, int file_type); -#ifdef HAVE_LIBPCAP -#ifndef _WIN32 -static void adjust_header(loop_data *, struct pcap_hdr *, struct pcaprec_hdr *); -static int pipe_open_live(char *, struct pcap_hdr *, loop_data *, char *, int); -static int pipe_dispatch(int, loop_data *, struct pcap_hdr *, \ - struct pcaprec_modified_hdr *, guchar *, char *, int); -#endif /* _WIN32 */ -#endif static void open_failure_message(const char *filename, int err, gboolean for_writing); @@ -609,6 +581,10 @@ add_decode_as(const gchar *cl_param) return TRUE; } +void log_func_ignore (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) +{ +} + int main(int argc, char *argv[]) { @@ -629,13 +605,8 @@ main(int argc, char *argv[]) int err; #ifdef HAVE_LIBPCAP gboolean capture_filter_specified = FALSE; - GList *if_list, *if_entry; - if_info_t *if_info; - long adapter_index; - char *p; - gchar err_str[PCAP_ERRBUF_SIZE]; - gchar *cant_get_if_list_errstr; gboolean list_link_layer_types = FALSE; + gboolean start_capture = FALSE; #else gboolean capture_option_specified = FALSE; #endif @@ -643,18 +614,13 @@ main(int argc, char *argv[]) gchar *save_file = NULL; int out_file_type = WTAP_FILE_PCAP; gchar *cf_name = NULL, *rfilter = NULL; -#ifdef HAVE_LIBPCAP - gboolean start_capture = FALSE; - gchar *if_text; - GList *lt_list, *lt_entry; - data_link_info_t *data_link_info; -#endif #ifdef HAVE_PCAP_OPEN_DEAD struct bpf_program fcode; #endif dfilter_t *rfcode = NULL; e_prefs *prefs; char badopt; + GLogLevelFlags log_flags; #define OPTSTRING_INIT "a:b:c:d:Df:F:hi:lLnN:o:pqr:R:s:St:T:vVw:xy:z:" #ifdef HAVE_LIBPCAP @@ -669,6 +635,20 @@ main(int argc, char *argv[]) static const char optstring[] = OPTSTRING_INIT OPTSTRING_WIN32; + /* nothing more than the standard GLib handler, but without a warning */ + log_flags = + G_LOG_LEVEL_ERROR| + G_LOG_LEVEL_CRITICAL| + G_LOG_LEVEL_WARNING| + G_LOG_LEVEL_MESSAGE| + G_LOG_LEVEL_INFO| + G_LOG_LEVEL_DEBUG| + G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION; + + g_log_set_handler(NULL, + log_flags, + log_func_ignore, NULL /* user_data */); + /* initialize memory allocation subsystem */ ep_init_chunk(); se_init_chunk(); @@ -826,6 +806,7 @@ main(int argc, char *argv[]) case 'b': /* Ringbuffer option */ case 'c': /* Capture xxx packets */ case 'f': /* capture filter */ + case 'i': /* Use interface xxx */ case 'p': /* Don't capture in promiscuous mode */ case 's': /* Set the snapshot (capture) length */ case 'y': /* Set the pcap data link type */ @@ -843,35 +824,9 @@ main(int argc, char *argv[]) if (!add_decode_as(optarg)) exit(1); break; - case 'D': /* Print a list of capture devices */ + case 'D': /* Print a list of capture devices and exit */ #ifdef HAVE_LIBPCAP - if_list = get_interface_list(&err, err_str); - if (if_list == NULL) { - switch (err) { - - case CANT_GET_INTERFACE_LIST: - cant_get_if_list_errstr = - cant_get_if_list_error_message(err_str); - cmdarg_err("%s", cant_get_if_list_errstr); - g_free(cant_get_if_list_errstr); - break; - - case NO_INTERFACES_FOUND: - cmdarg_err("There are no interfaces on which a capture can be done"); - break; - } - exit(2); - } - i = 1; /* Interface id number */ - for (if_entry = g_list_first(if_list); if_entry != NULL; - if_entry = g_list_next(if_entry)) { - if_info = if_entry->data; - printf("%d. %s", i++, if_info->name); - if (if_info->description != NULL) - printf(" (%s)", if_info->description); - printf("\n"); - } - free_interface_list(if_list); + capture_opts_list_interfaces(); exit(0); #else capture_option_specified = TRUE; @@ -890,62 +845,6 @@ main(int argc, char *argv[]) print_usage(TRUE); exit(0); break; - case 'i': /* Use interface xxx */ -#ifdef HAVE_LIBPCAP - /* - * If the argument is a number, treat it as an index into the list - * of adapters, as printed by "tethereal -D". - * - * This should be OK on UNIX systems, as interfaces shouldn't have - * names that begin with digits. It can be useful on Windows, where - * more than one interface can have the same name. - */ - adapter_index = strtol(optarg, &p, 10); - if (p != NULL && *p == '\0') { - if (adapter_index < 0) { - cmdarg_err("The specified adapter index is a negative number"); - exit(1); - } - if (adapter_index > INT_MAX) { - cmdarg_err("The specified adapter index is too large (greater than %d)", - INT_MAX); - exit(1); - } - if (adapter_index == 0) { - cmdarg_err("there is no interface with that adapter index"); - exit(1); - } - if_list = get_interface_list(&err, err_str); - if (if_list == NULL) { - switch (err) { - - case CANT_GET_INTERFACE_LIST: - cant_get_if_list_errstr = - cant_get_if_list_error_message(err_str); - cmdarg_err("%s", cant_get_if_list_errstr); - g_free(cant_get_if_list_errstr); - break; - - case NO_INTERFACES_FOUND: - cmdarg_err("There are no interfaces on which a capture can be done"); - break; - } - exit(2); - } - if_info = g_list_nth_data(if_list, adapter_index - 1); - if (if_info == NULL) { - cmdarg_err("there is no interface with that adapter index"); - exit(1); - } - capture_opts.iface = g_strdup(if_info->name); - free_interface_list(if_list); - } else - capture_opts.iface = g_strdup(optarg); -#else - capture_option_specified = TRUE; - arg_error = TRUE; -#endif - break; case 'l': /* "Line-buffer" standard output */ /* This isn't line-buffering, strictly speaking, it's just flushing the standard output after the information for @@ -1287,7 +1186,8 @@ main(int argc, char *argv[]) } #ifdef HAVE_LIBPCAP - capture_opts_trim(&capture_opts, MIN_PACKET_SIZE); + capture_opts_trim_snaplen(&capture_opts, MIN_PACKET_SIZE); + capture_opts_trim_ring_num_files(&capture_opts); #endif if (rfilter != NULL) { @@ -1414,64 +1314,16 @@ main(int argc, char *argv[]) } #endif - /* Yes; did the user specify an interface to use? */ - if (capture_opts.iface == NULL) { - /* No - is a default specified in the preferences file? */ - if (prefs->capture_device != NULL) { - /* Yes - use it. */ - if_text = strrchr(prefs->capture_device, ' '); - if (if_text == NULL) { - capture_opts.iface = g_strdup(prefs->capture_device); - } else { - capture_opts.iface = g_strdup(if_text + 1); /* Skip over space */ - } - } else { - /* No - pick the first one from the list of interfaces. */ - if_list = get_interface_list(&err, err_str); - if (if_list == NULL) { - switch (err) { - - case CANT_GET_INTERFACE_LIST: - cant_get_if_list_errstr = cant_get_if_list_error_message(err_str); - cmdarg_err("%s", cant_get_if_list_errstr); - g_free(cant_get_if_list_errstr); - break; - - case NO_INTERFACES_FOUND: - cmdarg_err("There are no interfaces on which a capture can be done"); - break; - } - exit(2); - } - if_info = if_list->data; /* first interface */ - capture_opts.iface = g_strdup(if_info->name); - free_interface_list(if_list); - } + /* trim the interface name and exit if that failed */ + if (!capture_opts_trim_iface(&capture_opts, + (prefs->capture_device) ? get_if_name(prefs->capture_device) : NULL)) { + exit(2); } + /* if requested, list the link layer types and exit */ if (list_link_layer_types) { - /* We were asked to list the link-layer types for an interface. - Get the list of link-layer types for the capture device. */ - lt_list = get_pcap_linktype_list(capture_opts.iface, err_str); - if (lt_list == NULL) { - if (err_str[0] != '\0') { - cmdarg_err("The list of data link types for the capture device could not be obtained (%s).\n" - "Please check to make sure you have sufficient permissions, and that\n" - "you have the proper interface or pipe specified.", err_str); - } else - cmdarg_err("The capture device has no data link types."); - exit(2); - } - cmdarg_err_cont("Data link types (use option -y to set):"); - for (lt_entry = lt_list; lt_entry != NULL; - lt_entry = g_list_next(lt_entry)) { - data_link_info = lt_entry->data; - cmdarg_err_cont(" %s (%s)", - data_link_info->name, - (data_link_info->description != NULL) ? data_link_info->description : "not supported"); - } - free_pcap_linktype_list(lt_list); - exit(0); + capture_opts_list_link_layer_types(&capture_opts); + exit(0); } if (!quiet) { @@ -1507,160 +1359,41 @@ main(int argc, char *argv[]) /* Do the low-level work of a capture. Returns TRUE if it succeeds, FALSE otherwise. */ -static condition *volatile cnd_ring_timeout = NULL; /* this must be visible in process_packet */ +static condition *volatile cnd_file_duration = NULL; /* this must be visible in process_packet */ static int capture(char *save_file, int out_file_type) { - int pcap_encap; - int file_snaplen; - gchar open_err_str[PCAP_ERRBUF_SIZE]; - gchar lookup_net_err_str[PCAP_ERRBUF_SIZE]; - bpf_u_int32 netnum, netmask; - struct bpf_program fcode; - const char *set_linktype_err_str; int err = 0; int volatile volatile_err = 0; int volatile inpkts = 0; int pcap_cnt; char errmsg[1024+1]; - condition *volatile cnd_stop_capturesize = NULL; - condition *volatile cnd_stop_timeout = NULL; + condition *volatile cnd_autostop_size = NULL; + condition *volatile cnd_autostop_duration = NULL; char *descr; #ifndef _WIN32 void (*oldhandler)(int); - static const char ppamsg[] = "can't find PPA for "; - const char *libpcap_warn; - volatile int pipe_fd = -1; - struct pcap_hdr hdr; - struct pcaprec_modified_hdr rechdr; guchar pcap_data[WTAP_MAX_PACKET_SIZE]; #endif struct pcap_stat stats; - gboolean write_err; - gboolean dump_ok; + gboolean write_ok; + gboolean close_ok; dfilter_t *rfcode = NULL; int save_file_fd; /* Initialize all data structures used for dissection. */ init_dissection(); - ld.linktype = WTAP_ENCAP_UNKNOWN; - ld.pdh = NULL; + ld.wtap_linktype = WTAP_ENCAP_UNKNOWN; + ld.wtap_pdh = NULL; + ld.packet_cb = capture_pcap_cb; - /* Open the network interface to capture from it. - Some versions of libpcap may put warnings into the error buffer - if they succeed; to tell if that's happened, we have to clear - the error buffer, and check if it's still a null string. */ - open_err_str[0] = '\0'; - ld.pch = pcap_open_live(capture_opts.iface, capture_opts.snaplen, - capture_opts.promisc_mode, 1000, open_err_str); - if (ld.pch != NULL) { - /* we've opened "iface" as a network device */ -#ifdef _WIN32 - /* try to set the capture buffer size */ - if (pcap_setbuff(ld.pch, capture_opts.buffer_size * 1024 * 1024) != 0) { - cmdarg_err("Couldn't set the capture buffer size!\n" - "\n" - "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.", - capture_opts.buffer_size); - } -#endif - - /* setting the data link type only works on real interfaces */ - if (capture_opts.linktype != -1) { - set_linktype_err_str = set_pcap_linktype(ld.pch, capture_opts.iface, - capture_opts.linktype); - if (set_linktype_err_str != NULL) { - g_snprintf(errmsg, sizeof errmsg, "Unable to set data link type (%s).", - set_linktype_err_str); - goto error; - } - } - } else { - /* We couldn't open "cfile.iface" as a network device. */ -#ifdef _WIN32 - /* On Windows, we don't support capturing on pipes, so we give up. */ - - /* On Win32 OSes, the capture devices are probably available to all - users; don't warn about permissions problems. - - Do, however, warn about the lack of 64-bit support, and warn that - WAN devices aren't supported. */ - g_snprintf(errmsg, sizeof errmsg, -"The capture session could not be initiated!\n" -"\n" -"(%s)\n" -"\n" -"Please check that you have the proper interface specified.\n" -"\n" -"\n" -"Help can be found at:\n" -"\n" -" http://wiki.ethereal.com/CaptureSetup\n" -"\n" -"64-bit Windows:\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" -"Modem (PPP/WAN):\n" -"Note that version 3.0 of WinPcap, and earlier versions of WinPcap, don't\n" -"support capturing on PPP/WAN interfaces on Windows NT 4.0 / 2000 / XP /\n" -"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).", - open_err_str); + /* open the "input file" from network interface or capture pipe */ + if (!capture_loop_open_input(&capture_opts, &ld, errmsg, sizeof(errmsg))) + { goto error; -#else - /* try to open cfile.iface as a pipe */ - pipe_fd = pipe_open_live(capture_opts.iface, &hdr, &ld, errmsg, - sizeof errmsg); - - if (pipe_fd == -1) { - - if (ld.pipe_err == PIPNEXIST) { - /* Pipe doesn't exist, so output message for interface */ - - /* If we got a "can't find PPA for XXX" message, warn the user (who - is running Tethereal on HP-UX) that they don't have a version - of libpcap that properly handles HP-UX (libpcap 0.6.x and later - versions, which properly handle HP-UX, say "can't find /dev/dlpi - PPA for XXX" rather than "can't find PPA for XXX"). */ - if (strncmp(open_err_str, ppamsg, sizeof ppamsg - 1) == 0) - libpcap_warn = - "\n\n" - "You are running Tethereal with a version of the libpcap library\n" - "that doesn't handle HP-UX network devices well; this means that\n" - "Tethereal may not be able to capture packets.\n" - "\n" - "To fix this, you should install libpcap 0.6.2, or a later version\n" - "of libpcap, rather than libpcap 0.4 or 0.5.x. It is available in\n" - "packaged binary form from the Software Porting And Archive Centre\n" - "for HP-UX; the Centre is at http://hpux.connect.org.uk/ - the page\n" - "at the URL lists a number of mirror sites."; - else - libpcap_warn = ""; - g_snprintf(errmsg, sizeof errmsg, - "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); - } - /* - * Else pipe (or file) does exist and pipe_open_live() has - * filled in errmsg - */ - goto error; - } else - /* pipe_open_live() succeeded; don't want - error message from pcap_open_live() */ - open_err_str[0] = '\0'; -#endif } #ifndef _WIN32 @@ -1679,92 +1412,26 @@ capture(char *save_file, int out_file_type) setgid(getgid()); #endif - if (capture_opts.cfilter && !ld.from_pipe) { - /* A capture filter was specified; set it up. */ - if (pcap_lookupnet(capture_opts.iface, &netnum, &netmask, lookup_net_err_str) < 0) { - /* - * Well, we can't get the netmask for this interface; it's used - * only for filters that check for broadcast IP addresses, so - * we just warn the user, and punt and use 0. - */ - cmdarg_err( - "Warning: Couldn't obtain netmask info (%s).", lookup_net_err_str); - netmask = 0; - } - if (pcap_compile(ld.pch, &fcode, capture_opts.cfilter, 1, netmask) < 0) { - if (dfilter_compile(capture_opts.cfilter, &rfcode)) { - g_snprintf(errmsg, sizeof errmsg, - "Unable to parse capture filter string (%s).\n" - " Interestingly enough, this looks like a valid display filter\n" - " Are you sure you didn't mix them up?", - pcap_geterr(ld.pch)); - } else { - g_snprintf(errmsg, sizeof errmsg, - "Unable to parse capture filter string (%s).", - pcap_geterr(ld.pch)); - } - goto error; - } - if (pcap_setfilter(ld.pch, &fcode) < 0) { - g_snprintf(errmsg, sizeof errmsg, "Can't install filter (%s).", - pcap_geterr(ld.pch)); -#ifdef HAVE_PCAP_FREECODE - pcap_freecode(&fcode); -#endif - goto error; - } -#ifdef HAVE_PCAP_FREECODE - pcap_freecode(&fcode); -#endif + capture_opts.save_file = save_file; + + /* open the output file (temporary/specified name/ringbuffer) */ + if (!capture_loop_open_output(&capture_opts, &save_file_fd, errmsg, sizeof(errmsg))) { + goto error; } - /* Set up to write to the capture file. */ -#ifndef _WIN32 - if (ld.from_pipe) { - pcap_encap = hdr.network; - file_snaplen = hdr.snaplen; - } else -#endif + /* 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; + } + + /* open the wiretap part of the output file (the output file is already open) */ + if(!capture_loop_init_wiretap_output(&capture_opts, save_file_fd, &ld, errmsg, sizeof errmsg)) { - pcap_encap = get_pcap_linktype(ld.pch, capture_opts.iface); - file_snaplen = pcap_snapshot(ld.pch); - } - ld.linktype = wtap_pcap_encap_to_wtap_encap(pcap_encap); - if (save_file != NULL) { - /* Set up to write to the capture file. */ - if (ld.linktype == WTAP_ENCAP_UNKNOWN) { - strcpy(errmsg, "The network you're capturing from is of a type" - " that Tethereal doesn't support."); goto error; - } - ld.save_file = save_file; - if (capture_opts.multi_files_on) { - save_file_fd = ringbuf_init(save_file, - capture_opts.ring_num_files); - if (save_file_fd != -1) { - ld.pdh = ringbuf_init_wtap_dump_fdopen(out_file_type, ld.linktype, - file_snaplen, &err); - } else { - err = errno; /* "ringbuf_init()" failed */ - ld.pdh = NULL; - } - } else { - ld.pdh = wtap_dump_open(save_file, out_file_type, - ld.linktype, file_snaplen, FALSE /* compress */, &err); - } - - if (ld.pdh == NULL) { - g_snprintf(errmsg, sizeof errmsg, - cf_open_error_message(err, NULL, TRUE, out_file_type), - *save_file == '\0' ? "stdout" : save_file); - goto error; - } } - /* Does "open_err_str" contain a non-empty string? If so, "pcap_open_live()" - returned a warning; print it, but keep capturing. */ - if (open_err_str[0] != '\0') - cmdarg_err("WARNING: %s.", open_err_str); #ifdef _WIN32 /* Catch a CTRL+C event and, if we get it, clean up and exit. */ @@ -1795,14 +1462,14 @@ capture(char *save_file, int out_file_type) init_capture_stop_conditions(); /* create stop conditions */ if (capture_opts.has_autostop_filesize) - cnd_stop_capturesize = cnd_new((const char*)CND_CLASS_CAPTURESIZE, + cnd_autostop_size = cnd_new((const char*)CND_CLASS_CAPTURESIZE, (long)capture_opts.autostop_filesize * 1024); if (capture_opts.has_autostop_duration) - cnd_stop_timeout = cnd_new((const char*)CND_CLASS_TIMEOUT, + cnd_autostop_duration = cnd_new((const char*)CND_CLASS_TIMEOUT, (gint32)capture_opts.autostop_duration); if (capture_opts.multi_files_on && capture_opts.has_file_duration) - cnd_ring_timeout = cnd_new(CND_CLASS_TIMEOUT, + cnd_file_duration = cnd_new(CND_CLASS_TIMEOUT, capture_opts.file_duration); if (!setjmp(ld.stopenv)) { @@ -1810,6 +1477,7 @@ capture(char *save_file, int out_file_type) ld.packet_count = 0; } else ld.go = FALSE; + while (ld.go) { /* We need to be careful with automatic variables defined in the outer scope which are changed inside the loop. Most compilers @@ -1838,7 +1506,7 @@ capture(char *save_file, int out_file_type) int loop_err = 0; int packet_count_prev = 0; - if (cnd_stop_capturesize == NULL && cnd_stop_timeout == NULL) { + if (cnd_autostop_size == NULL && cnd_autostop_duration == NULL) { /* We're not stopping at a particular capture file size, and we're not stopping after some particular amount of time has expired, so either we have no stop condition or the only stop condition @@ -1870,17 +1538,17 @@ capture(char *save_file, int out_file_type) pcap_cnt = 1; } #ifndef _WIN32 - if (ld.from_pipe) { - inpkts = pipe_dispatch(pipe_fd, &ld, &hdr, &rechdr, pcap_data, + if (ld.from_cap_pipe) { + inpkts = cap_pipe_dispatch(ld.cap_pipe_fd, &ld, &ld.cap_pipe_hdr, &ld.cap_pipe_rechdr, pcap_data, errmsg, sizeof errmsg); } else #endif - inpkts = pcap_dispatch(ld.pch, pcap_cnt, capture_pcap_cb, (u_char *) &ld); + inpkts = pcap_dispatch(ld.pcap_h, pcap_cnt, capture_pcap_cb, (u_char *) &ld); if (inpkts < 0) { /* Error from "pcap_dispatch()", or error or "no more packets" from - "pipe_dispatch(). */ + "cap_pipe_dispatch(). */ ld.go = FALSE; - } else if (cnd_stop_timeout != NULL && cnd_eval(cnd_stop_timeout)) { + } else if (cnd_autostop_duration != NULL && cnd_eval(cnd_autostop_duration)) { /* The specified capture time has elapsed; stop the capture. */ ld.go = FALSE; } else if (inpkts > 0) { @@ -1890,18 +1558,18 @@ capture(char *save_file, int out_file_type) passed both any capture filter in effect and any read filter in effect. */ ld.go = FALSE; - } else if (cnd_stop_capturesize != NULL && - cnd_eval(cnd_stop_capturesize, - (guint32)wtap_get_bytes_dumped(ld.pdh))) { + } else if (cnd_autostop_size != NULL && + cnd_eval(cnd_autostop_size, + (guint32)wtap_get_bytes_dumped(ld.wtap_pdh))) { /* We're saving the capture to a file, and the capture file reached its maximum size. */ if (capture_opts.multi_files_on) { /* Switch to the next ringbuffer file */ - if (ringbuf_switch_file(&ld.pdh, &save_file, &save_file_fd, &loop_err)) { + if (ringbuf_switch_file(&ld.wtap_pdh, &save_file, &save_file_fd, &loop_err)) { /* File switch succeeded: reset the condition */ - cnd_reset(cnd_stop_capturesize); - if (cnd_ring_timeout) { - cnd_reset(cnd_ring_timeout); + cnd_reset(cnd_autostop_size); + if (cnd_file_duration) { + cnd_reset(cnd_file_duration); } } else { /* File switch failed: stop here */ @@ -1915,7 +1583,7 @@ capture(char *save_file, int out_file_type) } if (ld.output_to_pipe) { if (ld.packet_count > packet_count_prev) { - wtap_dump_flush(ld.pdh); + wtap_dump_flush(ld.wtap_pdh); packet_count_prev = ld.packet_count; } } @@ -1923,12 +1591,12 @@ capture(char *save_file, int out_file_type) } /* while (ld.go) */ /* delete stop conditions */ - if (cnd_stop_capturesize != NULL) - cnd_delete(cnd_stop_capturesize); - if (cnd_stop_timeout != NULL) - cnd_delete(cnd_stop_timeout); - if (cnd_ring_timeout != NULL) - cnd_delete(cnd_ring_timeout); + if (cnd_autostop_size != NULL) + cnd_delete(cnd_autostop_size); + if (cnd_autostop_duration != NULL) + cnd_delete(cnd_autostop_duration); + if (cnd_file_duration != NULL) + cnd_delete(cnd_file_duration); if (print_packet_counts) { /* We're printing packet counts to stderr. @@ -1939,8 +1607,8 @@ capture(char *save_file, int out_file_type) /* If we got an error while capturing, report it. */ if (inpkts < 0) { #ifndef _WIN32 - if (ld.from_pipe) { - if (ld.pipe_err == PIPERR) { + if (ld.from_cap_pipe) { + if (ld.cap_pipe_err == PIPERR) { cmdarg_err("Error while capturing packets: %s", errmsg); } @@ -1948,47 +1616,44 @@ capture(char *save_file, int out_file_type) #endif { cmdarg_err("Error while capturing packets: %s", - pcap_geterr(ld.pch)); + pcap_geterr(ld.pcap_h)); } } if (volatile_err == 0) - write_err = FALSE; + write_ok = TRUE; else { show_capture_file_io_error(save_file, volatile_err, FALSE); - write_err = TRUE; + write_ok = FALSE; } if (save_file != NULL) { /* We're saving to a file or files; close all files. */ - if (capture_opts.multi_files_on) { - dump_ok = ringbuf_wtap_dump_close(&save_file, &err); - } else { - dump_ok = wtap_dump_close(ld.pdh, &err); - } + close_ok = capture_loop_close_output(&capture_opts, &ld, &err); + /* If we've displayed a message about a write error, there's no point in displaying another message about an error on close. */ - if (!dump_ok && !write_err) + if (!close_ok && write_ok) show_capture_file_io_error(save_file, err, TRUE); } #ifndef _WIN32 - if (ld.from_pipe && pipe_fd >= 0) - eth_close(pipe_fd); + if (ld.from_cap_pipe && ld.cap_pipe_fd >= 0) + eth_close(ld.cap_pipe_fd); else #endif { /* Get the capture statistics, and, if any packets were dropped, report that. */ - if (pcap_stats(ld.pch, &stats) >= 0) { + if (pcap_stats(ld.pcap_h, &stats) >= 0) { if (stats.ps_drop != 0) { fprintf(stderr, "%u packets dropped\n", stats.ps_drop); } } else { cmdarg_err("Can't get packet-drop statistics: %s", - pcap_geterr(ld.pch)); + pcap_geterr(ld.pcap_h)); } - pcap_close(ld.pch); + pcap_close(ld.pcap_h); } /* Report the number of captured packets if not reported during capture @@ -2005,14 +1670,14 @@ error: save_file = NULL; cmdarg_err("%s", errmsg); #ifndef _WIN32 - if (ld.from_pipe) { - if (pipe_fd >= 0) - eth_close(pipe_fd); + if (ld.from_cap_pipe) { + if (ld.cap_pipe_fd >= 0) + eth_close(ld.cap_pipe_fd); } else #endif { - if (ld.pch != NULL) - pcap_close(ld.pch); + if (ld.pcap_h != NULL) + pcap_close(ld.pcap_h); } return FALSE; @@ -2024,7 +1689,7 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr, { struct wtap_pkthdr whdr; union wtap_pseudo_header pseudo_header; - loop_data *ldat = (loop_data *) user; + loop_data *ld = (loop_data *) user; int loop_err; int err; int save_file_fd; @@ -2032,7 +1697,7 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr, /* Convert from libpcap to Wiretap format. If that fails, ignore the packet (wtap_process_pcap_packet has written an error message). */ - pd = wtap_process_pcap_packet(ldat->linktype, phdr, pd, &pseudo_header, + pd = wtap_process_pcap_packet(ld->wtap_linktype, phdr, pd, &pseudo_header, &whdr, &err); if (pd == NULL) return; @@ -2051,28 +1716,28 @@ capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr, * the first packet of a new series of events as the last * [or only] packet in the file, switch before writing! */ - if (cnd_ring_timeout != NULL && cnd_eval(cnd_ring_timeout)) { + if (cnd_file_duration != NULL && cnd_eval(cnd_file_duration)) { /* time elapsed for this ring file, switch to the next */ - if (ringbuf_switch_file(&ldat->pdh, &ldat->save_file, &save_file_fd, &loop_err)) { + if (ringbuf_switch_file(&ld->wtap_pdh, &ld->save_file, &save_file_fd, &loop_err)) { /* File switch succeeded: reset the condition */ - cnd_reset(cnd_ring_timeout); + cnd_reset(cnd_file_duration); } else { /* File switch failed: stop here */ /* XXX - we should do something with "loop_err" */ - ldat->go = FALSE; + ld->go = FALSE; } } - if (!process_packet(&cfile, ldat->pdh, 0, &whdr, &pseudo_header, pd, &err)) { + if (!process_packet(&cfile, ld->wtap_pdh, 0, &whdr, &pseudo_header, pd, &err)) { /* Error writing to a capture file */ if (print_packet_counts) { /* We're printing counts of packets captured; move to the line after the count. */ fprintf(stderr, "\n"); } - show_capture_file_io_error(ldat->save_file, err, FALSE); - pcap_close(ldat->pch); - wtap_dump_close(ldat->pdh, &err); + show_capture_file_io_error(ld->save_file, err, FALSE); + pcap_close(ld->pcap_h); + wtap_dump_close(ld->wtap_pdh, &err); exit(2); } @@ -3078,293 +2743,6 @@ fail: return CF_ERROR; } -#ifdef HAVE_LIBPCAP -#ifndef _WIN32 -/* Take care of byte order in the libpcap headers read from pipes. - * (function taken from wiretap/libpcap.c) */ -static void -adjust_header(loop_data *ldat, struct pcap_hdr *hdr, struct pcaprec_hdr *rechdr) -{ - if (ldat->byte_swapped) { - /* Byte-swap the record header fields. */ - rechdr->ts_sec = BSWAP32(rechdr->ts_sec); - rechdr->ts_usec = BSWAP32(rechdr->ts_usec); - rechdr->incl_len = BSWAP32(rechdr->incl_len); - rechdr->orig_len = BSWAP32(rechdr->orig_len); - } - - /* In file format version 2.3, the "incl_len" and "orig_len" fields were - swapped, in order to match the BPF header layout. - - Unfortunately, some files were, according to a comment in the "libpcap" - source, written with version 2.3 in their headers but without the - interchanged fields, so if "incl_len" is greater than "orig_len" - which - would make no sense - we assume that we need to swap them. */ - if (hdr->version_major == 2 && - (hdr->version_minor < 3 || - (hdr->version_minor == 3 && rechdr->incl_len > rechdr->orig_len))) { - guint32 temp; - - temp = rechdr->orig_len; - rechdr->orig_len = rechdr->incl_len; - rechdr->incl_len = temp; - } -} - -/* Mimic pcap_open_live() for pipe captures - * We check if "pipename" is "-" (stdin) or a FIFO, open it, and read the - * header. - * N.B. : we can't read the libpcap formats used in RedHat 6.1 or SuSE 6.3 - * because we can't seek on pipes (see wiretap/libpcap.c for details) */ -static int -pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ldat, - char *errmsg, int errmsgl) -{ - struct stat pipe_stat; - int fd; - guint32 magic; - int b; - unsigned int bytes_read; - - /* - * XXX Tethereal blocks until we return - */ - if (strcmp(pipename, "-") == 0) - fd = 0; /* read from stdin */ - else { - if (eth_stat(pipename, &pipe_stat) < 0) { - if (errno == ENOENT || errno == ENOTDIR) - ldat->pipe_err = PIPNEXIST; - else { - g_snprintf(errmsg, errmsgl, - "The capture session could not be initiated " - "due to error on pipe: %s", strerror(errno)); - ldat->pipe_err = PIPERR; - } - return -1; - } - if (! S_ISFIFO(pipe_stat.st_mode)) { - if (S_ISCHR(pipe_stat.st_mode)) { - /* - * Assume the user specified an interface on a system where - * interfaces are in /dev. Pretend we haven't seen it. - */ - ldat->pipe_err = PIPNEXIST; - } else { - g_snprintf(errmsg, errmsgl, - "The capture session could not be initiated because\n" - "\"%s\" is neither an interface nor a pipe", pipename); - ldat->pipe_err = PIPERR; - } - return -1; - } - fd = eth_open(pipename, O_RDONLY, 0000 /* no creation so don't matter */); - if (fd == -1) { - g_snprintf(errmsg, errmsgl, - "The capture session could not be initiated " - "due to error on pipe open: %s", strerror(errno)); - ldat->pipe_err = PIPERR; - return -1; - } - } - - ldat->from_pipe = TRUE; - - /* read the pcap header */ - bytes_read = 0; - while (bytes_read < sizeof magic) { - b = read(fd, ((char *)&magic)+bytes_read, sizeof magic-bytes_read); - if (b <= 0) { - if (b == 0) - g_snprintf(errmsg, errmsgl, "End of file on pipe during open"); - else - g_snprintf(errmsg, errmsgl, "Error on pipe during open: %s", - strerror(errno)); - goto error; - } - bytes_read += b; - } - - switch (magic) { - case PCAP_MAGIC: - /* Host that wrote it has our byte order, and was running - a program using either standard or ss990417 libpcap. */ - ldat->byte_swapped = FALSE; - ldat->modified = FALSE; - break; - case PCAP_MODIFIED_MAGIC: - /* Host that wrote it has our byte order, but was running - a program using either ss990915 or ss991029 libpcap. */ - ldat->byte_swapped = FALSE; - ldat->modified = TRUE; - break; - case PCAP_SWAPPED_MAGIC: - /* Host that wrote it has a byte order opposite to ours, - and was running a program using either standard or - ss990417 libpcap. */ - ldat->byte_swapped = TRUE; - ldat->modified = FALSE; - break; - case PCAP_SWAPPED_MODIFIED_MAGIC: - /* Host that wrote it out has a byte order opposite to - ours, and was running a program using either ss990915 - or ss991029 libpcap. */ - ldat->byte_swapped = TRUE; - ldat->modified = TRUE; - break; - default: - /* Not a "libpcap" type we know about. */ - g_snprintf(errmsg, errmsgl, "Unrecognized libpcap format"); - goto error; - } - - /* Read the rest of the header */ - bytes_read = 0; - while (bytes_read < sizeof(struct pcap_hdr)) { - b = read(fd, ((char *)hdr)+bytes_read, - sizeof(struct pcap_hdr) - bytes_read); - if (b <= 0) { - if (b == 0) - g_snprintf(errmsg, errmsgl, "End of file on pipe during open"); - else - g_snprintf(errmsg, errmsgl, "Error on pipe during open: %s", - strerror(errno)); - goto error; - } - bytes_read += b; - } - - if (ldat->byte_swapped) { - /* Byte-swap the header fields about which we care. */ - hdr->version_major = BSWAP16(hdr->version_major); - hdr->version_minor = BSWAP16(hdr->version_minor); - hdr->snaplen = BSWAP32(hdr->snaplen); - hdr->network = BSWAP32(hdr->network); - } - - if (hdr->version_major < 2) { - g_snprintf(errmsg, errmsgl, "Unable to read old libpcap format"); - goto error; - } - - ldat->pipe_state = STATE_EXPECT_REC_HDR; - ldat->pipe_err = PIPOK; - return fd; - -error: - ldat->pipe_err = PIPERR; - eth_close(fd); - return -1; - -} -/* We read one record from the pipe, take care of byte order in the record - * header, write the record in the capture file, and update capture statistics. */ - -static int -pipe_dispatch(int fd, loop_data *ldat, struct pcap_hdr *hdr, - struct pcaprec_modified_hdr *rechdr, guchar *data, - char *errmsg, int errmsgl) -{ - struct pcap_pkthdr phdr; - int b; - enum { PD_REC_HDR_READ, PD_DATA_READ, PD_PIPE_EOF, PD_PIPE_ERR, - PD_ERR } result; - - switch (ldat->pipe_state) { - - case STATE_EXPECT_REC_HDR: - ldat->bytes_to_read = ldat->modified ? - sizeof(struct pcaprec_modified_hdr) : sizeof(struct pcaprec_hdr); - ldat->bytes_read = 0; - ldat->pipe_state = STATE_READ_REC_HDR; - /* Fall through */ - - case STATE_READ_REC_HDR: - b = read(fd, ((char *)rechdr)+ldat->bytes_read, - ldat->bytes_to_read - ldat->bytes_read); - if (b <= 0) { - if (b == 0) - result = PD_PIPE_EOF; - else - result = PD_PIPE_ERR; - break; - } - if ((ldat->bytes_read += b) < ldat->bytes_to_read) - return 0; - result = PD_REC_HDR_READ; - break; - - case STATE_EXPECT_DATA: - ldat->bytes_read = 0; - ldat->pipe_state = STATE_READ_DATA; - /* Fall through */ - - case STATE_READ_DATA: - b = read(fd, data+ldat->bytes_read, rechdr->hdr.incl_len - ldat->bytes_read); - if (b <= 0) { - if (b == 0) - result = PD_PIPE_EOF; - else - result = PD_PIPE_ERR; - break; - } - if ((ldat->bytes_read += b) < rechdr->hdr.incl_len) - return 0; - result = PD_DATA_READ; - break; - - default: - g_snprintf(errmsg, errmsgl, "pipe_dispatch: invalid state"); - result = PD_ERR; - - } /* switch (ldat->pipe_state) */ - - /* - * We've now read as much data as we were expecting, so process it. - */ - switch (result) { - - case PD_REC_HDR_READ: - /* We've read the header. Take care of byte order. */ - adjust_header(ldat, hdr, &rechdr->hdr); - if (rechdr->hdr.incl_len > WTAP_MAX_PACKET_SIZE) { - g_snprintf(errmsg, errmsgl, "Frame %u too long (%d bytes)", - ldat->packet_count+1, rechdr->hdr.incl_len); - break; - } - ldat->pipe_state = STATE_EXPECT_DATA; - return 0; - - case PD_DATA_READ: - /* Fill in a "struct pcap_pkthdr", and process the packet. */ - phdr.ts.tv_sec = rechdr->hdr.ts_sec; - phdr.ts.tv_usec = rechdr->hdr.ts_usec; - phdr.caplen = rechdr->hdr.incl_len; - phdr.len = rechdr->hdr.orig_len; - - capture_pcap_cb((u_char *)ldat, &phdr, data); - - ldat->pipe_state = STATE_EXPECT_REC_HDR; - return 1; - - case PD_PIPE_EOF: - ldat->pipe_err = PIPEOF; - return -1; - - case PD_PIPE_ERR: - g_snprintf(errmsg, errmsgl, "Error reading from pipe: %s", - strerror(errno)); - /* Fall through */ - case PD_ERR: - break; - } - - ldat->pipe_err = PIPERR; - /* Return here rather than inside the switch to prevent GCC warning */ - return -1; -} -#endif /* _WIN32 */ -#endif /* HAVE_LIBPCAP */ /* * General errors are reported with an console message in Tethereal. @@ -3415,3 +2793,83 @@ cmdarg_err_cont(const char *fmt, ...) fprintf(stderr, "\n"); va_end(ap); } + + +/****************************************************************************************************************/ +/* sync pipe "dummies", needed for capture_loop.c */ + +#ifdef HAVE_LIBPCAP + +/** the child has opened a new capture file, notify the parent */ +void +sync_pipe_filename_to_parent(const char *filename) +{ + /* shouldn't happen */ + g_assert(0); +} + +/** the child captured some new packets, notify the parent */ +void +sync_pipe_packet_count_to_parent(int packet_count) +{ + /* shouldn't happen */ + g_assert(0); +} + +/** the child stopped capturing, notify the parent */ +void +sync_pipe_drops_to_parent(int drops) +{ + /* shouldn't happen */ + g_assert(0); +} + +/** the child encountered an error, notify the parent */ +void +sync_pipe_errmsg_to_parent(const char *errmsg) +{ + cmdarg_err(errmsg); +} + +#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 */ + +