Move ip6_to_str_buf() to to_str.c and make it take the buffer length.
[metze/wireshark/wip.git] / tshark.c
index 67e64ae9f045ac026873b310a89d944c027d8404..96f15556784c6f2b527003c9ee4f61383c7c2ad0 100644 (file)
--- a/tshark.c
+++ b/tshark.c
 #include <signal.h>
 #endif
 
-#ifdef HAVE_LIBZ
-#include <zlib.h>      /* to get the libz version number */
-#endif
-
 #ifdef HAVE_LIBCAP
 # include <sys/capability.h>
 #endif
@@ -65,8 +61,9 @@
 #include <wsutil/file_util.h>
 #include <wsutil/privileges.h>
 #include <wsutil/report_err.h>
-#include <wsutil/ws_diag_control.h>
-#include <wsutil/ws_version_info.h>
+#include <ws_version_info.h>
+#include <wiretap/wtap_opttypes.h>
+#include <wiretap/pcapng.h>
 
 #include "globals.h"
 #include <epan/timestamp.h>
 #endif
 #include "ui/util.h"
 #include "ui/ui_util.h"
+#include "ui/decode_as_utils.h"
 #include "ui/cli/tshark-tap.h"
+#include "ui/tap_export_pdu.h"
 #include "register.h"
+#include "filter_files.h"
 #include <epan/epan_dissect.h>
 #include <epan/tap.h>
 #include <epan/stat_tap_ui.h>
@@ -94,6 +94,7 @@
 #include <epan/srt_table.h>
 #include <epan/rtd_table.h>
 #include <epan/ex-opt.h>
+#include <epan/exported_pdu.h>
 
 #if defined(HAVE_HEIMDAL_KERBEROS) || defined(HAVE_MIT_KERBEROS)
 #include <epan/asn1.h>
 #endif /* _WIN32 */
 #include <capchild/capture_session.h>
 #include <capchild/capture_sync.h>
+#include <capture_info.h>
 #endif /* HAVE_LIBPCAP */
 #include "log.h"
 #include <epan/funnel.h>
 
 #include <wsutil/str_util.h>
+#include <wsutil/utf8_entities.h>
 
 #ifdef HAVE_PLUGINS
 #include <wsutil/plugins.h>
@@ -184,6 +187,7 @@ static gboolean print_packet_counts;
 
 static capture_options global_capture_opts;
 static capture_session global_capture_session;
+static info_data_t global_info_data;
 
 #ifdef SIGINFO
 static gboolean infodelay;      /* if TRUE, don't print capture info in SIGINFO handler */
@@ -374,6 +378,7 @@ print_usage(FILE *output)
   fprintf(output, "                           _ws.col.Info)\n");
   fprintf(output, "                           this option can be repeated to print multiple fields\n");
   fprintf(output, "  -E<fieldsoption>=<value> set options for output when -Tfields selected:\n");
+  fprintf(output, "     bom=y|n               print a UTF-8 BOM\n");
   fprintf(output, "     header=y|n            switch headers on and off\n");
   fprintf(output, "     separator=/t|/s|<char> select tab, space, printable character as separator\n");
   fprintf(output, "     occurrence=f|l|a      print first, last or all occurrences of each field\n");
@@ -389,6 +394,7 @@ print_usage(FILE *output)
   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, "  -U tap_name              PDUs export mode, see the man page for details\n");
   fprintf(output, "  -z <statistics>          various statistics, see the man page for details\n");
   fprintf(output, "  --capture-comment <comment>\n");
   fprintf(output, "                           add a capture comment to the newly created\n");
@@ -915,19 +921,6 @@ get_tshark_compiled_version_info(GString *str)
 {
   /* Capture libraries */
   get_compiled_caplibs_version(str);
-
-  /* LIBZ */
-  g_string_append(str, ", ");
-#ifdef HAVE_LIBZ
-  g_string_append(str, "with libz ");
-#ifdef ZLIB_VERSION
-  g_string_append(str, ZLIB_VERSION);
-#else /* ZLIB_VERSION */
-  g_string_append(str, "(version unknown)");
-#endif /* ZLIB_VERSION */
-#else /* HAVE_LIBZ */
-  g_string_append(str, "without libz");
-#endif /* HAVE_LIBZ */
 }
 
 static void
@@ -939,11 +932,6 @@ get_tshark_runtime_version_info(GString *str)
     get_runtime_caplibs_version(str);
 #endif
 
