extcap: check that argument parameter is not null before adding it to command line
[metze/wireshark/wip.git] / tshark.c
index 269d1d2c428bc4c53ebeb1faf81fd08670255435..c09aee777489450d3de43a1040c7c3e367f13ec1 100644 (file)
--- a/tshark.c
+++ b/tshark.c
 
 #include <errno.h>
 
+#ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+
 #ifndef _WIN32
 #include <signal.h>
 #endif
 #define INVALID_CAPABILITY 2
 #define INVALID_TAP 2
 #define INVALID_DATA_LINK 2
+#define INVALID_TIMESTAMP_TYPE 2
 #define INVALID_CAPTURE 2
 #define INIT_FAILED 2
 
+/*
+ * values 128..65535 are capture+dissect options, 65536 is used by
+ * ui/commandline.c, so start tshark-specific options 1000 after this
+ */
+#define LONGOPT_COLOR (65536+1000)
+#define LONGOPT_NO_DUPLICATE_KEYS (65536+1001)
+
 #if 0
 #define tshark_debug(...) g_warning(__VA_ARGS__)
 #else
@@ -162,6 +174,8 @@ static frame_data *prev_cap;
 static frame_data prev_cap_frame;
 
 static gboolean perform_two_pass_analysis;
+static guint32 epan_auto_reset_count = 0;
+static gboolean epan_auto_reset = FALSE;
 
 /*
  * The way the packet decode is to be written.
@@ -185,6 +199,7 @@ static gboolean print_hex;         /* TRUE if we're to print hex/ascci informati
 static gboolean line_buffered;
 static gboolean really_quiet = FALSE;
 static gchar* delimiter_char = " ";
+static gboolean dissect_color = FALSE;
 
 static print_format_e print_format = PR_FMT_TEXT;
 static print_stream_t *print_stream = NULL;
@@ -193,6 +208,9 @@ static output_fields_t* output_fields  = NULL;
 static gchar **protocolfilter = NULL;
 static pf_flags protocolfilter_flags = PF_NONE;
 
+static gboolean no_duplicate_keys = FALSE;
+static proto_node_children_grouper_func node_children_grouper = proto_node_group_children_by_unique;
+
 /* The line separator used between packets, changeable via the -S option */
 static const char *separator = "";
 
@@ -228,7 +246,8 @@ static char *output_file_name;
 
 #endif /* HAVE_LIBPCAP */
 
-static int read_cap_file(capture_file *, char *, int, gboolean, int, gint64);
+static void reset_epan_mem(capture_file *cf, epan_dissect_t *edt, gboolean tree, gboolean visual);
+static gboolean process_cap_file(capture_file *, char *, int, gboolean, int, gint64);
 static gboolean process_packet_single_pass(capture_file *cf,
     epan_dissect_t *edt, gint64 offset, struct wtap_pkthdr *whdr,
     const guchar *pd, guint tap_flags);
@@ -322,7 +341,11 @@ print_usage(FILE *output)
   fprintf(output, "Capture interface:\n");
   fprintf(output, "  -i <interface>           name or idx of interface (def: first non-loopback)\n");
   fprintf(output, "  -f <capture filter>      packet filter in libpcap filter syntax\n");
-  fprintf(output, "  -s <snaplen>             packet snapshot length (def: %u)\n", WTAP_MAX_PACKET_SIZE);
+#ifdef HAVE_PCAP_CREATE
+  fprintf(output, "  -s <snaplen>             packet snapshot length (def: appropriate maximum)\n");
+#else
+  fprintf(output, "  -s <snaplen>             packet snapshot length (def: %u)\n", WTAP_MAX_PACKET_SIZE_STANDARD);
+#endif
   fprintf(output, "  -p                       don't capture in promiscuous mode\n");
 #ifdef HAVE_PCAP_CREATE
   fprintf(output, "  -I                       capture in monitor mode, if available\n");
@@ -331,8 +354,10 @@ print_usage(FILE *output)
   fprintf(output, "  -B <buffer size>         size of kernel buffer (def: %dMB)\n", DEFAULT_CAPTURE_BUFFER_SIZE);
 #endif
   fprintf(output, "  -y <link type>           link layer type (def: first appropriate)\n");
+  fprintf(output, "  --time-stamp-type <type> timestamp method for interface\n");
   fprintf(output, "  -D                       print list of interfaces and exit\n");
   fprintf(output, "  -L                       print list of link-layer types of iface and exit\n");
+  fprintf(output, "  --list-time-stamp-types  print list of timestamp types for iface and exit\n");
   fprintf(output, "\n");
   fprintf(output, "Capture stop conditions:\n");
   fprintf(output, "  -c <packet count>        stop after n packets (def: infinite)\n");
