#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 <sys/un.h>
#endif
+#ifdef NEED_INET_V6DEFS_H
+# include "inet_v6defs.h"
+#endif
+
#include <wsutil/privileges.h>
#include "sync_pipe.h"
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: platform-dependent)\n");
+ 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");
fprintf(output, " -D print list of interfaces and exit\n");
return data_link_info;
}
-static GList *
-get_pcap_linktype_list(const char *devname, char **err_str)
+static if_capabilities_t *
+get_if_capabilities(const char *devname, gboolean monitor_mode
+#ifndef HAVE_PCAP_CREATE
+ _U_
+#endif
+, char **err_str)
{
- GList *linktype_list = NULL;
+ if_capabilities_t *caps;
+ char errbuf[PCAP_ERRBUF_SIZE];
pcap_t *pch;
+#ifdef HAVE_PCAP_CREATE
+ int status;
+#endif
int deflt;
- char errbuf[PCAP_ERRBUF_SIZE];
#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);
-#endif
+ caps->can_set_rfmon = FALSE;
if (pch == NULL) {
if (err_str != NULL)
*err_str = g_strdup(errbuf);
- return NULL;
+ g_free(caps);
+ return NULL;
}
+#endif
deflt = get_pcap_linktype(pch, devname);
#ifdef HAVE_PCAP_LIST_DATALINKS
nlt = pcap_list_datalinks(pch, &linktypes);
*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]);
* device has as the default?
*/
if (linktypes[i] == deflt)
- linktype_list = g_list_prepend(linktype_list, data_link_info);
+ caps->data_link_types = g_list_prepend(caps->data_link_types,
+ data_link_info);
else
- linktype_list = g_list_append(linktype_list, data_link_info);
+ caps->data_link_types = g_list_append(caps->data_link_types,
+ data_link_info);
}
#ifdef HAVE_PCAP_FREE_DATALINKS
pcap_free_datalinks(linktypes);
#else /* HAVE_PCAP_LIST_DATALINKS */
data_link_info = create_data_link_info(deflt);
- linktype_list = g_list_append(linktype_list, data_link_info);
+ 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 linktype_list;
+ 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];
+
+ /* Let our parent know we succeeded. */
+ pipe_write_block(2, SP_SUCCESS, NULL);
+
+ 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_sync.c:sync_linktype_list_open() accordingly!
+ * you MUST update capture_ifinfo.c:capture_get_if_capabilities() accordingly!
*/
static void
-print_machine_readable_link_layer_types(GList *lt_list)
+print_machine_readable_if_capabilities(if_capabilities_t *caps)
{
GList *lt_entry;
data_link_info_t *data_link_info;
const gchar *desc_str;
- for (lt_entry = lt_list; lt_entry != NULL; lt_entry = g_list_next(lt_entry)) {
+ /* Let our parent know we succeeded. */
+ pipe_write_block(2, SP_SUCCESS, NULL);
+
+ 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;
return 2;
}
+ /* Let our parent know we succeeded. */
+ pipe_write_block(2, SP_SUCCESS, NULL);
+
if (!machine_readable) {
printf("%-15s %10s %10s\n", "Interface", "Received",
"Dropped");
the error buffer, and check if it's still a null string. */
open_err_str[0] = '\0';
#ifdef HAVE_PCAP_OPEN
+ /*
+ * 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;
(capture_opts->nocap_rpcap ? PCAP_OPENFLAG_NOCAPTURE_RPCAP : 0),
CAP_READ_TIMEOUT, &auth, open_err_str);
} else
-#elif defined(HAVE_PCAP_CREATE)
+#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);
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
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) {
/* Get the list of link-layer types for the capture device. */
- GList *lt_list;
+ if_capabilities_t *caps;
gchar *err_str;
- lt_list = get_pcap_linktype_list(global_capture_opts.iface, &err_str);
- if (lt_list == NULL) {
- if (err_str != NULL) {
- cmdarg_err("The list of data link types for 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);
- } else
- cmdarg_err("The capture device \"%s\" has no data link types.", global_capture_opts.iface);
+ 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).\n"
+ "Please check to make sure you have sufficient permissions, and that\n"
+ "you have the proper interface or pipe specified.", 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_link_layer_types(lt_list);
+ print_machine_readable_if_capabilities(caps);
else
- capture_opts_print_link_layer_types(lt_list);
- free_pcap_linktype_list(lt_list);
+ 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);