-    /* zlib */
-#if defined(HAVE_LIBZ) && !defined(_WIN32)
-    g_string_append_printf(str, ", with libz %s", zlibVersion());
-#endif
-
     /* stuff used by libwireshark */
     epan_get_runtime_version_info(str);
 }
@@ -969,10 +957,12 @@ main(int argc, char *argv[])
 
   char                *gpf_path, *pf_path;
   char                *gdp_path, *dp_path;
+  char                *cf_path;
   int                  gpf_open_errno, gpf_read_errno;
   int                  pf_open_errno, pf_read_errno;
   int                  gdp_open_errno, gdp_read_errno;
   int                  dp_open_errno, dp_read_errno;
+  int                  cf_open_errno;
   int                  err;
   volatile int         exit_status = 0;
 #ifdef HAVE_LIBPCAP
@@ -1008,6 +998,8 @@ main(int argc, char *argv[])
   GSList              *disable_protocol_slist = NULL;
   GSList              *enable_heur_slist = NULL;
   GSList              *disable_heur_slist = NULL;
+  gchar               *volatile pdu_export_arg = NULL;
+  exp_pdu_t            exp_pdu_tap_data;
 
 /*
  * The leading + ensures that getopt_long() does not permute the argv[]
@@ -1028,7 +1020,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 "C:d:e:E:F:gG:hH:" "K:lnN:o:O:PqQr:R:S:t:T:u:vVw:W:xX:Y:z:"
+#define OPTSTRING "+2" OPTSTRING_CAPTURE_COMMON "C:d:e:E:F:gG:hH:" "K:lnN:o:O:PqQr:R:S:t:T:u:U:vVw:W:xX:Y:z:"
 
   static const char    optstring[] = OPTSTRING;
 
@@ -1059,7 +1051,7 @@ main(int argc, char *argv[])
   /*
    * Attempt to get the pathname of the executable file.
    */
-  init_progfile_dir_error = init_progfile_dir(argv[0], (void *)main);
+  init_progfile_dir_error = init_progfile_dir(argv[0], main);
   if (init_progfile_dir_error != NULL) {
     fprintf(stderr, "tshark: Can't get pathname of tshark program: %s.\n",
             init_progfile_dir_error);
@@ -1095,6 +1087,9 @@ main(int argc, char *argv[])
   g_string_free(comp_info_str, TRUE);
   g_string_free(runtime_info_str, TRUE);
 
+  /* Fail sometimes. Useful for testing fuzz scripts. */
+  /* if (g_random_int_range(0, 100) < 5) abort(); */
+
   /*
    * In order to have the -X opts assigned before the wslua machine starts
    * we need to call getopt_long before epan_init() gets called.
@@ -1292,6 +1287,9 @@ main(int argc, char *argv[])
     return 0;
   }
 
+  /* load the decode as entries of this profile */
+  load_decode_as_entries();
+
   tshark_debug("tshark reading preferences");
 
   prefs_p = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
@@ -1319,6 +1317,13 @@ main(int argc, char *argv[])
     pf_path = NULL;
   }
 
+  read_filter_list(CFILTER_LIST, &cf_path, &cf_open_errno);
+  if (cf_path != NULL) {
+      cmdarg_err("Could not open your capture filter file\n\"%s\": %s.",
+          cf_path, g_strerror(cf_open_errno));
+      g_free(cf_path);
+  }
+
   /* Read the disabled protocols file. */
   read_disabled_protos_list(&gdp_path, &gdp_open_errno, &gdp_read_errno,
                             &dp_path, &dp_open_errno, &dp_read_errno);
@@ -1532,8 +1537,7 @@ main(int argc, char *argv[])
       if (badopt != '\0') {
         cmdarg_err("-N specifies unknown resolving option '%c'; valid options are:",
                    badopt);
-        cmdarg_err_cont("\t'C' to enable concurrent (asynchronous) DNS lookups\n"
-                        "\t'd' to enable address resolution from captured DNS packets\n"
+        cmdarg_err_cont("\t'd' to enable address resolution from captured DNS packets\n"
                         "\t'm' to enable MAC address resolution\n"
                         "\t'n' to enable network address resolution\n"
                         "\t'N' to enable using external resolvers (e.g., DNS)\n"
@@ -1668,6 +1672,20 @@ main(int argc, char *argv[])
         return 1;
       }
       break;
+    case 'U':        /* Export PDUs to file */
+    {
+        GSList *export_pdu_tap_name_list = NULL;
+
+        if (!*optarg) {
+            cmdarg_err("Tap name is required! Valid names are:");
+            for (export_pdu_tap_name_list = get_export_pdu_tap_list(); export_pdu_tap_name_list; export_pdu_tap_name_list = g_slist_next(export_pdu_tap_name_list)) {
+                cmdarg_err("%s\n", (const char*)(export_pdu_tap_name_list->data));
+            }
+            return 1;
+        }
+        pdu_export_arg = g_strdup(optarg);
+        break;
+    }
     case 'v':         /* Show version and exit */
       comp_info_str = get_compiled_version_info(get_tshark_compiled_version_info,
                                                 epan_get_compiled_version_info);
@@ -2166,6 +2184,55 @@ main(int argc, char *argv[])
     }
   }
 
