Um, no, the problem with the Leopard x86 build is that we first do a
[obnox/wireshark/wip.git] / dumpcap.c
index 49b9766b086ee98422061bb87da27f2b4b76ef8b..ef865b97e73b98e0288136c8a988eb3710585490 100644 (file)
--- a/dumpcap.c
+++ b/dumpcap.c
 #include <unistd.h>
 #endif
 
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
 #if defined(__APPLE__) && defined(__LP64__)
 #include <sys/utsname.h>
 #endif
 
 #include "ringbuffer.h"
 #include "clopts_common.h"
+#include "console_io.h"
 #include "cmdarg_err.h"
 #include "version_info.h"
 
-#include <pcap.h>
-#include "pcapio.h"
-
 #include "capture-pcap-util.h"
 
+#include "pcapio.h"
+
 #ifdef _WIN32
 #include "capture-wpcap.h"
 #include <wsutil/unicode-utils.h>
 #endif
 
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
+
+#ifdef NEED_INET_V6DEFS_H
+# include "inet_v6defs.h"
+#endif
+
 #include <wsutil/privileges.h>
 
 #include "sync_pipe.h"
 
 #include "capture_opts.h"
+#include "capture_ifinfo.h"
 #include "capture_sync.h"
 
 #include "conditions.h"
@@ -261,7 +275,7 @@ static loop_data   global_ld;
  * fixed in 10.6.2.
  */
 #if defined(__APPLE__) && defined(__LP64__)
-static int need_timeout_workaround;
+static gboolean need_timeout_workaround;
 
 #define        CAP_READ_TIMEOUT        (need_timeout_workaround ? 1000 : 250)
 #else
@@ -272,8 +286,7 @@ static int need_timeout_workaround;
  * Timeout, in microseconds, for threaded reads from a pipe.
  */
 #define THREAD_READ_TIMEOUT   100
-#define THREAD_OPEN_TIMEOUT   (5 * 1000000)
-static char *cap_pipe_err_str;
+static const char *cap_pipe_err_str;
 
 static void
 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
@@ -318,7 +331,10 @@ print_usage(gboolean print_ver) {
   fprintf(output, "  -f <capture filter>      packet filter in libpcap filter syntax\n");
   fprintf(output, "  -s <snaplen>             packet snapshot length (def: 65535)\n");
   fprintf(output, "  -p                       don't capture in promiscuous mode\n");
-#ifdef _WIN32
+#ifdef HAVE_PCAP_CREATE
+  fprintf(output, "  -I                       capture in monitor mode, if available\n");
+#endif
+#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
   fprintf(output, "  -B <buffer size>         size of kernel buffer (def: 1MB)\n");
 #endif
   fprintf(output, "  -y <link type>           link layer type (def: first appropriate)\n");
@@ -375,6 +391,26 @@ show_version(GString *comp_info_str, GString *runtime_info_str)
         wireshark_svnversion, get_copyright_info() ,comp_info_str->str, runtime_info_str->str);
 }
 
+/*
+ * Print to the standard error.  This is a command-line tool, so there's
+ * no need to pop up a console.
+ */
+void
+vfprintf_stderr(const char *fmt, va_list ap)
+{
+  vfprintf(stderr, fmt, ap);
+}
+
+void
+fprintf_stderr(const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start(ap, fmt);
+  vfprintf_stderr(fmt, ap);
+  va_end(ap);
+}
+
 /*
  * Report an error in command-line arguments.
  */
@@ -423,6 +459,310 @@ cmdarg_err_cont(const char *fmt, ...)
   }
 }
 
