Move ip6_to_str_buf() to to_str.c and make it take the buffer length.
[metze/wireshark/wip.git] / tshark.c
index 0bd08b6d9c899d4349c732ed6fb09c7a238df496..96f15556784c6f2b527003c9ee4f61383c7c2ad0 100644 (file)
--- a/tshark.c
+++ b/tshark.c
@@ -84,6 +84,7 @@
 #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>
@@ -93,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>
 #include <epan/funnel.h>
 
 #include <wsutil/str_util.h>
+#include <wsutil/utf8_entities.h>
 
 #ifdef HAVE_PLUGINS
 #include <wsutil/plugins.h>
@@ -375,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");
@@ -390,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");
@@ -993,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[]
@@ -1013,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;
 
@@ -1665,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);
@@ -2163,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;
@@ -2171,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) {
@@ -2212,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
@@ -3151,9 +3233,9 @@ 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;
-  wtap_optionblock_t           shb_hdr = NULL;
+  GArray                      *shb_hdrs = NULL;
   wtapng_iface_descriptions_t *idb_inf = NULL;
-  wtap_optionblock_t           nrb_hdr = NULL;
+  GArray                      *nrb_hdrs = NULL;
   struct wtap_pkthdr phdr;
   Buffer       buf;
   epan_dissect_t *edt = NULL;
@@ -3183,16 +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 */
-    wtap_optionblock_get_option_string(shb_hdr, OPT_SHB_USERAPPL, &shb_user_appl);
+    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 */
-        shb_user_appl = g_strdup_printf("TShark (Wireshark) %s", get_ws_vcs_version_info());
-        wtap_optionblock_set_option_string(shb_hdr, OPT_SHB_USERAPPL, shb_user_appl);
-        g_free(shb_user_appl);
+        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 &&
@@ -3212,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);
         }
     }
 
@@ -3433,8 +3513,8 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
                 break;
               }
               wtap_dump_close(pdh, &err);
-              wtap_optionblock_free(shb_hdr);
-              wtap_optionblock_free(nrb_hdr);
+              wtap_optionblock_array_free(shb_hdrs);
+              wtap_optionblock_array_free(nrb_hdrs);
               exit(2);
             }
           }
@@ -3548,8 +3628,8 @@ load_cap_file(capture_file *cf, char *save_file, int out_file_type,
               break;
             }
             wtap_dump_close(pdh, &err);
-            wtap_optionblock_free(shb_hdr);
-            wtap_optionblock_free(nrb_hdr);
+            wtap_optionblock_array_free(shb_hdrs);
+            wtap_optionblock_array_free(nrb_hdrs);
             exit(2);
           }
         }
@@ -3665,8 +3745,8 @@ out:
   cf->wth = NULL;
 
   g_free(save_file_string);
-  wtap_optionblock_free(shb_hdr);
-  wtap_optionblock_free(nrb_hdr);
+  wtap_optionblock_array_free(shb_hdrs);
+  wtap_optionblock_array_free(nrb_hdrs);
 
   return err;
 }
@@ -3949,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:
@@ -3968,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:
@@ -3987,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:
@@ -4006,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:
@@ -4025,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:
@@ -4044,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:
@@ -4063,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: