Revert "TODO: smb2: simplify preauth_hash calculation..."
[wireshark-sm.git] / capinfos.c
blob4f1197859325ce490f0edb653b591e8f383fcf01
1 /* capinfos.c
2 * Reports capture file information including # of packets, duration, others
4 * Copyright 2004 Ian Schorr
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 * 2009-09-19: jyoung
16 * New capinfos features
18 * Continue processing additional files after
19 * a wiretap open failure. The new -C option
20 * reverts to capinfos' original behavior which
21 * is to cancel any further file processing at
22 * first file open failure.
24 * Change the behavior of how the default display
25 * of all infos is initiated. This gets rid of a
26 * special post getopt() argument count test.
28 * Add new table output format (with related options)
29 * This feature allows outputting the various infos
30 * into a tab delimited text file, or to a comma
31 * separated variables file (*.csv) instead of the
32 * original "long" format.
34 * 2011-04-05: wmeier
35 * behaviour changed: Upon exit capinfos will return
36 * an error status if an error occurred at any
37 * point during "continuous" file processing.
38 * (Previously a success status was always
39 * returned if the -C option was not used).
44 #include <config.h>
45 #define WS_LOG_DOMAIN LOG_DOMAIN_MAIN
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <stdarg.h>
51 #include <locale.h>
53 #include <ws_exit_codes.h>
54 #include <wsutil/ws_getopt.h>
56 #include <glib.h>
58 #include <wiretap/wtap.h>
60 #include <wsutil/cmdarg_err.h>
61 #include <wsutil/filesystem.h>
62 #include <wsutil/privileges.h>
63 #include <cli_main.h>
64 #include <wsutil/version_info.h>
65 #include <wiretap/wtap_opttypes.h>
67 #ifdef HAVE_PLUGINS
68 #include <wsutil/plugins.h>
69 #endif
71 #include <wsutil/report_message.h>
72 #include <wsutil/str_util.h>
73 #include <wsutil/to_str.h>
74 #include <wsutil/file_util.h>
75 #include <wsutil/ws_assert.h>
76 #include <wsutil/wslog.h>
78 #include <gcrypt.h>
80 #include "ui/failure_message.h"
83 * By default capinfos now continues processing
84 * the next filename if and when wiretap detects
85 * a problem opening or reading a file.
86 * Use the '-C' option to revert back to original
87 * capinfos behavior which is to abort any
88 * additional file processing at the first file
89 * open or read failure.
92 static gboolean stop_after_failure;
95 * table report variables
98 static gboolean long_report = TRUE; /* By default generate long report */
99 static gchar table_report_header = TRUE; /* Generate column header by default */
100 static gchar field_separator = '\t'; /* Use TAB as field separator by default */
101 static gchar quote_char = '\0'; /* Do NOT quote fields by default */
102 static gboolean machine_readable; /* Display machine-readable numbers */
105 * capinfos has the ability to report on a number of
106 * various characteristics ("infos") for each input file.
108 * By default reporting of all info fields is enabled.
110 * Optionally the reporting of any specific info field
111 * or combination of info fields can be enabled with
112 * individual options.
115 static gboolean report_all_infos = TRUE; /* Report all infos */
117 static gboolean cap_file_type = TRUE; /* Report capture type */
118 static gboolean cap_file_encap = TRUE; /* Report encapsulation */
119 static gboolean cap_snaplen = TRUE; /* Packet size limit (snaplen)*/
120 static gboolean cap_packet_count = TRUE; /* Report packet count */
121 static gboolean cap_file_size = TRUE; /* Report file size */
122 static gboolean cap_comment = TRUE; /* Display the capture comment */
123 static gboolean cap_file_more_info = TRUE; /* Report more file info */
124 static gboolean cap_file_idb = TRUE; /* Report Interface info */
125 static gboolean cap_file_nrb = TRUE; /* Report Name Resolution Block info */
126 static gboolean cap_file_dsb = TRUE; /* Report Decryption Secrets Block info */
128 static gboolean cap_data_size = TRUE; /* Report packet byte size */
129 static gboolean cap_duration = TRUE; /* Report capture duration */
130 static gboolean cap_start_time = TRUE; /* Report capture start time */
131 static gboolean cap_end_time = TRUE; /* Report capture end time */
132 static gboolean time_as_secs; /* Report time values as raw seconds */
134 static gboolean cap_data_rate_byte = TRUE; /* Report data rate bytes/sec */
135 static gboolean cap_data_rate_bit = TRUE; /* Report data rate bites/sec */
136 static gboolean cap_packet_size = TRUE; /* Report average packet size */
137 static gboolean cap_packet_rate = TRUE; /* Report average packet rate */
138 static gboolean cap_order = TRUE; /* Report if packets are in chronological order (True/False) */
139 static gboolean pkt_comments = TRUE; /* Report individual packet comments */
141 static gboolean cap_file_hashes = TRUE; /* Calculate file hashes */
143 // Strongest to weakest
144 #define HASH_SIZE_SHA256 32
145 #define HASH_SIZE_SHA1 20
147 #define HASH_STR_SIZE (65) /* Max hash size * 2 + '\0' */
148 #define HASH_BUF_SIZE (1024 * 1024)
151 static gchar file_sha256[HASH_STR_SIZE];
152 static gchar file_sha1[HASH_STR_SIZE];
154 static char *hash_buf;
155 static gcry_md_hd_t hd;
157 static guint num_ipv4_addresses;
158 static guint num_ipv6_addresses;
159 static guint num_decryption_secrets;
162 * If we have at least two packets with time stamps, and they're not in
163 * order - i.e., the later packet has a time stamp older than the earlier
164 * packet - the time stamps are known not to be in order.
166 * If every packet has a time stamp, and they're all in order, the time
167 * stamp is known to be in order.
169 * Otherwise, we have no idea.
171 typedef enum {
172 IN_ORDER,
173 NOT_IN_ORDER,
174 ORDER_UNKNOWN
175 } order_t;
177 typedef struct _pkt_cmt {
178 int recno;
179 gchar *cmt;
180 struct _pkt_cmt *next;
181 } pkt_cmt;
183 typedef struct _capture_info {
184 const char *filename;
185 guint16 file_type;
186 wtap_compression_type compression_type;
187 int file_encap;
188 int file_tsprec;
189 wtap *wth;
190 gint64 filesize;
191 guint64 packet_bytes;
192 gboolean times_known;
193 nstime_t start_time;
194 int start_time_tsprec;
195 nstime_t stop_time;
196 int stop_time_tsprec;
197 guint32 packet_count;
198 gboolean snap_set; /* If set in capture file header */
199 guint32 snaplen; /* value from the capture file header */
200 guint32 snaplen_min_inferred; /* If caplen < len for 1 or more rcds */
201 guint32 snaplen_max_inferred; /* ... */
202 gboolean drops_known;
203 guint32 drop_count;
205 nstime_t duration;
206 int duration_tsprec;
207 double packet_rate;
208 double packet_size;
209 double data_rate; /* in bytes/s */
210 gboolean know_order;
211 order_t order;
213 int *encap_counts; /* array of per_packet encap counts; array has one entry per wtap_encap type */
214 pkt_cmt *pkt_cmts; /* list of packet comments */
216 guint num_interfaces; /* number of IDBs, and thus size of interface_packet_counts array */
217 GArray *interface_packet_counts; /* array of per_packet interface_id counts; one entry per file IDB */
218 guint32 pkt_interface_id_unknown; /* counts if packet interface_id didn't match a known one */
219 GArray *idb_info_strings; /* array of IDB info strings */
220 } capture_info;
222 static char *decimal_point;
224 static void
225 enable_all_infos(void)
227 report_all_infos = TRUE;
229 cap_file_type = TRUE;
230 cap_file_encap = TRUE;
231 cap_snaplen = TRUE;
232 cap_packet_count = TRUE;
233 cap_file_size = TRUE;
234 cap_comment = TRUE;
235 pkt_comments = TRUE;
236 cap_file_more_info = TRUE;
237 cap_file_idb = TRUE;
238 cap_file_nrb = TRUE;
239 cap_file_dsb = TRUE;
241 cap_data_size = TRUE;
242 cap_duration = TRUE;
243 cap_start_time = TRUE;
244 cap_end_time = TRUE;
245 cap_order = TRUE;
247 cap_data_rate_byte = TRUE;
248 cap_data_rate_bit = TRUE;
249 cap_packet_size = TRUE;
250 cap_packet_rate = TRUE;
252 cap_file_hashes = TRUE;
255 static void
256 disable_all_infos(void)
258 report_all_infos = FALSE;
260 cap_file_type = FALSE;
261 cap_file_encap = FALSE;
262 cap_snaplen = FALSE;
263 cap_packet_count = FALSE;
264 cap_file_size = FALSE;
265 cap_comment = FALSE;
266 pkt_comments = FALSE;
267 cap_file_more_info = FALSE;
268 cap_file_idb = FALSE;
269 cap_file_nrb = FALSE;
270 cap_file_dsb = FALSE;
272 cap_data_size = FALSE;
273 cap_duration = FALSE;
274 cap_start_time = FALSE;
275 cap_end_time = FALSE;
276 cap_order = FALSE;
278 cap_data_rate_byte = FALSE;
279 cap_data_rate_bit = FALSE;
280 cap_packet_size = FALSE;
281 cap_packet_rate = FALSE;
283 cap_file_hashes = FALSE;
286 static const gchar *
287 order_string(order_t order)
289 switch (order) {
291 case IN_ORDER:
292 return "True";
294 case NOT_IN_ORDER:
295 return "False";
297 case ORDER_UNKNOWN:
298 return "Unknown";
300 default:
301 return "???"; /* "cannot happen" (the next step is "Profit!") */
305 static gchar *
306 absolute_time_string(nstime_t *timer, int tsprecision, capture_info *cf_info)
309 * https://web.archive.org/web/20120513133703/http://www.idrbt.ac.in/publications/workingpapers/Working%20Paper%20No.%209.pdf
311 * says:
313 * A 64-bit Unix time would be safe for the indefinite future, as
314 * this variable would not overflow until 2**63 or
315 * 9,223,372,036,854,775,808 (over nine quintillion) seconds
316 * after the beginning of the Unix epoch - corresponding to
317 * GMT 15:30:08, Sunday, 4th December, 292,277,026,596.
319 * So, if we're displaying the time as YYYY-MM-DD HH:MM:SS.SSSSSSSSS,
320 * we'll have the buffer be large enough for a date of the format
321 * 292277026596-MM-DD HH:MM:SS.SSSSSSSSS, which is the biggest value
322 * you'll get with a 64-bit time_t and a nanosecond-resolution
323 * fraction-of-a-second.
325 * That's 12+1+2+1+2+1+2+1+2+2+2+1+9+1, including the terminating
326 * \0, or 39.
328 * If we're displaying the time as epoch time, and the time is
329 * unsigned, 2^64-1 is 18446744073709551615, so the buffer has
330 * to be big enough for 18446744073709551615.999999999. That's
331 * 20+1+9+1, including the terminating '\0', or 31. If it's
332 * signed, 2^63 is 9223372036854775808, so the buffer has to
333 * be big enough for -9223372036854775808.999999999, which is
334 * again 20+1+9+1, or 31.
336 * So we go with 39.
338 static gchar time_string_buf[39];
340 if (cf_info->times_known && cf_info->packet_count > 0) {
341 if (time_as_secs) {
342 display_epoch_time(time_string_buf, sizeof time_string_buf, timer, tsprecision);
343 } else {
344 format_nstime_as_iso8601(time_string_buf, sizeof time_string_buf, timer, decimal_point, TRUE, tsprecision);
346 } else {
347 snprintf(time_string_buf, sizeof time_string_buf, "n/a");
349 return time_string_buf;
352 static gchar *
353 relative_time_string(nstime_t *timer, int tsprecision, capture_info *cf_info, gboolean want_seconds)
355 const gchar *second = want_seconds ? " second" : "";
356 const gchar *plural = want_seconds ? "s" : "";
358 * If we're displaying the time as epoch time, and the time is
359 * unsigned, 2^64-1 is 18446744073709551615, so the buffer has
360 * to be big enough for "18446744073709551615.999999999 seconds".
361 * That's 20+1+9+1+7+1, including the terminating '\0', or 39.
362 * If it'ssigned, 2^63 is 9223372036854775808, so the buffer has to
363 * be big enough for "-9223372036854775808.999999999 seconds",
364 * which is again 20+1+9+1+7+1, or 39.
366 static gchar time_string_buf[39];
368 if (cf_info->times_known && cf_info->packet_count > 0) {
369 char *ptr;
370 size_t remaining;
371 int num_bytes;
373 ptr = time_string_buf;
374 remaining = sizeof time_string_buf;
375 num_bytes = snprintf(ptr, remaining,
376 "%"PRId64,
377 (gint64)timer->secs);
378 if (num_bytes < 0) {
380 * That got an error.
381 * Not much else we can do.
383 snprintf(ptr, remaining, "snprintf() failed");
384 return time_string_buf;
386 if ((unsigned int)num_bytes >= remaining) {
388 * That filled up or would have overflowed the buffer.
389 * Nothing more we can do.
391 return time_string_buf;
393 ptr += num_bytes;
394 remaining -= num_bytes;
396 if (tsprecision != 0) {
398 * Append the fractional part.
400 num_bytes = format_fractional_part_nsecs(ptr, remaining, timer->nsecs, decimal_point, tsprecision);
401 if ((unsigned int)num_bytes >= remaining) {
403 * That filled up or would have overflowed the buffer.
404 * Nothing more we can do.
406 return time_string_buf;
408 ptr += num_bytes;
409 remaining -= num_bytes;
413 * Append the units.
415 snprintf(ptr, remaining, "%s%s",
416 second,
417 timer->secs == 1 ? "" : plural);
419 return time_string_buf;
422 snprintf(time_string_buf, sizeof time_string_buf, "n/a");
423 return time_string_buf;
426 static void print_value(const gchar *text_p1, gint width, const gchar *text_p2, double value)
428 if (value > 0.0)
429 printf("%s%.*f%s\n", text_p1, width, value, text_p2);
430 else
431 printf("%sn/a\n", text_p1);
434 /* multi-line comments would conflict with the formatting that capinfos uses
435 we replace linefeeds with spaces */
436 static void
437 string_replace_newlines(gchar *str)
439 gchar *p;
441 if (str) {
442 p = str;
443 while (*p != '\0') {
444 if (*p == '\n')
445 *p = ' ';
446 if (*p == '\r')
447 *p = ' ';
448 p++;
453 static void
454 show_option_string(const char *prefix, const char *option_str)
456 char *str;
458 if (option_str != NULL && option_str[0] != '\0') {
459 str = g_strdup(option_str);
460 string_replace_newlines(str);
461 printf("%s%s\n", prefix, str);
462 g_free(str);
466 static void
467 print_stats(const gchar *filename, capture_info *cf_info)
469 const gchar *file_type_string, *file_encap_string;
470 gchar *size_string;
471 pkt_cmt *p, *prev;
473 /* Build printable strings for various stats */
474 if (machine_readable) {
475 file_type_string = wtap_file_type_subtype_name(cf_info->file_type);
476 file_encap_string = wtap_encap_name(cf_info->file_encap);
478 else {
479 file_type_string = wtap_file_type_subtype_description(cf_info->file_type);
480 file_encap_string = wtap_encap_description(cf_info->file_encap);
483 if (filename) printf ("File name: %s\n", filename);
484 if (cap_file_type) {
485 const char *compression_type_description;
486 compression_type_description = wtap_compression_type_description(cf_info->compression_type);
487 if (compression_type_description == NULL)
488 printf ("File type: %s\n",
489 file_type_string);
490 else
491 printf ("File type: %s (%s)\n",
492 file_type_string, compression_type_description);
494 if (cap_file_encap) {
495 printf ("File encapsulation: %s\n", file_encap_string);
496 if (cf_info->file_encap == WTAP_ENCAP_PER_PACKET) {
497 int i;
498 printf ("Encapsulation in use by packets (# of pkts):\n");
499 for (i=0; i<WTAP_NUM_ENCAP_TYPES; i++) {
500 if (cf_info->encap_counts[i] > 0)
501 printf(" %s (%d)\n",
502 wtap_encap_description(i), cf_info->encap_counts[i]);
506 if (cap_file_more_info) {
507 printf ("File timestamp precision: %s (%d)\n",
508 wtap_tsprec_string(cf_info->file_tsprec), cf_info->file_tsprec);
511 if (cap_snaplen && cf_info->snap_set)
512 printf ("Packet size limit: file hdr: %u bytes\n", cf_info->snaplen);
513 else if (cap_snaplen && !cf_info->snap_set)
514 printf ("Packet size limit: file hdr: (not set)\n");
515 if (cf_info->snaplen_max_inferred > 0) {
516 if (cf_info->snaplen_min_inferred == cf_info->snaplen_max_inferred)
517 printf ("Packet size limit: inferred: %u bytes\n", cf_info->snaplen_min_inferred);
518 else
519 printf ("Packet size limit: inferred: %u bytes - %u bytes (range)\n",
520 cf_info->snaplen_min_inferred, cf_info->snaplen_max_inferred);
522 if (cap_packet_count) {
523 printf ("Number of packets: ");
524 if (machine_readable) {
525 printf ("%u\n", cf_info->packet_count);
526 } else {
527 size_string = format_size(cf_info->packet_count, FORMAT_SIZE_UNIT_NONE, 0);
528 printf ("%s\n", size_string);
529 g_free(size_string);
532 if (cap_file_size) {
533 printf ("File size: ");
534 if (machine_readable) {
535 printf ("%" PRId64 " bytes\n", cf_info->filesize);
536 } else {
537 size_string = format_size(cf_info->filesize, FORMAT_SIZE_UNIT_BYTES, 0);
538 printf ("%s\n", size_string);
539 g_free(size_string);
542 if (cap_data_size) {
543 printf ("Data size: ");
544 if (machine_readable) {
545 printf ("%" PRIu64 " bytes\n", cf_info->packet_bytes);
546 } else {
547 size_string = format_size(cf_info->packet_bytes, FORMAT_SIZE_UNIT_BYTES, 0);
548 printf ("%s\n", size_string);
549 g_free(size_string);
552 if (cf_info->times_known) {
553 if (cap_duration) /* XXX - shorten to hh:mm:ss */
554 printf("Capture duration: %s\n", relative_time_string(&cf_info->duration, cf_info->duration_tsprec, cf_info, TRUE));
555 if (cap_start_time)
556 printf("First packet time: %s\n", absolute_time_string(&cf_info->start_time, cf_info->start_time_tsprec, cf_info));
557 if (cap_end_time)
558 printf("Last packet time: %s\n", absolute_time_string(&cf_info->stop_time, cf_info->stop_time_tsprec, cf_info));
559 if (cap_data_rate_byte) {
560 printf("Data byte rate: ");
561 if (machine_readable) {
562 print_value("", 2, " bytes/sec", cf_info->data_rate);
563 } else {
564 size_string = format_size((int64_t)cf_info->data_rate, FORMAT_SIZE_UNIT_BYTES_S, 0);
565 printf ("%s\n", size_string);
566 g_free(size_string);
569 if (cap_data_rate_bit) {
570 printf("Data bit rate: ");
571 if (machine_readable) {
572 print_value("", 2, " bits/sec", cf_info->data_rate*8);
573 } else {
574 size_string = format_size((int64_t)(cf_info->data_rate*8), FORMAT_SIZE_UNIT_BITS_S, 0);
575 printf ("%s\n", size_string);
576 g_free(size_string);
580 if (cap_packet_size) printf("Average packet size: %.2f bytes\n", cf_info->packet_size);
581 if (cf_info->times_known) {
582 if (cap_packet_rate) {
583 printf("Average packet rate: ");
584 if (machine_readable) {
585 print_value("", 2, " packets/sec", cf_info->packet_rate);
586 } else {
587 size_string = format_size((int64_t)cf_info->packet_rate, FORMAT_SIZE_UNIT_PACKETS_S, 0);
588 printf ("%s\n", size_string);
589 g_free(size_string);
593 if (cap_file_hashes) {
594 printf ("SHA256: %s\n", file_sha256);
595 printf ("SHA1: %s\n", file_sha1);
597 if (cap_order) printf ("Strict time order: %s\n", order_string(cf_info->order));
599 gboolean has_multiple_sections = (wtap_file_get_num_shbs(cf_info->wth) > 1);
601 for (guint section_number = 0;
602 section_number < wtap_file_get_num_shbs(cf_info->wth);
603 section_number++) {
604 wtap_block_t shb;
606 // If we have more than one section, add headers for each section.
607 if (has_multiple_sections)
608 printf("Section %u:\n\n", section_number);
610 shb = wtap_file_get_shb(cf_info->wth, section_number);
611 if (shb != NULL) {
612 if (cap_file_more_info) {
613 char *str;
615 if (wtap_block_get_string_option_value(shb, OPT_SHB_HARDWARE, &str) == WTAP_OPTTYPE_SUCCESS)
616 show_option_string("Capture hardware: ", str);
617 if (wtap_block_get_string_option_value(shb, OPT_SHB_OS, &str) == WTAP_OPTTYPE_SUCCESS)
618 show_option_string("Capture oper-sys: ", str);
619 if (wtap_block_get_string_option_value(shb, OPT_SHB_USERAPPL, &str) == WTAP_OPTTYPE_SUCCESS)
620 show_option_string("Capture application: ", str);
622 if (cap_comment) {
623 unsigned int i;
624 char *str;
626 for (i = 0; wtap_block_get_nth_string_option_value(shb, OPT_COMMENT, i, &str) == WTAP_OPTTYPE_SUCCESS; i++) {
627 show_option_string("Capture comment: ", str);
631 if (pkt_comments && cf_info->pkt_cmts != NULL) {
632 for (p = cf_info->pkt_cmts; p != NULL; prev = p, p = p->next, g_free(prev)) {
633 if (machine_readable){
634 printf("Packet %d Comment: %s\n", p->recno, g_strescape(p->cmt, NULL));
635 } else {
636 printf("Packet %d Comment: %s\n", p->recno, p->cmt);
638 g_free(p->cmt);
642 if (cap_file_idb && cf_info->num_interfaces != 0) {
643 guint i;
644 ws_assert(cf_info->num_interfaces == cf_info->idb_info_strings->len);
645 printf ("Number of interfaces in file: %u\n", cf_info->num_interfaces);
646 for (i = 0; i < cf_info->idb_info_strings->len; i++) {
647 gchar *s = g_array_index(cf_info->idb_info_strings, gchar*, i);
648 guint32 packet_count = 0;
649 if (i < cf_info->interface_packet_counts->len)
650 packet_count = g_array_index(cf_info->interface_packet_counts, guint32, i);
651 printf ("Interface #%u info:\n", i);
652 printf ("%s", s);
653 printf (" Number of packets = %u\n", packet_count);
658 if (cap_file_nrb) {
659 if (num_ipv4_addresses != 0)
660 printf ("Number of resolved IPv4 addresses in file: %u\n", num_ipv4_addresses);
661 if (num_ipv6_addresses != 0)
662 printf ("Number of resolved IPv6 addresses in file: %u\n", num_ipv6_addresses);
664 if (cap_file_dsb) {
665 if (num_decryption_secrets != 0)
666 printf ("Number of decryption secrets in file: %u\n", num_decryption_secrets);
671 static void
672 putsep(void)
674 if (field_separator) putchar(field_separator);
677 static void
678 putquote(void)
680 if (quote_char) putchar(quote_char);
683 static void
684 print_stats_table_header_label(const gchar *label)
686 putsep();
687 putquote();
688 printf("%s", label);
689 putquote();
692 static void
693 print_stats_table_header(capture_info *cf_info)
695 pkt_cmt *p;
696 char *buf;
698 putquote();
699 printf("File name");
700 putquote();
702 if (cap_file_type) print_stats_table_header_label("File type");
703 if (cap_file_encap) print_stats_table_header_label("File encapsulation");
704 if (cap_file_more_info) print_stats_table_header_label("File time precision");
705 if (cap_snaplen) {
706 print_stats_table_header_label("Packet size limit");
707 print_stats_table_header_label("Packet size limit min (inferred)");
708 print_stats_table_header_label("Packet size limit max (inferred)");
710 if (cap_packet_count) print_stats_table_header_label("Number of packets");
711 if (cap_file_size) print_stats_table_header_label("File size (bytes)");
712 if (cap_data_size) print_stats_table_header_label("Data size (bytes)");
713 if (cap_duration) print_stats_table_header_label("Capture duration (seconds)");
714 if (cap_start_time) print_stats_table_header_label("Start time");
715 if (cap_end_time) print_stats_table_header_label("End time");
716 if (cap_data_rate_byte) print_stats_table_header_label("Data byte rate (bytes/sec)");
717 if (cap_data_rate_bit) print_stats_table_header_label("Data bit rate (bits/sec)");
718 if (cap_packet_size) print_stats_table_header_label("Average packet size (bytes)");
719 if (cap_packet_rate) print_stats_table_header_label("Average packet rate (packets/sec)");
720 if (cap_file_hashes) {
721 print_stats_table_header_label("SHA256");
722 print_stats_table_header_label("SHA1");
724 if (cap_order) print_stats_table_header_label("Strict time order");
725 if (cap_file_more_info) {
726 print_stats_table_header_label("Capture hardware");
727 print_stats_table_header_label("Capture oper-sys");
728 print_stats_table_header_label("Capture application");
730 if (cap_comment) print_stats_table_header_label("Capture comment");
732 if (pkt_comments && cf_info->pkt_cmts != NULL) {
733 /* Packet 2^64 Comment" + NULL */
734 buf = (char *)g_malloc0(strlen("Packet 18446744073709551616 Comment") + 1);
736 for (p = cf_info->pkt_cmts; p != NULL; p = p->next) {
737 snprintf(buf, strlen(buf), "Packet %d Comment", p->recno);
738 print_stats_table_header_label(buf);
742 printf("\n");
745 static void
746 print_stats_table(const gchar *filename, capture_info *cf_info)
748 const gchar *file_type_string, *file_encap_string;
749 pkt_cmt *p, *prev;
751 /* Build printable strings for various stats */
752 file_type_string = wtap_file_type_subtype_name(cf_info->file_type);
753 file_encap_string = wtap_encap_name(cf_info->file_encap);
755 if (filename) {
756 putquote();
757 printf("%s", filename);
758 putquote();
761 if (cap_file_type) {
762 putsep();
763 putquote();
764 printf("%s", file_type_string);
765 putquote();
768 /* ToDo: If WTAP_ENCAP_PER_PACKET, show the list of encapsulations encountered;
769 * Output a line for each different encap with all fields repeated except
770 * the encapsulation field which has "Per Packet: ..." for each
771 * encapsulation type seen ?
773 if (cap_file_encap) {
774 putsep();
775 putquote();
776 printf("%s", file_encap_string);
777 putquote();
780 if (cap_file_more_info) {
781 putsep();
782 putquote();
783 printf("%s", wtap_tsprec_string(cf_info->file_tsprec));
784 putquote();
787 if (cap_snaplen) {
788 putsep();
789 putquote();
790 if (cf_info->snap_set)
791 printf("%u", cf_info->snaplen);
792 else
793 printf("(not set)");
794 putquote();
795 if (cf_info->snaplen_max_inferred > 0) {
796 putsep();
797 putquote();
798 printf("%u", cf_info->snaplen_min_inferred);
799 putquote();
800 putsep();
801 putquote();
802 printf("%u", cf_info->snaplen_max_inferred);
803 putquote();
805 else {
806 putsep();
807 putquote();
808 printf("n/a");
809 putquote();
810 putsep();
811 putquote();
812 printf("n/a");
813 putquote();
817 if (cap_packet_count) {
818 putsep();
819 putquote();
820 printf("%u", cf_info->packet_count);
821 putquote();
824 if (cap_file_size) {
825 putsep();
826 putquote();
827 printf("%" PRId64, cf_info->filesize);
828 putquote();
831 if (cap_data_size) {
832 putsep();
833 putquote();
834 printf("%" PRIu64, cf_info->packet_bytes);
835 putquote();
838 if (cap_duration) {
839 putsep();
840 putquote();
841 printf("%s", relative_time_string(&cf_info->duration, cf_info->duration_tsprec, cf_info, FALSE));
842 putquote();
845 if (cap_start_time) {
846 putsep();
847 putquote();
848 printf("%s", absolute_time_string(&cf_info->start_time, cf_info->start_time_tsprec, cf_info));
849 putquote();
852 if (cap_end_time) {
853 putsep();
854 putquote();
855 printf("%s", absolute_time_string(&cf_info->stop_time, cf_info->stop_time_tsprec, cf_info));
856 putquote();
859 if (cap_data_rate_byte) {
860 putsep();
861 putquote();
862 if (cf_info->times_known)
863 printf("%.2f", cf_info->data_rate);
864 else
865 printf("n/a");
866 putquote();
869 if (cap_data_rate_bit) {
870 putsep();
871 putquote();
872 if (cf_info->times_known)
873 printf("%.2f", cf_info->data_rate*8);
874 else
875 printf("n/a");
876 putquote();
879 if (cap_packet_size) {
880 putsep();
881 putquote();
882 printf("%.2f", cf_info->packet_size);
883 putquote();
886 if (cap_packet_rate) {
887 putsep();
888 putquote();
889 if (cf_info->times_known)
890 printf("%.2f", cf_info->packet_rate);
891 else
892 printf("n/a");
893 putquote();
896 if (cap_file_hashes) {
897 putsep();
898 putquote();
899 printf("%s", file_sha256);
900 putquote();
902 putsep();
903 putquote();
904 printf("%s", file_sha1);
905 putquote();
908 if (cap_order) {
909 putsep();
910 putquote();
911 printf("%s", order_string(cf_info->order));
912 putquote();
915 for (guint section_number = 0;
916 section_number < wtap_file_get_num_shbs(cf_info->wth);
917 section_number++) {
918 wtap_block_t shb;
920 shb = wtap_file_get_shb(cf_info->wth, section_number);
921 if (cap_file_more_info) {
922 char *str;
924 putsep();
925 putquote();
926 if (wtap_block_get_string_option_value(shb, OPT_SHB_HARDWARE, &str) == WTAP_OPTTYPE_SUCCESS) {
927 printf("%s", str);
929 putquote();
931 putsep();
932 putquote();
933 if (wtap_block_get_string_option_value(shb, OPT_SHB_OS, &str) == WTAP_OPTTYPE_SUCCESS) {
934 printf("%s", str);
936 putquote();
938 putsep();
939 putquote();
940 if (wtap_block_get_string_option_value(shb, OPT_SHB_USERAPPL, &str) == WTAP_OPTTYPE_SUCCESS) {
941 printf("%s", str);
943 putquote();
947 * One might argue that the following is silly to put into a table format,
948 * but oh well note that there may be *more than one* of each of these types
949 * of options. To mitigate some of the potential silliness the if(cap_comment)
950 * block is moved AFTER the if(cap_file_more_info) block. This will make any
951 * comments the last item(s) in each row. We now have a new -K option to
952 * disable cap_comment to more easily manage the potential silliness.
953 * Potential silliness includes multiple comments (therefore resulting in
954 * more than one additional column and/or comments with embedded newlines
955 * and/or possible delimiters).
957 * To mitigate embedded newlines and other special characters, use -M
959 if (cap_comment) {
960 unsigned int i;
961 char *opt_comment;
962 gboolean have_cap = FALSE;
964 for (i = 0; wtap_block_get_nth_string_option_value(shb, OPT_COMMENT, i, &opt_comment) == WTAP_OPTTYPE_SUCCESS; i++) {
965 have_cap = TRUE;
966 putsep();
967 putquote();
968 if (machine_readable){
969 printf("%s", g_strescape(opt_comment, NULL));
970 } else {
971 printf("%s", opt_comment);
973 putquote();
975 if(!have_cap) {
976 /* Maintain column alignment when we have no OPT_COMMENT */
977 putsep();
978 putquote();
979 putquote();
985 if (pkt_comments && cf_info->pkt_cmts != NULL) {
986 for(p = cf_info->pkt_cmts; p != NULL; prev = p, p = p->next, g_free(prev)) {
987 putsep();
988 putquote();
989 if (machine_readable) {
990 printf("%s", g_strescape(p->cmt, NULL));
991 } else {
992 printf("%s", p->cmt);
994 g_free(p->cmt);
995 putquote();
999 printf("\n");
1002 static void
1003 cleanup_capture_info(capture_info *cf_info)
1005 guint i;
1006 ws_assert(cf_info != NULL);
1008 g_free(cf_info->encap_counts);
1009 cf_info->encap_counts = NULL;
1011 g_array_free(cf_info->interface_packet_counts, TRUE);
1012 cf_info->interface_packet_counts = NULL;
1014 if (cf_info->idb_info_strings) {
1015 for (i = 0; i < cf_info->idb_info_strings->len; i++) {
1016 gchar *s = g_array_index(cf_info->idb_info_strings, gchar*, i);
1017 g_free(s);
1019 g_array_free(cf_info->idb_info_strings, TRUE);
1021 cf_info->idb_info_strings = NULL;
1024 static void
1025 count_ipv4_address(const guint addr _U_, const gchar *name _U_, const bool static_entry _U_)
1027 num_ipv4_addresses++;
1030 static void
1031 count_ipv6_address(const void *addrp _U_, const gchar *name _U_, const bool static_entry _U_)
1033 num_ipv6_addresses++;
1036 static void
1037 count_decryption_secret(guint32 secrets_type _U_, const void *secrets _U_, guint size _U_)
1039 /* XXX - count them based on the secrets type (which is an opaque code,
1040 not a small integer)? */
1041 num_decryption_secrets++;
1044 static void
1045 hash_to_str(const unsigned char *hash, size_t length, char *str)
1047 int i;
1049 for (i = 0; i < (int) length; i++) {
1050 snprintf(str+(i*2), 3, "%02x", hash[i]);
1054 static void
1055 calculate_hashes(const char *filename)
1057 FILE *fh;
1058 size_t hash_bytes;
1060 (void) g_strlcpy(file_sha256, "<unknown>", HASH_STR_SIZE);
1061 (void) g_strlcpy(file_sha1, "<unknown>", HASH_STR_SIZE);
1063 if (cap_file_hashes) {
1064 fh = ws_fopen(filename, "rb");
1065 if (fh && hd) {
1066 while((hash_bytes = fread(hash_buf, 1, HASH_BUF_SIZE, fh)) > 0) {
1067 gcry_md_write(hd, hash_buf, hash_bytes);
1069 gcry_md_final(hd);
1070 hash_to_str(gcry_md_read(hd, GCRY_MD_SHA256), HASH_SIZE_SHA256, file_sha256);
1071 hash_to_str(gcry_md_read(hd, GCRY_MD_SHA1), HASH_SIZE_SHA1, file_sha1);
1073 if (fh) fclose(fh);
1074 if (hd) gcry_md_reset(hd);
1078 static int
1079 process_cap_file(const char *filename, gboolean need_separator)
1081 int status = 0;
1082 int err;
1083 gchar *err_info;
1084 gint64 size;
1085 gint64 data_offset;
1087 guint32 packet = 0;
1088 gint64 bytes = 0;
1089 guint32 snaplen_min_inferred = 0xffffffff;
1090 guint32 snaplen_max_inferred = 0;
1091 wtap_rec rec;
1092 Buffer buf;
1093 capture_info cf_info;
1094 gboolean have_times = TRUE;
1095 nstime_t start_time;
1096 int start_time_tsprec;
1097 nstime_t stop_time;
1098 int stop_time_tsprec;
1099 nstime_t cur_time;
1100 nstime_t prev_time;
1101 gboolean know_order = FALSE;
1102 order_t order = IN_ORDER;
1103 guint i;
1104 wtapng_iface_descriptions_t *idb_info;
1106 pkt_cmt *pc = NULL, *prev = NULL;
1108 cf_info.wth = wtap_open_offline(filename, WTAP_TYPE_AUTO, &err, &err_info, FALSE);
1109 if (!cf_info.wth) {
1110 cfile_open_failure_message(filename, err, err_info);
1111 return 2;
1115 * Calculate the checksums. Do this after wtap_open_offline, so we don't
1116 * bother calculating them for files that are not known capture types
1117 * where we wouldn't print them anyway.
1119 calculate_hashes(filename);
1121 if (need_separator && long_report) {
1122 printf("\n");
1125 nstime_set_zero(&start_time);
1126 start_time_tsprec = WTAP_TSPREC_UNKNOWN;
1127 nstime_set_zero(&stop_time);
1128 stop_time_tsprec = WTAP_TSPREC_UNKNOWN;
1129 nstime_set_zero(&cur_time);
1130 nstime_set_zero(&prev_time);
1132 cf_info.encap_counts = g_new0(int,WTAP_NUM_ENCAP_TYPES);
1134 idb_info = wtap_file_get_idb_info(cf_info.wth);
1136 ws_assert(idb_info->interface_data != NULL);
1138 cf_info.pkt_cmts = NULL;
1139 cf_info.num_interfaces = idb_info->interface_data->len;
1140 cf_info.interface_packet_counts = g_array_sized_new(FALSE, TRUE, sizeof(guint32), cf_info.num_interfaces);
1141 g_array_set_size(cf_info.interface_packet_counts, cf_info.num_interfaces);
1142 cf_info.pkt_interface_id_unknown = 0;
1144 g_free(idb_info);
1145 idb_info = NULL;
1147 /* Zero out the counters for the callbacks. */
1148 num_ipv4_addresses = 0;
1149 num_ipv6_addresses = 0;
1150 num_decryption_secrets = 0;
1152 /* Register callbacks for new name<->address maps from the file and
1153 decryption secrets from the file. */
1154 wtap_set_cb_new_ipv4(cf_info.wth, count_ipv4_address);
1155 wtap_set_cb_new_ipv6(cf_info.wth, count_ipv6_address);
1156 wtap_set_cb_new_secrets(cf_info.wth, count_decryption_secret);
1158 /* Tally up data that we need to parse through the file to find */
1159 wtap_rec_init(&rec);
1160 ws_buffer_init(&buf, 1514);
1161 while (wtap_read(cf_info.wth, &rec, &buf, &err, &err_info, &data_offset)) {
1162 if (rec.presence_flags & WTAP_HAS_TS) {
1163 prev_time = cur_time;
1164 cur_time = rec.ts;
1165 if (packet == 0) {
1166 start_time = rec.ts;
1167 start_time_tsprec = rec.tsprec;
1168 stop_time = rec.ts;
1169 stop_time_tsprec = rec.tsprec;
1170 prev_time = rec.ts;
1172 if (nstime_cmp(&cur_time, &prev_time) < 0) {
1173 order = NOT_IN_ORDER;
1175 if (nstime_cmp(&cur_time, &start_time) < 0) {
1176 start_time = cur_time;
1177 start_time_tsprec = rec.tsprec;
1179 if (nstime_cmp(&cur_time, &stop_time) > 0) {
1180 stop_time = cur_time;
1181 stop_time_tsprec = rec.tsprec;
1183 } else {
1184 have_times = FALSE; /* at least one packet has no time stamp */
1185 if (order != NOT_IN_ORDER)
1186 order = ORDER_UNKNOWN;
1189 if (rec.rec_type == REC_TYPE_PACKET) {
1190 bytes += rec.rec_header.packet_header.len;
1191 packet++;
1192 /* packet comments */
1193 if (pkt_comments && wtap_block_count_option(rec.block, OPT_COMMENT) > 0) {
1194 char *cmt_buff;
1195 for (i = 0; wtap_block_get_nth_string_option_value(rec.block, OPT_COMMENT, i, &cmt_buff) == WTAP_OPTTYPE_SUCCESS; i++) {
1196 pc = g_new0(pkt_cmt, 1);
1198 pc->recno = packet;
1199 pc->cmt = g_strdup(cmt_buff);
1200 pc->next = NULL;
1202 if (prev == NULL)
1203 cf_info.pkt_cmts = pc;
1204 else
1205 prev->next = pc;
1207 prev = pc;
1211 /* If caplen < len for a rcd, then presumably */
1212 /* 'Limit packet capture length' was done for this rcd. */
1213 /* Keep track as to the min/max actual snapshot lengths */
1214 /* seen for this file. */
1215 if (rec.rec_header.packet_header.caplen < rec.rec_header.packet_header.len) {
1216 if (rec.rec_header.packet_header.caplen < snaplen_min_inferred)
1217 snaplen_min_inferred = rec.rec_header.packet_header.caplen;
1218 if (rec.rec_header.packet_header.caplen > snaplen_max_inferred)
1219 snaplen_max_inferred = rec.rec_header.packet_header.caplen;
1222 if ((rec.rec_header.packet_header.pkt_encap > 0) &&
1223 (rec.rec_header.packet_header.pkt_encap < WTAP_NUM_ENCAP_TYPES)) {
1224 cf_info.encap_counts[rec.rec_header.packet_header.pkt_encap] += 1;
1225 } else {
1226 fprintf(stderr, "capinfos: Unknown packet encapsulation %d in frame %u of file \"%s\"\n",
1227 rec.rec_header.packet_header.pkt_encap, packet, filename);
1230 /* Packet interface_id info */
1231 if (rec.presence_flags & WTAP_HAS_INTERFACE_ID) {
1232 /* cf_info.num_interfaces is size, not index, so it's one more than max index */
1233 if (rec.rec_header.packet_header.interface_id >= cf_info.num_interfaces) {
1235 * OK, re-fetch the number of interfaces, as there might have
1236 * been an interface that was in the middle of packets, and
1237 * grow the array to be big enough for the new number of
1238 * interfaces.
1240 idb_info = wtap_file_get_idb_info(cf_info.wth);
1242 cf_info.num_interfaces = idb_info->interface_data->len;
1243 g_array_set_size(cf_info.interface_packet_counts, cf_info.num_interfaces);
1245 g_free(idb_info);
1246 idb_info = NULL;
1248 if (rec.rec_header.packet_header.interface_id < cf_info.num_interfaces) {
1249 g_array_index(cf_info.interface_packet_counts, guint32,
1250 rec.rec_header.packet_header.interface_id) += 1;
1252 else {
1253 cf_info.pkt_interface_id_unknown += 1;
1256 else {
1257 /* it's for interface_id 0 */
1258 if (cf_info.num_interfaces != 0) {
1259 g_array_index(cf_info.interface_packet_counts, guint32, 0) += 1;
1261 else {
1262 cf_info.pkt_interface_id_unknown += 1;
1267 wtap_rec_reset(&rec);
1268 } /* while */
1269 wtap_rec_cleanup(&rec);
1270 ws_buffer_free(&buf);
1273 * Get IDB info strings.
1274 * We do this at the end, so we can get information for all IDBs in
1275 * the file, even those that come after packet records, and so that
1276 * we get, for example, a count of the number of statistics entries
1277 * for each interface as of the *end* of the file.
1279 idb_info = wtap_file_get_idb_info(cf_info.wth);
1281 cf_info.idb_info_strings = g_array_sized_new(FALSE, FALSE, sizeof(gchar*), cf_info.num_interfaces);
1282 cf_info.num_interfaces = idb_info->interface_data->len;
1283 for (i = 0; i < cf_info.num_interfaces; i++) {
1284 const wtap_block_t if_descr = g_array_index(idb_info->interface_data, wtap_block_t, i);
1285 gchar *s = wtap_get_debug_if_descr(if_descr, 21, "\n");
1286 g_array_append_val(cf_info.idb_info_strings, s);
1289 g_free(idb_info);
1290 idb_info = NULL;
1292 if (err != 0) {
1293 fprintf(stderr,
1294 "capinfos: An error occurred after reading %u packets from \"%s\".\n",
1295 packet, filename);
1296 cfile_read_failure_message(filename, err, err_info);
1297 if (err == WTAP_ERR_SHORT_READ) {
1298 /* Don't give up completely with this one. */
1299 status = 1;
1300 fprintf(stderr,
1301 " (will continue anyway, checksums might be incorrect)\n");
1302 } else {
1303 cleanup_capture_info(&cf_info);
1304 wtap_close(cf_info.wth);
1305 return 2;
1309 /* File size */
1310 size = wtap_file_size(cf_info.wth, &err);
1311 if (size == -1) {
1312 fprintf(stderr,
1313 "capinfos: Can't get size of \"%s\": %s.\n",
1314 filename, g_strerror(err));
1315 cleanup_capture_info(&cf_info);
1316 wtap_close(cf_info.wth);
1317 return 2;
1320 cf_info.filesize = size;
1322 /* File Type */
1323 cf_info.file_type = wtap_file_type_subtype(cf_info.wth);
1324 cf_info.compression_type = wtap_get_compression_type(cf_info.wth);
1326 /* File Encapsulation */
1327 cf_info.file_encap = wtap_file_encap(cf_info.wth);
1329 cf_info.file_tsprec = wtap_file_tsprec(cf_info.wth);
1331 /* Packet size limit (snaplen) */
1332 cf_info.snaplen = wtap_snapshot_length(cf_info.wth);
1333 if (cf_info.snaplen > 0)
1334 cf_info.snap_set = TRUE;
1335 else
1336 cf_info.snap_set = FALSE;
1338 cf_info.snaplen_min_inferred = snaplen_min_inferred;
1339 cf_info.snaplen_max_inferred = snaplen_max_inferred;
1341 /* # of packets */
1342 cf_info.packet_count = packet;
1344 /* File Times */
1345 cf_info.times_known = have_times;
1346 cf_info.start_time = start_time;
1347 cf_info.start_time_tsprec = start_time_tsprec;
1348 cf_info.stop_time = stop_time;
1349 cf_info.stop_time_tsprec = stop_time_tsprec;
1350 nstime_delta(&cf_info.duration, &stop_time, &start_time);
1351 /* Duration precision is the higher of the start and stop time precisions. */
1352 if (cf_info.stop_time_tsprec > cf_info.start_time_tsprec)
1353 cf_info.duration_tsprec = cf_info.stop_time_tsprec;
1354 else
1355 cf_info.duration_tsprec = cf_info.start_time_tsprec;
1356 cf_info.know_order = know_order;
1357 cf_info.order = order;
1359 /* Number of packet bytes */
1360 cf_info.packet_bytes = bytes;
1362 cf_info.data_rate = 0.0;
1363 cf_info.packet_rate = 0.0;
1364 cf_info.packet_size = 0.0;
1366 if (packet > 0) {
1367 double delta_time = nstime_to_sec(&stop_time) - nstime_to_sec(&start_time);
1368 if (delta_time > 0.0) {
1369 cf_info.data_rate = (double)bytes / delta_time; /* Data rate per second */
1370 cf_info.packet_rate = (double)packet / delta_time; /* packet rate per second */
1372 cf_info.packet_size = (double)bytes / packet; /* Avg packet size */
1375 if (!long_report && table_report_header) {
1376 print_stats_table_header(&cf_info);
1379 if (long_report) {
1380 print_stats(filename, &cf_info);
1381 } else {
1382 print_stats_table(filename, &cf_info);
1385 cleanup_capture_info(&cf_info);
1386 wtap_close(cf_info.wth);
1388 return status;
1391 static void
1392 print_usage(FILE *output)
1394 fprintf(output, "\n");
1395 fprintf(output, "Usage: capinfos [options] <infile> ...\n");
1396 fprintf(output, "\n");
1397 fprintf(output, "General infos:\n");
1398 fprintf(output, " -t display the capture file type\n");
1399 fprintf(output, " -E display the capture file encapsulation\n");
1400 fprintf(output, " -I display the capture file interface information\n");
1401 fprintf(output, " -F display additional capture file information\n");
1402 fprintf(output, " -H display the SHA256 and SHA1 hashes of the file\n");
1403 fprintf(output, " -k display the capture comment\n");
1404 fprintf(output, " -p display individual packet comments\n");
1405 fprintf(output, "\n");
1406 fprintf(output, "Size infos:\n");
1407 fprintf(output, " -c display the number of packets\n");
1408 fprintf(output, " -s display the size of the file (in bytes)\n");
1409 fprintf(output, " -d display the total length of all packets (in bytes)\n");
1410 fprintf(output, " -l display the packet size limit (snapshot length)\n");
1411 fprintf(output, "\n");
1412 fprintf(output, "Time infos:\n");
1413 fprintf(output, " -u display the capture duration (in seconds)\n");
1414 fprintf(output, " -a display the capture start time\n");
1415 fprintf(output, " -e display the capture end time\n");
1416 fprintf(output, " -o display the capture file chronological status (True/False)\n");
1417 fprintf(output, " -S display start and end times as seconds\n");
1418 fprintf(output, "\n");
1419 fprintf(output, "Statistic infos:\n");
1420 fprintf(output, " -y display average data rate (in bytes/sec)\n");
1421 fprintf(output, " -i display average data rate (in bits/sec)\n");
1422 fprintf(output, " -z display average packet size (in bytes)\n");
1423 fprintf(output, " -x display average packet rate (in packets/sec)\n");
1424 fprintf(output, "\n");
1425 fprintf(output, "Metadata infos:\n");
1426 fprintf(output, " -n display number of resolved IPv4 and IPv6 addresses\n");
1427 fprintf(output, " -D display number of decryption secrets\n");
1428 fprintf(output, "\n");
1429 fprintf(output, "Output format:\n");
1430 fprintf(output, " -L generate long report (default)\n");
1431 fprintf(output, " -T generate table report\n");
1432 fprintf(output, " -M display machine-readable values in long reports\n");
1433 fprintf(output, "\n");
1434 fprintf(output, "Table report options:\n");
1435 fprintf(output, " -R generate header record (default)\n");
1436 fprintf(output, " -r do not generate header record\n");
1437 fprintf(output, "\n");
1438 fprintf(output, " -B separate infos with TAB character (default)\n");
1439 fprintf(output, " -m separate infos with comma (,) character\n");
1440 fprintf(output, " -b separate infos with SPACE character\n");
1441 fprintf(output, "\n");
1442 fprintf(output, " -N do not quote infos (default)\n");
1443 fprintf(output, " -q quote infos with single quotes (')\n");
1444 fprintf(output, " -Q quote infos with double quotes (\")\n");
1445 fprintf(output, "\n");
1446 fprintf(output, "Miscellaneous:\n");
1447 fprintf(output, " -h, --help display this help and exit\n");
1448 fprintf(output, " -v, --version display version info and exit\n");
1449 fprintf(output, " -C cancel processing if file open fails (default is to continue)\n");
1450 fprintf(output, " -A generate all infos (default)\n");
1451 fprintf(output, " -K disable displaying the capture comment\n");
1452 fprintf(output, " -P disable displaying individual packet comments\n");
1453 fprintf(output, "\n");
1454 fprintf(output, "Options are processed from left to right order with later options superseding\n");
1455 fprintf(output, "or adding to earlier options.\n");
1456 fprintf(output, "\n");
1457 fprintf(output, "If no options are given the default is to display all infos in long report\n");
1458 fprintf(output, "output format.\n");
1462 * Report an error in command-line arguments.
1464 static void
1465 capinfos_cmdarg_err(const char *msg_format, va_list ap)
1467 fprintf(stderr, "capinfos: ");
1468 vfprintf(stderr, msg_format, ap);
1469 fprintf(stderr, "\n");
1473 * Report additional information for an error in command-line arguments.
1475 static void
1476 capinfos_cmdarg_err_cont(const char *msg_format, va_list ap)
1478 vfprintf(stderr, msg_format, ap);
1479 fprintf(stderr, "\n");
1483 main(int argc, char *argv[])
1485 char *configuration_init_error;
1486 static const struct report_message_routines capinfos_report_routines = {
1487 failure_message,
1488 failure_message,
1489 open_failure_message,
1490 read_failure_message,
1491 write_failure_message,
1492 cfile_open_failure_message,
1493 cfile_dump_open_failure_message,
1494 cfile_read_failure_message,
1495 cfile_write_failure_message,
1496 cfile_close_failure_message
1498 gboolean need_separator = FALSE;
1499 int opt;
1500 int overall_error_status = EXIT_SUCCESS;
1501 static const struct ws_option long_options[] = {
1502 {"help", ws_no_argument, NULL, 'h'},
1503 {"version", ws_no_argument, NULL, 'v'},
1504 {0, 0, 0, 0 }
1507 int status = 0;
1510 * Set the C-language locale to the native environment and set the
1511 * code page to UTF-8 on Windows.
1513 #ifdef _WIN32
1514 setlocale(LC_ALL, ".UTF-8");
1515 #else
1516 setlocale(LC_ALL, "");
1517 #endif
1519 cmdarg_err_init(capinfos_cmdarg_err, capinfos_cmdarg_err_cont);
1521 /* Initialize log handler early so we can have proper logging during startup. */
1522 ws_log_init("capinfos", vcmdarg_err);
1524 /* Early logging command-line initialization. */
1525 ws_log_parse_args(&argc, argv, vcmdarg_err, WS_EXIT_INVALID_OPTION);
1527 ws_noisy("Finished log init and parsing command line log arguments");
1529 /* Get the decimal point. */
1530 decimal_point = g_strdup(localeconv()->decimal_point);
1532 /* Initialize the version information. */
1533 ws_init_version_info("Capinfos", NULL, NULL);
1535 #ifdef _WIN32
1536 create_app_running_mutex();
1537 #endif /* _WIN32 */
1540 * Get credential information for later use.
1542 init_process_policies();
1545 * Attempt to get the pathname of the directory containing the
1546 * executable file.
1548 configuration_init_error = configuration_init(argv[0], NULL);
1549 if (configuration_init_error != NULL) {
1550 fprintf(stderr,
1551 "capinfos: Can't get pathname of directory containing the capinfos program: %s.\n",
1552 configuration_init_error);
1553 g_free(configuration_init_error);
1556 init_report_message("capinfos", &capinfos_report_routines);
1558 wtap_init(TRUE);
1560 /* Process the options */
1561 while ((opt = ws_getopt_long(argc, argv, "abcdehiklmnopqrstuvxyzABCDEFHIKLMNPQRST", long_options, NULL)) !=-1) {
1563 switch (opt) {
1565 case 't':
1566 if (report_all_infos) disable_all_infos();
1567 cap_file_type = TRUE;
1568 break;
1570 case 'E':
1571 if (report_all_infos) disable_all_infos();
1572 cap_file_encap = TRUE;
1573 break;
1575 case 'l':
1576 if (report_all_infos) disable_all_infos();
1577 cap_snaplen = TRUE;
1578 break;
1580 case 'c':
1581 if (report_all_infos) disable_all_infos();
1582 cap_packet_count = TRUE;
1583 break;
1585 case 's':
1586 if (report_all_infos) disable_all_infos();
1587 cap_file_size = TRUE;
1588 break;
1590 case 'd':
1591 if (report_all_infos) disable_all_infos();
1592 cap_data_size = TRUE;
1593 break;
1595 case 'u':
1596 if (report_all_infos) disable_all_infos();
1597 cap_duration = TRUE;
1598 break;
1600 case 'a':
1601 if (report_all_infos) disable_all_infos();
1602 cap_start_time = TRUE;
1603 break;
1605 case 'e':
1606 if (report_all_infos) disable_all_infos();
1607 cap_end_time = TRUE;
1608 break;
1610 case 'S':
1611 time_as_secs = TRUE;
1612 break;
1614 case 'y':
1615 if (report_all_infos) disable_all_infos();
1616 cap_data_rate_byte = TRUE;
1617 break;
1619 case 'i':
1620 if (report_all_infos) disable_all_infos();
1621 cap_data_rate_bit = TRUE;
1622 break;
1624 case 'z':
1625 if (report_all_infos) disable_all_infos();
1626 cap_packet_size = TRUE;
1627 break;
1629 case 'x':
1630 if (report_all_infos) disable_all_infos();
1631 cap_packet_rate = TRUE;
1632 break;
1634 case 'H':
1635 if (report_all_infos) disable_all_infos();
1636 cap_file_hashes = TRUE;
1637 break;
1639 case 'o':
1640 if (report_all_infos) disable_all_infos();
1641 cap_order = TRUE;
1642 break;
1644 case 'k':
1645 if (report_all_infos) disable_all_infos();
1646 cap_comment = TRUE;
1647 break;
1649 case 'p':
1650 if (report_all_infos) disable_all_infos();
1651 pkt_comments = TRUE;
1652 break;
1654 case 'K':
1655 cap_comment = FALSE;
1656 break;
1658 case 'P':
1659 pkt_comments = FALSE;
1660 break;
1662 case 'F':
1663 if (report_all_infos) disable_all_infos();
1664 cap_file_more_info = TRUE;
1665 break;
1667 case 'I':
1668 if (report_all_infos) disable_all_infos();
1669 cap_file_idb = TRUE;
1670 break;
1672 case 'n':
1673 if (report_all_infos) disable_all_infos();
1674 cap_file_nrb = TRUE;
1675 break;
1677 case 'D':
1678 if (report_all_infos) disable_all_infos();
1679 cap_file_dsb = TRUE;
1680 break;
1682 case 'C':
1683 stop_after_failure = TRUE;
1684 break;
1686 case 'A':
1687 enable_all_infos();
1688 break;
1690 case 'L':
1691 long_report = TRUE;
1692 break;
1694 case 'T':
1695 long_report = FALSE;
1696 break;
1698 case 'M':
1699 machine_readable = TRUE;
1700 break;
1702 case 'R':
1703 table_report_header = TRUE;
1704 break;
1706 case 'r':
1707 table_report_header = FALSE;
1708 break;
1710 case 'N':
1711 quote_char = '\0';
1712 break;
1714 case 'q':
1715 quote_char = '\'';
1716 break;
1718 case 'Q':
1719 quote_char = '"';
1720 break;
1722 case 'B':
1723 field_separator = '\t';
1724 break;
1726 case 'm':
1727 field_separator = ',';
1728 break;
1730 case 'b':
1731 field_separator = ' ';
1732 break;
1734 case 'h':
1735 show_help_header("Print various information (infos) about capture files.");
1736 print_usage(stdout);
1737 goto exit;
1738 break;
1740 case 'v':
1741 show_version();
1742 goto exit;
1743 break;
1745 case '?': /* Bad flag - print usage message */
1746 print_usage(stderr);
1747 overall_error_status = WS_EXIT_INVALID_OPTION;
1748 goto exit;
1749 break;
1753 if ((argc - ws_optind) < 1) {
1754 print_usage(stderr);
1755 overall_error_status = WS_EXIT_INVALID_OPTION;
1756 goto exit;
1759 if (cap_file_hashes) {
1760 gcry_check_version(NULL);
1761 gcry_md_open(&hd, GCRY_MD_SHA256, 0);
1762 if (hd)
1763 gcry_md_enable(hd, GCRY_MD_SHA1);
1765 hash_buf = (char *)g_malloc(HASH_BUF_SIZE);
1768 overall_error_status = 0;
1770 for (opt = ws_optind; opt < argc; opt++) {
1772 status = process_cap_file(argv[opt], need_separator);
1773 if (status) {
1774 /* Something failed. It's been reported; remember that processing
1775 one file failed and, if -C was specified, stop. */
1776 overall_error_status = status;
1777 if (stop_after_failure)
1778 goto exit;
1780 if (status != 2) {
1781 /* Either it succeeded or it got a "short read" but printed
1782 information anyway. Note that we need a blank line before
1783 the next file's information, to separate it from the
1784 previous file. */
1785 need_separator = TRUE;
1789 exit:
1790 g_free(hash_buf);
1791 gcry_md_close(hd);
1792 wtap_cleanup();
1793 free_progdirs();
1794 return overall_error_status;