Do the full string in get_{compiled,runtime}_version_info().
[metze/wireshark/wip.git] / dumpcap.c
index 4b6ced0ad394cc35a31deaff95f046c18fb27803..9aae11b54bbde46529580798f82983344add8e07 100644 (file)
--- a/dumpcap.c
+++ b/dumpcap.c
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <stdio.h>
 #include <stdlib.h> /* for exit() */
 #include <glib.h>
 
 #include <string.h>
-#include <ctype.h>
 
 #ifdef HAVE_SYS_TYPES_H
 # include <sys/types.h>
 #include <signal.h>
 #include <errno.h>
 
+#ifdef HAVE_LIBZ
+#include <zlib.h>      /* to get the libz version number */
+#endif
+
+#include <wsutil/cmdarg_err.h>
 #include <wsutil/crash_info.h>
+#include <wsutil/ws_version_info.h>
 
-#ifndef HAVE_GETOPT
+#ifndef HAVE_GETOPT_LONG
 #include "wsutil/wsgetopt.h"
 #endif
 
 #endif
 
 #include "ringbuffer.h"
-#include "clopts_common.h"
-#include "cmdarg_err.h"
-#include "version_info.h"
 
-#include "capture-pcap-util.h"
+#include "caputils/capture_ifinfo.h"
+#include "caputils/capture-pcap-util.h"
+#include "caputils/capture-pcap-util-int.h"
 #ifdef _WIN32
-#include "capture-wpcap.h"
+#include "caputils/capture-wpcap.h"
 #endif /* _WIN32 */
 
 #include "pcapio.h"
 
 #ifdef _WIN32
-#include "capture-wpcap.h"
 #include <wsutil/unicode-utils.h>
 #endif
 
 # include "wsutil/inet_v6defs.h"
 #endif
 
+#include <wsutil/clopts_common.h>
 #include <wsutil/privileges.h>
 
 #include "sync_pipe.h"
 
 #include "capture_opts.h"
-#include "capture_session.h"
-#include "capture_ifinfo.h"
-#include "capture_sync.h"
+#include <capchild/capture_session.h>
+#include <capchild/capture_sync.h>
 
 #include "conditions.h"
 #include "capture_stop_conditions.h"
 #include "wsutil/tempfile.h"
 #include "log.h"
 #include "wsutil/file_util.h"
+#include "wsutil/os_version_info.h"
 
-#include "ws80211_utils.h"
+#include "caputils/ws80211_utils.h"
 
 /*
  * Get information about libpcap format from "wiretap/libpcap.h".
@@ -185,7 +189,7 @@ enable_kernel_bpf_jit_compiler(void)
     ssize_t written _U_;
     static const char file[] = "/proc/sys/net/core/bpf_jit_enable";
 
-    fd = open(file, O_WRONLY);
+    fd = ws_open(file, O_WRONLY);
     if (fd < 0)
         return;
 
@@ -468,20 +472,8 @@ create_timestamp(void) {
 }
 
 static void
-print_usage(gboolean print_ver)
+print_usage(FILE *output)
 {
-    FILE *output;
-
-    if (print_ver) {
-        output = stdout;
-        fprintf(output,
-                "Dumpcap " VERSION "%s\n"
-                "Capture network packets and dump them into a pcapng file.\n"
-                "See http://www.wireshark.org for more information.\n",
-                wireshark_gitversion);
-    } else {
-        output = stderr;
-    }
     fprintf(output, "\nUsage: dumpcap [options] ...\n");
     fprintf(output, "\n");
     fprintf(output, "Capture interface:\n");
@@ -558,64 +550,43 @@ print_usage(gboolean print_ver)
     fprintf(output, "Use Ctrl-C to stop capturing at any time.\n");
 }
 
-static void
-show_version(GString *comp_info_str, GString *runtime_info_str)
-{
-    printf(
-        "Dumpcap " VERSION "%s\n"
-        "\n"
-        "%s\n"
-        "%s\n"
-        "%s\n"
-        "See http://www.wireshark.org for more information.\n",
-        wireshark_gitversion, get_copyright_info(), comp_info_str->str, runtime_info_str->str);
-}
-
 /*
  * Report an error in command-line arguments.
+ * If we're a capture child, send a message back to the parent, otherwise
+ * just print it.
  */
