* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/* With MSVC and a libethereal.dll this file needs to import some variables
- in a special way. Therefore _NEED_VAR_IMPORT_ is defined. */
-#define _NEED_VAR_IMPORT_
-
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "util.h"
#include "clopts_common.h"
#include "version_info.h"
-#ifdef HAVE_LIBPCAP
-#include "pcap-util.h"
-#endif
#include <epan/conversation.h>
#include <epan/plugins.h>
#include "register.h"
#include <epan/timestamp.h>
#ifdef HAVE_LIBPCAP
+#include <pcap.h>
+#include "pcap-util.h"
#include <wiretap/wtap-capture.h>
#include <wiretap/libpcap.h>
-#endif
-
#ifdef _WIN32
#include "capture-wpcap.h"
#endif
+#include "capture.h"
+#endif
+
/*
* This is the template for the decode as option; it is shared between the
static guint32 firstsec, firstusec;
static guint32 prevsec, prevusec;
static GString *comp_info_str, *runtime_info_str;
-static gboolean quiet;
static gboolean print_packet_info; /* TRUE if we're to print packet information */
/*
static print_stream_t *print_stream;
#ifdef HAVE_LIBPCAP
+/*
+ * TRUE if we're to print packet counts to keep track of captured packets.
+ */
+static gboolean print_packet_counts;
+
typedef struct _loop_data {
gboolean go; /* TRUE as long as we're supposed to keep capturing */
gint linktype;
static loop_data ld;
#ifdef HAVE_LIBPCAP
-typedef struct {
- gchar *cfilter; /* Capture filter string */
- gchar *iface; /* the network interface to capture from */
- int snaplen; /* Maximum captured packet length */
- int promisc_mode; /* Capture in promiscuous mode */
- int autostop_count; /* Maximum packet count */
- gboolean has_autostop_duration; /* TRUE if maximum capture duration
- is specified */
- gint32 autostop_duration; /* Maximum capture duration */
- gboolean has_autostop_filesize; /* TRUE if maximum capture file size
- is specified */
- gint32 autostop_filesize; /* Maximum capture file size */
- gboolean ringbuffer_on; /* TRUE if ring buffer in use */
- guint32 ringbuffer_num_files; /* Number of ring buffer files */
- gboolean has_ring_duration; /* TRUE if ring duration specified */
- gint32 ringbuffer_duration; /* Switch file after n seconds */
- int linktype; /* Data link type to use, or -1 for
- "use default" */
-} capture_options;
-
-static capture_options capture_opts = {
- "", /* No capture filter string specified */
- NULL, /* Default is "pick the first interface" */
- WTAP_MAX_PACKET_SIZE, /* snapshot length - default is
- infinite, in effect */
- TRUE, /* promiscuous mode is the default */
- 0, /* max packet count - default is 0,
- meaning infinite */
- FALSE, /* maximum capture duration not
- specified by default */
- 0, /* maximum capture duration */
- FALSE, /* maximum capture file size not
- specified by default */
- 0, /* maximum capture file size */
- FALSE, /* ring buffer off by default */
- RINGBUFFER_MIN_NUM_FILES, /* default number of ring buffer files */
- FALSE, /* Switch ring file after some */
- 0, /* specified time is off by default */
- -1 /* Default to not change link type */
-};
+static capture_options capture_opts;
-static gboolean list_link_layer_types;
#ifdef SIGINFO
static gboolean infodelay; /* if TRUE, don't print capture info in SIGINFO handler */
fprintf(output, "\tdefault is libpcap\n");
}
-#ifdef HAVE_LIBPCAP
-static int
-get_natural_int(const char *string, const char *name)
-{
- long number;
- char *p;
-
- number = strtol(string, &p, 10);
- if (p == string || *p != '\0') {
- fprintf(stderr, "tethereal: The specified %s \"%s\" isn't a decimal number\n",
- name, string);
- exit(1);
- }
- if (number < 0) {
- fprintf(stderr, "tethereal: The specified %s is a negative number\n",
- name);
- exit(1);
- }
- if (number > INT_MAX) {
- fprintf(stderr, "tethereal: The specified %s is too large (greater than %d)\n",
- name, INT_MAX);
- exit(1);
- }
- return number;
-}
-
-static int
-get_positive_int(const char *string, const char *name)
-{
- long number;
-
- number = get_natural_int(string, name);
-
- if (number == 0) {
- fprintf(stderr, "tethereal: The specified %s is zero\n",
- name);
- exit(1);
- }
-
- return number;
-}
-
-/*
- * Given a string of the form "<autostop criterion>:<value>", as might appear
- * as an argument to a "-a" option, parse it and set the criterion in
- * question. Return an indication of whether it succeeded or failed
- * in some fashion.
- */
-static gboolean
-set_autostop_criterion(const char *autostoparg)
-{
- guchar *p, *colonp;
-
- colonp = strchr(autostoparg, ':');
- if (colonp == NULL)
- return FALSE;
-
- p = colonp;
- *p++ = '\0';
-
- /*
- * Skip over any white space (there probably won't be any, but
- * as we allow it in the preferences file, we might as well
- * allow it here).
- */
- while (isspace(*p))
- p++;
- if (*p == '\0') {
- /*
- * Put the colon back, so if our caller uses, in an
- * error message, the string they passed us, the message
- * looks correct.
- */
- *colonp = ':';
- return FALSE;
- }
- if (strcmp(autostoparg,"duration") == 0) {
- capture_opts.has_autostop_duration = TRUE;
- capture_opts.autostop_duration = get_positive_int(p,"autostop duration");
- } else if (strcmp(autostoparg,"filesize") == 0) {
- capture_opts.has_autostop_filesize = TRUE;
- capture_opts.autostop_filesize = get_positive_int(p,"autostop filesize");
- } else {
- return FALSE;
- }
- *colonp = ':'; /* put the colon back */
- return TRUE;
-}
-
-/*
- * Given a string of the form "<ring buffer file>:<duration>", as might appear
- * as an argument to a "-b" option, parse it and set the arguments in
- * question. Return an indication of whether it succeeded or failed
- * in some fashion.
- */
-static gboolean
-get_ring_arguments(const char *arg)
-{
- guchar *p = NULL, *colonp;
-
- colonp = strchr(arg, ':');
-
- if (colonp != NULL) {
- p = colonp;
- *p++ = '\0';
- }
-
- capture_opts.ringbuffer_num_files =
- get_natural_int(arg, "number of ring buffer files");
-
- if (colonp == NULL)
- return TRUE;
-
- /*
- * Skip over any white space (there probably won't be any, but
- * as we allow it in the preferences file, we might as well
- * allow it here).
- */
- while (isspace(*p))
- p++;
- if (*p == '\0') {
- /*
- * Put the colon back, so if our caller uses, in an
- * error message, the string they passed us, the message
- * looks correct.
- */
- *colonp = ':';
- return FALSE;
- }
-
- capture_opts.has_ring_duration = TRUE;
- capture_opts.ringbuffer_duration = get_positive_int(p,
- "ring buffer duration");
-
- *colonp = ':'; /* put the colon back */
- return TRUE;
-}
-#endif
-
-/* structure to keep track of what tap listeners have been registered.
- */
-typedef struct _ethereal_tap_list {
- struct _ethereal_tap_list *next;
- char *cmd;
- void (*func)(char *arg);
-} ethereal_tap_list;
-static ethereal_tap_list *tap_list=NULL;
-
-void
-register_ethereal_tap(char *cmd, void (*func)(char *arg))
-{
- ethereal_tap_list *newtl;
-
- newtl=malloc(sizeof(ethereal_tap_list));
- newtl->next=tap_list;
- tap_list=newtl;
- newtl->cmd=cmd;
- newtl->func=func;
-
-}
-
/*
* For a dissector table, print on the stream described by output,
* its short name (which is what's used in the "-d" option) and its
char *p;
gchar err_str[PCAP_ERRBUF_SIZE];
gchar *cant_get_if_list_errstr;
+ gboolean list_link_layer_types = FALSE;
#else
gboolean capture_option_specified = FALSE;
#endif
+ gboolean quiet = FALSE;
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;
dfilter_t *rfcode = NULL;
e_prefs *prefs;
char badopt;
- ethereal_tap_list *tli;
-
-
- /* XXX - better use capture_opts_init instead */
- capture_opts.cfilter = g_strdup("");
+
+#ifdef HAVE_LIBPCAP
+ capture_opts_init(&capture_opts, NULL /* cfile */);
+#endif
set_timestamp_setting(TS_RELATIVE);
/* Register all tap listeners; we do this before we parse the arguments,
as the "-z" argument can specify a registered tap. */
+
+ /* we register the plugin taps before the other taps because
+ stats_tree taps plugins will be registered as tap listeners
+ by stats_tree_stat.c and need to registered before that */
+ register_all_plugin_tap_listeners();
register_all_tap_listeners();
/* Now register the preferences for any non-dissector modules.
while ((opt = getopt(argc, argv, "a:b:c:d:Df:F:hi:lLnN:o:pqr:R:s:St:T:vw:Vxy:z:")) != -1) {
switch (opt) {
case 'a': /* autostop criteria */
-#ifdef HAVE_LIBPCAP
- if (set_autostop_criterion(optarg) == FALSE) {
- fprintf(stderr, "tethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
- exit(1);
- }
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
case 'b': /* Ringbuffer option */
-#ifdef HAVE_LIBPCAP
- capture_opts.ringbuffer_on = TRUE;
- if (get_ring_arguments(optarg) == FALSE) {
- fprintf(stderr, "tethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
- exit(1);
- }
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
case 'c': /* Capture xxx packets */
+ case 'f': /* capture filter */
+ case 'p': /* Don't capture in promiscuous mode */
+ case 's': /* Set the snapshot (capture) length */
+ case 'y': /* Set the pcap data link type */
#ifdef HAVE_LIBPCAP
- capture_opts.autostop_count =
- get_positive_int(optarg, "packet count");
+ capture_opts_add_opt(&capture_opts, "tethereal", opt, optarg, &start_capture);
#else
capture_option_specified = TRUE;
arg_error = TRUE;
arg_error = TRUE;
#endif
break;
- case 'f':
-#ifdef HAVE_LIBPCAP
- capture_filter_specified = TRUE;
- if (capture_opts.cfilter)
- g_free(capture_opts.cfilter);
- capture_opts.cfilter = g_strdup(optarg);
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
case 'F':
out_file_type = wtap_short_string_to_file_type(optarg);
if (out_file_type < 0) {
break;
}
break;
- case 'p': /* Don't capture in promiscuous mode */
-#ifdef HAVE_LIBPCAP
- capture_opts.promisc_mode = FALSE;
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
case 'q': /* Quiet */
quiet = TRUE;
break;
case 'R': /* Read file filter */
rfilter = optarg;
break;
- case 's': /* Set the snapshot (capture) length */
-#ifdef HAVE_LIBPCAP
- capture_opts.snaplen = get_positive_int(optarg, "snapshot length");
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
case 'S': /* show packets in real time */
print_packet_info = TRUE;
break;
case 'x': /* Print packet data in hex (and ASCII) */
print_hex = TRUE;
break;
- case 'y': /* Set the pcap data link type */
-#ifdef HAVE_LIBPCAP
-#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
- capture_opts.linktype = pcap_datalink_name_to_val(optarg);
- if (capture_opts.linktype == -1) {
- fprintf(stderr, "tethereal: The specified data link type \"%s\" isn't valid\n",
- optarg);
- exit(1);
- }
-#else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
- /* XXX - just treat it as a number */
- capture_opts.linktype = get_natural_int(optarg, "data link type");
-#endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
-#else
- capture_option_specified = TRUE;
- arg_error = TRUE;
-#endif
- break;
case 'z':
- for(tli=tap_list;tli;tli=tli->next){
- if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
- (*tli->func)(optarg);
- break;
- }
- }
- if(!tli){
- fprintf(stderr,"tethereal: invalid -z argument.\n");
- fprintf(stderr," -z argument must be one of :\n");
- for(tli=tap_list;tli;tli=tli->next){
- fprintf(stderr," %s\n",tli->cmd);
- }
- exit(1);
- }
+ /* We won't call the init function for the tap this soon
+ as it would disallow MATE's fields (which are registered
+ by the preferences set callback) from being used as
+ part of a tap filter. Instead, we just add the argument
+ to a list of tap arguments. */
+ if (!process_tap_cmd_arg(optarg)) {
+ fprintf(stderr,"tethereal: invalid -z argument.\n");
+ fprintf(stderr," -z argument must be one of :\n");
+ list_tap_cmd_args();
+ exit(1);
+ }
break;
default:
case '?': /* Bad flag - print usage message */
exit(1);
}
/* No - did they specify a ring buffer option? */
- if (capture_opts.ringbuffer_on) {
+ if (capture_opts.multi_files_on) {
fprintf(stderr, "tethereal: Ring buffer requested, but a capture isn't being done.\n");
exit(1);
}
exit(1);
}
- if (capture_opts.ringbuffer_on) {
+ if (capture_opts.multi_files_on) {
/* Ring buffer works only under certain conditions:
a) ring buffer does not work if you're not saving the capture to
a file;
line that their preferences have changed. */
prefs_apply_all();
+ /* At this point MATE will have registered its field array so we can
+ have a filter with one of MATE's late-registered fields as part
+ of the tap's filter. We can now process all the "-z" arguments. */
+ start_requested_taps();
+
/* disabled protocols as per configuration file */
if (gdp_path == NULL && dp_path == NULL) {
set_disabled_protos_list();
else if (capture_opts.snaplen < MIN_PACKET_SIZE)
capture_opts.snaplen = MIN_PACKET_SIZE;
- /* Check the value range of the ringbuffer_num_files parameter */
- if (capture_opts.ringbuffer_num_files > RINGBUFFER_MAX_NUM_FILES)
- capture_opts.ringbuffer_num_files = RINGBUFFER_MAX_NUM_FILES;
+ /* 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;
#if RINGBUFFER_MIN_NUM_FILES > 0
- else if (capture_opts.ringbuffer_num_files < RINGBUFFER_MIN_NUM_FILES)
- capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
+ else if (capture_opts.ring_num_files < RINGBUFFER_MIN_NUM_FILES)
+ capture_opts.ring_num_files = RINGBUFFER_MIN_NUM_FILES;
#endif
#endif
exit(0);
}
+ if (!quiet) {
+ /*
+ * The user didn't ask us not to print a count of packets as
+ * they arrive, so do so.
+ */
+ print_packet_counts = TRUE;
+ }
+
capture(save_file, out_file_type);
- if (capture_opts.ringbuffer_on) {
+ if (capture_opts.multi_files_on) {
ringbuf_free();
}
#else
if (pcap_setfilter(ld.pch, &fcode) < 0) {
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
}
/* Set up to write to the capture file. */
goto error;
}
ld.save_file = save_file;
- if (capture_opts.ringbuffer_on) {
+ if (capture_opts.multi_files_on) {
save_file_fd = ringbuf_init(save_file,
- capture_opts.ringbuffer_num_files);
+ 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);
cnd_stop_timeout = cnd_new((const char*)CND_CLASS_TIMEOUT,
(gint32)capture_opts.autostop_duration);
- if (capture_opts.ringbuffer_on && capture_opts.has_ring_duration)
+ if (capture_opts.multi_files_on && capture_opts.has_file_duration)
cnd_ring_timeout = cnd_new(CND_CLASS_TIMEOUT,
- capture_opts.ringbuffer_duration);
+ capture_opts.file_duration);
if (!setjmp(ld.stopenv)) {
ld.go = TRUE;
reading the FIFO sees the packets immediately and doesn't get
any partial packet, forcing it to block in the middle of reading
that packet. */
- if (capture_opts.autostop_count == 0)
+ if (capture_opts.autostop_packets == 0)
pcap_cnt = -1;
else {
- if (ld.packet_count >= capture_opts.autostop_count) {
+ if (ld.packet_count >= capture_opts.autostop_packets) {
/* XXX do we need this test here? */
/* It appears there's nothing more to capture. */
break;
}
- pcap_cnt = capture_opts.autostop_count - ld.packet_count;
+ pcap_cnt = capture_opts.autostop_packets - ld.packet_count;
}
} else {
/* We need to check the capture file size or the timeout after
/* The specified capture time has elapsed; stop the capture. */
ld.go = FALSE;
} else if (inpkts > 0) {
- if (capture_opts.autostop_count != 0 &&
- ld.packet_count >= capture_opts.autostop_count) {
+ if (capture_opts.autostop_packets != 0 &&
+ ld.packet_count >= capture_opts.autostop_packets) {
/* The specified number of packets have been captured and have
passed both any capture filter in effect and any read filter
in effect. */
(guint32)wtap_get_bytes_dumped(ld.pdh))) {
/* We're saving the capture to a file, and the capture file reached
its maximum size. */
- if (capture_opts.ringbuffer_on) {
+ 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)) {
/* File switch succeeded: reset the condition */
if (cnd_ring_timeout != NULL)
cnd_delete(cnd_ring_timeout);
- if ((save_file != NULL) && !quiet) {
- /* We're saving to a file, which means we're printing packet counts
- to stderr if we are not running silent and deep.
+ if (print_packet_counts) {
+ /* We're printing packet counts to stderr.
Send a newline so that we move to the line after the packet count. */
fprintf(stderr, "\n");
}
if (save_file != NULL) {
/* We're saving to a file or files; close all files. */
- if (capture_opts.ringbuffer_on) {
+ if (capture_opts.multi_files_on) {
dump_ok = ringbuf_wtap_dump_close(&save_file, &err);
} else {
dump_ok = wtap_dump_close(ld.pdh, &err);
return TRUE;
error:
- if (capture_opts.ringbuffer_on) {
+ if (capture_opts.multi_files_on) {
ringbuf_error_cleanup();
}
g_free(save_file);
if (!process_packet(&cfile, ldat->pdh, 0, &whdr, &pseudo_header, pd, &err)) {
/* Error writing to a capture file */
- if (!quiet) {
- /* We're capturing packets, so (if -q not specified) we're printing
- a count of packets captured; move to the line after the count. */
+ 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);
signal(SIGINFO, report_counts_siginfo);
#endif /* SIGINFO */
- if (quiet || print_packet_info) {
+ if (!print_packet_counts) {
/* Report the count only if we aren't printing a packet count
as packets arrive. */
fprintf(stderr, "%u packets captured\n", ld.packet_count);
if (!wtap_dump(pdh, whdr, pseudo_header, pd, err))
return FALSE;
#ifdef HAVE_LIBPCAP
- /* Report packet capture count if not quiet */
- if (!quiet && !print_packet_info) {
- /* Don't print a packet count if we were asked not to with "-q"
- or if we're also printing packet info. */
+ if (print_packet_counts) {
+ /* We're printing packet counts. */
if (ld.packet_count != 0) {
fprintf(stderr, "\r%u ", ld.packet_count);
/* stderr could be line buffered */
for (i = 0; i < cf->cinfo.num_cols; i++) {
switch (cf->cinfo.col_fmt[i]) {
case COL_NUMBER:
+#ifdef HAVE_LIBPCAP
/*
* Don't print this if we're doing a live capture from a network
* interface - if we're doing a live capture, you won't be
*/
if (capture_opts.iface != NULL)
continue;
+#endif
column_len = strlen(cf->cinfo.col_data[i]);
if (column_len < 3)
column_len = 3;