X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=tshark.c;h=687b6c14d553e4bda781c6bcb93ce8dd23e31aed;hb=fdfa22979374b9790667232f33347a08c297aba4;hp=eae9acf34e2349a3a88cec72028ff5d543fa3a45;hpb=585d17ae7f03d76713cf8ab2959260d19dabc619;p=metze%2Fwireshark%2Fwip.git diff --git a/tshark.c b/tshark.c index eae9acf34e..687b6c14d5 100644 --- a/tshark.c +++ b/tshark.c @@ -7,19 +7,7 @@ * By Gerald Combs * Copyright 1998 Gerald Combs * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -36,7 +24,7 @@ #include -#ifdef HAVE_WINSOCK2_H +#ifdef _WIN32 # include #endif @@ -55,7 +43,6 @@ #include #include -#include #include #include @@ -65,7 +52,7 @@ #include #include #include -#include +#include #include #include @@ -85,8 +72,9 @@ #ifdef HAVE_LIBPCAP #include "ui/capture_ui_utils.h" #endif +#include "ui/taps.h" #include "ui/util.h" -#include "ui/ui_util.h" +#include "ui/ws_ui_util.h" #include "ui/decode_as_utils.h" #include "ui/filter_files.h" #include "ui/cli/tshark-tap.h" @@ -100,7 +88,7 @@ #if defined(HAVE_GEOIP) #include "epan/geoip_db.h" #endif -#include "register.h" +#include "epan/register.h" #include #include #include @@ -148,6 +136,7 @@ #define INVALID_CAPABILITY 2 #define INVALID_TAP 2 #define INVALID_DATA_LINK 2 +#define INVALID_TIMESTAMP_TYPE 2 #define INVALID_CAPTURE 2 #define INIT_FAILED 2 @@ -156,6 +145,7 @@ * ui/commandline.c, so start tshark-specific options 1000 after this */ #define LONGOPT_COLOR (65536+1000) +#define LONGOPT_NO_DUPLICATE_KEYS (65536+1001) #if 0 #define tshark_debug(...) g_warning(__VA_ARGS__) @@ -163,12 +153,11 @@ #define tshark_debug(...) #endif +capture_file cfile; + static guint32 cum_bytes; -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 perform_two_pass_analysis; @@ -191,7 +180,7 @@ typedef enum { static output_action_e output_action; 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_summary; /* 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; @@ -206,9 +195,14 @@ static output_fields_t* output_fields = NULL; static gchar **protocolfilter = NULL; static pf_flags protocolfilter_flags = PF_NONE; +static gboolean no_duplicate_keys = FALSE; +static proto_node_children_grouper_func node_children_grouper = proto_node_group_children_by_unique; + /* The line separator used between packets, changeable via the -S option */ static const char *separator = ""; +static gboolean prefs_loaded = FALSE; + #ifdef HAVE_LIBPCAP /* * TRUE if we're to print packet counts to keep track of captured packets. @@ -258,8 +252,6 @@ static void read_failure_message(const char *filename, int err); static void write_failure_message(const char *filename, int err); static void failure_message_cont(const char *msg_format, va_list ap); -capture_file cfile; - static GHashTable *output_only_tables = NULL; struct string_elem { @@ -349,8 +341,10 @@ print_usage(FILE *output) fprintf(output, " -B size of kernel buffer (def: %dMB)\n", DEFAULT_CAPTURE_BUFFER_SIZE); #endif fprintf(output, " -y link layer type (def: first appropriate)\n"); + fprintf(output, " --time-stamp-type timestamp method for interface\n"); fprintf(output, " -D print list of interfaces and exit\n"); fprintf(output, " -L print list of link-layer types of iface and exit\n"); + fprintf(output, " --list-time-stamp-types print list of timestamp types for iface and exit\n"); fprintf(output, "\n"); fprintf(output, "Capture stop conditions:\n"); fprintf(output, " -c stop after n packets (def: infinite)\n"); @@ -360,6 +354,7 @@ print_usage(FILE *output) /*fprintf(output, "\n");*/ fprintf(output, "Capture output:\n"); fprintf(output, " -b ... duration:NUM - switch to next file after NUM secs\n"); + fprintf(output, " interval:NUM - create time intervals of NUM secs\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 */ @@ -446,6 +441,9 @@ print_usage(FILE *output) fprintf(output, " requires a terminal with 24-bit color support\n"); fprintf(output, " Also supplies color attributes to pdml and psml formats\n"); fprintf(output, " (Note that attributes are nonstandard)\n"); + fprintf(output, " --no-duplicate-keys If -T json is specified, merge duplicate keys in an object\n"); + fprintf(output, " into a single key with as value a json array containing all\n"); + fprintf(output, " values"); fprintf(output, "\n"); fprintf(output, "Miscellaneous:\n"); @@ -455,13 +453,12 @@ print_usage(FILE *output) fprintf(output, " -K keytab file to use for kerberos decryption\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"); + fprintf(output, " use \"-G help\" 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 } @@ -503,7 +500,7 @@ tshark_log_handler (const gchar *log_domain, GLogLevelFlags log_level, { /* ignore log message, if log_level isn't interesting based upon the console log preferences. - If the preferences haven't been loaded loaded yet, display the + If the preferences haven't been loaded yet, display the message anyway. The default console_log_level preference value is such that only @@ -514,8 +511,7 @@ tshark_log_handler (const gchar *log_domain, GLogLevelFlags log_level, 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 && - prefs.console_log_level != 0) { + if (prefs_loaded && (log_level & G_LOG_LEVEL_MASK & prefs.console_log_level) == 0) { return; } @@ -600,16 +596,31 @@ about_folders(void) constpath = get_progfile_dir(); printf("%-21s\t%s\n", "Program:", constpath); -#if defined(HAVE_PLUGINS) || defined(HAVE_LUA) +#ifdef HAVE_PLUGINS /* pers plugins */ - path = get_plugins_pers_dir(); + printf("%-21s\t%s\n", "Personal Plugins:", get_plugins_pers_dir_with_version()); - printf("%-21s\t%s\n", "Personal Plugins:", path); + /* global plugins */ + printf("%-21s\t%s\n", "Global Plugins:", get_plugins_dir_with_version()); +#endif - g_free(path); +#ifdef HAVE_LUA + /* pers lua plugins */ + printf("%-21s\t%s\n", "Personal Lua Plugins:", get_plugins_pers_dir()); - /* global plugins */ - printf("%-21s\t%s\n", "Global Plugins:", get_plugin_dir()); + /* global lua plugins */ + printf("%-21s\t%s\n", "Global Lua Plugins:", get_plugins_dir()); +#endif + +#ifdef HAVE_EXTCAP + /* Extcap */ + constpath = get_extcap_dir(); + + resultArray = g_strsplit(constpath, G_SEARCHPATH_SEPARATOR_S, 10); + for(i = 0; resultArray[i]; i++) + printf("%-21s\t%s\n", "Extcap path:", g_strstrip(resultArray[i])); + + g_strfreev(resultArray); #endif #ifdef HAVE_GEOIP @@ -637,17 +648,6 @@ about_folders(void) g_free(path); #endif -#ifdef HAVE_EXTCAP - /* Extcap */ - constpath = get_extcap_dir(); - - resultArray = g_strsplit(constpath, G_SEARCHPATH_SEPARATOR_S, 10); - for(i = 0; resultArray[i]; i++) - printf("%-21s\t%s\n", "Extcap path:", g_strstrip(resultArray[i])); - - g_strfreev(resultArray); -#endif - } int @@ -662,8 +662,10 @@ main(int argc, char *argv[]) {"version", no_argument, NULL, 'v'}, LONGOPT_CAPTURE_COMMON LONGOPT_DISSECT_COMMON + {"print", no_argument, NULL, 'P'}, {"export-objects", required_argument, NULL, LONGOPT_EXPORT_OBJECTS}, {"color", no_argument, NULL, LONGOPT_COLOR}, + {"no-duplicate-keys", no_argument, NULL, LONGOPT_NO_DUPLICATE_KEYS}, {0, 0, 0, 0 } }; gboolean arg_error = FALSE; @@ -677,7 +679,7 @@ main(int argc, char *argv[]) volatile gboolean success; volatile int exit_status = EXIT_SUCCESS; #ifdef HAVE_LIBPCAP - gboolean list_link_layer_types = FALSE; + int caps_queries = 0; gboolean start_capture = FALSE; GList *if_list; gchar *err_str; @@ -856,15 +858,6 @@ main(int argc, char *argv[]) } } - /* - * 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; - /** Send All g_log messages to our own handler **/ log_flags = @@ -907,18 +900,6 @@ main(int argc, char *argv[]) wtap_init(); -#ifdef HAVE_PLUGINS - /* Register all the plugin types we have. */ - epan_register_plugin_types(); /* Types known to libwireshark */ - - /* Scan for plugins. This does *not* call their registration routines; - that's done later. */ - scan_plugins(REPORT_LOAD_FAILURE); - - /* 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 @@ -941,7 +922,10 @@ main(int argc, char *argv[]) #ifdef HAVE_EXTCAP extcap_register_preferences(); #endif - register_all_tap_listeners(); + /* Register all tap listeners. */ + for (tap_reg_t *t = tap_reg_listener; t->cb_func != NULL; t++) { + t->cb_func(); + } conversation_table_set_gui_info(init_iousers); hostlist_table_set_gui_info(init_hostlists); srt_table_iterate_tables(register_srt_tables, NULL); @@ -998,12 +982,18 @@ main(int argc, char *argv[]) proto_registrar_dump_protocols(); else if (strcmp(argv[2], "values") == 0) proto_registrar_dump_values(); + else if (strcmp(argv[2], "help") == 0) + glossary_option_help(); + /* These are supported only for backwards compatibility and may or may not work + * for a given user in a given directory on a given operating system with a given + * command-line interpreter. + */ else if (strcmp(argv[2], "?") == 0) glossary_option_help(); else if (strcmp(argv[2], "-?") == 0) glossary_option_help(); else { - cmdarg_err("Invalid \"%s\" option for -G flag, enter -G ? for more help.", argv[2]); + cmdarg_err("Invalid \"%s\" option for -G flag, enter -G help for more help.", argv[2]); exit_status = INVALID_OPTION; goto clean_exit; } @@ -1016,6 +1006,7 @@ main(int argc, char *argv[]) /* Load libwireshark settings from the current profile. */ prefs_p = epan_load_settings(); + prefs_loaded = TRUE; read_filter_list(CFILTER_LIST); @@ -1073,6 +1064,7 @@ main(int argc, char *argv[]) case 'f': /* capture filter */ case 'g': /* enable group read access on file(s) */ case 'i': /* Use interface x */ + case LONGOPT_SET_TSTAMP_TYPE: /* Set capture timestamp type */ case 'p': /* Don't capture in promiscuous mode */ #ifdef HAVE_PCAP_REMOTE case 'A': /* Authentication */ @@ -1217,7 +1209,15 @@ main(int argc, char *argv[]) break; case 'L': /* Print list of link-layer types and exit */ #ifdef HAVE_LIBPCAP - list_link_layer_types = TRUE; + caps_queries |= CAPS_QUERY_LINK_TYPES; +#else + capture_option_specified = TRUE; + arg_error = TRUE; +#endif + break; + case LONGOPT_LIST_TSTAMP_TYPES: /* List possible timestamp types */ +#ifdef HAVE_LIBPCAP + caps_queries |= CAPS_QUERY_TIMESTAMP_TYPES; #else capture_option_specified = TRUE; arg_error = TRUE; @@ -1298,8 +1298,8 @@ main(int argc, char *argv[]) print_summary = FALSE; /* Don't allow summary */ } else if (strcmp(optarg, "ek") == 0) { output_action = WRITE_EK; - print_details = TRUE; /* Need details */ - print_summary = FALSE; /* Don't allow summary */ + if (!print_summary) + print_details = TRUE; } else if (strcmp(optarg, "jsonraw") == 0) { output_action = WRITE_JSON_RAW; print_details = TRUE; /* Need details */ @@ -1436,6 +1436,10 @@ main(int argc, char *argv[]) case LONGOPT_COLOR: /* print in color where appropriate */ dissect_color = TRUE; break; + case LONGOPT_NO_DUPLICATE_KEYS: + no_duplicate_keys = TRUE; + node_children_grouper = proto_node_group_children_by_json_key; + break; default: case '?': /* Bad flag - print usage message */ switch(optopt) { @@ -1451,6 +1455,21 @@ main(int argc, char *argv[]) } } + /* + * Print packet summary information is the default if neither -V or -x + * were specified. 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 && !print_details && !print_hex) + print_summary = TRUE; + + if (no_duplicate_keys && output_action != WRITE_JSON && output_action != WRITE_JSON_RAW) { + cmdarg_err("--no-duplicate-keys can only be used with \"-T json\" and \"-T jsonraw\""); + exit_status = INVALID_OPTION; + goto clean_exit; + } + /* If we specified output fields, but not the output field type... */ if ((WRITE_FIELDS != output_action && WRITE_XML != output_action && WRITE_JSON != output_action && WRITE_EK != output_action) && 0 != output_fields_num_fields(output_fields)) { cmdarg_err("Output fields were specified with \"-e\", " @@ -1496,12 +1515,10 @@ main(int argc, char *argv[]) goto clean_exit; } 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); - global_capture_opts.ifaces = g_array_remove_index(global_capture_opts.ifaces, i); - g_array_insert_val(global_capture_opts.ifaces, i, interface_opts); + 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); } else { cmdarg_err("A capture filter was specified both with \"-f\"" " and with additional command-line arguments."); @@ -1582,12 +1599,13 @@ main(int argc, char *argv[]) } #ifdef HAVE_LIBPCAP - if (list_link_layer_types) { - /* We're supposed to list the link-layer types for an interface; + if (caps_queries) { + /* We're supposed to list the link-layer/timestamp types for an interface; did the user also specify a capture file to be read? */ if (cf_name) { /* Yes - that's bogus. */ - cmdarg_err("You can't specify -L and a capture file to be read."); + cmdarg_err("You can't specify %s and a capture file to be read.", + caps_queries & CAPS_QUERY_LINK_TYPES ? "-L" : "--list-time-stamp-types"); exit_status = INVALID_OPTION; goto clean_exit; } @@ -1620,6 +1638,12 @@ main(int argc, char *argv[]) goto clean_exit; } if (global_capture_opts.has_file_duration) { + cmdarg_err("Switching capture files after a time period was specified, but " + "a capture isn't being done."); + exit_status = INVALID_OPTION; + goto clean_exit; + } + if (global_capture_opts.has_file_interval) { cmdarg_err("Switching capture files after a time interval was specified, but " "a capture isn't being done."); exit_status = INVALID_OPTION; @@ -1702,9 +1726,10 @@ main(int argc, char *argv[]) goto clean_exit; } if (!global_capture_opts.has_autostop_filesize && - !global_capture_opts.has_file_duration) { + !global_capture_opts.has_file_duration && + !global_capture_opts.has_file_interval) { cmdarg_err("Multiple capture files requested, but " - "no maximum capture file size or duration was specified."); + "no maximum capture file size, duration or interval was specified."); exit_status = INVALID_OPTION; goto clean_exit; } @@ -2053,22 +2078,23 @@ main(int argc, char *argv[]) } /* if requested, list the link layer types and exit */ - if (list_link_layer_types) { + if (caps_queries) { guint i; /* Get the list of link-layer types for the capture devices. */ for (i = 0; i < global_capture_opts.ifaces->len; i++) { - interface_options interface_opts; + interface_options *interface_opts; if_capabilities_t *caps; char *auth_str = NULL; + int if_caps_queries = caps_queries; - interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i); + interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, i); #ifdef HAVE_PCAP_REMOTE - if (interface_opts.auth_type == CAPTURE_AUTH_PWD) { - auth_str = g_strdup_printf("%s:%s", interface_opts.auth_username, interface_opts.auth_password); + if (interface_opts->auth_type == CAPTURE_AUTH_PWD) { + auth_str = g_strdup_printf("%s:%s", interface_opts->auth_username, interface_opts->auth_password); } #endif - caps = capture_get_if_capabilities(interface_opts.name, interface_opts.monitor_mode, auth_str, &err_str, NULL); + caps = capture_get_if_capabilities(interface_opts->name, interface_opts->monitor_mode, auth_str, &err_str, NULL); g_free(auth_str); if (caps == NULL) { cmdarg_err("%s", err_str); @@ -2076,12 +2102,19 @@ main(int argc, char *argv[]) exit_status = INVALID_CAPABILITY; goto clean_exit; } - if (caps->data_link_types == NULL) { - cmdarg_err("The capture device \"%s\" has no data link types.", interface_opts.name); + if ((if_caps_queries & CAPS_QUERY_LINK_TYPES) && caps->data_link_types == NULL) { + cmdarg_err("The capture device \"%s\" has no data link types.", interface_opts->name); exit_status = INVALID_DATA_LINK; goto clean_exit; } - capture_opts_print_if_capabilities(caps, interface_opts.name, interface_opts.monitor_mode); + if ((if_caps_queries & CAPS_QUERY_TIMESTAMP_TYPES) && caps->timestamp_types == NULL) { + cmdarg_err("The capture device \"%s\" has no timestamp types.", interface_opts->name); + exit_status = INVALID_TIMESTAMP_TYPE; + goto clean_exit; + } + if (interface_opts->monitor_mode) + if_caps_queries |= CAPS_MONITOR_MODE; + capture_opts_print_if_capabilities(caps, interface_opts->name, if_caps_queries); free_if_capabilities(caps); } exit_status = EXIT_SUCCESS; @@ -2157,9 +2190,9 @@ main(int argc, char *argv[]) g_free(cf_name); - if (cfile.frames != NULL) { - free_frame_data_sequence(cfile.frames); - cfile.frames = NULL; + if (cfile.provider.frames != NULL) { + free_frame_data_sequence(cfile.provider.frames); + cfile.provider.frames = NULL; } draw_tap_listeners(TRUE); @@ -2182,9 +2215,6 @@ clean_exit: free_filter_lists(); wtap_cleanup(); free_progdirs(); -#ifdef HAVE_PLUGINS - plugins_cleanup(); -#endif cf_close(&cfile); return exit_status; } @@ -2301,21 +2331,19 @@ pipe_input_set_handler(gint source, gpointer user_data, ws_process_id *child_pro } static const nstime_t * -tshark_get_frame_ts(void *data, guint32 frame_num) +tshark_get_frame_ts(struct packet_provider_data *prov, guint32 frame_num) { - capture_file *cf = (capture_file *) data; - - if (ref && ref->num == frame_num) - return &ref->abs_ts; + if (prov->ref && prov->ref->num == frame_num) + return &prov->ref->abs_ts; - if (prev_dis && prev_dis->num == frame_num) - return &prev_dis->abs_ts; + if (prov->prev_dis && prov->prev_dis->num == frame_num) + return &prov->prev_dis->abs_ts; - if (prev_cap && prev_cap->num == frame_num) - return &prev_cap->abs_ts; + if (prov->prev_cap && prov->prev_cap->num == frame_num) + return &prov->prev_cap->abs_ts; - if (cf->frames) { - frame_data *fd = frame_data_sequence_find(cf->frames, frame_num); + if (prov->frames) { + frame_data *fd = frame_data_sequence_find(prov->frames, frame_num); return (fd) ? &fd->abs_ts : NULL; } @@ -2326,15 +2354,14 @@ tshark_get_frame_ts(void *data, guint32 frame_num) 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_interface_description = cap_file_get_interface_description; - epan->get_user_comment = NULL; + static const struct packet_provider_funcs funcs = { + tshark_get_frame_ts, + cap_file_provider_get_interface_name, + cap_file_provider_get_interface_description, + NULL, + }; - return epan; + return epan_new(&cf->provider, &funcs); } #ifdef HAVE_LIBPCAP @@ -2395,12 +2422,10 @@ capture(void) /* Let the user know which interfaces were chosen. */ for (i = 0; i < global_capture_opts.ifaces->len; i++) { - interface_options interface_opts; + interface_options *interface_opts; - interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i); - interface_opts.descr = get_interface_descriptive_name(interface_opts.name); - global_capture_opts.ifaces = g_array_remove_index(global_capture_opts.ifaces, i); - g_array_insert_val(global_capture_opts.ifaces, i, interface_opts); + interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, i); + interface_opts->descr = get_interface_descriptive_name(interface_opts->name); } str = get_iface_list_string(&global_capture_opts, IFLIST_QUOTE_IF_DESCRIPTION); if (really_quiet == FALSE) @@ -2490,12 +2515,12 @@ capture_input_cfilter_error_message(capture_session *cap_session, guint i, char { capture_options *capture_opts = cap_session->capture_opts; dfilter_t *rfcode = NULL; - interface_options interface_opts; + interface_options *interface_opts; g_assert(i < capture_opts->ifaces->len); - interface_opts = g_array_index(capture_opts->ifaces, interface_options, i); + interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i); - if (dfilter_compile(interface_opts.cfilter, &rfcode, NULL) && rfcode != NULL) { + if (dfilter_compile(interface_opts->cfilter, &rfcode, NULL) && rfcode != NULL) { cmdarg_err( "Invalid capture filter \"%s\" for interface '%s'.\n" "\n" @@ -2506,7 +2531,7 @@ capture_input_cfilter_error_message(capture_session *cap_session, guint i, char "so you can't use most display filter expressions as capture filters.\n" "\n" "See the User's Guide for a description of the capture filter syntax.", - interface_opts.cfilter, interface_opts.descr, error_message); + interface_opts->cfilter, interface_opts->descr, error_message); dfilter_free(rfcode); } else { cmdarg_err( @@ -2514,7 +2539,7 @@ capture_input_cfilter_error_message(capture_session *cap_session, guint i, char "\n" "That string isn't a valid capture filter (%s).\n" "See the User's Guide for a description of the capture filter syntax.", - interface_opts.cfilter, interface_opts.descr, error_message); + interface_opts->cfilter, interface_opts->descr, error_message); } } @@ -2540,9 +2565,9 @@ capture_input_new_file(capture_session *cap_session, gchar *new_file) /* we start a new capture file, close the old one (if we had one before) */ if (cf->state != FILE_CLOSED) { - if (cf->wth != NULL) { - wtap_close(cf->wth); - cf->wth = NULL; + if (cf->provider.wth != NULL) { + wtap_close(cf->provider.wth); + cf->provider.wth = NULL; } cf->state = FILE_CLOSED; } @@ -2645,19 +2670,19 @@ capture_input_new_packets(capture_session *cap_session, int to_read) ("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); + while (to_read-- && cf->provider.wth) { + wtap_cleareof(cf->provider.wth); + ret = wtap_read(cf->provider.wth, &err, &err_info, &data_offset); reset_epan_mem(cf, edt, create_proto_tree, print_packet_info && print_details); if (ret == FALSE) { /* read from file failed, tell the capture child to stop */ sync_pipe_stop(cap_session); - wtap_close(cf->wth); - cf->wth = NULL; + wtap_close(cf->provider.wth); + cf->provider.wth = NULL; } else { ret = process_packet_single_pass(cf, edt, data_offset, - wtap_phdr(cf->wth), - wtap_buf_ptr(cf->wth), tap_flags); + wtap_phdr(cf->provider.wth), + wtap_buf_ptr(cf->provider.wth), tap_flags); } if (ret != FALSE) { /* packet successfully read and gone through the "Read Filter" */ @@ -2761,8 +2786,8 @@ capture_input_closed(capture_session *cap_session, gchar *msg) report_counts(); - if (cf != NULL && cf->wth != NULL) { - wtap_close(cf->wth); + if (cf != NULL && cf->provider.wth != NULL) { + wtap_close(cf->provider.wth); if (cf->is_tempfile) { ws_unlink(cf->filename); } @@ -2870,13 +2895,15 @@ process_packet_first_pass(capture_file *cf, epan_dissect_t *edt, prime_epan_dissect_with_postdissector_wanted_hfids(edt); frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time, - &ref, prev_dis); - if (ref == &fdlocal) { + &cf->provider.ref, cf->provider.prev_dis); + if (cf->provider.ref == &fdlocal) { ref_frame = fdlocal; - ref = &ref_frame; + cf->provider.ref = &ref_frame; } - epan_dissect_run(edt, cf->cd_t, whdr, frame_tvbuff_new(&fdlocal, pd), &fdlocal, NULL); + epan_dissect_run(edt, cf->cd_t, whdr, + frame_tvbuff_new(&cf->provider, &fdlocal, pd), + &fdlocal, NULL); /* Run the read filter if we have one. */ if (cf->rfcode) @@ -2885,7 +2912,7 @@ process_packet_first_pass(capture_file *cf, epan_dissect_t *edt, if (passed) { frame_data_set_after_dissect(&fdlocal, &cum_bytes); - prev_cap = prev_dis = frame_data_sequence_add(cf->frames, &fdlocal); + cf->provider.prev_cap = cf->provider.prev_dis = frame_data_sequence_add(cf->provider.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 @@ -2895,7 +2922,7 @@ process_packet_first_pass(capture_file *cf, epan_dissect_t *edt, */ if (edt && cf->dfcode) { if (dfilter_apply_edt(cf->dfcode, edt)) { - g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->frames); + g_slist_foreach(edt->pi.dependent_frames, find_and_mark_frame_depended_upon, cf->provider.frames); } } @@ -2955,10 +2982,10 @@ process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, cinfo = NULL; frame_data_set_before_dissect(fdata, &cf->elapsed_time, - &ref, prev_dis); - if (ref == fdata) { + &cf->provider.ref, cf->provider.prev_dis); + if (cf->provider.ref == fdata) { ref_frame = *fdata; - ref = &ref_frame; + cf->provider.ref = &ref_frame; } if (dissect_color) { @@ -2966,7 +2993,9 @@ process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, fdata->flags.need_colorize = 1; } - epan_dissect_run_with_taps(edt, cf->cd_t, phdr, frame_tvbuff_new_buffer(fdata, buf), fdata, cinfo); + epan_dissect_run_with_taps(edt, cf->cd_t, phdr, + frame_tvbuff_new_buffer(&cf->provider, fdata, buf), + fdata, cinfo); /* Run the read/display filter if we have one. */ if (cf->dfcode) @@ -2992,9 +3021,9 @@ process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, exit(2); } } - prev_dis = fdata; + cf->provider.prev_dis = fdata; } - prev_cap = fdata; + cf->provider.prev_cap = fdata; if (edt) { epan_dissect_reset(edt); @@ -3026,27 +3055,27 @@ process_cap_file(capture_file *cf, char *save_file, int out_file_type, wtap_phdr_init(&phdr); - idb_inf = wtap_file_get_idb_info(cf->wth); + idb_inf = wtap_file_get_idb_info(cf->provider.wth); #ifdef PCAP_NG_DEFAULT if (idb_inf->interface_data->len > 1) { linktype = WTAP_ENCAP_PER_PACKET; } else { - linktype = wtap_file_encap(cf->wth); + linktype = wtap_file_encap(cf->provider.wth); } #else - linktype = wtap_file_encap(cf->wth); + linktype = wtap_file_encap(cf->provider.wth); #endif if (save_file != NULL) { /* Set up to write to the capture file. */ - snapshot_length = wtap_snapshot_length(cf->wth); + snapshot_length = wtap_snapshot_length(cf->provider.wth); if (snapshot_length == 0) { /* Snapshot length of input file not known. */ snapshot_length = WTAP_MAX_PACKET_SIZE_STANDARD; } tshark_debug("tshark: snapshot_length = %d", snapshot_length); - shb_hdrs = wtap_file_get_shb_for_new_file(cf->wth); - nrb_hdrs = wtap_file_get_nrb_for_new_file(cf->wth); + shb_hdrs = wtap_file_get_shb_for_new_file(cf->provider.wth); + nrb_hdrs = wtap_file_get_nrb_for_new_file(cf->provider.wth); /* If we don't have an application name add Tshark */ if (wtap_block_get_string_option_value(g_array_index(shb_hdrs, wtap_block_t, 0), OPT_SHB_USERAPPL, &shb_user_appl) != WTAP_OPTTYPE_SUCCESS) { @@ -3113,7 +3142,7 @@ process_cap_file(capture_file *cf, char *save_file, int out_file_type, tshark_debug("tshark: perform_two_pass_analysis, do_dissection=%s", do_dissection ? "TRUE" : "FALSE"); /* Allocate a frame_data_sequence for all the frames. */ - cf->frames = new_frame_data_sequence(); + cf->provider.frames = new_frame_data_sequence(); if (do_dissection) { gboolean create_proto_tree; @@ -3140,9 +3169,9 @@ process_cap_file(capture_file *cf, char *save_file, int out_file_type, } tshark_debug("tshark: reading records for first pass"); - while (wtap_read(cf->wth, &err, &err_info, &data_offset)) { - if (process_packet_first_pass(cf, edt, data_offset, wtap_phdr(cf->wth), - wtap_buf_ptr(cf->wth))) { + while (wtap_read(cf->provider.wth, &err, &err_info, &data_offset)) { + if (process_packet_first_pass(cf, edt, data_offset, wtap_phdr(cf->provider.wth), + wtap_buf_ptr(cf->provider.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. @@ -3177,14 +3206,14 @@ process_cap_file(capture_file *cf, char *save_file, int out_file_type, } /* Close the sequential I/O side, to free up memory it requires. */ - wtap_sequential_close(cf->wth); + wtap_sequential_close(cf->provider.wth); /* Allow the protocol dissectors to free up memory that they * don't need after the sequential run-through of the packets. */ postseq_cleanup_all_protocols(); - prev_dis = NULL; - prev_cap = NULL; + cf->provider.prev_dis = NULL; + cf->provider.prev_cap = NULL; ws_buffer_init(&buf, 1500); tshark_debug("tshark: done with first pass"); @@ -3219,8 +3248,8 @@ process_cap_file(capture_file *cf, char *save_file, int out_file_type, } 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, &phdr, &buf, &err, + fdata = frame_data_sequence_find(cf->provider.frames, framenum); + if (wtap_seek_read(cf->provider.wth, fdata->file_off, &phdr, &buf, &err, &err_info)) { tshark_debug("tshark: invoking process_packet_second_pass() for frame #%d", framenum); if (process_packet_second_pass(cf, edt, fdata, &phdr, &buf, @@ -3300,21 +3329,21 @@ process_cap_file(capture_file *cf, char *save_file, int out_file_type, edt = epan_dissect_new(cf->epan, create_proto_tree, print_packet_info && print_details); } - while (wtap_read(cf->wth, &err, &err_info, &data_offset)) { + while (wtap_read(cf->provider.wth, &err, &err_info, &data_offset)) { framenum++; tshark_debug("tshark: processing packet #%d", framenum); reset_epan_mem(cf, edt, create_proto_tree, print_packet_info && print_details); - if (process_packet_single_pass(cf, edt, data_offset, wtap_phdr(cf->wth), - wtap_buf_ptr(cf->wth), tap_flags)) { + if (process_packet_single_pass(cf, edt, data_offset, wtap_phdr(cf->provider.wth), + wtap_buf_ptr(cf->provider.wth), 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) { tshark_debug("tshark: writing packet #%d to outfile", framenum); - if (!wtap_dump(pdh, wtap_phdr(cf->wth), wtap_buf_ptr(cf->wth), &err, &err_info)) { + if (!wtap_dump(pdh, wtap_phdr(cf->provider.wth), wtap_buf_ptr(cf->provider.wth), &err, &err_info)) { /* Error writing to a capture file */ tshark_debug("tshark: error writing to a capture file (%d)", err); cfile_write_failure_message("TShark", cf->filename, save_file, @@ -3407,8 +3436,8 @@ process_cap_file(capture_file *cf, char *save_file, int out_file_type, } out: - wtap_close(cf->wth); - cf->wth = NULL; + wtap_close(cf->provider.wth); + cf->provider.wth = NULL; wtap_block_array_free(shb_hdrs); wtap_block_array_free(nrb_hdrs); @@ -3470,10 +3499,10 @@ process_packet_single_pass(capture_file *cf, epan_dissect_t *edt, gint64 offset, cinfo = NULL; frame_data_set_before_dissect(&fdata, &cf->elapsed_time, - &ref, prev_dis); - if (ref == &fdata) { + &cf->provider.ref, cf->provider.prev_dis); + if (cf->provider.ref == &fdata) { ref_frame = fdata; - ref = &ref_frame; + cf->provider.ref = &ref_frame; } if (dissect_color) { @@ -3481,7 +3510,9 @@ process_packet_single_pass(capture_file *cf, epan_dissect_t *edt, gint64 offset, fdata.flags.need_colorize = 1; } - epan_dissect_run_with_taps(edt, cf->cd_t, whdr, frame_tvbuff_new(&fdata, pd), &fdata, cinfo); + epan_dissect_run_with_taps(edt, cf->cd_t, whdr, + frame_tvbuff_new(&cf->provider, &fdata, pd), + &fdata, cinfo); /* Run the filter if we have it. */ if (cf->dfcode) @@ -3495,6 +3526,7 @@ process_packet_single_pass(capture_file *cf, epan_dissect_t *edt, gint64 offset, if (print_packet_info) { /* We're printing packet information; print the information for this packet. */ + g_assert(edt); print_packet(cf, edt); /* If we're doing "line-buffering", flush the standard output @@ -3511,11 +3543,11 @@ process_packet_single_pass(capture_file *cf, epan_dissect_t *edt, gint64 offset, /* this must be set after print_packet() [bug #8160] */ prev_dis_frame = fdata; - prev_dis = &prev_dis_frame; + cf->provider.prev_dis = &prev_dis_frame; } prev_cap_frame = fdata; - prev_cap = &prev_cap_frame; + cf->provider.prev_cap = &prev_cap_frame; if (edt) { epan_dissect_reset(edt); @@ -3722,7 +3754,7 @@ print_columns(capture_file *cf, const epan_dissect_t *edt) case COL_DEF_DST: case COL_RES_DST: case COL_UNRES_DST: - g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_RIGHTWARDS_ARROW, delimiter_char); + g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_RIGHTWARDS_ARROW, delimiter_char); put_string(line_bufp + buf_offset, str_format, 5); buf_offset += 5; break; @@ -3742,7 +3774,7 @@ print_columns(capture_file *cf, const epan_dissect_t *edt) case COL_DEF_DL_DST: case COL_RES_DL_DST: case COL_UNRES_DL_DST: - g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_RIGHTWARDS_ARROW, delimiter_char); + g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_RIGHTWARDS_ARROW, delimiter_char); put_string(line_bufp + buf_offset, str_format, 5); buf_offset += 5; break; @@ -3762,7 +3794,7 @@ print_columns(capture_file *cf, const epan_dissect_t *edt) case COL_DEF_NET_DST: case COL_RES_NET_DST: case COL_UNRES_NET_DST: - g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_RIGHTWARDS_ARROW, delimiter_char); + g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_RIGHTWARDS_ARROW, delimiter_char); put_string(line_bufp + buf_offset, str_format, 5); buf_offset += 5; break; @@ -3782,7 +3814,7 @@ print_columns(capture_file *cf, const epan_dissect_t *edt) case COL_DEF_SRC: case COL_RES_SRC: case COL_UNRES_SRC: - g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_LEFTWARDS_ARROW, delimiter_char); + g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_LEFTWARDS_ARROW, delimiter_char); put_string(line_bufp + buf_offset, str_format, 5); buf_offset += 5; break; @@ -3802,7 +3834,7 @@ print_columns(capture_file *cf, const epan_dissect_t *edt) case COL_DEF_DL_SRC: case COL_RES_DL_SRC: case COL_UNRES_DL_SRC: - g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_LEFTWARDS_ARROW, delimiter_char); + g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_LEFTWARDS_ARROW, delimiter_char); put_string(line_bufp + buf_offset, str_format, 5); buf_offset += 5; break; @@ -3822,7 +3854,7 @@ print_columns(capture_file *cf, const epan_dissect_t *edt) case COL_DEF_NET_SRC: case COL_RES_NET_SRC: case COL_UNRES_NET_SRC: - g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_LEFTWARDS_ARROW, delimiter_char); + g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_LEFTWARDS_ARROW, delimiter_char); put_string(line_bufp + buf_offset, str_format, 5); buf_offset += 5; break; @@ -3851,36 +3883,17 @@ print_columns(capture_file *cf, const epan_dissect_t *edt) static gboolean print_packet(capture_file *cf, epan_dissect_t *edt) { - if (print_summary || output_fields_has_cols(output_fields)) { + 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) { - - case WRITE_TEXT: - if (!print_columns(cf, edt)) - return FALSE; - break; - - case WRITE_XML: - write_psml_columns(edt, stdout, dissect_color); - return !ferror(stdout); - case WRITE_FIELDS: /*No non-verbose "fields" format */ - case WRITE_JSON: - case WRITE_EK: - case WRITE_JSON_RAW: - g_assert_not_reached(); - break; - } - } - } - if (print_details) { - /* Print the information in the protocol tree. */ - switch (output_action) { + /* Print summary columns and/or protocol tree */ + switch (output_action) { - case WRITE_TEXT: + case WRITE_TEXT: + if (print_summary && !print_columns(cf, edt)) + return FALSE; + if (print_details) { if (!proto_tree_print(print_details ? print_dissections_expanded : print_dissections_none, print_hex, edt, output_only_tables, print_stream)) return FALSE; @@ -3888,33 +3901,61 @@ print_packet(capture_file *cf, epan_dissect_t *edt) if (!print_line(print_stream, 0, separator)) return FALSE; } - break; + } + break; - case WRITE_XML: - write_pdml_proto_tree(output_fields, protocolfilter, protocolfilter_flags, edt, stdout, dissect_color); + case WRITE_XML: + if (print_summary) { + write_psml_columns(edt, stdout, dissect_color); + return !ferror(stdout); + } + if (print_details) { + write_pdml_proto_tree(output_fields, protocolfilter, protocolfilter_flags, edt, &cf->cinfo, stdout, dissect_color); printf("\n"); return !ferror(stdout); - case WRITE_FIELDS: + } + break; + + case WRITE_FIELDS: + if (print_summary) { + /*No non-verbose "fields" format */ + g_assert_not_reached(); + } + if (print_details) { write_fields_proto_tree(output_fields, edt, &cf->cinfo, stdout); printf("\n"); return !ferror(stdout); - case WRITE_JSON: + } + break; + + case WRITE_JSON: + if (print_summary) + g_assert_not_reached(); + if (print_details) { write_json_proto_tree(output_fields, print_dissections_expanded, print_hex, protocolfilter, protocolfilter_flags, - edt, stdout); - printf("\n"); + edt, &cf->cinfo, node_children_grouper, stdout); return !ferror(stdout); - case WRITE_JSON_RAW: + } + break; + + case WRITE_JSON_RAW: + if (print_summary) + g_assert_not_reached(); + if (print_details) { write_json_proto_tree(output_fields, print_dissections_none, TRUE, - protocolfilter, protocolfilter_flags, edt, stdout); - printf("\n"); - return !ferror(stdout); - case WRITE_EK: - write_ek_proto_tree(output_fields, print_hex, protocolfilter, - protocolfilter_flags, edt, stdout); + protocolfilter, protocolfilter_flags, + edt, &cf->cinfo, node_children_grouper, stdout); return !ferror(stdout); } + break; + + case WRITE_EK: + write_ek_proto_tree(output_fields, print_summary, print_hex, protocolfilter, + protocolfilter_flags, edt, &cf->cinfo, stdout); + return !ferror(stdout); } + if (print_hex) { if (print_summary || print_details) { if (!print_line(print_stream, 0, "")) @@ -3983,7 +4024,7 @@ cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_temp epan_free(cf->epan); cf->epan = tshark_epan_new(cf); - cf->wth = wth; + cf->provider.wth = wth; cf->f_datalen = 0; /* not used, but set it anyway */ /* Set the file name because we need it to set the follow stream filter. @@ -3997,21 +4038,21 @@ cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_temp /* No user changes yet. */ cf->unsaved_changes = FALSE; - cf->cd_t = wtap_file_type_subtype(cf->wth); + cf->cd_t = wtap_file_type_subtype(cf->provider.wth); cf->open_type = type; cf->count = 0; cf->drops_known = FALSE; cf->drops = 0; - cf->snap = wtap_snapshot_length(cf->wth); + cf->snap = wtap_snapshot_length(cf->provider.wth); nstime_set_zero(&cf->elapsed_time); - ref = NULL; - prev_dis = NULL; - prev_cap = NULL; + cf->provider.ref = NULL; + cf->provider.prev_dis = NULL; + cf->provider.prev_cap = NULL; cf->state = FILE_READ_IN_PROGRESS; - wtap_set_cb_new_ipv4(cf->wth, add_ipv4_name); - wtap_set_cb_new_ipv6(cf->wth, (wtap_new_ipv6_callback_t) add_ipv6_name); + wtap_set_cb_new_ipv4(cf->provider.wth, add_ipv4_name); + wtap_set_cb_new_ipv6(cf->provider.wth, (wtap_new_ipv6_callback_t) add_ipv6_name); return CF_OK;