From d64ad1de91cb8303ce5b76faf0c5bdc0bf09a930 Mon Sep 17 00:00:00 2001 From: Hadriel Kaplan Date: Sun, 16 Aug 2015 12:37:11 -0400 Subject: capinfos: add more info about file and interfaces Add more information about the capture file, and about the interface descriptions in it. Also remove long-unused g_options code. Change-Id: I93cbd70fc7b09ec1b8b2fd6c85bb885c7f749543 Reviewed-on: https://code.wireshark.org/review/10073 Petri-Dish: Hadriel Kaplan Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman --- capinfos.c | 395 +++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 212 insertions(+), 183 deletions(-) (limited to 'capinfos.c') diff --git a/capinfos.c b/capinfos.c index dd20593c5e..457919a448 100644 --- a/capinfos.c +++ b/capinfos.c @@ -145,6 +145,8 @@ static gboolean cap_snaplen = TRUE; /* Packet size limit (snaplen)*/ static gboolean cap_packet_count = TRUE; /* Report packet count */ static gboolean cap_file_size = TRUE; /* Report file size */ static gboolean cap_comment = TRUE; /* Display the capture comment */ +static gboolean cap_file_more_info = TRUE; /* Report more file info */ +static gboolean cap_file_idb = TRUE; /* Report Interface info */ static gboolean cap_data_size = TRUE; /* Report packet byte size */ static gboolean cap_duration = TRUE; /* Report capture duration */ @@ -160,106 +162,7 @@ static gboolean cap_order = TRUE; /* Report if packets are in chronolo #ifdef HAVE_LIBGCRYPT static gboolean cap_file_hashes = TRUE; /* Calculate file hashes */ -#endif - -#ifdef USE_GOPTION -static gboolean cap_help = FALSE; -static gboolean table_report = FALSE; - -static GOptionEntry general_entries[] = -{ - /* General */ - { "type", 't', 0, G_OPTION_ARG_NONE, &cap_file_type, - "display the capture file type", NULL }, - { "Encapsulation", 'E', 0, G_OPTION_ARG_NONE, &cap_file_encap, - "display the capture file encapsulation", NULL }, -#ifdef HAVE_LIBGCRYPT - { "Hash", 'H', 0, G_OPTION_ARG_NONE, &cap_file_hashes, - "display the SHA1, RMD160, and MD5 hashes of the file", NULL }, -#endif /* HAVE_LIBGCRYPT */ - { "capture-comment", 'k', 0, G_OPTION_ARG_NONE, &cap_comment, - "display the capture comment ", NULL }, - { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL } -}; -static GOptionEntry size_entries[] = -{ - /* Size */ - { "packets", 'c', 0, G_OPTION_ARG_NONE, &cap_packet_count, - "display the number of packets", NULL }, - { "size", 's', 0, G_OPTION_ARG_NONE, &cap_file_size, - "display the size of the file (in bytes)", NULL }, - { "tot-len-of-pkts", 'd', 0, G_OPTION_ARG_NONE, &cap_data_size, - "display the total length of all packets (in bytes)", NULL }, - { "snap", 'l', 0, G_OPTION_ARG_NONE, &cap_snaplen, - "display the packet size limit (snapshot length)", NULL }, - { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL } -}; -static GOptionEntry time_entries[] = -{ - /* Time */ - { "duration", 'u', 0, G_OPTION_ARG_NONE, &cap_duration, - "display the capture duration (in seconds)", NULL }, - { "start", 'a', 0, G_OPTION_ARG_NONE, &cap_start_time, - "display the capture start time", NULL }, - { "end", 'e', 0, G_OPTION_ARG_NONE, &cap_end_time, - "display the capture end time", NULL }, - { "cron", 'o', 0, G_OPTION_ARG_NONE, &cap_order, - "display the capture file chronological status (True/False)", NULL }, - { "start-end-time-sec", 'S', 0, G_OPTION_ARG_NONE, &time_as_secs, - "display start and end times as seconds", NULL }, - { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL } -}; - -static GOptionEntry stats_entries[] = -{ - /* Statistics */ - { "bytes", 'y', 0, G_OPTION_ARG_NONE, &cap_data_rate_byte, - "display average data rate (in bytes/s)", NULL }, - { "bits", 'i', 0, G_OPTION_ARG_NONE, &cap_data_rate_bit, - "display average data rate (in bits/s)", NULL }, - { "packet-bytes", 'z', 0, G_OPTION_ARG_NONE, &cap_packet_size, - "display average packet size (in bytes)", NULL }, - { "packets", 'x', 0, G_OPTION_ARG_NONE, &cap_packet_rate, - "display average packet rate (in packets/s)", NULL }, - { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL } -}; - -static GOptionEntry output_format_entries[] = -{ - /* Output format */ - { "long", 'L', 0, G_OPTION_ARG_NONE, &long_report, - "generate long report (default)", NULL }, - { "Table", 'T', 0, G_OPTION_ARG_NONE, &table_report, - "generate table report", NULL }, - { "machine-readable", 'M', 0, G_OPTION_ARG_NONE, &machine_readable, - "display machine-readable (unabbreviated) values in long reports", NULL }, - { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL } -}; - -static GOptionEntry table_report_entries[] = -{ - /* Table report */ - { "header-rec", 'R', 0, G_OPTION_ARG_NONE, &table_report_header, - "generate header record (default)", NULL }, - { "no-table", 'r', 0, G_OPTION_ARG_NONE, &table_report_header, - "do not generate header record", NULL }, - { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL } -}; - -static GOptionEntry misc_entries[] = -{ - { "helpcompat", 'h', 0, G_OPTION_ARG_NONE, &cap_help, - "display help", NULL }, - { NULL,'\0',0,G_OPTION_ARG_NONE,NULL,NULL,NULL } -}; - -GOptionContext *ctx; -GOptionGroup *general_grp, *size_grp, *time_grp, *stats_grp, *output_grp, *table_report_grp; -GError *parse_err = NULL; - -#endif /* USE_GOPTION */ -#ifdef HAVE_LIBGCRYPT #define HASH_SIZE_SHA1 20 #define HASH_SIZE_RMD160 20 #define HASH_SIZE_MD5 16 @@ -298,8 +201,12 @@ typedef struct _capture_info { guint16 file_type; gboolean iscompressed; int file_encap; + int file_tsprec; gint64 filesize; gchar *comment; + gchar *hardware; + gchar *os; + gchar *usr_appl; guint64 packet_bytes; gboolean times_known; @@ -324,6 +231,11 @@ typedef struct _capture_info { order_t order; int *encap_counts; /* array of per_packet encap counts; array has one entry per wtap_encap type */ + + guint num_interfaces; /* number of IDBs, and thus size of interface_ids array */ + guint32 *interface_ids; /* array of per_packet interface_id counts; one entry per file IDB */ + guint32 pkt_interface_id_unknown; /* counts if packet interface_id didn't match a known one */ + GArray *idb_info_strings; /* array of IDB info strings */ } capture_info; @@ -338,6 +250,8 @@ enable_all_infos(void) cap_packet_count = TRUE; cap_file_size = TRUE; cap_comment = TRUE; + cap_file_more_info = TRUE; + cap_file_idb = TRUE; cap_data_size = TRUE; cap_duration = TRUE; @@ -366,6 +280,8 @@ disable_all_infos(void) cap_packet_count = FALSE; cap_file_size = FALSE; cap_comment = FALSE; + cap_file_more_info = FALSE; + cap_file_idb = FALSE; cap_data_size = FALSE; cap_duration = FALSE; @@ -650,14 +566,24 @@ print_stats(const gchar *filename, capture_info *cf_info) if (cap_file_type) printf ("File type: %s%s\n", file_type_string, cf_info->iscompressed ? " (gzip compressed)" : ""); - if (cap_file_encap) printf ("File encapsulation: %s\n", file_encap_string); - if (cap_file_encap && (cf_info->file_encap == WTAP_ENCAP_PER_PACKET)) { - int i; - for (i=0; iencap_counts[i] > 0) - printf(" %s\n", wtap_encap_string(i)); + + if (cap_file_encap) { + printf ("File encapsulation: %s\n", file_encap_string); + if (cf_info->file_encap == WTAP_ENCAP_PER_PACKET) { + int i; + printf ("Encapsulation in use by packets (# of pkts):\n"); + for (i=0; iencap_counts[i] > 0) + printf(" %s (%d)\n", + wtap_encap_string(i), cf_info->encap_counts[i]); + } } } + if (cap_file_more_info) { + printf ("File timestamp precision: %s (%d)\n", + wtap_tsprec_string(cf_info->file_tsprec), cf_info->file_tsprec); + } + if (cap_snaplen && cf_info->snap_set) printf ("Packet size limit: file hdr: %u bytes\n", cf_info->snaplen); else if (cap_snaplen && !cf_info->snap_set) @@ -750,6 +676,26 @@ print_stats(const gchar *filename, capture_info *cf_info) if (cap_order) printf ("Strict time order: %s\n", order_string(cf_info->order)); if (cap_comment && cf_info->comment) printf ("Capture comment: %s\n", cf_info->comment); + if (cap_file_more_info) { + if (cf_info->hardware) + printf ("Capture hardware: %s\n", cf_info->hardware); + if (cf_info->os) + printf ("Capture oper-sys: %s\n", cf_info->os); + if (cf_info->usr_appl) + printf ("Capture application: %s\n", cf_info->usr_appl); + } + + if (cap_file_idb) { + guint i; + g_assert(cf_info->num_interfaces == cf_info->idb_info_strings->len); + printf ("Number of interfaces in file: %u\n", cf_info->num_interfaces); + for (i = 0; i < cf_info->idb_info_strings->len; i++) { + gchar *s = g_array_index(cf_info->idb_info_strings, gchar*, i); + printf ("Interface #%u info:\n", i); + printf ("%s", s); + printf (" Number of packets = %u\n", cf_info->interface_ids[i]); + } + } } static void @@ -782,6 +728,7 @@ print_stats_table_header(void) if (cap_file_type) print_stats_table_header_label("File type"); if (cap_file_encap) print_stats_table_header_label("File encapsulation"); + if (cap_file_more_info) print_stats_table_header_label("File time precision"); if (cap_snaplen) print_stats_table_header_label("Packet size limit"); if (cap_snaplen) print_stats_table_header_label("Packet size limit min (inferred)"); if (cap_snaplen) print_stats_table_header_label("Packet size limit max (inferred)"); @@ -804,6 +751,11 @@ print_stats_table_header(void) #endif /* HAVE_LIBGCRYPT */ if (cap_order) print_stats_table_header_label("Strict time order"); if (cap_comment) print_stats_table_header_label("Capture comment"); + if (cap_file_more_info) { + print_stats_table_header_label("Capture hardware"); + print_stats_table_header_label("Capture oper-sys"); + print_stats_table_header_label("Capture application"); + } printf("\n"); } @@ -842,6 +794,13 @@ print_stats_table(const gchar *filename, capture_info *cf_info) putquote(); } + if (cap_file_more_info) { + putsep(); + putquote(); + printf("%s", wtap_tsprec_string(cf_info->file_tsprec)); + putquote(); + } + if (cap_snaplen) { putsep(); putquote(); @@ -977,6 +936,7 @@ print_stats_table(const gchar *filename, capture_info *cf_info) putquote(); } + /* this is silly to put into a table format, but oh well */ if (cap_comment) { putsep(); putquote(); @@ -984,10 +944,80 @@ print_stats_table(const gchar *filename, capture_info *cf_info) putquote(); } + if (cap_file_more_info) { + putsep(); + putquote(); + printf("%s", cf_info->hardware); + putquote(); + + putsep(); + putquote(); + printf("%s", cf_info->os); + putquote(); + + putsep(); + putquote(); + printf("%s", cf_info->usr_appl); + putquote(); + } printf("\n"); } +static void +cleanup_capture_info(capture_info *cf_info) +{ + guint i; + g_assert(cf_info != NULL); + + g_free(cf_info->comment); + cf_info->comment = NULL; + + g_free(cf_info->hardware); + cf_info->hardware = NULL; + + g_free(cf_info->os); + cf_info->os = NULL; + + g_free(cf_info->usr_appl); + cf_info->usr_appl = NULL; + + g_free(cf_info->encap_counts); + cf_info->encap_counts = NULL; + + g_free(cf_info->interface_ids); + cf_info->interface_ids = NULL; + + if (cf_info->idb_info_strings) { + for (i = 0; i < cf_info->idb_info_strings->len; i++) { + gchar *s = g_array_index(cf_info->idb_info_strings, gchar*, i); + g_free(s); + } + g_array_free(cf_info->idb_info_strings, TRUE); + } + cf_info->idb_info_strings = NULL; +} + +/* multi-line comments would conflict with the formatting that capinfos uses + we replace linefeeds with spaces */ +static void +string_replace_newlines(gchar *str) +{ + gchar *p; + + if (str) { + p = str; + while (*p != '\0') { + if (*p == '\n') + *p = ' '; + if (*p == '\r') + *p = ' '; + p++; + } + } +} + + static int process_cap_file(wtap *wth, const char *filename) { @@ -1012,9 +1042,12 @@ process_cap_file(wtap *wth, const char *filename) nstime_t prev_time; gboolean know_order = FALSE; order_t order = IN_ORDER; - const gchar *shb_comment; - gchar *p; + const wtapng_section_t *shb_inf; + guint i; + wtapng_iface_descriptions_t *idb_info; + g_assert(wth != NULL); + g_assert(filename != NULL); nstime_set_zero(&start_time); start_time_tsprec = WTAP_TSPREC_UNKNOWN; @@ -1023,8 +1056,35 @@ process_cap_file(wtap *wth, const char *filename) nstime_set_zero(&cur_time); nstime_set_zero(&prev_time); + cf_info.comment = NULL; + cf_info.hardware = NULL; + cf_info.os = NULL; + cf_info.usr_appl = NULL; + cf_info.encap_counts = g_new0(int,WTAP_NUM_ENCAP_TYPES); + idb_info = wtap_file_get_idb_info(wth); + + /* every file should have at least one IDB, or else it's an internal programming error */ + g_assert(idb_info->interface_data != NULL); + g_assert(idb_info->interface_data->len > 0); + + cf_info.num_interfaces = idb_info->interface_data->len; + cf_info.interface_ids = g_new0(guint32, cf_info.num_interfaces); + cf_info.pkt_interface_id_unknown = 0; + + cf_info.idb_info_strings = g_array_sized_new(FALSE, FALSE, sizeof(gchar*), cf_info.num_interfaces); + + /* get IDB info strings */ + for (i = 0; i < cf_info.num_interfaces; i++) { + const wtapng_if_descr_t *if_descr = &g_array_index(idb_info->interface_data, wtapng_if_descr_t, i); + gchar *s = wtap_get_debug_if_descr(if_descr, 21, "\n"); + g_array_append_val(cf_info.idb_info_strings, s); + } + + g_free(idb_info); + idb_info = NULL; + /* Tally up data that we need to parse through the file to find */ while (wtap_read(wth, &err, &err_info, &data_offset)) { phdr = wtap_phdr(wth); @@ -1079,6 +1139,21 @@ process_cap_file(wtap *wth, const char *filename) phdr->pkt_encap, packet, filename); } } + + /* Packet interface_id info */ + if (phdr->presence_flags & WTAP_HAS_INTERFACE_ID) { + /* cf_info.num_interfaces is size, not index, so it's one more than max index */ + if (phdr->interface_id < cf_info.num_interfaces) { + cf_info.interface_ids[phdr->interface_id] += 1; + } + else { + cf_info.pkt_interface_id_unknown += 1; + } + } + else { + /* it's for interface_id 0 */ + cf_info.interface_ids[0] += 1; + } } } /* while */ @@ -1098,7 +1173,7 @@ process_cap_file(wtap *wth, const char *filename) g_free(err_info); } - g_free(cf_info.encap_counts); + cleanup_capture_info(&cf_info); return 1; } } @@ -1109,7 +1184,7 @@ process_cap_file(wtap *wth, const char *filename) fprintf(stderr, "capinfos: Can't get size of \"%s\": %s.\n", filename, g_strerror(err)); - g_free(cf_info.encap_counts); + cleanup_capture_info(&cf_info); return 1; } @@ -1122,6 +1197,8 @@ process_cap_file(wtap *wth, const char *filename) /* File Encapsulation */ cf_info.file_encap = wtap_file_encap(wth); + cf_info.file_tsprec = wtap_file_tsprec(wth); + /* Packet size limit (snaplen) */ cf_info.snaplen = wtap_snapshot_length(wth); if (cf_info.snaplen > 0) @@ -1166,31 +1243,27 @@ process_cap_file(wtap *wth, const char *filename) cf_info.packet_size = (double)bytes / packet; /* Avg packet size */ } - cf_info.comment = NULL; - shb_comment = wtap_file_get_shb_comment(wth); - if (shb_comment) { + shb_inf = wtap_file_get_shb(wth); + if (shb_inf) { /* opt_comment is always 0-terminated by pcapng_read_section_header_block */ - cf_info.comment = g_strdup(shb_comment); - /* multi-line comments would conflict with the formatting that capinfos uses - we replace carriage-returns/linefeeds with spaces */ - p = cf_info.comment; - while (*p != '\0') { - if (*p == '\n') - *p = ' '; - if (*p == '\r') - *p = ' '; - p++; - } + cf_info.comment = g_strdup(shb_inf->opt_comment); + cf_info.hardware = g_strdup(shb_inf->shb_hardware); + cf_info.os = g_strdup(shb_inf->shb_os); + cf_info.usr_appl = g_strdup(shb_inf->shb_user_appl); } + string_replace_newlines(cf_info.comment); + string_replace_newlines(cf_info.hardware); + string_replace_newlines(cf_info.os); + string_replace_newlines(cf_info.usr_appl); + if (long_report) { print_stats(filename, &cf_info); } else { print_stats_table(filename, &cf_info); } - g_free(cf_info.encap_counts); - g_free(cf_info.comment); + cleanup_capture_info(&cf_info); return status; } @@ -1204,6 +1277,8 @@ print_usage(FILE *output) fprintf(output, "General infos:\n"); fprintf(output, " -t display the capture file type\n"); fprintf(output, " -E display the capture file encapsulation\n"); + fprintf(output, " -I display the capture file interface information\n"); + fprintf(output, " -F display additional capture file information\n"); #ifdef HAVE_LIBGCRYPT fprintf(output, " -H display the SHA1, RMD160, and MD5 hashes of the file\n"); #endif @@ -1387,64 +1462,8 @@ DIAG_ON(cast-qual) #endif /* Process the options */ -#ifdef USE_GOPTION - ctx = g_option_context_new(" ... - print information about capture file(s)"); - general_grp = g_option_group_new("gen", "General infos:", - "Show general options", NULL, NULL); - size_grp = g_option_group_new("size", "Size infos:", - "Show size options", NULL, NULL); - time_grp = g_option_group_new("time", "Time infos:", - "Show time options", NULL, NULL); - stats_grp = g_option_group_new("stats", "Statistics infos:", - "Show statistics options", NULL, NULL); - output_grp = g_option_group_new("output", "Output format:", - "Show output format options", NULL, NULL); - table_report_grp = g_option_group_new("table", "Table report options:", - "Show table report options", NULL, NULL); - g_option_group_add_entries(general_grp, general_entries); - g_option_group_add_entries(size_grp, size_entries); - g_option_group_add_entries(time_grp, time_entries); - g_option_group_add_entries(stats_grp, stats_entries); - g_option_group_add_entries(output_grp, output_format_entries); - g_option_group_add_entries(table_report_grp, table_report_entries); - g_option_context_add_main_entries(ctx, misc_entries, NULL); - g_option_context_add_group(ctx, general_grp); - g_option_context_add_group(ctx, size_grp); - g_option_context_add_group(ctx, time_grp); - g_option_context_add_group(ctx, stats_grp); - g_option_context_add_group(ctx, output_grp); - g_option_context_add_group(ctx, table_report_grp); - /* There's probably a better way to do this, but this works for now. - GOptions displays the name in argv[0] as the name of the - application. This is reasonable, but because we actually have a - script wrapper that calls the executable. The name that gets - displayed is not exactly the same as the command the user used - ran. - */ - argv[0] = (char *)"capinfos"; - - /* if we have at least one cmdline option, we disable printing all infos */ - if (argc > 2 && report_all_infos) - disable_all_infos(); - - if ( !g_option_context_parse(ctx, &argc, &argv, &parse_err) ) { - if (parse_err) - g_printerr ("option parsing failed: %s\n", parse_err->message); - g_printerr("%s", g_option_context_get_help (ctx, TRUE, NULL)); - exit(1); - } - if ( cap_help ) { - g_print("%s", g_option_context_get_help (ctx, FALSE, NULL)); - exit(0); - } - if ( argc < 2 ) { - g_printerr("%s", g_option_context_get_help (ctx, FALSE, NULL)); - exit(1); - } - g_option_context_free(ctx); - -#endif /* USE_GOPTION */ - while ((opt = getopt_long(argc, argv, "tEcs" FILE_HASH_OPT "dluaeyizvhxokCALTMRrSNqQBmb", long_options, NULL)) !=-1) { + /* FILE_HASH_OPT will be "H" if libgcrypt is compiled in, so don't use "H" */ + while ((opt = getopt_long(argc, argv, "abcdehiklmoqrstuvxyzABCEF" FILE_HASH_OPT "ILMNQRST", long_options, NULL)) !=-1) { switch (opt) { @@ -1534,6 +1553,16 @@ DIAG_ON(cast-qual) cap_comment = TRUE; break; + case 'F': + if (report_all_infos) disable_all_infos(); + cap_file_more_info = TRUE; + break; + + case 'I': + if (report_all_infos) disable_all_infos(); + cap_file_idb = TRUE; + break; + case 'C': continue_after_wtap_open_offline_failure = FALSE; break; -- cgit v1.2.1