*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#endif
#include <glib.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 <epan/timestamp.h>
#include <epan/packet.h>
#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 "util.h"
+#include "ui/util.h"
#include "clopts_common.h"
-#include "console_io.h"
#include "cmdarg_err.h"
#include "version_info.h"
#include <epan/plugins.h>
#include "capture-wpcap.h"
#include <wsutil/unicode-utils.h>
#endif /* _WIN32 */
+#include "capture_session.h"
#include "capture_sync.h"
+#include "capture_opts.h"
#endif /* HAVE_LIBPCAP */
#include "log.h"
#include <epan/funnel.h>
-#include "capture_opts.h"
/*
* This is the template for the decode as option; it is shared between the
static const gchar decode_as_arg_template[] = "<layer_type>==<selector>,<decode_as_protocol>";
static guint32 cum_bytes;
-static nstime_t first_ts;
-static nstime_t prev_dis_ts;
-static nstime_t prev_cap_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;
+static frame_data prev_cap_frame;
-static gboolean print_packet_info; /* TRUE if we're to print packet information */
+static const char* prev_display_dissector_name = NULL;
static gboolean perform_two_pass_analysis;
} output_action_e;
static output_action_e output_action;
-static gboolean do_dissection; /* TRUE if we have to dissect each packet */
-static gboolean verbose;
-static gboolean print_hex;
+static gboolean do_dissection; /* TRUE if we have to dissect each packet */
+static gboolean print_packet_info; /* TRUE if we're to print packet information */
+static gint print_summary = -1; /* TRUE if we're to print packet summary information */
+static gboolean print_details; /* TRUE if we're to print packet details information */
+static gboolean print_hex; /* TRUE if we're to print hex/ascci information */
static gboolean line_buffered;
+static gboolean really_quiet = FALSE;
static print_format_e print_format = PR_FMT_TEXT;
static print_stream_t *print_stream;
static output_fields_t* output_fields = NULL;
/* The line separator used between packets, changeable via the -S option */
-static char *separator = "";
+static const char *separator = "";
#ifdef HAVE_LIBPCAP
/*
* TRUE if we're to print packet counts to keep track of captured packets.
*/
-static gboolean print_packet_counts;
+static gboolean print_packet_counts = TRUE;
static capture_options global_capture_opts;
+static capture_session global_capture_session;
#ifdef SIGINFO
static gboolean infodelay; /* if TRUE, don't print capture info in SIGINFO handler */
static int load_cap_file(capture_file *, char *, int, gboolean, int, gint64);
static gboolean process_packet(capture_file *cf, gint64 offset,
- const struct wtap_pkthdr *whdr, union wtap_pseudo_header *pseudo_header,
- const guchar *pd, gboolean filtering_tap_listeners, guint tap_flags);
+ struct wtap_pkthdr *whdr, const guchar *pd,
+ gboolean filtering_tap_listeners, 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);
static void
list_capture_types(void) {
- int i;
+ int i;
struct string_elem *captypes;
- GSList *list = NULL;
+ GSList *list = NULL;
- captypes = g_malloc(sizeof(struct string_elem) * WTAP_NUM_FILE_TYPES);
+ captypes = g_new(struct string_elem, WTAP_NUM_FILE_TYPES);
fprintf(stderr, "tshark: The available capture file types for the \"-F\" flag are:\n");
for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) {
fprintf(output, " -I capture in monitor mode, if available\n");
#endif
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
- fprintf(output, " -B <buffer size> size of kernel buffer (def: 1MB)\n");
+ fprintf(output, " -B <buffer size> size of kernel buffer (def: %dMB)\n", DEFAULT_CAPTURE_BUFFER_SIZE);
#endif
fprintf(output, " -y <link type> link layer type (def: first appropriate)\n");
fprintf(output, " -D print list of interfaces and exit\n");
fprintf(output, " filesize:NUM - switch to next file after NUM KB\n");
fprintf(output, " files:NUM - ringbuffer: replace after NUM files\n");
#endif /* HAVE_LIBPCAP */
-
+#ifdef HAVE_PCAP_REMOTE
+ fprintf(output, "RPCAP options:\n");
+ fprintf(output, " -A <user>:<password> use RPCAP password authentication\n");
+#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, "\n");
fprintf(output, "Processing:\n");
fprintf(output, " -2 perform a two-pass analysis\n");
- fprintf(output, " -R <read filter> packet filter in Wireshark display filter syntax\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, " -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, " -V add output of packet tree (Packet Details)\n");
fprintf(output, " -O <protocols> Only show packet details of these protocols, comma\n");
fprintf(output, " separated\n");
- fprintf(output, " -P print packets even when writing to a file\n");
+ fprintf(output, " -P print packet summary even when writing to a file\n");
fprintf(output, " -S <separator> the line separator to print between packets\n");
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);\n");
+ fprintf(output, " -e <field> field to print if -Tfields selected (e.g. tcp.port, 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, " -Q only log true errors to stderr (quieter than -q)\n");
+ fprintf(output, " -g enable group read access on the output file(s)\n");
fprintf(output, " -W n Save extra information in the file, if supported.\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, "Usage: tshark -G [report]\n");
fprintf(output, "\n");
fprintf(output, "Glossary table reports:\n");
- fprintf(output, " -G [fields] dump glossary in original format and exit\n");
- fprintf(output, " -G fields2 dump glossary in format 2 and exit\n");
- fprintf(output, " -G fields3 dump glossary in format 3 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 defaultprefs dump default preferences and exit\n");
fprintf(output, " -G currentprefs dump current preferences and exit\n");
fprintf(output, "\n");
-
}
/*
display_dissector_table_names(const char *table_name, const char *ui_name,
gpointer output)
{
- fprintf((FILE *)output, "\t%s (%s)\n", table_name, ui_name);
+ if ((prev_display_dissector_name == NULL) ||
+ (strcmp(prev_display_dissector_name, table_name) != 0)) {
+ fprintf((FILE *)output, "\t%s (%s)\n", table_name, ui_name);
+ prev_display_dissector_name = table_name;
+ }
}
/*
static void
display_dissector_names(const gchar *table _U_, gpointer handle, gpointer output)
{
- int proto_id;
- const gchar* proto_filter_name;
- const gchar* proto_ui_name;
+ int proto_id;
+ const gchar *proto_filter_name;
+ const gchar *proto_ui_name;
proto_id = dissector_handle_get_protocol_index((dissector_handle_t)handle);
g_assert(proto_filter_name != NULL);
g_assert(proto_ui_name != NULL);
- fprintf((FILE *)output, "\t%s (%s)\n",
- proto_filter_name,
- proto_ui_name);
+ if ((prev_display_dissector_name == NULL) ||
+ (strcmp(prev_display_dissector_name, proto_filter_name) != 0)) {
+ fprintf((FILE *)output, "\t%s (%s)\n",
+ proto_filter_name,
+ proto_ui_name);
+ prev_display_dissector_name = proto_filter_name;
+ }
}
}
find_protocol_name_func(const gchar *table _U_, gpointer handle, gpointer user_data)
{
- int proto_id;
- const gchar *protocol_filter_name;
- protocol_name_search_t search_info;
+ int proto_id;
+ const gchar *protocol_filter_name;
+ protocol_name_search_t search_info;
g_assert(handle);
}
}
+/*
+ * Allow dissector key names to be sorted alphabetically
+ */
+
+static gint
+compare_dissector_key_name(gconstpointer dissector_a, gconstpointer dissector_b)
+{
+ return strcmp((const char*)dissector_a, (const char*)dissector_b);
+}
+
/*
* Print all layer type names supported.
* We send the output to the stream described by the handle output.
fprint_all_layer_types(FILE *output)
{
- dissector_all_tables_foreach_table(display_dissector_table_names, (gpointer)output);
+ prev_display_dissector_name = NULL;
+ dissector_all_tables_foreach_table(display_dissector_table_names, (gpointer)output, (GCompareFunc)compare_dissector_key_name);
}
/*
fprint_all_protocols_for_layer_types(FILE *output, gchar *table_name)
{
+ prev_display_dissector_name = NULL;
dissector_table_foreach_handle(table_name,
display_dissector_names,
(gpointer)output);
add_decode_as(const gchar *cl_param)
{
gchar *table_name;
- guint32 selector;
+ guint32 selector, selector2;
gchar *decoded_param;
gchar *remaining_param;
gchar *selector_str;
dissector_table_t table_matching;
ftenum_t dissector_table_selector_type;
struct protocol_name_search user_protocol_name;
+ guint64 i;
+ char op;
/* The following code will allocate and copy the command-line options in a string pointed by decoded_param */
/* The selector for this table is an unsigned number. Parse it as such.
There's no need to remove leading and trailing spaces from the
selector number string, because sscanf will do that for us. */
- if ( sscanf(selector_str, "%u", &selector) != 1 ) {
- cmdarg_err("Invalid selector number \"%s\"", selector_str);
- g_free(decoded_param);
- return FALSE;
+ switch (sscanf(selector_str, "%u%c%u", &selector, &op, &selector2)) {
+ case 1:
+ op = '\0';
+ break;
+ case 3:
+ if (op != ':' && op != '-') {
+ cmdarg_err("Invalid selector numeric range \"%s\"", selector_str);
+ g_free(decoded_param);
+ return FALSE;
+ }
+ if (op == ':') {
+ if ((selector2 == 0) || ((guint64)selector + selector2 - 1) > G_MAXUINT32) {
+ cmdarg_err("Invalid selector numeric range \"%s\"", selector_str);
+ g_free(decoded_param);
+ return FALSE;
+ }
+ }
+ else if (selector2 < selector) {
+ /* We could swap them for the user, but maybe it's better to call
+ * this out as an error in case it's not what was intended? */
+ cmdarg_err("Invalid selector numeric range \"%s\"", selector_str);
+ g_free(decoded_param);
+ return FALSE;
+ }
+ break;
+ default:
+ cmdarg_err("Invalid selector number \"%s\"", selector_str);
+ g_free(decoded_param);
+ return FALSE;
}
break;
case FT_UINT24:
case FT_UINT32:
/* The selector for this table is an unsigned number. */
- dissector_change_uint(table_name, selector, dissector_matching);
+ if (op == '\0') {
+ dissector_change_uint(table_name, selector, dissector_matching);
+ } else if (op == ':') {
+ for (i = selector; i < (guint64)selector + selector2; i++) {
+ dissector_change_uint(table_name, (guint32)i, dissector_matching);
+ }
+ } else { /* op == '-' */
+ for (i = selector; i <= selector2; i++) {
+ dissector_change_uint(table_name, (guint32)i, dissector_matching);
+ }
+ }
break;
case FT_STRING:
ERROR and CRITICAL level messages so the current code is a behavioral
change. The current behavior is the same as in Wireshark.
*/
- if((log_level & G_LOG_LEVEL_MASK & prefs.console_log_level) == 0 &&
+ if ((log_level & G_LOG_LEVEL_MASK & prefs.console_log_level) == 0 &&
prefs.console_log_level != 0) {
return;
}
static void
print_current_user(void) {
gchar *cur_user, *cur_group;
+
if (started_with_special_privs()) {
cur_user = get_cur_username();
cur_group = get_cur_groupname();
int
main(int argc, char *argv[])
{
+ GString *comp_info_str;
+ GString *runtime_info_str;
char *init_progfile_dir_error;
int opt;
gboolean arg_error = FALSE;
int status;
GList *if_list;
gchar *err_str;
- guint i;
- interface_options interface_opts;
#else
gboolean capture_option_specified = FALSE;
#endif
volatile gboolean out_file_name_res = FALSE;
gchar *volatile cf_name = NULL;
gchar *rfilter = NULL;
+ gchar *dfilter = NULL;
#ifdef HAVE_PCAP_OPEN_DEAD
struct bpf_program fcode;
#endif
dfilter_t *rfcode = NULL;
+ dfilter_t *dfcode = NULL;
e_prefs *prefs_p;
char badopt;
- GLogLevelFlags log_flags;
+ int log_flags;
int optind_initial;
gchar *output_only = NULL;
+#ifdef HAVE_PCAP_REMOTE
+#define OPTSTRING_A "A:"
+#else
+#define OPTSTRING_A ""
+#endif
#ifdef HAVE_LIBPCAP
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
#define OPTSTRING_B "B:"
#define OPTSTRING_I ""
#endif
-#define OPTSTRING "2a:A:b:" OPTSTRING_B "c:C:d:De:E:f:F:G:hH:i:" OPTSTRING_I "K:lLnN:o:O:pPqr:R:s:S:t:T:u:vVw:W:xX:y:z:"
+#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;
+ /* Assemble the compile-time version information string */
+ comp_info_str = g_string_new("Compiled ");
+ get_compiled_version_info(comp_info_str, NULL, epan_get_compiled_version_info);
+
+ /* Assemble the run-time version information string */
+ runtime_info_str = g_string_new("Running ");
+ get_runtime_version_info(runtime_info_str, NULL);
+
+ /* Add it to the information to be reported on a crash. */
+ ws_add_crash_info("TShark " VERSION "%s\n"
+ "\n"
+ "%s"
+ "\n"
+ "%s",
+ wireshark_svnversion, comp_info_str->str, runtime_info_str->str);
+
#ifdef _WIN32
arg_list_utf_16to8(argc, argv);
+ create_app_running_mutex();
#if !GLIB_CHECK_VERSION(2,31,0)
g_thread_init(NULL);
#endif
return 1;
}
break;
+ case 'P': /* Print packet summary info even when writing to a file */
+ print_packet_info = TRUE;
+ print_summary = TRUE;
+ break;
+ case 'O': /* Only output these protocols */
+ output_only = g_strdup(optarg);
+ /* FALLTHROUGH */
+ case 'V': /* Verbose */
+ print_details = TRUE;
+ print_packet_info = TRUE;
+ break;
+ case 'x': /* Print packet data in hex (and ASCII) */
+ print_hex = TRUE;
+ /* The user asked for hex output, so let's ensure they get it,
+ * even if they're writing to a file.
+ */
+ print_packet_info = TRUE;
+ break;
case 'X':
ex_opt_add(optarg);
break;
}
}
+ /*
+ * Print packet summary information is the default, unless either -V or -x
+ * were specified and -P was not. Note that this is new behavior, which
+ * allows for the possibility of printing only hex/ascii output without
+ * necessarily requiring that either the summary or details be printed too.
+ */
+ if (print_summary == -1)
+ print_summary = (print_details || print_hex) ? FALSE : TRUE;
+
optind = optind_initial;
opterr = 1;
G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
g_log_set_handler(NULL,
- log_flags,
+ (GLogLevelFlags)log_flags,
tshark_log_handler, NULL /* user_data */);
g_log_set_handler(LOG_DOMAIN_MAIN,
- log_flags,
+ (GLogLevelFlags)log_flags,
tshark_log_handler, NULL /* user_data */);
#ifdef HAVE_LIBPCAP
g_log_set_handler(LOG_DOMAIN_CAPTURE,
- log_flags,
+ (GLogLevelFlags)log_flags,
tshark_log_handler, NULL /* user_data */);
g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
- log_flags,
+ (GLogLevelFlags)log_flags,
tshark_log_handler, NULL /* user_data */);
#endif
initialize_funnel_ops();
#ifdef HAVE_LIBPCAP
- capture_opts_init(&global_capture_opts, &cfile);
+ capture_opts_init(&global_capture_opts);
+ capture_session_init(&global_capture_session, (void *)&cfile);
#endif
timestamp_set_type(TS_RELATIVE);
#endif
register_all_tap_listeners();
- /* Now register the preferences for any non-dissector modules.
- We must do that before we read the preferences as well. */
- prefs_register_modules();
-
/* If invoked with the "-G" flag, we dump out information based on
the argument to the "-G" flag; if no argument is specified,
for backwards compatibility we dump out a glossary of display
proto_initialize_all_prefixes();
if (argc == 2)
- proto_registrar_dump_fields(1);
+ proto_registrar_dump_fields();
else {
if (strcmp(argv[2], "fields") == 0)
- proto_registrar_dump_fields(1);
- else if (strcmp(argv[2], "fields2") == 0)
- proto_registrar_dump_fields(2);
- else if (strcmp(argv[2], "fields3") == 0)
- proto_registrar_dump_fields(3);
+ proto_registrar_dump_fields();
else if (strcmp(argv[2], "protocols") == 0)
proto_registrar_dump_protocols();
else if (strcmp(argv[2], "values") == 0)
pf_path = NULL;
}
- /* Set the name resolution code's flags from the preferences. */
- gbl_resolv_flags = prefs_p->name_resolve;
-
/* Read the disabled protocols file. */
read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
&dp_path, &dp_open_errno, &dp_read_errno);
case 'b': /* Ringbuffer option */
case 'c': /* Capture x packets */
case 'f': /* capture filter */
+ case 'g': /* enable group read access on file(s) */
case 'i': /* Use interface x */
case 'p': /* Don't capture in promiscuous mode */
+#ifdef HAVE_PCAP_REMOTE
+ case 'A': /* Authentication */
+#endif
#ifdef HAVE_PCAP_CREATE
case 'I': /* Capture in monitor mode, if available */
#endif
#endif /* _WIN32 or HAVE_PCAP_CREATE */
#ifdef HAVE_LIBPCAP
status = capture_opts_add_opt(&global_capture_opts, opt, optarg, &start_capture);
- if(status != 0) {
+ if (status != 0) {
return status;
}
#else
#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 'E':
/* Field option */
- if(!output_fields_set_option(output_fields, optarg)) {
+ if (!output_fields_set_option(output_fields, optarg)) {
cmdarg_err("\"%s\" is not a valid field output option=value pair.", optarg);
output_fields_list_options(stderr);
return 1;
break;
case 'W': /* Select extra information to save in our capture file */
/* This is patterned after the -N flag which may not be the best idea. */
- if (strchr(optarg, 'n'))
+ if (strchr(optarg, 'n')) {
out_file_name_res = TRUE;
+ } else {
+ cmdarg_err("Invalid -W argument \"%s\"", optarg);
+ return 1;
+ }
break;
case 'H': /* Read address to name mappings from a hosts file */
- if (! read_hosts_file(optarg))
+ if (! add_hosts_file(optarg))
{
cmdarg_err("Can't read host entries from \"%s\"", optarg);
return 1;
#endif
break;
case 'n': /* No name resolution */
- gbl_resolv_flags = RESOLV_NONE;
+ gbl_resolv_flags.mac_name = FALSE;
+ gbl_resolv_flags.network_name = FALSE;
+ gbl_resolv_flags.transport_name = FALSE;
+ gbl_resolv_flags.concurrent_dns = FALSE;
break;
case 'N': /* Select what types of addresses/port #s to resolve */
- if (gbl_resolv_flags == RESOLV_ALL)
- gbl_resolv_flags = RESOLV_NONE;
badopt = string_to_name_resolve(optarg, &gbl_resolv_flags);
if (badopt != '\0') {
cmdarg_err("-N specifies unknown resolving option '%c';",
case 'q': /* Quiet */
quiet = TRUE;
break;
+ case 'Q': /* Really quiet */
+ quiet = TRUE;
+ really_quiet = TRUE;
+ break;
case 'r': /* Read capture file x */
cf_name = g_strdup(optarg);
break;
case 'R': /* Read file filter */
rfilter = optarg;
break;
- case 'P': /* Print packets even when writing to a file */
- print_packet_info = TRUE;
- break;
+ case 'P':
+ /* already processed; just ignore it now */
+ break;
case 'S': /* Set the line Separator to be printed between packets */
separator = strdup(optarg);
break;
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_cont("It must be \"a\" for absolute, \"ad\" for absolute with date, \"d\" for delta,");
+ cmdarg_err_cont("\"dd\" for delta displayed, \"e\" for epoch, \"r\" for relative, \"u\" for UTC, ");
+ cmdarg_err_cont("or \"ud\" for UTC with date.");
return 1;
}
break;
print_format = PR_FMT_PS;
} else if (strcmp(optarg, "pdml") == 0) {
output_action = WRITE_XML;
- verbose = TRUE;
+ print_details = TRUE; /* Need details */
+ print_summary = FALSE; /* Don't allow summary */
} else if (strcmp(optarg, "psml") == 0) {
output_action = WRITE_XML;
- verbose = FALSE;
- } else if(strcmp(optarg, "fields") == 0) {
+ print_details = FALSE; /* Don't allow details */
+ print_summary = TRUE; /* Need summary */
+ } else if (strcmp(optarg, "fields") == 0) {
output_action = WRITE_FIELDS;
- verbose = TRUE; /* Need full tree info */
+ 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\".");
break;
case 'v': /* Show version and exit */
{
- GString *comp_info_str;
- GString *runtime_info_str;
- /* Assemble the compile-time version information string */
- comp_info_str = g_string_new("Compiled ");
- get_compiled_version_info(comp_info_str, NULL, epan_get_compiled_version_info);
-
- /* Assemble the run-time version information string */
- runtime_info_str = g_string_new("Running ");
- get_runtime_version_info(runtime_info_str, NULL);
show_version(comp_info_str, runtime_info_str);
g_string_free(comp_info_str, TRUE);
g_string_free(runtime_info_str, TRUE);
+ /* We don't really have to cleanup here, but it's a convenient way to test
+ * start-up and shut-down of the epan library without any UI-specific
+ * cruft getting in the way. Makes the results of running
+ * $ ./tools/valgrind-wireshark -n
+ * much more useful. */
+ epan_cleanup();
return 0;
- break;
}
case 'O': /* Only output these protocols */
- output_only = g_strdup(optarg);
- /* FALLTHROUGH */
+ /* already processed; just ignore it now */
+ break;
case 'V': /* Verbose */
- verbose = TRUE;
- /* The user asked for a verbose output, so let's ensure they get it,
- * even if they're writing to a file.
- */
- print_packet_info = TRUE;
+ /* already processed; just ignore it now */
break;
case 'x': /* Print packet data in hex (and ASCII) */
- print_hex = TRUE;
- /* The user asked for hex output, so let's ensure they get it,
- * even if they're writing to a file.
- */
- print_packet_info = TRUE;
+ /* already processed; just ignore it now */
break;
case 'X':
break;
+ case 'Y':
+ dfilter = optarg;
+ break;
case 'z':
/* We won't call the init function for the stat this soon
as it would disallow MATE's fields (which are registered
part of a tap filter. Instead, we just add the argument
to a list of stat arguments. */
if (!process_stat_cmd_arg(optarg)) {
- cmdarg_err("invalid -z argument.");
+ if (strcmp("help", optarg)==0) {
+ fprintf(stderr, "tshark: The available statistics for the \"-z\" option are:\n");
+ list_stat_cmd_args();
+ return 0;
+ }
+ cmdarg_err("Invalid -z argument \"%s\".", optarg);
cmdarg_err_cont(" -z argument must be one of :");
list_stat_cmd_args();
return 1;
}
/* If we specified output fields, but not the output field type... */
- if(WRITE_FIELDS != output_action && 0 != output_fields_num_fields(output_fields)) {
+ if (WRITE_FIELDS != output_action && 0 != output_fields_num_fields(output_fields)) {
cmdarg_err("Output fields were specified with \"-e\", "
"but \"-Tfields\" was not specified.");
return 1;
- } else if(WRITE_FIELDS == output_action && 0 == output_fields_num_fields(output_fields)) {
+ } else if (WRITE_FIELDS == output_action && 0 == output_fields_num_fields(output_fields)) {
cmdarg_err("\"-Tfields\" was specified, but no fields were "
"specified with \"-e\".");
return 1;
}
- /* If no capture filter or read filter has been specified, and there are
+ /* If no capture filter or display filter has been specified, and there are
still command-line arguments, treat them as the tokens of a capture
- filter (if no "-r" flag was specified) or a read filter (if a "-r"
+ filter (if no "-r" flag was specified) or a display filter (if a "-r"
flag was specified. */
if (optind < argc) {
if (cf_name != NULL) {
- if (rfilter != NULL) {
- cmdarg_err("Read filters were specified both with \"-R\" "
+ if (dfilter != NULL) {
+ cmdarg_err("Display filters were specified both with \"-d\" "
"and with additional command-line arguments.");
return 1;
}
- rfilter = get_args_as_string(argc, argv, optind);
+ dfilter = get_args_as_string(argc, argv, optind);
} else {
#ifdef HAVE_LIBPCAP
+ guint i;
+
if (global_capture_opts.default_options.cfilter) {
cmdarg_err("A default capture filter was specified both with \"-f\""
" and with additional command-line arguments.");
return 1;
}
for (i = 0; i < global_capture_opts.ifaces->len; i++) {
+ interface_options interface_opts;
interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
if (interface_opts.cfilter == NULL) {
interface_opts.cfilter = get_args_as_string(argc, argv, optind);
if (output_only != NULL) {
char *ps;
- if (!verbose) {
+ if (!print_details) {
cmdarg_err("-O requires -V");
return 1;
}
}
}
+ 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.");
+ }
+
#ifdef HAVE_LIBPCAP
if (list_link_layer_types) {
/* We're supposed to list the link-layer types for an interface;
return 1;
}
}
- /* Currently, we don't support read filters when capturing
+ /* Currently, we don't support read or display filters when capturing
and saving the packets. */
if (rfilter != NULL) {
cmdarg_err("Read filters aren't supported when capturing and saving the captured packets.");
return 1;
}
+ if (dfilter != NULL) {
+ cmdarg_err("Display filters aren't supported when capturing and saving the captured packets.");
+ return 1;
+ }
} else {
/* They didn't specify a "-w" flag, so we won't be saving to a
capture file. Check for options that only make sense if
if (pc != NULL) {
if (pcap_compile(pc, &fcode, rfilter, 0, 0) != -1) {
cmdarg_err_cont(
- " Note: That display filter code looks like a valid capture filter;");
+ " Note: That read filter code looks like a valid capture filter;");
cmdarg_err_cont(
" maybe you mixed them up?");
}
}
cfile.rfcode = rfcode;
+ if (dfilter != NULL) {
+ if (!dfilter_compile(dfilter, &dfcode)) {
+ cmdarg_err("%s", dfilter_error_msg);
+ epan_cleanup();
+#ifdef HAVE_PCAP_OPEN_DEAD
+ {
+ pcap_t *pc;
+
+ pc = pcap_open_dead(DLT_EN10MB, MIN_PACKET_SIZE);
+ 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(
+ " maybe you mixed them up?");
+ }
+ pcap_close(pc);
+ }
+ }
+#endif
+ return 2;
+ }
+ }
+ cfile.dfcode = dfcode;
+
if (print_packet_info) {
/* If we're printing as text or PostScript, we have
to create a print stream. */
we're using a read filter on the packets;
+ we're using a display filter on the packets;
+
we're using any taps that need dissection. */
- do_dissection = print_packet_info || rfcode || tap_listeners_require_dissection();
+ do_dissection = print_packet_info || rfcode || dfcode || tap_listeners_require_dissection();
if (cf_name) {
/*
}
} else {
/* No capture file specified, so we're supposed to do a live capture
- (or get a list of link-layer types for a live capture device);
+ or get a list of link-layer types for a live capture device;
do we have support for live captures? */
#ifdef HAVE_LIBPCAP
- /* trim the interface name and exit if that failed */
- if (!capture_opts_trim_iface(&global_capture_opts,
- (prefs_p->capture_device) ? get_if_name(prefs_p->capture_device) : NULL)) {
- return 2;
- }
+ /* if no interface was specified, pick a default */
+ exit_status = capture_opts_default_iface_if_necessary(&global_capture_opts,
+ ((prefs_p->capture_device) && (*prefs_p->capture_device != '\0')) ? get_if_name(prefs_p->capture_device) : NULL);
+ if (exit_status != 0)
+ return exit_status;
/* if requested, list the link layer types and exit */
if (list_link_layer_types) {
guint i;
- interface_options interface_opts;
/* Get the list of link-layer types for the capture devices. */
for (i = 0; i < global_capture_opts.ifaces->len; i++) {
- 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);
- if (caps == NULL) {
- cmdarg_err("%s", err_str);
- g_free(err_str);
- return 2;
- }
- if (caps->data_link_types == NULL) {
- cmdarg_err("The capture device \"%s\" has no data link types.", interface_opts.name);
- return 2;
- }
- capture_opts_print_if_capabilities(caps, interface_opts.name, interface_opts.monitor_mode);
- free_if_capabilities(caps);
+ interface_options interface_opts;
+ 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, NULL);
+ if (caps == NULL) {
+ cmdarg_err("%s", err_str);
+ g_free(err_str);
+ return 2;
+ }
+ if (caps->data_link_types == NULL) {
+ cmdarg_err("The capture device \"%s\" has no data link types.", interface_opts.name);
+ return 2;
+ }
+ capture_opts_print_if_capabilities(caps, interface_opts.name, interface_opts.monitor_mode);
+ free_if_capabilities(caps);
}
return 0;
}
* Instead, pass on the exit status from the capture child.
*/
capture();
- exit_status = global_capture_opts.fork_child_status;
+ exit_status = global_capture_session.fork_child_status;
if (print_packet_info) {
if (!write_finale()) {
typedef gboolean (*pipe_input_cb_t) (gint source, gpointer user_data);
typedef struct pipe_input_tag {
- gint source;
- gpointer user_data;
- int *child_process;
- pipe_input_cb_t input_cb;
- guint pipe_input_id;
+ gint source;
+ gpointer user_data;
+ int *child_process;
+ pipe_input_cb_t input_cb;
+ guint pipe_input_id;
#ifdef _WIN32
- GMutex *callback_running;
+ GMutex *callback_running;
#endif
} pipe_input_t;
static gint
pipe_timer_cb(gpointer data)
{
- HANDLE handle;
- DWORD avail = 0;
- gboolean result, result1;
- DWORD childstatus;
+ HANDLE handle;
+ DWORD avail = 0;
+ gboolean result;
+ DWORD childstatus;
pipe_input_t *pipe_input_p = data;
- gint iterations = 0;
+ gint iterations = 0;
g_mutex_lock (pipe_input_p->callback_running);
result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL);
/* Get the child process exit status */
- result1 = GetExitCodeProcess((HANDLE)*(pipe_input_p->child_process),
- &childstatus);
+ GetExitCodeProcess((HANDLE)*(pipe_input_p->child_process),
+ &childstatus);
/* If the Peek returned an error, or there are bytes to be read
or the childwatcher thread has terminated then call the normal
#endif
}
+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;
+}
+
+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;
+
+ return epan;
+}
#ifdef HAVE_LIBPCAP
static gboolean
capture(void)
{
- gboolean ret;
- guint i;
- GString *str = g_string_new("");
+ gboolean ret;
+ guint i;
+ GString *str = g_string_new("");
#ifdef USE_TSHARK_SELECT
- fd_set readfds;
+ fd_set readfds;
#endif
#ifndef _WIN32
- struct sigaction action, oldaction;
+ struct sigaction action, oldaction;
#endif
/*
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. */
the capture child to finish; it will report that it finished,
or will exit abnormally, so we'll stop reading from the sync
pipe, pick up the exit status, and quit. */
+ memset(&action, 0, sizeof(action));
action.sa_handler = capture_cleanup;
action.sa_flags = SA_RESTART;
sigemptyset(&action.sa_mask);
#endif /* SIGINFO */
#endif /* _WIN32 */
- global_capture_opts.state = CAPTURE_PREPARING;
+ global_capture_session.state = CAPTURE_PREPARING;
/* Let the user know which interfaces were chosen. */
for (i = 0; i < global_capture_opts.ifaces->len; i++) {
g_string_append_printf(str, "and ");
}
}
- g_string_append_printf(str, "%s", interface_opts.descr);
+ g_string_append_printf(str, "'%s'", interface_opts.descr);
}
} else {
g_string_append_printf(str, "%u interfaces", global_capture_opts.ifaces->len);
}
- fprintf(stderr, "Capturing on %s\n", str->str);
+ if (really_quiet == FALSE)
+ fprintf(stderr, "Capturing on %s\n", str->str);
+ fflush(stderr);
g_string_free(str, TRUE);
- ret = sync_pipe_start(&global_capture_opts);
+ 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_options *capture_opts _U_, char *error_msg, char *secondary_error_msg)
+capture_input_error_message(capture_session *cap_session _U_, char *error_msg, char *secondary_error_msg)
{
cmdarg_err("%s", error_msg);
cmdarg_err_cont("%s", secondary_error_msg);
/* capture child detected an capture filter related error */
void
-capture_input_cfilter_error_message(capture_options *capture_opts, guint i, char *error_message)
+capture_input_cfilter_error_message(capture_session *cap_session, guint i, char *error_message)
{
- dfilter_t *rfcode = NULL;
- interface_options interface_opts;
+ capture_options *capture_opts = cap_session->capture_opts;
+ dfilter_t *rfcode = NULL;
+ interface_options interface_opts;
g_assert(i < capture_opts->ifaces->len);
interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
/* capture child tells us we have a new (or the first) capture file */
gboolean
-capture_input_new_file(capture_options *capture_opts, gchar *new_file)
+capture_input_new_file(capture_session *cap_session, gchar *new_file)
{
+ capture_options *capture_opts = cap_session->capture_opts;
gboolean is_tempfile;
- int err;
+ int err;
- if(capture_opts->state == CAPTURE_PREPARING) {
+ if (cap_session->state == CAPTURE_PREPARING) {
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture started!");
}
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "File: \"%s\"", new_file);
- g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
+ g_assert(cap_session->state == CAPTURE_PREPARING || cap_session->state == CAPTURE_RUNNING);
/* free the old filename */
if (capture_opts->save_file != NULL) {
/* we start a new capture file, close the old one (if we had one before) */
- if( ((capture_file *) capture_opts->cf)->state != FILE_CLOSED) {
- if ( ((capture_file *) capture_opts->cf)->wth != NULL) {
- wtap_close(((capture_file *) capture_opts->cf)->wth);
+ 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 *) capture_opts->cf)->state = FILE_CLOSED;
+ ((capture_file *) cap_session->cf)->state = FILE_CLOSED;
}
g_free(capture_opts->save_file);
capture_opts->save_file = g_strdup(new_file);
/* if we are in real-time mode, open the new file now */
- if(do_dissection) {
+ if (do_dissection) {
/* Attempt to open the capture file and set up to read from it. */
- switch(cf_open(capture_opts->cf, capture_opts->save_file, is_tempfile, &err)) {
+ switch(cf_open((capture_file *)cap_session->cf, capture_opts->save_file, is_tempfile, &err)) {
case CF_OK:
break;
case CF_ERROR:
}
}
- capture_opts->state = CAPTURE_RUNNING;
+ cap_session->state = CAPTURE_RUNNING;
return TRUE;
}
/* capture child tells us we have new packets to read */
void
-capture_input_new_packets(capture_options *capture_opts, int to_read)
+capture_input_new_packets(capture_session *cap_session, int to_read)
{
- gboolean ret;
- int err;
+ gboolean ret;
+ int err;
gchar *err_info;
- gint64 data_offset;
- capture_file *cf = capture_opts->cf;
- gboolean filtering_tap_listeners;
- guint tap_flags;
+ gint64 data_offset;
+ capture_file *cf = (capture_file *)cap_session->cf;
+ gboolean filtering_tap_listeners;
+ guint tap_flags;
#ifdef SIGINFO
/*
/* Get the union of the flags for all tap listeners. */
tap_flags = union_of_tap_listener_flags();
- if(do_dissection) {
+ if (do_dissection) {
while (to_read-- && cf->wth) {
wtap_cleareof(cf->wth);
ret = wtap_read(cf->wth, &err, &err_info, &data_offset);
- if(ret == FALSE) {
+ if (ret == FALSE) {
/* read from file failed, tell the capture child to stop */
- sync_pipe_stop(capture_opts);
+ sync_pipe_stop(cap_session);
wtap_close(cf->wth);
cf->wth = NULL;
} else {
ret = process_packet(cf, data_offset, wtap_phdr(cf->wth),
- wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
+ wtap_buf_ptr(cf->wth),
filtering_tap_listeners, tap_flags);
}
if (ret != FALSE) {
static void
report_counts(void)
{
- if (!print_packet_counts) {
+ if ((print_packet_counts == FALSE) && (really_quiet == FALSE)) {
/* Report the count only if we aren't printing a packet count
as packets arrive. */
- fprintf(stderr, "%u packet%s captured\n", packet_count,
+ fprintf(stderr, "%u packet%s captured\n", packet_count,
plurality(packet_count, "", "s"));
}
#ifdef SIGINFO
/* capture child detected any packet drops? */
void
-capture_input_drops(capture_options *capture_opts _U_, guint32 dropped)
+capture_input_drops(capture_session *cap_session _U_, guint32 dropped)
{
if (print_packet_counts) {
/* We're printing packet counts to stderr.
* do the required cleanup.
*/
void
-capture_input_closed(capture_options *capture_opts, gchar *msg)
+capture_input_closed(capture_session *cap_session, gchar *msg)
{
+ capture_file *cf = (capture_file *) cap_session->cf;
+
if (msg != NULL)
fprintf(stderr, "tshark: %s\n", msg);
report_counts();
- if(capture_opts->cf != NULL && ((capture_file *) capture_opts->cf)->wth != NULL) {
- wtap_close(((capture_file *) capture_opts->cf)->wth);
- if(((capture_file *) capture_opts->cf)->user_saved == FALSE) {
- ws_unlink(((capture_file *) capture_opts->cf)->filename);
+ if (cf != NULL && cf->wth != NULL) {
+ wtap_close(cf->wth);
+ if (cf->is_tempfile) {
+ ws_unlink(cf->filename);
}
}
#ifdef USE_BROKEN_G_MAIN_LOOP
building it with Cygwin may make the problem go away). */
/* tell the capture child to stop */
- sync_pipe_stop(&global_capture_opts);
+ sync_pipe_stop(&global_capture_session);
/* don't stop our own loop already here, otherwise status messages and
* cleanup wouldn't be done properly. The child will indicate the stop of
capture_cleanup(int signum _U_)
{
/* tell the capture child to stop */
- sync_pipe_stop(&global_capture_opts);
+ sync_pipe_stop(&global_capture_session);
/* don't stop our own loop already here, otherwise status messages and
* cleanup wouldn't be done properly. The child will indicate the stop of
static gboolean
process_packet_first_pass(capture_file *cf,
- gint64 offset, const struct wtap_pkthdr *whdr,
- union wtap_pseudo_header *pseudo_header, const guchar *pd)
+ gint64 offset, struct wtap_pkthdr *whdr,
+ const guchar *pd)
{
- frame_data fdlocal;
- guint32 framenum;
+ frame_data fdlocal;
+ guint32 framenum;
+ gboolean create_proto_tree = FALSE;
epan_dissect_t edt;
- gboolean passed;
+ gboolean passed;
/* The frame number of this packet is one more than the count of
frames in this packet. */
frame_data_init(&fdlocal, framenum, whdr, offset, cum_bytes);
/* 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
+ 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 (gbl_resolv_flags)
+ 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(NULL);
+ host_name_lookup_process();
- /* 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 ("verbose"
- is true). */
- epan_dissect_init(&edt, FALSE, 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". */
+ epan_dissect_init(&edt, cf->epan, create_proto_tree, FALSE);
/* If we're running a read filter, prime the epan_dissect_t with that
filter. */
epan_dissect_prime_dfilter(&edt, cf->rfcode);
frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time,
- &first_ts, &prev_dis_ts, &prev_cap_ts);
+ &ref, prev_dis);
+ if (ref == &fdlocal) {
+ ref_frame = fdlocal;
+ ref = &ref_frame;
+ }
- epan_dissect_run(&edt, pseudo_header, 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)
}
if (passed) {
- frame_data_set_after_dissect(&fdlocal, &cum_bytes, &prev_dis_ts);
- frame_data_sequence_add(cf->frames, &fdlocal);
+ frame_data_set_after_dissect(&fdlocal, &cum_bytes);
+ prev_cap = prev_dis = frame_data_sequence_add(cf->frames, &fdlocal);
+
+ /* If we're not doing dissection then there won't be any dependent frames.
+ * 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);
+ }
+
cf->count++;
+ } else {
+ /* if we don't add it to the frame_data_sequence, clean it up right now
+ * to avoid leaks */
+ frame_data_destroy(&fdlocal);
}
if (do_dissection)
static gboolean
process_packet_second_pass(capture_file *cf, frame_data *fdata,
- union wtap_pseudo_header *pseudo_header, const guchar *pd,
+ struct wtap_pkthdr *phdr, Buffer *buf,
gboolean filtering_tap_listeners, guint tap_flags)
{
- gboolean create_proto_tree;
- column_info *cinfo;
- epan_dissect_t edt;
- gboolean passed;
+ 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
packet information, we don't need to do a dissection. This means
run a read filter, or we're going to process taps, set up to
do a dissection and do so. */
if (do_dissection) {
- if (gbl_resolv_flags)
+ 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(NULL);
+ host_name_lookup_process();
- if (cf->rfcode || verbose || filtering_tap_listeners ||
+ if (cf->dfcode || print_details || filtering_tap_listeners ||
(tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo))
create_proto_tree = TRUE;
else
/* 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 ("verbose"
- is true). */
- epan_dissect_init(&edt, create_proto_tree, print_packet_info && verbose);
+ ("print_packet_info" is true) and we're in verbose mode
+ ("packet_details" is true). */
+ epan_dissect_init(&edt, cf->epan, create_proto_tree, print_packet_info && print_details);
- /* If we're running a read filter, prime the epan_dissect_t with that
+ /* If we're running a display 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);
col_custom_prime_edt(&edt, &cf->cinfo);
- tap_queue_init(&edt);
-
/* We only need the columns if either
-
1) some tap needs the columns
-
or
-
2) we're printing packet info but we're *not* verbose; in verbose
- mode, we print the protocol tree, not the protocol summary. */
- if ((tap_flags & TL_REQUIRES_COLUMNS) || (print_packet_info && !verbose))
+ mode, we print the protocol tree, not the protocol summary.
+ */
+ if ((tap_flags & TL_REQUIRES_COLUMNS) || (print_packet_info && print_summary))
cinfo = &cf->cinfo;
else
cinfo = NULL;
- epan_dissect_run(&edt, pseudo_header, pd, fdata, cinfo);
+ frame_data_set_before_dissect(fdata, &cf->elapsed_time,
+ &ref, prev_dis);
+ if (ref == fdata) {
+ ref_frame = *fdata;
+ ref = &ref_frame;
+ }
- tap_push_tapped_queue(&edt);
+ epan_dissect_run_with_taps(&edt, phdr, frame_tvbuff_new_buffer(fdata, buf), fdata, cinfo);
- /* Run the read filter if we have one. */
- if (cf->rfcode)
- passed = dfilter_apply_edt(cf->rfcode, &edt);
+ /* Run the read/display filter if we have one. */
+ if (cf->dfcode)
+ 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
exit(2);
}
}
+ prev_dis = fdata;
}
+ prev_cap = fdata;
if (do_dissection) {
epan_dissect_cleanup(&edt);
}
- return passed;
+ return passed || fdata->flags.dependent_of_displayed;
}
static int
wtap_dumper *pdh;
guint32 framenum;
int err;
- gchar *err_info = NULL;
+ gchar *err_info = NULL;
gint64 data_offset;
- char *save_file_string = NULL;
+ char *save_file_string = NULL;
gboolean filtering_tap_listeners;
guint tap_flags;
+ wtapng_section_t *shb_hdr;
+ wtapng_iface_descriptions_t *idb_inf;
+ char appname[100];
+ Buffer buf;
+ shb_hdr = wtap_file_get_shb_info(cf->wth);
+ idb_inf = wtap_file_get_idb_info(cf->wth);
#ifdef PCAP_NG_DEFAULT
- linktype = WTAP_ENCAP_PER_PACKET;
+ if (idb_inf->number_of_interfaces > 1) {
+ linktype = WTAP_ENCAP_PER_PACKET;
+ } else {
+ linktype = wtap_file_encap(cf->wth);
+ }
#else
linktype = wtap_file_encap(cf->wth);
#endif
/* Snapshot length of input file not known. */
snapshot_length = WTAP_MAX_PACKET_SIZE;
}
- pdh = wtap_dump_open(save_file, out_file_type, linktype, snapshot_length,
- FALSE /* compressed */, &err);
+ /* 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);
+ shb_hdr->shb_user_appl = appname;
+ }
+
+ if (linktype != WTAP_ENCAP_PER_PACKET && out_file_type == WTAP_FILE_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;
if (pdh == NULL) {
/* We couldn't set up to write to the capture file. */
while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
if (process_packet_first_pass(cf, data_offset, wtap_phdr(cf->wth),
- wtap_pseudoheader(cf->wth), wtap_buf_ptr(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
* 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)) {
+ if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
err = 0; /* This is not an error */
break;
}
max_packet_count = old_max_packet_count;
+ prev_dis = NULL;
+ prev_cap = NULL;
+ buffer_init(&buf, 1500);
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->pseudo_header,
- cf->pd, fdata->cap_len, &err, &err_info)) {
- if (process_packet_second_pass(cf, fdata,
- &cf->pseudo_header, cf->pd,
- filtering_tap_listeners, tap_flags)) {
+ if (wtap_seek_read(cf->wth, fdata->file_off, &cf->phdr,
+ &buf, fdata->cap_len, &err, &err_info)) {
+ if (process_packet_second_pass(cf, fdata, &cf->phdr, &buf,
+ filtering_tap_listeners, 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, wtap_phdr(cf->wth),
- wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
- &err)) {
+ if (!wtap_dump(pdh, &cf->phdr, buffer_start_ptr(&cf->buf), &err)) {
/* Error writing to a capture file */
switch (err) {
break;
}
wtap_dump_close(pdh, &err);
+ g_free(shb_hdr);
exit(2);
}
}
* 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)) {
+ if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
err = 0; /* This is not an error */
break;
}
}
}
}
+ buffer_free(&buf);
}
else {
framenum = 0;
framenum++;
if (process_packet(cf, data_offset, wtap_phdr(cf->wth),
- wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
+ wtap_buf_ptr(cf->wth),
filtering_tap_listeners, 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, wtap_phdr(cf->wth),
- wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
- &err)) {
+ if (!wtap_dump(pdh, wtap_phdr(cf->wth), wtap_buf_ptr(cf->wth), &err)) {
/* Error writing to a capture file */
switch (err) {
break;
}
wtap_dump_close(pdh, &err);
+ g_free(shb_hdr);
exit(2);
}
}
* 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)) {
+ if ( (--max_packet_count == 0) || (max_byte_count != 0 && data_offset >= max_byte_count)) {
err = 0; /* This is not an error */
break;
}
cf->wth = NULL;
g_free(save_file_string);
+ g_free(shb_hdr);
return err;
}
static gboolean
-process_packet(capture_file *cf, gint64 offset, const struct wtap_pkthdr *whdr,
- union wtap_pseudo_header *pseudo_header, const guchar *pd,
+process_packet(capture_file *cf, gint64 offset, struct wtap_pkthdr *whdr,
+ const guchar *pd,
gboolean filtering_tap_listeners, guint tap_flags)
{
- frame_data fdata;
- gboolean create_proto_tree;
- column_info *cinfo;
- epan_dissect_t edt;
- gboolean passed;
+ frame_data fdata;
+ gboolean create_proto_tree;
+ column_info *cinfo;
+ epan_dissect_t edt;
+ gboolean passed;
/* Count this packet. */
cf->count++;
run a read filter, or we're going to process taps, set up to
do a dissection and do so. */
if (do_dissection) {
- if (print_packet_info && gbl_resolv_flags)
+ 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(NULL);
+ host_name_lookup_process();
- if (cf->rfcode || verbose || filtering_tap_listeners ||
+ 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
/* 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 ("verbose"
- is true). */
- epan_dissect_init(&edt, create_proto_tree, print_packet_info && verbose);
+ ("print_packet_info" is true) and we're in verbose mode
+ ("packet_details" is true). */
+ epan_dissect_init(&edt, cf->epan, create_proto_tree, print_packet_info && print_details);
- /* If we're running a read filter, prime the epan_dissect_t with that
+ /* 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);
col_custom_prime_edt(&edt, &cf->cinfo);
- tap_queue_init(&edt);
-
/* We only need the columns if either
-
1) some tap needs the columns
-
or
-
2) we're printing packet info but we're *not* verbose; in verbose
- mode, we print the protocol tree, not the protocol summary. */
- if ((tap_flags & TL_REQUIRES_COLUMNS) || (print_packet_info && !verbose))
+ mode, we print the protocol tree, not the protocol summary.
+ or
+ 3) there is a column mapped as an individual field */
+ if ((tap_flags & TL_REQUIRES_COLUMNS) || (print_packet_info && print_summary) || output_fields_has_cols(output_fields))
cinfo = &cf->cinfo;
else
cinfo = NULL;
frame_data_set_before_dissect(&fdata, &cf->elapsed_time,
- &first_ts, &prev_dis_ts, &prev_cap_ts);
-
- epan_dissect_run(&edt, pseudo_header, pd, &fdata, cinfo);
+ &ref, prev_dis);
+ if (ref == &fdata) {
+ ref_frame = fdata;
+ ref = &ref_frame;
+ }
- tap_push_tapped_queue(&edt);
+ epan_dissect_run_with_taps(&edt, whdr, frame_tvbuff_new(&fdata, pd), &fdata, cinfo);
- /* Run the read filter if we have one. */
+ /* 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);
}
if (passed) {
- frame_data_set_after_dissect(&fdata, &cum_bytes, &prev_dis_ts);
+ frame_data_set_after_dissect(&fdata, &cum_bytes);
/* Process this packet. */
if (print_packet_info) {
exit(2);
}
}
+
+ /* this must be set after print_packet() [bug #8160] */
+ prev_dis_frame = fdata;
+ prev_dis = &prev_dis_frame;
}
+ prev_cap_frame = fdata;
+ prev_cap = &prev_cap_frame;
+
if (do_dissection) {
epan_dissect_cleanup(&edt);
- frame_data_cleanup(&fdata);
+ 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_svnversion);
case WRITE_XML:
- if (verbose)
+ if (print_details)
write_pdml_preamble(stdout, cf ? cf->filename : NULL);
else
write_psml_preamble(stdout);
static char *
get_line_buf(size_t len)
{
- static char *line_bufp = NULL;
- static size_t line_buf_len = 256;
- size_t new_line_buf_len;
+ static char *line_bufp = NULL;
+ static size_t line_buf_len = 256;
+ size_t new_line_buf_len;
for (new_line_buf_len = line_buf_len; len > new_line_buf_len;
new_line_buf_len *= 2)
;
if (line_bufp == NULL) {
line_buf_len = new_line_buf_len;
- line_bufp = g_malloc(line_buf_len + 1);
+ line_bufp = (char *)g_malloc(line_buf_len + 1);
} else {
if (new_line_buf_len > line_buf_len) {
line_buf_len = new_line_buf_len;
- line_bufp = g_realloc(line_bufp, line_buf_len + 1);
+ line_bufp = (char *)g_realloc(line_bufp, line_buf_len + 1);
}
}
return line_bufp;
static gboolean
print_columns(capture_file *cf)
{
- char *line_bufp;
- int i;
- size_t buf_offset;
- size_t column_len;
+ char *line_bufp;
+ int i;
+ size_t buf_offset;
+ size_t column_len;
line_bufp = get_line_buf(256);
buf_offset = 0;
static gboolean
print_packet(capture_file *cf, epan_dissect_t *edt)
{
- print_args_t print_args;
+ print_args_t print_args;
+
+ if (print_summary || output_fields_has_cols(output_fields)) {
+ /* Just fill in the columns. */
+ epan_dissect_fill_in_columns(edt, FALSE, TRUE);
+
+ if (print_summary) {
+ /* Now print them. */
+ switch (output_action) {
- if (verbose) {
+ case WRITE_TEXT:
+ if (!print_columns(cf))
+ return FALSE;
+ break;
+
+ case WRITE_XML:
+ proto_tree_write_psml(edt, stdout);
+ return !ferror(stdout);
+ case WRITE_FIELDS: /*No non-verbose "fields" format */
+ g_assert_not_reached();
+ break;
+ }
+ }
+ }
+ if (print_details) {
/* Print the information in the protocol tree. */
switch (output_action) {
case WRITE_TEXT:
+ /* Only initialize the fields that are actually used in proto_tree_print.
+ * This is particularly important for .range, as that's heap memory which
+ * we would otherwise have to g_free().
print_args.to_file = TRUE;
print_args.format = print_format;
- print_args.print_summary = !verbose;
- print_args.print_hex = verbose && print_hex;
+ print_args.print_summary = print_summary;
print_args.print_formfeed = FALSE;
- print_args.print_dissections = verbose ? print_dissections_expanded : print_dissections_none;
-
- /* init the packet range */
- packet_range_init(&print_args.range);
+ packet_range_init(&print_args.range, &cfile);
+ */
+ print_args.print_hex = print_hex;
+ print_args.print_dissections = print_details ? print_dissections_expanded : print_dissections_none;
if (!proto_tree_print(&print_args, edt, print_stream))
return FALSE;
if (!print_hex) {
- /* "print_hex_data()" will put out a leading blank line, as well
- as a trailing one; print one here, to separate the packets,
- only if "print_hex_data()" won't be called. */
if (!print_line(print_stream, 0, separator))
return FALSE;
}
printf("\n");
return !ferror(stdout);
case WRITE_FIELDS:
- proto_tree_write_fields(output_fields, edt, stdout);
+ proto_tree_write_fields(output_fields, edt, &cf->cinfo, stdout);
printf("\n");
return !ferror(stdout);
}
- } else {
- /* Just fill in the columns. */
- epan_dissect_fill_in_columns(edt, FALSE, TRUE);
-
- /* Now print them. */
- switch (output_action) {
-
- case WRITE_TEXT:
- if (!print_columns(cf))
- return FALSE;
- break;
-
- case WRITE_XML:
- proto_tree_write_psml(edt, stdout);
- return !ferror(stdout);
- case WRITE_FIELDS: /*No non-verbose "fields" format */
- g_assert_not_reached();
- break;
- }
}
if (print_hex) {
+ if (print_summary || print_details) {
+ if (!print_line(print_stream, 0, ""))
+ return FALSE;
+ }
if (!print_hex_data(print_stream, edt))
return FALSE;
- if (!print_line(print_stream, 0, ""))
+ if (!print_line(print_stream, 0, separator))
return FALSE;
}
return TRUE;
return print_finale(print_stream);
case WRITE_XML:
- if (verbose)
+ if (print_details)
write_pdml_finale(stdout);
else
write_psml_finale(stdout);
cf_status_t
cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err)
{
- wtap *wth;
- gchar *err_info;
- char err_msg[2048+1];
+ wtap *wth;
+ gchar *err_info;
+ char err_msg[2048+1];
wth = wtap_open_offline(fname, err, &err_info, perform_two_pass_analysis);
if (wth == NULL)
/* 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 */
/* Indicate whether it's a permanent or temporary file. */
cf->is_tempfile = is_tempfile;
- /* If it's a temporary capture buffer file, mark it as not saved. */
- cf->user_saved = !is_tempfile;
+ /* No user changes yet. */
+ cf->unsaved_changes = FALSE;
cf->cd_t = wtap_file_type(cf->wth);
cf->count = 0;
} else
cf->has_snap = TRUE;
nstime_set_zero(&cf->elapsed_time);
- nstime_set_unset(&first_ts);
- nstime_set_unset(&prev_dis_ts);
- nstime_set_unset(&prev_cap_ts);
+ ref = NULL;
+ prev_dis = NULL;
+ prev_cap = NULL;
cf->state = FILE_READ_IN_PROGRESS;
filename, g_strerror(err));
}
-/*
- * Print to the standard error. This is a command-line tool, so there's
- * no need to pop up a console.
- */
-void
-vfprintf_stderr(const char *fmt, va_list ap)
-{
- vfprintf(stderr, fmt, ap);
-}
-
-void
-fprintf_stderr(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vfprintf_stderr(fmt, ap);
- va_end(ap);
-}
-
/*
* Report an error in command-line arguments.
*/
fprintf(stderr, "\n");
va_end(ap);
}
+
+
+/*
+ * Editor modelines - http://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 2
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=2 tabstop=8 expandtab:
+ * :indentSize=2:tabSize=8:noTabs=true:
+ */