![Roland Knall](/assets/img/avatar_default.png)
Extcap is a plugin interface, which allows for the usage of external capture interfaces via pipes using a predefined configuration language which results in a graphical gui. This implementation seeks for a generic implementation, which results in a seamless integration with the current system, and does add all external interfaces as simple interfaces. Windows Note: Due to limitations with GTK and Windows, a gspawn-winXX-helper.exe, respective gspawn-winXX-helper-console.exe is needed, which is part of any GTK windows installation. The default installation directory from the build is an extcap subdirectory underneath the run directory. The folder used by extcap may be viewed in the folders tab of the about dialog. The default installation directory for extcap plugins with a pre-build or installer version of wireshark is the extcap subdirectory underneath the main wireshark directory. For more information see: http://youtu.be/Nn84T506SwU bug #9009 Also take a look in doc/extcap_example.py for a Python-example and in extcap.pod for the arguments grammer. Todo: - Integrate with Qt - currently no GUI is generated, but the interfaces are still usable Change-Id: I4f1239b2f1ebd8b2969f73af137915f5be1ce50f Signed-off-by: Mike Ryan <mikeryan+wireshark@lacklustre.net> Signed-off-by: Mike Kershaw <dragorn@kismetwireless.net> Signed-off-by: Roland Knall <rknall@gmail.com> Reviewed-on: https://code.wireshark.org/review/359 Petri-Dish: Michael Mann <mmann78@netscape.net> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Michael Mann <mmann78@netscape.net>
374 lines
12 KiB
C
374 lines
12 KiB
C
/* capture_ifinfo.c
|
|
* Routines for getting interface information from dumpcap
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#ifdef HAVE_LIBPCAP
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#ifdef HAVE_ARPA_INET_H
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
|
#include <sys/socket.h> /* needed to define AF_ values on UNIX */
|
|
#endif
|
|
|
|
#ifdef HAVE_WINSOCK2_H
|
|
#include <winsock2.h> /* needed to define AF_ values on Windows */
|
|
#endif
|
|
|
|
#ifdef NEED_INET_V6DEFS_H
|
|
# include "wsutil/inet_v6defs.h"
|
|
#endif
|
|
|
|
#include <glib.h>
|
|
|
|
#include "capture_opts.h"
|
|
#include <capchild/capture_session.h>
|
|
#include <capchild/capture_sync.h>
|
|
#ifdef HAVE_EXTCAP
|
|
#include "extcap.h"
|
|
#endif
|
|
#include "log.h"
|
|
|
|
#include <caputils/capture_ifinfo.h>
|
|
|
|
#ifdef HAVE_PCAP_REMOTE
|
|
static GList *remote_interface_list = NULL;
|
|
|
|
static void append_remote_list(GList *iflist)
|
|
{
|
|
GSList *list;
|
|
GList *rlist;
|
|
if_addr_t *if_addr, *temp_addr;
|
|
if_info_t *if_info, *temp;
|
|
|
|
for (rlist = g_list_nth(remote_interface_list, 0); rlist != NULL; rlist = g_list_next(rlist)) {
|
|
if_info = (if_info_t *)rlist->data;
|
|
temp = g_malloc0(sizeof(if_info_t));
|
|
temp->name = g_strdup(if_info->name);
|
|
temp->friendly_name = g_strdup(if_info->friendly_name);
|
|
temp->vendor_description = g_strdup(if_info->vendor_description);
|
|
for (list = g_slist_nth(if_info->addrs, 0); list != NULL; list = g_slist_next(list)) {
|
|
temp_addr = g_malloc0(sizeof(if_addr_t));
|
|
if_addr = (if_addr_t *)list->data;
|
|
if (if_addr) {
|
|
temp_addr->ifat_type = if_addr->ifat_type;
|
|
if (temp_addr->ifat_type == IF_AT_IPv4) {
|
|
temp_addr->addr.ip4_addr = if_addr->addr.ip4_addr;
|
|
} else {
|
|
memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
|
|
}
|
|
} else {
|
|
g_free(temp_addr);
|
|
temp_addr = NULL;
|
|
}
|
|
if (temp_addr) {
|
|
temp->addrs = g_slist_append(temp->addrs, temp_addr);
|
|
}
|
|
}
|
|
temp->loopback = if_info->loopback;
|
|
iflist = g_list_append(iflist, temp);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* Fetch the interface list from a child process (dumpcap).
|
|
*
|
|
* @return A GList containing if_info_t structs if successful, NULL (with err and possibly err_str set) otherwise.
|
|
*
|
|
*/
|
|
|
|
/* XXX - We parse simple text output to get our interface list. Should
|
|
* we use "real" data serialization instead, e.g. via XML? */
|
|
GList *
|
|
capture_interface_list(int *err, char **err_str, void (*update_cb)(void))
|
|
{
|
|
int ret;
|
|
GList *if_list = NULL;
|
|
int i, j;
|
|
gchar *data, *primary_msg, *secondary_msg;
|
|
gchar **raw_list, **if_parts, **addr_parts;
|
|
gchar *name;
|
|
if_info_t *if_info;
|
|
if_addr_t *if_addr;
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
|
|
|
|
*err = 0;
|
|
#ifdef HAVE_EXTCAP
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Loading External Capture Interface List ...");
|
|
if_list = extcap_interface_list(err_str);
|
|
#endif
|
|
|
|
/* Try to get our interface list */
|
|
ret = sync_interface_list_open(&data, &primary_msg, &secondary_msg, update_cb);
|
|
if (ret != 0) {
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed, error %d, %s (%s)!",
|
|
*err, primary_msg ? primary_msg : "no message",
|
|
secondary_msg ? secondary_msg : "no secondary message");
|
|
if (err_str) {
|
|
*err_str = primary_msg;
|
|
} else {
|
|
g_free(primary_msg);
|
|
}
|
|
g_free(secondary_msg);
|
|
*err = CANT_GET_INTERFACE_LIST;
|
|
return NULL;
|
|
}
|
|
|
|
/* Split our lines */
|
|
#ifdef _WIN32
|
|
raw_list = g_strsplit(data, "\r\n", 0);
|
|
#else
|
|
raw_list = g_strsplit(data, "\n", 0);
|
|
#endif
|
|
g_free(data);
|
|
|
|
for (i = 0; raw_list[i] != NULL; i++) {
|
|
#ifdef HAVE_EXTCAP
|
|
if_parts = g_strsplit(raw_list[i], "\t", 7);
|
|
if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL ||
|
|
if_parts[3] == NULL || if_parts[4] == NULL || if_parts[5] == NULL ||
|
|
if_parts[6] == NULL) {
|
|
g_strfreev(if_parts);
|
|
continue;
|
|
}
|
|
#else
|
|
if_parts = g_strsplit(raw_list[i], "\t", 6);
|
|
if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL ||
|
|
if_parts[3] == NULL || if_parts[4] == NULL || if_parts[5] == NULL) {
|
|
g_strfreev(if_parts);
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
/* Number followed by the name, e.g "1. eth0" */
|
|
name = strchr(if_parts[0], ' ');
|
|
if (name) {
|
|
name++;
|
|
} else {
|
|
g_strfreev(if_parts);
|
|
continue;
|
|
}
|
|
|
|
if_info = g_new0(if_info_t,1);
|
|
if_info->name = g_strdup(name);
|
|
if (strlen(if_parts[1]) > 0)
|
|
if_info->vendor_description = g_strdup(if_parts[1]);
|
|
if (strlen(if_parts[2]) > 0)
|
|
if_info->friendly_name = g_strdup(if_parts[2]);
|
|
if_info->type = (interface_type)(int)strtol(if_parts[3], NULL, 10);
|
|
addr_parts = g_strsplit(if_parts[4], ",", 0);
|
|
for (j = 0; addr_parts[j] != NULL; j++) {
|
|
if_addr = g_new0(if_addr_t,1);
|
|
if (inet_pton(AF_INET, addr_parts[j], &if_addr->addr.ip4_addr) > 0) {
|
|
if_addr->ifat_type = IF_AT_IPv4;
|
|
} else if (inet_pton(AF_INET6, addr_parts[j],
|
|
&if_addr->addr.ip6_addr) > 0) {
|
|
if_addr->ifat_type = IF_AT_IPv6;
|
|
} else {
|
|
g_free(if_addr);
|
|
if_addr = NULL;
|
|
}
|
|
if (if_addr) {
|
|
if_info->addrs = g_slist_append(if_info->addrs, if_addr);
|
|
}
|
|
}
|
|
if (strcmp(if_parts[5], "loopback") == 0)
|
|
if_info->loopback = TRUE;
|
|
#ifdef HAVE_EXTCAP
|
|
if_info->extcap = g_strdup(if_parts[6]);
|
|
#endif
|
|
g_strfreev(if_parts);
|
|
g_strfreev(addr_parts);
|
|
if_list = g_list_append(if_list, if_info);
|
|
}
|
|
g_strfreev(raw_list);
|
|
|
|
#ifdef HAVE_PCAP_REMOTE
|
|
if (remote_interface_list && g_list_length(remote_interface_list) > 0) {
|
|
append_remote_list(if_list);
|
|
}
|
|
#endif
|
|
return if_list;
|
|
}
|
|
|
|
/* XXX - We parse simple text output to get our interface list. Should
|
|
* we use "real" data serialization instead, e.g. via XML? */
|
|
if_capabilities_t *
|
|
capture_get_if_capabilities(const gchar *ifname, gboolean monitor_mode,
|
|
char **err_str, void (*update_cb)(void))
|
|
{
|
|
if_capabilities_t *caps;
|
|
GList *linktype_list = NULL;
|
|
int err, i;
|
|
gchar *data, *primary_msg, *secondary_msg;
|
|
gchar **raw_list, **lt_parts;
|
|
data_link_info_t *data_link_info;
|
|
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities ...");
|
|
|
|
#ifdef HAVE_EXTCAP
|
|
/* see if the interface is from extcap */
|
|
caps = extcap_get_if_dlts(ifname, err_str);
|
|
if (caps != NULL)
|
|
return caps;
|
|
|
|
/* return if the extcap interface generated an error */
|
|
if (err_str != NULL && *err_str != NULL)
|
|
return NULL;
|
|
#endif /* HAVE_EXTCAP */
|
|
|
|
/* Try to get our interface list */
|
|
err = sync_if_capabilities_open(ifname, monitor_mode, &data,
|
|
&primary_msg, &secondary_msg, update_cb);
|
|
if (err != 0) {
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities failed, error %d, %s (%s)!",
|
|
err, primary_msg ? primary_msg : "no message",
|
|
secondary_msg ? secondary_msg : "no secondary message");
|
|
if (err_str) {
|
|
*err_str = primary_msg;
|
|
} else {
|
|
g_free(primary_msg);
|
|
}
|
|
g_free(secondary_msg);
|
|
return NULL;
|
|
}
|
|
|
|
/* Split our lines */
|
|
#ifdef _WIN32
|
|
raw_list = g_strsplit(data, "\r\n", 0);
|
|
#else
|
|
raw_list = g_strsplit(data, "\n", 0);
|
|
#endif
|
|
g_free(data);
|
|
|
|
/*
|
|
* First line is 0 if monitor mode isn't supported, 1 if it is.
|
|
*/
|
|
if (raw_list[0] == NULL || *raw_list[0] == '\0') {
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities returned no information!");
|
|
if (err_str) {
|
|
*err_str = g_strdup("Dumpcap returned no interface capability information");
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Allocate the interface capabilities structure.
|
|
*/
|
|
caps = (if_capabilities_t *)g_malloc(sizeof *caps);
|
|
switch (*raw_list[0]) {
|
|
|
|
case '0':
|
|
caps->can_set_rfmon = FALSE;
|
|
break;
|
|
|
|
case '1':
|
|
caps->can_set_rfmon = TRUE;
|
|
break;
|
|
|
|
default:
|
|
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities returned bad information!");
|
|
if (err_str) {
|
|
*err_str = g_strdup_printf("Dumpcap returned \"%s\" for monitor-mode capability",
|
|
raw_list[0]);
|
|
}
|
|
g_free(caps);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* The rest are link-layer types.
|
|
*/
|
|
for (i = 1; raw_list[i] != NULL; i++) {
|
|
/* ...and what if the interface name has a tab in it, Mr. Clever Programmer? */
|
|
lt_parts = g_strsplit(raw_list[i], "\t", 3);
|
|
if (lt_parts[0] == NULL || lt_parts[1] == NULL || lt_parts[2] == NULL) {
|
|
g_strfreev(lt_parts);
|
|
continue;
|
|
}
|
|
|
|
data_link_info = g_new(data_link_info_t,1);
|
|
data_link_info->dlt = (int) strtol(lt_parts[0], NULL, 10);
|
|
data_link_info->name = g_strdup(lt_parts[1]);
|
|
if (strcmp(lt_parts[2], "(not supported)") != 0)
|
|
data_link_info->description = g_strdup(lt_parts[2]);
|
|
else
|
|
data_link_info->description = NULL;
|
|
|
|
linktype_list = g_list_append(linktype_list, data_link_info);
|
|
}
|
|
g_strfreev(raw_list);
|
|
|
|
/* Check to see if we built a list */
|
|
if (linktype_list == NULL) {
|
|
/* No. */
|
|
if (err_str)
|
|
*err_str = g_strdup("Dumpcap returned no link-layer types");
|
|
g_free(caps);
|
|
return NULL;
|
|
}
|
|
caps->data_link_types = linktype_list;
|
|
return caps;
|
|
}
|
|
|
|
#ifdef HAVE_PCAP_REMOTE
|
|
void add_interface_to_remote_list(if_info_t *if_info)
|
|
{
|
|
GSList *list;
|
|
if_addr_t *if_addr, *temp_addr;
|
|
|
|
if_info_t *temp = g_malloc0(sizeof(if_info_t));
|
|
temp->name = g_strdup(if_info->name);
|
|
temp->friendly_name = g_strdup(if_info->friendly_name);
|
|
temp->vendor_description = g_strdup(if_info->vendor_description);
|
|
for (list = g_slist_nth(if_info->addrs, 0); list != NULL; list = g_slist_next(list)) {
|
|
temp_addr = g_malloc0(sizeof(if_addr_t));
|
|
if_addr = (if_addr_t *)list->data;
|
|
if (if_addr) {
|
|
temp_addr->ifat_type = if_addr->ifat_type;
|
|
if (temp_addr->ifat_type == IF_AT_IPv4) {
|
|
temp_addr->addr.ip4_addr = if_addr->addr.ip4_addr;
|
|
} else {
|
|
memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
|
|
}
|
|
} else {
|
|
g_free(temp_addr);
|
|
temp_addr = NULL;
|
|
}
|
|
if (temp_addr) {
|
|
temp->addrs = g_slist_append(temp->addrs, temp_addr);
|
|
}
|
|
}
|
|
temp->loopback = if_info->loopback;
|
|
remote_interface_list = g_list_append(remote_interface_list, temp);
|
|
}
|
|
#endif
|
|
#endif /* HAVE_LIBPCAP */
|