From Martin Kaiser via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6838
[obnox/wireshark/wip.git] / tshark.c
index e5c7d3436d8660e919bdad05b9e9308e249be86c..3707f08004d9f548ff2430dae198aa0c7f7876de 100644 (file)
--- a/tshark.c
+++ b/tshark.c
@@ -70,7 +70,7 @@
 #include <epan/column.h>
 #include "print.h"
 #include <epan/addr_resolv.h>
-#include "util.h"
+#include "ui/util.h"
 #include "clopts_common.h"
 #include "console_io.h"
 #include "cmdarg_err.h"
 #include "capture-pcap-util.h"
 #ifdef _WIN32
 #include "capture-wpcap.h"
-#include "capture_errs.h"
 #include <wsutil/unicode-utils.h>
 #endif /* _WIN32 */
 #include "capture_sync.h"
 #endif /* HAVE_LIBPCAP */
 #include "log.h"
 #include <epan/funnel.h>
+#include "capture_opts.h"
 
 /*
  * This is the template for the decode as option; it is shared between the
@@ -284,13 +284,15 @@ print_usage(gboolean print_ver)
   fprintf(output, "  -d %s ...\n", decode_as_arg_template);
   fprintf(output, "                           \"Decode As\", see the man page for details\n");
   fprintf(output, "                           Example: tcp.port==8888,http\n");
+  fprintf(output, "  -H <hosts file>          read a list of entries from a hosts file, which will\n");
+  fprintf(output, "                           then be written to a capture file. (Implies -W n)\n");
 
   /*fprintf(output, "\n");*/
   fprintf(output, "Output:\n");
   fprintf(output, "  -w <outfile|->           write packets to a pcap-format file named \"outfile\"\n");
   fprintf(output, "                           (or to the standard output for \"-\")\n");
   fprintf(output, "  -C <config profile>      start with specified configuration profile\n");
-  fprintf(output, "  -F <output file type>    set the output file type, default is libpcap\n");
+  fprintf(output, "  -F <output file type>    set the output file type, default is pcapng\n");
   fprintf(output, "                           an empty \"-F\" option will list the file types\n");
   fprintf(output, "  -V                       add output of packet tree        (Packet Details)\n");
   fprintf(output, "  -O <protocols>           Only show packet details of these protocols, comma\n");
@@ -313,6 +315,8 @@ print_usage(gboolean print_ver)
   fprintf(output, "  -u s|hms                 output format of seconds (def: s: seconds)\n");
   fprintf(output, "  -l                       flush standard output after each packet\n");
   fprintf(output, "  -q                       be more quiet on stdout (e.g. when using statistics)\n");
+  fprintf(output, "  -W n                     Save extra information in the file, if supported.\n");
+  fprintf(output, "                           n = write network address resolution information\n");
   fprintf(output, "  -X <key>:<value>         eXtension options, see the man page for details\n");
   fprintf(output, "  -z <statistics>          various statistics, see the man page for details\n");
 
@@ -345,7 +349,9 @@ glossary_option_help(void)
   fprintf(output, "  -G fields3               dump glossary in format 3 and exit\n");
   fprintf(output, "  -G protocols             dump protocols in registration database and exit\n");
   fprintf(output, "  -G values                dump value, range, true/false strings and exit\n");
+  fprintf(output, "  -G ftypes                dump field type basic and descriptive names\n");
   fprintf(output, "  -G decodes               dump \"layer type\"/\"decode as\" associations and exit\n");
+  fprintf(output, "  -G heuristic-decodes     dump heuristic dissector tables\n");
   fprintf(output, "\n");
   fprintf(output, "Preference reports:\n");
   fprintf(output, "  -G defaultprefs          dump default preferences and exit\n");
@@ -803,7 +809,7 @@ main(int argc, char *argv[])
   int                  gdp_open_errno, gdp_read_errno;
   int                  dp_open_errno, dp_read_errno;
   int                  err;
-  int                  exit_status = 0;
+  volatile int         exit_status = 0;
 #ifdef HAVE_LIBPCAP
   gboolean             list_link_layer_types = FALSE;
   gboolean             start_capture = FALSE;
@@ -817,12 +823,13 @@ main(int argc, char *argv[])
 #endif
   gboolean             quiet = FALSE;
 #ifdef PCAP_NG_DEFAULT
-  int                  out_file_type = WTAP_FILE_PCAPNG;
+  volatile int         out_file_type = WTAP_FILE_PCAPNG;
 #else
-  int                  out_file_type = WTAP_FILE_PCAP;
+  volatile int         out_file_type = WTAP_FILE_PCAP;
 #endif
