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 */ + +