-void
-cmdarg_err(const char *fmt, ...)
+static void
+dumpcap_cmdarg_err(const char *fmt, va_list ap)
 {
-    va_list ap;
-
     if (capture_child) {
         gchar *msg;
         /* Generate a 'special format' message back to parent */
-        va_start(ap, fmt);
         msg = g_strdup_vprintf(fmt, ap);
         sync_pipe_errmsg_to_parent(2, msg, "");
         g_free(msg);
-        va_end(ap);
     } else {
-        va_start(ap, fmt);
         fprintf(stderr, "dumpcap: ");
         vfprintf(stderr, fmt, ap);
         fprintf(stderr, "\n");
-        va_end(ap);
     }
 }
 
 /*
  * Report additional information for an error in command-line arguments.
+ * If we're a capture child, send a message back to the parent, otherwise
+ * just print it.
  */
-void
-cmdarg_err_cont(const char *fmt, ...)
+static void
+dumpcap_cmdarg_err_cont(const char *fmt, va_list ap)
 {
-    va_list ap;
-
     if (capture_child) {
         gchar *msg;
-        va_start(ap, fmt);
         msg = g_strdup_vprintf(fmt, ap);
         sync_pipe_errmsg_to_parent(2, msg, "");
         g_free(msg);
-        va_end(ap);
     } else {
-        va_start(ap, fmt);
         vfprintf(stderr, fmt, ap);
         fprintf(stderr, "\n");
-        va_end(ap);
     }
 }
 
@@ -653,7 +624,12 @@ relinquish_all_capabilities(void)
 #endif
 
 static pcap_t *