-  gboolean             out_file_name_res = FALSE;
-  gchar               *cf_name = NULL, *rfilter = NULL;
+  volatile gboolean    out_file_name_res = FALSE;
+  gchar               *volatile cf_name = NULL;
+  gchar               *rfilter = NULL;
 #ifdef HAVE_PCAP_OPEN_DEAD
   struct bpf_program   fcode;
 #endif
@@ -855,6 +862,9 @@ main(int argc, char *argv[])
 
 #ifdef _WIN32
   arg_list_utf_16to8(argc, argv);
+#if !GLIB_CHECK_VERSION(2,31,0)
+  g_thread_init(NULL);
+#endif
 #endif /* _WIN32 */
 
   /*
@@ -985,8 +995,12 @@ main(int argc, char *argv[])
         proto_registrar_dump_protocols();
       else if (strcmp(argv[2], "values") == 0)
         proto_registrar_dump_values();
+      else if (strcmp(argv[2], "ftypes") == 0)
+        proto_registrar_dump_ftypes();
       else if (strcmp(argv[2], "decodes") == 0)
         dissector_dump_decodes();
+      else if (strcmp(argv[2], "heuristic-decodes") == 0)
+        dissector_dump_heur_decodes();
       else if (strcmp(argv[2], "defaultprefs") == 0)
         write_prefs(NULL);
       else if (strcmp(argv[2], "plugins") == 0)
@@ -1124,6 +1138,7 @@ main(int argc, char *argv[])
       if (if_list == NULL) {
         switch (err) {
         case CANT_GET_INTERFACE_LIST:
+        case DONT_HAVE_PCAP:
           cmdarg_err("%s", err_str);
           g_free(err_str);
           break;
@@ -1740,13 +1755,26 @@ main(int argc, char *argv[])
     }
 
     /* Process the packets in the file */
+    TRY {
 #ifdef HAVE_LIBPCAP
-    err = load_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);
+      err = load_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 = load_cap_file(&cfile, NULL, out_file_type, out_file_name_res, 0, 0);
+      err = load_cap_file(&cfile, NULL, out_file_type, out_file_name_res, 0, 0);
 #endif
+    }
+    CATCH(OutOfMemoryError) {
+      fprintf(stderr,
+              "Out Of Memory!\n"
+              "\n"
+              "Sorry, but TShark has to terminate now!\n"
+              "\n"
+              "Some infos / workarounds can be found at:\n"
+              "http://wiki.wireshark.org/KnownBugs/OutOfMemory\n");
+      err = ENOMEM;
+    }
+    ENDTRY;
     if (err != 0) {
       /* We still dump out the results of taps, etc., as we might have
          read some packets; however, we exit with an error status. */
@@ -1757,19 +1785,6 @@ main(int argc, char *argv[])
        (or get a list of link-layer types for a live capture device);
        do we have support for live captures? */
 #ifdef HAVE_LIBPCAP
-
-#ifdef _WIN32
-    if (!has_wpcap) {
-      char *detailed_err;
-
-      cmdarg_err("WinPcap couldn't be found.");
-      detailed_err = cant_load_winpcap_err("TShark");
-      cmdarg_err_cont("%s", detailed_err);
-      g_free(detailed_err);
-      return 2;
-    }
-#endif
-
     /* trim the interface name and exit if that failed */
     if (!capture_opts_trim_iface(&global_capture_opts,
         (prefs_p->capture_device) ? get_if_name(prefs_p->capture_device) : NULL)) {
@@ -2128,27 +2143,40 @@ capture(void)
 
   loop_running = TRUE;
 
-  while (loop_running)
+  TRY
   {
+    while (loop_running)
+    {
 #ifdef USE_TSHARK_SELECT
-    ret = select(pipe_input.source+1, &readfds, NULL, NULL, NULL);
+      ret = select(pipe_input.source+1, &readfds, NULL, NULL, NULL);
 
-    if (ret == -1)
-    {
-      perror("select()");
-      return TRUE;
-    } else if (ret == 1) {
+      if (ret == -1)
+      {
+        perror("select()");
+        return TRUE;
+      } else if (ret == 1) {
 #endif
-      /* Call the real handler */
-      if (!pipe_input.input_cb(pipe_input.source, pipe_input.user_data)) {
-        g_log(NULL, G_LOG_LEVEL_DEBUG, "input pipe closed");
-        return FALSE;
-      }
+        /* Call the real handler */
+        if (!pipe_input.input_cb(pipe_input.source, pipe_input.user_data)) {
+          g_log(NULL, G_LOG_LEVEL_DEBUG, "input pipe closed");
+          return FALSE;
+        }
 #ifdef USE_TSHARK_SELECT
-    }
+      }
 #endif
+    }
   }
-
+  CATCH(OutOfMemoryError) {
+    fprintf(stderr,
+            "Out Of Memory!\n"
+            "\n"
+            "Sorry, but TShark has to terminate now!\n"
+            "\n"
+            "Some infos / workarounds can be found at:\n"
+            "http://wiki.wireshark.org/KnownBugs/OutOfMemory\n");
+    exit(1);
+  }
+  ENDTRY;
   return TRUE;
 }
 
@@ -2642,15 +2670,24 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
   gint         linktype;
   int          snapshot_length;
   wtap_dumper *pdh;
+  guint32      framenum;
   int          err;
   gchar        *err_info = NULL;
   gint64       data_offset;
   char         *save_file_string = NULL;
   gboolean     filtering_tap_listeners;
   guint        tap_flags;
+  wtapng_section_t *shb_hdr;
+  wtapng_iface_descriptions_t *idb_inf;
 
+  shb_hdr = wtap_file_get_shb_info(cf->wth);
+  idb_inf = wtap_file_get_idb_info(cf->wth);
 #ifdef PCAP_NG_DEFAULT
-  linktype = WTAP_ENCAP_PER_PACKET;
+  if (idb_inf->number_of_interfaces > 0) {
+    linktype = WTAP_ENCAP_PER_PACKET;
+  } else {
+    linktype = wtap_file_encap(cf->wth);
+  }
 #else
   linktype = wtap_file_encap(cf->wth);
 #endif
@@ -2664,8 +2701,8 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
       /* Snapshot length of input file not known. */
       snapshot_length = WTAP_MAX_PACKET_SIZE;
     }
-    pdh = wtap_dump_open(save_file, out_file_type, linktype, snapshot_length,
-                         FALSE /* compressed */, &err);
+    pdh = wtap_dump_open_ng(save_file, out_file_type, linktype, snapshot_length,
+        FALSE /* compressed */, shb_hdr, idb_inf, &err);
 
     if (pdh == NULL) {
       /* We couldn't set up to write to the capture file. */
@@ -2677,8 +2714,8 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
 
       case WTAP_ERR_UNSUPPORTED_ENCAP:
       case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
-        cmdarg_err("The capture file being read can't be written in "
-          "the format \"%s\".", wtap_encap_short_string(linktype));
+        cmdarg_err("The capture file being read can't be written as a "
+          "\"%s\" file.", wtap_file_type_short_string(out_file_type));
         break;
 
       case WTAP_ERR_CANT_OPEN:
@@ -2723,7 +2760,6 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
   tap_flags = union_of_tap_listener_flags();
 
   if (perform_two_pass_analysis) {
-    guint32 framenum;
     frame_data *fdata;
     int old_max_packet_count = max_packet_count;
 
@@ -2769,7 +2805,26 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
                            wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
                            &err)) {
               /* Error writing to a capture file */
-              show_capture_file_io_error(save_file, err, FALSE);
+              switch (err) {
+
+              case WTAP_ERR_UNSUPPORTED_ENCAP:
+                /*
+                 * This is a problem with the particular frame we're writing;
+                 * note that, and give the frame number.
+                 *
+                 * XXX - framenum is not necessarily the frame number in
+                 * the input file if there was a read filter.
+                 */
+                fprintf(stderr,
+                        "Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.\n",
+                        framenum, cf->filename,
+                        wtap_file_type_short_string(out_file_type));
+                break;
+
+              default:
+                show_capture_file_io_error(save_file, err, FALSE);
+                break;
+              }
               wtap_dump_close(pdh, &err);
               exit(2);
             }