+/*
+ * capture_interface_list() is expected to do the right thing to get
+ * a list of interfaces.
+ *
+ * In most of the programs in the Wireshark suite, "the right thing"
+ * is to run dumpcap and ask it for the list, because dumpcap may
+ * be the only program in the suite with enough privileges to get
+ * the list.
+ *
+ * In dumpcap itself, however, we obviously can't run dumpcap to
+ * ask for the list.  Therefore, our capture_interface_list() should
+ * just call get_interface_list().
+ */
+GList *
+capture_interface_list(int *err, char **err_str)
+{
+  return get_interface_list(err, err_str);
+}
+
+/*
+ * Get the data-link types available for a libpcap device.
+ */
+static data_link_info_t *
+create_data_link_info(int dlt)
+{
+    data_link_info_t *data_link_info;
+    const char *text;
+
+    data_link_info = (data_link_info_t *)g_malloc(sizeof (data_link_info_t));
+    data_link_info->dlt = dlt;
+    text = pcap_datalink_val_to_name(dlt);
+    if (text != NULL)
+        data_link_info->name = g_strdup(text);
+    else
+        data_link_info->name = g_strdup_printf("DLT %d", dlt);
+    text = pcap_datalink_val_to_description(dlt);
+    if (text != NULL)
+        data_link_info->description = g_strdup(text);
+    else
+        data_link_info->description = NULL;
+    return data_link_info;
+}
+
+static if_capabilities_t *
+get_if_capabilities(const char *devname, gboolean monitor_mode
+#ifndef HAVE_PCAP_CREATE
+       _U_
+#endif
+, char **err_str)
+{
+    if_capabilities_t *caps;
+    char errbuf[PCAP_ERRBUF_SIZE];
+    pcap_t *pch;
+#ifdef HAVE_PCAP_CREATE
+    int status;
+#endif
+    int deflt;
+#ifdef HAVE_PCAP_LIST_DATALINKS
+    int *linktypes;
+    int i, nlt;
+#endif
+    data_link_info_t *data_link_info;
+
+    /*
+     * Allocate the interface capabilities structure.
+     */
+    caps = g_malloc(sizeof *caps);
+
+#ifdef HAVE_PCAP_OPEN
+    pch = pcap_open(devname, MIN_PACKET_SIZE, 0, 0, NULL, errbuf);
+    caps->can_set_rfmon = FALSE;
+    if (pch == NULL) {
+        if (err_str != NULL)
+            *err_str = g_strdup(errbuf);
+        g_free(caps);
+        return NULL;
+    }
+#elif defined(HAVE_PCAP_CREATE)
+    pch = pcap_create(devname, errbuf);
+    if (pch == NULL) {
+        if (err_str != NULL)
+            *err_str = g_strdup(errbuf);
+        g_free(caps);
+        return NULL;
+    }
+    status = pcap_can_set_rfmon(pch); 
+    switch (status) {
+
+    case 0:
+        caps->can_set_rfmon = FALSE;
+        break;
+
+    case 1:
+        caps->can_set_rfmon = TRUE;
+        if (monitor_mode)
+               pcap_set_rfmon(pch, 1);
+        break;
+
+    case PCAP_ERROR_NO_SUCH_DEVICE:
+        if (err_str != NULL)
+            *err_str = g_strdup_printf("There is no capture device named \"%s\"", devname);
+        pcap_close(pch);
+        g_free(caps);
+        return NULL;
+
+    case PCAP_ERROR:
+        if (err_str != NULL)
+            *err_str = g_strdup_printf("pcap_can_set_rfmon on \"%s\" failed: %s",
+                                       devname, pcap_geterr(pch));
+        pcap_close(pch);
+        g_free(caps);
+        return NULL;
+
+    default:
+        if (err_str != NULL)
+            *err_str = g_strdup_printf("pcap_can_set_rfmon on \"%s\" failed: %s",
+                                       devname, pcap_statustostr(status));
+        pcap_close(pch);
+        g_free(caps);
+        return NULL;
+    }
+
+    status = pcap_activate(pch);
+    if (status < 0) {
+        /* Error.  We ignore warnings (status > 0). */
+        if (err_str != NULL) {
+            if (status == PCAP_ERROR) {
+                *err_str = g_strdup_printf("pcap_activate on %s failed: %s",
+                                           devname, pcap_geterr(pch));
+            } else {
+                *err_str = g_strdup_printf("pcap_activate on %s failed: %s",
+                                           devname, pcap_statustostr(status));
+            }
+        }
+        pcap_close(pch);
+        g_free(caps);
+        return NULL;
+    }
+#else
+    pch = pcap_open_live(devname, MIN_PACKET_SIZE, 0, 0, errbuf);
+    caps->can_set_rfmon = FALSE;
+    if (pch == NULL) {
+        if (err_str != NULL)
+            *err_str = g_strdup(errbuf);
+        g_free(caps);
+        return NULL;
+    }
+#endif
+    deflt = get_pcap_linktype(pch, devname);
+#ifdef HAVE_PCAP_LIST_DATALINKS
+    nlt = pcap_list_datalinks(pch, &linktypes);
+    if (nlt == 0 || linktypes == NULL) {
+        pcap_close(pch);
+        if (err_str != NULL)
+            *err_str = NULL; /* an empty list doesn't mean an error */
+        return NULL;
+    }
+    caps->data_link_types = NULL;
+    for (i = 0; i < nlt; i++) {
+        data_link_info = create_data_link_info(linktypes[i]);
+
+        /*
+         * XXX - for 802.11, make the most detailed 802.11
+         * version the default, rather than the one the
+         * device has as the default?
+         */
+        if (linktypes[i] == deflt)
+            caps->data_link_types = g_list_prepend(caps->data_link_types,
+                                                   data_link_info);
+        else
+            caps->data_link_types = g_list_append(caps->data_link_types,
+                                                  data_link_info);
+    }
+#ifdef HAVE_PCAP_FREE_DATALINKS
+    pcap_free_datalinks(linktypes);
+#else
+    /*
+     * In Windows, there's no guarantee that if you have a library
+     * built with one version of the MSVC++ run-time library, and
+     * it returns a pointer to allocated data, you can free that
+     * data from a program linked with another version of the
+     * MSVC++ run-time library.
+     *
+     * This is not an issue on UN*X.
+     *
+     * See the mail threads starting at
+     *
+     *    http://www.winpcap.org/pipermail/winpcap-users/2006-September/001421.html
+     *
+     * and
+     *
+     *    http://www.winpcap.org/pipermail/winpcap-users/2008-May/002498.html
+     */
+#ifndef _WIN32
+#define xx_free free  /* hack so checkAPIs doesn't complain */
+    xx_free(linktypes);
+#endif /* _WIN32 */
+#endif /* HAVE_PCAP_FREE_DATALINKS */
+#else /* HAVE_PCAP_LIST_DATALINKS */
+
+    data_link_info = create_data_link_info(deflt);
+    caps->data_link_types = g_list_append(caps->data_link_types,
+                                          data_link_info);
+#endif /* HAVE_PCAP_LIST_DATALINKS */
+
+    pcap_close(pch);
+
+    if (err_str != NULL)
+        *err_str = NULL;
+    return caps;
+}
+
+#define ADDRSTRLEN 46 /* Covers IPv4 & IPv6 */
+static void
+print_machine_readable_interfaces(GList *if_list)
+{
+    int         i;
+    GList       *if_entry;
+    if_info_t   *if_info;
+    GSList      *addr;
+    if_addr_t   *if_addr;
+    char        addr_str[ADDRSTRLEN];
+
+    i = 1;  /* Interface id number */
+    for (if_entry = g_list_first(if_list); if_entry != NULL;
+         if_entry = g_list_next(if_entry)) {
+        if_info = (if_info_t *)if_entry->data;
+        printf("%d. %s", i++, if_info->name);
+
+        /*
+         * Print the contents of the if_entry struct in a parseable format.
+         * Each if_entry element is tab-separated.  Addresses are comma-
+         * separated.
+         */
+        /* XXX - Make sure our description doesn't contain a tab */
+        if (if_info->description != NULL)
+            printf("\t%s\t", if_info->description);
+        else
+            printf("\t\t");
+
+        for(addr = g_slist_nth(if_info->addrs, 0); addr != NULL;
+                    addr = g_slist_next(addr)) {
+            if (addr != g_slist_nth(if_info->addrs, 0))
+                printf(",");
+
+            if_addr = (if_addr_t *)addr->data;
+            switch(if_addr->ifat_type) {
+            case IF_AT_IPv4:
+                if (inet_ntop(AF_INET, &if_addr->addr.ip4_addr, addr_str,
+                              ADDRSTRLEN)) {
+                    printf("%s", addr_str);
+                } else {
+                    printf("<unknown IPv4>");
+                }
+                break;
+            case IF_AT_IPv6:
+                if (inet_ntop(AF_INET6, &if_addr->addr.ip6_addr,
+                              addr_str, ADDRSTRLEN)) {
+                    printf("%s", addr_str);
+                } else {
+                    printf("<unknown IPv6>");
+                }
+                break;
+            default:
+                printf("<type unknown %u>", if_addr->ifat_type);
+            }
+        }
+
+        if (if_info->loopback)
+            printf("\tloopback");
+        else
+            printf("\tnetwork");
+
+        printf("\n");
+    }
+}
+
+/*
+ * If you change the machine-readable output format of this function,
+ * you MUST update capture_ifinfo.c:capture_get_if_capabilities() accordingly!
+ */
+static void
+print_machine_readable_if_capabilities(if_capabilities_t *caps)
+{
+    GList *lt_entry;
+    data_link_info_t *data_link_info;
+    const gchar *desc_str;
+
+    if (caps->can_set_rfmon)
+        printf("1\n");
+    else
+        printf("0\n");
+    for (lt_entry = caps->data_link_types; lt_entry != NULL;
+         lt_entry = g_list_next(lt_entry)) {
+      data_link_info = (data_link_info_t *)lt_entry->data;
+      if (data_link_info->description != NULL)
+        desc_str = data_link_info->description;
+      else
+        desc_str = "(not supported)";
+      printf("%d\t%s\t%s\n", data_link_info->dlt, data_link_info->name,
+             desc_str);
+    }
+}
+
 typedef struct {
     char *name;
     pcap_t *pch;
@@ -457,7 +797,7 @@ print_statistics_loop(gboolean machine_readable)
     }
 
     for (if_entry = g_list_first(if_list); if_entry != NULL; if_entry = g_list_next(if_entry)) {
-        if_info = if_entry->data;
+        if_info = (if_info_t *)if_entry->data;
 #ifdef HAVE_PCAP_OPEN
         pch = pcap_open(if_info->name, MIN_PACKET_SIZE, 0, 0, NULL, errbuf);
 #else
@@ -465,7 +805,7 @@ print_statistics_loop(gboolean machine_readable)
 #endif
 
         if (pch) {
-            if_stat = g_malloc(sizeof(if_stat_t));
+            if_stat = (if_stat_t *)g_malloc(sizeof(if_stat_t));
             if_stat->name = g_strdup(if_info->name);
             if_stat->pch = pch;
             stat_list = g_list_append(stat_list, if_stat);
@@ -485,7 +825,7 @@ print_statistics_loop(gboolean machine_readable)
     global_ld.go = TRUE;
     while (global_ld.go) {
         for (stat_entry = g_list_first(stat_list); stat_entry != NULL; stat_entry = g_list_next(stat_entry)) {
-            if_stat = stat_entry->data;
+            if_stat = (if_stat_t *)stat_entry->data;
             pcap_stats(if_stat->pch, &ps);
 
             if (!machine_readable) {
@@ -507,7 +847,7 @@ print_statistics_loop(gboolean machine_readable)
 
     /* XXX - Not reached.  Should we look for 'q' in stdin? */
     for (stat_entry = g_list_first(stat_list); stat_entry != NULL; stat_entry = g_list_next(stat_entry)) {
-        if_stat = stat_entry->data;
+        if_stat = (if_stat_t *)stat_entry->data;
         pcap_close(if_stat->pch);
         g_free(if_stat->name);
         g_free(if_stat);
@@ -598,14 +938,14 @@ static void
 /* '='   means 'all= '  ie: no capabilities                                  */
 /* '=ip' means 'all=ip' ie: all capabilities are permissible and inheritable */
 /* ....                                                                      */
-print_caps(char *pfx) {
+print_caps(const char *pfx) {
     cap_t caps = cap_get_proc();
     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG,
           "%s: EUID: %d  Capabilities: %s", pfx,
           geteuid(), cap_to_text(caps, NULL));
     cap_free(caps);
 #else
-print_caps(char *pfx _U_) {
+print_caps(const char *pfx _U_) {
 #endif
 }
 
@@ -656,7 +996,7 @@ relinquish_privs_except_capture(void)
 
 
 static void
-relinquish_all_capabilities()
+relinquish_all_capabilities(void)
 {
     /* Drop any and all capabilities this process may have.            */
     /* Allowed whether or not process has any privileges.              */
@@ -671,6 +1011,26 @@ relinquish_all_capabilities()
 
 #endif /* HAVE_LIBCAP */
 
+/* Set the data link type on a pcap. */
+static const char *
+set_pcap_linktype(pcap_t *pch, char *devname
+#ifdef HAVE_PCAP_SET_DATALINK
+       _U_
+#endif
+       , int dlt)
+{
+#ifdef HAVE_PCAP_SET_DATALINK
+       if (pcap_set_datalink(pch, dlt) == 0)
+               return NULL;    /* no error */
+       return pcap_geterr(pch);
+#else
+       /* Let them set it to the type it is; reject any other request. */
+       if (get_pcap_linktype(pch, devname) == dlt)
+               return NULL;    /* no error */
+       return "That DLT isn't one of the DLTs supported by this device";
+#endif
+}
+
 /* Take care of byte order in the libpcap headers read from pipes.
  * (function taken from wiretap/libpcap.c) */
 static void
@@ -817,20 +1177,19 @@ cap_pipe_select(int pipe_fd) {
 
 
 /* Mimic pcap_open_live() for pipe captures
- * We check if "pipename" is "-" (stdin) or a FIFO, open it, and read the
- * header.
+
+ * We check if "pipename" is "-" (stdin), a AF_UNIX socket, or a FIFO,
+ * open it, and read the header.
+ *
  * N.B. : we can't read the libpcap formats used in RedHat 6.1 or SuSE 6.3
  * because we can't seek on pipes (see wiretap/libpcap.c for details) */
 static void
 cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
-                 char *errmsg, int errmsgl)
+                   char *errmsg, int errmsgl)
 {
-#ifdef USE_THREADS
-  GTimeVal wait_time;
-  gpointer q_status;
-#endif
 #ifndef _WIN32
   struct stat pipe_stat;
+  struct sockaddr_un sa;
   int          sel_ret;
   int          b;
   unsigned int bytes_read;
@@ -851,7 +1210,8 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "cap_pipe_open_live: %s", pipename);
 
   /*
-   * XXX (T)Wireshark blocks until we return
+   * XXX - this blocks until a pcap per-file header has been written to
+   * the pipe, so it could block indefinitely.
    */
   if (strcmp(pipename, "-") == 0) {
 #ifndef _WIN32
@@ -867,12 +1227,70 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
       else {
         g_snprintf(errmsg, errmsgl,
           "The capture session could not be initiated "
-          "due to error on pipe: %s", strerror(errno));
+          "due to error getting information on pipe/socket: %s", strerror(errno));
         ld->cap_pipe_err = PIPERR;
       }
       return;
     }
-    if (! S_ISFIFO(pipe_stat.st_mode)) {
+    if (S_ISFIFO(pipe_stat.st_mode)) {
+      fd = ws_open(pipename, O_RDONLY | O_NONBLOCK, 0000 /* no creation so don't matter */);
+      if (fd == -1) {
+        g_snprintf(errmsg, errmsgl,
+            "The capture session could not be initiated "
+            "due to error on pipe open: %s", strerror(errno));
+        ld->cap_pipe_err = PIPERR;
+        return;
+      }
+    } else if (S_ISSOCK(pipe_stat.st_mode)) {
+      fd = socket(AF_UNIX, SOCK_STREAM, 0);
+      if (fd == -1) {
+        g_snprintf(errmsg, errmsgl,
+           "The capture session could not be initiated "
+           "due to error on socket create: %s", strerror(errno));
+        ld->cap_pipe_err = PIPERR;
+       return;
+      }
+      sa.sun_family = AF_UNIX;
+      /*
+       * The Single UNIX Specification says:
+       *
+       *   The size of sun_path has intentionally been left undefined.
+       *   This is because different implementations use different sizes.
+       *   For example, 4.3 BSD uses a size of 108, and 4.4 BSD uses a size
+       *   of 104. Since most implementations originate from BSD versions,
+       *   the size is typically in the range 92 to 108.
+       *
+       *   Applications should not assume a particular length for sun_path
+       *   or assume that it can hold {_POSIX_PATH_MAX} bytes (256).
+       *
+       * It also says
+       *
+       *   The <sys/un.h> header shall define the sockaddr_un structure,
+       *   which shall include at least the following members:
+       *
+       *   sa_family_t  sun_family  Address family.
+       *   char         sun_path[]  Socket pathname.
+       *
+       * so we assume that it's an array, with a specified size,
+       * and that the size reflects the maximum path length.
+       */
+      if (g_strlcpy(sa.sun_path, pipename, sizeof sa.sun_path) > sizeof sa.sun_path) {
+        /* Path name too long */
+        g_snprintf(errmsg, errmsgl,
+           "The capture session coud not be initiated "
+           "due to error on socket connect: Path name too long");
+        ld->cap_pipe_err = PIPERR;
+       return;
+      }
+      b = connect(fd, (struct sockaddr *)&sa, sizeof sa);
+      if (b == -1) {
+        g_snprintf(errmsg, errmsgl,
+           "The capture session coud not be initiated "
+           "due to error on socket connect: %s", strerror(errno));
+        ld->cap_pipe_err = PIPERR;
+       return;
+      }
+    } else {
       if (S_ISCHR(pipe_stat.st_mode)) {
         /*
          * Assume the user specified an interface on a system where
@@ -883,19 +1301,11 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
       {
         g_snprintf(errmsg, errmsgl,
             "The capture session could not be initiated because\n"
-            "\"%s\" is neither an interface nor a pipe", pipename);
+            "\"%s\" is neither an interface nor a socket nor a pipe", pipename);
         ld->cap_pipe_err = PIPERR;
       }
       return;
     }
-    fd = ws_open(pipename, O_RDONLY | O_NONBLOCK, 0000 /* no creation so don't matter */);
-    if (fd == -1) {
-      g_snprintf(errmsg, errmsgl,
-          "The capture session could not be initiated "
-          "due to error on pipe open: %s", strerror(errno));
-      ld->cap_pipe_err = PIPERR;
-      return;
-    }
 #else /* _WIN32 */
 #define PIPE_STR "\\pipe\\"
     /* Under Windows, named pipes _must_ have the form
@@ -950,7 +1360,6 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
         return;
       }
     }
-
 #endif /* _WIN32 */
   }
 
@@ -986,14 +1395,8 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
   ld->cap_pipe_bytes_to_read = sizeof(magic);
   /* We don't have to worry about cap_pipe_read_mtx here */
   g_async_queue_push(cap_pipe_pending_q, ld->cap_pipe_buf);
-  g_get_current_time(&wait_time);
-  g_time_val_add(&wait_time, THREAD_OPEN_TIMEOUT);
-  q_status = g_async_queue_timed_pop(cap_pipe_done_q, &wait_time);
-  if (!q_status) {
-    /* XXX - Are there more appropriate values we should use? */
-    g_snprintf(errmsg, errmsgl, "Timeout on pipe magic during open");
-    goto error;
-  } else if (ld->cap_pipe_bytes_read <= 0) {
+  g_async_queue_pop(cap_pipe_done_q);
+  if (ld->cap_pipe_bytes_read <= 0) {
     if (ld->cap_pipe_bytes_read == 0)
       g_snprintf(errmsg, errmsgl, "End of file on pipe magic during open");
     else
@@ -1001,7 +1404,7 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
                  strerror(errno));
     goto error;
   }
-  
+
 #endif /* USE_THREADS */
 
   switch (magic) {
@@ -1065,13 +1468,8 @@ cap_pipe_open_live(char *pipename, struct pcap_hdr *hdr, loop_data *ld,
   ld->cap_pipe_bytes_read = 0;
   ld->cap_pipe_bytes_to_read = sizeof(struct pcap_hdr);
   g_async_queue_push(cap_pipe_pending_q, ld->cap_pipe_buf);
-  g_get_current_time(&wait_time);
-  g_time_val_add(&wait_time, THREAD_OPEN_TIMEOUT);
-  q_status = g_async_queue_timed_pop(cap_pipe_done_q, &wait_time);
-  if (!q_status) {
-    g_snprintf(errmsg, errmsgl, "Timeout on pipe header during open");
-    goto error;
-  } else if (ld->cap_pipe_bytes_read <= 0) {
+  g_async_queue_pop(cap_pipe_done_q);
+  if (ld->cap_pipe_bytes_read <= 0) {
     if (ld->cap_pipe_bytes_read == 0)
       g_snprintf(errmsg, errmsgl, "End of file on pipe header during open");
     else
@@ -1108,11 +1506,6 @@ error:
 #ifndef _WIN32
   ws_close(fd);
   ld->cap_pipe_fd = -1;
-#else
-  if (ld->cap_pipe_h != INVALID_HANDLE_VALUE) {
-    CloseHandle(ld->cap_pipe_h);
-    ld->cap_pipe_h = INVALID_HANDLE_VALUE;
-  }
 #endif
   return;
 
@@ -1384,32 +1777,64 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
      the error buffer, and check if it's still a null string.  */
   open_err_str[0] = '\0';
 #ifdef HAVE_PCAP_OPEN
-  auth.type = capture_opts->auth_type == CAPTURE_AUTH_PWD ?
-                    RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
-  auth.username = capture_opts->auth_username;
-  auth.password = capture_opts->auth_password;
-
-  ld->pcap_h = pcap_open(capture_opts->iface,
-               capture_opts->has_snaplen ? capture_opts->snaplen :
-                          WTAP_MAX_PACKET_SIZE,
-               /* flags */
-               (capture_opts->promisc_mode ? PCAP_OPENFLAG_PROMISCUOUS : 0) |
-               (capture_opts->datatx_udp ? PCAP_OPENFLAG_DATATX_UDP : 0) |
-               (capture_opts->nocap_rpcap ? PCAP_OPENFLAG_NOCAPTURE_RPCAP : 0),
-               CAP_READ_TIMEOUT, &auth, open_err_str);
+  /*
+   * If we're opening a remote device, use pcap_open(); that's currently
+   * the only open routine that supports remote devices.
+   */
+  if (strncmp (capture_opts->iface, "rpcap://", 8) == 0) {
+    auth.type = capture_opts->auth_type == CAPTURE_AUTH_PWD ?
+      RPCAP_RMTAUTH_PWD : RPCAP_RMTAUTH_NULL;
+    auth.username = capture_opts->auth_username;
+    auth.password = capture_opts->auth_password;
+
+    ld->pcap_h = pcap_open(capture_opts->iface,
+                 capture_opts->has_snaplen ? capture_opts->snaplen :
+                            WTAP_MAX_PACKET_SIZE,
+                 /* flags */
+                 (capture_opts->promisc_mode ? PCAP_OPENFLAG_PROMISCUOUS : 0) |
+                 (capture_opts->datatx_udp ? PCAP_OPENFLAG_DATATX_UDP : 0) |
+                 (capture_opts->nocap_rpcap ? PCAP_OPENFLAG_NOCAPTURE_RPCAP : 0),
+                 CAP_READ_TIMEOUT, &auth, open_err_str);
+  } else
+#endif /* HAVE_PCAP_OPEN */
+  {
+    /*
+     * If we're not opening a remote device, use pcap_create() and
+     * pcap_activate() if we have them, so that we can set the buffer
+     * size, otherwise use pcap_open_live().
+     */
+#ifdef HAVE_PCAP_CREATE
+    ld->pcap_h = pcap_create(capture_opts->iface, open_err_str);
+    if (ld->pcap_h != NULL) {
+      pcap_set_snaplen(ld->pcap_h, capture_opts->has_snaplen ? capture_opts->snaplen : WTAP_MAX_PACKET_SIZE);
+      pcap_set_promisc(ld->pcap_h, capture_opts->promisc_mode);
+      pcap_set_timeout(ld->pcap_h, CAP_READ_TIMEOUT);
+
+      if (capture_opts->buffer_size > 1) {
+        pcap_set_buffer_size(ld->pcap_h, capture_opts->buffer_size * 1024 * 1024);
+      }
+      if (capture_opts->monitor_mode)
+        pcap_set_rfmon(ld->pcap_h, 1);
+      if (pcap_activate(ld->pcap_h) != 0) {
+        /* Failed to activate, set to NULL */
+        pcap_close(ld->pcap_h);
+        ld->pcap_h = NULL;
+      }
+    }
 #else
-  ld->pcap_h = pcap_open_live(capture_opts->iface,
-                              capture_opts->has_snaplen ? capture_opts->snaplen :
-                                                          WTAP_MAX_PACKET_SIZE,
-                              capture_opts->promisc_mode, CAP_READ_TIMEOUT,
-                              open_err_str);
-#endif
-
-/* If not using libcap: we now can now set euid/egid to ruid/rgid         */
-/*  to remove any suid privileges.                                        */
-/* If using libcap: we can now remove NET_RAW and NET_ADMIN capabilities  */
-/*  (euid/egid have already previously been set to ruid/rgid.             */
-/* (See comment in main() for details)                                    */
+    ld->pcap_h = pcap_open_live(capture_opts->iface,
+                                capture_opts->has_snaplen ? capture_opts->snaplen :
+                                                            WTAP_MAX_PACKET_SIZE,
+                                capture_opts->promisc_mode, CAP_READ_TIMEOUT,
+                                open_err_str);
+#endif
+  }
+
+  /* If not using libcap: we now can now set euid/egid to ruid/rgid         */
+  /*  to remove any suid privileges.                                        */
+  /* If using libcap: we can now remove NET_RAW and NET_ADMIN capabilities  */
+  /*  (euid/egid have already previously been set to ruid/rgid.             */
+  /* (See comment in main() for details)                                    */
 #ifndef HAVE_LIBCAP
   relinquish_special_privs_perm();
 #else
@@ -1423,7 +1848,7 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
     if (capture_opts->buffer_size > 1 &&
         pcap_setbuff(ld->pcap_h, capture_opts->buffer_size * 1024 * 1024) != 0) {
         sync_secondary_msg_str = g_strdup_printf(
-          "The capture buffer size of %luMB seems to be too high for your machine,\n"
+          "The capture buffer size of %dMB seems to be too high for your machine,\n"
           "the default of 1MB will be used.\n"
           "\n"
           "Nonetheless, the capture is started.\n",
@@ -1435,7 +1860,8 @@ capture_loop_open_input(capture_options *capture_opts, loop_data *ld,
 #endif
 
 #if defined(HAVE_PCAP_REMOTE) && defined(HAVE_PCAP_SETSAMPLING)
-    if (capture_opts->sampling_method != CAPTURE_SAMP_NONE)
+    if ((capture_opts->sampling_method != CAPTURE_SAMP_NONE) &&
+        (strncmp (capture_opts->iface, "rpcap://", 8) == 0))
     {
         struct pcap_samp *samp;
 
@@ -2539,7 +2965,7 @@ static void
 capture_loop_packet_cb(u_char *user, const struct pcap_pkthdr *phdr,
   const u_char *pd)
 {
-  loop_data *ld = (void *) user;
+  loop_data *ld = (loop_data *) (void *) user;
   int err;
 
   /* We may be called multiple times from pcap_dispatch(); if we've set
@@ -2601,19 +3027,34 @@ main(int argc, char *argv[])
 #endif
 
 #ifdef HAVE_PCAP_REMOTE
-#define OPTSTRING_INIT "a:A:b:c:Df:hi:Lm:MnprSs:uvw:y:Z:"
+#define OPTSTRING_A "A:"
+#define OPTSTRING_r "r"
+#define OPTSTRING_u "u"
 #else
-#define OPTSTRING_INIT "a:b:c:Df:hi:LMnpSs:vw:y:Z:"
+#define OPTSTRING_A ""
+#define OPTSTRING_r ""
+#define OPTSTRING_u ""
 #endif
 
-#ifdef _WIN32
-#define OPTSTRING_WIN32 "B:"
+#ifdef HAVE_PCAP_SETSAMPLING
+#define OPTSTRING_m "m:"
 #else
-#define OPTSTRING_WIN32 ""
-#endif  /* _WIN32 */
+#define OPTSTRING_m ""
+#endif
 
-  char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
-    OPTSTRING_INIT OPTSTRING_WIN32;
+#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
+#define OPTSTRING_B "B:"
+#else
+#define OPTSTRING_B ""
+#endif  /* _WIN32 or HAVE_PCAP_CREATE */
+
+#ifdef HAVE_PCAP_CREATE
+#define OPTSTRING_I "I"
+#else
+#define OPTSTRING_I ""
+#endif
+
+#define OPTSTRING "a:" OPTSTRING_A "b:" OPTSTRING_B "c:Df:hi:" OPTSTRING_I "L" OPTSTRING_m "Mnp" OPTSTRING_r "Ss:" OPTSTRING_u "vw:y:Z:"
 
 #ifdef DEBUG_CHILD_DUMPCAP
   if ((debug_log = ws_fopen("dumpcap_debug_log.tmp","w")) == NULL) {
@@ -2624,17 +3065,28 @@ main(int argc, char *argv[])
 
 #if defined(__APPLE__) && defined(__LP64__)
   /*
-   * Is this Mac OS X 10.6 or 10.6.1?  If so, we need a bug workaround.
+   * Is this Mac OS X 10.6.x, other than 10.6.2?  If so, we need a bug
+   * workaround - timeouts less than 1 second don't work with libpcap
+   * in 64-bit code.  (The bug was introduced in 10.6, fixed in 10.6.2,
+   * and re-introduced in 10.6.3.  We don't know whether it'll be fixed
+   * again in a later 10.6.x release; we'll assume that it'll be fixed
+   * in any future major releases.)
    */
   if (uname(&osinfo) == 0) {
     /*
-     * Mac OS X 10.x uses Darwin x.0.0.  Mac OS X 10.x.y uses Darwin
-     * x.y.0 (except that 10.6.1 appears to have a uname version
+     * Mac OS X 10.x uses Darwin {x+4}.0.0.  Mac OS X 10.x.y uses Darwin
+     * {x+4}.y.0 (except that 10.6.1 appears to have a uname version
      * number of 10.0.0, not 10.1.0 - go figure).
      */
-    if (strcmp(osinfo.release, "10.0.0") == 0 ||
-        strcmp(osinfo.release, "10.1.0") == 0)
-      need_timeout_workaround = 1;
+    if (strncmp(osinfo.release, "10.", 3) == 0) {
+      /*
+       * OK, it's Snow Leopard - which version?
+       */
+      if (strcmp(osinfo.release, "10.2.0") != 0) {
+        /* Not 10.6.2. */
+        need_timeout_workaround = TRUE;
+      }
+    }
   }
 #endif
 
@@ -2827,7 +3279,7 @@ main(int argc, char *argv[])
   global_capture_opts.has_ring_num_files  = TRUE;
 
   /* Now get our args */
-  while ((opt = getopt(argc, argv, optstring)) != -1) {
+  while ((opt = getopt(argc, argv, OPTSTRING)) != -1) {
     switch (opt) {
       case 'h':        /* Print help and exit */
         print_usage(TRUE);
@@ -2869,9 +3321,12 @@ main(int argc, char *argv[])
 #ifdef HAVE_PCAP_SETSAMPLING
       case 'm':        /* Sampling */
 #endif
-#ifdef _WIN32
+#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
       case 'B':        /* Buffer size */
-#endif /* _WIN32 */
+#endif /* _WIN32 or HAVE_PCAP_CREATE */
+#ifdef HAVE_PCAP_CREATE
+      case 'I':        /* Monitor mode */
+#endif
         status = capture_opts_add_opt(&global_capture_opts, opt, optarg, &start_capture);
         if(status != 0) {
           exit_main(status);
@@ -2989,11 +3444,57 @@ main(int argc, char *argv[])
   g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "Interface: %s\n", global_capture_opts.iface);
 
   if (list_interfaces) {
-    status = capture_opts_list_interfaces(machine_readable);
-    exit_main(status);
+    /* Get the list of interfaces */
+    GList       *if_list;
+    int         err;
+    gchar       *err_str;
+
+    if_list = capture_interface_list(&err, &err_str);
+    if (if_list == NULL) {
+        switch (err) {
+        case CANT_GET_INTERFACE_LIST:
+            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;
+        }
+        exit_main(2);
+    }
+
+    if (machine_readable)      /* tab-separated values to stdout */
+      print_machine_readable_interfaces(if_list);
+    else
+      capture_opts_print_interfaces(if_list);
+    free_interface_list(if_list);
+    exit_main(0);
   } else if (list_link_layer_types) {
-    status = capture_opts_list_link_layer_types(&global_capture_opts, machine_readable);
-    exit_main(status);
+    /* Get the list of link-layer types for the capture device. */
+    if_capabilities_t *caps;
+    gchar *err_str;
+
+    caps = get_if_capabilities(global_capture_opts.iface,
+                               global_capture_opts.monitor_mode, &err_str);
+    if (caps == NULL) {
+      cmdarg_err("The capabilities of the capture device \"%s\" could not be obtained (%s)."
+       "Please check to make sure you have sufficient permissions, and that\n"
+       "you have the proper interface or pipe specified.\n", global_capture_opts.iface, err_str);
+      g_free(err_str);
+      exit_main(2);
+    }
+    if (caps->data_link_types == NULL) {
+      cmdarg_err("The capture device \"%s\" has no data link types.", global_capture_opts.iface);
+      exit_main(2);
+    }
+    if (machine_readable)      /* tab-separated values to stdout */
+      print_machine_readable_if_capabilities(caps);
+    else
+      capture_opts_print_if_capabilities(caps,
+                                         global_capture_opts.monitor_mode);
+    free_if_capabilities(caps);
+    exit_main(0);
   } else if (print_statistics) {
     status = print_statistics_loop(machine_readable);
     exit_main(status);