1 /* capinfos.c
2 * Reports capture file information including # of packets, duration, others
3 *
4 * Copyright 2004 Ian Schorr
5 *
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 */
12
13 /*
14 * 2009-09-19: jyoung
15 *
16 * New capinfos features
17 *
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.
23 *
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.
27 *
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.
33 *
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).
40 *
41
42 */
43
44
45 #include <config.h>
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <stdarg.h>
51 #include <locale.h>
52 #include <errno.h>
53
54 #include <wsutil/ws_getopt.h>
55
56 #include <glib.h>
57
58 #include <wiretap/wtap.h>
59
60 #include <ui/cmdarg_err.h>
61 #include <ui/exit_codes.h>
62 #include <wsutil/filesystem.h>
63 #include <wsutil/privileges.h>
64 #include <cli_main.h>
65 #include <ui/version_info.h>
66 #include <wiretap/wtap_opttypes.h>
67
68 #ifdef HAVE_PLUGINS
69 #include <wsutil/plugins.h>
70 #endif
71
72 #include <wsutil/report_message.h>
73 #include <wsutil/str_util.h>
74 #include <wsutil/file_util.h>
75 #include <wsutil/ws_assert.h>
76 #include <wsutil/wslog.h>
77
78 #include <wsutil/wsgcrypt.h>
79
80 #include "ui/failure_message.h"
81
82 /*
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.
90 */
91
92 static gboolean stop_after_failure = FALSE;
93
94 /*
95 * table report variables
96 */
97
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 = FALSE; /* Display machine-readable numbers */
103
104 /*
105 * capinfos has the ability to report on a number of
106 * various characteristics ("infos") for each input file.
107 *
108 * By default reporting of all info fields is enabled.
109 *
110 * Optionally the reporting of any specific info field
111 * or combination of info fields can be enabled with
112 * individual options.
113 */
114
115 static gboolean report_all_infos = TRUE; /* Report all infos */
116
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 */
127
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 = FALSE; /* Report time values as raw seconds */
133
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
140 static gboolean cap_file_hashes = TRUE; /* Calculate file hashes */
141
142 // Strongest to weakest
143 #define HASH_SIZE_SHA256 32
144 #define HASH_SIZE_RMD160 20
145 #define HASH_SIZE_SHA1 20
146
147 #define HASH_STR_SIZE (65) /* Max hash size * 2 + '\0' */
148 #define HASH_BUF_SIZE (1024 * 1024)
149
150
151 static gchar file_sha256[HASH_STR_SIZE];
152 static gchar file_rmd160[HASH_STR_SIZE];
153 static gchar file_sha1[HASH_STR_SIZE];
154
155 static char *hash_buf = NULL;
156 static gcry_md_hd_t hd = NULL;
157
158 static guint num_ipv4_addresses;
159 static guint num_ipv6_addresses;
160 static guint num_decryption_secrets;
161
162 /*
163 * If we have at least two packets with time stamps, and they're not in
164 * order - i.e., the later packet has a time stamp older than the earlier
165 * packet - the time stamps are known not to be in order.
166 *
167 * If every packet has a time stamp, and they're all in order, the time
168 * stamp is known to be in order.
169 *
170 * Otherwise, we have no idea.
171 */
172 typedef enum {
173 IN_ORDER,
174 NOT_IN_ORDER,
175 ORDER_UNKNOWN
176 } order_t;
177
178 typedef struct _capture_info {
179 const char *filename;
180 guint16 file_type;
181 wtap_compression_type compression_type;
182 int file_encap;
183 int file_tsprec;
184 wtap *wth;
185 gint64 filesize;
186 guint64 packet_bytes;
187 gboolean times_known;
188 nstime_t start_time;
189 int start_time_tsprec;
190 nstime_t stop_time;
191 int stop_time_tsprec;
192 guint32 packet_count;
193 gboolean snap_set; /* If set in capture file header */
194 guint32 snaplen; /* value from the capture file header */
195 guint32 snaplen_min_inferred; /* If caplen < len for 1 or more rcds */
196 guint32 snaplen_max_inferred; /* ... */
197 gboolean drops_known;
198 guint32 drop_count;
199
200 nstime_t duration;
201 int duration_tsprec;
202 double packet_rate;
203 double packet_size;
204 double data_rate; /* in bytes/s */
205 gboolean know_order;
206 order_t order;
207
208 int *encap_counts; /* array of per_packet encap counts; array has one entry per wtap_encap type */
209
210 guint num_interfaces; /* number of IDBs, and thus size of interface_packet_counts array */
211 GArray *interface_packet_counts; /* array of per_packet interface_id counts; one entry per file IDB */
212 guint32 pkt_interface_id_unknown; /* counts if packet interface_id didn't match a known one */
213 GArray *idb_info_strings; /* array of IDB info strings */
214 } capture_info;
215
216 static char *decimal_point;
217
218 static void
enable_all_infos(void)219 enable_all_infos(void)
220 {
221 report_all_infos = TRUE;
222
223 cap_file_type = TRUE;
224 cap_file_encap = TRUE;
225 cap_snaplen = TRUE;
226 cap_packet_count = TRUE;
227 cap_file_size = TRUE;
228 cap_comment = TRUE;
229 cap_file_more_info = TRUE;
230 cap_file_idb = TRUE;
231 cap_file_nrb = TRUE;
232 cap_file_dsb = TRUE;
233
234 cap_data_size = TRUE;
235 cap_duration = TRUE;
236 cap_start_time = TRUE;
237 cap_end_time = TRUE;
238 cap_order = TRUE;
239
240 cap_data_rate_byte = TRUE;
241 cap_data_rate_bit = TRUE;
242 cap_packet_size = TRUE;
243 cap_packet_rate = TRUE;
244
245 cap_file_hashes = TRUE;
246 }
247
248 static void
disable_all_infos(void)249 disable_all_infos(void)
250 {
251 report_all_infos = FALSE;
252
253 cap_file_type = FALSE;
254 cap_file_encap = FALSE;
255 cap_snaplen = FALSE;
256 cap_packet_count = FALSE;
257 cap_file_size = FALSE;
258 cap_comment = FALSE;
259 cap_file_more_info = FALSE;
260 cap_file_idb = FALSE;
261 cap_file_nrb = FALSE;
262 cap_file_dsb = FALSE;
263
264 cap_data_size = FALSE;
265 cap_duration = FALSE;
266 cap_start_time = FALSE;
267 cap_end_time = FALSE;
268 cap_order = FALSE;
269
270 cap_data_rate_byte = FALSE;
271 cap_data_rate_bit = FALSE;
272 cap_packet_size = FALSE;
273 cap_packet_rate = FALSE;
274
275 cap_file_hashes = FALSE;
276 }
277
278 static const gchar *
order_string(order_t order)279 order_string(order_t order)
280 {
281 switch (order) {
282
283 case IN_ORDER:
284 return "True";
285
286 case NOT_IN_ORDER:
287 return "False";
288
289 case ORDER_UNKNOWN:
290 return "Unknown";
291
292 default:
293 return "???"; /* "cannot happen" (the next step is "Profit!") */
294 }
295 }
296
297 static gchar *
absolute_time_string(nstime_t * timer,int tsprecision,capture_info * cf_info)298 absolute_time_string(nstime_t *timer, int tsprecision, capture_info *cf_info)
299 {
300 /*
301 * https://web.archive.org/web/20120513133703/http://www.idrbt.ac.in/publications/workingpapers/Working%20Paper%20No.%209.pdf
302 *
303 * says:
304 *
305 * A 64-bit Unix time would be safe for the indefinite future, as
306 * this variable would not overflow until 2**63 or
307 * 9,223,372,036,854,775,808 (over nine quintillion) seconds
308 * after the beginning of the Unix epoch - corresponding to
309 * GMT 15:30:08, Sunday, 4th December, 292,277,026,596.
310 *
311 * So, if we're displaying the time as YYYY-MM-DD HH:MM:SS.SSSSSSSSS,
312 * we'll have the buffer be large enouth for a date of the format
313 * 292277026596-MM-DD HH:MM:SS.SSSSSSSSS, which is the biggest value
314 * you'll get with a 64-bit time_t and a nanosecond-resolution
315 * fraction-of-a-second.
316 *
317 * That's 12+1+2+1+2+1+2+1+2+2+2+1+9+1, including the terminating
318 * \0, or 39.
319 *
320 * If we're displaying the time as epoch time, and the time is
321 * unsigned, 2^64-1 is 18446744073709551615, so the buffer has
322 * to be big enough for 18446744073709551615.999999999. That's
323 * 20+1+9+1, including the terminating '\0', or 31. If it's
324 * signed, 2^63 is 9223372036854775808, so the buffer has to
325 * be big enough for -9223372036854775808.999999999, which is
326 * again 20+1+9+1, or 31.
327 *
328 * So we go with 39.
329 */
330 static gchar time_string_buf[39];
331 struct tm *ti_tm;
332
333 if (cf_info->times_known && cf_info->packet_count > 0) {
334 if (time_as_secs) {
335 switch (tsprecision) {
336
337 case WTAP_TSPREC_SEC:
338 g_snprintf(time_string_buf, sizeof time_string_buf,
339 "%"G_GINT64_MODIFIER"d",
340 (gint64)timer->secs);
341 break;
342
343 case WTAP_TSPREC_DSEC:
344 g_snprintf(time_string_buf, sizeof time_string_buf,
345 "%"G_GINT64_MODIFIER"d%s%01d",
346 (gint64)timer->secs,
347 decimal_point,
348 timer->nsecs / 100000000);
349 break;
350
351 case WTAP_TSPREC_CSEC:
352 g_snprintf(time_string_buf, sizeof time_string_buf,
353 "%"G_GINT64_MODIFIER"d%s%02d",
354 (gint64)timer->secs,
355 decimal_point,
356 timer->nsecs / 10000000);
357 break;
358
359 case WTAP_TSPREC_MSEC:
360 g_snprintf(time_string_buf, sizeof time_string_buf,
361 "%"G_GINT64_MODIFIER"d%s%03d",
362 (gint64)timer->secs,
363 decimal_point,
364 timer->nsecs / 1000000);
365 break;
366
367 case WTAP_TSPREC_USEC:
368 g_snprintf(time_string_buf, sizeof time_string_buf,
369 "%"G_GINT64_MODIFIER"d%s%06d",
370 (gint64)timer->secs,
371 decimal_point,
372 timer->nsecs / 1000);
373 break;
374
375 case WTAP_TSPREC_NSEC:
376 g_snprintf(time_string_buf, sizeof time_string_buf,
377 "%"G_GINT64_MODIFIER"d%s%09d",
378 (gint64)timer->secs,
379 decimal_point,
380 timer->nsecs);
381 break;
382
383 default:
384 g_snprintf(time_string_buf, sizeof time_string_buf,
385 "Unknown precision %d",
386 tsprecision);
387 break;
388 }
389 return time_string_buf;
390 } else {
391 ti_tm = localtime(&timer->secs);
392 if (ti_tm == NULL) {
393 g_snprintf(time_string_buf, sizeof time_string_buf, "Not representable");
394 return time_string_buf;
395 }
396 switch (tsprecision) {
397
398 case WTAP_TSPREC_SEC:
399 g_snprintf(time_string_buf, sizeof time_string_buf,
400 "%04d-%02d-%02d %02d:%02d:%02d",
401 ti_tm->tm_year + 1900,
402 ti_tm->tm_mon + 1,
403 ti_tm->tm_mday,
404 ti_tm->tm_hour,
405 ti_tm->tm_min,
406 ti_tm->tm_sec);
407 break;
408
409 case WTAP_TSPREC_DSEC:
410 g_snprintf(time_string_buf, sizeof time_string_buf,
411 "%04d-%02d-%02d %02d:%02d:%02d%s%01d",
412 ti_tm->tm_year + 1900,
413 ti_tm->tm_mon + 1,
414 ti_tm->tm_mday,
415 ti_tm->tm_hour,
416 ti_tm->tm_min,
417 ti_tm->tm_sec,
418 decimal_point,
419 timer->nsecs / 100000000);
420 break;
421
422 case WTAP_TSPREC_CSEC:
423 g_snprintf(time_string_buf, sizeof time_string_buf,
424 "%04d-%02d-%02d %02d:%02d:%02d%s%02d",
425 ti_tm->tm_year + 1900,
426 ti_tm->tm_mon + 1,
427 ti_tm->tm_mday,
428 ti_tm->tm_hour,
429 ti_tm->tm_min,
430 ti_tm->tm_sec,
431 decimal_point,
432 timer->nsecs / 10000000);
433 break;
434
435 case WTAP_TSPREC_MSEC:
436 g_snprintf(time_string_buf, sizeof time_string_buf,
437 "%04d-%02d-%02d %02d:%02d:%02d%s%03d",
438 ti_tm->tm_year + 1900,
439 ti_tm->tm_mon + 1,
440 ti_tm->tm_mday,
441 ti_tm->tm_hour,
442 ti_tm->tm_min,
443 ti_tm->tm_sec,
444 decimal_point,
445 timer->nsecs / 1000000);
446 break;
447
448 case WTAP_TSPREC_USEC:
449 g_snprintf(time_string_buf, sizeof time_string_buf,
450 "%04d-%02d-%02d %02d:%02d:%02d%s%06d",
451 ti_tm->tm_year + 1900,
452 ti_tm->tm_mon + 1,
453 ti_tm->tm_mday,
454 ti_tm->tm_hour,
455 ti_tm->tm_min,
456 ti_tm->tm_sec,
457 decimal_point,
458 timer->nsecs / 1000);
459 break;
460
461 case WTAP_TSPREC_NSEC:
462 g_snprintf(time_string_buf, sizeof time_string_buf,
463 "%04d-%02d-%02d %02d:%02d:%02d%s%09d",
464 ti_tm->tm_year + 1900,
465 ti_tm->tm_mon + 1,
466 ti_tm->tm_mday,
467 ti_tm->tm_hour,
468 ti_tm->tm_min,
469 ti_tm->tm_sec,
470 decimal_point,
471 timer->nsecs);
472 break;
473
474 default:
475 g_snprintf(time_string_buf, sizeof time_string_buf,
476 "Unknown precision %d",
477 tsprecision);
478 break;
479 }
480 return time_string_buf;
481 }
482 }
483
484 g_snprintf(time_string_buf, sizeof time_string_buf, "n/a");
485 return time_string_buf;
486 }
487
488 static gchar *
relative_time_string(nstime_t * timer,int tsprecision,capture_info * cf_info,gboolean want_seconds)489 relative_time_string(nstime_t *timer, int tsprecision, capture_info *cf_info, gboolean want_seconds)
490 {
491 const gchar *second = want_seconds ? " second" : "";
492 const gchar *plural = want_seconds ? "s" : "";
493 /*
494 * If we're displaying the time as epoch time, and the time is
495 * unsigned, 2^64-1 is 18446744073709551615, so the buffer has
496 * to be big enough for "18446744073709551615.999999999 seconds".
497 * That's 20+1+9+1+7+1, including the terminating '\0', or 39.
498 * If it'ssigned, 2^63 is 9223372036854775808, so the buffer has to
499 * be big enough for "-9223372036854775808.999999999 seconds",
500 * which is again 20+1+9+1+7+1, or 39.
501 */
502 static gchar time_string_buf[39];
503
504 if (cf_info->times_known && cf_info->packet_count > 0) {
505 switch (tsprecision) {
506
507 case WTAP_TSPREC_SEC:
508 g_snprintf(time_string_buf, sizeof time_string_buf,
509 "%"G_GINT64_MODIFIER"d%s%s",
510 (gint64)timer->secs,
511 second,
512 timer->secs == 1 ? "" : plural);
513 break;
514
515 case WTAP_TSPREC_DSEC:
516 g_snprintf(time_string_buf, sizeof time_string_buf,
517 "%"G_GINT64_MODIFIER"d%s%01d%s%s",
518 (gint64)timer->secs,
519 decimal_point,
520 timer->nsecs / 100000000,
521 second,
522 (timer->secs == 1 && timer->nsecs == 0) ? "" : plural);
523 break;
524
525 case WTAP_TSPREC_CSEC:
526 g_snprintf(time_string_buf, sizeof time_string_buf,
527 "%"G_GINT64_MODIFIER"d%s%02d%s%s",
528 (gint64)timer->secs,
529 decimal_point,
530 timer->nsecs / 10000000,
531 second,
532 (timer->secs == 1 && timer->nsecs == 0) ? "" : plural);
533 break;
534
535 case WTAP_TSPREC_MSEC:
536 g_snprintf(time_string_buf, sizeof time_string_buf,
537 "%"G_GINT64_MODIFIER"d%s%03d%s%s",
538 (gint64)timer->secs,
539 decimal_point,
540 timer->nsecs / 1000000,
541 second,
542 (timer->secs == 1 && timer->nsecs == 0) ? "" : plural);
543 break;
544
545 case WTAP_TSPREC_USEC:
546 g_snprintf(time_string_buf, sizeof time_string_buf,
547 "%"G_GINT64_MODIFIER"d%s%06d%s%s",
548 (gint64)timer->secs,
549 decimal_point,
550 timer->nsecs / 1000,
551 second,
552 (timer->secs == 1 && timer->nsecs == 0) ? "" : plural);
553 break;
554
555 case WTAP_TSPREC_NSEC:
556 g_snprintf(time_string_buf, sizeof time_string_buf,
557 "%"G_GINT64_MODIFIER"d%s%09d%s%s",
558 (gint64)timer->secs,
559 decimal_point,
560 timer->nsecs,
561 second,
562 (timer->secs == 1 && timer->nsecs == 0) ? "" : plural);
563 break;
564
565 default:
566 g_snprintf(time_string_buf, sizeof time_string_buf,
567 "Unknown precision %d",
568 tsprecision);
569 break;
570 }
571 return time_string_buf;
572 }
573
574 g_snprintf(time_string_buf, sizeof time_string_buf, "n/a");
575 return time_string_buf;
576 }
577
print_value(const gchar * text_p1,gint width,const gchar * text_p2,double value)578 static void print_value(const gchar *text_p1, gint width, const gchar *text_p2, double value) {
579 if (value > 0.0)
580 printf("%s%.*f%s\n", text_p1, width, value, text_p2);
581 else
582 printf("%sn/a\n", text_p1);
583 }
584
585 /* multi-line comments would conflict with the formatting that capinfos uses
586 we replace linefeeds with spaces */
587 static void
string_replace_newlines(gchar * str)588 string_replace_newlines(gchar *str)
589 {
590 gchar *p;
591
592 if (str) {
593 p = str;
594 while (*p != '\0') {
595 if (*p == '\n')
596 *p = ' ';
597 if (*p == '\r')
598 *p = ' ';
599 p++;
600 }
601 }
602 }
603
604 static void
show_option_string(const char * prefix,const char * option_str)605 show_option_string(const char *prefix, const char *option_str)
606 {
607 char *str;
608
609 if (option_str != NULL && option_str[0] != '\0') {
610 str = g_strdup(option_str);
611 string_replace_newlines(str);
612 printf("%s%s\n", prefix, str);
613 g_free(str);
614 }
615 }
616
617 static void
print_stats(const gchar * filename,capture_info * cf_info)618 print_stats(const gchar *filename, capture_info *cf_info)
619 {
620 const gchar *file_type_string, *file_encap_string;
621 gchar *size_string;
622
623 /* Build printable strings for various stats */
624 if (machine_readable) {
625 file_type_string = wtap_file_type_subtype_name(cf_info->file_type);
626 file_encap_string = wtap_encap_name(cf_info->file_encap);
627 }
628 else {
629 file_type_string = wtap_file_type_subtype_description(cf_info->file_type);
630 file_encap_string = wtap_encap_description(cf_info->file_encap);
631 }
632
633 if (filename) printf ("File name: %s\n", filename);
634 if (cap_file_type) {
635 const char *compression_type_description;
636 compression_type_description = wtap_compression_type_description(cf_info->compression_type);
637 if (compression_type_description == NULL)
638 printf ("File type: %s\n",
639 file_type_string);
640 else
641 printf ("File type: %s (%s)\n",
642 file_type_string, compression_type_description);
643 }
644 if (cap_file_encap) {
645 printf ("File encapsulation: %s\n", file_encap_string);
646 if (cf_info->file_encap == WTAP_ENCAP_PER_PACKET) {
647 int i;
648 printf ("Encapsulation in use by packets (# of pkts):\n");
649 for (i=0; i<WTAP_NUM_ENCAP_TYPES; i++) {
650 if (cf_info->encap_counts[i] > 0)
651 printf(" %s (%d)\n",
652 wtap_encap_description(i), cf_info->encap_counts[i]);
653 }
654 }
655 }
656 if (cap_file_more_info) {
657 printf ("File timestamp precision: %s (%d)\n",
658 wtap_tsprec_string(cf_info->file_tsprec), cf_info->file_tsprec);
659 }
660
661 if (cap_snaplen && cf_info->snap_set)
662 printf ("Packet size limit: file hdr: %u bytes\n", cf_info->snaplen);
663 else if (cap_snaplen && !cf_info->snap_set)
664 printf ("Packet size limit: file hdr: (not set)\n");
665 if (cf_info->snaplen_max_inferred > 0) {
666 if (cf_info->snaplen_min_inferred == cf_info->snaplen_max_inferred)
667 printf ("Packet size limit: inferred: %u bytes\n", cf_info->snaplen_min_inferred);
668 else
669 printf ("Packet size limit: inferred: %u bytes - %u bytes (range)\n",
670 cf_info->snaplen_min_inferred, cf_info->snaplen_max_inferred);
671 }
672 if (cap_packet_count) {
673 printf ("Number of packets: ");
674 if (machine_readable) {
675 printf ("%u\n", cf_info->packet_count);
676 } else {
677 size_string = format_size(cf_info->packet_count, format_size_unit_none);
678 printf ("%s\n", size_string);
679 g_free(size_string);
680 }
681 }
682 if (cap_file_size) {
683 printf ("File size: ");
684 if (machine_readable) {
685 printf ("%" G_GINT64_MODIFIER "d bytes\n", cf_info->filesize);
686 } else {
687 size_string = format_size(cf_info->filesize, format_size_unit_bytes);
688 printf ("%s\n", size_string);
689 g_free(size_string);
690 }
691 }
692 if (cap_data_size) {
693 printf ("Data size: ");
694 if (machine_readable) {
695 printf ("%" G_GINT64_MODIFIER "u bytes\n", cf_info->packet_bytes);
696 } else {
697 size_string = format_size(cf_info->packet_bytes, format_size_unit_bytes);
698 printf ("%s\n", size_string);
699 g_free(size_string);
700 }
701 }
702 if (cf_info->times_known) {
703 if (cap_duration) /* XXX - shorten to hh:mm:ss */
704 printf("Capture duration: %s\n", relative_time_string(&cf_info->duration, cf_info->duration_tsprec, cf_info, TRUE));
705 if (cap_start_time)
706 printf("First packet time: %s\n", absolute_time_string(&cf_info->start_time, cf_info->start_time_tsprec, cf_info));
707 if (cap_end_time)
708 printf("Last packet time: %s\n", absolute_time_string(&cf_info->stop_time, cf_info->stop_time_tsprec, cf_info));
709 if (cap_data_rate_byte) {
710 printf("Data byte rate: ");
711 if (machine_readable) {
712 print_value("", 2, " bytes/sec", cf_info->data_rate);
713 } else {
714 size_string = format_size((gint64)cf_info->data_rate, format_size_unit_bytes_s);
715 printf ("%s\n", size_string);
716 g_free(size_string);
717 }
718 }
719 if (cap_data_rate_bit) {
720 printf("Data bit rate: ");
721 if (machine_readable) {
722 print_value("", 2, " bits/sec", cf_info->data_rate*8);
723 } else {
724 size_string = format_size((gint64)(cf_info->data_rate*8), format_size_unit_bits_s);
725 printf ("%s\n", size_string);
726 g_free(size_string);
727 }
728 }
729 }
730 if (cap_packet_size) printf("Average packet size: %.2f bytes\n", cf_info->packet_size);
731 if (cf_info->times_known) {
732 if (cap_packet_rate) {
733 printf("Average packet rate: ");
734 if (machine_readable) {
735 print_value("", 2, " packets/sec", cf_info->packet_rate);
736 } else {
737 size_string = format_size((gint64)cf_info->packet_rate, format_size_unit_packets_s);
738 printf ("%s\n", size_string);
739 g_free(size_string);
740 }
741 }
742 }
743 if (cap_file_hashes) {
744 printf ("SHA256: %s\n", file_sha256);
745 printf ("RIPEMD160: %s\n", file_rmd160);
746 printf ("SHA1: %s\n", file_sha1);
747 }
748 if (cap_order) printf ("Strict time order: %s\n", order_string(cf_info->order));
749
750 gboolean has_multiple_sections = (wtap_file_get_num_shbs(cf_info->wth) > 1);
751
752 for (guint section_number = 0;
753 section_number < wtap_file_get_num_shbs(cf_info->wth);
754 section_number++) {
755 wtap_block_t shb;
756
757 // If we have more than one section, add headers for each section.
758 if (has_multiple_sections)
759 printf("Section %u:\n\n", section_number);
760
761 shb = wtap_file_get_shb(cf_info->wth, section_number);
762 if (shb != NULL) {
763 if (cap_file_more_info) {
764 char *str;
765
766 if (wtap_block_get_string_option_value(shb, OPT_SHB_HARDWARE, &str) == WTAP_OPTTYPE_SUCCESS)
767 show_option_string("Capture hardware: ", str);
768 if (wtap_block_get_string_option_value(shb, OPT_SHB_OS, &str) == WTAP_OPTTYPE_SUCCESS)
769 show_option_string("Capture oper-sys: ", str);
770 if (wtap_block_get_string_option_value(shb, OPT_SHB_USERAPPL, &str) == WTAP_OPTTYPE_SUCCESS)
771 show_option_string("Capture application: ", str);
772 }
773 if (cap_comment) {
774 unsigned int i;
775 char *str;
776
777 for (i = 0; wtap_block_get_nth_string_option_value(shb, OPT_COMMENT, i, &str) == WTAP_OPTTYPE_SUCCESS; i++) {
778 show_option_string("Capture comment: ", str);
779 }
780 }
781
782 if (cap_file_idb && cf_info->num_interfaces != 0) {
783 guint i;
784 ws_assert(cf_info->num_interfaces == cf_info->idb_info_strings->len);
785 printf ("Number of interfaces in file: %u\n", cf_info->num_interfaces);
786 for (i = 0; i < cf_info->idb_info_strings->len; i++) {
787 gchar *s = g_array_index(cf_info->idb_info_strings, gchar*, i);
788 guint32 packet_count = 0;
789 if (i < cf_info->interface_packet_counts->len)
790 packet_count = g_array_index(cf_info->interface_packet_counts, guint32, i);
791 printf ("Interface #%u info:\n", i);
792 printf ("%s", s);
793 printf (" Number of packets = %u\n", packet_count);
794 }
795 }
796 }
797
798 if (cap_file_nrb) {
799 if (num_ipv4_addresses != 0)
800 printf ("Number of resolved IPv4 addresses in file: %u\n", num_ipv4_addresses);
801 if (num_ipv6_addresses != 0)
802 printf ("Number of resolved IPv6 addresses in file: %u\n", num_ipv6_addresses);
803 }
804 if (cap_file_dsb) {
805 if (num_decryption_secrets != 0)
806 printf ("Number of decryption secrets in file: %u\n", num_decryption_secrets);
807 }
808 }
809 }
810
811 static void
putsep(void)812 putsep(void)
813 {
814 if (field_separator) putchar(field_separator);
815 }
816
817 static void
putquote(void)818 putquote(void)
819 {
820 if (quote_char) putchar(quote_char);
821 }
822
823 static void
print_stats_table_header_label(const gchar * label)824 print_stats_table_header_label(const gchar *label)
825 {
826 putsep();
827 putquote();
828 printf("%s", label);
829 putquote();
830 }
831
832 static void
print_stats_table_header(void)833 print_stats_table_header(void)
834 {
835 putquote();
836 printf("File name");
837 putquote();
838
839 if (cap_file_type) print_stats_table_header_label("File type");
840 if (cap_file_encap) print_stats_table_header_label("File encapsulation");
841 if (cap_file_more_info) print_stats_table_header_label("File time precision");
842 if (cap_snaplen) {
843 print_stats_table_header_label("Packet size limit");
844 print_stats_table_header_label("Packet size limit min (inferred)");
845 print_stats_table_header_label("Packet size limit max (inferred)");
846 }
847 if (cap_packet_count) print_stats_table_header_label("Number of packets");
848 if (cap_file_size) print_stats_table_header_label("File size (bytes)");
849 if (cap_data_size) print_stats_table_header_label("Data size (bytes)");
850 if (cap_duration) print_stats_table_header_label("Capture duration (seconds)");
851 if (cap_start_time) print_stats_table_header_label("Start time");
852 if (cap_end_time) print_stats_table_header_label("End time");
853 if (cap_data_rate_byte) print_stats_table_header_label("Data byte rate (bytes/sec)");
854 if (cap_data_rate_bit) print_stats_table_header_label("Data bit rate (bits/sec)");
855 if (cap_packet_size) print_stats_table_header_label("Average packet size (bytes)");
856 if (cap_packet_rate) print_stats_table_header_label("Average packet rate (packets/sec)");
857 if (cap_file_hashes) {
858 print_stats_table_header_label("SHA256");
859 print_stats_table_header_label("RIPEMD160");
860 print_stats_table_header_label("SHA1");
861 }
862 if (cap_order) print_stats_table_header_label("Strict time order");
863 if (cap_file_more_info) {
864 print_stats_table_header_label("Capture hardware");
865 print_stats_table_header_label("Capture oper-sys");
866 print_stats_table_header_label("Capture application");
867 }
868 if (cap_comment) print_stats_table_header_label("Capture comment");
869
870 printf("\n");
871 }
872
873 static void
print_stats_table(const gchar * filename,capture_info * cf_info)874 print_stats_table(const gchar *filename, capture_info *cf_info)
875 {
876 const gchar *file_type_string, *file_encap_string;
877
878 /* Build printable strings for various stats */
879 file_type_string = wtap_file_type_subtype_name(cf_info->file_type);
880 file_encap_string = wtap_encap_name(cf_info->file_encap);
881
882 if (filename) {
883 putquote();
884 printf("%s", filename);
885 putquote();
886 }
887
888 if (cap_file_type) {
889 putsep();
890 putquote();
891 printf("%s", file_type_string);
892 putquote();
893 }
894
895 /* ToDo: If WTAP_ENCAP_PER_PACKET, show the list of encapsulations encountered;
896 * Output a line for each different encap with all fields repeated except
897 * the encapsulation field which has "Per Packet: ..." for each
898 * encapsulation type seen ?
899 */
900 if (cap_file_encap) {
901 putsep();
902 putquote();
903 printf("%s", file_encap_string);
904 putquote();
905 }
906
907 if (cap_file_more_info) {
908 putsep();
909 putquote();
910 printf("%s", wtap_tsprec_string(cf_info->file_tsprec));
911 putquote();
912 }
913
914 if (cap_snaplen) {
915 putsep();
916 putquote();
917 if (cf_info->snap_set)
918 printf("%u", cf_info->snaplen);
919 else
920 printf("(not set)");
921 putquote();
922 if (cf_info->snaplen_max_inferred > 0) {
923 putsep();
924 putquote();
925 printf("%u", cf_info->snaplen_min_inferred);
926 putquote();
927 putsep();
928 putquote();
929 printf("%u", cf_info->snaplen_max_inferred);
930 putquote();
931 }
932 else {
933 putsep();
934 putquote();
935 printf("n/a");
936 putquote();
937 putsep();
938 putquote();
939 printf("n/a");
940 putquote();
941 }
942 }
943
944 if (cap_packet_count) {
945 putsep();
946 putquote();
947 printf("%u", cf_info->packet_count);
948 putquote();
949 }
950
951 if (cap_file_size) {
952 putsep();
953 putquote();
954 printf("%" G_GINT64_MODIFIER "d", cf_info->filesize);
955 putquote();
956 }
957
958 if (cap_data_size) {
959 putsep();
960 putquote();
961 printf("%" G_GINT64_MODIFIER "u", cf_info->packet_bytes);
962 putquote();
963 }
964
965 if (cap_duration) {
966 putsep();
967 putquote();
968 printf("%s", relative_time_string(&cf_info->duration, cf_info->duration_tsprec, cf_info, FALSE));
969 putquote();
970 }
971
972 if (cap_start_time) {
973 putsep();
974 putquote();
975 printf("%s", absolute_time_string(&cf_info->start_time, cf_info->start_time_tsprec, cf_info));
976 putquote();
977 }
978
979 if (cap_end_time) {
980 putsep();
981 putquote();
982 printf("%s", absolute_time_string(&cf_info->stop_time, cf_info->stop_time_tsprec, cf_info));
983 putquote();
984 }
985
986 if (cap_data_rate_byte) {
987 putsep();
988 putquote();
989 if (cf_info->times_known)
990 printf("%.2f", cf_info->data_rate);
991 else
992 printf("n/a");
993 putquote();
994 }
995
996 if (cap_data_rate_bit) {
997 putsep();
998 putquote();
999 if (cf_info->times_known)
1000 printf("%.2f", cf_info->data_rate*8);
1001 else
1002 printf("n/a");
1003 putquote();
1004 }
1005
1006 if (cap_packet_size) {
1007 putsep();
1008 putquote();
1009 printf("%.2f", cf_info->packet_size);
1010 putquote();
1011 }
1012
1013 if (cap_packet_rate) {
1014 putsep();
1015 putquote();
1016 if (cf_info->times_known)
1017 printf("%.2f", cf_info->packet_rate);
1018 else
1019 printf("n/a");
1020 putquote();
1021 }
1022
1023 if (cap_file_hashes) {
1024 putsep();
1025 putquote();
1026 printf("%s", file_sha256);
1027 putquote();
1028
1029 putsep();
1030 putquote();
1031 printf("%s", file_rmd160);
1032 putquote();
1033
1034 putsep();
1035 putquote();
1036 printf("%s", file_sha1);
1037 putquote();
1038 }
1039
1040 if (cap_order) {
1041 putsep();
1042 putquote();
1043 printf("%s", order_string(cf_info->order));
1044 putquote();
1045 }
1046
1047 for (guint section_number = 0;
1048 section_number < wtap_file_get_num_shbs(cf_info->wth);
1049 section_number++) {
1050 wtap_block_t shb;
1051
1052 shb = wtap_file_get_shb(cf_info->wth, section_number);
1053 if (cap_file_more_info) {
1054 char *str;
1055
1056 putsep();
1057 putquote();
1058 if (wtap_block_get_string_option_value(shb, OPT_SHB_HARDWARE, &str) == WTAP_OPTTYPE_SUCCESS) {
1059 printf("%s", str);
1060 }
1061 putquote();
1062
1063 putsep();
1064 putquote();
1065 if (wtap_block_get_string_option_value(shb, OPT_SHB_OS, &str) == WTAP_OPTTYPE_SUCCESS) {
1066 printf("%s", str);
1067 }
1068 putquote();
1069
1070 putsep();
1071 putquote();
1072 if (wtap_block_get_string_option_value(shb, OPT_SHB_USERAPPL, &str) == WTAP_OPTTYPE_SUCCESS) {
1073 printf("%s", str);
1074 }
1075 putquote();
1076 }
1077
1078 /*
1079 * One might argue that the following is silly to put into a table format,
1080 * but oh well note that there may be *more than one* of each of these types
1081 * of options. To mitigate some of the potential silliness the if(cap_comment)
1082 * block is moved AFTER the if(cap_file_more_info) block. This will make any
1083 * comments the last item(s) in each row. We now have a new -K option to
1084 * disable cap_comment to more easily manage the potential silliness.
1085 * Potential silliness includes multiple comments (therefore resulting in
1086 * more than one additional column and/or comments with embeded newlines
1087 * and/or possible delimiters).
1088 */
1089 if (cap_comment) {
1090 unsigned int i;
1091 char *opt_comment;
1092 gboolean have_cap = FALSE;
1093
1094 for (i = 0; wtap_block_get_nth_string_option_value(shb, OPT_COMMENT, i, &opt_comment) == WTAP_OPTTYPE_SUCCESS; i++) {
1095 have_cap = TRUE;
1096 putsep();
1097 putquote();
1098 printf("%s", opt_comment);
1099 putquote();
1100 }
1101 if(!have_cap) {
1102 /* Maintain column alignment when we have no OPT_COMMENT */
1103 putsep();
1104 putquote();
1105 putquote();
1106 }
1107 }
1108
1109 }
1110
1111 printf("\n");
1112 }
1113
1114 static void
cleanup_capture_info(capture_info * cf_info)1115 cleanup_capture_info(capture_info *cf_info)
1116 {
1117 guint i;
1118 ws_assert(cf_info != NULL);
1119
1120 g_free(cf_info->encap_counts);
1121 cf_info->encap_counts = NULL;
1122
1123 g_array_free(cf_info->interface_packet_counts, TRUE);
1124 cf_info->interface_packet_counts = NULL;
1125
1126 if (cf_info->idb_info_strings) {
1127 for (i = 0; i < cf_info->idb_info_strings->len; i++) {
1128 gchar *s = g_array_index(cf_info->idb_info_strings, gchar*, i);
1129 g_free(s);
1130 }
1131 g_array_free(cf_info->idb_info_strings, TRUE);
1132 }
1133 cf_info->idb_info_strings = NULL;
1134 }
1135
1136 static void
count_ipv4_address(const guint addr _U_,const gchar * name _U_)1137 count_ipv4_address(const guint addr _U_, const gchar *name _U_)
1138 {
1139 num_ipv4_addresses++;
1140 }
1141
1142 static void
count_ipv6_address(const void * addrp _U_,const gchar * name _U_)1143 count_ipv6_address(const void *addrp _U_, const gchar *name _U_)
1144 {
1145 num_ipv6_addresses++;
1146 }
1147
1148 static void
count_decryption_secret(guint32 secrets_type _U_,const void * secrets _U_,guint size _U_)1149 count_decryption_secret(guint32 secrets_type _U_, const void *secrets _U_, guint size _U_)
1150 {
1151 /* XXX - count them based on the secrets type (which is an opaque code,
1152 not a small integer)? */
1153 num_decryption_secrets++;
1154 }
1155
1156 static void
hash_to_str(const unsigned char * hash,size_t length,char * str)1157 hash_to_str(const unsigned char *hash, size_t length, char *str) {
1158 int i;
1159
1160 for (i = 0; i < (int) length; i++) {
1161 g_snprintf(str+(i*2), 3, "%02x", hash[i]);
1162 }
1163 }
1164
1165 static void
calculate_hashes(const char * filename)1166 calculate_hashes(const char *filename)
1167 {
1168 FILE *fh;
1169 size_t hash_bytes;
1170
1171 (void) g_strlcpy(file_sha256, "<unknown>", HASH_STR_SIZE);
1172 (void) g_strlcpy(file_rmd160, "<unknown>", HASH_STR_SIZE);
1173 (void) g_strlcpy(file_sha1, "<unknown>", HASH_STR_SIZE);
1174
1175 if (cap_file_hashes) {
1176 fh = ws_fopen(filename, "rb");
1177 if (fh && hd) {
1178 while((hash_bytes = fread(hash_buf, 1, HASH_BUF_SIZE, fh)) > 0) {
1179 gcry_md_write(hd, hash_buf, hash_bytes);
1180 }
1181 gcry_md_final(hd);
1182 hash_to_str(gcry_md_read(hd, GCRY_MD_SHA256), HASH_SIZE_SHA256, file_sha256);
1183 hash_to_str(gcry_md_read(hd, GCRY_MD_RMD160), HASH_SIZE_RMD160, file_rmd160);
1184 hash_to_str(gcry_md_read(hd, GCRY_MD_SHA1), HASH_SIZE_SHA1, file_sha1);
1185 }
1186 if (fh) fclose(fh);
1187 if (hd) gcry_md_reset(hd);
1188 }
1189 }
1190
1191 static int
process_cap_file(const char * filename,gboolean need_separator)1192 process_cap_file(const char *filename, gboolean need_separator)
1193 {
1194 int status = 0;
1195 int err;
1196 gchar *err_info;
1197 gint64 size;
1198 gint64 data_offset;
1199
1200 guint32 packet = 0;
1201 gint64 bytes = 0;
1202 guint32 snaplen_min_inferred = 0xffffffff;
1203 guint32 snaplen_max_inferred = 0;
1204 wtap_rec rec;
1205 Buffer buf;
1206 capture_info cf_info;
1207 gboolean have_times = TRUE;
1208 nstime_t start_time;
1209 int start_time_tsprec;
1210 nstime_t stop_time;
1211 int stop_time_tsprec;
1212 nstime_t cur_time;
1213 nstime_t prev_time;
1214 gboolean know_order = FALSE;
1215 order_t order = IN_ORDER;
1216 guint i;
1217 wtapng_iface_descriptions_t *idb_info;
1218
1219 cf_info.wth = wtap_open_offline(filename, WTAP_TYPE_AUTO, &err, &err_info, FALSE);
1220 if (!cf_info.wth) {
1221 cfile_open_failure_message(filename, err, err_info);
1222 return 2;
1223 }
1224
1225 /*
1226 * Calculate the checksums. Do this after wtap_open_offline, so we don't
1227 * bother calculating them for files that are not known capture types
1228 * where we wouldn't print them anyway.
1229 */
1230 calculate_hashes(filename);
1231
1232 if (need_separator && long_report) {
1233 printf("\n");
1234 }
1235
1236 nstime_set_zero(&start_time);
1237 start_time_tsprec = WTAP_TSPREC_UNKNOWN;
1238 nstime_set_zero(&stop_time);
1239 stop_time_tsprec = WTAP_TSPREC_UNKNOWN;
1240 nstime_set_zero(&cur_time);
1241 nstime_set_zero(&prev_time);
1242
1243 cf_info.encap_counts = g_new0(int,WTAP_NUM_ENCAP_TYPES);
1244
1245 idb_info = wtap_file_get_idb_info(cf_info.wth);
1246
1247 ws_assert(idb_info->interface_data != NULL);
1248
1249 cf_info.num_interfaces = idb_info->interface_data->len;
1250 cf_info.interface_packet_counts = g_array_sized_new(FALSE, TRUE, sizeof(guint32), cf_info.num_interfaces);
1251 g_array_set_size(cf_info.interface_packet_counts, cf_info.num_interfaces);
1252 cf_info.pkt_interface_id_unknown = 0;
1253
1254 g_free(idb_info);
1255 idb_info = NULL;
1256
1257 /* Register callbacks for new name<->address maps from the file and
1258 decryption secrets from the file. */
1259 wtap_set_cb_new_ipv4(cf_info.wth, count_ipv4_address);
1260 wtap_set_cb_new_ipv6(cf_info.wth, count_ipv6_address);
1261 wtap_set_cb_new_secrets(cf_info.wth, count_decryption_secret);
1262
1263 /* Zero out the counters for the callbacks. */
1264 num_ipv4_addresses = 0;
1265 num_ipv6_addresses = 0;
1266 num_decryption_secrets = 0;
1267
1268 /* Tally up data that we need to parse through the file to find */
1269 wtap_rec_init(&rec);
1270 ws_buffer_init(&buf, 1514);
1271 while (wtap_read(cf_info.wth, &rec, &buf, &err, &err_info, &data_offset)) {
1272 if (rec.presence_flags & WTAP_HAS_TS) {
1273 prev_time = cur_time;
1274 cur_time = rec.ts;
1275 if (packet == 0) {
1276 start_time = rec.ts;
1277 start_time_tsprec = rec.tsprec;
1278 stop_time = rec.ts;
1279 stop_time_tsprec = rec.tsprec;
1280 prev_time = rec.ts;
1281 }
1282 if (nstime_cmp(&cur_time, &prev_time) < 0) {
1283 order = NOT_IN_ORDER;
1284 }
1285 if (nstime_cmp(&cur_time, &start_time) < 0) {
1286 start_time = cur_time;
1287 start_time_tsprec = rec.tsprec;
1288 }
1289 if (nstime_cmp(&cur_time, &stop_time) > 0) {
1290 stop_time = cur_time;
1291 stop_time_tsprec = rec.tsprec;
1292 }
1293 } else {
1294 have_times = FALSE; /* at least one packet has no time stamp */
1295 if (order != NOT_IN_ORDER)
1296 order = ORDER_UNKNOWN;
1297 }
1298
1299 if (rec.rec_type == REC_TYPE_PACKET) {
1300 bytes += rec.rec_header.packet_header.len;
1301 packet++;
1302
1303 /* If caplen < len for a rcd, then presumably */
1304 /* 'Limit packet capture length' was done for this rcd. */
1305 /* Keep track as to the min/max actual snapshot lengths */
1306 /* seen for this file. */
1307 if (rec.rec_header.packet_header.caplen < rec.rec_header.packet_header.len) {
1308 if (rec.rec_header.packet_header.caplen < snaplen_min_inferred)
1309 snaplen_min_inferred = rec.rec_header.packet_header.caplen;
1310 if (rec.rec_header.packet_header.caplen > snaplen_max_inferred)
1311 snaplen_max_inferred = rec.rec_header.packet_header.caplen;
1312 }
1313
1314 if ((rec.rec_header.packet_header.pkt_encap > 0) &&
1315 (rec.rec_header.packet_header.pkt_encap < WTAP_NUM_ENCAP_TYPES)) {
1316 cf_info.encap_counts[rec.rec_header.packet_header.pkt_encap] += 1;
1317 } else {
1318 fprintf(stderr, "capinfos: Unknown packet encapsulation %d in frame %u of file \"%s\"\n",
1319 rec.rec_header.packet_header.pkt_encap, packet, filename);
1320 }
1321
1322 /* Packet interface_id info */
1323 if (rec.presence_flags & WTAP_HAS_INTERFACE_ID) {
1324 /* cf_info.num_interfaces is size, not index, so it's one more than max index */
1325 if (rec.rec_header.packet_header.interface_id >= cf_info.num_interfaces) {
1326 /*
1327 * OK, re-fetch the number of interfaces, as there might have
1328 * been an interface that was in the middle of packets, and
1329 * grow the array to be big enough for the new number of
1330 * interfaces.
1331 */
1332 idb_info = wtap_file_get_idb_info(cf_info.wth);
1333
1334 cf_info.num_interfaces = idb_info->interface_data->len;
1335 g_array_set_size(cf_info.interface_packet_counts, cf_info.num_interfaces);
1336
1337 g_free(idb_info);
1338 idb_info = NULL;
1339 }
1340 if (rec.rec_header.packet_header.interface_id < cf_info.num_interfaces) {
1341 g_array_index(cf_info.interface_packet_counts, guint32,
1342 rec.rec_header.packet_header.interface_id) += 1;
1343 }
1344 else {
1345 cf_info.pkt_interface_id_unknown += 1;
1346 }
1347 }
1348 else {
1349 /* it's for interface_id 0 */
1350 if (cf_info.num_interfaces != 0) {
1351 g_array_index(cf_info.interface_packet_counts, guint32, 0) += 1;
1352 }
1353 else {
1354 cf_info.pkt_interface_id_unknown += 1;
1355 }
1356 }
1357 }
1358
1359 wtap_rec_reset(&rec);
1360 } /* while */
1361 wtap_rec_cleanup(&rec);
1362 ws_buffer_free(&buf);
1363
1364 /*
1365 * Get IDB info strings.
1366 * We do this at the end, so we can get information for all IDBs in
1367 * the file, even those that come after packet records, and so that
1368 * we get, for example, a count of the number of statistics entries
1369 * for each interface as of the *end* of the file.
1370 */
1371 idb_info = wtap_file_get_idb_info(cf_info.wth);
1372
1373 cf_info.idb_info_strings = g_array_sized_new(FALSE, FALSE, sizeof(gchar*), cf_info.num_interfaces);
1374 cf_info.num_interfaces = idb_info->interface_data->len;
1375 for (i = 0; i < cf_info.num_interfaces; i++) {
1376 const wtap_block_t if_descr = g_array_index(idb_info->interface_data, wtap_block_t, i);
1377 gchar *s = wtap_get_debug_if_descr(if_descr, 21, "\n");
1378 g_array_append_val(cf_info.idb_info_strings, s);
1379 }
1380
1381 g_free(idb_info);
1382 idb_info = NULL;
1383
1384 if (err != 0) {
1385 fprintf(stderr,
1386 "capinfos: An error occurred after reading %u packets from \"%s\".\n",
1387 packet, filename);
1388 cfile_read_failure_message(filename, err, err_info);
1389 if (err == WTAP_ERR_SHORT_READ) {
1390 /* Don't give up completely with this one. */
1391 status = 1;
1392 fprintf(stderr,
1393 " (will continue anyway, checksums might be incorrect)\n");
1394 } else {
1395 cleanup_capture_info(&cf_info);
1396 wtap_close(cf_info.wth);
1397 return 2;
1398 }
1399 }
1400
1401 /* File size */
1402 size = wtap_file_size(cf_info.wth, &err);
1403 if (size == -1) {
1404 fprintf(stderr,
1405 "capinfos: Can't get size of \"%s\": %s.\n",
1406 filename, g_strerror(err));
1407 cleanup_capture_info(&cf_info);
1408 wtap_close(cf_info.wth);
1409 return 2;
1410 }
1411
1412 cf_info.filesize = size;
1413
1414 /* File Type */
1415 cf_info.file_type = wtap_file_type_subtype(cf_info.wth);
1416 cf_info.compression_type = wtap_get_compression_type(cf_info.wth);
1417
1418 /* File Encapsulation */
1419 cf_info.file_encap = wtap_file_encap(cf_info.wth);
1420
1421 cf_info.file_tsprec = wtap_file_tsprec(cf_info.wth);
1422
1423 /* Packet size limit (snaplen) */
1424 cf_info.snaplen = wtap_snapshot_length(cf_info.wth);
1425 if (cf_info.snaplen > 0)
1426 cf_info.snap_set = TRUE;
1427 else
1428 cf_info.snap_set = FALSE;
1429
1430 cf_info.snaplen_min_inferred = snaplen_min_inferred;
1431 cf_info.snaplen_max_inferred = snaplen_max_inferred;
1432
1433 /* # of packets */
1434 cf_info.packet_count = packet;
1435
1436 /* File Times */
1437 cf_info.times_known = have_times;
1438 cf_info.start_time = start_time;
1439 cf_info.start_time_tsprec = start_time_tsprec;
1440 cf_info.stop_time = stop_time;
1441 cf_info.stop_time_tsprec = stop_time_tsprec;
1442 nstime_delta(&cf_info.duration, &stop_time, &start_time);
1443 /* Duration precision is the higher of the start and stop time precisions. */
1444 if (cf_info.stop_time_tsprec > cf_info.start_time_tsprec)
1445 cf_info.duration_tsprec = cf_info.stop_time_tsprec;
1446 else
1447 cf_info.duration_tsprec = cf_info.start_time_tsprec;
1448 cf_info.know_order = know_order;
1449 cf_info.order = order;
1450
1451 /* Number of packet bytes */
1452 cf_info.packet_bytes = bytes;
1453
1454 cf_info.data_rate = 0.0;
1455 cf_info.packet_rate = 0.0;
1456 cf_info.packet_size = 0.0;
1457
1458 if (packet > 0) {
1459 double delta_time = nstime_to_sec(&stop_time) - nstime_to_sec(&start_time);
1460 if (delta_time > 0.0) {
1461 cf_info.data_rate = (double)bytes / delta_time; /* Data rate per second */
1462 cf_info.packet_rate = (double)packet / delta_time; /* packet rate per second */
1463 }
1464 cf_info.packet_size = (double)bytes / packet; /* Avg packet size */
1465 }
1466
1467 if (long_report) {
1468 print_stats(filename, &cf_info);
1469 } else {
1470 print_stats_table(filename, &cf_info);
1471 }
1472
1473 cleanup_capture_info(&cf_info);
1474 wtap_close(cf_info.wth);
1475
1476 return status;
1477 }
1478
1479 static void
print_usage(FILE * output)1480 print_usage(FILE *output)
1481 {
1482 fprintf(output, "\n");
1483 fprintf(output, "Usage: capinfos [options] <infile> ...\n");
1484 fprintf(output, "\n");
1485 fprintf(output, "General infos:\n");
1486 fprintf(output, " -t display the capture file type\n");
1487 fprintf(output, " -E display the capture file encapsulation\n");
1488 fprintf(output, " -I display the capture file interface information\n");
1489 fprintf(output, " -F display additional capture file information\n");
1490 fprintf(output, " -H display the SHA256, RIPEMD160, and SHA1 hashes of the file\n");
1491 fprintf(output, " -k display the capture comment\n");
1492 fprintf(output, "\n");
1493 fprintf(output, "Size infos:\n");
1494 fprintf(output, " -c display the number of packets\n");
1495 fprintf(output, " -s display the size of the file (in bytes)\n");
1496 fprintf(output, " -d display the total length of all packets (in bytes)\n");
1497 fprintf(output, " -l display the packet size limit (snapshot length)\n");
1498 fprintf(output, "\n");
1499 fprintf(output, "Time infos:\n");
1500 fprintf(output, " -u display the capture duration (in seconds)\n");
1501 fprintf(output, " -a display the capture start time\n");
1502 fprintf(output, " -e display the capture end time\n");
1503 fprintf(output, " -o display the capture file chronological status (True/False)\n");
1504 fprintf(output, " -S display start and end times as seconds\n");
1505 fprintf(output, "\n");
1506 fprintf(output, "Statistic infos:\n");
1507 fprintf(output, " -y display average data rate (in bytes/sec)\n");
1508 fprintf(output, " -i display average data rate (in bits/sec)\n");
1509 fprintf(output, " -z display average packet size (in bytes)\n");
1510 fprintf(output, " -x display average packet rate (in packets/sec)\n");
1511 fprintf(output, "\n");
1512 fprintf(output, "Metadata infos:\n");
1513 fprintf(output, " -n display number of resolved IPv4 and IPv6 addresses\n");
1514 fprintf(output, " -D display number of decryption secrets\n");
1515 fprintf(output, "\n");
1516 fprintf(output, "Output format:\n");
1517 fprintf(output, " -L generate long report (default)\n");
1518 fprintf(output, " -T generate table report\n");
1519 fprintf(output, " -M display machine-readable values in long reports\n");
1520 fprintf(output, "\n");
1521 fprintf(output, "Table report options:\n");
1522 fprintf(output, " -R generate header record (default)\n");
1523 fprintf(output, " -r do not generate header record\n");
1524 fprintf(output, "\n");
1525 fprintf(output, " -B separate infos with TAB character (default)\n");
1526 fprintf(output, " -m separate infos with comma (,) character\n");
1527 fprintf(output, " -b separate infos with SPACE character\n");
1528 fprintf(output, "\n");
1529 fprintf(output, " -N do not quote infos (default)\n");
1530 fprintf(output, " -q quote infos with single quotes (')\n");
1531 fprintf(output, " -Q quote infos with double quotes (\")\n");
1532 fprintf(output, "\n");
1533 fprintf(output, "Miscellaneous:\n");
1534 fprintf(output, " -h, --help display this help and exit\n");
1535 fprintf(output, " -v, --version display version info and exit\n");
1536 fprintf(output, " -C cancel processing if file open fails (default is to continue)\n");
1537 fprintf(output, " -A generate all infos (default)\n");
1538 fprintf(output, " -K disable displaying the capture comment\n");
1539 fprintf(output, "\n");
1540 fprintf(output, "Options are processed from left to right order with later options superseding\n");
1541 fprintf(output, "or adding to earlier options.\n");
1542 fprintf(output, "\n");
1543 fprintf(output, "If no options are given the default is to display all infos in long report\n");
1544 fprintf(output, "output format.\n");
1545 }
1546
1547 /*
1548 * Report an error in command-line arguments.
1549 */
1550 static void
capinfos_cmdarg_err(const char * msg_format,va_list ap)1551 capinfos_cmdarg_err(const char *msg_format, va_list ap)
1552 {
1553 fprintf(stderr, "capinfos: ");
1554 vfprintf(stderr, msg_format, ap);
1555 fprintf(stderr, "\n");
1556 }
1557
1558 /*
1559 * Report additional information for an error in command-line arguments.
1560 */
1561 static void
capinfos_cmdarg_err_cont(const char * msg_format,va_list ap)1562 capinfos_cmdarg_err_cont(const char *msg_format, va_list ap)
1563 {
1564 vfprintf(stderr, msg_format, ap);
1565 fprintf(stderr, "\n");
1566 }
1567
1568 int
main(int argc,char * argv[])1569 main(int argc, char *argv[])
1570 {
1571 char *init_progfile_dir_error;
1572 static const struct report_message_routines capinfos_report_routines = {
1573 failure_message,
1574 failure_message,
1575 open_failure_message,
1576 read_failure_message,
1577 write_failure_message,
1578 cfile_open_failure_message,
1579 cfile_dump_open_failure_message,
1580 cfile_read_failure_message,
1581 cfile_write_failure_message,
1582 cfile_close_failure_message
1583 };
1584 gboolean need_separator = FALSE;
1585 int opt;
1586 int overall_error_status = EXIT_SUCCESS;
1587 static const struct ws_option long_options[] = {
1588 {"help", ws_no_argument, NULL, 'h'},
1589 {"version", ws_no_argument, NULL, 'v'},
1590 {0, 0, 0, 0 }
1591 };
1592
1593 int status = 0;
1594
1595 /*
1596 * Set the C-language locale to the native environment and set the
1597 * code page to UTF-8 on Windows.
1598 */
1599 #ifdef _WIN32
1600 setlocale(LC_ALL, ".UTF-8");
1601 #else
1602 setlocale(LC_ALL, "");
1603 #endif
1604
1605 cmdarg_err_init(capinfos_cmdarg_err, capinfos_cmdarg_err_cont);
1606
1607 /* Initialize log handler early so we can have proper logging during startup. */
1608 ws_log_init("capinfos", vcmdarg_err);
1609
1610 /* Early logging command-line initialization. */
1611 ws_log_parse_args(&argc, argv, vcmdarg_err, INVALID_OPTION);
1612
1613 /* Get the decimal point. */
1614 decimal_point = g_strdup(localeconv()->decimal_point);
1615
1616 /* Initialize the version information. */
1617 ws_init_version_info("Capinfos (Wireshark)", NULL, NULL, NULL);
1618
1619 #ifdef _WIN32
1620 create_app_running_mutex();
1621 #endif /* _WIN32 */
1622
1623 /*
1624 * Get credential information for later use.
1625 */
1626 init_process_policies();
1627
1628 /*
1629 * Attempt to get the pathname of the directory containing the
1630 * executable file.
1631 */
1632 init_progfile_dir_error = init_progfile_dir(argv[0]);
1633 if (init_progfile_dir_error != NULL) {
1634 fprintf(stderr,
1635 "capinfos: Can't get pathname of directory containing the capinfos program: %s.\n",
1636 init_progfile_dir_error);
1637 g_free(init_progfile_dir_error);
1638 }
1639
1640 init_report_message("capinfos", &capinfos_report_routines);
1641
1642 wtap_init(TRUE);
1643
1644 /* Process the options */
1645 while ((opt = ws_getopt_long(argc, argv, "abcdehiklmnoqrstuvxyzABCDEFHIKLMNQRST", long_options, NULL)) !=-1) {
1646
1647 switch (opt) {
1648
1649 case 't':
1650 if (report_all_infos) disable_all_infos();
1651 cap_file_type = TRUE;
1652 break;
1653
1654 case 'E':
1655 if (report_all_infos) disable_all_infos();
1656 cap_file_encap = TRUE;
1657 break;
1658
1659 case 'l':
1660 if (report_all_infos) disable_all_infos();
1661 cap_snaplen = TRUE;
1662 break;
1663
1664 case 'c':
1665 if (report_all_infos) disable_all_infos();
1666 cap_packet_count = TRUE;
1667 break;
1668
1669 case 's':
1670 if (report_all_infos) disable_all_infos();
1671 cap_file_size = TRUE;
1672 break;
1673
1674 case 'd':
1675 if (report_all_infos) disable_all_infos();
1676 cap_data_size = TRUE;
1677 break;
1678
1679 case 'u':
1680 if (report_all_infos) disable_all_infos();
1681 cap_duration = TRUE;
1682 break;
1683
1684 case 'a':
1685 if (report_all_infos) disable_all_infos();
1686 cap_start_time = TRUE;
1687 break;
1688
1689 case 'e':
1690 if (report_all_infos) disable_all_infos();
1691 cap_end_time = TRUE;
1692 break;
1693
1694 case 'S':
1695 time_as_secs = TRUE;
1696 break;
1697
1698 case 'y':
1699 if (report_all_infos) disable_all_infos();
1700 cap_data_rate_byte = TRUE;
1701 break;
1702
1703 case 'i':
1704 if (report_all_infos) disable_all_infos();
1705 cap_data_rate_bit = TRUE;
1706 break;
1707
1708 case 'z':
1709 if (report_all_infos) disable_all_infos();
1710 cap_packet_size = TRUE;
1711 break;
1712
1713 case 'x':
1714 if (report_all_infos) disable_all_infos();
1715 cap_packet_rate = TRUE;
1716 break;
1717
1718 case 'H':
1719 if (report_all_infos) disable_all_infos();
1720 cap_file_hashes = TRUE;
1721 break;
1722
1723 case 'o':
1724 if (report_all_infos) disable_all_infos();
1725 cap_order = TRUE;
1726 break;
1727
1728 case 'k':
1729 if (report_all_infos) disable_all_infos();
1730 cap_comment = TRUE;
1731 break;
1732
1733 case 'K':
1734 cap_comment = FALSE;
1735 break;
1736
1737 case 'F':
1738 if (report_all_infos) disable_all_infos();
1739 cap_file_more_info = TRUE;
1740 break;
1741
1742 case 'I':
1743 if (report_all_infos) disable_all_infos();
1744 cap_file_idb = TRUE;
1745 break;
1746
1747 case 'n':
1748 if (report_all_infos) disable_all_infos();
1749 cap_file_nrb = TRUE;
1750 break;
1751
1752 case 'D':
1753 if (report_all_infos) disable_all_infos();
1754 cap_file_dsb = TRUE;
1755 break;
1756
1757 case 'C':
1758 stop_after_failure = TRUE;
1759 break;
1760
1761 case 'A':
1762 enable_all_infos();
1763 break;
1764
1765 case 'L':
1766 long_report = TRUE;
1767 break;
1768
1769 case 'T':
1770 long_report = FALSE;
1771 break;
1772
1773 case 'M':
1774 machine_readable = TRUE;
1775 break;
1776
1777 case 'R':
1778 table_report_header = TRUE;
1779 break;
1780
1781 case 'r':
1782 table_report_header = FALSE;
1783 break;
1784
1785 case 'N':
1786 quote_char = '\0';
1787 break;
1788
1789 case 'q':
1790 quote_char = '\'';
1791 break;
1792
1793 case 'Q':
1794 quote_char = '"';
1795 break;
1796
1797 case 'B':
1798 field_separator = '\t';
1799 break;
1800
1801 case 'm':
1802 field_separator = ',';
1803 break;
1804
1805 case 'b':
1806 field_separator = ' ';
1807 break;
1808
1809 case 'h':
1810 show_help_header("Print various information (infos) about capture files.");
1811 print_usage(stdout);
1812 goto exit;
1813 break;
1814
1815 case 'v':
1816 show_version();
1817 goto exit;
1818 break;
1819
1820 case '?': /* Bad flag - print usage message */
1821 print_usage(stderr);
1822 overall_error_status = INVALID_OPTION;
1823 goto exit;
1824 break;
1825 }
1826 }
1827
1828 if ((argc - ws_optind) < 1) {
1829 print_usage(stderr);
1830 overall_error_status = INVALID_OPTION;
1831 goto exit;
1832 }
1833
1834 if (!long_report && table_report_header) {
1835 print_stats_table_header();
1836 }
1837
1838 if (cap_file_hashes) {
1839 gcry_check_version(NULL);
1840 gcry_md_open(&hd, GCRY_MD_SHA256, 0);
1841 if (hd) {
1842 gcry_md_enable(hd, GCRY_MD_RMD160);
1843 gcry_md_enable(hd, GCRY_MD_SHA1);
1844 }
1845 hash_buf = (char *)g_malloc(HASH_BUF_SIZE);
1846 }
1847
1848 overall_error_status = 0;
1849
1850 for (opt = ws_optind; opt < argc; opt++) {
1851
1852 status = process_cap_file(argv[opt], need_separator);
1853 if (status) {
1854 /* Something failed. It's been reported; remember that processing
1855 one file failed and, if -C was specified, stop. */
1856 overall_error_status = status;
1857 if (stop_after_failure)
1858 goto exit;
1859 }
1860 if (status != 2) {
1861 /* Either it succeeded or it got a "short read" but printed
1862 information anyway. Note that we need a blank line before
1863 the next file's information, to separate it from the
1864 previous file. */
1865 need_separator = TRUE;
1866 }
1867 }
1868
1869 exit:
1870 g_free(hash_buf);
1871 gcry_md_close(hd);
1872 wtap_cleanup();
1873 free_progdirs();
1874 return overall_error_status;
1875 }
1876
1877 /*
1878 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1879 *
1880 * Local variables:
1881 * c-basic-offset: 2
1882 * tab-width: 8
1883 * indent-tabs-mode: nil
1884 * End:
1885 *
1886 * vi: set shiftwidth=2 tabstop=8 expandtab:
1887 * :indentSize=2:tabSize=8:noTabs=true:
1888 */
1889