@@ -342,6 +367,7 @@ print_usage(FILE *output)
   /*fprintf(output, "\n");*/
   fprintf(output, "Capture output:\n");
   fprintf(output, "  -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
+  fprintf(output, "                           interval:NUM - create time intervals of NUM secs\n");
   fprintf(output, "                           filesize:NUM - switch to next file after NUM KB\n");
   fprintf(output, "                              files:NUM - ringbuffer: replace after NUM files\n");
 #endif  /* HAVE_LIBPCAP */
@@ -356,6 +382,7 @@ print_usage(FILE *output)
   fprintf(output, "\n");
   fprintf(output, "Processing:\n");
   fprintf(output, "  -2                       perform a two-pass analysis\n");
+  fprintf(output, "  -M <packet count>        perform session auto reset\n");
   fprintf(output, "  -R <read filter>         packet Read filter in Wireshark display filter syntax\n");
   fprintf(output, "                           (requires -2)\n");
   fprintf(output, "  -Y <display filter>      packet displaY filter in Wireshark display filter\n");
@@ -423,6 +450,13 @@ print_usage(FILE *output)
   fprintf(output, "                           output file (only for pcapng)\n");
   fprintf(output, "  --export-objects <protocol>,<destdir> save exported objects for a protocol to\n");
   fprintf(output, "                           a directory named \"destdir\"\n");
+  fprintf(output, "  --color                  color output text similarly to the Wireshark GUI,\n");
+  fprintf(output, "                           requires a terminal with 24-bit color support\n");
+  fprintf(output, "                           Also supplies color attributes to pdml and psml formats\n");
+  fprintf(output, "                           (Note that attributes are nonstandard)\n");
+  fprintf(output, "  --no-duplicate-keys      If -T json is specified, merge duplicate keys in an object\n");
+  fprintf(output, "                           into a single key with as value a json array containing all\n");
+  fprintf(output, "                           values");
 
   fprintf(output, "\n");
   fprintf(output, "Miscellaneous:\n");
@@ -640,6 +674,8 @@ main(int argc, char *argv[])
     LONGOPT_CAPTURE_COMMON
     LONGOPT_DISSECT_COMMON
     {"export-objects", required_argument, NULL, LONGOPT_EXPORT_OBJECTS},
+    {"color", no_argument, NULL, LONGOPT_COLOR},
+    {"no-duplicate-keys", no_argument, NULL, LONGOPT_NO_DUPLICATE_KEYS},
     {0, 0, 0, 0 }
   };
   gboolean             arg_error = FALSE;
@@ -650,9 +686,10 @@ main(int argc, char *argv[])
 #endif  /* _WIN32 */
 
   int                  err;
+  volatile gboolean    success;
   volatile int         exit_status = EXIT_SUCCESS;
 #ifdef HAVE_LIBPCAP
-  gboolean             list_link_layer_types = FALSE;
+  int                  caps_queries = 0;
   gboolean             start_capture = FALSE;
   GList               *if_list;
   gchar               *err_str;
@@ -702,7 +739,7 @@ main(int argc, char *argv[])
  * We do *not* use a leading - because the behavior of a leading - is
  * platform-dependent.
  */
-#define OPTSTRING "+2" OPTSTRING_CAPTURE_COMMON OPTSTRING_DISSECT_COMMON "C:e:E:F:gG:hH:j:J:lo:O:PqQr:R:S:T:U:vVw:W:xX:Y:z:"
+#define OPTSTRING "+2" OPTSTRING_CAPTURE_COMMON OPTSTRING_DISSECT_COMMON "M:C:e:E:F:gG:hH:j:J:lo:O:PqQr:R:S:T:U:vVw:W:xX:Y:z:"
 
   static const char    optstring[] = OPTSTRING;
 
@@ -748,6 +785,7 @@ main(int argc, char *argv[])
 
 #ifdef _WIN32
   ws_init_dll_search_path();
+#ifdef HAVE_LIBPCAP
   /* Load wpcap if possible. Do this before collecting the run-time version information */
   load_wpcap();
 
@@ -756,7 +794,8 @@ main(int argc, char *argv[])
     fprintf(stderr, "The NPF driver isn't running.  You may have trouble "
       "capturing or\nlisting interfaces.\n");
   }
