* Text-mode variant of Wireshark, along the lines of tcpdump and snoop,
* by Gilbert Ramirez <gram@alumni.rice.edu> and Guy Harris <guy@alum.mit.edu>.
*
- * $Id$
- *
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
#include <unistd.h>
#endif
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
#include <errno.h>
#ifdef HAVE_FCNTL_H
#endif
#include <glib.h>
+
+#include <epan/exceptions.h>
+#include <epan/epan-int.h>
#include <epan/epan.h>
-#include <epan/filesystem.h>
#include <wsutil/crash_info.h>
#include <wsutil/privileges.h>
#include <wsutil/file_util.h>
+#include <wsutil/filesystem.h>
+#include <wsutil/report_err.h>
#include "globals.h"
#include <epan/timestamp.h>
#include <epan/packet.h>
+#ifdef HAVE_LUA
+#include <epan/wslua/init_wslua.h>
+#endif
#include "file.h"
-#include "disabled_protos.h"
+#include "frame_tvbuff.h"
+#include <epan/disabled_protos.h>
#include <epan/prefs.h>
#include <epan/column.h>
-#include "print.h"
+#include <epan/print.h>
#include <epan/addr_resolv.h>
#include "ui/util.h"
+#include "ui/ui_util.h"
#include "clopts_common.h"
#include "cmdarg_err.h"
#include "version_info.h"
-#include <epan/plugins.h>
#include "register.h"
#include <epan/epan_dissect.h>
#include <epan/tap.h>
#include <epan/timestamp.h>
#include <epan/ex-opt.h>
+#include "capture_opts.h"
+
#ifdef HAVE_LIBPCAP
#include "capture_ui_utils.h"
#include "capture_ifinfo.h"
#include "log.h"
#include <epan/funnel.h>
+#ifdef HAVE_PLUGINS
+#include <wsutil/plugins.h>
+#endif
+
/*
* This is the template for the decode as option; it is shared between the
* various functions that output the usage for this parameter.
static const gchar decode_as_arg_template[] = "<layer_type>==<selector>,<decode_as_protocol>";
static guint32 cum_bytes;
-static nstime_t first_ts;
+static const frame_data *ref;
+static frame_data ref_frame;
static frame_data *prev_dis;
static frame_data prev_dis_frame;
static frame_data *prev_cap;
/*
* TRUE if we're to print packet counts to keep track of captured packets.
*/
-static gboolean print_packet_counts = TRUE;
+static gboolean print_packet_counts;
static capture_options global_capture_opts;
static capture_session global_capture_session;
#endif /* HAVE_LIBPCAP */
static int load_cap_file(capture_file *, char *, int, gboolean, int, gint64);
-static gboolean process_packet(capture_file *cf, gint64 offset,
+static gboolean process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset,
struct wtap_pkthdr *whdr, const guchar *pd,
- gboolean filtering_tap_listeners, guint tap_flags);
+ guint tap_flags);
static void show_capture_file_io_error(const char *, int, gboolean);
static void show_print_file_io_error(int err);
static gboolean write_preamble(capture_file *cf);
struct string_elem *captypes;
GSList *list = NULL;
- captypes = g_new(struct string_elem, WTAP_NUM_FILE_TYPES);
+ captypes = g_new(struct string_elem, WTAP_NUM_FILE_TYPES_SUBTYPES);
fprintf(stderr, "tshark: The available capture file types for the \"-F\" flag are:\n");
- for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
+ for (i = 0; i < WTAP_NUM_FILE_TYPES_SUBTYPES; i++) {
if (wtap_dump_can_open(i)) {
- captypes[i].sstr = wtap_file_type_short_string(i);
- captypes[i].lstr = wtap_file_type_string(i);
+ captypes[i].sstr = wtap_file_type_subtype_short_string(i);
+ captypes[i].lstr = wtap_file_type_subtype_string(i);
list = g_slist_insert_sorted(list, &captypes[i], string_compare);
}
}
g_free(captypes);
}
+static void
+list_read_capture_types(void) {
+ int i;
+ struct string_elem *captypes;
+ GSList *list = NULL;
+ const char *magic = "Magic-value-based";
+ const char *heuristic = "Heuristics-based";
+
+ /* this is a hack, but WTAP_NUM_FILE_TYPES_SUBTYPES is always >= number of open routines so we're safe */
+ captypes = g_new(struct string_elem, WTAP_NUM_FILE_TYPES_SUBTYPES);
+
+ fprintf(stderr, "tshark: The available read file types for the \"-X read_format:\" option are:\n");
+ for (i = 0; open_routines[i].name != NULL; i++) {
+ captypes[i].sstr = open_routines[i].name;
+ captypes[i].lstr = (open_routines[i].type == OPEN_INFO_MAGIC) ? magic : heuristic;
+ list = g_slist_insert_sorted(list, &captypes[i], string_compare);
+ }
+ g_slist_foreach(list, string_elem_print, NULL);
+ g_slist_free(list);
+ g_free(captypes);
+}
+
static void
print_usage(gboolean print_ver)
{
"See http://www.wireshark.org for more information.\n"
"\n"
"%s",
- wireshark_svnversion, get_copyright_info());
+ wireshark_gitversion, get_copyright_info());
} else {
output = stderr;
}
#endif
/*fprintf(output, "\n");*/
fprintf(output, "Input file:\n");
- fprintf(output, " -r <infile> set the filename to read from (no pipes or stdin!)\n");
+ fprintf(output, " -r <infile> set the filename to read from (no stdin!)\n");
fprintf(output, "\n");
fprintf(output, "Processing:\n");
fprintf(output, " -2 perform a two-pass analysis\n");
fprintf(output, " -R <read filter> packet Read filter in Wireshark display filter syntax\n");
- fprintf(output, " -Y <display filter> packet displaY filter in Wireshark display filter syntax\n");
+ fprintf(output, " -Y <display filter> packet displaY filter in Wireshark display filter\n");
+ fprintf(output, " syntax\n");
fprintf(output, " -n disable all name resolutions (def: all enabled)\n");
fprintf(output, " -N <name resolve flags> enable specific name resolution(s): \"mntC\"\n");
fprintf(output, " -d %s ...\n", decode_as_arg_template);
fprintf(output, " -x add output of hex and ASCII dump (Packet Bytes)\n");
fprintf(output, " -T pdml|ps|psml|text|fields\n");
fprintf(output, " format of text output (def: text)\n");
- fprintf(output, " -e <field> field to print if -Tfields selected (e.g. tcp.port, col.Info);\n");
+ fprintf(output, " -e <field> field to print if -Tfields selected (e.g. tcp.port,\n");
+ fprintf(output, " _ws.col.Info)\n");
fprintf(output, " this option can be repeated to print multiple fields\n");
fprintf(output, " -E<fieldsoption>=<value> set options for output when -Tfields selected:\n");
fprintf(output, " header=y|n switch headers on and off\n");
fprintf(output, " aggregator=,|/s|<char> select comma, space, printable character as\n");
fprintf(output, " aggregator\n");
fprintf(output, " quote=d|s|n select double, single, no quotes for values\n");
- fprintf(output, " -t ad|a|r|d|dd|e output format of time stamps (def: r: rel. to first)\n");
+ fprintf(output, " -t a|ad|d|dd|e|r|u|ud output format of time stamps (def: r: rel. to first)\n");
fprintf(output, " -u s|hms output format of seconds (def: s: seconds)\n");
fprintf(output, " -l flush standard output after each packet\n");
fprintf(output, " -q be more quiet on stdout (e.g. when using statistics)\n");
fprintf(output, " n = write network address resolution information\n");
fprintf(output, " -X <key>:<value> eXtension options, see the man page for details\n");
fprintf(output, " -z <statistics> various statistics, see the man page for details\n");
+ fprintf(output, " --capture-comment <comment>\n");
+ fprintf(output, " add a capture comment to the newly created\n");
+ fprintf(output, " output file (only for pcapng)\n");
fprintf(output, "\n");
fprintf(output, "Miscellaneous:\n");
fprintf(output, " -G [report] dump one of several available reports and exit\n");
fprintf(output, " default report=\"fields\"\n");
fprintf(output, " use \"-G ?\" for more help\n");
+#ifdef __linux__
+ fprintf(output, "\n");
+ fprintf(output, "WARNING: dumpcap will enable kernel BPF JIT compiler if available.\n");
+ fprintf(output, "You might want to reset it\n");
+ fprintf(output, "By doing \"echo 0 > /proc/sys/net/core/bpf_jit_enable\"\n");
+ fprintf(output, "\n");
+#endif
+
}
static void
output = stdout;
- fprintf(output, "TShark " VERSION "%s\n", wireshark_svnversion);
+ fprintf(output, "TShark " VERSION "%s\n", wireshark_gitversion);
fprintf(output, "\n");
fprintf(output, "Usage: tshark -G [report]\n");
fprintf(output, "\n");
fprintf(output, "Glossary table reports:\n");
+ fprintf(output, " -G column-formats dump column format codes and exit\n");
+ fprintf(output, " -G decodes dump \"layer type\"/\"decode as\" associations and exit\n");
fprintf(output, " -G fields dump fields glossary and exit\n");
- fprintf(output, " -G protocols dump protocols in registration database and exit\n");
- fprintf(output, " -G values dump value, range, true/false strings and exit\n");
fprintf(output, " -G ftypes dump field type basic and descriptive names\n");
- fprintf(output, " -G decodes dump \"layer type\"/\"decode as\" associations and exit\n");
fprintf(output, " -G heuristic-decodes dump heuristic dissector tables\n");
+ fprintf(output, " -G plugins dump installed plugins and exit\n");
+ fprintf(output, " -G protocols dump protocols in registration database and exit\n");
+ fprintf(output, " -G values dump value, range, true/false strings and exit\n");
fprintf(output, "\n");
fprintf(output, "Preference reports:\n");
- fprintf(output, " -G defaultprefs dump default preferences and exit\n");
fprintf(output, " -G currentprefs dump current preferences and exit\n");
+ fprintf(output, " -G defaultprefs dump default preferences and exit\n");
fprintf(output, "\n");
}
"%s"
"\n"
"%s",
- wireshark_svnversion, get_copyright_info(), comp_info_str->str,
+ wireshark_gitversion, get_copyright_info(), comp_info_str->str,
runtime_info_str->str);
}
GString *runtime_info_str;
char *init_progfile_dir_error;
int opt;
+ struct option long_options[] = {
+ {(char *)"capture-comment", required_argument, NULL, LONGOPT_NUM_CAP_COMMENT },
+ {0, 0, 0, 0 }
+ };
gboolean arg_error = FALSE;
#ifdef _WIN32
#endif
gboolean quiet = FALSE;
#ifdef PCAP_NG_DEFAULT
- volatile int out_file_type = WTAP_FILE_PCAPNG;
+ volatile int out_file_type = WTAP_FILE_TYPE_SUBTYPE_PCAPNG;
#else
- volatile int out_file_type = WTAP_FILE_PCAP;
+ volatile int out_file_type = WTAP_FILE_TYPE_SUBTYPE_PCAP;
#endif
volatile gboolean out_file_name_res = FALSE;
+ volatile int in_file_type = WTAP_TYPE_AUTO;
gchar *volatile cf_name = NULL;
gchar *rfilter = NULL;
gchar *dfilter = NULL;
#define OPTSTRING_I ""
#endif
-#define OPTSTRING "2a:" OPTSTRING_A "b:" OPTSTRING_B "c:C:d:De:E:f:F:gG:hH:i:" OPTSTRING_I "K:lLnN:o:O:pPqQr:R:s:S:t:T:u:vVw:W:xX:y:Y:z:"
+/* the leading - ensures that getopt() does not permute the argv[] entries
+ we have to make sure that the first getopt() preserves the content of argv[]
+ for the subsequent getopt_long() call */
+#define OPTSTRING "-2a:" OPTSTRING_A "b:" OPTSTRING_B "c:C:d:De:E:f:F:gG:hH:i:" OPTSTRING_I "K:lLnN:o:O:pPqQr:R:s:S:t:T:u:vVw:W:xX:y:Y:z:"
static const char optstring[] = OPTSTRING;
"%s"
"\n"
"%s",
- wireshark_svnversion, comp_info_str->str, runtime_info_str->str);
+ wireshark_gitversion, comp_info_str->str, runtime_info_str->str);
#ifdef _WIN32
arg_list_utf_16to8(argc, argv);
initialize_funnel_ops();
+ init_report_err(failure_message, open_failure_message, read_failure_message,
+ write_failure_message);
+
#ifdef HAVE_LIBPCAP
capture_opts_init(&global_capture_opts);
capture_session_init(&global_capture_session, (void *)&cfile);
timestamp_set_precision(TS_PREC_AUTO);
timestamp_set_seconds_type(TS_SECONDS_DEFAULT);
+ init_open_routines();
+
+#ifdef HAVE_PLUGINS
+ /* Register all the plugin types we have. */
+ epan_register_plugin_types(); /* Types known to libwireshark */
+ wtap_register_plugin_types(); /* Types known to libwiretap */
+
+ /* Scan for plugins. This does *not* call their registration routines;
+ that's done later. */
+ scan_plugins();
+
+ /* Register all libwiretap plugin modules. */
+ register_all_wiretap_modules();
+#endif
+
/* Register all dissectors; we must do this before checking for the
"-G" flag, as the "-G" flag dumps information registered by the
dissectors, and we must do it before we read the preferences, in
case any dissectors register preferences. */
- epan_init(register_all_protocols, register_all_protocol_handoffs, NULL, NULL,
- failure_message, open_failure_message, read_failure_message,
- write_failure_message);
+ epan_init(register_all_protocols, register_all_protocol_handoffs, NULL, NULL);
/* Register all tap listeners; we do this before we parse the arguments,
as the "-z" argument can specify a registered tap. */
if (argc == 2)
proto_registrar_dump_fields();
else {
- if (strcmp(argv[2], "fields") == 0)
+ if (strcmp(argv[2], "column-formats") == 0)
+ column_dump_column_formats();
+ else if (strcmp(argv[2], "currentprefs") == 0) {
+ read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
+ &pf_open_errno, &pf_read_errno, &pf_path);
+ write_prefs(NULL);
+ }
+ else if (strcmp(argv[2], "decodes") == 0)
+ dissector_dump_decodes();
+ else if (strcmp(argv[2], "defaultprefs") == 0)
+ write_prefs(NULL);
+ else if (strcmp(argv[2], "fields") == 0)
proto_registrar_dump_fields();
- else if (strcmp(argv[2], "protocols") == 0)
- proto_registrar_dump_protocols();
- else if (strcmp(argv[2], "values") == 0)
- proto_registrar_dump_values();
else if (strcmp(argv[2], "ftypes") == 0)
proto_registrar_dump_ftypes();
- else if (strcmp(argv[2], "decodes") == 0)
- dissector_dump_decodes();
else if (strcmp(argv[2], "heuristic-decodes") == 0)
dissector_dump_heur_decodes();
- else if (strcmp(argv[2], "defaultprefs") == 0)
- write_prefs(NULL);
- else if (strcmp(argv[2], "plugins") == 0)
+ else if (strcmp(argv[2], "plugins") == 0) {
+#ifdef HAVE_PLUGINS
plugins_dump_all();
+#endif
+#ifdef HAVE_LUA
+ wslua_plugins_dump_all();
+#endif
+ }
+ else if (strcmp(argv[2], "protocols") == 0)
+ proto_registrar_dump_protocols();
+ else if (strcmp(argv[2], "values") == 0)
+ proto_registrar_dump_values();
else if (strcmp(argv[2], "?") == 0)
glossary_option_help();
else if (strcmp(argv[2], "-?") == 0)
glossary_option_help();
- else if (strcmp(argv[2], "currentprefs") == 0) {
- read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
- &pf_open_errno, &pf_read_errno, &pf_path);
- write_prefs(NULL);
- } else {
+ else {
cmdarg_err("Invalid \"%s\" option for -G flag, enter -G ? for more help.", argv[2]);
return 1;
}
output_fields = output_fields_new();
/* Now get our args */
- while ((opt = getopt(argc, argv, optstring)) != -1) {
+ while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
switch (opt) {
case '2': /* Perform two pass analysis */
perform_two_pass_analysis = TRUE;
case 's': /* Set the snapshot (capture) length */
case 'w': /* Write to capture file x */
case 'y': /* Set the pcap data link type */
+ case LONGOPT_NUM_CAP_COMMENT: /* add a capture comment */
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
case 'B': /* Buffer size */
#endif /* _WIN32 or HAVE_PCAP_CREATE */
#endif
case 'D': /* Print a list of capture devices and exit */
#ifdef HAVE_LIBPCAP
- if_list = capture_interface_list(&err, &err_str);
+ if_list = capture_interface_list(&err, &err_str,NULL);
if (if_list == NULL) {
switch (err) {
case CANT_GET_INTERFACE_LIST:
}
break;
case 'F':
- out_file_type = wtap_short_string_to_file_type(optarg);
+ out_file_type = wtap_short_string_to_file_type_subtype(optarg);
if (out_file_type < 0) {
cmdarg_err("\"%s\" isn't a valid capture file type", optarg);
list_capture_types();
if (strchr(optarg, 'n')) {
out_file_name_res = TRUE;
} else {
- cmdarg_err("Invalid -W argument \"%s\"", optarg);
+ cmdarg_err("Invalid -W argument \"%s\"; it must be one of:", optarg);
+ cmdarg_err_cont("\t'n' write network address resolution information (pcapng only)");
return 1;
}
break;
case 'N': /* Select what types of addresses/port #s to resolve */
badopt = string_to_name_resolve(optarg, &gbl_resolv_flags);
if (badopt != '\0') {
- cmdarg_err("-N specifies unknown resolving option '%c';",
+ cmdarg_err("-N specifies unknown resolving option '%c'; valid options are:",
badopt);
- cmdarg_err_cont( " Valid options are 'm', 'n', 't', and 'C'");
+ cmdarg_err_cont("\t'C' to enable concurrent (asynchronous) DNS lookups\n"
+ "\t'm' to enable MAC address resolution\n"
+ "\t'n' to enable network address resolution\n"
+ "\t'N' to enable using external resolvers (e.g., DNS)\n"
+ "\t for network address resolution\n"
+ "\t't' to enable transport-layer port number resolution");
return 1;
}
break;
else if (strcmp(optarg, "a") == 0)
timestamp_set_type(TS_ABSOLUTE);
else if (strcmp(optarg, "ad") == 0)
- timestamp_set_type(TS_ABSOLUTE_WITH_DATE);
+ timestamp_set_type(TS_ABSOLUTE_WITH_YMD);
+ else if (strcmp(optarg, "adoy") == 0)
+ timestamp_set_type(TS_ABSOLUTE_WITH_YDOY);
else if (strcmp(optarg, "d") == 0)
timestamp_set_type(TS_DELTA);
else if (strcmp(optarg, "dd") == 0)
else if (strcmp(optarg, "u") == 0)
timestamp_set_type(TS_UTC);
else if (strcmp(optarg, "ud") == 0)
- timestamp_set_type(TS_UTC_WITH_DATE);
+ timestamp_set_type(TS_UTC_WITH_YMD);
+ else if (strcmp(optarg, "udoy") == 0)
+ timestamp_set_type(TS_UTC_WITH_YDOY);
else {
- cmdarg_err("Invalid time stamp type \"%s\"",
- optarg);
- cmdarg_err_cont("It must be \"r\" for relative, \"a\" for absolute,");
- cmdarg_err_cont("\"ad\" for absolute with date, or \"d\" for delta.");
+ cmdarg_err("Invalid time stamp type \"%s\"; it must be one of:", optarg);
+ cmdarg_err_cont("\t\"a\" for absolute\n"
+ "\t\"ad\" for absolute with YYYY-MM-DD date\n"
+ "\t\"adoy\" for absolute with YYYY/DOY date\n"
+ "\t\"d\" for delta\n"
+ "\t\"dd\" for delta displayed\n"
+ "\t\"e\" for epoch\n"
+ "\t\"r\" for relative\n"
+ "\t\"u\" for absolute UTC\n"
+ "\t\"ud\" for absolute UTC with YYYY-MM-DD date\n"
+ "\t\"udoy\" for absolute UTC with YYYY/DOY date");
return 1;
}
break;
case 'T': /* printing Type */
+ print_packet_info = TRUE;
if (strcmp(optarg, "text") == 0) {
output_action = WRITE_TEXT;
print_format = PR_FMT_TEXT;
print_details = TRUE; /* Need full tree info */
print_summary = FALSE; /* Don't allow summary */
} else {
- cmdarg_err("Invalid -T parameter.");
- cmdarg_err_cont("It must be \"ps\", \"text\", \"pdml\", \"psml\" or \"fields\".");
+ cmdarg_err("Invalid -T parameter \"%s\"; it must be one of:", optarg); /* x */
+ cmdarg_err_cont("\t\"fields\" The values of fields specified with the -e option, in a form\n"
+ "\t specified by the -E option.\n"
+ "\t\"pdml\" Packet Details Markup Language, an XML-based format for the\n"
+ "\t details of a decoded packet. This information is equivalent to\n"
+ "\t the packet details printed with the -V flag.\n"
+ "\t\"ps\" PostScript for a human-readable one-line summary of each of\n"
+ "\t the packets, or a multi-line view of the details of each of\n"
+ "\t the packets, depending on whether the -V flag was specified.\n"
+ "\t\"psml\" Packet Summary Markup Language, an XML-based format for the\n"
+ "\t summary information of a decoded packet. This information is\n"
+ "\t equivalent to the information shown in the one-line summary\n"
+ "\t printed by default.\n"
+ "\t\"text\" Text of a human-readable one-line summary of each of the\n"
+ "\t packets, or a multi-line view of the details of each of the\n"
+ "\t packets, depending on whether the -V flag was specified.\n"
+ "\t This is the default.");
return 1;
}
break;
else if (strcmp(optarg, "hms") == 0)
timestamp_set_seconds_type(TS_SECONDS_HOUR_MIN_SEC);
else {
- cmdarg_err("Invalid seconds type \"%s\"", optarg);
- cmdarg_err_cont("It must be \"s\" for seconds or \"hms\" for hours, minutes and seconds.");
+ cmdarg_err("Invalid seconds type \"%s\"; it must be one of:", optarg);
+ cmdarg_err_cont("\t\"s\" for seconds\n"
+ "\t\"hms\" for hours, minutes and seconds");
return 1;
}
break;
list_stat_cmd_args();
return 0;
}
- cmdarg_err("Invalid -z argument \"%s\".", optarg);
- cmdarg_err_cont(" -z argument must be one of :");
+ cmdarg_err("Invalid -z argument \"%s\"; it must be one of:", optarg);
list_stat_cmd_args();
return 1;
}
return 1;
}
- /* We don't support capture filters when reading from a capture file
- (the BPF compiler doesn't support all link-layer types that we
- support in capture files we read). */
-#ifdef HAVE_LIBPCAP
- if (cf_name != NULL) {
- if (global_capture_opts.default_options.cfilter) {
- cmdarg_err("Only read filters, not capture filters, "
- "can be specified when reading a capture file.");
- return 1;
- }
- }
-#endif
-
if (print_hex) {
if (output_action != WRITE_TEXT) {
cmdarg_err("Raw packet hex data can only be printed as text or PostScript");
}
if (rfilter != NULL && !perform_two_pass_analysis) {
- /* Just a warning, so we don't return */
cmdarg_err("-R without -2 is deprecated. For single-pass filtering use -Y.");
+ return 1;
}
#ifdef HAVE_LIBPCAP
* "-r" was specified, so we're reading a capture file.
* Capture options don't apply here.
*/
+
+ /* We don't support capture filters when reading from a capture file
+ (the BPF compiler doesn't support all link-layer types that we
+ support in capture files we read). */
+ if (global_capture_opts.default_options.cfilter) {
+ cmdarg_err("Only read filters, not capture filters, "
+ "can be specified when reading a capture file.");
+ return 1;
+ }
if (global_capture_opts.multi_files_on) {
cmdarg_err("Multiple capture files requested, but "
"a capture isn't being done.");
"a capture isn't being done.");
return 1;
}
+ if (global_capture_opts.capture_comment) {
+ cmdarg_err("A capture comment was specified, but "
+ "a capture isn't being done.\nThere's no support for adding "
+ "a capture comment to an existing capture file.");
+ return 1;
+ }
/* Note: TShark now allows the restriction of a _read_ file by packet count
* and byte count as well as a write file. Other autostop options remain valid
/*
* "-r" wasn't specified, so we're doing a live capture.
*/
+ if (perform_two_pass_analysis) {
+ /* Two-pass analysis doesn't work with live capture since it requires us
+ * to buffer packets until we've read all of them, but a live capture
+ * has no useful/meaningful definition of "all" */
+ cmdarg_err("Live captures do not support two-pass analysis.");
+ return 1;
+ }
+
if (global_capture_opts.saving_to_file) {
/* They specified a "-w" flag, so we'll be saving to a capture file. */
/* When capturing, we only support writing pcap or pcap-ng format. */
- if (out_file_type != WTAP_FILE_PCAP && out_file_type != WTAP_FILE_PCAPNG) {
+ if (out_file_type != WTAP_FILE_TYPE_SUBTYPE_PCAP &&
+ out_file_type != WTAP_FILE_TYPE_SUBTYPE_PCAPNG) {
cmdarg_err("Live captures can only be saved in libpcap format.");
return 1;
}
+ if (global_capture_opts.capture_comment &&
+ out_file_type != WTAP_FILE_TYPE_SUBTYPE_PCAPNG) {
+ cmdarg_err("A capture comment can only be written to a pcapng file.");
+ return 1;
+ }
if (global_capture_opts.multi_files_on) {
/* Multiple-file mode doesn't work under certain conditions:
a) it doesn't work if you're writing to the standard output;
"the capture isn't being saved to a file.");
return 1;
}
+ if (global_capture_opts.capture_comment) {
+ cmdarg_err("A capture comment was specified, but "
+ "the capture isn't being saved to a file.");
+ return 1;
+ }
}
}
}
}
#endif
+ if (ex_opt_count("read_format") > 0) {
+ const gchar* name = ex_opt_get_next("read_format");
+ in_file_type = open_info_name_to_type(name);
+ if (in_file_type == WTAP_TYPE_AUTO) {
+ cmdarg_err("\"%s\" isn't a valid read file format type", name? name : "");
+ list_read_capture_types();
+ return 1;
+ }
+ }
+
/* disabled protocols as per configuration file */
if (gdp_path == NULL && dp_path == NULL) {
set_disabled_protos_list();
if (pc != NULL) {
if (pcap_compile(pc, &fcode, rfilter, 0, 0) != -1) {
cmdarg_err_cont(
- " Note: That read filter code looks like a valid capture filter;");
- cmdarg_err_cont(
+ " Note: That read filter code looks like a valid capture filter;\n"
" maybe you mixed them up?");
}
pcap_close(pc);
if (pc != NULL) {
if (pcap_compile(pc, &fcode, dfilter, 0, 0) != -1) {
cmdarg_err_cont(
- " Note: That display filter code looks like a valid capture filter;");
- cmdarg_err_cont(
+ " Note: That display filter code looks like a valid capture filter;\n"
" maybe you mixed them up?");
}
pcap_close(pc);
relinquish_special_privs_perm();
print_current_user();
- if (cf_open(&cfile, cf_name, FALSE, &err) != CF_OK) {
+ if (cf_open(&cfile, cf_name, in_file_type, FALSE, &err) != CF_OK) {
epan_cleanup();
return 2;
}
if_capabilities_t *caps;
interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
- caps = capture_get_if_capabilities(interface_opts.name, interface_opts.monitor_mode, &err_str);
+ caps = capture_get_if_capabilities(interface_opts.name, interface_opts.monitor_mode, &err_str, NULL);
if (caps == NULL) {
cmdarg_err("%s", err_str);
g_free(err_str);
return 0;
}
+ /*
+ * If the standard error isn't a terminal, don't print packet counts,
+ * as they won't show up on the user's terminal and they'll get in
+ * the way of error messages in the file (to which we assume the
+ * standard error was redirected; if it's redirected to the null
+ * device, there's no point in printing packet counts anyway).
+ *
+ * Otherwise, if we're printing packet information and the standard
+ * output is a terminal (which we assume means the standard output and
+ * error are going to the same terminal), don't print packet counts,
+ * as they'll get in the way of the packet information.
+ *
+ * Otherwise, if the user specified -q, don't print packet counts.
+ *
+ * Otherwise, print packet counts.
+ *
+ * XXX - what if the user wants to do a live capture, doesn't want
+ * to save it to a file, doesn't want information printed for each
+ * packet, does want some "-z" statistic, and wants packet counts
+ * so they know whether they're seeing any packets? -q will
+ * suppress the information printed for each packet, but it'll
+ * also suppress the packet counts.
+ */
+ if (!isatty(fileno(stderr)))
+ print_packet_counts = FALSE;
+ else if (print_packet_info && isatty(fileno(stdout)))
+ print_packet_counts = FALSE;
+ else if (quiet)
+ print_packet_counts = FALSE;
+ else
+ print_packet_counts = TRUE;
+
if (print_packet_info) {
if (!write_preamble(NULL)) {
show_print_file_io_error(errno);
return 2;
}
- } else if (!quiet) {
- /*
- * We're not printing information for each packet, and the user
- * didn't ask us not to print a count of packets as they arrive,
- * so print that count so the user knows that packets are arriving.
- *
- * XXX - what if the user wants to do a live capture, doesn't want
- * to save it to a file, doesn't want information printed for each
- * packet, does want some "-z" statistic, and wants packet counts
- * so they know whether they're seeing any packets?
- */
- print_packet_counts = TRUE;
}
/* For now, assume libpcap gives microsecond precision. */
draw_tap_listeners(TRUE);
funnel_dump_all_text_windows();
+ epan_free(cfile.epan);
epan_cleanup();
output_fields_free(output_fields);
guint32 packet_count = 0;
-/* XXX - move to the right position / file */
-/* read from a pipe (callback) */
-typedef gboolean (*pipe_input_cb_t) (gint source, gpointer user_data);
-
typedef struct pipe_input_tag {
gint source;
gpointer user_data;
#endif
}
+static const nstime_t *
+tshark_get_frame_ts(void *data, guint32 frame_num)
+{
+ capture_file *cf = (capture_file *) data;
+
+ if (ref && ref->num == frame_num)
+ return &ref->abs_ts;
+
+ if (prev_dis && prev_dis->num == frame_num)
+ return &prev_dis->abs_ts;
+
+ if (prev_cap && prev_cap->num == frame_num)
+ return &prev_cap->abs_ts;
+
+ if (cf->frames) {
+ frame_data *fd = frame_data_sequence_find(cf->frames, frame_num);
+
+ return (fd) ? &fd->abs_ts : NULL;
+ }
+
+ return NULL;
+}
+
+static epan_t *
+tshark_epan_new(capture_file *cf)
+{
+ epan_t *epan = epan_new();
+
+ epan->data = cf;
+ epan->get_frame_ts = tshark_get_frame_ts;
+ epan->get_interface_name = cap_file_get_interface_name;
+ epan->get_user_comment = NULL;
+
+ return epan;
+}
#ifdef HAVE_LIBPCAP
static gboolean
relinquish_special_privs_perm();
print_current_user();
- /* Cleanup all data structures used for dissection. */
- cleanup_dissection();
- /* Initialize all data structures used for dissection. */
- init_dissection();
+ /* Create new dissection section. */
+ epan_free(cfile.epan);
+ cfile.epan = tshark_epan_new(&cfile);
#ifdef _WIN32
/* Catch a CTRL+C event and, if we get it, clean up and exit. */
g_array_insert_val(global_capture_opts.ifaces, i, interface_opts);
}
#ifdef _WIN32
- if (global_capture_opts.ifaces->len < 2) {
+ if (global_capture_opts.ifaces->len < 2)
#else
- if (global_capture_opts.ifaces->len < 4) {
+ if (global_capture_opts.ifaces->len < 4)
#endif
+ {
for (i = 0; i < global_capture_opts.ifaces->len; i++) {
interface_options interface_opts;
fflush(stderr);
g_string_free(str, TRUE);
- ret = sync_pipe_start(&global_capture_opts, &global_capture_session);
+ ret = sync_pipe_start(&global_capture_opts, &global_capture_session, NULL);
if (!ret)
return FALSE;
return TRUE;
}
-
-/* XXX - move the call to main_window_update() out of capture_sync.c */
-/* dummy for capture_sync.c to make linker happy */
-void main_window_update(void)
-{
-}
-
/* capture child detected an error */
void
capture_input_error_message(capture_session *cap_session _U_, char *error_msg, char *secondary_error_msg)
if (dfilter_compile(interface_opts.cfilter, &rfcode) && rfcode != NULL) {
cmdarg_err(
- "Invalid capture filter \"%s\" for interface %s!\n"
+ "Invalid capture filter \"%s\" for interface '%s'!\n"
"\n"
"That string looks like a valid display filter; however, it isn't a valid\n"
"capture filter (%s).\n"
dfilter_free(rfcode);
} else {
cmdarg_err(
- "Invalid capture filter \"%s\" for interface %s!\n"
+ "Invalid capture filter \"%s\" for interface '%s'!\n"
"\n"
"That string isn't a valid capture filter (%s).\n"
"See the User's Guide for a description of the capture filter syntax.",
if ( ((capture_file *) cap_session->cf)->state != FILE_CLOSED) {
if ( ((capture_file *) cap_session->cf)->wth != NULL) {
wtap_close(((capture_file *) cap_session->cf)->wth);
+ ((capture_file *) cap_session->cf)->wth = NULL;
}
((capture_file *) cap_session->cf)->state = FILE_CLOSED;
}
/* if we are in real-time mode, open the new file now */
if (do_dissection) {
/* Attempt to open the capture file and set up to read from it. */
- switch(cf_open((capture_file *)cap_session->cf, capture_opts->save_file, is_tempfile, &err)) {
+ switch(cf_open((capture_file *)cap_session->cf, capture_opts->save_file, WTAP_TYPE_AUTO, is_tempfile, &err)) {
case CF_OK:
break;
case CF_ERROR:
tap_flags = union_of_tap_listener_flags();
if (do_dissection) {
+ gboolean create_proto_tree;
+ epan_dissect_t *edt;
+
+ if (cf->rfcode || cf->dfcode || print_details || filtering_tap_listeners ||
+ (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo))
+ create_proto_tree = TRUE;
+ else
+ create_proto_tree = FALSE;
+
+ /* The protocol tree will be "visible", i.e., printed, only if we're
+ printing packet details, which is true if we're printing stuff
+ ("print_packet_info" is true) and we're in verbose mode
+ ("packet_details" is true). */
+ edt = epan_dissect_new(cf->epan, create_proto_tree, print_packet_info && print_details);
+
while (to_read-- && cf->wth) {
wtap_cleareof(cf->wth);
ret = wtap_read(cf->wth, &err, &err_info, &data_offset);
wtap_close(cf->wth);
cf->wth = NULL;
} else {
- ret = process_packet(cf, data_offset, wtap_phdr(cf->wth),
+ ret = process_packet(cf, edt, data_offset, wtap_phdr(cf->wth),
wtap_buf_ptr(cf->wth),
- filtering_tap_listeners, tap_flags);
+ tap_flags);
}
if (ret != FALSE) {
/* packet successfully read and gone through the "Read Filter" */
packet_count++;
}
}
+
+ epan_dissect_free(edt);
+
} else {
/*
* Dumpcap's doing all the work; we're not doing any dissection.
#endif /* HAVE_LIBPCAP */
static gboolean
-process_packet_first_pass(capture_file *cf,
+process_packet_first_pass(capture_file *cf, epan_dissect_t *edt,
gint64 offset, struct wtap_pkthdr *whdr,
const guchar *pd)
{
frame_data fdlocal;
guint32 framenum;
- gboolean create_proto_tree = FALSE;
- epan_dissect_t edt;
gboolean passed;
/* The frame number of this packet is one more than the count of
/* If we're going to print packet information, or we're going to
run a read filter, or display filter, or we're going to process taps, set up to
do a dissection and do so. */
- if (do_dissection) {
+ if (edt) {
if (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
gbl_resolv_flags.transport_name || gbl_resolv_flags.concurrent_dns)
/* Grab any resolved addresses */
host_name_lookup_process();
- /* If we're going to be applying a filter, we'll need to
- create a protocol tree against which to apply the filter. */
- if (cf->rfcode)
- create_proto_tree = TRUE;
-
- /* We're not going to display the protocol tree on this pass,
- so it's not going to be "visible". */
- epan_dissect_init(&edt, create_proto_tree, FALSE);
-
/* If we're running a read filter, prime the epan_dissect_t with that
filter. */
if (cf->rfcode)
- epan_dissect_prime_dfilter(&edt, cf->rfcode);
+ epan_dissect_prime_dfilter(edt, cf->rfcode);
frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time,
- &first_ts, prev_dis, prev_cap);
+ &ref, prev_dis);
+ if (ref == &fdlocal) {
+ ref_frame = fdlocal;
+ ref = &ref_frame;
+ }
- epan_dissect_run(&edt, whdr, pd, &fdlocal, NULL);
+ epan_dissect_run(edt, whdr, frame_tvbuff_new(&fdlocal, pd), &fdlocal, NULL);
/* Run the read filter if we have one. */
if (cf->rfcode)
- passed = dfilter_apply_edt(cf->rfcode, &edt);
+ passed = dfilter_apply_edt(cf->rfcode, edt);
}
if (passed) {
* More importantly, edt.pi.dependent_frames won't be initialized because
* epan hasn't been initialized.
*/
- if (do_dissection) {
- g_slist_foreach(edt.pi.dependent_frames, find_and_mark_frame_depended_upon, cf->frames);
+ if (edt) {
+ g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->frames);
}
cf->count++;
/* if we don't add it to the frame_data_sequence, clean it up right now
* to avoid leaks */
frame_data_destroy(&fdlocal);
- /* TODO, bug #8160 */
- /*
- prev_cap_frame = fdlocal;
- prev_cap = &prev_cap_frame;
- */
}
- if (do_dissection)
- epan_dissect_cleanup(&edt);
+ if (edt)
+ epan_dissect_reset(edt);
return passed;
}
static gboolean
-process_packet_second_pass(capture_file *cf, frame_data *fdata,
- struct wtap_pkthdr *phdr, const guchar *pd,
- gboolean filtering_tap_listeners, guint tap_flags)
+process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, frame_data *fdata,
+ struct wtap_pkthdr *phdr, Buffer *buf,
+ guint tap_flags)
{
- gboolean create_proto_tree;
column_info *cinfo;
- epan_dissect_t edt;
gboolean passed;
/* If we're not running a display filter and we're not printing any
/* If we're going to print packet information, or we're going to
run a read filter, or we're going to process taps, set up to
do a dissection and do so. */
- if (do_dissection) {
+ if (edt) {
if (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
gbl_resolv_flags.transport_name || gbl_resolv_flags.concurrent_dns)
/* Grab any resolved addresses */
host_name_lookup_process();
- if (cf->dfcode || print_details || filtering_tap_listeners ||
- (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo))
- create_proto_tree = TRUE;
- else
- create_proto_tree = FALSE;
-
- /* The protocol tree will be "visible", i.e., printed, only if we're
- printing packet details, which is true if we're printing stuff
- ("print_packet_info" is true) and we're in verbose mode
- ("packet_details" is true). */
- epan_dissect_init(&edt, create_proto_tree, print_packet_info && print_details);
-
/* If we're running a display filter, prime the epan_dissect_t with that
filter. */
if (cf->dfcode)
- epan_dissect_prime_dfilter(&edt, cf->dfcode);
+ epan_dissect_prime_dfilter(edt, cf->dfcode);
- col_custom_prime_edt(&edt, &cf->cinfo);
+ col_custom_prime_edt(edt, &cf->cinfo);
/* We only need the columns if either
1) some tap needs the columns
else
cinfo = NULL;
- epan_dissect_run_with_taps(&edt, phdr, pd, fdata, cinfo);
+ frame_data_set_before_dissect(fdata, &cf->elapsed_time,
+ &ref, prev_dis);
+ if (ref == fdata) {
+ ref_frame = *fdata;
+ ref = &ref_frame;
+ }
+
+ epan_dissect_run_with_taps(edt, phdr, frame_tvbuff_new_buffer(fdata, buf), fdata, cinfo);
/* Run the read/display filter if we have one. */
if (cf->dfcode)
- passed = dfilter_apply_edt(cf->dfcode, &edt);
+ passed = dfilter_apply_edt(cf->dfcode, edt);
}
if (passed) {
+ frame_data_set_after_dissect(fdata, &cum_bytes);
/* Process this packet. */
if (print_packet_info) {
/* We're printing packet information; print the information for
this packet. */
- if (do_dissection)
- print_packet(cf, &edt);
- else
- print_packet(cf, NULL);
+ print_packet(cf, edt);
/* The ANSI C standard does not appear to *require* that a line-buffered
stream be flushed to the host environment whenever a newline is
exit(2);
}
}
+ prev_dis = fdata;
}
+ prev_cap = fdata;
- if (do_dissection) {
- epan_dissect_cleanup(&edt);
+ if (edt) {
+ epan_dissect_reset(edt);
}
return passed || fdata->flags.dependent_of_displayed;
}
wtapng_section_t *shb_hdr;
wtapng_iface_descriptions_t *idb_inf;
char appname[100];
+ struct wtap_pkthdr phdr;
+ Buffer buf;
+ epan_dissect_t *edt = NULL;
shb_hdr = wtap_file_get_shb_info(cf->wth);
idb_inf = wtap_file_get_idb_info(cf->wth);
#ifdef PCAP_NG_DEFAULT
- if (idb_inf->number_of_interfaces > 0) {
+ if (idb_inf->number_of_interfaces > 1) {
linktype = WTAP_ENCAP_PER_PACKET;
} else {
linktype = wtap_file_encap(cf->wth);
}
/* If we don't have an application name add Tshark */
if (shb_hdr->shb_user_appl == NULL) {
- g_snprintf(appname, sizeof(appname), "TShark " VERSION "%s", wireshark_svnversion);
+ g_snprintf(appname, sizeof(appname), "TShark " VERSION "%s", wireshark_gitversion);
shb_hdr->shb_user_appl = appname;
}
- pdh = wtap_dump_open_ng(save_file, out_file_type, linktype, snapshot_length,
- FALSE /* compressed */, shb_hdr, idb_inf, &err);
+ if (linktype != WTAP_ENCAP_PER_PACKET &&
+ out_file_type == WTAP_FILE_TYPE_SUBTYPE_PCAP)
+ pdh = wtap_dump_open(save_file, out_file_type, linktype,
+ snapshot_length, FALSE /* compressed */, &err);
+ else
+ pdh = wtap_dump_open_ng(save_file, out_file_type, linktype,
+ snapshot_length, FALSE /* compressed */, shb_hdr, idb_inf, &err);
g_free(idb_inf);
idb_inf = NULL;
case WTAP_ERR_UNSUPPORTED_ENCAP:
case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
cmdarg_err("The capture file being read can't be written as a "
- "\"%s\" file.", wtap_file_type_short_string(out_file_type));
+ "\"%s\" file.", wtap_file_type_subtype_short_string(out_file_type));
break;
case WTAP_ERR_CANT_OPEN:
goto out;
}
}
+ g_free(idb_inf);
+ idb_inf = NULL;
pdh = NULL;
}
if (pdh && out_file_name_res) {
if (!wtap_dump_set_addrinfo_list(pdh, get_addrinfo_list())) {
cmdarg_err("The file format \"%s\" doesn't support name resolution information.",
- wtap_file_type_short_string(out_file_type));
+ wtap_file_type_subtype_short_string(out_file_type));
}
}
if (perform_two_pass_analysis) {
frame_data *fdata;
- int old_max_packet_count = max_packet_count;
/* Allocate a frame_data_sequence for all the frames. */
cf->frames = new_frame_data_sequence();
+ if (do_dissection) {
+ gboolean create_proto_tree = FALSE;
+
+ /* If we're going to be applying a filter, we'll need to
+ create a protocol tree against which to apply the filter. */
+ if (cf->rfcode)
+ create_proto_tree = TRUE;
+
+ /* We're not going to display the protocol tree on this pass,
+ so it's not going to be "visible". */
+ edt = epan_dissect_new(cf->epan, create_proto_tree, FALSE);
+ }
+
while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
- if (process_packet_first_pass(cf, data_offset, wtap_phdr(cf->wth),
+ if (process_packet_first_pass(cf, edt, data_offset, wtap_phdr(cf->wth),
wtap_buf_ptr(cf->wth))) {
/* Stop reading if we have the maximum number of packets;
* When the -c option has not been used, max_packet_count
}
}
+ if (edt) {
+ epan_dissect_free(edt);
+ edt = NULL;
+ }
+
/* Close the sequential I/O side, to free up memory it requires. */
wtap_sequential_close(cf->wth);
* don't need after the sequential run-through of the packets. */
postseq_cleanup_all_protocols();
- max_packet_count = old_max_packet_count;
+ prev_dis = NULL;
+ prev_cap = NULL;
+ buffer_init(&buf, 1500);
+
+ if (do_dissection) {
+ gboolean create_proto_tree;
+
+ if (cf->dfcode || print_details || filtering_tap_listeners ||
+ (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo))
+ create_proto_tree = TRUE;
+ else
+ create_proto_tree = FALSE;
+
+ /* The protocol tree will be "visible", i.e., printed, only if we're
+ printing packet details, which is true if we're printing stuff
+ ("print_packet_info" is true) and we're in verbose mode
+ ("packet_details" is true). */
+ edt = epan_dissect_new(cf->epan, create_proto_tree, print_packet_info && print_details);
+ }
for (framenum = 1; err == 0 && framenum <= cf->count; framenum++) {
fdata = frame_data_sequence_find(cf->frames, framenum);
- if (wtap_seek_read(cf->wth, fdata->file_off, &cf->phdr,
- cf->pd, fdata->cap_len, &err, &err_info)) {
- if (process_packet_second_pass(cf, fdata,
- &cf->phdr, cf->pd,
- filtering_tap_listeners, tap_flags)) {
+ if (wtap_seek_read(cf->wth, fdata->file_off, &phdr, &buf, &err,
+ &err_info)) {
+ if (process_packet_second_pass(cf, edt, fdata, &phdr, &buf,
+ tap_flags)) {
/* Either there's no read filtering or this packet passed the
filter, so, if we're writing to a capture file, write
this packet out. */
if (pdh != NULL) {
- if (!wtap_dump(pdh, &cf->phdr, cf->pd, &err)) {
+ if (!wtap_dump(pdh, &phdr, buffer_start_ptr(&buf), &err)) {
/* Error writing to a capture file */
switch (err) {
case WTAP_ERR_UNSUPPORTED_ENCAP:
/*
- * This is a problem with the particular frame we're writing;
- * note that, and give the frame number.
+ * This is a problem with the particular frame we're writing
+ * and the file type and subtype we're writing; note that,
+ * and report the frame number and file type/subtype.
*
* XXX - framenum is not necessarily the frame number in
* the input file if there was a read filter.
fprintf(stderr,
"Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.\n",
framenum, cf->filename,
- wtap_file_type_short_string(out_file_type));
+ wtap_file_type_subtype_short_string(out_file_type));
+ break;
+
+ case WTAP_ERR_PACKET_TOO_LARGE:
+ /*
+ * This is a problem with the particular frame we're writing
+ * and the file type and subtype we're writing; note that,
+ * and report the frame number and file type/subtype.
+ *
+ * XXX - framenum is not necessarily the frame number in
+ * the input file if there was a read filter.
+ */
+ fprintf(stderr,
+ "Frame %u of \"%s\" is too large for a \"%s\" file.\n",
+ framenum, cf->filename,
+ wtap_file_type_subtype_short_string(out_file_type));
break;
default:
exit(2);
}
}
- /* Stop reading if we have the maximum number of packets;
- * When the -c option has not been used, max_packet_count
- * starts at 0, which practically means, never stop reading.
- * (unless we roll over max_packet_count ?)
- */
- if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
- err = 0; /* This is not an error */
- break;
- }
}
}
}
+
+ if (edt) {
+ epan_dissect_free(edt);
+ edt = NULL;
+ }
+
+ buffer_free(&buf);
}
else {
framenum = 0;
+
+ if (do_dissection) {
+ gboolean create_proto_tree;
+
+ if (cf->rfcode || cf->dfcode || print_details || filtering_tap_listeners ||
+ (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo))
+ create_proto_tree = TRUE;
+ else
+ create_proto_tree = FALSE;
+
+ /* The protocol tree will be "visible", i.e., printed, only if we're
+ printing packet details, which is true if we're printing stuff
+ ("print_packet_info" is true) and we're in verbose mode
+ ("packet_details" is true). */
+ edt = epan_dissect_new(cf->epan, create_proto_tree, print_packet_info && print_details);
+ }
+
while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
framenum++;
- if (process_packet(cf, data_offset, wtap_phdr(cf->wth),
+ if (process_packet(cf, edt, data_offset, wtap_phdr(cf->wth),
wtap_buf_ptr(cf->wth),
- filtering_tap_listeners, tap_flags)) {
+ tap_flags)) {
/* Either there's no read filtering or this packet passed the
filter, so, if we're writing to a capture file, write
this packet out. */
case WTAP_ERR_UNSUPPORTED_ENCAP:
/*
- * This is a problem with the particular frame we're writing;
- * note that, and give the frame number.
+ * This is a problem with the particular frame we're writing
+ * and the file type and subtype we're writing; note that,
+ * and report the frame number and file type/subtype.
*/
fprintf(stderr,
"Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.\n",
framenum, cf->filename,
- wtap_file_type_short_string(out_file_type));
+ wtap_file_type_subtype_short_string(out_file_type));
+ break;
+
+ case WTAP_ERR_PACKET_TOO_LARGE:
+ /*
+ * This is a problem with the particular frame we're writing
+ * and the file type and subtype we're writing; note that,
+ * and report the frame number and file type/subtype.
+ */
+ fprintf(stderr,
+ "Frame %u of \"%s\" is too large for a \"%s\" file.\n",
+ framenum, cf->filename,
+ wtap_file_type_subtype_short_string(out_file_type));
break;
default:
exit(2);
}
}
- /* Stop reading if we have the maximum number of packets;
- * When the -c option has not been used, max_packet_count
- * starts at 0, which practically means, never stop reading.
- * (unless we roll over max_packet_count ?)
- */
- if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
- err = 0; /* This is not an error */
- break;
- }
+ }
+ /* Stop reading if we have the maximum number of packets;
+ * When the -c option has not been used, max_packet_count
+ * starts at 0, which practically means, never stop reading.
+ * (unless we roll over max_packet_count ?)
+ */
+ if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
+ err = 0; /* This is not an error */
+ break;
}
}
+
+ if (edt) {
+ epan_dissect_free(edt);
+ edt = NULL;
+ }
}
if (err != 0) {
}
static gboolean
-process_packet(capture_file *cf, gint64 offset, struct wtap_pkthdr *whdr,
- const guchar *pd,
- gboolean filtering_tap_listeners, guint tap_flags)
+process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset, struct wtap_pkthdr *whdr,
+ const guchar *pd, guint tap_flags)
{
frame_data fdata;
- gboolean create_proto_tree;
column_info *cinfo;
- epan_dissect_t edt;
gboolean passed;
/* Count this packet. */
/* If we're going to print packet information, or we're going to
run a read filter, or we're going to process taps, set up to
do a dissection and do so. */
- if (do_dissection) {
+ if (edt) {
if (print_packet_info && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
gbl_resolv_flags.transport_name || gbl_resolv_flags.concurrent_dns))
/* Grab any resolved addresses */
host_name_lookup_process();
- if (cf->rfcode || cf->dfcode || print_details || filtering_tap_listeners ||
- (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo))
- create_proto_tree = TRUE;
- else
- create_proto_tree = FALSE;
-
- /* The protocol tree will be "visible", i.e., printed, only if we're
- printing packet details, which is true if we're printing stuff
- ("print_packet_info" is true) and we're in verbose mode
- ("packet_details" is true). */
- epan_dissect_init(&edt, create_proto_tree, print_packet_info && print_details);
-
/* If we're running a filter, prime the epan_dissect_t with that
filter. */
- if (cf->rfcode)
- epan_dissect_prime_dfilter(&edt, cf->rfcode);
if (cf->dfcode)
- epan_dissect_prime_dfilter(&edt, cf->dfcode);
+ epan_dissect_prime_dfilter(edt, cf->dfcode);
- col_custom_prime_edt(&edt, &cf->cinfo);
+ col_custom_prime_edt(edt, &cf->cinfo);
/* We only need the columns if either
1) some tap needs the columns
cinfo = NULL;
frame_data_set_before_dissect(&fdata, &cf->elapsed_time,
- &first_ts, prev_dis, prev_cap);
+ &ref, prev_dis);
+ if (ref == &fdata) {
+ ref_frame = fdata;
+ ref = &ref_frame;
+ }
- epan_dissect_run_with_taps(&edt, whdr, pd, &fdata, cinfo);
+ epan_dissect_run_with_taps(edt, whdr, frame_tvbuff_new(&fdata, pd), &fdata, cinfo);
- /* Run the filters if we have them. */
- if (cf->rfcode)
- passed = dfilter_apply_edt(cf->rfcode, &edt);
- if (passed && cf->dfcode)
- passed = dfilter_apply_edt(cf->dfcode, &edt);
+ /* Run the filter if we have it. */
+ if (cf->dfcode)
+ passed = dfilter_apply_edt(cf->dfcode, edt);
}
if (passed) {
if (print_packet_info) {
/* We're printing packet information; print the information for
this packet. */
- if (do_dissection)
- print_packet(cf, &edt);
- else
- print_packet(cf, NULL);
+ print_packet(cf, edt);
/* The ANSI C standard does not appear to *require* that a line-buffered
stream be flushed to the host environment whenever a newline is
prev_cap_frame = fdata;
prev_cap = &prev_cap_frame;
- if (do_dissection) {
- epan_dissect_cleanup(&edt);
+ if (edt) {
+ epan_dissect_reset(edt);
frame_data_destroy(&fdata);
}
return passed;
switch (output_action) {
case WRITE_TEXT:
- return print_preamble(print_stream, cf ? cf->filename : NULL);
+ return print_preamble(print_stream, cf ? cf->filename : NULL, wireshark_gitversion);
case WRITE_XML:
if (print_details)
return line_bufp;
}
+static inline void
+put_string(char *dest, const char *str, size_t str_len)
+{
+ memcpy(dest, str, str_len);
+ dest[str_len] = '\0';
+}
+
+static inline void
+put_spaces_string(char *dest, const char *str, size_t str_len, size_t str_with_spaces)
+{
+ size_t i;
+
+ for (i = str_len; i < str_with_spaces; i++)
+ *dest++ = ' ';
+
+ put_string(dest, str, str_len);
+}
+
+static inline void
+put_string_spaces(char *dest, const char *str, size_t str_len, size_t str_with_spaces)
+{
+ size_t i;
+
+ memcpy(dest, str, str_len);
+ for (i = str_len; i < str_with_spaces; i++)
+ dest[i] = ' ';
+
+ dest[str_with_spaces] = '\0';
+}
+
static gboolean
print_columns(capture_file *cf)
{
int i;
size_t buf_offset;
size_t column_len;
+ size_t col_len;
line_bufp = get_line_buf(256);
buf_offset = 0;
continue;
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
- * able to look at the capture in the future (it's not being
- * saved anywhere), so the frame numbers are unlikely to be
- * useful.
- *
- * (XXX - it might be nice to be able to save and print at
- * the same time, sort of like an "Update list of packets
- * in real time" capture in Wireshark.)
- */
- if (global_capture_opts.ifaces->len > 0)
- continue;
-#endif
- column_len = strlen(cf->cinfo.col_data[i]);
+ column_len = col_len = strlen(cf->cinfo.col_data[i]);
if (column_len < 3)
column_len = 3;
line_bufp = get_line_buf(buf_offset + column_len);
- g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%3s", cf->cinfo.col_data[i]);
+ put_spaces_string(line_bufp + buf_offset, cf->cinfo.col_data[i], col_len, column_len);
break;
case COL_CLS_TIME:
case COL_REL_TIME:
case COL_ABS_TIME:
- case COL_ABS_DATE_TIME:
+ case COL_ABS_YMD_TIME: /* XXX - wider */
+ case COL_ABS_YDOY_TIME: /* XXX - wider */
case COL_UTC_TIME:
- case COL_UTC_DATE_TIME: /* XXX - wider */
- column_len = strlen(cf->cinfo.col_data[i]);
+ case COL_UTC_YMD_TIME: /* XXX - wider */
+ case COL_UTC_YDOY_TIME: /* XXX - wider */
+ column_len = col_len = strlen(cf->cinfo.col_data[i]);
if (column_len < 10)
column_len = 10;
line_bufp = get_line_buf(buf_offset + column_len);
- g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%10s", cf->cinfo.col_data[i]);
+ put_spaces_string(line_bufp + buf_offset, cf->cinfo.col_data[i], col_len, column_len);
break;
case COL_DEF_SRC:
case COL_DEF_NET_SRC:
case COL_RES_NET_SRC:
case COL_UNRES_NET_SRC:
- column_len = strlen(cf->cinfo.col_data[i]);
+ column_len = col_len = strlen(cf->cinfo.col_data[i]);
if (column_len < 12)
column_len = 12;
line_bufp = get_line_buf(buf_offset + column_len);
- g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%12s", cf->cinfo.col_data[i]);
+ put_spaces_string(line_bufp + buf_offset, cf->cinfo.col_data[i], col_len, column_len);
break;
case COL_DEF_DST:
case COL_DEF_NET_DST:
case COL_RES_NET_DST:
case COL_UNRES_NET_DST:
- column_len = strlen(cf->cinfo.col_data[i]);
+ column_len = col_len = strlen(cf->cinfo.col_data[i]);
if (column_len < 12)
column_len = 12;
line_bufp = get_line_buf(buf_offset + column_len);
- g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%-12s", cf->cinfo.col_data[i]);
+ put_string_spaces(line_bufp + buf_offset, cf->cinfo.col_data[i], col_len, column_len);
break;
default:
column_len = strlen(cf->cinfo.col_data[i]);
line_bufp = get_line_buf(buf_offset + column_len);
- g_strlcat(line_bufp + buf_offset, cf->cinfo.col_data[i], column_len + 1);
+ put_string(line_bufp + buf_offset, cf->cinfo.col_data[i], column_len);
break;
}
buf_offset += column_len;
case COL_DEF_DST:
case COL_RES_DST:
case COL_UNRES_DST:
- g_strlcat(line_bufp + buf_offset, " -> ", 5);
+ put_string(line_bufp + buf_offset, " -> ", 4);
buf_offset += 4;
break;
default:
- g_strlcat(line_bufp + buf_offset, " ", 5);
+ put_string(line_bufp + buf_offset, " ", 1);
buf_offset += 1;
break;
}
case COL_DEF_DL_DST:
case COL_RES_DL_DST:
case COL_UNRES_DL_DST:
- g_strlcat(line_bufp + buf_offset, " -> ", 5);
+ put_string(line_bufp + buf_offset, " -> ", 4);
buf_offset += 4;
break;
default:
- g_strlcat(line_bufp + buf_offset, " ", 5);
+ put_string(line_bufp + buf_offset, " ", 1);
buf_offset += 1;
break;
}
case COL_DEF_NET_DST:
case COL_RES_NET_DST:
case COL_UNRES_NET_DST:
- g_strlcat(line_bufp + buf_offset, " -> ", 5);
+ put_string(line_bufp + buf_offset, " -> ", 4);
buf_offset += 4;
break;
default:
- g_strlcat(line_bufp + buf_offset, " ", 5);
+ put_string(line_bufp + buf_offset, " ", 1);
buf_offset += 1;
break;
}
case COL_DEF_SRC:
case COL_RES_SRC:
case COL_UNRES_SRC:
- g_strlcat(line_bufp + buf_offset, " <- ", 5);
+ put_string(line_bufp + buf_offset, " <- ", 4);
buf_offset += 4;
break;
default:
- g_strlcat(line_bufp + buf_offset, " ", 5);
+ put_string(line_bufp + buf_offset, " ", 1);
buf_offset += 1;
break;
}
case COL_DEF_DL_SRC:
case COL_RES_DL_SRC:
case COL_UNRES_DL_SRC:
- g_strlcat(line_bufp + buf_offset, " <- ", 5);
+ put_string(line_bufp + buf_offset, " <- ", 4);
buf_offset += 4;
break;
default:
- g_strlcat(line_bufp + buf_offset, " ", 5);
+ put_string(line_bufp + buf_offset, " ", 1);
buf_offset += 1;
break;
}
case COL_DEF_NET_SRC:
case COL_RES_NET_SRC:
case COL_UNRES_NET_SRC:
- g_strlcat(line_bufp + buf_offset, " <- ", 5);
+ put_string(line_bufp + buf_offset, " <- ", 4);
buf_offset += 4;
break;
default:
- g_strlcat(line_bufp + buf_offset, " ", 5);
+ put_string(line_bufp + buf_offset, " ", 1);
buf_offset += 1;
break;
}
break;
default:
- g_strlcat(line_bufp + buf_offset, " ", 5);
+ put_string(line_bufp + buf_offset, " ", 1);
buf_offset += 1;
break;
}
}
cf_status_t
-cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
+cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_tempfile, int *err)
{
wtap *wth;
gchar *err_info;
char err_msg[2048+1];
- wth = wtap_open_offline(fname, err, &err_info, perform_two_pass_analysis);
+ wth = wtap_open_offline(fname, type, err, &err_info, perform_two_pass_analysis);
if (wth == NULL)
goto fail;
/* The open succeeded. Fill in the information for this file. */
- /* Cleanup all data structures used for dissection. */
- cleanup_dissection();
- /* Initialize all data structures used for dissection. */
- init_dissection();
+ /* Create new epan session for dissection. */
+ epan_free(cf->epan);
+ cf->epan = tshark_epan_new(cf);
cf->wth = wth;
cf->f_datalen = 0; /* not used, but set it anyway */
/* No user changes yet. */
cf->unsaved_changes = FALSE;
- cf->cd_t = wtap_file_type(cf->wth);
+ cf->cd_t = wtap_file_type_subtype(cf->wth);
cf->count = 0;
cf->drops_known = FALSE;
cf->drops = 0;
} else
cf->has_snap = TRUE;
nstime_set_zero(&cf->elapsed_time);
- nstime_set_unset(&first_ts);
+ ref = NULL;
prev_dis = NULL;
prev_cap = NULL;
/* Seen only when opening a capture file for writing. */
g_snprintf(errmsg_errno, sizeof(errmsg_errno),
"The file \"%%s\" is a pipe, and \"%s\" capture files can't be "
- "written to a pipe.", wtap_file_type_short_string(file_type));
+ "written to a pipe.", wtap_file_type_subtype_short_string(file_type));
errmsg = errmsg_errno;
break;
if (for_writing) {
g_snprintf(errmsg_errno, sizeof(errmsg_errno),
"TShark can't save this capture as a \"%s\" file.",
- wtap_file_type_short_string(file_type));
+ wtap_file_type_subtype_short_string(file_type));
} else {
g_snprintf(errmsg_errno, sizeof(errmsg_errno),
"The file \"%%s\" is a capture for a network type that TShark doesn't support.\n"
if (for_writing) {
g_snprintf(errmsg_errno, sizeof(errmsg_errno),
"TShark can't save this capture as a \"%s\" file.",
- wtap_file_type_short_string(file_type));
+ wtap_file_type_subtype_short_string(file_type));
errmsg = errmsg_errno;
} else
errmsg = "The file \"%s\" is a capture for a network type that TShark doesn't support.";