-open_capture_device(interface_options *interface_opts,
+open_capture_device(capture_options *capture_opts
+#ifndef HAVE_PCAP_SET_TSTAMP_PRECISION
+                    _U_
+#endif
+                    ,
+                    interface_options *interface_opts,
                     char (*open_err_str)[PCAP_ERRBUF_SIZE])
 {
     pcap_t *pcap_h;
@@ -726,6 +702,22 @@ open_capture_device(interface_options *interface_opts,
             pcap_set_promisc(pcap_h, interface_opts->promisc_mode);
             pcap_set_timeout(pcap_h, CAP_READ_TIMEOUT);
 
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+            /*
+             * If we're writing pcap-ng files, try to enable
+             * nanosecond-resolution capture; any code that
+             * can read pcap-ng files must be able to handle
+             * nanosecond-resolution time stamps.
+             *
+             * If we're writing pcap files, don't try to enable
+             * nanosecond-resolution capture, as not all code
+             * that reads pcap files recognizes the nanosecond-
+             * resolution pcap file magic number.
+             */
+            if (capture_opts->use_pcapng)
+                request_high_resolution_timestamp(pcap_h);
+#endif /* HAVE_PCAP_SET_TSTAMP_PRECISION */
+
             g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
                   "buffersize %d.", interface_opts->buffer_size);
             if (interface_opts->buffer_size != 0) {
@@ -917,7 +909,7 @@ show_filter_code(capture_options *capture_opts)
 
     for (j = 0; j < capture_opts->ifaces->len; j++) {
         interface_opts = g_array_index(capture_opts->ifaces, interface_options, j);
-        pcap_h = open_capture_device(&interface_opts, &open_err_str);
+        pcap_h = open_capture_device(capture_opts, &interface_opts, &open_err_str);
         if (pcap_h == NULL) {
             /* Open failed; get messages */
             get_capture_device_open_failure_messages(open_err_str,
@@ -1385,7 +1377,9 @@ print_machine_readable_interfaces(GList *if_list)
             printf("\tloopback");
         else
             printf("\tnetwork");
-
+#ifdef HAVE_EXTCAP
+        printf("\t%s", if_info->extcap);
+#endif
         printf("\n");
     }
 }
@@ -1442,16 +1436,11 @@ print_statistics_loop(gboolean machine_readable)
 
     if_list = get_interface_list(&err, &err_str);
     if (if_list == NULL) {
-        switch (err) {
-        case CANT_GET_INTERFACE_LIST:
-        case DONT_HAVE_PCAP:
+       if (err == 0)
+            cmdarg_err("There are no interfaces on which a capture can be done");
+        else {
             cmdarg_err("%s", err_str);
             g_free(err_str);
-            break;
-
-        case NO_INTERFACES_FOUND:
-            cmdarg_err("There are no interfaces on which a capture can be done");
-            break;
         }
         return err;
     }
@@ -1881,14 +1870,14 @@ cap_open_socket(char *pipename, pcap_options *pcap_opts, char *errmsg, int errms
     goto fail_invalid;
   }
 
-  strncpy(buf, sockname, len);
+  g_snprintf ( buf,(gulong)len + 1, "%s", sockname );
   buf[len] = '\0';
   if (inet_pton(AF_INET, buf, &sa.sin_addr) <= 0) {
     goto fail_invalid;
   }
 
   sa.sin_family = AF_INET;
-  sa.sin_port = htons((u_short)port);
+  sa.sin_port = g_htons((u_short)port);
 
   if (((fd = (int)socket(AF_INET, SOCK_STREAM, 0)) < 0) ||
       (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)) {
@@ -1910,7 +1899,7 @@ cap_open_socket(char *pipename, pcap_options *pcap_opts, char *errmsg, int errms
       if (errorText)
           LocalFree(errorText);
 #else
-      "         %d: %s", errno, strerror(errno));
+      "         %d: %s", errno, g_strerror(errno));
 #endif
       pcap_opts->cap_pipe_err = PIPERR;
 
@@ -1964,12 +1953,12 @@ cap_pipe_open_live(char *pipename,
 #else /* _WIN32 */
     char    *pncopy, *pos;
     wchar_t *err_str;
+    interface_options interface_opts;
 #endif
     ssize_t  b;
     int      fd = -1, sel_ret;
     size_t   bytes_read;
     guint32  magic = 0;
-
     pcap_opts->cap_pipe_fd = -1;
 #ifdef _WIN32
     pcap_opts->cap_pipe_h = INVALID_HANDLE_VALUE;
@@ -2100,10 +2089,16 @@ cap_pipe_open_live(char *pipename,
             return;
         }
 
+        interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, 0);
+
         /* Wait for the pipe to appear */
         while (1) {
-            pcap_opts->cap_pipe_h = CreateFile(utf_8to16(pipename), GENERIC_READ, 0, NULL,
-                                               OPEN_EXISTING, 0, NULL);
+
+            if(strncmp(interface_opts.name,"\\\\.\\pipe\\",9)== 0)
+                pcap_opts->cap_pipe_h = GetStdHandle(STD_INPUT_HANDLE);
+            else
+                pcap_opts->cap_pipe_h = CreateFile(utf_8to16(pipename), GENERIC_READ, 0, NULL,
+                                                   OPEN_EXISTING, 0, NULL);
 
             if (pcap_opts->cap_pipe_h != INVALID_HANDLE_VALUE)
                 break;
@@ -2122,7 +2117,7 @@ cap_pipe_open_live(char *pipename,
 
             if (!WaitNamedPipe(utf_8to16(pipename), 30 * 1000)) {
                 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
-                              NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL);
+                             NULL, GetLastError(), 0, (LPTSTR) &err_str, 0, NULL);
                 g_snprintf(errmsg, errmsgl,
                            "The capture session on \"%s\" timed out during "
                            "pipe open: %s (error %d)",
@@ -2588,7 +2583,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
     if ((use_threads == FALSE) &&
         (capture_opts->ifaces->len > 1)) {
         g_snprintf(errmsg, (gulong) errmsg_len,
-                   "Using threads is required for capturing on multiple interfaces!");
+                   "Using threads is required for capturing on multiple interfaces.");
         return FALSE;
     }
 
@@ -2643,10 +2638,16 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
         g_array_append_val(ld->pcaps, pcap_opts);
 
         g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "capture_loop_open_input : %s", interface_opts.name);
-        pcap_opts->pcap_h = open_capture_device(&interface_opts, &open_err_str);
+        pcap_opts->pcap_h = open_capture_device(capture_opts, &interface_opts, &open_err_str);
 
         if (pcap_opts->pcap_h != NULL) {
             /* we've opened "iface" as a network device */
+
+#ifdef HAVE_PCAP_SET_TSTAMP_PRECISION
+            /* Find out if we're getting nanosecond-precision time stamps */
+            pcap_opts->ts_nsec = have_high_resolution_timestamp(pcap_opts->pcap_h);
+#endif
+
 #ifdef _WIN32
             /* try to set the capture buffer size */
             if (interface_opts.buffer_size > 1 &&
@@ -2657,7 +2658,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
                     "\n"
                     "Nonetheless, the capture is started.\n",
                     interface_opts.buffer_size, DEFAULT_CAPTURE_BUFFER_SIZE);
-                report_capture_error("Couldn't set the capture buffer size!",
+                report_capture_error("Couldn't set the capture buffer size.",
                                      sync_secondary_msg_str);
                 g_free(sync_secondary_msg_str);
             }
@@ -2854,7 +2855,7 @@ capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *err
     if ((capture_opts->use_pcapng == FALSE) &&
         (capture_opts->ifaces->len > 1)) {
         g_snprintf(errmsg, errmsg_len,
-                   "Using PCAPNG is required for capturing on multiple interfaces! Use the -n option.");
+                   "Using PCAPNG is required for capturing on multiple interfaces. Use the -n option.");
         return FALSE;
     }
 
@@ -2875,7 +2876,7 @@ capture_loop_init_output(capture_options *capture_opts, loop_data *ld, char *err
             os_info_str = g_string_new("");
             get_os_version_info(os_info_str);
 
-            g_snprintf(appname, sizeof(appname), "Dumpcap " VERSION "%s", wireshark_gitversion);
+            g_snprintf(appname, sizeof(appname), "Dumpcap (Wireshark) %s", get_ws_vcs_version_info());
             successful = pcapng_write_session_header_block(ld->pdh,
                                 (const char *)capture_opts->capture_comment,   /* Comment*/
                                 NULL,                        /* HW*/
@@ -3368,7 +3369,7 @@ do_file_switch_or_stop(capture_options *capture_opts,
                 os_info_str = g_string_new("");
                 get_os_version_info(os_info_str);
 
-                g_snprintf(appname, sizeof(appname), "Dumpcap " VERSION "%s", wireshark_gitversion);
+                g_snprintf(appname, sizeof(appname), "Dumpcap (Wireshark) %s", get_ws_vcs_version_info());
                 successful = pcapng_write_session_header_block(global_ld.pdh,
                                 NULL,                        /* Comment */
                                 NULL,                        /* HW */
@@ -3598,7 +3599,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
     gettimeofday(&upd_time, NULL);
 #endif
     start_time = create_timestamp();
-    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Capture loop running!");
+    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Capture loop running.");
 
     /* WOW, everything is prepared! */
     /* please fasten your seat belts, we will enter now the actual capture loop */
@@ -3904,7 +3905,7 @@ capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct
     /* close the input file (pcap or capture pipe) */
     capture_loop_close_input(&global_ld);
 
-    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Capture loop stopped!");
+    g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "Capture loop stopped.");
 
     /* ok, if the write and the close were successful. */
     return write_ok && close_ok;
@@ -4169,6 +4170,40 @@ out:
     return ret;
 }
 
+static void
+get_dumpcap_compiled_info(GString *str)
+{
+    /* Capture libraries */
+    g_string_append(str, ", ");
+    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
+get_dumpcap_runtime_info(GString *str)
+{
+    /* Capture libraries */
+    g_string_append(str, ", ");
+    get_runtime_caplibs_version(str);
+
+    /* zlib */
+#if defined(HAVE_LIBZ) && !defined(_WIN32)
+    g_string_append_printf(str, ", with libz %s", zlibVersion());
+#endif
+}
+
 /* And now our feature presentation... [ fade to music ] */
 int
 main(int argc, char *argv[])
@@ -4177,10 +4212,9 @@ main(int argc, char *argv[])
     GString          *runtime_info_str;
     int               opt;
     static const struct option long_options[] = {
-        {(char *)"capture-comment", required_argument, NULL, LONGOPT_NUM_CAP_COMMENT },
         {(char *)"help", no_argument, NULL, 'h'},
         {(char *)"version", no_argument, NULL, 'v'},
-        LONGOPT_CAPTURE_COMMON,
+        LONGOPT_CAPTURE_COMMON
         {0, 0, 0, 0 }
     };
 
@@ -4213,21 +4247,21 @@ main(int argc, char *argv[])
 #endif
     GString          *str;
 
-    /* Assemble the compile-time version information string */
-    comp_info_str = g_string_new("Compiled ");
-    get_compiled_version_info(comp_info_str, NULL, NULL);
+    cmdarg_err_init(dumpcap_cmdarg_err, dumpcap_cmdarg_err_cont);
 
-    /* Assemble the run-time version information string */
-    runtime_info_str = g_string_new("Running ");
-    get_runtime_version_info(runtime_info_str, NULL);
+    /* Get the compile-time version information string */
+    comp_info_str = get_compiled_version_info(NULL, get_dumpcap_compiled_info);
+
+    /* Get the run-time version information string */
+    runtime_info_str = get_runtime_version_info(get_dumpcap_runtime_info);
 
     /* Add it to the information to be reported on a crash. */
-    ws_add_crash_info("Dumpcap " VERSION "%s\n"
+    ws_add_crash_info("Dumpcap (Wireshark) %s\n"
            "\n"
            "%s"
            "\n"
            "%s",
-        wireshark_gitversion, comp_info_str->str, runtime_info_str->str);
+        get_ws_vcs_version_info(), comp_info_str->str, runtime_info_str->str);
 
 #ifdef _WIN32
     arg_list_utf_16to8(argc, argv);
@@ -4240,6 +4274,12 @@ main(int argc, char *argv[])
     ws_init_dll_search_path();
 #endif
 
+#ifdef HAVE_BPF_IMAGE
+#define OPTSTRING_d "d"
+#else
+#define OPTSTRING_d ""
+#endif
+
 #ifdef HAVE_PCAP_REMOTE
 #define OPTSTRING_r "r"
 #define OPTSTRING_u "u"
@@ -4258,7 +4298,7 @@ main(int argc, char *argv[])
 
 #ifdef DEBUG_CHILD_DUMPCAP
     if ((debug_log = ws_fopen("dumpcap_debug_log.tmp","w")) == NULL) {
-        fprintf (stderr, "Unable to open debug log file !\n");
+        fprintf (stderr, "Unable to open debug log file .\n");
         exit (1);
     }
 #endif
@@ -4502,7 +4542,6 @@ main(int argc, char *argv[])
     /* Set the initial values in the capture options. This might be overwritten
        by the command line parameters. */
     capture_opts_init(&global_capture_opts);
-
     /* We always save to a file - if no file was specified, we save to a
        temporary file. */
     global_capture_opts.saving_to_file      = TRUE;
@@ -4515,12 +4554,16 @@ main(int argc, char *argv[])
     while ((opt = getopt_long(argc, argv, OPTSTRING, long_options, NULL)) != -1) {
         switch (opt) {
         case 'h':        /* Print help and exit */
-            print_usage(TRUE);
+            printf("Dumpcap (Wireshark) %s\n"
+                   "Capture network packets and dump them into a pcapng or pcap file.\n"
+                   "See http://www.wireshark.org for more information.\n",
+                   get_ws_vcs_version_info());
+            print_usage(stdout);
             exit_main(0);
             break;
         case 'v':        /* Show version and exit */
         {
-            show_version(comp_info_str, runtime_info_str);
+            show_version("Dumpcap (Wireshark)", comp_info_str, runtime_info_str);
             g_string_free(comp_info_str, TRUE);
             g_string_free(runtime_info_str, TRUE);
             exit_main(0);
@@ -4660,7 +4703,7 @@ main(int argc, char *argv[])
         pcap_queue_packet_limit = 1000;
     }
     if (arg_error) {
-        print_usage(FALSE);
+        print_usage(stderr);
         exit_main(1);
     }
 
@@ -4722,15 +4765,7 @@ main(int argc, char *argv[])
 
         if_list = capture_interface_list(&err, &err_str,NULL);
         if (if_list == NULL) {
-            switch (err) {
-            case CANT_GET_INTERFACE_LIST:
-            case DONT_HAVE_PCAP:
-                cmdarg_err("%s", err_str);
-                g_free(err_str);
-                exit_main(2);
-                break;
-
-            case NO_INTERFACES_FOUND:
+            if (err == 0) {
                 /*
                  * If we're being run by another program, just give them
                  * an empty list of interfaces, don't report this as
@@ -4741,7 +4776,10 @@ main(int argc, char *argv[])
                     cmdarg_err("There are no interfaces on which a capture can be done");
                     exit_main(2);
                 }
-                break;
+            } else {
+                cmdarg_err("%s", err_str);
+                g_free(err_str);
+                exit_main(2);
             }
         }
 
@@ -4834,6 +4872,7 @@ main(int argc, char *argv[])
             interface_options interface_opts;
 
             interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, ii);
+
             caps = get_if_capabilities(interface_opts.name,
                                        interface_opts.monitor_mode, &err_str);
             if (caps == NULL) {
@@ -4877,7 +4916,6 @@ main(int argc, char *argv[])
     fflush(stderr);
 
     /* Now start the capture. */
-
     if (capture_loop_start(&global_capture_opts, &stats_known, &stats) == TRUE) {
         /* capture ok */
         exit_main(0);
@@ -5048,7 +5086,7 @@ report_cfilter_error(capture_options *capture_opts, guint i, const char *errmsg)
              */
             interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
             cmdarg_err(
-              "Invalid capture filter \"%s\" for interface '%s'!\n"
+              "Invalid capture filter \"%s\" for interface '%s'.\n"
               "\n"
               "That string isn't a valid capture filter (%s).\n"
               "See the User's Guide for a description of the capture filter syntax.",