-#endif
+#endif /* HAVE_LIBPCAP */
+#endif /* _WIN32 */
 
   /* Get the compile-time version information string */
   comp_info_str = get_compiled_version_info(get_tshark_compiled_version_info,
@@ -1026,14 +1065,27 @@ main(int argc, char *argv[])
   while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) {
     switch (opt) {
     case '2':        /* Perform two pass analysis */
+      if(epan_auto_reset){
+        cmdarg_err("-2 does not support auto session reset.");
+        arg_error=TRUE;
+      }
       perform_two_pass_analysis = TRUE;
       break;
+    case 'M':
+      if(perform_two_pass_analysis){
+        cmdarg_err("-M does not support two pass analysis.");
+        arg_error=TRUE;
+      }
+      epan_auto_reset_count = get_positive_int(optarg, "epan reset count");
+      epan_auto_reset = TRUE;
+      break;
     case 'a':        /* autostop criteria */
     case 'b':        /* Ringbuffer option */
     case 'c':        /* Capture x packets */
     case 'f':        /* capture filter */
     case 'g':        /* enable group read access on file(s) */
     case 'i':        /* Use interface x */
+    case LONGOPT_SET_TSTAMP_TYPE: /* Set capture timestamp type */
     case 'p':        /* Don't capture in promiscuous mode */
 #ifdef HAVE_PCAP_REMOTE
     case 'A':        /* Authentication */
@@ -1178,20 +1230,33 @@ main(int argc, char *argv[])
       break;
     case 'L':        /* Print list of link-layer types and exit */
 #ifdef HAVE_LIBPCAP
-      list_link_layer_types = TRUE;
+      caps_queries |= CAPS_QUERY_LINK_TYPES;
+#else
+      capture_option_specified = TRUE;
+      arg_error = TRUE;
+#endif
+      break;
+    case LONGOPT_LIST_TSTAMP_TYPES: /* List possible timestamp types */
+#ifdef HAVE_LIBPCAP
+      caps_queries |= CAPS_QUERY_TIMESTAMP_TYPES;
 #else
       capture_option_specified = TRUE;
       arg_error = TRUE;
 #endif
       break;
     case 'o':        /* Override preference from command line */
-      switch (prefs_set_pref(optarg)) {
+    {
+      char *errmsg = NULL;
+
+      switch (prefs_set_pref(optarg, &errmsg)) {
 
       case PREFS_SET_OK:
         break;
 
       case PREFS_SET_SYNTAX_ERR:
-        cmdarg_err("Invalid -o flag \"%s\"", optarg);
+        cmdarg_err("Invalid -o flag \"%s\"%s%s", optarg,
+            errmsg ? ": " : "", errmsg ? errmsg : "");
+        g_free(errmsg);
         exit_status = INVALID_OPTION;
         goto clean_exit;
         break;
@@ -1204,6 +1269,7 @@ main(int argc, char *argv[])
         break;
       }
       break;
+    }
     case 'q':        /* Quiet */
       quiet = TRUE;
       break;
@@ -1388,6 +1454,13 @@ main(int argc, char *argv[])
         goto clean_exit;
       }
       break;
+    case LONGOPT_COLOR: /* print in color where appropriate */
+      dissect_color = TRUE;
+      break;
+    case LONGOPT_NO_DUPLICATE_KEYS:
+      no_duplicate_keys = TRUE;
+      node_children_grouper = proto_node_group_children_by_json_key;
+      break;
     default:
     case '?':        /* Bad flag - print usage message */
       switch(optopt) {
@@ -1403,6 +1476,12 @@ main(int argc, char *argv[])
     }
   }
 
+  if (no_duplicate_keys && output_action != WRITE_JSON && output_action != WRITE_JSON_RAW) {
+    cmdarg_err("--no-duplicate-keys can only be used with \"-T json\" and \"-T jsonraw\"");
+    exit_status = INVALID_OPTION;
+    goto clean_exit;
+  }
+
   /* If we specified output fields, but not the output field type... */
   if ((WRITE_FIELDS != output_action && WRITE_XML != output_action && WRITE_JSON != output_action && WRITE_EK != output_action) && 0 != output_fields_num_fields(output_fields)) {
         cmdarg_err("Output fields were specified with \"-e\", "
@@ -1417,6 +1496,13 @@ main(int argc, char *argv[])
         goto clean_exit;
   }
 
+  if (dissect_color) {
+    if (!color_filters_init(&err_msg, NULL)) {
+      fprintf(stderr, "%s\n", err_msg);
+      g_free(err_msg);
+    }
+  }
+
   /* If no capture filter or display filter has been specified, and there are
      still command-line arguments, treat them as the tokens of a capture
      filter (if no "-r" flag was specified) or a display filter (if a "-r"
@@ -1441,12 +1527,10 @@ main(int argc, char *argv[])
         goto clean_exit;
       }
       for (i = 0; i < global_capture_opts.ifaces->len; i++) {
-        interface_options interface_opts;
-        interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
-        if (interface_opts.cfilter == NULL) {
-          interface_opts.cfilter = get_args_as_string(argc, argv, optind);
-          global_capture_opts.ifaces = g_array_remove_index(global_capture_opts.ifaces, i);
-          g_array_insert_val(global_capture_opts.ifaces, i, interface_opts);
+        interface_options *interface_opts;
+        interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, i);
+        if (interface_opts->cfilter == NULL) {
+          interface_opts->cfilter = get_args_as_string(argc, argv, optind);
         } else {
           cmdarg_err("A capture filter was specified both with \"-f\""
               " and with additional command-line arguments.");
@@ -1527,12 +1611,13 @@ main(int argc, char *argv[])
   }
 
 #ifdef HAVE_LIBPCAP
-  if (list_link_layer_types) {
-    /* We're supposed to list the link-layer types for an interface;
+  if (caps_queries) {
+    /* We're supposed to list the link-layer/timestamp types for an interface;
        did the user also specify a capture file to be read? */
     if (cf_name) {
       /* Yes - that's bogus. */
-      cmdarg_err("You can't specify -L and a capture file to be read.");
+      cmdarg_err("You can't specify %s and a capture file to be read.",
+                 caps_queries & CAPS_QUERY_LINK_TYPES ? "-L" : "--list-time-stamp-types");
       exit_status = INVALID_OPTION;
       goto clean_exit;
     }
@@ -1565,6 +1650,12 @@ main(int argc, char *argv[])
         goto clean_exit;
       }
       if (global_capture_opts.has_file_duration) {
+        cmdarg_err("Switching capture files after a time period was specified, but "
+                   "a capture isn't being done.");
+        exit_status = INVALID_OPTION;
+        goto clean_exit;
+      }
+      if (global_capture_opts.has_file_interval) {
         cmdarg_err("Switching capture files after a time interval was specified, but "
                    "a capture isn't being done.");
         exit_status = INVALID_OPTION;
@@ -1647,9 +1738,10 @@ main(int argc, char *argv[])
             goto clean_exit;
           }
           if (!global_capture_opts.has_autostop_filesize &&
-              !global_capture_opts.has_file_duration) {
+              !global_capture_opts.has_file_duration &&
+              !global_capture_opts.has_file_interval) {
             cmdarg_err("Multiple capture files requested, but "
-              "no maximum capture file size or duration was specified.");
+              "no maximum capture file size, duration or interval was specified.");
             exit_status = INVALID_OPTION;
             goto clean_exit;
           }