+  /* PDU export requested. Take the ownership of the '-w' file, apply tap
+  * filters and start tapping. */
+  if (pdu_export_arg) {
+      const char *exp_pdu_filename;
+      const char *exp_pdu_tap_name = pdu_export_arg;
+      const char *exp_pdu_filter = dfilter; /* may be NULL to disable filter */
+      char       *exp_pdu_error;
+      int         exp_fd;
+
+      if (!cf_name) {
+          cmdarg_err("PDUs export requires a capture file (specify with -r).");
+          return 1;
+      }
+      /* Take ownership of the '-w' output file. */
+#ifdef HAVE_LIBPCAP
+      exp_pdu_filename = global_capture_opts.save_file;
+      global_capture_opts.save_file = NULL;
+#else
+      exp_pdu_filename = output_file_name;
+      output_file_name = NULL;
+#endif
+      if (exp_pdu_filename == NULL) {
+          cmdarg_err("PDUs export requires an output file (-w).");
+          return 1;
+      }
+
+      exp_pdu_error = exp_pdu_pre_open(exp_pdu_tap_name, exp_pdu_filter,
+          &exp_pdu_tap_data);
+      if (exp_pdu_error) {
+          cmdarg_err("Cannot register tap: %s", exp_pdu_error);
+          g_free(exp_pdu_error);
+          return 2;
+      }
+
+      exp_fd = ws_open(exp_pdu_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+      if (exp_fd == -1) {
+          cmdarg_err("%s: %s", exp_pdu_filename, file_open_error_message(errno, TRUE));
+          return 2;
+      }
+
+      /* Activate the export PDU tap */
+      err = exp_pdu_open(&exp_pdu_tap_data, exp_fd,
+          g_strdup_printf("Dump of PDUs from %s", cf_name));
+      if (err != 0) {
+          cmdarg_err("Failed to start the PDU export: %s", g_strerror(err));
+          return 2;
+      }
+  }
+
   /* We have to dissect each packet if:
 
         we're printing information about each packet;
@@ -2174,8 +2241,11 @@ main(int argc, char *argv[])
 
         we're using a display filter on the packets;
 
+        we're exporting PDUs;
+
         we're using any taps that need dissection. */
-  do_dissection = print_packet_info || rfcode || dfcode || tap_listeners_require_dissection();
+  do_dissection = print_packet_info || rfcode || dfcode || pdu_export_arg ||
+      tap_listeners_require_dissection();
   tshark_debug("tshark: do_dissection = %s", do_dissection ? "TRUE" : "FALSE");
 
   if (cf_name) {
@@ -2215,6 +2285,15 @@ main(int argc, char *argv[])
          read some packets; however, we exit with an error status. */
       exit_status = 2;
     }
+
+    if (pdu_export_arg) {
+        err = exp_pdu_close(&exp_pdu_tap_data);
+        if (err) {
+            cmdarg_err("%s", wtap_strerror(err));
+            exit_status = 2;
+        }
+        g_free(pdu_export_arg);
+    }
   } else {
     tshark_debug("tshark: no capture file specified");
     /* No capture file specified, so we're supposed to do a live capture
@@ -2283,9 +2362,9 @@ main(int argc, char *argv[])
      * suppress the information printed for each packet, but it'll
      * also suppress the packet counts.
      */
-    if (!isatty(fileno(stderr)))
+    if (!ws_isatty(ws_fileno(stderr)))
       print_packet_counts = FALSE;
-    else if (print_packet_info && isatty(fileno(stdout)))
+    else if (print_packet_info && ws_isatty(ws_fileno(stdout)))
       print_packet_counts = FALSE;
     else if (quiet)
       print_packet_counts = FALSE;
@@ -2562,7 +2641,7 @@ capture(void)
   fflush(stderr);
   g_string_free(str, TRUE);
 
-  ret = sync_pipe_start(&global_capture_opts, &global_capture_session, NULL);
+  ret = sync_pipe_start(&global_capture_opts, &global_capture_session, &global_info_data, NULL);
 
   if (!ret)
     return FALSE;
@@ -2985,7 +3064,7 @@ process_packet_first_pass(capture_file *cf, epan_dissect_t *edt,
      do a dissection and do so. */
   if (edt) {
     if (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
-        gbl_resolv_flags.transport_name || gbl_resolv_flags.concurrent_dns)
+        gbl_resolv_flags.transport_name)
       /* Grab any resolved addresses */
       host_name_lookup_process();
 
@@ -3058,7 +3137,7 @@ process_packet_second_pass(capture_file *cf, epan_dissect_t *edt, frame_data *fd
      do a dissection and do so. */
   if (edt) {
     if (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
-        gbl_resolv_flags.transport_name || gbl_resolv_flags.concurrent_dns)
+        gbl_resolv_flags.transport_name)
       /* Grab any resolved addresses */
       host_name_lookup_process();
 
@@ -3154,12 +3233,13 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
   char        *save_file_string = NULL;
   gboolean     filtering_tap_listeners;
   guint        tap_flags;
-  wtapng_section_t            *shb_hdr = NULL;
+  GArray                      *shb_hdrs = NULL;
   wtapng_iface_descriptions_t *idb_inf = NULL;
-  wtapng_name_res_t           *nrb_hdr = NULL;
+  GArray                      *nrb_hdrs = NULL;
   struct wtap_pkthdr phdr;
   Buffer       buf;
   epan_dissect_t *edt = NULL;
+  char                        *shb_user_appl;
 
   wtap_phdr_init(&phdr);
 
@@ -3185,13 +3265,14 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
     }
     tshark_debug("tshark: snapshot_length = %d", snapshot_length);
 
-    shb_hdr = wtap_file_get_shb_for_new_file(cf->wth);
-    nrb_hdr = wtap_file_get_nrb_for_new_file(cf->wth);
+    shb_hdrs = wtap_file_get_shb_for_new_file(cf->wth);
+    nrb_hdrs = wtap_file_get_nrb_for_new_file(cf->wth);
 
     /* If we don't have an application name add Tshark */
-    if (shb_hdr->shb_user_appl == NULL) {
-        /* this is free'd by wtap_free_shb() later */
-        shb_hdr->shb_user_appl = g_strdup_printf("TShark (Wireshark) %s", get_ws_vcs_version_info());
+    wtap_optionblock_get_option_string(g_array_index(shb_hdrs, wtap_optionblock_t, 0), OPT_SHB_USERAPPL, &shb_user_appl);
+    if (shb_user_appl == NULL) {
+        /* this is free'd by wtap_optionblock_free() later */
+        wtap_optionblock_set_option_string_format(g_array_index(shb_hdrs, wtap_optionblock_t, 0), OPT_SHB_USERAPPL, "TShark (Wireshark) %s", get_ws_vcs_version_info());
     }
 
     if (linktype != WTAP_ENCAP_PER_PACKET &&
@@ -3211,10 +3292,10 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
         if (strcmp(save_file, "-") == 0) {
           /* Write to the standard output. */
           pdh = wtap_dump_open_stdout_ng(out_file_type, linktype,
-              snapshot_length, FALSE /* compressed */, shb_hdr, idb_inf, nrb_hdr, &err);
+              snapshot_length, FALSE /* compressed */, shb_hdrs, idb_inf, nrb_hdrs, &err);
         } else {
           pdh = wtap_dump_open_ng(save_file, out_file_type, linktype,
-              snapshot_length, FALSE /* compressed */, shb_hdr, idb_inf, nrb_hdr, &err);
+              snapshot_length, FALSE /* compressed */, shb_hdrs, idb_inf, nrb_hdrs, &err);
         }
     }
 
@@ -3432,8 +3513,8 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
                 break;
               }
               wtap_dump_close(pdh, &err);