@@ -2788,7 +2843,10 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
     }
   }
   else {
+    framenum = 0;
     while (wtap_read(cf->wth, &err, &err_info, &data_offset)) {
+      framenum++;
+
       if (process_packet(cf, data_offset, wtap_phdr(cf->wth),
                          wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
                          filtering_tap_listeners, tap_flags)) {
@@ -2800,7 +2858,23 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
                          wtap_pseudoheader(cf->wth), wtap_buf_ptr(cf->wth),
                          &err)) {
             /* Error writing to a capture file */
-            show_capture_file_io_error(save_file, err, FALSE);
+            switch (err) {
+
+            case WTAP_ERR_UNSUPPORTED_ENCAP:
+              /*
+               * This is a problem with the particular frame we're writing;
+               * note that, and give the frame number.
+               */
+              fprintf(stderr,
+                      "Frame %u of \"%s\" has a network type that can't be saved in a \"%s\" file.\n",
+                      framenum, cf->filename,
+                      wtap_file_type_short_string(out_file_type));
+              break;
+
+            default:
+              show_capture_file_io_error(save_file, err, FALSE);
+              break;
+            }
             wtap_dump_close(pdh, &err);
             exit(2);
           }
@@ -2845,6 +2919,12 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
 #endif
     switch (err) {
 
+    case WTAP_ERR_UNSUPPORTED:
+      cmdarg_err("The file \"%s\" contains record data that TShark doesn't support.\n(%s)",
+                 cf->filename, err_info);
+      g_free(err_info);
+      break;
+
     case WTAP_ERR_UNSUPPORTED_ENCAP:
       cmdarg_err("The file \"%s\" has a packet with a network type that TShark doesn't support.\n(%s)",
                  cf->filename, err_info);
@@ -2861,7 +2941,7 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
                  cf->filename);
       break;
 
-    case WTAP_ERR_BAD_RECORD:
+    case WTAP_ERR_BAD_FILE:
       cmdarg_err("The file \"%s\" appears to be damaged or corrupt.\n(%s)",
                  cf->filename, err_info);
       g_free(err_info);
@@ -3551,6 +3631,11 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
       errmsg = "The file \"%s\" is a \"special file\" or socket or other non-regular file.";
       break;
 
+    case WTAP_ERR_RANDOM_OPEN_PIPE:
+      /* Seen only when opening a capture file for reading. */
+      errmsg = "The file \"%s\" is a pipe or FIFO; TShark can't read pipe or FIFO files in two-pass mode.";
+      break;
+
     case WTAP_ERR_FILE_UNKNOWN_FORMAT:
       /* Seen only when opening a capture file for reading. */
       errmsg = "The file \"%s\" isn't a capture file in a format TShark understands.";
@@ -3568,8 +3653,8 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
     case WTAP_ERR_CANT_WRITE_TO_PIPE:
       /* Seen only when opening a capture file for writing. */
       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
-                 "The file \"%%s\" is a pipe, and %s capture files can't be "
-                 "written to a pipe.", wtap_file_type_string(file_type));
+                 "The file \"%%s\" is a pipe, and \"%s\" capture files can't be "
+                 "written to a pipe.", wtap_file_type_short_string(file_type));
       errmsg = errmsg_errno;
       break;
 
@@ -3579,25 +3664,30 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
       break;
 
     case WTAP_ERR_UNSUPPORTED_ENCAP:
-      if (for_writing)
-        errmsg = "TShark can't save this capture in that format.";
-      else {
+      if (for_writing) {
+        g_snprintf(errmsg_errno, sizeof(errmsg_errno),
+                   "TShark can't save this capture as a \"%s\" file.",
+                   wtap_file_type_short_string(file_type));
+      } else {
         g_snprintf(errmsg_errno, sizeof(errmsg_errno),
                  "The file \"%%s\" is a capture for a network type that TShark doesn't support.\n"
                  "(%s)", err_info);
         g_free(err_info);
-        errmsg = errmsg_errno;
       }
+      errmsg = errmsg_errno;
       break;
 
     case WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED:
-      if (for_writing)
-        errmsg = "TShark can't save this capture in that format.";
-      else
+      if (for_writing) {
+        g_snprintf(errmsg_errno, sizeof(errmsg_errno),
+                   "TShark can't save this capture as a \"%s\" file.",
+                   wtap_file_type_short_string(file_type));
+        errmsg = errmsg_errno;
+      } else
         errmsg = "The file \"%s\" is a capture for a network type that TShark doesn't support.";
       break;
 
-    case WTAP_ERR_BAD_RECORD:
+    case WTAP_ERR_BAD_FILE:
       /* Seen only when opening a capture file for reading. */
       g_snprintf(errmsg_errno, sizeof(errmsg_errno),
                "The file \"%%s\" appears to be damaged or corrupt.\n"
@@ -3622,6 +3712,10 @@ cf_open_error_message(int err, gchar *err_info, gboolean for_writing,
       errmsg = "A full header couldn't be written to the file \"%s\".";
       break;
 
+    case WTAP_ERR_COMPRESSION_NOT_SUPPORTED:
+      errmsg = "This file type cannot be written as a compressed file.";
+      break;
+
     case WTAP_ERR_DECOMPRESS:
       /* Seen only when opening a capture file for reading. */
       g_snprintf(errmsg_errno, sizeof(errmsg_errno),