@@ -1930,7 +2022,7 @@ main(int argc, char *argv[])
 
         we're using any taps that need dissection. */
   do_dissection = print_packet_info || rfcode || dfcode || pdu_export_arg ||
-      tap_listeners_require_dissection();
+      tap_listeners_require_dissection() || dissect_color;
   tshark_debug("tshark: do_dissection = %s", do_dissection ? "TRUE" : "FALSE");
 
   if (cf_name) {
@@ -1948,14 +2040,14 @@ main(int argc, char *argv[])
     }
 
     /* Process the packets in the file */
-    tshark_debug("tshark: invoking read_cap_file() to process the packets");
+    tshark_debug("tshark: invoking process_cap_file() to process the packets");
     TRY {
 #ifdef HAVE_LIBPCAP
-      err = read_cap_file(&cfile, global_capture_opts.save_file, out_file_type, out_file_name_res,
+      success = process_cap_file(&cfile, global_capture_opts.save_file, out_file_type, out_file_name_res,
           global_capture_opts.has_autostop_packets ? global_capture_opts.autostop_packets : 0,
           global_capture_opts.has_autostop_filesize ? global_capture_opts.autostop_filesize : 0);
 #else
-      err = read_cap_file(&cfile, output_file_name, out_file_type, out_file_name_res, 0, 0);
+      success = process_cap_file(&cfile, output_file_name, out_file_type, out_file_name_res, 0, 0);
 #endif
     }
     CATCH(OutOfMemoryError) {
@@ -1966,10 +2058,11 @@ main(int argc, char *argv[])
               "\n"
               "More information and workarounds can be found at\n"
               "https://wiki.wireshark.org/KnownBugs/OutOfMemory\n");
-      err = ENOMEM;
+      success = FALSE;
     }
     ENDTRY;