-              wtap_free_shb(shb_hdr);
-              wtap_free_nrb(nrb_hdr);
+              wtap_optionblock_array_free(shb_hdrs);
+              wtap_optionblock_array_free(nrb_hdrs);
               exit(2);
             }
           }
@@ -3547,8 +3628,8 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
               break;
             }
             wtap_dump_close(pdh, &err);
-            wtap_free_shb(shb_hdr);
-            wtap_free_nrb(nrb_hdr);
+            wtap_optionblock_array_free(shb_hdrs);
+            wtap_optionblock_array_free(nrb_hdrs);
             exit(2);
           }
         }
@@ -3664,8 +3745,8 @@ out:
   cf->wth = NULL;
 
   g_free(save_file_string);
-  wtap_free_shb(shb_hdr);
-  wtap_free_nrb(nrb_hdr);
+  wtap_optionblock_array_free(shb_hdrs);
+  wtap_optionblock_array_free(nrb_hdrs);
 
   return err;
 }
@@ -3693,7 +3774,7 @@ process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset, struct wtap
      do a dissection and do so. */
   if (edt) {
     if (print_packet_info && (gbl_resolv_flags.mac_name || gbl_resolv_flags.network_name ||
-        gbl_resolv_flags.transport_name || gbl_resolv_flags.concurrent_dns))
+        gbl_resolv_flags.transport_name))
       /* Grab any resolved addresses */
       host_name_lookup_process();
 
