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