-    if (err != 0) {
+
+    if (!success) {
       /* We still dump out the results of taps, etc., as we might have
          read some packets; however, we exit with an error status. */
       exit_status = 2;
@@ -1997,22 +2090,23 @@ main(int argc, char *argv[])
     }
 
     /* if requested, list the link layer types and exit */
-    if (list_link_layer_types) {
+    if (caps_queries) {
         guint i;
 
         /* Get the list of link-layer types for the capture devices. */
         for (i = 0; i < global_capture_opts.ifaces->len; i++) {
-          interface_options  interface_opts;
+          interface_options *interface_opts;
           if_capabilities_t *caps;
           char *auth_str = NULL;
+          int if_caps_queries = caps_queries;
 
-          interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
+          interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, i);
 #ifdef HAVE_PCAP_REMOTE
-          if (interface_opts.auth_type == CAPTURE_AUTH_PWD) {
-              auth_str = g_strdup_printf("%s:%s", interface_opts.auth_username, interface_opts.auth_password);
+          if (interface_opts->auth_type == CAPTURE_AUTH_PWD) {
+              auth_str = g_strdup_printf("%s:%s", interface_opts->auth_username, interface_opts->auth_password);
           }
 #endif
-          caps = capture_get_if_capabilities(interface_opts.name, interface_opts.monitor_mode, auth_str, &err_str, NULL);
+          caps = capture_get_if_capabilities(interface_opts->name, interface_opts->monitor_mode, auth_str, &err_str, NULL);
           g_free(auth_str);
           if (caps == NULL) {
             cmdarg_err("%s", err_str);
@@ -2020,12 +2114,19 @@ main(int argc, char *argv[])
             exit_status = INVALID_CAPABILITY;
             goto clean_exit;
           }
-          if (caps->data_link_types == NULL) {
-            cmdarg_err("The capture device \"%s\" has no data link types.", interface_opts.name);
+          if ((if_caps_queries & CAPS_QUERY_LINK_TYPES) && caps->data_link_types == NULL) {
+            cmdarg_err("The capture device \"%s\" has no data link types.", interface_opts->name);
             exit_status = INVALID_DATA_LINK;
             goto clean_exit;
           }
-          capture_opts_print_if_capabilities(caps, interface_opts.name, interface_opts.monitor_mode);
+          if ((if_caps_queries & CAPS_QUERY_TIMESTAMP_TYPES) && caps->timestamp_types == NULL) {
+            cmdarg_err("The capture device \"%s\" has no timestamp types.", interface_opts->name);
+            exit_status = INVALID_TIMESTAMP_TYPE;
+            goto clean_exit;
+          }
+          if (interface_opts->monitor_mode)
+                if_caps_queries |= CAPS_MONITOR_MODE;
+          capture_opts_print_if_capabilities(caps, interface_opts->name, if_caps_queries);
           free_if_capabilities(caps);
         }
         exit_status = EXIT_SUCCESS;
@@ -2088,8 +2189,7 @@ main(int argc, char *argv[])
 
     if (print_packet_info) {
       if (!write_finale()) {
-        err = errno;
-        show_print_file_io_error(err);
+        show_print_file_io_error(errno);
       }
     }
 #else
@@ -2340,12 +2440,10 @@ capture(void)
 
   /* Let the user know which interfaces were chosen. */
   for (i = 0; i < global_capture_opts.ifaces->len; i++) {
-    interface_options interface_opts;
+    interface_options *interface_opts;
 
-    interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
-    interface_opts.descr = get_interface_descriptive_name(interface_opts.name);
-    global_capture_opts.ifaces = g_array_remove_index(global_capture_opts.ifaces, i);
-    g_array_insert_val(global_capture_opts.ifaces, i, interface_opts);
+    interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, i);
+    interface_opts->descr = get_interface_descriptive_name(interface_opts->name);
   }
   str = get_iface_list_string(&global_capture_opts, IFLIST_QUOTE_IF_DESCRIPTION);
   if (really_quiet == FALSE)
@@ -2435,12 +2533,12 @@ capture_input_cfilter_error_message(capture_session *cap_session, guint i, char
 {
   capture_options *capture_opts = cap_session->capture_opts;
   dfilter_t         *rfcode = NULL;
-  interface_options  interface_opts;
+  interface_options *interface_opts;
 
   g_assert(i < capture_opts->ifaces->len);
-  interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
+  interface_opts = &g_array_index(capture_opts->ifaces, interface_options, i);
 
-  if (dfilter_compile(interface_opts.cfilter, &rfcode, NULL) && rfcode != NULL) {
+  if (dfilter_compile(interface_opts->cfilter, &rfcode, NULL) && rfcode != NULL) {
     cmdarg_err(
       "Invalid capture filter \"%s\" for interface '%s'.\n"
       "\n"
@@ -2451,7 +2549,7 @@ capture_input_cfilter_error_message(capture_session *cap_session, guint i, char
       "so you can't use most display filter expressions as capture filters.\n"
       "\n"
       "See the User's Guide for a description of the capture filter syntax.",
-      interface_opts.cfilter, interface_opts.descr, error_message);
+      interface_opts->cfilter, interface_opts->descr, error_message);
     dfilter_free(rfcode);
   } else {
     cmdarg_err(
@@ -2459,7 +2557,7 @@ capture_input_cfilter_error_message(capture_session *cap_session, guint i, char
       "\n"
       "That string isn't a valid capture filter (%s).\n"
       "See the User's Guide for a description of the capture filter syntax.",
-      interface_opts.cfilter, interface_opts.descr, error_message);
+      interface_opts->cfilter, interface_opts->descr, error_message);
   }
 }
 
@@ -2582,7 +2680,7 @@ capture_input_new_packets(capture_session *cap_session, int to_read)
     create_proto_tree =
       (cf->rfcode || cf->dfcode || print_details || filtering_tap_listeners ||
         (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids() ||
-        have_custom_cols(&cf->cinfo));
+        have_custom_cols(&cf->cinfo) || dissect_color);
 
     /* The protocol tree will be "visible", i.e., printed, only if we're
        printing packet details, which is true if we're printing stuff
@@ -2593,6 +2691,7 @@ capture_input_new_packets(capture_session *cap_session, int to_read)
     while (to_read-- && cf->wth) {
       wtap_cleareof(cf->wth);
       ret = wtap_read(cf->wth, &err, &err_info, &data_offset);
+      reset_epan_mem(cf, edt, create_proto_tree, print_packet_info && print_details);
       if (ret == FALSE) {
         /* read from file failed, tell the capture child to stop */
         sync_pipe_stop(cap_session);
@@ -2905,6 +3004,11 @@ process_packet_second_pass(capture_file *cf, epan_dissect_t *edt,
       ref = &ref_frame;
     }
 
+    if (dissect_color) {
+      color_filters_prime_edt(edt);
+      fdata->flags.need_colorize = 1;
+    }
+
     epan_dissect_run_with_taps(edt, cf->cd_t, phdr, frame_tvbuff_new_buffer(fdata, buf), fdata, cinfo);
 
     /* Run the read/display filter if we have one. */
@@ -2941,16 +3045,17 @@ process_packet_second_pass(capture_file *cf, epan_dissect_t *edt,
   return passed || fdata->flags.dependent_of_displayed;
 }
 
-static int
-read_cap_file(capture_file *cf, char *save_file, int out_file_type,
+static gboolean
+process_cap_file(capture_file *cf, char *save_file, int out_file_type,
     gboolean out_file_name_res, int max_packet_count, gint64 max_byte_count)
 {
+  gboolean     success = TRUE;
   gint         linktype;
   int          snapshot_length;
   wtap_dumper *pdh;
   guint32      framenum;
-  int          err;
-  gchar       *err_info = NULL;
+  int          err = 0, err_pass1 = 0;
+  gchar       *err_info = NULL, *err_info_pass1 = NULL;
   gint64       data_offset;
   gboolean     filtering_tap_listeners;
   guint        tap_flags;
@@ -2979,7 +3084,7 @@ read_cap_file(capture_file *cf, char *save_file, int out_file_type,
     snapshot_length = wtap_snapshot_length(cf->wth);
     if (snapshot_length == 0) {
       /* Snapshot length of input file not known. */
-      snapshot_length = WTAP_MAX_PACKET_SIZE;
+      snapshot_length = WTAP_MAX_PACKET_SIZE_STANDARD;
     }
     tshark_debug("tshark: snapshot_length = %d", snapshot_length);
 
@@ -3022,13 +3127,15 @@ read_cap_file(capture_file *cf, char *save_file, int out_file_type,
     if (pdh == NULL) {
       /* We couldn't set up to write to the capture file. */
       cfile_dump_open_failure_message("TShark", save_file, err, out_file_type);
+      success = FALSE;
       goto out;
     }
   } else {
+    /* Set up to print packet information. */
     if (print_packet_info) {
       if (!write_preamble(cf)) {
-        err = errno;
-        show_print_file_io_error(err);
+        show_print_file_io_error(errno);
+        success = FALSE;
         goto out;
       }
     }
@@ -3066,7 +3173,7 @@ read_cap_file(capture_file *cf, char *save_file, int out_file_type,
        *    on the first pass.
        */
       create_proto_tree =
-        (cf->rfcode != NULL || cf->dfcode != NULL || postdissectors_want_hfids());
+        (cf->rfcode != NULL || cf->dfcode != NULL || postdissectors_want_hfids() || dissect_color);
 
       tshark_debug("tshark: create_proto_tree = %s", create_proto_tree ? "TRUE" : "FALSE");
 
@@ -3093,6 +3200,20 @@ read_cap_file(capture_file *cf, char *save_file, int out_file_type,
       }
     }
 
+    /*
+     * If we got a read error on the first pass, remember the error, so
+     * but do the second pass, so we can at least process the packets we
+     * read, and then report the first-pass error after the second pass
+     * (and before we report any second-pass errors), so all the the
+     * errors show up at the end.
+     */
+    if (err != 0) {
+      err_pass1 = err;
+      err_info_pass1 = err_info;
+      err = 0;
+      err_info = NULL;
+    }
+
     if (edt) {
       epan_dissect_free(edt);
       edt = NULL;
@@ -3129,7 +3250,7 @@ read_cap_file(capture_file *cf, char *save_file, int out_file_type,
        */
       create_proto_tree =
         (cf->dfcode || print_details || filtering_tap_listeners ||
-         (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo));
+         (tap_flags & TL_REQUIRES_PROTO_TREE) || have_custom_cols(&cf->cinfo) || dissect_color);
 
       tshark_debug("tshark: create_proto_tree = %s", create_proto_tree ? "TRUE" : "FALSE");
 
@@ -3184,12 +3305,10 @@ read_cap_file(capture_file *cf, char *save_file, int out_file_type,
   else {
     /* !perform_two_pass_analysis */
     framenum = 0;
-
+    gboolean create_proto_tree = FALSE;
     tshark_debug("tshark: perform one pass analysis, do_dissection=%s", do_dissection ? "TRUE" : "FALSE");
 
     if (do_dissection) {
-      gboolean create_proto_tree;
-
       /*
        * Determine whether we need to create a protocol tree.
        * We do if:
@@ -3213,7 +3332,7 @@ read_cap_file(capture_file *cf, char *save_file, int out_file_type,
       create_proto_tree =
         (cf->rfcode || cf->dfcode || print_details || filtering_tap_listeners ||
           (tap_flags & TL_REQUIRES_PROTO_TREE) || postdissectors_want_hfids() ||
-          have_custom_cols(&cf->cinfo))
+          have_custom_cols(&cf->cinfo) || dissect_color);
 
       tshark_debug("tshark: create_proto_tree = %s", create_proto_tree ? "TRUE" : "FALSE");
 
@@ -3229,6 +3348,8 @@ read_cap_file(capture_file *cf, char *save_file, int out_file_type,
 
       tshark_debug("tshark: processing packet #%d", framenum);
 
+      reset_epan_mem(cf, edt, create_proto_tree, print_packet_info && print_details);
+
       if (process_packet_single_pass(cf, edt, data_offset, wtap_phdr(cf->wth),
                                      wtap_buf_ptr(cf->wth), tap_flags)) {
         /* Either there's no read filtering or this packet passed the
@@ -3269,7 +3390,7 @@ read_cap_file(capture_file *cf, char *save_file, int out_file_type,
 
   wtap_phdr_cleanup(&phdr);
 
-  if (err != 0) {
+  if (err != 0 || err_pass1 != 0) {
     tshark_debug("tshark: something failed along the line (%d)", err);
     /*
      * Print a message noting that the read failed somewhere along the line.
@@ -3295,29 +3416,35 @@ read_cap_file(capture_file *cf, char *save_file, int out_file_type,
       }
     }
 #endif
-    cfile_read_failure_message("TShark", cf->filename, err, err_info);
-    if (save_file != NULL) {
-      /* Now close the capture file. */
-      if (!wtap_dump_close(pdh, &err))
-        cfile_close_failure_message(save_file, err);
+    if (err_pass1 != 0) {
+      /* Error on pass 1 of two-pass processing. */
+      cfile_read_failure_message("TShark", cf->filename, err_pass1,
+                                 err_info_pass1);
     }
-  } else {
-    if (save_file != NULL) {
-      if (pdh && out_file_name_res) {
-        if (!wtap_dump_set_addrinfo_list(pdh, get_addrinfo_list())) {
-          cmdarg_err("The file format \"%s\" doesn't support name resolution information.",
-                     wtap_file_type_subtype_short_string(out_file_type));
-        }
+    if (err != 0) {
+      /* Error on pass 2 of two-pass processing or on the only pass of
+         one-pass processing. */
+      cfile_read_failure_message("TShark", cf->filename, err, err_info);
+    }
+    success = FALSE;
+  }
+  if (save_file != NULL) {
+    if (pdh && out_file_name_res) {
+      if (!wtap_dump_set_addrinfo_list(pdh, get_addrinfo_list())) {
+        cmdarg_err("The file format \"%s\" doesn't support name resolution information.",
+                   wtap_file_type_subtype_short_string(out_file_type));
       }
-      /* Now close the capture file. */
-      if (!wtap_dump_close(pdh, &err))
-        cfile_close_failure_message(save_file, err);
-    } else {
-      if (print_packet_info) {
-        if (!write_finale()) {
-          err = errno;
-          show_print_file_io_error(err);
-        }
+    }
+    /* Now close the capture file. */
+    if (!wtap_dump_close(pdh, &err)) {
+      cfile_close_failure_message(save_file, err);
+      success = FALSE;
+    }
+  } else {
+    if (print_packet_info) {
+      if (!write_finale()) {
+        show_print_file_io_error(errno);
+        success = FALSE;
       }
     }
   }
@@ -3329,7 +3456,7 @@ out:
   wtap_block_array_free(shb_hdrs);
   wtap_block_array_free(nrb_hdrs);
 
-  return err;
+  return success;
 }
 
 static gboolean
@@ -3392,6 +3519,11 @@ process_packet_single_pass(capture_file *cf, epan_dissect_t *edt, gint64 offset,
       ref = &ref_frame;
     }
 
+    if (dissect_color) {
+      color_filters_prime_edt(edt);
+      fdata.flags.need_colorize = 1;
+    }
+
     epan_dissect_run_with_taps(edt, cf->cd_t, whdr, frame_tvbuff_new(&fdata, pd), &fdata, cinfo);
 
     /* Run the filter if we have it. */
@@ -3406,6 +3538,7 @@ process_packet_single_pass(capture_file *cf, epan_dissect_t *edt, gint64 offset,
     if (print_packet_info) {
       /* We're printing packet information; print the information for
          this packet. */
+      g_assert(edt);
       print_packet(cf, edt);
 
       /* If we're doing "line-buffering", flush the standard output
@@ -3521,7 +3654,7 @@ put_string_spaces(char *dest, const char *str, size_t str_len, size_t str_with_s
 }
 
 static gboolean
-print_columns(capture_file *cf)
+print_columns(capture_file *cf, const epan_dissect_t *edt)
 {
   char   *line_bufp;
   int     i;
@@ -3530,10 +3663,15 @@ print_columns(capture_file *cf)
   size_t  col_len;
   col_item_t* col_item;
   gchar str_format[11];
+  const color_filter_t *color_filter = NULL;
 
   line_bufp = get_line_buf(256);
   buf_offset = 0;
   *line_bufp = '\0';
+
+  if (dissect_color)
+    color_filter = edt->pi.fd->color_filter;
+
   for (i = 0; i < cf->cinfo.num_cols; i++) {
     col_item = &cf->cinfo.columns[i];
     /* Skip columns not marked as visible. */
@@ -3628,7 +3766,7 @@ print_columns(capture_file *cf)
         case COL_DEF_DST:
         case COL_RES_DST:
         case COL_UNRES_DST:
-          g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_RIGHTWARDS_ARROW, delimiter_char);
+          g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_RIGHTWARDS_ARROW, delimiter_char);
           put_string(line_bufp + buf_offset, str_format, 5);
           buf_offset += 5;
           break;
@@ -3648,7 +3786,7 @@ print_columns(capture_file *cf)
         case COL_DEF_DL_DST:
         case COL_RES_DL_DST:
         case COL_UNRES_DL_DST:
-          g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_RIGHTWARDS_ARROW, delimiter_char);
+          g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_RIGHTWARDS_ARROW, delimiter_char);
           put_string(line_bufp + buf_offset, str_format, 5);
           buf_offset += 5;
           break;
@@ -3668,7 +3806,7 @@ print_columns(capture_file *cf)
         case COL_DEF_NET_DST:
         case COL_RES_NET_DST:
         case COL_UNRES_NET_DST:
-          g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_RIGHTWARDS_ARROW, delimiter_char);
+          g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_RIGHTWARDS_ARROW, delimiter_char);
           put_string(line_bufp + buf_offset, str_format, 5);
           buf_offset += 5;
           break;
@@ -3688,7 +3826,7 @@ print_columns(capture_file *cf)
         case COL_DEF_SRC:
         case COL_RES_SRC:
         case COL_UNRES_SRC:
-          g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_LEFTWARDS_ARROW, delimiter_char);
+          g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_LEFTWARDS_ARROW, delimiter_char);
           put_string(line_bufp + buf_offset, str_format, 5);
           buf_offset += 5;
           break;
@@ -3708,7 +3846,7 @@ print_columns(capture_file *cf)
         case COL_DEF_DL_SRC:
         case COL_RES_DL_SRC:
         case COL_UNRES_DL_SRC:
-          g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_LEFTWARDS_ARROW, delimiter_char);
+          g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_LEFTWARDS_ARROW, delimiter_char);
           put_string(line_bufp + buf_offset, str_format, 5);
           buf_offset += 5;
           break;
@@ -3728,7 +3866,7 @@ print_columns(capture_file *cf)
         case COL_DEF_NET_SRC:
         case COL_RES_NET_SRC:
         case COL_UNRES_NET_SRC:
-          g_snprintf(str_format, sizeof(str_format), " %s%s", UTF8_LEFTWARDS_ARROW, delimiter_char);
+          g_snprintf(str_format, sizeof(str_format), "%s%s%s", delimiter_char, UTF8_LEFTWARDS_ARROW, delimiter_char);
           put_string(line_bufp + buf_offset, str_format, 5);
           buf_offset += 5;
           break;
@@ -3747,14 +3885,16 @@ print_columns(capture_file *cf)
       }
     }
   }
-  return print_line(print_stream, 0, line_bufp);
+
+  if (dissect_color && color_filter != NULL)
+    return print_line_color(print_stream, 0, line_bufp, &color_filter->fg_color, &color_filter->bg_color);
+  else
+    return print_line(print_stream, 0, line_bufp);
 }
 
 static gboolean
 print_packet(capture_file *cf, epan_dissect_t *edt)
 {
-  print_args_t print_args;
-
   if (print_summary || output_fields_has_cols(output_fields)) {
     /* Just fill in the columns. */
     epan_dissect_fill_in_columns(edt, FALSE, TRUE);
@@ -3764,12 +3904,12 @@ print_packet(capture_file *cf, epan_dissect_t *edt)
       switch (output_action) {
 
       case WRITE_TEXT:
-        if (!print_columns(cf))
+        if (!print_columns(cf, edt))
           return FALSE;
         break;
 
       case WRITE_XML:
-        write_psml_columns(edt, stdout);
+        write_psml_columns(edt, stdout, dissect_color);
         return !ferror(stdout);
       case WRITE_FIELDS: /*No non-verbose "fields" format */
       case WRITE_JSON:
@@ -3785,19 +3925,8 @@ print_packet(capture_file *cf, epan_dissect_t *edt)
     switch (output_action) {
 
     case WRITE_TEXT:
-      /* Only initialize the fields that are actually used in proto_tree_print.
-       * This is particularly important for .range, as that's heap memory which
-       * we would otherwise have to g_free().
-      print_args.to_file = TRUE;
-      print_args.format = print_format;
-      print_args.print_summary = print_summary;
-      print_args.print_formfeed = FALSE;
-      packet_range_init(&print_args.range, &cfile);
-      */
-      print_args.print_hex = print_hex;
-      print_args.print_dissections = print_details ? print_dissections_expanded : print_dissections_none;
-
-      if (!proto_tree_print(&print_args, edt, output_only_tables, print_stream))
+      if (!proto_tree_print(print_details ? print_dissections_expanded : print_dissections_none,
+                            print_hex, edt, output_only_tables, print_stream))
         return FALSE;
       if (!print_hex) {
         if (!print_line(print_stream, 0, separator))
@@ -3806,7 +3935,7 @@ print_packet(capture_file *cf, epan_dissect_t *edt)
       break;
 
     case WRITE_XML:
-      write_pdml_proto_tree(output_fields, protocolfilter, protocolfilter_flags, edt, stdout);
+      write_pdml_proto_tree(output_fields, protocolfilter, protocolfilter_flags, edt, stdout, dissect_color);
       printf("\n");
       return !ferror(stdout);
     case WRITE_FIELDS:
@@ -3814,20 +3943,18 @@ print_packet(capture_file *cf, epan_dissect_t *edt)
       printf("\n");
       return !ferror(stdout);
     case WRITE_JSON:
-      print_args.print_dissections = print_dissections_expanded;
-      print_args.print_hex = print_hex;
-      write_json_proto_tree(output_fields, &print_args, protocolfilter, protocolfilter_flags, edt, stdout);
-      printf("\n");
+      write_json_proto_tree(output_fields, print_dissections_expanded,
+                            print_hex, protocolfilter, protocolfilter_flags,
+                            edt, node_children_grouper, stdout);
       return !ferror(stdout);
     case WRITE_JSON_RAW:
-      print_args.print_dissections = print_dissections_none;
-      print_args.print_hex = TRUE;
-      write_json_proto_tree(output_fields, &print_args, protocolfilter, protocolfilter_flags, edt, stdout);
-      printf("\n");
+      write_json_proto_tree(output_fields, print_dissections_none, TRUE,
+                            protocolfilter, protocolfilter_flags,
+                            edt, node_children_grouper, stdout);
       return !ferror(stdout);
     case WRITE_EK:
-      print_args.print_hex = print_hex;
-      write_ek_proto_tree(output_fields, &print_args, protocolfilter, protocolfilter_flags, edt, stdout);
+      write_ek_proto_tree(output_fields, print_hex, protocolfilter,
+                          protocolfilter_flags, edt, stdout);
       return !ferror(stdout);
     }
   }
@@ -3919,12 +4046,6 @@ cf_open(capture_file *cf, const char *fname, unsigned int type, gboolean is_temp
   cf->drops_known = FALSE;
   cf->drops     = 0;
   cf->snap      = wtap_snapshot_length(cf->wth);
-  if (cf->snap == 0) {
-    /* Snapshot length not known. */
-    cf->has_snap = FALSE;
-    cf->snap = WTAP_MAX_PACKET_SIZE;
-  } else
-    cf->has_snap = TRUE;
   nstime_set_zero(&cf->elapsed_time);
   ref = NULL;
   prev_dis = NULL;
@@ -4009,6 +4130,21 @@ write_failure_message(const char *filename, int err)
              filename, g_strerror(err));
 }
 
+static void reset_epan_mem(capture_file *cf,epan_dissect_t *edt, gboolean tree, gboolean visual)
+{
+  if (!epan_auto_reset || (cf->count < epan_auto_reset_count))
+    return;
+
+  fprintf(stderr, "resetting session.\n");
+
+  epan_dissect_cleanup(edt);
+  epan_free(cf->epan);
+
+  cf->epan = tshark_epan_new(cf);
+  epan_dissect_init(edt, cf->epan, tree, visual);
+  cf->count = 0;
+}
+
 /*
  * Report additional information for an error in command-line arguments.
  */