@@ -3948,15 +4029,15 @@ print_columns(capture_file *cf)
        *
        * If we printed a network source and are printing a
        * network destination of the same type next, separate
-       * them with " -> "; if we printed a network destination
-       * and are printing a network source of the same type
-       * next, separate them with " <- "; otherwise separate them
-       * with a space.
+       * them with a UTF-8 right arrow; if we printed a network
+       * destination and are printing a network source of the same
+       * type next, separate them with a UTF-8 left arrow;
+       * otherwise separate them with a space.
        *
-       * We add enough space to the buffer for " <- " or " -> ",
-       * even if we're only adding " ".
+       * We add enough space to the buffer for " \xe2\x86\x90 "
+       * or " \xe2\x86\x92 ", even if we're only adding " ".
        */
-      line_bufp = get_line_buf(buf_offset + 4);
+      line_bufp = get_line_buf(buf_offset + 5);
       switch (col_item->col_fmt) {
 
       case COL_DEF_SRC:
@@ -3967,8 +4048,8 @@ print_columns(capture_file *cf)
         case COL_DEF_DST:
         case COL_RES_DST:
         case COL_UNRES_DST:
-          put_string(line_bufp + buf_offset, " -> ", 4);
-          buf_offset += 4;
+          put_string(line_bufp + buf_offset, " " UTF8_RIGHTWARDS_ARROW " ", 5);
+          buf_offset += 5;
           break;
 
         default:
@@ -3986,8 +4067,8 @@ print_columns(capture_file *cf)
         case COL_DEF_DL_DST:
         case COL_RES_DL_DST:
         case COL_UNRES_DL_DST:
-          put_string(line_bufp + buf_offset, " -> ", 4);
-          buf_offset += 4;
+          put_string(line_bufp + buf_offset, " " UTF8_RIGHTWARDS_ARROW " ", 5);
+          buf_offset += 5;
           break;
 
         default:
@@ -4005,8 +4086,8 @@ print_columns(capture_file *cf)
         case COL_DEF_NET_DST:
         case COL_RES_NET_DST:
         case COL_UNRES_NET_DST:
-          put_string(line_bufp + buf_offset, " -> ", 4);
-          buf_offset += 4;
+          put_string(line_bufp + buf_offset, " " UTF8_RIGHTWARDS_ARROW " ", 5);
+          buf_offset += 5;
           break;
 
         default:
@@ -4024,8 +4105,8 @@ print_columns(capture_file *cf)
         case COL_DEF_SRC:
         case COL_RES_SRC:
         case COL_UNRES_SRC:
-          put_string(line_bufp + buf_offset, " <- ", 4);
-          buf_offset += 4;
+          put_string(line_bufp + buf_offset, " " UTF8_LEFTWARDS_ARROW " ", 5);
+          buf_offset += 5;
           break;
 
         default:
@@ -4043,8 +4124,8 @@ print_columns(capture_file *cf)
         case COL_DEF_DL_SRC:
         case COL_RES_DL_SRC:
         case COL_UNRES_DL_SRC:
-          put_string(line_bufp + buf_offset, " <- ", 4);
-          buf_offset += 4;
+          put_string(line_bufp + buf_offset, " " UTF8_LEFTWARDS_ARROW " ", 5);
+          buf_offset += 5;
           break;
 
         default:
@@ -4062,8 +4143,8 @@ print_columns(capture_file *cf)
         case COL_DEF_NET_SRC:
         case COL_RES_NET_SRC:
         case COL_UNRES_NET_SRC:
-          put_string(line_bufp + buf_offset, " <- ", 4);
-          buf_offset += 4;
+          put_string(line_bufp + buf_offset, " " UTF8_LEFTWARDS_ARROW " ", 5);
+          buf_offset += 5;
           break;
 
         default: