X-Git-Url: http://git.samba.org/samba.git/?p=obnox%2Fwireshark%2Fwip.git;a=blobdiff_plain;f=tshark.c;h=296ab4a5ff7c3123c3435f144de8515ba32a8f96;hp=73c810a2cab02d5b797643467d215701c59c51be;hb=6ed34593966e17116ace8eb57a10c463c6957b95;hpb=2af0be08a49b37fa8429ea75821327888caada9f diff --git a/tshark.c b/tshark.c index 73c810a2ca..296ab4a5ff 100644 --- a/tshark.c +++ b/tshark.c @@ -51,20 +51,15 @@ # include #endif -#ifdef NEED_STRERROR_H -#include "strerror.h" -#endif - -#ifdef HAVE_GETOPT_H -#include -#else -#include "wsgetopt.h" +#ifndef HAVE_GETOPT +#include "wsutil/wsgetopt.h" #endif #include #include #include #include +#include #include "globals.h" #include @@ -94,13 +89,13 @@ #include "capture-pcap-util.h" #ifdef _WIN32 #include "capture-wpcap.h" -#include "capture_errs.h" +#include #endif /* _WIN32 */ #include "capture_sync.h" #endif /* HAVE_LIBPCAP */ #include "log.h" #include - +#include "capture_opts.h" /* * This is the template for the decode as option; it is shared between the @@ -113,7 +108,7 @@ static nstime_t first_ts; static nstime_t prev_dis_ts; static nstime_t prev_cap_ts; -static gboolean print_packet_info; /* TRUE if we're to print packet information */ +static gboolean print_packet_info; /* TRUE if we're to print packet information */ static gboolean perform_two_pass_analysis; @@ -121,14 +116,14 @@ static gboolean perform_two_pass_analysis; * The way the packet decode is to be written. */ typedef enum { - WRITE_TEXT, /* summary or detail text */ - WRITE_XML, /* PDML or PSML */ - WRITE_FIELDS /* User defined list of fields */ - /* Add CSV and the like here */ + WRITE_TEXT, /* summary or detail text */ + WRITE_XML, /* PDML or PSML */ + WRITE_FIELDS /* User defined list of fields */ + /* Add CSV and the like here */ } output_action_e; static output_action_e output_action; -static gboolean do_dissection; /* TRUE if we have to dissect each packet */ +static gboolean do_dissection; /* TRUE if we have to dissect each packet */ static gboolean verbose; static gboolean print_hex; static gboolean line_buffered; @@ -138,11 +133,8 @@ static print_stream_t *print_stream; static output_fields_t* output_fields = NULL; -/* - * Standard secondary message for unexpected errors. - */ -static const char please_report[] = - "Please report this to the Wireshark developers"; +/* The line separator used between packets, changeable via the -S option */ +static char *separator = ""; #ifdef HAVE_LIBPCAP /* @@ -150,12 +142,11 @@ static const char please_report[] = */ static gboolean print_packet_counts; - static capture_options global_capture_opts; #ifdef SIGINFO -static gboolean infodelay; /* if TRUE, don't print capture info in SIGINFO handler */ -static gboolean infoprint; /* if TRUE, print capture info after clearing infodelay */ +static gboolean infodelay; /* if TRUE, don't print capture info in SIGINFO handler */ +static gboolean infoprint; /* if TRUE, print capture info after clearing infodelay */ #endif /* SIGINFO */ static gboolean capture(void); @@ -170,7 +161,7 @@ static void report_counts_siginfo(int); #endif /* _WIN32 */ #endif /* HAVE_LIBPCAP */ -static int load_cap_file(capture_file *, char *, int, int, gint64); +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); @@ -190,21 +181,45 @@ static void write_failure_message(const char *filename, int err); capture_file cfile; -void -cf_mark_frame(capture_file *cf _U_, frame_data *frame _U_) +struct string_elem { + const char *sstr; /* The short string */ + const char *lstr; /* The long string */ +}; + +static gint +string_compare(gconstpointer a, gconstpointer b) { - g_assert_not_reached(); + return strcmp(((const struct string_elem *)a)->sstr, + ((const struct string_elem *)b)->sstr); +} + +static void +string_elem_print(gpointer data, gpointer not_used _U_) +{ + fprintf(stderr, " %s - %s\n", + ((struct string_elem *)data)->sstr, + ((struct string_elem *)data)->lstr); } -static void list_capture_types(void) { - int i; +static void +list_capture_types(void) { + int i; + struct string_elem *captypes; + GSList *list = NULL; + + captypes = g_malloc(sizeof(struct string_elem) * WTAP_NUM_FILE_TYPES); - fprintf(stderr, "editcap: The available capture file types for \"F\":\n"); - for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) { - if (wtap_dump_can_open(i)) - fprintf(stderr, " %s - %s\n", - wtap_file_type_short_string(i), wtap_file_type_string(i)); + fprintf(stderr, "tshark: The available capture file types for the \"-F\" flag are:\n"); + for (i = 0; i < WTAP_NUM_FILE_TYPES; i++) { + if (wtap_dump_can_open(i)) { + captypes[i].sstr = wtap_file_type_short_string(i); + captypes[i].lstr = wtap_file_type_string(i); + list = g_slist_insert_sorted(list, &captypes[i], string_compare); } + } + g_slist_foreach(list, string_elem_print, NULL); + g_slist_free(list); + g_free(captypes); } static void @@ -220,7 +235,7 @@ print_usage(gboolean print_ver) "See http://www.wireshark.org for more information.\n" "\n" "%s", - wireshark_svnversion, get_copyright_info()); + wireshark_svnversion, get_copyright_info()); } else { output = stderr; } @@ -262,22 +277,28 @@ print_usage(gboolean print_ver) fprintf(output, "\n"); fprintf(output, "Processing:\n"); + fprintf(output, " -2 perform a two-pass analysis\n"); fprintf(output, " -R packet filter in Wireshark display filter syntax\n"); fprintf(output, " -n disable all name resolutions (def: all enabled)\n"); fprintf(output, " -N enable specific name resolution(s): \"mntC\"\n"); fprintf(output, " -d %s ...\n", decode_as_arg_template); fprintf(output, " \"Decode As\", see the man page for details\n"); fprintf(output, " Example: tcp.port==8888,http\n"); + fprintf(output, " -H read a list of entries from a hosts file, which will\n"); + fprintf(output, " then be written to a capture file. (Implies -W n)\n"); /*fprintf(output, "\n");*/ fprintf(output, "Output:\n"); fprintf(output, " -w write packets to a pcap-format file named \"outfile\"\n"); fprintf(output, " (or to the standard output for \"-\")\n"); fprintf(output, " -C start with specified configuration profile\n"); - fprintf(output, " -F set the output file type, default is libpcap\n"); + fprintf(output, " -F set the output file type, default is pcapng\n"); fprintf(output, " an empty \"-F\" option will list the file types\n"); fprintf(output, " -V add output of packet tree (Packet Details)\n"); - fprintf(output, " -S display packets even when writing to a file\n"); + fprintf(output, " -O 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, " -S 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"); @@ -286,11 +307,16 @@ print_usage(gboolean print_ver) fprintf(output, " -E= set options for output when -Tfields selected:\n"); fprintf(output, " header=y|n switch headers on and off\n"); fprintf(output, " separator=/t|/s| select tab, space, printable character as separator\n"); + fprintf(output, " occurrence=f|l|a print first, last or all occurrences of each field\n"); + fprintf(output, " aggregator=,|/s| 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, " -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, " -W n Save extra information in the file, if supported.\n"); + fprintf(output, " n = write network address resolution information\n"); fprintf(output, " -X : eXtension options, see the man page for details\n"); fprintf(output, " -z various statistics, see the man page for details\n"); @@ -300,6 +326,38 @@ print_usage(gboolean print_ver) fprintf(output, " -v display version info and exit\n"); fprintf(output, " -o : ... override preference setting\n"); 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"); +} + +static void +glossary_option_help(void) +{ + FILE *output; + + output = stdout; + + fprintf(output, "TShark " VERSION "%s\n", wireshark_svnversion); + + fprintf(output, "\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 protocols dump protocols in registration database and exit\n"); + fprintf(output, " -G values dump value, range, true/false strings and exit\n"); + fprintf(output, " -G ftypes dump field type basic and descriptive names\n"); + fprintf(output, " -G decodes dump \"layer type\"/\"decode as\" associations and exit\n"); + fprintf(output, " -G heuristic-decodes dump heuristic dissector tables\n"); + fprintf(output, "\n"); + fprintf(output, "Preference reports:\n"); + fprintf(output, " -G defaultprefs dump default preferences and exit\n"); + fprintf(output, " -G currentprefs dump current preferences and exit\n"); + fprintf(output, "\n"); + } /* @@ -539,7 +597,6 @@ add_decode_as(const gchar *cl_param) case FT_STRING: case FT_STRINGZ: - case FT_EBCDIC: /* The selector for this table is a string. */ break; @@ -599,7 +656,7 @@ add_decode_as(const gchar *cl_param) cmdarg_err("Unknown protocol -- \"%s\"", dissector_str); } else { cmdarg_err("Protocol \"%s\" isn't valid for layer type \"%s\"", - dissector_str, table_name); + dissector_str, table_name); } } } @@ -631,12 +688,11 @@ add_decode_as(const gchar *cl_param) case FT_UINT24: case FT_UINT32: /* The selector for this table is an unsigned number. */ - dissector_change(table_name, selector, dissector_matching); + dissector_change_uint(table_name, selector, dissector_matching); break; case FT_STRING: case FT_STRINGZ: - case FT_EBCDIC: /* The selector for this table is a string. */ dissector_change_string(table_name, selector_str, dissector_matching); break; @@ -646,7 +702,7 @@ add_decode_as(const gchar *cl_param) than the ones listed above. */ g_assert_not_reached(); } - g_free(decoded_param); /* "Decode As" rule has been succesfully added */ + g_free(decoded_param); /* "Decode As" rule has been successfully added */ return TRUE; } @@ -700,12 +756,16 @@ print_current_user(void) { cur_group = get_cur_groupname(); fprintf(stderr, "Running as user \"%s\" and group \"%s\".", cur_user, cur_group); - g_free(cur_user); - g_free(cur_group); if (running_with_special_privs()) { - fprintf(stderr, " This could be dangerous."); + fprintf(stderr, "Running as user \"%s\" and group \"%s\". This could be dangerous.\n", + cur_user, cur_group); } - fprintf(stderr, "\n"); + else { + fprintf(stdout, "Running as user \"%s\" and group \"%s\".", + cur_user, cur_group); + } + g_free(cur_user); + g_free(cur_group); } } @@ -743,8 +803,8 @@ main(int argc, char *argv[]) gboolean arg_error = FALSE; #ifdef _WIN32 - WSADATA wsaData; -#endif /* _WIN32 */ + WSADATA wsaData; +#endif /* _WIN32 */ char *gpf_path, *pf_path; char *gdp_path, *dp_path; @@ -753,18 +813,27 @@ main(int argc, char *argv[]) int gdp_open_errno, gdp_read_errno; int dp_open_errno, dp_read_errno; int err; + volatile int exit_status = 0; #ifdef HAVE_LIBPCAP gboolean list_link_layer_types = FALSE; gboolean start_capture = FALSE; int status; GList *if_list; gchar *err_str; + guint i; + interface_options interface_opts; #else gboolean capture_option_specified = FALSE; #endif gboolean quiet = FALSE; - int out_file_type = WTAP_FILE_PCAP; - gchar *cf_name = NULL, *rfilter = NULL; +#ifdef PCAP_NG_DEFAULT + volatile int out_file_type = WTAP_FILE_PCAPNG; +#else + volatile int out_file_type = WTAP_FILE_PCAP; +#endif + volatile gboolean out_file_name_res = FALSE; + gchar *volatile cf_name = NULL; + gchar *rfilter = NULL; #ifdef HAVE_PCAP_OPEN_DEAD struct bpf_program fcode; #endif @@ -773,6 +842,7 @@ main(int argc, char *argv[]) char badopt; GLogLevelFlags log_flags; int optind_initial; + gchar *output_only = NULL; #ifdef HAVE_LIBPCAP #if defined(_WIN32) || defined(HAVE_PCAP_CREATE) @@ -790,14 +860,21 @@ main(int argc, char *argv[]) #define OPTSTRING_I "" #endif -#define OPTSTRING "a:b:" OPTSTRING_B "c:C:d:De:E:f:F:G:hi:" OPTSTRING_I "K:lLnN:o:pPqr:R:s:St:T:u:vVw:xX:y:z:" +#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:" static const char optstring[] = OPTSTRING; +#ifdef _WIN32 + arg_list_utf_16to8(argc, argv); +#if !GLIB_CHECK_VERSION(2,31,0) + g_thread_init(NULL); +#endif +#endif /* _WIN32 */ + /* * Get credential information for later use. */ - get_credential_info(); + init_process_policies(); /* * Attempt to get the pathname of the executable file. @@ -816,21 +893,21 @@ main(int argc, char *argv[]) optind_initial = optind; while ((opt = getopt(argc, argv, optstring)) != -1) { - switch (opt) { - case 'C': /* Configuration Profile */ - if (profile_exists (optarg)) { - set_profile_name (optarg); - } else { - cmdarg_err("Configuration Profile \"%s\" does not exist", optarg); - return 1; - } - break; - case 'X': - ex_opt_add(optarg); - break; - default: - break; - } + switch (opt) { + case 'C': /* Configuration Profile */ + if (profile_exists (optarg, FALSE)) { + set_profile_name (optarg); + } else { + cmdarg_err("Configuration Profile \"%s\" does not exist", optarg); + return 1; + } + break; + case 'X': + ex_opt_add(optarg); + break; + default: + break; + } } optind = optind_initial; @@ -841,28 +918,28 @@ main(int argc, char *argv[]) /** Send All g_log messages to our own handler **/ log_flags = - G_LOG_LEVEL_ERROR| - G_LOG_LEVEL_CRITICAL| - G_LOG_LEVEL_WARNING| - G_LOG_LEVEL_MESSAGE| - G_LOG_LEVEL_INFO| - G_LOG_LEVEL_DEBUG| - G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION; + G_LOG_LEVEL_ERROR| + G_LOG_LEVEL_CRITICAL| + G_LOG_LEVEL_WARNING| + G_LOG_LEVEL_MESSAGE| + G_LOG_LEVEL_INFO| + G_LOG_LEVEL_DEBUG| + G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION; g_log_set_handler(NULL, - log_flags, - tshark_log_handler, NULL /* user_data */); + log_flags, + tshark_log_handler, NULL /* user_data */); g_log_set_handler(LOG_DOMAIN_MAIN, - log_flags, - tshark_log_handler, NULL /* user_data */); + log_flags, + tshark_log_handler, NULL /* user_data */); #ifdef HAVE_LIBPCAP g_log_set_handler(LOG_DOMAIN_CAPTURE, - log_flags, - tshark_log_handler, NULL /* user_data */); + log_flags, + tshark_log_handler, NULL /* user_data */); g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD, - log_flags, - tshark_log_handler, NULL /* user_data */); + log_flags, + tshark_log_handler, NULL /* user_data */); #endif initialize_funnel_ops(); @@ -907,7 +984,7 @@ main(int argc, char *argv[]) If none of our build or other processes uses "-G" with no arguments, we can just process it with the other arguments. */ if (argc >= 2 && strcmp(argv[1], "-G") == 0) { - proto_initialize_all_prefixes(); + proto_initialize_all_prefixes(); if (argc == 2) proto_registrar_dump_fields(1); @@ -922,16 +999,26 @@ 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], "ftypes") == 0) + proto_registrar_dump_ftypes(); else if (strcmp(argv[2], "decodes") == 0) dissector_dump_decodes(); + else if (strcmp(argv[2], "heuristic-decodes") == 0) + dissector_dump_heur_decodes(); else if (strcmp(argv[2], "defaultprefs") == 0) write_prefs(NULL); + else if (strcmp(argv[2], "plugins") == 0) + plugins_dump_all(); + else if (strcmp(argv[2], "?") == 0) + glossary_option_help(); + else if (strcmp(argv[2], "-?") == 0) + glossary_option_help(); else if (strcmp(argv[2], "currentprefs") == 0) { read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path, &pf_open_errno, &pf_read_errno, &pf_path); write_prefs(NULL); } else { - cmdarg_err("Invalid \"%s\" option for -G flag", argv[2]); + cmdarg_err("Invalid \"%s\" option for -G flag, enter -G ? for more help.", argv[2]); return 1; } } @@ -946,28 +1033,28 @@ main(int argc, char *argv[]) if (gpf_path != NULL) { if (gpf_open_errno != 0) { cmdarg_err("Can't open global preferences file \"%s\": %s.", - pf_path, strerror(gpf_open_errno)); + pf_path, g_strerror(gpf_open_errno)); } if (gpf_read_errno != 0) { cmdarg_err("I/O error reading global preferences file \"%s\": %s.", - pf_path, strerror(gpf_read_errno)); + pf_path, g_strerror(gpf_read_errno)); } } if (pf_path != NULL) { if (pf_open_errno != 0) { cmdarg_err("Can't open your preferences file \"%s\": %s.", pf_path, - strerror(pf_open_errno)); + g_strerror(pf_open_errno)); } if (pf_read_errno != 0) { cmdarg_err("I/O error reading your preferences file \"%s\": %s.", - pf_path, strerror(pf_read_errno)); + pf_path, g_strerror(pf_read_errno)); } g_free(pf_path); pf_path = NULL; } /* Set the name resolution code's flags from the preferences. */ - g_resolv_flags = prefs_p->name_resolve; + gbl_resolv_flags = prefs_p->name_resolve; /* Read the disabled protocols file. */ read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno, @@ -975,11 +1062,11 @@ main(int argc, char *argv[]) if (gdp_path != NULL) { if (gdp_open_errno != 0) { cmdarg_err("Could not open global disabled protocols file\n\"%s\": %s.", - gdp_path, strerror(gdp_open_errno)); + gdp_path, g_strerror(gdp_open_errno)); } if (gdp_read_errno != 0) { cmdarg_err("I/O error reading global disabled protocols file\n\"%s\": %s.", - gdp_path, strerror(gdp_read_errno)); + gdp_path, g_strerror(gdp_read_errno)); } g_free(gdp_path); } @@ -987,12 +1074,12 @@ main(int argc, char *argv[]) if (dp_open_errno != 0) { cmdarg_err( "Could not open your disabled protocols file\n\"%s\": %s.", dp_path, - strerror(dp_open_errno)); + g_strerror(dp_open_errno)); } if (dp_read_errno != 0) { cmdarg_err( "I/O error reading your disabled protocols file\n\"%s\": %s.", dp_path, - strerror(dp_read_errno)); + g_strerror(dp_read_errno)); } g_free(dp_path); } @@ -1009,274 +1096,297 @@ main(int argc, char *argv[]) /* Now get our args */ while ((opt = getopt(argc, argv, optstring)) != -1) { switch (opt) { - case 'a': /* autostop criteria */ - case 'b': /* Ringbuffer option */ - case 'c': /* Capture x packets */ - case 'f': /* capture filter */ - case 'i': /* Use interface x */ - case 'p': /* Don't capture in promiscuous mode */ + case '2': /* Perform two pass analysis */ + perform_two_pass_analysis = TRUE; + break; + case 'a': /* autostop criteria */ + case 'b': /* Ringbuffer option */ + case 'c': /* Capture x packets */ + case 'f': /* capture filter */ + case 'i': /* Use interface x */ + case 'p': /* Don't capture in promiscuous mode */ #ifdef HAVE_PCAP_CREATE - case 'I': /* Capture in monitor mode, if available */ + case 'I': /* Capture in monitor mode, if available */ #endif - case 's': /* Set the snapshot (capture) length */ - case 'w': /* Write to capture file x */ - case 'y': /* Set the pcap data link type */ + case 's': /* Set the snapshot (capture) length */ + case 'w': /* Write to capture file x */ + case 'y': /* Set the pcap data link type */ #if defined(_WIN32) || defined(HAVE_PCAP_CREATE) - case 'B': /* Buffer size */ + case 'B': /* Buffer size */ #endif /* _WIN32 or HAVE_PCAP_CREATE */ #ifdef HAVE_LIBPCAP - status = capture_opts_add_opt(&global_capture_opts, opt, optarg, &start_capture); - if(status != 0) { - return status; - } + status = capture_opts_add_opt(&global_capture_opts, opt, optarg, &start_capture); + if(status != 0) { + return status; + } #else - capture_option_specified = TRUE; - arg_error = TRUE; + capture_option_specified = TRUE; + arg_error = TRUE; #endif - break; - case 'C': - /* Configuration profile settings were already processed just ignore them this time*/ - break; - case 'd': /* Decode as rule */ - if (!add_decode_as(optarg)) - return 1; - break; + break; + case 'C': + /* Configuration profile settings were already processed just ignore them this time*/ + break; + case 'd': /* Decode as rule */ + if (!add_decode_as(optarg)) + return 1; + break; #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS) - case 'K': /* Kerberos keytab file */ - read_keytab_file(optarg); - break; + case 'K': /* Kerberos keytab file */ + read_keytab_file(optarg); + break; #endif - case 'D': /* Print a list of capture devices and exit */ + case 'D': /* Print a list of capture devices and exit */ #ifdef HAVE_LIBPCAP - if_list = capture_interface_list(&err, &err_str); - if (if_list == NULL) { - switch (err) { - case CANT_GET_INTERFACE_LIST: - cmdarg_err("%s", err_str); - g_free(err_str); - break; + if_list = capture_interface_list(&err, &err_str); + if (if_list == NULL) { + switch (err) { + case CANT_GET_INTERFACE_LIST: + case DONT_HAVE_PCAP: + cmdarg_err("%s", err_str); + g_free(err_str); + break; - case NO_INTERFACES_FOUND: - cmdarg_err("There are no interfaces on which a capture can be done"); - break; - } - return 2; + case NO_INTERFACES_FOUND: + cmdarg_err("There are no interfaces on which a capture can be done"); + break; } - capture_opts_print_interfaces(if_list); - free_interface_list(if_list); - return 0; + return 2; + } + capture_opts_print_interfaces(if_list); + free_interface_list(if_list); + return 0; #else - capture_option_specified = TRUE; - arg_error = TRUE; + capture_option_specified = TRUE; + arg_error = TRUE; #endif - break; - case 'e': - /* Field entry */ - output_fields_add(output_fields, optarg); - break; - case 'E': - /* Field option */ - 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 'F': - out_file_type = wtap_short_string_to_file_type(optarg); - if (out_file_type < 0) { - cmdarg_err("\"%s\" isn't a valid capture file type", optarg); - list_capture_types(); - return 1; - } - break; - case 'h': /* Print help and exit */ - print_usage(TRUE); - return 0; - break; - case 'l': /* "Line-buffer" standard output */ - /* This isn't line-buffering, strictly speaking, it's just - flushing the standard output after the information for - each packet is printed; however, that should be good - enough for all the purposes to which "-l" is put (and - is probably actually better for "-V", as it does fewer - writes). - - See the comment in "process_packet()" for an explanation of - why we do that, and why we don't just use "setvbuf()" to - make the standard output line-buffered (short version: in - Windows, "line-buffered" is the same as "fully-buffered", - and the output buffer is only flushed when it fills up). */ - line_buffered = TRUE; - break; - case 'L': /* Print list of link-layer types and exit */ + break; + case 'e': + /* Field entry */ + output_fields_add(output_fields, optarg); + break; + case 'E': + /* Field option */ + 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 'F': + out_file_type = wtap_short_string_to_file_type(optarg); + if (out_file_type < 0) { + cmdarg_err("\"%s\" isn't a valid capture file type", optarg); + list_capture_types(); + 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')) + out_file_name_res = TRUE; + break; + case 'H': /* Read address to name mappings from a hosts file */ + if (! read_hosts_file(optarg)) + { + cmdarg_err("Can't read host entries from \"%s\"", optarg); + return 1; + } + out_file_name_res = TRUE; + break; + + case 'h': /* Print help and exit */ + print_usage(TRUE); + return 0; + break; + case 'l': /* "Line-buffer" standard output */ + /* This isn't line-buffering, strictly speaking, it's just + flushing the standard output after the information for + each packet is printed; however, that should be good + enough for all the purposes to which "-l" is put (and + is probably actually better for "-V", as it does fewer + writes). + + See the comment in "process_packet()" for an explanation of + why we do that, and why we don't just use "setvbuf()" to + make the standard output line-buffered (short version: in + Windows, "line-buffered" is the same as "fully-buffered", + and the output buffer is only flushed when it fills up). */ + line_buffered = TRUE; + break; + case 'L': /* Print list of link-layer types and exit */ #ifdef HAVE_LIBPCAP - list_link_layer_types = TRUE; + list_link_layer_types = TRUE; #else - capture_option_specified = TRUE; - arg_error = TRUE; -#endif - break; -#if GLIB_CHECK_VERSION(2,10,0) - case 'P': /* Perform two pass analysis */ - perform_two_pass_analysis = TRUE; - break; + capture_option_specified = TRUE; + arg_error = TRUE; #endif - case 'n': /* No name resolution */ - g_resolv_flags = RESOLV_NONE; - break; - case 'N': /* Select what types of addresses/port #s to resolve */ - if (g_resolv_flags == RESOLV_ALL) - g_resolv_flags = RESOLV_NONE; - badopt = string_to_name_resolve(optarg, &g_resolv_flags); - if (badopt != '\0') { - cmdarg_err("-N specifies unknown resolving option '%c';", - badopt); - cmdarg_err_cont( " Valid options are 'm', 'n', 't', and 'C'"); - return 1; - } - break; - case 'o': /* Override preference from command line */ - switch (prefs_set_pref(optarg)) { - - case PREFS_SET_OK: - break; - - case PREFS_SET_SYNTAX_ERR: - cmdarg_err("Invalid -o flag \"%s\"", optarg); - return 1; - break; + break; + case 'n': /* No name resolution */ + gbl_resolv_flags = RESOLV_NONE; + 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';", + badopt); + cmdarg_err_cont( " Valid options are 'm', 'n', 't', and 'C'"); + return 1; + } + break; + case 'o': /* Override preference from command line */ + switch (prefs_set_pref(optarg)) { - case PREFS_SET_NO_SUCH_PREF: - case PREFS_SET_OBSOLETE: - cmdarg_err("-o flag \"%s\" specifies unknown preference", optarg); - return 1; - break; - } - break; - case 'q': /* Quiet */ - quiet = TRUE; - break; - case 'r': /* Read capture file x */ - cf_name = g_strdup(optarg); - break; - case 'R': /* Read file filter */ - rfilter = optarg; - break; - case 'S': /* show packets in real time */ - print_packet_info = TRUE; - break; - case 't': /* Time stamp type */ - if (strcmp(optarg, "r") == 0) - timestamp_set_type(TS_RELATIVE); - else if (strcmp(optarg, "a") == 0) - timestamp_set_type(TS_ABSOLUTE); - else if (strcmp(optarg, "ad") == 0) - timestamp_set_type(TS_ABSOLUTE_WITH_DATE); - else if (strcmp(optarg, "d") == 0) - timestamp_set_type(TS_DELTA); - else if (strcmp(optarg, "dd") == 0) - timestamp_set_type(TS_DELTA_DIS); - else if (strcmp(optarg, "e") == 0) - timestamp_set_type(TS_EPOCH); - 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."); - return 1; - } - break; - case 'T': /* printing Type */ - if (strcmp(optarg, "text") == 0) { - output_action = WRITE_TEXT; - print_format = PR_FMT_TEXT; - } else if (strcmp(optarg, "ps") == 0) { - output_action = WRITE_TEXT; - print_format = PR_FMT_PS; - } else if (strcmp(optarg, "pdml") == 0) { - output_action = WRITE_XML; - verbose = TRUE; - } else if (strcmp(optarg, "psml") == 0) { - output_action = WRITE_XML; - verbose = FALSE; - } else if(strcmp(optarg, "fields") == 0) { - output_action = WRITE_FIELDS; - verbose = TRUE; /* Need full tree info */ - } else { - cmdarg_err("Invalid -T parameter."); - cmdarg_err_cont("It must be \"ps\", \"text\", \"pdml\", \"psml\" or \"fields\"."); - return 1; - } + case PREFS_SET_OK: break; - case 'u': /* Seconds type */ - if (strcmp(optarg, "s") == 0) - timestamp_set_seconds_type(TS_SECONDS_DEFAULT); - else if (strcmp(optarg, "hms") == 0) - timestamp_set_seconds_type(TS_SECONDS_HOUR_MIN_SEC); - else { - cmdarg_err("Invalid seconds type \"%s\"", optarg); - cmdarg_err_cont("It must be \"s\" for seconds or \"hms\" for hours, minutes and seconds."); - return 1; - } + + case PREFS_SET_SYNTAX_ERR: + cmdarg_err("Invalid -o flag \"%s\"", optarg); + return 1; 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, get_epan_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); - return 0; + + case PREFS_SET_NO_SUCH_PREF: + case PREFS_SET_OBSOLETE: + cmdarg_err("-o flag \"%s\" specifies unknown preference", optarg); + return 1; break; } - case 'V': /* Verbose */ + break; + case 'q': /* Quiet */ + 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 'S': /* Set the line Separator to be printed between packets */ + separator = strdup(optarg); + break; + case 't': /* Time stamp type */ + if (strcmp(optarg, "r") == 0) + timestamp_set_type(TS_RELATIVE); + else if (strcmp(optarg, "a") == 0) + timestamp_set_type(TS_ABSOLUTE); + else if (strcmp(optarg, "ad") == 0) + timestamp_set_type(TS_ABSOLUTE_WITH_DATE); + else if (strcmp(optarg, "d") == 0) + timestamp_set_type(TS_DELTA); + else if (strcmp(optarg, "dd") == 0) + timestamp_set_type(TS_DELTA_DIS); + else if (strcmp(optarg, "e") == 0) + timestamp_set_type(TS_EPOCH); + else if (strcmp(optarg, "u") == 0) + timestamp_set_type(TS_UTC); + else if (strcmp(optarg, "ud") == 0) + timestamp_set_type(TS_UTC_WITH_DATE); + 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."); + return 1; + } + break; + case 'T': /* printing Type */ + if (strcmp(optarg, "text") == 0) { + output_action = WRITE_TEXT; + print_format = PR_FMT_TEXT; + } else if (strcmp(optarg, "ps") == 0) { + output_action = WRITE_TEXT; + print_format = PR_FMT_PS; + } else if (strcmp(optarg, "pdml") == 0) { + output_action = WRITE_XML; 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; - 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': - 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 - by the preferences set callback) from being used as - 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."); - cmdarg_err_cont(" -z argument must be one of :"); - list_stat_cmd_args(); - return 1; - } - break; - default: - case '?': /* Bad flag - print usage message */ - switch(optopt) { - case 'F': - list_capture_types(); - break; - default: - print_usage(TRUE); - } + } else if (strcmp(optarg, "psml") == 0) { + output_action = WRITE_XML; + verbose = FALSE; + } else if(strcmp(optarg, "fields") == 0) { + output_action = WRITE_FIELDS; + verbose = TRUE; /* Need full tree info */ + } else { + cmdarg_err("Invalid -T parameter."); + cmdarg_err_cont("It must be \"ps\", \"text\", \"pdml\", \"psml\" or \"fields\"."); return 1; + } + break; + case 'u': /* Seconds type */ + if (strcmp(optarg, "s") == 0) + timestamp_set_seconds_type(TS_SECONDS_DEFAULT); + else if (strcmp(optarg, "hms") == 0) + timestamp_set_seconds_type(TS_SECONDS_HOUR_MIN_SEC); + else { + cmdarg_err("Invalid seconds type \"%s\"", optarg); + cmdarg_err_cont("It must be \"s\" for seconds or \"hms\" for hours, minutes and seconds."); + return 1; + } + 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); + return 0; + break; + } + case 'O': /* Only output these protocols */ + output_only = g_strdup(optarg); + /* FALLTHROUGH */ + 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; + 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': + 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 + by the preferences set callback) from being used as + 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."); + cmdarg_err_cont(" -z argument must be one of :"); + list_stat_cmd_args(); + return 1; + } + break; + default: + case '?': /* Bad flag - print usage message */ + switch(optopt) { + case 'F': + list_capture_types(); break; + default: + print_usage(TRUE); + } + return 1; + break; } } @@ -1300,19 +1410,30 @@ main(int argc, char *argv[]) if (cf_name != NULL) { if (rfilter != NULL) { cmdarg_err("Read filters were specified both with \"-R\" " - "and with additional command-line arguments"); + "and with additional command-line arguments."); return 1; } rfilter = get_args_as_string(argc, argv, optind); } else { #ifdef HAVE_LIBPCAP - if (global_capture_opts.has_cfilter) { - cmdarg_err("Capture filters were specified both with \"-f\"" - " and with additional command-line arguments"); + 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; } - global_capture_opts.has_cfilter = TRUE; - global_capture_opts.cfilter = get_args_as_string(argc, argv, optind); + for (i = 0; i < global_capture_opts.ifaces->len; i++) { + 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); + } else { + cmdarg_err("A capture filter was specified both with \"-f\"" + " and with additional command-line arguments."); + return 1; + } + } + global_capture_opts.default_options.cfilter = get_args_as_string(argc, argv, optind); #else capture_option_specified = TRUE; #endif @@ -1358,7 +1479,7 @@ main(int argc, char *argv[]) support in capture files we read). */ #ifdef HAVE_LIBPCAP if (cf_name != NULL) { - if (global_capture_opts.has_cfilter) { + if (global_capture_opts.default_options.cfilter) { cmdarg_err("Only read filters, not capture filters, " "can be specified when reading a capture file."); return 1; @@ -1373,6 +1494,20 @@ main(int argc, char *argv[]) } } + if (output_only != NULL) { + char *ps; + + if (!verbose) { + cmdarg_err("-O requires -V"); + return 1; + } + + output_only_tables = g_hash_table_new (g_str_hash, g_str_equal); + for (ps = strtok (output_only, ","); ps; ps = strtok (NULL, ",")) { + g_hash_table_insert(output_only_tables, (gpointer)ps, (gpointer)ps); + } + } + #ifdef HAVE_LIBPCAP if (list_link_layer_types) { /* We're supposed to list the link-layer types for an interface; @@ -1430,8 +1565,8 @@ main(int argc, char *argv[]) if (global_capture_opts.saving_to_file) { /* They specified a "-w" flag, so we'll be saving to a capture file. */ - /* When capturing, we only support writing libpcap format. */ - if (out_file_type != WTAP_FILE_PCAP) { + /* When capturing, we only support writing pcap or pcap-ng format. */ + if (out_file_type != WTAP_FILE_PCAP && out_file_type != WTAP_FILE_PCAPNG) { cmdarg_err("Live captures can only be saved in libpcap format."); return 1; } @@ -1439,7 +1574,7 @@ main(int argc, char *argv[]) /* Multiple-file mode doesn't work under certain conditions: a) it doesn't work if you're writing to the standard output; b) it doesn't work if you're writing to a pipe; - */ + */ if (strcmp(global_capture_opts.save_file, "-") == 0) { cmdarg_err("Multiple capture files requested, but " "the capture is being written to the standard output."); @@ -1451,12 +1586,18 @@ main(int argc, char *argv[]) return 1; } if (!global_capture_opts.has_autostop_filesize && - !global_capture_opts.has_file_duration) { + !global_capture_opts.has_file_duration) { cmdarg_err("Multiple capture files requested, but " "no maximum capture file size or duration was specified."); return 1; } } + /* Currently, we don't support read 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; + } } 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 @@ -1491,6 +1632,22 @@ main(int argc, char *argv[]) of the filter. We can now process all the "-z" arguments. */ start_requested_stats(); +#ifdef HAVE_LIBPCAP + /* We currently don't support taps, or printing dissected packets, + if we're writing to a pipe. */ + if (global_capture_opts.saving_to_file && + global_capture_opts.output_to_pipe) { + if (tap_listeners_require_dissection()) { + cmdarg_err("Taps aren't supported when saving to a pipe."); + return 1; + } + if (print_packet_info) { + cmdarg_err("Printing dissected packets isn't supported when saving to a pipe."); + return 1; + } + } +#endif + /* disabled protocols as per configuration file */ if (gdp_path == NULL && dp_path == NULL) { set_disabled_protos_list(); @@ -1555,8 +1712,8 @@ main(int argc, char *argv[]) we're using a read filter on the packets; - we're using any taps. */ - do_dissection = print_packet_info || rfcode || have_tap_listeners(); + we're using any taps that need dissection. */ + do_dissection = print_packet_info || rfcode || tap_listeners_require_dissection(); if (cf_name) { /* @@ -1602,35 +1759,36 @@ main(int argc, char *argv[]) } /* Process the packets in the file */ + TRY { #ifdef HAVE_LIBPCAP - err = load_cap_file(&cfile, global_capture_opts.save_file, out_file_type, - global_capture_opts.has_autostop_packets ? global_capture_opts.autostop_packets : 0, - global_capture_opts.has_autostop_filesize ? global_capture_opts.autostop_filesize : 0); + err = load_cap_file(&cfile, global_capture_opts.save_file, out_file_type, out_file_name_res, + global_capture_opts.has_autostop_packets ? global_capture_opts.autostop_packets : 0, + global_capture_opts.has_autostop_filesize ? global_capture_opts.autostop_filesize : 0); #else - err = load_cap_file(&cfile, NULL, out_file_type, 0, 0); + err = load_cap_file(&cfile, NULL, out_file_type, out_file_name_res, 0, 0); #endif + } + CATCH(OutOfMemoryError) { + fprintf(stderr, + "Out Of Memory!\n" + "\n" + "Sorry, but TShark has to terminate now!\n" + "\n" + "Some infos / workarounds can be found at:\n" + "http://wiki.wireshark.org/KnownBugs/OutOfMemory\n"); + err = ENOMEM; + } + ENDTRY; if (err != 0) { - epan_cleanup(); - return 2; + /* We still dump out the results of taps, etc., as we might have + read some packets; however, we exit with an error status. */ + exit_status = 2; } } 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); do we have support for live captures? */ #ifdef HAVE_LIBPCAP - -#ifdef _WIN32 - if (!has_wpcap) { - char *detailed_err; - - cmdarg_err("WinPcap couldn't be found."); - detailed_err = cant_load_winpcap_err("TShark"); - cmdarg_err_cont("%s", detailed_err); - g_free(detailed_err); - return 2; - } -#endif - /* 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)) { @@ -1639,24 +1797,27 @@ main(int argc, char *argv[]) /* if requested, list the link layer types and exit */ if (list_link_layer_types) { - /* Get the list of link-layer types for the capture device. */ - if_capabilities_t *caps; - - caps = capture_get_if_capabilities(global_capture_opts.iface, - global_capture_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.", global_capture_opts.iface); - return 2; + 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); } - capture_opts_print_if_capabilities(caps, - global_capture_opts.monitor_mode); - free_if_capabilities(caps); return 0; } @@ -1682,9 +1843,18 @@ main(int argc, char *argv[]) /* For now, assume libpcap gives microsecond precision. */ timestamp_set_precision(TS_PREC_AUTO_USEC); - if (!capture()) { - return 2; /* an error occurred */ - } + /* + * XXX - this returns FALSE if an error occurred, but it also + * returns FALSE if the capture stops because a time limit + * was reached (and possibly other limits), so we can't assume + * it means an error. + * + * The capture code is a bit twisty, so it doesn't appear to + * be an easy fix. We just ignore the return value for now. + * Instead, pass on the exit status from the capture child. + */ + capture(); + exit_status = global_capture_opts.fork_child_status; if (print_packet_info) { if (!write_finale()) { @@ -1701,10 +1871,10 @@ main(int argc, char *argv[]) g_free(cf_name); -#if GLIB_CHECK_VERSION(2,10,0) - if (cfile.plist_start != NULL) - g_slice_free_chain(frame_data, cfile.plist_start, next); -#endif + if (cfile.frames != NULL) { + free_frame_data_sequence(cfile.frames); + cfile.frames = NULL; + } draw_tap_listeners(TRUE); funnel_dump_all_text_windows(); @@ -1713,7 +1883,7 @@ main(int argc, char *argv[]) output_fields_free(output_fields); output_fields = NULL; - return 0; + return exit_status; } /*#define USE_BROKEN_G_MAIN_LOOP*/ @@ -1731,13 +1901,13 @@ main(int argc, char *argv[]) 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 - GStaticMutex callback_running; + GMutex *callback_running; #endif } pipe_input_t; @@ -1753,55 +1923,54 @@ pipe_timer_cb(gpointer data) DWORD avail = 0; gboolean result, result1; DWORD childstatus; - pipe_input_t *pipe_input = data; + pipe_input_t *pipe_input_p = data; gint iterations = 0; - - g_static_mutex_lock (&pipe_input->callback_running); + g_mutex_lock (pipe_input_p->callback_running); /* try to read data from the pipe only 5 times, to avoid blocking */ while(iterations < 5) { - /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/ + /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: new iteration");*/ - /* Oddly enough although Named pipes don't work on win9x, - PeekNamedPipe does !!! */ - handle = (HANDLE) _get_osfhandle (pipe_input->source); - result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL); + /* Oddly enough although Named pipes don't work on win9x, + PeekNamedPipe does !!! */ + handle = (HANDLE) _get_osfhandle (pipe_input_p->source); + result = PeekNamedPipe(handle, NULL, 0, NULL, &avail, NULL); - /* Get the child process exit status */ - result1 = GetExitCodeProcess((HANDLE)*(pipe_input->child_process), - &childstatus); + /* Get the child process exit status */ + result1 = 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 - callback */ - if (!result || avail > 0 || childstatus != STILL_ACTIVE) { + /* If the Peek returned an error, or there are bytes to be read + or the childwatcher thread has terminated then call the normal + callback */ + if (!result || avail > 0 || childstatus != STILL_ACTIVE) { - /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/ + /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: data avail");*/ - /* And call the real handler */ - if (!pipe_input->input_cb(pipe_input->source, pipe_input->user_data)) { - g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations); - /* pipe closed, return false so that the timer is stopped */ - g_static_mutex_unlock (&pipe_input->callback_running); - return FALSE; - } - } - else { - /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/ - /* No data, stop now */ - break; - } + /* And call the real handler */ + if (!pipe_input_p->input_cb(pipe_input_p->source, pipe_input_p->user_data)) { + g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: input pipe closed, iterations: %u", iterations); + /* pipe closed, return false so that the timer is stopped */ + g_mutex_unlock (pipe_input_p->callback_running); + return FALSE; + } + } + else { + /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: no data avail");*/ + /* No data, stop now */ + break; + } - iterations++; + iterations++; } - /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, new timer", iterations);*/ + /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_timer_cb: finished with iterations: %u, new timer", iterations);*/ - g_static_mutex_unlock (&pipe_input->callback_running); + g_mutex_unlock (pipe_input_p->callback_running); - /* we didn't stopped the timer, so let it run */ - return TRUE; + /* we didn't stopped the timer, so let it run */ + return TRUE; } #endif @@ -1810,20 +1979,25 @@ void pipe_input_set_handler(gint source, gpointer user_data, int *child_process, pipe_input_cb_t input_cb) { - pipe_input.source = source; - pipe_input.child_process = child_process; - pipe_input.user_data = user_data; - pipe_input.input_cb = input_cb; + pipe_input.source = source; + pipe_input.child_process = child_process; + pipe_input.user_data = user_data; + pipe_input.input_cb = input_cb; #ifdef _WIN32 - g_static_mutex_init(&pipe_input.callback_running); - /* Tricky to use pipes in win9x, as no concept of wait. NT can - do this but that doesn't cover all win32 platforms. GTK can do - this but doesn't seem to work over processes. Attempt to do - something similar here, start a timer and check for data on every - timeout. */ - /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/ - pipe_input.pipe_input_id = g_timeout_add(200, pipe_timer_cb, &pipe_input); +#if GLIB_CHECK_VERSION(2,31,0) + pipe_input.callback_running = g_malloc(sizeof(GMutex)); + g_mutex_init(pipe_input.callback_running); +#else + pipe_input.callback_running = g_mutex_new(); +#endif + /* Tricky to use pipes in win9x, as no concept of wait. NT can + do this but that doesn't cover all win32 platforms. GTK can do + this but doesn't seem to work over processes. Attempt to do + something similar here, start a timer and check for data on every + timeout. */ + /*g_log(NULL, G_LOG_LEVEL_DEBUG, "pipe_input_set_handler: new");*/ + pipe_input.pipe_input_id = g_timeout_add(200, pipe_timer_cb, &pipe_input); #endif } @@ -1833,6 +2007,8 @@ static gboolean capture(void) { gboolean ret; + guint i; + GString *str = g_string_new(""); #ifdef USE_TSHARK_SELECT fd_set readfds; #endif @@ -1906,9 +2082,40 @@ capture(void) global_capture_opts.state = CAPTURE_PREPARING; - /* Let the user know what interface was chosen. */ - global_capture_opts.iface_descr = get_interface_descriptive_name(global_capture_opts.iface); - fprintf(stderr, "Capturing on %s\n", global_capture_opts.iface_descr); + /* Let the user know which interfaces were chosen. */ + 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); + 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); + } +#ifdef _WIN32 + if (global_capture_opts.ifaces->len < 2) { +#else + if (global_capture_opts.ifaces->len < 4) { +#endif + 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 (i > 0) { + if (global_capture_opts.ifaces->len > 2) { + g_string_append_printf(str, ","); + } + g_string_append_printf(str, " "); + if (i == global_capture_opts.ifaces->len - 1) { + g_string_append_printf(str, "and "); + } + } + g_string_append_printf(str, "%s", interface_opts.descr); + } + } else { + g_string_append_printf(str, "%u interfaces", global_capture_opts.ifaces->len); + } + fprintf(stdout, "Capturing on %s\n", str->str); + g_string_free(str, TRUE); ret = sync_pipe_start(&global_capture_opts); @@ -1940,27 +2147,40 @@ capture(void) loop_running = TRUE; - while (loop_running) + TRY { + while (loop_running) + { #ifdef USE_TSHARK_SELECT - ret = select(pipe_input.source+1, &readfds, NULL, NULL, NULL); + ret = select(pipe_input.source+1, &readfds, NULL, NULL, NULL); - if (ret == -1) - { - perror("select()"); - return TRUE; - } else if (ret == 1) { + if (ret == -1) + { + perror("select()"); + return TRUE; + } else if (ret == 1) { #endif - /* Call the real handler */ - if (!pipe_input.input_cb(pipe_input.source, pipe_input.user_data)) { - g_log(NULL, G_LOG_LEVEL_DEBUG, "input pipe closed"); - return FALSE; - } + /* Call the real handler */ + if (!pipe_input.input_cb(pipe_input.source, pipe_input.user_data)) { + g_log(NULL, G_LOG_LEVEL_DEBUG, "input pipe closed"); + return FALSE; + } #ifdef USE_TSHARK_SELECT - } + } #endif + } } - + CATCH(OutOfMemoryError) { + fprintf(stderr, + "Out Of Memory!\n" + "\n" + "Sorry, but TShark has to terminate now!\n" + "\n" + "Some infos / workarounds can be found at:\n" + "http://wiki.wireshark.org/KnownBugs/OutOfMemory\n"); + exit(1); + } + ENDTRY; return TRUE; } @@ -1975,39 +2195,42 @@ void main_window_update(void) void capture_input_error_message(capture_options *capture_opts _U_, char *error_msg, char *secondary_error_msg) { - cmdarg_err("%s", error_msg); - cmdarg_err_cont("%s", 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, char *error_message) +capture_input_cfilter_error_message(capture_options *capture_opts, guint i, char *error_message) { - dfilter_t *rfcode = NULL; - - - if (dfilter_compile(capture_opts->cfilter, &rfcode) && rfcode != NULL) { - cmdarg_err( - "Invalid capture filter: \"%s\"!\n" - "\n" - "That string looks like a valid display filter; however, it isn't a valid\n" - "capture filter (%s).\n" - "\n" - "Note that display filters and capture filters don't have the same syntax,\n" - "so you can't use most display filter expressions as capture filters.\n" - "\n" - "See the User's Guide for a description of the capture filter syntax.", - capture_opts->cfilter, error_message); - dfilter_free(rfcode); - } else { - cmdarg_err( - "Invalid capture filter: \"%s\"!\n" - "\n" - "That string isn't a valid capture filter (%s).\n" - "See the User's Guide for a description of the capture filter syntax.", - capture_opts->cfilter, error_message); - } + 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); + + if (dfilter_compile(interface_opts.cfilter, &rfcode) && rfcode != NULL) { + cmdarg_err( + "Invalid capture filter \"%s\" for interface %s!\n" + "\n" + "That string looks like a valid display filter; however, it isn't a valid\n" + "capture filter (%s).\n" + "\n" + "Note that display filters and capture filters don't have the same syntax,\n" + "so you can't use most display filter expressions as capture filters.\n" + "\n" + "See the User's Guide for a description of the capture filter syntax.", + interface_opts.cfilter, interface_opts.descr, error_message); + dfilter_free(rfcode); + } else { + cmdarg_err( + "Invalid capture filter \"%s\" for interface %s!\n" + "\n" + "That string isn't a valid capture filter (%s).\n" + "See the User's Guide for a description of the capture filter syntax.", + interface_opts.cfilter, interface_opts.descr, error_message); + } } @@ -2018,7 +2241,6 @@ capture_input_new_file(capture_options *capture_opts, gchar *new_file) gboolean is_tempfile; int err; - if(capture_opts->state == CAPTURE_PREPARING) { g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture started!"); } @@ -2097,6 +2319,7 @@ capture_input_new_packets(capture_options *capture_opts, int to_read) 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) { /* read from file failed, tell the capture child to stop */ @@ -2109,7 +2332,7 @@ capture_input_new_packets(capture_options *capture_opts, int to_read) filtering_tap_listeners, tap_flags); } if (ret != FALSE) { - /* packet sucessfully read and gone through the "Read Filter" */ + /* packet successfully read and gone through the "Read Filter" */ packet_count++; } } @@ -2150,7 +2373,7 @@ report_counts(void) if (!print_packet_counts) { /* 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(stdout, "%u packet%s captured\n", packet_count, plurality(packet_count, "", "s")); } #ifdef SIGINFO @@ -2207,6 +2430,9 @@ capture_input_closed(capture_options *capture_opts, gchar *msg) 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); + } } #ifdef USE_BROKEN_G_MAIN_LOOP /*g_main_loop_quit(loop);*/ @@ -2267,31 +2493,32 @@ capture_cleanup(int signum _U_) #endif /* _WIN32 */ #endif /* HAVE_LIBPCAP */ -#if GLIB_CHECK_VERSION(2,10,0) 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) { - frame_data *fdata = g_slice_new(frame_data); + frame_data fdlocal; + guint32 framenum; epan_dissect_t edt; gboolean passed; - /* Count this packet. */ - cf->count++; + /* The frame number of this packet is one more than the count of + frames in this packet. */ + framenum = cf->count + 1; /* 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 that all packets can be marked as 'passed'. */ passed = TRUE; - frame_data_init(fdata, cf->count, whdr, offset, cum_bytes); + 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 do a dissection and do so. */ if (do_dissection) { - if (g_resolv_flags) + if (gbl_resolv_flags) /* Grab any resolved addresses */ host_name_lookup_process(NULL); @@ -2306,10 +2533,10 @@ process_packet_first_pass(capture_file *cf, if (cf->rfcode) epan_dissect_prime_dfilter(&edt, cf->rfcode); - frame_data_set_before_dissect(fdata, &cf->elapsed_time, + frame_data_set_before_dissect(&fdlocal, &cf->elapsed_time, &first_ts, &prev_dis_ts, &prev_cap_ts); - epan_dissect_run(&edt, pseudo_header, pd, fdata, NULL); + epan_dissect_run(&edt, pseudo_header, pd, &fdlocal, NULL); /* Run the read filter if we have one. */ if (cf->rfcode) @@ -2317,11 +2544,10 @@ process_packet_first_pass(capture_file *cf, } if (passed) { - frame_data_set_after_dissect(fdata, &cum_bytes, &prev_dis_ts); - cap_file_add_fdata(cf, fdata); + frame_data_set_after_dissect(&fdlocal, &cum_bytes, &prev_dis_ts); + frame_data_sequence_add(cf->frames, &fdlocal); + cf->count++; } - else - g_slice_free(frame_data, fdata); if (do_dissection) epan_dissect_cleanup(&edt); @@ -2348,7 +2574,7 @@ process_packet_second_pass(capture_file *cf, frame_data *fdata, run a read filter, or we're going to process taps, set up to do a dissection and do so. */ if (do_dissection) { - if (g_resolv_flags) + if (gbl_resolv_flags) /* Grab any resolved addresses */ host_name_lookup_process(NULL); @@ -2440,23 +2666,27 @@ process_packet_second_pass(capture_file *cf, frame_data *fdata, } return passed; } -#endif static int load_cap_file(capture_file *cf, char *save_file, int out_file_type, - int max_packet_count, gint64 max_byte_count) + gboolean out_file_name_res, int max_packet_count, gint64 max_byte_count) { gint linktype; int snapshot_length; wtap_dumper *pdh; + guint32 framenum; int err; - gchar *err_info; + gchar *err_info = NULL; gint64 data_offset; char *save_file_string = NULL; gboolean filtering_tap_listeners; guint tap_flags; +#ifdef PCAP_NG_DEFAULT + linktype = WTAP_ENCAP_PER_PACKET; +#else linktype = wtap_file_encap(cf->wth); +#endif if (save_file != NULL) { /* Get a string that describes what we're writing to */ save_file_string = output_file_description(save_file); @@ -2480,8 +2710,8 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, case WTAP_ERR_UNSUPPORTED_ENCAP: case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED: - cmdarg_err("The capture file being read can't be written in " - "that format."); + cmdarg_err("The capture file being read can't be written as a " + "\"%s\" file.", wtap_file_type_short_string(out_file_type)); break; case WTAP_ERR_CANT_OPEN: @@ -2512,6 +2742,13 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, pdh = NULL; } + if (pdh && out_file_name_res) { + if (!wtap_dump_set_addrinfo_list(pdh, get_addrinfo_list())) { + cmdarg_err("The file format \"%s\" doesn't support name resolution information.", + wtap_file_type_short_string(out_file_type)); + } + } + /* Do we have any tap listeners with filters? */ filtering_tap_listeners = have_filtering_tap_listeners(); @@ -2519,10 +2756,12 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, tap_flags = union_of_tap_listener_flags(); if (perform_two_pass_analysis) { -#if GLIB_CHECK_VERSION(2,10,0) frame_data *fdata; int old_max_packet_count = max_packet_count; + /* Allocate a frame_data_sequence for all the frames. */ + cf->frames = new_frame_data_sequence(); + 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))) { @@ -2547,7 +2786,8 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, max_packet_count = old_max_packet_count; - for (fdata = cf->plist_start; err == 0 && fdata != NULL; fdata = fdata->next) { + 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, @@ -2561,7 +2801,26 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth), &err)) { /* Error writing to a capture file */ - show_capture_file_io_error(save_file, err, FALSE); + switch (err) { + + case WTAP_ERR_UNSUPPORTED_ENCAP: + /* + * This is a problem with the particular frame we're writing; + * note that, and give the frame number. + * + * XXX - framenum is not necessarily the frame number in + * the input file if there was a read filter. + */ + fprintf(stderr, + "Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.\n", + framenum, cf->filename, + wtap_file_type_short_string(out_file_type)); + break; + + default: + show_capture_file_io_error(save_file, err, FALSE); + break; + } wtap_dump_close(pdh, &err); exit(2); } @@ -2578,10 +2837,12 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, } } } -#endif } else { + framenum = 0; while (wtap_read(cf->wth, &err, &err_info, &data_offset)) { + framenum++; + if (process_packet(cf, data_offset, wtap_phdr(cf->wth), wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth), filtering_tap_listeners, tap_flags)) { @@ -2593,7 +2854,23 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth), &err)) { /* Error writing to a capture file */ - show_capture_file_io_error(save_file, err, FALSE); + switch (err) { + + case WTAP_ERR_UNSUPPORTED_ENCAP: + /* + * This is a problem with the particular frame we're writing; + * note that, and give the frame number. + */ + fprintf(stderr, + "Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.\n", + framenum, cf->filename, + wtap_file_type_short_string(out_file_type)); + break; + + default: + show_capture_file_io_error(save_file, err, FALSE); + break; + } wtap_dump_close(pdh, &err); exit(2); } @@ -2612,33 +2889,61 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type, } if (err != 0) { - /* Print a message noting that the read failed somewhere along the line. */ + /* + * Print a message noting that the read failed somewhere along the line. + * + * If we're printing packet data, and the standard output and error are + * going to the same place, flush the standard output, so everything + * buffered up is written, and then print a newline to the standard error + * before printing the error message, to separate it from the packet + * data. (Alas, that only works on UN*X; st_dev is meaningless, and + * the _fstat() documentation at Microsoft doesn't indicate whether + * st_ino is even supported.) + */ +#ifndef _WIN32 + if (print_packet_info) { + struct stat stat_stdout, stat_stderr; + + if (fstat(1, &stat_stdout) == 0 && fstat(2, &stat_stderr) == 0) { + if (stat_stdout.st_dev == stat_stderr.st_dev && + stat_stdout.st_ino == stat_stderr.st_ino) { + fflush(stdout); + fprintf(stderr, "\n"); + } + } + } +#endif switch (err) { case WTAP_ERR_UNSUPPORTED_ENCAP: - cmdarg_err("\"%s\" has a packet with a network type that TShark doesn't support.\n(%s)", + cmdarg_err("The file \"%s\" has a packet with a network type that TShark doesn't support.\n(%s)", cf->filename, err_info); g_free(err_info); break; case WTAP_ERR_CANT_READ: - cmdarg_err("An attempt to read from \"%s\" failed for some unknown reason.", + cmdarg_err("An attempt to read from the file \"%s\" failed for some unknown reason.", cf->filename); break; case WTAP_ERR_SHORT_READ: - cmdarg_err("\"%s\" appears to have been cut short in the middle of a packet.", + cmdarg_err("The file \"%s\" appears to have been cut short in the middle of a packet.", cf->filename); break; - case WTAP_ERR_BAD_RECORD: - cmdarg_err("\"%s\" appears to be damaged or corrupt.\n(%s)", + case WTAP_ERR_BAD_FILE: + cmdarg_err("The file \"%s\" appears to be damaged or corrupt.\n(%s)", cf->filename, err_info); g_free(err_info); break; + case WTAP_ERR_DECOMPRESS: + cmdarg_err("The compressed file \"%s\" appears to be damaged or corrupt.\n" + "(%s)", cf->filename, err_info); + break; + default: - cmdarg_err("An error occurred while reading \"%s\": %s.", + cmdarg_err("An error occurred while reading the file \"%s\": %s.", cf->filename, wtap_strerror(err)); break; } @@ -2696,7 +3001,7 @@ process_packet(capture_file *cf, gint64 offset, const struct wtap_pkthdr *whdr, 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 && g_resolv_flags) + if (print_packet_info && gbl_resolv_flags) /* Grab any resolved addresses */ host_name_lookup_process(NULL); @@ -2805,7 +3110,7 @@ write_preamble(capture_file *cf) case WRITE_XML: if (verbose) - write_pdml_preamble(stdout); + write_pdml_preamble(stdout, cf ? cf->filename : NULL); else write_psml_preamble(stdout); return !ferror(stdout); @@ -2854,6 +3159,9 @@ print_columns(capture_file *cf) buf_offset = 0; *line_bufp = '\0'; for (i = 0; i < cf->cinfo.num_cols; i++) { + /* Skip columns not marked as visible. */ + if (!get_column_visible(i)) + continue; switch (cf->cinfo.col_fmt[i]) { case COL_NUMBER: #ifdef HAVE_LIBPCAP @@ -2868,25 +3176,27 @@ print_columns(capture_file *cf) * the same time, sort of like an "Update list of packets * in real time" capture in Wireshark.) */ - if (global_capture_opts.iface != NULL) + if (global_capture_opts.ifaces->len > 0) continue; #endif column_len = strlen(cf->cinfo.col_data[i]); if (column_len < 3) column_len = 3; line_bufp = get_line_buf(buf_offset + column_len); - sprintf(line_bufp + buf_offset, "%3s", cf->cinfo.col_data[i]); + g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%3s", cf->cinfo.col_data[i]); break; case COL_CLS_TIME: case COL_REL_TIME: case COL_ABS_TIME: - case COL_ABS_DATE_TIME: /* XXX - wider */ + case COL_ABS_DATE_TIME: + case COL_UTC_TIME: + case COL_UTC_DATE_TIME: /* XXX - wider */ column_len = strlen(cf->cinfo.col_data[i]); if (column_len < 10) column_len = 10; line_bufp = get_line_buf(buf_offset + column_len); - sprintf(line_bufp + buf_offset, "%10s", cf->cinfo.col_data[i]); + g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%10s", cf->cinfo.col_data[i]); break; case COL_DEF_SRC: @@ -2902,7 +3212,7 @@ print_columns(capture_file *cf) if (column_len < 12) column_len = 12; line_bufp = get_line_buf(buf_offset + column_len); - sprintf(line_bufp + buf_offset, "%12s", cf->cinfo.col_data[i]); + g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%12s", cf->cinfo.col_data[i]); break; case COL_DEF_DST: @@ -2918,13 +3228,13 @@ print_columns(capture_file *cf) if (column_len < 12) column_len = 12; line_bufp = get_line_buf(buf_offset + column_len); - sprintf(line_bufp + buf_offset, "%-12s", cf->cinfo.col_data[i]); + g_snprintf(line_bufp + buf_offset, (int)column_len + 1, "%-12s", cf->cinfo.col_data[i]); break; default: column_len = strlen(cf->cinfo.col_data[i]); line_bufp = get_line_buf(buf_offset + column_len); - strcat(line_bufp + buf_offset, cf->cinfo.col_data[i]); + g_strlcat(line_bufp + buf_offset, cf->cinfo.col_data[i], column_len + 1); break; } buf_offset += column_len; @@ -2935,9 +3245,9 @@ print_columns(capture_file *cf) * * If we printed a network source and are printing a * network destination of the same type next, separate - * them with "->"; if we printed a network destination + * them with " -> "; if we printed a network destination * and are printing a network source of the same type - * next, separate them with "<-"; otherwise separate them + * next, separate them with " <- "; otherwise separate them * with a space. * * We add enough space to the buffer for " <- " or " -> ", @@ -2954,12 +3264,12 @@ print_columns(capture_file *cf) case COL_DEF_DST: case COL_RES_DST: case COL_UNRES_DST: - strcat(line_bufp + buf_offset, " -> "); + g_strlcat(line_bufp + buf_offset, " -> ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -2973,12 +3283,12 @@ print_columns(capture_file *cf) case COL_DEF_DL_DST: case COL_RES_DL_DST: case COL_UNRES_DL_DST: - strcat(line_bufp + buf_offset, " -> "); + g_strlcat(line_bufp + buf_offset, " -> ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -2992,12 +3302,12 @@ print_columns(capture_file *cf) case COL_DEF_NET_DST: case COL_RES_NET_DST: case COL_UNRES_NET_DST: - strcat(line_bufp + buf_offset, " -> "); + g_strlcat(line_bufp + buf_offset, " -> ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -3011,12 +3321,12 @@ print_columns(capture_file *cf) case COL_DEF_SRC: case COL_RES_SRC: case COL_UNRES_SRC: - strcat(line_bufp + buf_offset, " <- "); + g_strlcat(line_bufp + buf_offset, " <- ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -3030,12 +3340,12 @@ print_columns(capture_file *cf) case COL_DEF_DL_SRC: case COL_RES_DL_SRC: case COL_UNRES_DL_SRC: - strcat(line_bufp + buf_offset, " <- "); + g_strlcat(line_bufp + buf_offset, " <- ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -3049,19 +3359,19 @@ print_columns(capture_file *cf) case COL_DEF_NET_SRC: case COL_RES_NET_SRC: case COL_UNRES_NET_SRC: - strcat(line_bufp + buf_offset, " <- "); + g_strlcat(line_bufp + buf_offset, " <- ", 5); buf_offset += 4; break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } break; default: - strcat(line_bufp + buf_offset, " "); + g_strlcat(line_bufp + buf_offset, " ", 5); buf_offset += 1; break; } @@ -3096,7 +3406,7 @@ print_packet(capture_file *cf, epan_dissect_t *edt) /* "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, "")) + if (!print_line(print_stream, 0, separator)) return FALSE; } break; @@ -3214,6 +3524,9 @@ cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err) 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); + return CF_OK; fail: @@ -3288,7 +3601,7 @@ show_print_file_io_error(int err) default: cmdarg_err("An error occurred while printing packets: %s.", - strerror(err)); + g_strerror(err)); break; } } @@ -3325,8 +3638,8 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing, case WTAP_ERR_CANT_WRITE_TO_PIPE: /* Seen only when opening a capture file for writing. */ g_snprintf(errmsg_errno, sizeof(errmsg_errno), - "The file \"%%s\" is a pipe, and %s capture files can't be " - "written to a pipe.", wtap_file_type_string(file_type)); + "The file \"%%s\" is a pipe, and \"%s\" capture files can't be " + "written to a pipe.", wtap_file_type_short_string(file_type)); errmsg = errmsg_errno; break; @@ -3336,25 +3649,30 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing, break; case WTAP_ERR_UNSUPPORTED_ENCAP: - if (for_writing) - errmsg = "TShark can't save this capture in that format."; - else { + if (for_writing) { + g_snprintf(errmsg_errno, sizeof(errmsg_errno), + "TShark can't save this capture as a \"%s\" file.", + wtap_file_type_short_string(file_type)); + } else { g_snprintf(errmsg_errno, sizeof(errmsg_errno), "The file \"%%s\" is a capture for a network type that TShark doesn't support.\n" "(%s)", err_info); g_free(err_info); - errmsg = errmsg_errno; } + errmsg = errmsg_errno; break; case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED: - if (for_writing) - errmsg = "TShark can't save this capture in that format."; - else + if (for_writing) { + g_snprintf(errmsg_errno, sizeof(errmsg_errno), + "TShark can't save this capture as a \"%s\" file.", + wtap_file_type_short_string(file_type)); + errmsg = errmsg_errno; + } else errmsg = "The file \"%s\" is a capture for a network type that TShark doesn't support."; break; - case WTAP_ERR_BAD_RECORD: + case WTAP_ERR_BAD_FILE: /* Seen only when opening a capture file for reading. */ g_snprintf(errmsg_errno, sizeof(errmsg_errno), "The file \"%%s\" appears to be damaged or corrupt.\n" @@ -3379,6 +3697,15 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing, errmsg = "A full header couldn't be written to the file \"%s\"."; break; + case WTAP_ERR_DECOMPRESS: + /* Seen only when opening a capture file for reading. */ + g_snprintf(errmsg_errno, sizeof(errmsg_errno), + "The compressed file \"%%s\" appears to be damaged or corrupt.\n" + "(%s)", err_info); + g_free(err_info); + errmsg = errmsg_errno; + break; + default: g_snprintf(errmsg_errno, sizeof(errmsg_errno), "The file \"%%s\" could not be %s: %s.", @@ -3422,7 +3749,7 @@ static void read_failure_message(const char *filename, int err) { cmdarg_err("An error occurred while reading from the file \"%s\": %s.", - filename, strerror(err)); + filename, g_strerror(err)); } /* @@ -3432,7 +3759,7 @@ static void write_failure_message(const char *filename, int err) { cmdarg_err("An error occurred while writing to the file \"%s\": %s.", - filename, strerror(err)); + filename, g_strerror(err)); } /*