Extcap Capture Interface

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>
This commit is contained in:
Roland Knall 2014-02-25 14:05:11 +01:00 committed by Michael Mann
parent 401469880b
commit bed29af46d
33 changed files with 3589 additions and 18 deletions

View File

@ -792,6 +792,11 @@ foreach(PLUGIN_DIR ${PLUGIN_SRC_DIRS})
add_subdirectory( ${PLUGIN_DIR} )
endforeach()
if(ENABLE_EXTCAP)
set(HAVE_EXTCAP 1)
set(EXTCAP_DIR "${DATAFILE_DIR}/extcap/")
endif()
add_subdirectory( asn1 EXCLUDE_FROM_ALL )
add_subdirectory( capchild )
add_subdirectory( caputils )
@ -945,6 +950,15 @@ set(SHARK_COMMON_SRC
version_info.c
)
# sources for external capture interfaces
if(ENABLE_EXTCAP)
set(SHARK_COMMON_SRC
${SHARK_COMMON_SRC}
extcap.c
extcap_parser.c
)
endif()
set(TSHARK_TAP_SRC
ui/cli/tap-afpstat.c
ui/cli/tap-ansi_astat.c

View File

@ -44,6 +44,7 @@ endif()
option(ENABLE_STATIC "Build a static version of Wireshark (not yet working)" OFF)
option(ENABLE_ECHLD "Enable echld support" OFF)
option(ENABLE_PLUGINS "Build with plugins" ON)
option(ENABLE_EXTCAP "Build with extcap hooks" ON)
option(ENABLE_GUIDES "Build Guides" OFF)
option(ENABLE_PCAP_NG_DEFAULT "Enable pcap-ng as default file format" ON)

View File

@ -44,12 +44,16 @@ SHARK_COMMON_SRC = \
cfile.c \
frame_tvbuff.c \
sync_pipe_write.c \
version_info.c
version_info.c \
extcap.c \
extcap_parser.c
# corresponding headers
SHARK_COMMON_INCLUDES = \
cfile.h \
color.h \
extcap.h \
extcap_parser.h \
file.h \
fileset.h \
frame_tvbuff.h \

View File

@ -1371,6 +1371,8 @@ install-all: install-generated-files
xcopy $(GTK_DIR)\bin\libgobject-2.0-0.dll $(INSTALL_DIR) /d
xcopy $(GTK_DIR)\bin\libgthread-2.0-0.dll $(INSTALL_DIR) /d
xcopy $(GTK_DIR)\bin\$(INTL_DLL) $(INSTALL_DIR) /d
xcopy $(GTK_DIR)\bin\gspawn-$(WIRESHARK_TARGET_PLATFORM)-helper.exe $(INSTALL_DIR) /d
xcopy $(GTK_DIR)\bin\gspawn-$(WIRESHARK_TARGET_PLATFORM)-helper-console.exe $(INSTALL_DIR) /d
!IFDEF ZLIB_DIR
xcopy $(ZLIB_DLL) $(INSTALL_DIR) /d
!ENDIF

View File

@ -49,6 +49,9 @@
#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>
@ -117,6 +120,10 @@ capture_interface_list(int *err, char **err_str, void (*update_cb)(void))
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);
@ -143,12 +150,22 @@ capture_interface_list(int *err, char **err_str, void (*update_cb)(void))
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], ' ');
@ -184,6 +201,9 @@ capture_interface_list(int *err, char **err_str, void (*update_cb)(void))
}
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);
@ -213,6 +233,17 @@ capture_get_if_capabilities(const gchar *ifname, gboolean monitor_mode,
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);

View File

@ -98,6 +98,9 @@
#include <wsutil/filesystem.h>
#include <wsutil/file_util.h>
#include <wsutil/report_err.h>
#ifdef HAVE_EXTCAP
#include "extcap.h"
#endif
#include "log.h"
#ifdef _WIN32
@ -391,6 +394,14 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
cap_session->fork_child = -1;
#ifdef HAVE_EXTCAP
if (!extcaps_init_initerfaces(capture_opts)) {
report_failure("Unable to init extcaps. (tmp fifo already exists?)");
return FALSE;
}
#endif
argv = init_pipe_args(&argc);
if (!argv) {
/* We don't know where to find dumpcap. */
@ -463,7 +474,12 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
interface_opts = g_array_index(capture_opts->ifaces, interface_options, j);
argv = sync_pipe_add_arg(argv, &argc, "-i");
argv = sync_pipe_add_arg(argv, &argc, interface_opts.name);
#ifdef HAVE_EXTCAP
if (interface_opts.extcap_fifo != NULL)
argv = sync_pipe_add_arg(argv, &argc, interface_opts.extcap_fifo);
else
#endif
argv = sync_pipe_add_arg(argv, &argc, interface_opts.name);
if (interface_opts.cfilter != NULL && strlen(interface_opts.cfilter) != 0) {
argv = sync_pipe_add_arg(argv, &argc, "-f");
@ -476,8 +492,12 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
}
if (interface_opts.linktype != -1) {
argv = sync_pipe_add_arg(argv, &argc, "-y");
argv = sync_pipe_add_arg(argv, &argc, linktype_val_to_name(interface_opts.linktype));
const char *linktype = linktype_val_to_name(interface_opts.linktype);
if ( linktype != NULL )
{
argv = sync_pipe_add_arg(argv, &argc, "-y");
argv = sync_pipe_add_arg(argv, &argc, linktype);
}
}
if (!interface_opts.promisc_mode) {
@ -487,6 +507,8 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
if (interface_opts.buffer_size != DEFAULT_CAPTURE_BUFFER_SIZE) {
argv = sync_pipe_add_arg(argv, &argc, "-B");
if(interface_opts.buffer_size == 0x00)
interface_opts.buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE;
g_snprintf(buffer_size, ARGV_NUMBER_LEN, "%d", interface_opts.buffer_size);
argv = sync_pipe_add_arg(argv, &argc, buffer_size);
}
@ -591,7 +613,20 @@ sync_pipe_start(capture_options *capture_opts, capture_session *cap_session, voi
#else
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE; /* this hides the console window */
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
#if defined(_WIN32)
/* needs first a check if NULL *
* otherwise wouldnt work with non extcap interfaces */
if(interface_opts.extcap_fifo != NULL)
{
if(strncmp(interface_opts.extcap_fifo,"\\\\.\\pipe\\",9)== 0)
{
si.hStdInput = extcap_get_win32_handle();
}
}
else
#endif
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = sync_pipe_write;
/*si.hStdError = (HANDLE) _get_osfhandle(2);*/
@ -805,7 +840,8 @@ sync_pipe_open_command(char** argv, int *data_read_fd,
#else
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE; /* this hides the console window */
si.hStdInput = NULL;
si.hStdInput = NULL; /* handle for named pipe*/
si.hStdOutput = data_pipe[PIPE_WRITE];
si.hStdError = sync_pipe[PIPE_WRITE];
#endif
@ -1740,6 +1776,10 @@ sync_pipe_input_cb(gint source, gpointer user_data)
#ifdef _WIN32
ws_close(cap_session->signal_pipe_write_fd);
#endif
#ifdef HAVE_EXTCAP
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "sync_pipe_input_cb: cleaning extcap pipe");
extcap_cleanup(cap_session->capture_opts);
#endif
capture_input_closed(cap_session, primary_msg);
g_free(primary_msg);
@ -2047,7 +2087,6 @@ sync_pipe_stop(capture_session *cap_session)
DWORD childstatus;
gboolean terminate = TRUE;
#endif
if (cap_session->fork_child != -1) {
#ifndef _WIN32
/* send the SIGINT signal to close the capture child gracefully. */
@ -2116,6 +2155,7 @@ sync_pipe_kill(int fork_child)
* And this also will require to have the process id.
*/
TerminateProcess((HANDLE) (fork_child), 0);
#endif
}
}

View File

@ -66,6 +66,12 @@ capture_opts_init(capture_options *capture_opts)
capture_opts->default_options.linktype = -1; /* use interface default */
capture_opts->default_options.promisc_mode = TRUE;
capture_opts->default_options.if_type = IF_WIRED;
#ifdef HAVE_EXTCAP
capture_opts->default_options.extcap = NULL;
capture_opts->default_options.extcap_fifo = NULL;
capture_opts->default_options.extcap_args = NULL;
capture_opts->default_options.extcap_pid = (GPid)-1;
#endif
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
capture_opts->default_options.buffer_size = DEFAULT_CAPTURE_BUFFER_SIZE;
#endif
@ -138,6 +144,11 @@ capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_optio
g_log(log_domain, log_level, "Snap length[%02d] (%u) : %d", i, interface_opts.has_snaplen, interface_opts.snaplen);
g_log(log_domain, log_level, "Link Type[%02d] : %d", i, interface_opts.linktype);
g_log(log_domain, log_level, "Promiscuous Mode[%02d]: %s", i, interface_opts.promisc_mode?"TRUE":"FALSE");
#ifdef HAVE_EXTCAP
g_log(log_domain, log_level, "Extcap[%02d] : %s", i, interface_opts.extcap ? interface_opts.extcap : "(unspecified)");
g_log(log_domain, log_level, "Extcap FIFO[%02d] : %s", i, interface_opts.extcap_fifo ? interface_opts.extcap_fifo : "(unspecified)");
g_log(log_domain, log_level, "Extcap PID[%02d] : %d", i, interface_opts.extcap_pid);
#endif
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
g_log(log_domain, log_level, "Buffer size[%02d] : %d (MB)", i, interface_opts.buffer_size);
#endif
@ -174,6 +185,10 @@ capture_opts_log(const char *log_domain, GLogLevelFlags log_level, capture_optio
g_log(log_domain, log_level, "Snap length[df] (%u) : %d", capture_opts->default_options.has_snaplen, capture_opts->default_options.snaplen);
g_log(log_domain, log_level, "Link Type[df] : %d", capture_opts->default_options.linktype);
g_log(log_domain, log_level, "Promiscuous Mode[df]: %s", capture_opts->default_options.promisc_mode?"TRUE":"FALSE");
#ifdef HAVE_EXTCAP
g_log(log_domain, log_level, "Extcap[df] : %s", capture_opts->default_options.extcap ? capture_opts->default_options.extcap : "(unspecified)");
g_log(log_domain, log_level, "Extcap FIFO[df] : %s", capture_opts->default_options.extcap_fifo ? capture_opts->default_options.extcap_fifo : "(unspecified)");
#endif
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
g_log(log_domain, log_level, "Buffer size[df] : %d (MB)", capture_opts->default_options.buffer_size);
#endif
@ -591,6 +606,12 @@ capture_opts_add_iface_opt(capture_options *capture_opts, const char *optarg_str
interface_opts.linktype = capture_opts->default_options.linktype;
interface_opts.promisc_mode = capture_opts->default_options.promisc_mode;
interface_opts.if_type = capture_opts->default_options.if_type;
#ifdef HAVE_EXTCAP
interface_opts.extcap = g_strdup(capture_opts->default_options.extcap);
interface_opts.extcap_fifo = g_strdup(capture_opts->default_options.extcap_fifo);
interface_opts.extcap_args = NULL;
interface_opts.extcap_pid = (GPid)-1;
#endif
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
interface_opts.buffer_size = capture_opts->default_options.buffer_size;
#endif
@ -1020,6 +1041,14 @@ capture_opts_del_iface(capture_options *capture_opts, guint if_index)
if (interface_opts.console_display_name != NULL)
g_free(interface_opts.console_display_name);
g_free(interface_opts.cfilter);
#ifdef HAVE_EXTCAP
g_free(interface_opts.extcap);
g_free(interface_opts.extcap_fifo);
if (interface_opts.extcap_args)
g_hash_table_unref(interface_opts.extcap_args);
if (interface_opts.extcap_pid > 0)
g_spawn_close_pid(interface_opts.extcap_pid);
#endif
#ifdef HAVE_PCAP_REMOTE
if (interface_opts.src_type == CAPTURE_IFREMOTE) {
g_free(interface_opts.remote_host);
@ -1061,6 +1090,13 @@ collect_ifaces(capture_options *capture_opts)
interface_opts.has_snaplen = device.has_snaplen;
interface_opts.promisc_mode = device.pmode;
interface_opts.if_type = device.if_info.type;
#ifdef HAVE_EXTCAP
interface_opts.extcap = g_strdup(device.if_info.extcap);
interface_opts.extcap_fifo = NULL;
interface_opts.extcap_args = device.external_cap_args_settings;
interface_opts.extcap_pid = (GPid)-1;
g_hash_table_ref(interface_opts.extcap_args);
#endif
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
interface_opts.buffer_size = device.buffer;
#endif

View File

@ -195,6 +195,10 @@ typedef struct interface_tag {
gboolean selected;
gboolean hidden;
gboolean locked;
#ifdef HAVE_EXTCAP
/* External capture cached data */
GHashTable *external_cap_args_settings;
#endif
} interface_t;
typedef struct link_row_tag {
@ -212,6 +216,12 @@ typedef struct interface_options_tag {
int linktype;
gboolean promisc_mode;
interface_type if_type;
#ifdef HAVE_EXTCAP
gchar *extcap;
gchar *extcap_fifo;
GHashTable *extcap_args;
GPid extcap_pid;
#endif
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
int buffer_size;
#endif

View File

@ -246,6 +246,9 @@ if_info_new(const char *name, const char *description, gboolean loopback)
if_info->friendly_name = NULL; /* default - unknown */
if_info->vendor_description = NULL;
if_info->type = IF_WIRED; /* default */
#ifdef HAVE_EXTCAP
if_info->extcap = g_strdup("");
#endif
#ifdef _WIN32
/*
* Get the interface type.
@ -506,6 +509,9 @@ free_if_cb(gpointer data, gpointer user_data _U_)
g_free(if_info->name);
g_free(if_info->friendly_name);
g_free(if_info->vendor_description);
#ifdef HAVE_EXTCAP
g_free(if_info->extcap);
#endif
g_slist_foreach(if_info->addrs, free_if_info_addr_cb, NULL);
g_slist_free(if_info->addrs);

View File

@ -38,6 +38,9 @@ typedef enum {
IF_WIRELESS,
IF_DIALUP,
IF_USB,
#ifdef HAVE_EXTCAP
IF_EXTCAP,
#endif
IF_VIRTUAL
} interface_type;
@ -56,6 +59,9 @@ typedef struct {
GSList *addrs; /* containing address values of if_addr_t */
interface_type type; /* type of interface */
gboolean loopback; /* TRUE if loopback, FALSE otherwise */
#ifdef HAVE_EXTCAP
char *extcap; /* extcap arguments, which present the data to call the extcap interface */
#endif
} if_info_t;
/*

View File

@ -18,6 +18,12 @@
/* Build wsutil with SIMD optimization */
#cmakedefine HAVE_SSE4_2 1
/* Directory where extcap hooks reside */
#define EXTCAP_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/${CPACK_PACKAGE_NAME}/extcap/"
/* Define to 1 if we want to enable extcap */
#cmakedefine HAVE_EXTCAP 1
/* Define to 1 if we want to enable plugins */
#cmakedefine HAVE_PLUGINS 1

View File

@ -39,6 +39,7 @@
#define YYTEXT_POINTER 1
#define HAVE_PLUGINS 1
#define HAVE_EXTCAP 1
/* #undef HAVE_SA_LEN */

View File

@ -2699,6 +2699,32 @@ CPPFLAGS="$CPPFLAGS '-DPLUGIN_INSTALL_DIR=\"\$(plugindir)\"'"
PLUGIN_LIBS=""
AC_SUBST(PLUGIN_LIBS)
dnl Use extcap by default
extcapdir='${datadir}/wireshark/extcap/'
AC_ARG_WITH(extcap,
AC_HELP_STRING( [--with-extcap@<:@=DIR@:>@],
[use extcap for external capture sources (installed in DIR, if supplied) @<:@default=yes, if possible@:>@]),
[
if test "x$withval" = "xno"; then
have_extcap=no
elif test "x$withval" = "xyes"; then
have_extcap=yes
elif test "x$withval" != "xyes"; then
have_extcap=yes
extcapdir ="$withval"
fi
],[
have_extcap=yes
])
AM_CONDITIONAL(HAVE_EXTCAP, test "x$have_extcap" = "xyes")
if test "x$have_extcap" = "xyes"
then
AC_DEFINE(HAVE_EXTCAP, 1, [Define if external capture sources should be enabled])
AC_DEFINE_UNQUOTED(EXTCAP_DIR,"$extcapdir", [Directory for extcap plugins])
fi
AC_SUBST(extcapdir)
#
# Check if (emem) memory allocations must be 8-byte aligned.
# I haven't been able to write C code that reliably makes that determination
@ -3079,6 +3105,7 @@ echo " Install dumpcap with capabilities : $setcap_message"
echo " Install dumpcap setuid : $setuid_message"
echo " Use dumpcap group : $dumpcap_group_message"
echo " Use plugins : $have_plugins"
echo " Use external capture sources : $have_extcap"
echo " Use Lua library : $lua_message"
echo " Build rtp_player : $portaudio_message"
echo " Build profile binaries : $enable_profile_build"

78
doc/extcap.pod Normal file
View File

@ -0,0 +1,78 @@
=head1 NAME
extcap - Extcap grammar elements
=head1 SYNOPSIS
Suggested config grammar elements:
arg (options) argument for CLI calling
number Reference # of argument for other values, display order
call Literal argument to call (--call=...)
display Displayed name
default Default value, in proper form for type
range Range of valid values for UI checking (min,max) in proper form
type Argument type for UI filtering for raw, or UI type for selector:
integer
unsigned
long (may include scientific / special notation)
float
menu (display popup menu in UI)
selector (display selector table, all values as strings)
boolean (display checkbox)
radio (display group of radio buttons with provided values, all values as strings)
value (options) Values for argument selection
arg Argument # this value applies to
value Passed value
display Displayed value
default Boolean (true if default, all others ignored, ie default=true)
flag (options) external-capture level flags
dedicated Bypass dumpcap & mux for high speed
failure Failure message
Possible grammar example:
arg {number=0}{call=channel}{display=Wi-Fi Channel}{type=integer}
arg {number=1}{call=chanflags}{display=Channel Flags}{type=radio}
arg {number=2}{call=interface}{display=Interface}{type=selector}
value {arg=0}{range=1,11}
value {arg=1}{value=ht40p}{display=HT40+}
value {arg=1}{value=ht40m}{display=HT40-}
value {arg=1}{value=ht20}{display=HT20}
value {arg=2}{value=wlan0}{display=wlan0}
Example 2
arg {number=0}{call=usbdevice}{USB Device}{type=selector}
value {arg=0}{call=/dev/sysfs/usb/foo/123}{display=Ubertooth One sn 1234}
value {arg=0}{call=”/dev/sysfs/usb/foo/456}{display=Ubertooth One sn 8901}
Example 3
arg {number=0}{call=usbdevice}{USB Device}{type=selector}
flag {failure=Permission denied opening Ubertooth device}
Security awareness:
- Users running wireshark as root, we cant save you
- Dumpcap retains suid/setgid and group+x permissions to allow users in wireshark group only
- Third-party capture programs run w/ whatever privs theyre installed with
- If an attacker can write to a system binary directory, were game over anyhow
- Dont let wireshark be told to look for capture binaries somewhere else?
Notes:
- daemonized dumpcap?
- multiuser?
- sync_pipe.h commands
- expand pipe commands to have status notifications, etc?
- Wireshark->dumpcap options for channel control, etc?
TODO
define grammar
write grammar to HTML mockup
sketch interface with dumpcap
launch external-pcap from wireshark, bypass dumpcap
launch external-pcap from wireshark, hand fd to dumpcap
extract netif capture as first cap source

249
doc/extcap_example.py Executable file
View File

@ -0,0 +1,249 @@
#!/usr/bin/env python
"""
This is a generic example, which produces pcap packages every n seconds, and
is configurable via extcap options.
@note
{
To use this script on Windows, please generate an extcap_example.bat inside
the extcap folder, with the following content:
-------
@echo off
<Path to python interpreter> <Path to script file> $*
-------
Windows is not able to execute Python scripts directly, which also goes for all
other script-based formates beside VBScript
}
"""
import os
import sys
import signal
import re
import argparse
import time
import struct
import binascii
from threading import Thread
ERROR_USAGE = 0
ERROR_ARG = 1
ERROR_INTERFACE = 2
ERROR_FIFO = 3
doExit = False
globalinterface = 0
def signalHandler(signal, frame):
global doExit
doExit = True
#### EXTCAP FUNCTIONALITY
"""@brief Extcap configuration
This method prints the extcap configuration, which will be picked up by the
interface in Wireshark to present a interface specific configuration for
this extcap plugin
"""
def extcap_config(interface):
args = []
values = []
args.append ( (0, '--delay', 'Time delay', 'Time delay between packages', 'integer', '{range=1,15}') )
args.append ( (1, '--message', 'Message', 'Package message content', 'string', '') )
args.append ( (2, '--verify', 'Verify', 'Verify package content', 'boolflag', '') )
args.append ( (3, '--remote', 'Remote Channel', 'Remote Channel Selector', 'selector', ''))
values.append ( (3, "if1", "Remote1", "true" ) )
values.append ( (3, "if2", "Remote2", "false" ) )
for arg in args:
print ("arg {number=%d}{call=%s}{display=%s}{tooltip=%s}{type=%s}%s" % arg)
for value in values:
print ("value {arg=%d}{value=%s}{display=%s}{default=%s}" % value)
def extcap_interfaces():
print ("interface {value=example1}{display=Example interface usage for extcap}")
def extcap_dlts(interface):
if ( interface == 'example1' ):
print ("dlt {number=147}{name=USER0}{display=Demo Implementation for Extcap}")
"""
### FAKE DATA GENERATOR
Extcap capture routine
This routine simulates a capture by any kind of user defined device. The parameters
are user specified and must be handled by the extcap.
The data captured inside this routine is fake, so change this routine to present
your own input data, or call your own capture program via Popen for example. See
for more details.
"""
def unsigned(n):
return int(n) & 0xFFFFFFFF
def append_bytes(ba, blist):
for c in range(0, len(blist)):
ba.append(blist[c])
return ba
def pcap_fake_header():
header = bytearray()
header = append_bytes(header, struct.pack('<L', int ('a1b2c3d4', 16) ))
header = append_bytes(header, struct.pack('<H', unsigned(2)) ) # Pcap Major Version
header = append_bytes(header, struct.pack('<H', unsigned(4)) ) # Pcap Minor Version
header = append_bytes(header, struct.pack('<I', int(0))) # Timezone
header = append_bytes(header, struct.pack('<I', int(0))) # Accurancy of timestamps
header = append_bytes(header, struct.pack('<L', int ('0000ffff', 16) )) # Max Length of capture frame
header = append_bytes(header, struct.pack('<L', unsigned(1))) # Ethernet
return header
# Calculates and returns the IP checksum based on the given IP Header
def ip_checksum(iph):
#split into bytes
words = splitN(''.join(iph.split()),4)
csum = 0;
for word in words:
csum += int(word, base=16)
csum += (csum >> 16)
csum = csum & 0xFFFF ^ 0xFFFF
return csum
def pcap_fake_package ( message ):
pcap = bytearray()
#length = 14 bytes [ eth ] + 20 bytes [ ip ] + messagelength
caplength = len(message) + 14 + 20
timestamp = int(time.time())
pcap = append_bytes(pcap, struct.pack('<L', unsigned(timestamp) ) ) # timestamp seconds
pcap = append_bytes(pcap, struct.pack('<L', 0x00 ) ) # timestamp nanoseconds
pcap = append_bytes(pcap, struct.pack('<L', unsigned(caplength) ) ) # length captured
pcap = append_bytes(pcap, struct.pack('<L', unsigned(caplength) ) ) # length in frame
# ETH
pcap = append_bytes(pcap, struct.pack('h', 0 )) # source mac
pcap = append_bytes(pcap, struct.pack('h', 0 )) # source mac
pcap = append_bytes(pcap, struct.pack('h', 0 )) # source mac
pcap = append_bytes(pcap, struct.pack('h', 0 )) # dest mac
pcap = append_bytes(pcap, struct.pack('h', 0 )) # dest mac
pcap = append_bytes(pcap, struct.pack('h', 0 )) # dest mac
pcap = append_bytes(pcap, struct.pack('<h', unsigned(8) )) # protocol (ip)
# IP
pcap = append_bytes(pcap, struct.pack('b', int ( '45', 16) )) # IP version
pcap = append_bytes(pcap, struct.pack('b', int ( '0', 16) )) #
pcap = append_bytes(pcap, struct.pack('>H', unsigned(len(message)+20) )) # length of data + payload
pcap = append_bytes(pcap, struct.pack('<H', int ( '0', 16) )) # Identification
pcap = append_bytes(pcap, struct.pack('b', int ( '40', 16) )) # Don't fragment
pcap = append_bytes(pcap, struct.pack('b', int ( '0', 16) )) # Fragment Offset
pcap = append_bytes(pcap, struct.pack('b', int ( '40', 16) ))
pcap = append_bytes(pcap, struct.pack('B', 0xFE )) # Protocol (2 = unspecified)
pcap = append_bytes(pcap, struct.pack('<H', int ( '0000', 16) )) # Checksum
pcap = append_bytes(pcap, struct.pack('>L', int ( '7F000001', 16) )) # Source IP
pcap = append_bytes(pcap, struct.pack('>L', int ( '7F000001', 16) )) # Dest IP
pcap = append_bytes(pcap, message)
return pcap
def extcap_capture(interface, fifo, delay, verify, message, remote):
global doExit
signal.signal(signal.SIGINT, signalHandler)
signal.signal(signal.SIGTERM , signalHandler)
tdelay = delay if delay != 0 else 5
try:
os.stat(fifo)
except OSError:
doExit = True
print ( "Fifo does not exist, exiting!" )
fh = open(fifo, 'w+b', 0 )
fh.write (pcap_fake_header())
while doExit == False:
out = str( "%s|%04X%s|%s" % ( remote.strip(), len(message), message, verify ) )
try:
fh.write (pcap_fake_package(out))
time.sleep(tdelay)
except IOError:
doExit = True
fh.close()
####
def usage():
print ( "Usage: %s <--extcap-interfaces | --extcap-dlts | --extcap-interface | --extcap-config | --capture | --fifo>" % sys.argv[0] )
if __name__ == '__main__':
interface = ""
# Capture options
delay = 0
message = ""
parser = argparse.ArgumentParser(
prog="Extcap Example",
description="Extcap example program for python"
)
# Extcap Arguments
parser.add_argument("--capture", help="Start the capture routine", action="store_true" )
parser.add_argument("--extcap-interfaces", help="Provide a list of interfaces to capture from", action="store_true")
parser.add_argument("--extcap-interface", help="Provide the interface to capture from")
parser.add_argument("--extcap-dlts", help="Provide a list of dlts for the given interface", action="store_true")
parser.add_argument("--extcap-config", help="Provide a list of configurations for the given interface", action="store_true")
parser.add_argument("--fifo", help="Use together with capture to provide the fifo to dump data to")
# Interface Arguments
parser.add_argument("--verify", help="Demonstrates a verification bool flag", action="store_true" )
parser.add_argument("--delay", help="Demonstrates an integer variable", type=int, default=0, choices=[0, 1, 2, 3, 4, 5] )
parser.add_argument("--remote", help="Demonstrates a selector choice", default="if1", choices=["if1", "if2"] )
parser.add_argument("--message", help="Demonstrates string variable", nargs='?', default="" )
args = parser.parse_args()
if ( len(sys.argv) <= 1 ):
parser.exit("No arguments given!")
if ( args.extcap_interfaces == False and args.extcap_interface == None ):
parser.exit("An interface must be provided or the selection must be displayed")
if ( args.extcap_interfaces == True or args.extcap_interface == None ):
extcap_interfaces()
sys.exit(0)
m = re.match ( 'example(\d+)', args.extcap_interface )
if not m:
sys.exit(ERROR_INTERFACE)
interface = m.group(1)
message = args.message
if ( args.message == None or len(args.message) == 0 ):
message = "Extcap Test"
if args.extcap_config:
extcap_config(interface)
elif args.extcap_dlts:
extcap_dlts(interface)
elif args.capture:
if args.fifo is None:
sys.exit(ERROR_FIFO)
extcap_capture(interface, args.fifo, args.delay, args.verify, message, args.remote)
else:
usage()
sys.exit(ERROR_USAGE)

View File

@ -193,7 +193,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;
@ -1373,7 +1373,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");
}
}
@ -1864,14 +1866,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)) {
@ -1893,7 +1895,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;
@ -1947,12 +1949,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;
@ -2083,10 +2085,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;
@ -2105,7 +2113,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)",
@ -4526,7 +4534,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;
@ -4857,6 +4864,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) {
@ -4900,7 +4908,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);

654
extcap.c Normal file
View File

@ -0,0 +1,654 @@
/* extcap.h
*
* Routines for extcap external capture
* Copyright 2013, Mike Ryan <mikeryan@lacklustre.net>
*
* 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"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#include <process.h>
#include <time.h>
#else
/* Include for unlink */
#include <unistd.h>
#endif
#include <glib.h>
#include <log.h>
#include <wsutil/file_util.h>
#include <wsutil/filesystem.h>
#include <wsutil/tempfile.h>
#include "capture_opts.h"
#ifdef HAVE_EXTCAP
#include "extcap.h"
#include "extcap_parser.h"
#ifdef _WIN32
static HANDLE pipe_h = NULL;
#endif
/* internal container, for all the extcap interfaces that have been found.
* will be resetted by every call to extcap_interface_list() and is being
* used in extcap_get_if_* as well as extcaps_init_initerfaces to ensure,
* that only extcap interfaces are being given to underlying extcap programs
*/
static GHashTable *ifaces = NULL;
/* Prefix for the pipe interfaces */
#define EXTCAP_PIPE_PREFIX "wireshark_extcap"
/* Callback definition for extcap_foreach */
typedef gboolean (*extcap_cb_t)(const gchar *extcap, gchar *output, void *data,
gchar **err_str);
/* #define ARG_DEBUG */
#if ARG_DEBUG
static void extcap_debug_arguments ( extcap_arg *arg_iter );
#endif
static gboolean
extcap_if_exists(const char *ifname)
{
if ( ifname != NULL )
{
if ( ifaces != NULL )
{
if ( g_hash_table_size(ifaces) > 0 )
{
if ( g_hash_table_lookup(ifaces, (const gchar *)ifname) != NULL )
{
return TRUE;
}
}
}
}
return FALSE;
}
static gboolean
extcap_if_exists_for_extcap(const char *ifname, const char *extcap)
{
gchar * entry = NULL;
if ( extcap_if_exists(ifname) )
{
if ( ( entry = (gchar *)g_hash_table_lookup(ifaces, (const gchar *)ifname) ) != NULL )
{
if ( strcmp(entry, extcap) == 0 )
return TRUE;
}
}
return FALSE;
}
static gchar *
extcap_if_executable(const char *ifname)
{
if ( extcap_if_exists(ifname) )
return (gchar *)g_hash_table_lookup(ifaces, (const gchar *)ifname);
return (gchar *)NULL;
}
static void
extcap_if_cleanup(void)
{
if ( ifaces == NULL )
ifaces = g_hash_table_new(g_str_hash, g_str_equal);
g_hash_table_remove_all(ifaces);
}
static void
extcap_if_add(gchar *ifname, gchar *extcap)
{
if ( !g_hash_table_contains(ifaces, ifname) )
g_hash_table_insert(ifaces, ifname, extcap);
}
static void extcap_foreach(gint argc, gchar **args, extcap_cb_t cb,
void *cb_data, char **err_str, const char * ifname _U_) {
const char *dirname = get_extcap_dir();
GDir *dir;
const gchar *file;
gboolean keep_going;
gchar **argv;
keep_going = TRUE;
argv = (gchar **) g_malloc0(sizeof(gchar *) * (argc + 2));
if ((dir = g_dir_open(dirname, 0, NULL)) != NULL) {
#ifdef WIN32
dirname = g_strescape(dirname,NULL);
#endif
while (keep_going && (file = g_dir_read_name(dir)) != NULL ) {
GString *extcap_string = NULL;
gchar *extcap = NULL;
gchar *command_output = NULL;
gboolean status = FALSE;
gint i;
gint exit_status = 0;
GError *error = NULL;
/* full path to extcap binary */
extcap_string = g_string_new("");
#ifdef WIN32
g_string_printf(extcap_string, "%s\\\\%s",dirname,file);
extcap = g_string_free(extcap_string, FALSE);
#else
g_string_printf(extcap_string, "%s/%s", dirname, file);
extcap = g_string_free(extcap_string, FALSE);
#endif
if ( extcap_if_exists(ifname) && !extcap_if_exists_for_extcap(ifname, extcap ) )
continue;
argv[0] = extcap;
for (i = 0; i < argc; ++i)
argv[i+1] = args[i];
argv[argc+1] = NULL;
status = g_spawn_sync(dirname, argv, NULL,
(GSpawnFlags) 0, NULL, NULL,
&command_output, NULL, &exit_status, &error);
if (status && exit_status == 0)
keep_going = cb(extcap, command_output, cb_data, err_str);
g_free(extcap);
g_free(command_output);
}
g_dir_close(dir);
}
g_free(argv);
}
static gboolean dlt_cb(const gchar *extcap _U_, gchar *output, void *data,
char **err_str) {
extcap_token_sentence *tokens;
extcap_dlt *dlts, *dlt_iter, *next;
if_capabilities_t *caps;
GList *linktype_list = NULL;
data_link_info_t *data_link_info;
tokens = extcap_tokenize_sentences(output);
extcap_parse_dlts(tokens, &dlts);
extcap_free_tokenized_sentence_list(tokens);
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap pipe %s ", extcap);
/*
* Allocate the interface capabilities structure.
*/
caps = (if_capabilities_t *) g_malloc(sizeof *caps);
caps->can_set_rfmon = FALSE;
dlt_iter = dlts;
while (dlt_iter != NULL ) {
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
" DLT %d name=\"%s\" display=\"%s\" ", dlt_iter->number,
dlt_iter->name, dlt_iter->display);
data_link_info = g_new(data_link_info_t, 1);
data_link_info->dlt = dlt_iter->number;
data_link_info->name = g_strdup(dlt_iter->name);
data_link_info->description = g_strdup(dlt_iter->display);
linktype_list = g_list_append(linktype_list, data_link_info);
dlt_iter = dlt_iter->next_dlt;
}
/* Check to see if we built a list */
if (linktype_list != NULL && data != NULL) {
caps->data_link_types = linktype_list;
*(if_capabilities_t **) data = caps;
} else {
if (err_str) {
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, " returned no DLTs");
*err_str = g_strdup("Extcap returned no DLTs");
}
g_free(caps);
}
dlt_iter = dlts;
while (dlt_iter != NULL ) {
next = dlt_iter->next_dlt;
extcap_free_dlt(dlt_iter);
dlt_iter = next;
}
return FALSE;
}
if_capabilities_t *
extcap_get_if_dlts(const gchar *ifname, char **err_str) {
gchar *argv[3];
gint i;
if_capabilities_t *caps = NULL;
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, " returned no DLTs");
if (ifname != NULL && err_str != NULL)
*err_str = NULL;
if ( extcap_if_exists(ifname) )
{
argv[0] = g_strdup(EXTCAP_ARGUMENT_LIST_DLTS);
argv[1] = g_strdup(EXTCAP_ARGUMENT_INTERFACE);
argv[2] = g_strdup(ifname);
if (err_str)
*err_str = NULL;
extcap_foreach(3, argv, dlt_cb, &caps, err_str, ifname);
for (i = 0; i < 3; ++i)
g_free(argv[i]);
}
return caps;
}
static gboolean interfaces_cb(const gchar *extcap, gchar *output, void *data,
char **err_str _U_) {
GList **il = (GList **) data;
extcap_token_sentence *tokens;
extcap_interface *interfaces, *int_iter; /*, *next; */
if_info_t *if_info;
tokens = extcap_tokenize_sentences(output);
extcap_parse_interfaces(tokens, &interfaces);
extcap_free_tokenized_sentence_list(tokens);
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap pipe %s ", extcap);
int_iter = interfaces;
while (int_iter != NULL ) {
if ( extcap_if_exists(int_iter->call) )
{
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_WARNING, "Extcap interface \"%s\" is already provided by \"%s\" ",
int_iter->call, (gchar *)extcap_if_executable(int_iter->call) );
int_iter = int_iter->next_interface;
continue;
}
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, " Interface [%s] \"%s\" ",
int_iter->call, int_iter->display);
if_info = g_new0(if_info_t, 1);
if_info->name = g_strdup(int_iter->call);
if_info->friendly_name = g_strdup(int_iter->display);
if_info->type = IF_EXTCAP;
if_info->extcap = g_strdup(extcap);
*il = g_list_append(*il, if_info);
extcap_if_add(g_strdup(int_iter->call), g_strdup(extcap) );
int_iter = int_iter->next_interface;
}
return TRUE;
}
GList *
extcap_interface_list(char **err_str) {
gchar *argv;
/* gint i; */
GList *ret = NULL;
if (err_str != NULL)
*err_str = NULL;
extcap_if_cleanup();
argv = g_strdup(EXTCAP_ARGUMENT_LIST_INTERFACES);
if (err_str)
*err_str = NULL;
extcap_foreach(1, &argv, interfaces_cb, &ret, err_str, NULL);
g_free(argv);
return ret;
}
static gboolean search_cb(const gchar *extcap _U_, gchar *output, void *data,
char **err_str _U_) {
extcap_token_sentence *tokens = NULL;
GList *arguments = NULL;
GList **il = (GList **) data;
tokens = extcap_tokenize_sentences(output);
arguments = extcap_parse_args(tokens);
extcap_free_tokenized_sentence_list(tokens);
#if ARG_DEBUG
extcap_debug_arguments ( arguments );
#endif
*il = g_list_append(*il, arguments);
/* By returning false, extcap_foreach will break on first found */
return TRUE;
}
GList *
extcap_get_if_configuration(const char * ifname) {
gchar *argv[4];
GList *ret = NULL;
gchar **err_str = NULL;
if ( extcap_if_exists(ifname) )
{
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG, "Extcap path %s",
get_extcap_dir());
if (err_str != NULL)
*err_str = NULL;
argv[0] = g_strdup(EXTCAP_ARGUMENT_CONFIG);
argv[1] = g_strdup(EXTCAP_ARGUMENT_INTERFACE);
argv[2] = g_strdup(ifname);
argv[3] = NULL;
extcap_foreach(4, argv, search_cb, &ret, err_str, ifname);
}
return ret;
}
void extcap_cleanup(capture_options * capture_opts) {
interface_options interface_opts;
guint icnt = 0;
for (icnt = 0; icnt < capture_opts->ifaces->len; icnt++) {
interface_opts = g_array_index(capture_opts->ifaces, interface_options,
icnt);
/* skip native interfaces */
if (interface_opts.if_type != IF_EXTCAP)
continue;
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
"Extcap [%s] - Cleaning up fifo: %s; PID: %d", interface_opts.name,
interface_opts.extcap_fifo, interface_opts.extcap_pid);
#ifdef WIN32
if (pipe_h)
{
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
"Extcap [%s] - Closing pipe", interface_opts.name);
FlushFileBuffers(pipe_h);
DisconnectNamedPipe(pipe_h);
CloseHandle(pipe_h);
}
#else
if (interface_opts.extcap_fifo != NULL && file_exists(interface_opts.extcap_fifo))
{
/* the fifo will not be freed here, but with the other capture_opts in capture_sync */
ws_unlink(interface_opts.extcap_fifo);
interface_opts.extcap_fifo = NULL;
}
#endif
/* Maybe the client closed and removed fifo, but ws should check if
* pid should be closed */
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
"Extcap [%s] - Closing spawned PID: %d", interface_opts.name,
interface_opts.extcap_pid);
if (interface_opts.extcap_pid != (GPid)-1 )
{
g_spawn_close_pid(interface_opts.extcap_pid);
interface_opts.extcap_pid = (GPid)-1;
}
}
}
static void
extcap_arg_cb(gpointer key, gpointer value, gpointer data) {
GPtrArray *args = (GPtrArray *)data;
if ( key != NULL )
{
g_ptr_array_add(args, key);
if ( value != NULL )
g_ptr_array_add(args, value);
}
}
/* call mkfifo for each extcap,
* returns FALSE if there's an error creating a FIFO */
gboolean
extcaps_init_initerfaces(capture_options *capture_opts)
{
guint i;
interface_options interface_opts;
for (i = 0; i < capture_opts->ifaces->len; i++)
{
GPtrArray *args = NULL;
GPid pid = 0;
interface_opts = g_array_index(capture_opts->ifaces, interface_options, i);
/* skip native interfaces */
if (interface_opts.if_type != IF_EXTCAP )
continue;
/* create pipe for fifo */
if ( ! extcap_create_pipe ( &interface_opts.extcap_fifo ) )
return FALSE;
/* Create extcap call */
args = g_ptr_array_new_with_free_func(g_free);
#define add_arg(X) g_ptr_array_add(args, g_strdup(X))
add_arg(interface_opts.extcap);
add_arg(EXTCAP_ARGUMENT_RUN_CAPTURE);
add_arg(EXTCAP_ARGUMENT_INTERFACE);
add_arg(interface_opts.name);
add_arg(EXTCAP_ARGUMENT_RUN_PIPE);
add_arg(interface_opts.extcap_fifo);
if (interface_opts.extcap_args != NULL)
g_hash_table_foreach(interface_opts.extcap_args, extcap_arg_cb, args);
add_arg(NULL);
#undef add_arg
/* Wireshark for windows crashes here sometimes *
* Access violation reading location 0x... */
g_spawn_async(NULL, (gchar **)args->pdata, NULL,
(GSpawnFlags) 0, NULL, NULL,
&pid,NULL);
interface_opts.extcap_pid = pid;
capture_opts->ifaces = g_array_remove_index(capture_opts->ifaces, i);
g_array_insert_val(capture_opts->ifaces, i, interface_opts);
}
return TRUE;
}
#ifdef WIN32
/* called by capture_sync to get the CreatNamedPipe handle*/
HANDLE
extcap_get_win32_handle()
{
return pipe_h;
}
#endif
gboolean extcap_create_pipe(char ** fifo)
{
#ifdef WIN32
gchar timestr[ 14+1 ];
time_t current_time;
gchar *pipename = NULL;
LPSECURITY_ATTRIBUTES security = NULL;
/* create pipename */
current_time = time(NULL);
strftime(timestr, sizeof(timestr), "%Y%m%d%H%M%S", localtime(&current_time));
pipename = g_strconcat ( "\\\\.\\pipe\\", EXTCAP_PIPE_PREFIX, "_", timestr, NULL );
/* Security struct to enable Inheritable HANDLE */
security = (LPSECURITY_ATTRIBUTES)g_malloc0(sizeof(LPSECURITY_ATTRIBUTES));
security->nLength = sizeof(LPSECURITY_ATTRIBUTES);
security->bInheritHandle = TRUE;
security->lpSecurityDescriptor = NULL;
/* create a namedPipe*/
pipe_h = CreateNamedPipe(
utf_8to16(pipename),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE| PIPE_READMODE_MESSAGE | PIPE_WAIT,
5, 65536, 65536,
300,
security);
if (pipe_h == INVALID_HANDLE_VALUE)
{
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,"\nError creating pipe => (%d)", GetLastError());
return FALSE;
}
else
{
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,"\nWireshark Created pipe =>(%s)",pipename);
*fifo = g_strdup(pipename);
}
#else
gchar *temp_name = NULL;
int fd = 0;
if ( ( fd = create_tempfile ( &temp_name, EXTCAP_PIPE_PREFIX ) ) == 0 )
return FALSE;
ws_close(fd);
g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_DEBUG,
"Extcap - Creating fifo: %s", temp_name);
if ( file_exists(temp_name) )
ws_unlink(temp_name);
if (mkfifo(temp_name, 0600) == 0)
*fifo = g_strdup(temp_name);
#endif
return TRUE;
}
#if ARG_DEBUG
void extcap_debug_arguments ( extcap_arg *arg_iter )
{
extcap_value *v = NULL;
GList *walker = NULL;
printf("debug - parser dump\n");
while (arg_iter != NULL) {
printf("ARG %d call=%s display=\"%s\" type=", arg_iter->arg_num, arg_iter->call, arg_iter->display);
switch (arg_iter->arg_type) {
case EXTCAP_ARG_INTEGER:
printf("int\n");
break;
case EXTCAP_ARG_UNSIGNED:
printf("unsigned\n");
break;
case EXTCAP_ARG_LONG:
printf("long\n");
break;
case EXTCAP_ARG_DOUBLE:
printf("double\n");
break;
case EXTCAP_ARG_BOOLEAN:
printf("boolean\n");
break;
case EXTCAP_ARG_MENU:
printf("menu\n");
break;
case EXTCAP_ARG_RADIO:
printf("radio\n");
break;
case EXTCAP_ARG_SELECTOR:
printf("selctor\n");
break;
case EXTCAP_ARG_STRING:
printf ( "string\n" );
break;
case EXTCAP_ARG_MULTICHECK:
printf ( "unknown\n" );
break;
case EXTCAP_ARG_UNKNOWN:
printf ( "unknown\n" );
break;
}
if (arg_iter->range_start != NULL && arg_iter->range_end != NULL) {
printf("\tRange: ");
extcap_printf_complex(arg_iter->range_start);
printf(" - ");
extcap_printf_complex(arg_iter->range_end);
printf("\n");
}
for ( walker = g_list_first ( arg_iter->value_list ); walker; walker = walker->next )
{
v = (extcap_value *)walker->data;
if (v->is_default == TRUE)
printf("*");
printf("\tcall=\"%p\" display=\"%p\"\n", v->call, v->display);
printf("\tcall=\"%s\" display=\"%s\"\n", v->call, v->display);
}
arg_iter = arg_iter->next_arg;
}
}
#endif
#endif
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=4 tabstop=4 noexpandtab:
* :indentSize=4:tabSize=4:noTabs=false:
*/

90
extcap.h Normal file
View File

@ -0,0 +1,90 @@
/* extcap.h
* Definitions for extcap external capture
* Copyright 2013, Mike Ryan <mikeryan@lacklustre.net>
*
* 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.
*/
#ifndef __EXTCAP_H__
#define __EXTCAP_H__
#include "config.h"
#include <glib.h>
#ifdef _WIN32
#include <windows.h>
#include <wsutil/unicode-utils.h>
#endif
#include <ui/capture_ui_utils.h>
#ifdef HAVE_EXTCAP
#define EXTCAP_ARGUMENT_CONFIG "--extcap-config"
#define EXTCAP_ARGUMENT_LIST_INTERFACES "--extcap-interfaces"
#define EXTCAP_ARGUMENT_INTERFACE "--extcap-interface"
#define EXTCAP_ARGUMENT_LIST_DLTS "--extcap-dlts"
#define EXTCAP_ARGUMENT_RUN_CAPTURE "--capture"
#define EXTCAP_ARGUMENT_RUN_PIPE "--fifo"
/* try to get if capabilities from extcap */
if_capabilities_t *
extcap_get_if_dlts(const gchar * ifname, char ** err_str);
/* get a list of all capture interfaces */
GList *
extcap_interface_list(char **err_str);
/* returns the configuration for the given interface name, or an
* empty list, if no configuration has been found */
GList *
extcap_get_if_configuration(const char * ifname);
#ifdef WIN32
HANDLE
extcap_get_win32_handle();
#endif
gboolean
extcaps_init_initerfaces(capture_options * capture_opts);
gboolean
extcap_create_pipe(char ** fifo);
void
extcap_cleanup(capture_options * capture_opts _U_);
#endif
#endif
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=4 tabstop=4 noexpandtab:
* :indentSize=4:tabSize=4:noTabs=false:
*/

881
extcap_parser.c Normal file
View File

@ -0,0 +1,881 @@
/* extcap_parser.c
*
* Routines for extcap external capture
* Copyright 2013, Mike Ryan <mikeryan@lacklustre.net>
*
* 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"
#include <stdio.h>
#include <glib.h>
#include <string.h>
#include "extcap_parser.h"
void extcap_printf_complex(extcap_complex *comp) {
gchar *ret = extcap_get_complex_as_string(comp);
printf("%s", ret);
g_free(ret);
}
gchar *extcap_get_complex_as_string(extcap_complex *comp) {
/* Pick an arbitrary size that should be big enough */
gchar *ret = g_new(gchar, 32);
if (comp == NULL) {
g_snprintf(ret, 32, "(null)");
return ret;
}
switch (comp->complex_type) {
case EXTCAP_ARG_INTEGER:
g_snprintf(ret, 32, "%d", comp->complex_value.int_value);
break;
case EXTCAP_ARG_UNSIGNED:
g_snprintf(ret, 32, "%u", comp->complex_value.uint_value);
break;
case EXTCAP_ARG_LONG:
g_snprintf(ret, 32, "%ld", comp->complex_value.long_value);
break;
case EXTCAP_ARG_DOUBLE:
g_snprintf(ret, 32, "%f", comp->complex_value.double_value);
break;
case EXTCAP_ARG_BOOLEAN:
g_snprintf(ret, 32, "%s",
comp->complex_value.bool_value ? "TRUE" : "FALSE");
break;
case EXTCAP_ARG_STRING:
case EXTCAP_ARG_FILESELECT:
g_free(ret);
ret = g_strdup(comp->complex_value.string_value);
break;
default:
/* Nulling out the return string */
g_snprintf(ret, 32, " ");
break;
}
return ret;
}
extcap_complex *extcap_parse_complex(extcap_arg_type complex_type,
const gchar *data) {
extcap_complex *rc = g_new(extcap_complex, 1);
gboolean success = FALSE;
long double exp_f;
switch (complex_type) {
case EXTCAP_ARG_INTEGER:
if (sscanf(data, "%Lf", &exp_f) == 1) {
rc->complex_value.int_value = (int) exp_f;
success = TRUE;
break;
}
break;
case EXTCAP_ARG_UNSIGNED:
if (sscanf(data, "%Lf", &exp_f) == 1) {
rc->complex_value.uint_value = (unsigned int) exp_f;
success = TRUE;
break;
}
break;
case EXTCAP_ARG_LONG:
if (sscanf(data, "%Lf", &exp_f) == 1) {
rc->complex_value.long_value = (long) exp_f;
success = TRUE;
break;
}
break;
case EXTCAP_ARG_DOUBLE:
if (sscanf(data, "%Lf", &exp_f) == 1) {
rc->complex_value.double_value = (double) exp_f;
success = TRUE;
break;
}
break;
case EXTCAP_ARG_BOOLEAN:
case EXTCAP_ARG_BOOLFLAG:
if (data[0] == 't' || data[0] == 'T' || data[0] == '1') {
rc->complex_value.bool_value = 1;
} else {
rc->complex_value.bool_value = 0;
}
success = TRUE;
break;
case EXTCAP_ARG_STRING:
case EXTCAP_ARG_FILESELECT:
rc->complex_value.string_value = g_strdup(data);
success = TRUE;
break;
default:
break;
}
if (!success) {
g_free(rc);
return NULL ;
}
rc->complex_type = complex_type;
rc->value_filled = TRUE;
return rc;
}
gboolean extcap_compare_is_default(extcap_arg *element, extcap_complex *test) {
gboolean result = FALSE;
if (element->default_complex == NULL)
return result;
switch (element->arg_type) {
case EXTCAP_ARG_INTEGER:
if (extcap_complex_get_int(test)
== extcap_complex_get_int(element->default_complex))
result = TRUE;
break;
case EXTCAP_ARG_UNSIGNED:
if (extcap_complex_get_uint(test)
== extcap_complex_get_uint(element->default_complex))
result = TRUE;
break;
case EXTCAP_ARG_LONG:
if (extcap_complex_get_long(test)
== extcap_complex_get_long(element->default_complex))
result = TRUE;
break;
case EXTCAP_ARG_DOUBLE:
if (extcap_complex_get_double(test)
== extcap_complex_get_double(element->default_complex))
result = TRUE;
break;
case EXTCAP_ARG_BOOLEAN:
case EXTCAP_ARG_BOOLFLAG:
if (extcap_complex_get_bool(test)
== extcap_complex_get_bool(element->default_complex))
result = TRUE;
break;
case EXTCAP_ARG_STRING:
if (strcmp(extcap_complex_get_string(test),
extcap_complex_get_string(element->default_complex)) == 0)
result = TRUE;
break;
default:
break;
}
return result;
}
void extcap_free_complex(extcap_complex *comp) {
if (comp->complex_type == EXTCAP_ARG_STRING
|| comp->complex_type == EXTCAP_ARG_FILESELECT)
g_free(comp->complex_value.string_value);
g_free(comp);
}
int extcap_complex_get_int(extcap_complex *comp) {
if ( comp == NULL )
return (int)0;
return comp->complex_value.int_value;
}
unsigned int extcap_complex_get_uint(extcap_complex *comp) {
if ( comp == NULL )
return (unsigned int)0;
return comp->complex_value.uint_value;
}
long extcap_complex_get_long(extcap_complex *comp) {
if ( comp == NULL )
return (long)0;
return comp->complex_value.long_value;
}
double extcap_complex_get_double(extcap_complex *comp) {
if ( comp == NULL )
return (double)0;
return comp->complex_value.double_value;
}
gboolean extcap_complex_get_bool(extcap_complex *comp) {
if ( comp == NULL )
return FALSE;
return comp->complex_value.bool_value;
}
gchar *extcap_complex_get_string(extcap_complex *comp) {
return comp->complex_value.string_value;
}
void extcap_free_tokenized_param(extcap_token_param *v) {
if (v == NULL)
return;
if (v->arg != NULL)
g_free(v->arg);
if (v->value != NULL)
g_free(v->value);
g_free(v);
}
void extcap_free_tokenized_sentence(extcap_token_sentence *s) {
extcap_token_param *tv;
if (s == NULL)
return;
if (s->sentence != NULL)
g_free(s->sentence);
while (s->param_list != NULL ) {
tv = s->param_list;
s->param_list = tv->next_token;
extcap_free_tokenized_param(tv);
}
}
void extcap_free_tokenized_sentence_list(extcap_token_sentence *f) {
extcap_token_sentence *t;
while (f != NULL ) {
t = f->next_sentence;
extcap_free_tokenized_sentence(f);
f = t;
}
}
extcap_token_sentence *extcap_tokenize_sentence(const gchar *s) {
gchar *b, *e, *eq;
extcap_token_param *tv = NULL;
extcap_token_sentence *rs = g_new(extcap_token_sentence, 1);
rs->sentence = NULL;
rs->next_sentence = NULL;
rs->param_list = NULL;
if ((b = g_strstr_len(s, -1, " ")) == NULL) {
extcap_free_tokenized_sentence(rs);
return NULL ;
}
rs->sentence = g_strndup(s, b - s);
if ((b = g_strstr_len(s, -1, "{")) == NULL) {
/* printf("debug - tokenizer - sentence with no values\n"); */
extcap_free_tokenized_sentence(rs);
return NULL ;
}
while (b != NULL ) {
if ((e = g_strstr_len(b, -1, "}")) == NULL) {
/* printf("debug - tokenizer - invalid, missing }\n"); */
extcap_free_tokenized_sentence(rs);
return NULL ;
}
if ((eq = g_strstr_len(b, -1, "=")) == NULL) {
/* printf("debug - tokenizer - invalid, missing =\n"); */
extcap_free_tokenized_sentence(rs);
return NULL ;
}
b++;
e--;
if (b >= eq || e <= eq) {
/* printf("debug - tokenizer - invalid, missing arg or value in {}\n"); */
extcap_free_tokenized_sentence(rs);
return NULL ;
}
tv = g_new(extcap_token_param, 1);
tv->arg = g_strndup(b, eq - b);
tv->value = g_strndup(eq + 1, e - eq);
if (g_ascii_strcasecmp(tv->arg, "number") == 0) {
tv->param_type = EXTCAP_PARAM_ARGNUM;
} else if (g_ascii_strcasecmp(tv->arg, "call") == 0) {
tv->param_type = EXTCAP_PARAM_CALL;
} else if (g_ascii_strcasecmp(tv->arg, "display") == 0) {
tv->param_type = EXTCAP_PARAM_DISPLAY;
} else if (g_ascii_strcasecmp(tv->arg, "type") == 0) {
tv->param_type = EXTCAP_PARAM_TYPE;
} else if (g_ascii_strcasecmp(tv->arg, "arg") == 0) {
tv->param_type = EXTCAP_PARAM_ARG;
} else if (g_ascii_strcasecmp(tv->arg, "default") == 0) {
tv->param_type = EXTCAP_PARAM_DEFAULT;
} else if (g_ascii_strcasecmp(tv->arg, "value") == 0) {
tv->param_type = EXTCAP_PARAM_VALUE;
} else if (g_ascii_strcasecmp(tv->arg, "range") == 0) {
tv->param_type = EXTCAP_PARAM_RANGE;
} else if (g_ascii_strcasecmp(tv->arg, "tooltip") == 0) {
tv->param_type = EXTCAP_PARAM_TOOLTIP;
} else if (g_ascii_strcasecmp(tv->arg, "mustexist") == 0) {
tv->param_type = EXTCAP_PARAM_FILE_MUSTEXIST;
} else if (g_ascii_strcasecmp(tv->arg, "name") == 0) {
tv->param_type = EXTCAP_PARAM_NAME;
} else if (g_ascii_strcasecmp(tv->arg, "enabled") == 0) {
tv->param_type = EXTCAP_PARAM_ENABLED;
} else {
tv->param_type = EXTCAP_PARAM_UNKNOWN;
}
tv->next_token = rs->param_list;
rs->param_list = tv;
/* printf("debug - tokenizer - got '%s' = '%s'\n", tv->arg, tv->value); */
b = e + 1;
if ((size_t) (b - s) > strlen(s))
break;
b = g_strstr_len(b, -1, "{");
}
return rs;
}
extcap_token_sentence *extcap_tokenize_sentences(const gchar *s) {
extcap_token_sentence *first = NULL, *cur = NULL, *last = NULL;
gchar **list, **list_iter;
list_iter = list = g_strsplit(s, "\n", 0);
while (*list_iter != NULL ) {
cur = extcap_tokenize_sentence(*list_iter);
if (cur != NULL) {
if (first == NULL) {
first = cur;
last = cur;
} else {
last->next_sentence = cur;
last = cur;
}
}
list_iter++;
}
g_strfreev(list);
return first;
}
extcap_token_param *extcap_find_param_by_type(extcap_token_param *first,
extcap_param_type t) {
while (first != NULL ) {
if (first->param_type == t) {
return first;
}
first = first->next_token;
}
return NULL ;
}
void extcap_free_value(extcap_value *v) {
if (v == NULL)
return;
if (v->call != NULL)
g_free(v->call);
if (v->display != NULL)
g_free(v->display);
g_free(v);
}
extcap_interface *extcap_new_interface(void) {
extcap_interface *r = g_new(extcap_interface, 1);
r->call = r->display = NULL;
r->next_interface = NULL;
return r;
}
void extcap_free_interface(extcap_interface *i) {
if (i == NULL)
return;
if (i->call != NULL)
g_free(i->call);
if (i->display != NULL)
g_free(i->display);
}
extcap_dlt *extcap_new_dlt(void) {
extcap_dlt *r = g_new(extcap_dlt, 1);
r->number = -1;
r->name = r->display = NULL;
r->next_dlt = NULL;
return r;
}
void extcap_free_dlt(extcap_dlt *d) {
if (d == NULL)
return;
if (d->name != NULL)
g_free(d->name);
if (d->display != NULL)
g_free(d->display);
}
extcap_arg *extcap_new_arg(void) {
extcap_arg *r = g_new(extcap_arg, 1);
r->call = NULL;
r->display = NULL;
r->tooltip = NULL;
r->arg_type = EXTCAP_ARG_UNKNOWN;
r->range_start = NULL;
r->range_end = NULL;
r->default_complex = NULL;
r->fileexists = FALSE;
r->values = NULL;
/*r->next_arg = NULL; */
return r;
}
static void extcap_free_valuelist(gpointer data, gpointer user_data _U_) {
extcap_free_value((extcap_value *) data);
}
void extcap_free_arg(extcap_arg *a) {
if (a == NULL)
return;
if (a->call != NULL)
g_free(a->call);
if (a->display != NULL)
g_free(a->display);
if (a->tooltip != NULL)
g_free(a->tooltip);
if (a->range_start != NULL)
extcap_free_complex(a->range_start);
if (a->range_end != NULL)
extcap_free_complex(a->range_end);
if (a->default_complex != NULL)
extcap_free_complex(a->default_complex);
g_list_foreach(a->values, (GFunc) extcap_free_valuelist, NULL);
}
static void extcap_free_arg_list_cb(gpointer listentry) {
if (listentry != NULL)
extcap_free_arg((extcap_arg *) listentry);
}
void extcap_free_arg_list(GList *a) {
g_list_free_full(a, extcap_free_arg_list_cb);
}
static gint glist_find_numbered_arg(gconstpointer listelem, gconstpointer needle) {
if (((const extcap_arg *) listelem)->arg_num == *((const int*) needle))
return 0;
return 1;
}
extcap_arg *extcap_parse_arg_sentence(GList * args, extcap_token_sentence *s) {
extcap_token_param *v = NULL;
extcap_arg *target_arg = NULL;
extcap_value *value = NULL;
GList * entry = NULL;
int tint;
extcap_sentence_type sent = EXTCAP_SENTENCE_UNKNOWN;
if (s == NULL)
return target_arg;
if (g_ascii_strcasecmp(s->sentence, "arg") == 0) {
sent = EXTCAP_SENTENCE_ARG;
/* printf("ARG sentence\n"); */
} else if (g_ascii_strcasecmp(s->sentence, "value") == 0) {
sent = EXTCAP_SENTENCE_VALUE;
/* printf("VALUE sentence\n"); */
}
if (sent == EXTCAP_SENTENCE_ARG) {
target_arg = extcap_new_arg();
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_ARGNUM))
== NULL) {
extcap_free_arg(target_arg);
return NULL ;
}
if (sscanf(v->value, "%d", &(target_arg->arg_num)) != 1) {
extcap_free_arg(target_arg);
return NULL ;
}
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_CALL))
== NULL) {
extcap_free_arg(target_arg);
return NULL ;
}
target_arg->call = g_strdup(v->value);
/* No value only parameters allowed */
if (strlen(target_arg->call) == 0) {
extcap_free_arg(target_arg);
return NULL ;
}
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_DISPLAY))
== NULL) {
extcap_free_arg(target_arg);
return NULL ;
}
target_arg->display = g_strdup(v->value);
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_TOOLTIP))
!= NULL) {
target_arg->tooltip = g_strdup(v->value);
}
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_FILE_MUSTEXIST))
!= NULL) {
target_arg->fileexists = (v->value[0] == 't' || v->value[0] == 'T');
}
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_TYPE))
== NULL) {
/* printf("no type in ARG sentence\n"); */
extcap_free_arg(target_arg);
return NULL ;
}
if (g_ascii_strcasecmp(v->value, "integer") == 0) {
target_arg->arg_type = EXTCAP_ARG_INTEGER;
} else if (g_ascii_strcasecmp(v->value, "unsigned") == 0) {
target_arg->arg_type = EXTCAP_ARG_UNSIGNED;
} else if (g_ascii_strcasecmp(v->value, "long") == 0) {
target_arg->arg_type = EXTCAP_ARG_LONG;
} else if (g_ascii_strcasecmp(v->value, "double") == 0) {
target_arg->arg_type = EXTCAP_ARG_DOUBLE;
} else if (g_ascii_strcasecmp(v->value, "boolean") == 0) {
target_arg->arg_type = EXTCAP_ARG_BOOLEAN;
} else if (g_ascii_strcasecmp(v->value, "boolflag") == 0) {
target_arg->arg_type = EXTCAP_ARG_BOOLFLAG;
} else if (g_ascii_strcasecmp(v->value, "menu") == 0) {
target_arg->arg_type = EXTCAP_ARG_MENU;
} else if (g_ascii_strcasecmp(v->value, "selector") == 0) {
target_arg->arg_type = EXTCAP_ARG_SELECTOR;
} else if (g_ascii_strcasecmp(v->value, "radio") == 0) {
target_arg->arg_type = EXTCAP_ARG_RADIO;
} else if (g_ascii_strcasecmp(v->value, "string") == 0) {
target_arg->arg_type = EXTCAP_ARG_STRING;
} else if (g_ascii_strcasecmp(v->value, "fileselect") == 0) {
target_arg->arg_type = EXTCAP_ARG_FILESELECT;
} else if (g_ascii_strcasecmp(v->value, "multicheck") == 0) {
target_arg->arg_type = EXTCAP_ARG_MULTICHECK;
} else {
printf("invalid type %s in ARG sentence\n", v->value);
extcap_free_arg(target_arg);
return NULL ;
}
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_RANGE))
!= NULL) {
gchar *cp = g_strstr_len(v->value, -1, ",");
if (cp == NULL) {
printf("invalid range, expected value,value got %s\n",
v->value);
extcap_free_arg(target_arg);
return NULL ;
}
if ((target_arg->range_start = extcap_parse_complex(
target_arg->arg_type, v->value)) == NULL) {
printf("invalid range, expected value,value got %s\n",
v->value);
extcap_free_arg(target_arg);
return NULL ;
}
if ((target_arg->range_end = extcap_parse_complex(
target_arg->arg_type, cp + 1)) == NULL) {
printf("invalid range, expected value,value got %s\n",
v->value);
extcap_free_arg(target_arg);
return NULL ;
}
}
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_DEFAULT))
!= NULL) {
if ((target_arg->default_complex = extcap_parse_complex(
target_arg->arg_type, v->value)) == NULL) {
printf("invalid default, couldn't parse %s\n", v->value);
}
}
} else if (sent == EXTCAP_SENTENCE_VALUE) {
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_ARG))
== NULL) {
printf("no arg in VALUE sentence\n");
return NULL ;
}
if (sscanf(v->value, "%d", &tint) != 1) {
printf("invalid arg in VALUE sentence\n");
return NULL ;
}
;
if ((entry = g_list_find_custom(args, &tint, glist_find_numbered_arg))
== NULL) {
printf("couldn't find arg %d in list for VALUE sentence\n", tint);
return NULL ;
}
value = g_new(extcap_value, 1);
value->display = NULL;
value->call = NULL;
value->enabled = FALSE;
value->is_default = FALSE;
value->arg_num = tint;
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_VALUE))
== NULL) {
/* printf("no value in VALUE sentence\n"); */
extcap_free_value(value);
return NULL ;
}
value->call = g_strdup(v->value);
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_DISPLAY))
== NULL) {
/* printf("no display in VALUE sentence\n"); */
extcap_free_value(value);
return NULL ;
}
value->display = g_strdup(v->value);
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_DEFAULT))
!= NULL) {
/* printf("found default value\n"); */
value->is_default = (v->value[0] == 't' || v->value[0] == 'T');
}
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_ENABLED))
!= NULL) {
value->enabled = (v->value[0] == 't' || v->value[0] == 'T');
}
((extcap_arg*) entry->data)->values = g_list_append(
((extcap_arg*) entry->data)->values, value);
return NULL ;
}
return target_arg;
}
GList * extcap_parse_args(extcap_token_sentence *first_s) {
GList * args = NULL;
while (first_s) {
extcap_arg *ra = NULL;
if ((ra = extcap_parse_arg_sentence(args, first_s)) != NULL)
args = g_list_append(args, (gpointer) ra);
first_s = first_s->next_sentence;
}
return args;
}
int extcap_parse_interface_sentence(extcap_token_sentence *s,
extcap_interface **ri) {
extcap_token_param *v = NULL;
extcap_sentence_type sent = EXTCAP_SENTENCE_UNKNOWN;
*ri = NULL;
if (s == NULL)
return -1;
if (g_ascii_strcasecmp(s->sentence, "interface") == 0) {
sent = EXTCAP_SENTENCE_INTERFACE;
/* printf("INTERFACE sentence\n"); */
}
if (sent == EXTCAP_SENTENCE_UNKNOWN)
return -1;
*ri = extcap_new_interface();
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_VALUE))
== NULL) {
printf("No value in INTERFACE sentence\n");
extcap_free_interface(*ri);
return -1;
}
(*ri)->call = g_strdup(v->value);
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_DISPLAY))
== NULL) {
printf("No display in INTERFACE sentence\n");
extcap_free_interface(*ri);
return -1;
}
(*ri)->display = g_strdup(v->value);
return 1;
}
int extcap_parse_interfaces(extcap_token_sentence *first_s,
extcap_interface **first_int) {
extcap_interface *first_i = NULL, *last_i = NULL;
while (first_s) {
extcap_interface *ri;
if (extcap_parse_interface_sentence(first_s, &ri) >= 0 && ri != NULL) {
if (first_i == NULL) {
first_i = last_i = ri;
} else {
last_i->next_interface = ri;
last_i = ri;
}
}
first_s = first_s->next_sentence;
}
*first_int = first_i;
return 1;
}
int extcap_parse_dlt_sentence(extcap_token_sentence *s, extcap_dlt **rd) {
extcap_token_param *v = NULL;
extcap_sentence_type sent = EXTCAP_SENTENCE_UNKNOWN;
*rd = NULL;
if (s == NULL)
return -1;
if (g_ascii_strcasecmp(s->sentence, "dlt") == 0) {
sent = EXTCAP_SENTENCE_DLT;
}
if (sent == EXTCAP_SENTENCE_UNKNOWN)
return -1;
*rd = extcap_new_dlt();
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_ARGNUM))
== NULL) {
printf("No number in DLT sentence\n");
extcap_free_dlt(*rd);
return -1;
}
if (sscanf(v->value, "%d", &((*rd)->number)) != 1) {
printf("Invalid number in DLT sentence\n");
extcap_free_dlt(*rd);
return -1;
}
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_NAME))
== NULL) {
printf("No name in DLT sentence\n");
extcap_free_dlt(*rd);
return -1;
}
(*rd)->name = g_strdup(v->value);
if ((v = extcap_find_param_by_type(s->param_list, EXTCAP_PARAM_DISPLAY))
== NULL) {
printf("No display in DLT sentence\n");
extcap_free_dlt(*rd);
return -1;
}
(*rd)->display = g_strdup(v->value);
return 1;
}
int extcap_parse_dlts(extcap_token_sentence *first_s, extcap_dlt **first_dlt) {
extcap_dlt *first_d = NULL, *last_d = NULL;
while (first_s) {
extcap_dlt *rd;
if (extcap_parse_dlt_sentence(first_s, &rd) >= 0 && rd != NULL) {
if (first_d == NULL) {
first_d = last_d = rd;
} else {
last_d->next_dlt = rd;
last_d = rd;
}
}
first_s = first_s->next_sentence;
}
*first_dlt = first_d;
return 1;
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=4 tabstop=4 noexpandtab:
* :indentSize=4:tabSize=4:noTabs=false:
*/

253
extcap_parser.h Normal file
View File

@ -0,0 +1,253 @@
/* extcap_parser.h
*
* 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.
*/
#ifndef __EXTCAP_PARSER_H__
#define __EXTCAP_PARSER_H__
#include <stdio.h>
#include <glib.h>
#include <string.h>
typedef enum {
EXTCAP_SENTENCE_UNKNOWN,
EXTCAP_SENTENCE_ARG,
EXTCAP_SENTENCE_VALUE,
EXTCAP_SENTENCE_FLAG,
EXTCAP_SENTENCE_INTERFACE,
EXTCAP_SENTENCE_DLT
} extcap_sentence_type;
typedef enum {
/* Simple types */
EXTCAP_ARG_UNKNOWN,
EXTCAP_ARG_INTEGER,
EXTCAP_ARG_UNSIGNED,
EXTCAP_ARG_LONG,
EXTCAP_ARG_DOUBLE,
EXTCAP_ARG_BOOLEAN,
EXTCAP_ARG_BOOLFLAG,
EXTCAP_ARG_STRING,
/* Complex GUI types which are populated with value sentences */
EXTCAP_ARG_MENU,
EXTCAP_ARG_SELECTOR,
EXTCAP_ARG_RADIO,
EXTCAP_ARG_MULTICHECK,
EXTCAP_ARG_FILESELECT
} extcap_arg_type;
typedef enum {
/* value types */
EXTCAP_PARAM_UNKNOWN,
EXTCAP_PARAM_ARGNUM,
EXTCAP_PARAM_CALL,
EXTCAP_PARAM_DISPLAY,
EXTCAP_PARAM_TYPE,
EXTCAP_PARAM_ARG,
EXTCAP_PARAM_DEFAULT,
EXTCAP_PARAM_VALUE,
EXTCAP_PARAM_RANGE,
EXTCAP_PARAM_TOOLTIP,
EXTCAP_PARAM_NAME,
EXTCAP_PARAM_ENABLED,
EXTCAP_PARAM_FILE_MUSTEXIST
} extcap_param_type;
/* Values for a given sentence; values are all stored as a call
* and a value string, or a valid range, so we only need to store
* those and repeat them */
typedef struct _extcap_value {
int arg_num;
gchar *call;
gchar *display;
gboolean enabled;
gboolean is_default;
} extcap_value;
/* Complex-ish struct for storing complex values */
typedef struct _extcap_complex {
extcap_arg_type complex_type;
union {
int int_value;
unsigned int uint_value;
long long_value;
double double_value;
gboolean bool_value;
gchar *string_value;
} complex_value;
gboolean value_filled;
} extcap_complex;
/* An argument sentence and accompanying options */
typedef struct _extcap_arg {
int arg_num;
gchar *call;
gchar *display;
gchar *tooltip;
gboolean fileexists;
extcap_arg_type arg_type;
extcap_complex *range_start;
extcap_complex *range_end;
extcap_complex *default_complex;
GList * values;
} extcap_arg;
typedef struct _extcap_if {
gchar * extcap_path;
GList * interfaces;
} extcap_if;
typedef struct _extcap_interface {
gchar *call;
gchar *display;
struct _extcap_interface *next_interface;
} extcap_interface;
extcap_interface *extcap_new_interface(void);
void extcap_free_interface(extcap_interface *interface);
typedef struct _extcap_dlt {
gint number;
gchar *name;
gchar *display;
struct _extcap_dlt *next_dlt;
} extcap_dlt;
extcap_dlt *extcap_new_dlt(void);
void extcap_free_dlt(extcap_dlt *dlt);
/* Parser internals */
typedef struct _extcap_token_param {
gchar *arg;
gchar *value;
extcap_param_type param_type;
struct _extcap_token_param *next_token;
} extcap_token_param;
typedef struct _extcap_token_sentence {
gchar *sentence;
extcap_token_param *param_list;
struct _extcap_token_sentence *next_sentence;
} extcap_token_sentence;
/* Parse a string into a complex type */
extcap_complex *extcap_parse_complex(extcap_arg_type complex_type,
const gchar *data);
/* Free a complex */
void extcap_free_complex(extcap_complex *comp);
/* Print a complex value out for debug */
void extcap_printf_complex(extcap_complex *comp);
/*
* Return a string representation of a complex type
* Caller is responsible for calling g_free on the returned string
*/
gchar *extcap_get_complex_as_string(extcap_complex *comp);
int extcap_complex_get_int(extcap_complex *comp);
unsigned int extcap_complex_get_uint(extcap_complex *comp);
long extcap_complex_get_long(extcap_complex *comp);
double extcap_complex_get_double(extcap_complex *comp);
gboolean extcap_complex_get_bool(extcap_complex *comp);
gchar *extcap_complex_get_string(extcap_complex *comp);
/* compares the default value of an element with a given parameter */
gboolean extcap_compare_is_default(extcap_arg *element, extcap_complex *test);
void extcap_free_tokenized_param(extcap_token_param *v);
void extcap_free_tokenized_sentence(extcap_token_sentence *s);
void extcap_free_tokenized_sentence_list(extcap_token_sentence *f);
/* Turn a sentence into logical tokens, don't validate beyond basic syntax */
extcap_token_sentence *extcap_tokenize_sentence(const gchar *s);
/* Tokenize a set of sentences (such as the output of a g_spawn_sync) */
extcap_token_sentence *extcap_tokenize_sentences(const gchar *s);
/* Find an argument in the extcap_arg list which matches the given arg=X number */
extcap_arg *extcap_find_numbered_arg(extcap_arg *first, int number);
/* Find the first occurrence in a parameter list of a parameter of the given type */
extcap_token_param *extcap_find_param_by_type(extcap_token_param *first,
extcap_param_type t);
void extcap_free_value(extcap_value *v);
extcap_arg *extcap_new_arg(void);
/* Free a single argument */
void extcap_free_arg(extcap_arg *a);
/* Free an entire arg list */
void extcap_free_arg_list(GList *a);
/*
* Parse a tokenized sentence and validate. If a new sentence is created, the result
* is returned in 'ra'. On error, < 0 is returned. Not all sentences will create a
* new returned sentence (VALUE sentences, for example)
*/
extcap_arg * extcap_parse_arg_sentence(GList * args, extcap_token_sentence *s);
/* Parse all sentences for args and values */
GList * extcap_parse_args(extcap_token_sentence *first_s);
/*
* Parse a tokenized set of sentences and validate, looking for interface definitions.
*/
int extcap_parse_interface_sentence(extcap_token_sentence *s,
extcap_interface **ri);
/* Parse all sentences for interfaces */
int extcap_parse_interfaces(extcap_token_sentence *first_s,
extcap_interface **first_int);
/* Parse a tokenized set of sentences and validate, looking for DLT definitions */
int extcap_parse_dlt_sentence(extcap_token_sentence *s, extcap_dlt **ri);
/* Parse all sentences for DLTs */
int extcap_parse_dlts(extcap_token_sentence *first_s, extcap_dlt **first_dlt);
#endif
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=4 tabstop=4 noexpandtab:
* :indentSize=4:tabSize=4:noTabs=false:
*/

View File

@ -886,6 +886,8 @@ SetOutPath $INSTDIR
File "${STAGING_DIR}\${PROGRAM_NAME_PATH_GTK}"
File "${STAGING_DIR}\${GDK_DLL}"
File "${STAGING_DIR}\libgdk_pixbuf-2.0-0.dll"
File "${STAGING_DIR}\gspawn-${WIRESHARK_TARGET_PLATFORM}-helper.exe"
File "${STAGING_DIR}\gspawn-${WIRESHARK_TARGET_PLATFORM}-helper-console.exe"
File "${STAGING_DIR}\${GTK_DLL}"
File "${STAGING_DIR}\libatk-1.0-0.dll"
File "${STAGING_DIR}\libpango-1.0-0.dll"

View File

@ -119,6 +119,13 @@ set(WIRESHARK_GTK_SRC
webbrowser.c
)
if(HAVE_EXTCAP)
set(WIRESHARK_GTK_SRC
${WIRESHARK_GTK_SRC}
extcap_gtk.c
)
endif()
set(WIRESHARK_DIRTY_TAP_SRC
)

View File

@ -135,6 +135,7 @@ WIRESHARK_GTK_SRC = \
uat_gui.c \
voip_calls.c \
webbrowser.c \
extcap_gtk.c \
$(WIRESHARK_CUSTOM_GTK_SRC)
about_dlg.c main_welcome.c: wssplash.h remote_icons.h
@ -317,4 +318,5 @@ noinst_HEADERS = \
wsiconcap.h \
wsicon.h \
wssplash.h \
extcap_gtk.h \
$(WIRESHARK_CUSTOM_HDRS)

View File

@ -484,6 +484,18 @@ about_folders_page_new(void)
g_free(path);
#endif
#ifdef HAVE_EXTCAP
/* extcap */
constpath = get_extcap_dir();
resultArray = g_strsplit(constpath, G_SEARCHPATH_SEPARATOR_S, 10);
for(i = 0; resultArray[i]; i++)
about_folders_row(table, "Extcap path", g_strstrip(resultArray[i]),
"Extcap Plugins search path");
g_strfreev(resultArray);
#endif
gtk_container_add(GTK_CONTAINER(scrolledwindow), table);
return scrolledwindow;

View File

@ -80,6 +80,11 @@
#include "airpcap_dlg.h"
#endif
#ifdef HAVE_EXTCAP
#include "extcap.h"
#include "ui/gtk/extcap_gtk.h"
#endif
/*
* Symbolic names for column indices.
*/
@ -165,6 +170,10 @@ enum
#define E_CAP_T_RESOLVE_KEY "cap_t_resolve"
#define E_CAP_E_RESOLVE_KEY "cap_e_resolve"
#ifdef HAVE_EXTCAP
#define E_CAP_EXTCAP_KEY "cap_extcap_vbox"
#endif
#define E_CAP_IFTYPE_CBX_KEY "cap_iftype_cbx"
#ifdef HAVE_PCAP_REMOTE
#define E_CAP_IF_LIST_KEY "cap_if_list"
@ -2382,6 +2391,9 @@ save_options_cb(GtkWidget *win _U_, gpointer user_data _U_)
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
GtkWidget *buffer_size_sb;
#endif
#ifdef HAVE_EXTCAP
GtkWidget *extcap_vbox;
#endif
interface_t device;
gpointer ptr = NULL;
@ -2403,6 +2415,10 @@ save_options_cb(GtkWidget *win _U_, gpointer user_data _U_)
linktype_combo_box = (GtkWidget *) g_object_get_data(G_OBJECT(opt_edit_w), E_CAP_LT_CBX_KEY);
#ifdef HAVE_EXTCAP
extcap_vbox = (GtkWidget *) g_object_get_data(G_OBJECT(opt_edit_w), E_CAP_EXTCAP_KEY);
#endif
if (device.links != NULL) {
if (ws_combo_box_get_active_pointer(GTK_COMBO_BOX(linktype_combo_box), &ptr)) {
/* Even though device.links != NULL, we might not have an active pointer
@ -2436,6 +2452,19 @@ save_options_cb(GtkWidget *win _U_, gpointer user_data _U_)
g_free(device.cfilter);
g_assert(filter_text != NULL);
device.cfilter = filter_text;
#ifdef HAVE_EXTCAP
if (device.external_cap_args_settings != NULL)
g_hash_table_unref(device.external_cap_args_settings);
device.external_cap_args_settings = extcap_gtk_get_state(extcap_vbox);
/* Destroy the args data linked in the gtk widget */
#if 0
extcap_gtk_free_args(extcap_vbox);
#endif
#endif
#ifdef HAVE_PCAP_CREATE
/* if dumpcap reported that the interface does not support monitor
mode, we disable monitor mode even if the user explicitly selected it */
@ -2472,6 +2501,36 @@ adjust_snap_sensitivity(GtkWidget *tb _U_, gpointer parent_w _U_)
g_array_insert_val(global_capture_opts.all_ifaces, marked_interface, device);
}
#ifdef HAVE_EXTCAP
void
extcap_free_arglist(gpointer data, gpointer user_data _U_)
{
extcap_free_arg ( (extcap_arg *) data );
}
static GtkWidget *build_extcap_options(const gchar *name, GHashTable *hash) {
GtkWidget *ret_box = NULL;
GList *arglist = NULL;
GList *elem = NULL;
arglist = extcap_get_if_configuration( name );
for ( elem = g_list_first(arglist); elem; elem = elem->next )
{
GSList *widget_list;
#if GTK_CHECK_VERSION(3, 0, 0)
ret_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3);
#else
ret_box = gtk_vbox_new(FALSE, 3);
#endif
widget_list = extcap_populate_gtk_vbox((GList *) elem->data, ret_box, hash);
g_object_set_data(G_OBJECT(ret_box), EXTCAP_GTK_DATA_KEY_WIDGETLIST, widget_list);
}
return ret_box;
}
#endif
void options_interface_cb(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *column _U_, gpointer userdata)
{
GtkWidget *caller, *window, *swindow = NULL, *if_view,
@ -2494,7 +2553,11 @@ void options_interface_cb(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColum
*compile_bt,
#endif
*bbox, *ok_but, *cancel_bt,
#ifdef HAVE_EXTCAP
*extcap_vbox,
#endif
*help_bt;
GList *cf_entry, *list, *cfilter_list;
GtkAdjustment *snap_adj;
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
@ -2518,6 +2581,9 @@ void options_interface_cb(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColum
GtkCellRenderer *renderer;
GtkListStore *store;
const gchar *new_cfilter;
#ifdef HAVE_EXTCAP
GHashTable *extcap_hash;
#endif
window = (GtkWidget *)userdata;
caller = gtk_widget_get_toplevel(GTK_WIDGET(window));
@ -2544,6 +2610,9 @@ void options_interface_cb(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColum
#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
device.buffer = DEFAULT_CAPTURE_BUFFER_SIZE;
#endif
#ifdef HAVE_EXTCAP
device.external_cap_args_settings = NULL;
#endif
model = gtk_tree_view_get_model(view);
gtk_tree_model_get_iter (model, &iter, path);
@ -2913,6 +2982,14 @@ void options_interface_cb(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColum
}
#endif
#ifdef HAVE_EXTCAP
extcap_hash = device.external_cap_args_settings;
extcap_vbox = build_extcap_options(device.name, extcap_hash);
gtk_box_pack_start(GTK_BOX(capture_vb), extcap_vbox, FALSE, FALSE, 5);
gtk_widget_show(extcap_vbox);
g_object_set_data(G_OBJECT(opt_edit_w), E_CAP_EXTCAP_KEY, extcap_vbox);
#endif
/* Button row: "Start", "Cancel" and "Help" buttons */
bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CANCEL, GTK_STOCK_HELP, NULL);
gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);

View File

@ -426,6 +426,9 @@ GtkWidget * capture_get_if_icon(interface_t *device)
return pixbuf_to_widget(network_wired_pb_data);
case IF_PIPE:
case IF_STDIN:
#ifdef HAVE_EXTCAP
case IF_EXTCAP:
#endif
return pixbuf_to_widget(pipe_pb_data);
default:
printf("unknown device type\n");

806
ui/gtk/extcap_gtk.c Normal file
View File

@ -0,0 +1,806 @@
/* extcap_gtk.c
*
* 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"
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <ui/gtk/gui_utils.h>
#include <wsutil/filesystem.h>
#include <extcap_parser.h>
#include "extcap_gtk.h"
GHashTable *extcap_gtk_get_state(GtkWidget *widget) {
GSList *widget_list, *widget_iter;
GSList *radio_list = NULL, *radio_iter = NULL;
GtkWidget *list_widget, *radio_widget, *tree_widget, *entry_widget;
extcap_arg *arg = NULL;
extcap_value *value = NULL;
extcap_complex *parsed_complex = NULL;
GtkTreeSelection *treeselection;
GtkTreeModel *treemodel;
GtkTreeIter treeiter;
GHashTable *ret_hash;
gchar *call_string = NULL;
gchar **multi_list = NULL;
int multi_num = 0;
gboolean multi_valid, multi_enabled;
widget_list = (GSList *) g_object_get_data(G_OBJECT(widget),
EXTCAP_GTK_DATA_KEY_WIDGETLIST);
if (widget_list == NULL)
return NULL ;
/* String hash */
ret_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
for (widget_iter = widget_list; widget_iter; widget_iter =
widget_iter->next) {
list_widget = (GtkWidget *) widget_iter->data;
if ((arg = (extcap_arg *) g_object_get_data(G_OBJECT(list_widget),
EXTCAP_GTK_DATA_KEY_ARGPTR)) == NULL) {
continue;
}
switch (arg->arg_type) {
case EXTCAP_ARG_INTEGER:
case EXTCAP_ARG_UNSIGNED:
case EXTCAP_ARG_LONG:
case EXTCAP_ARG_DOUBLE:
case EXTCAP_ARG_STRING:
parsed_complex = extcap_parse_complex(arg->arg_type,
gtk_entry_get_text(GTK_ENTRY(list_widget)));
if (parsed_complex == NULL) {
continue;
}
break;
case EXTCAP_ARG_BOOLEAN:
case EXTCAP_ARG_BOOLFLAG:
parsed_complex = extcap_parse_complex(arg->arg_type,
gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(list_widget)) ? "true" : "false");
break;
case EXTCAP_ARG_FILESELECT:
if ((entry_widget =
(GtkWidget *) g_object_get_data(G_OBJECT(list_widget),
EXTCAP_GTK_DATA_KEY_FILENAME)) == NULL) {
continue;
}
parsed_complex = extcap_parse_complex(arg->arg_type,
gtk_entry_get_text(GTK_ENTRY(entry_widget)));
if (parsed_complex == NULL) {
continue;
}
break;
case EXTCAP_ARG_MENU:
break;
case EXTCAP_ARG_RADIO:
if ((radio_widget = (GtkWidget *) g_object_get_data(
G_OBJECT(list_widget),
EXTCAP_GTK_DATA_KEY_FIRSTRADIO)) == NULL) {
continue;
}
if ((radio_list = gtk_radio_button_get_group(
GTK_RADIO_BUTTON(radio_widget))) == NULL) {
continue;
}
for (radio_iter = radio_list; radio_iter;
radio_iter = radio_iter->next) {
GtkWidget *cur_radio = (GtkWidget *) radio_iter->data;
if (gtk_toggle_button_get_active(
GTK_TOGGLE_BUTTON(cur_radio))) {
if ((value = (extcap_value *) g_object_get_data(
G_OBJECT(cur_radio),
EXTCAP_GTK_DATA_KEY_VALPTR)) == NULL) {
continue;
}
if (value->is_default)
continue;
call_string = g_strdup(value->call);
break;
}
}
break;
case EXTCAP_ARG_SELECTOR:
if ((tree_widget = (GtkWidget *) g_object_get_data(
G_OBJECT(list_widget),
EXTCAP_GTK_DATA_KEY_TREEVIEW)) == NULL) {
continue;
}
treeselection = gtk_tree_view_get_selection(
GTK_TREE_VIEW(tree_widget));
treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_widget));
if (gtk_tree_selection_get_selected(treeselection, &treemodel,
&treeiter)) {
gtk_tree_model_get(treemodel, &treeiter, EXTCAP_GTK_COL_VALUE,
&value, -1);
if (value->is_default)
continue;
call_string = g_strdup(value->call);
}
break;
case EXTCAP_ARG_MULTICHECK:
if ((tree_widget = (GtkWidget *) g_object_get_data(
G_OBJECT(list_widget),
EXTCAP_GTK_DATA_KEY_TREEVIEW)) == NULL) {
continue;
}
treeselection = gtk_tree_view_get_selection(
GTK_TREE_VIEW(tree_widget));
treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_widget));
multi_num = 0;
/* Count the # of items enabled */
multi_valid = gtk_tree_model_get_iter_first(treemodel, &treeiter);
while (multi_valid) {
gtk_tree_model_get(treemodel, &treeiter,
EXTCAP_GTK_MULTI_COL_CHECK, &multi_enabled, -1);
if (multi_enabled)
multi_num++;
multi_valid = gtk_tree_model_iter_next(treemodel, &treeiter);
}
multi_list = g_new(gchar *, multi_num + 1);
multi_num = 0;
/* Count the # of items enabled */
multi_valid = gtk_tree_model_get_iter_first(treemodel, &treeiter);
while (multi_valid) {
gtk_tree_model_get(treemodel, &treeiter,
EXTCAP_GTK_MULTI_COL_CHECK, &multi_enabled,
EXTCAP_GTK_MULTI_COL_VALUE, &value, -1);
if (multi_enabled) {
multi_list[multi_num] = g_strdup(value->call);
multi_num++;
}
multi_valid = gtk_tree_model_iter_next(treemodel, &treeiter);
}
multi_list[multi_num] = NULL;
call_string = g_strjoinv(",", multi_list);
g_strfreev(multi_list);
break;
default:
break;
}
if (parsed_complex == NULL && call_string == NULL)
continue;
/* Comparing if the user has changed the value at all, and ignoring it if so */
if (extcap_compare_is_default(arg, parsed_complex))
continue;
/* Flags are set as is, and have not true/false switch */
if ((arg->arg_type == EXTCAP_ARG_BOOLFLAG)
&& (extcap_complex_get_bool(parsed_complex) == TRUE)) {
call_string = g_strdup(" ");
}
if (parsed_complex != NULL && call_string == NULL)
call_string = extcap_get_complex_as_string(parsed_complex);
g_hash_table_insert(ret_hash, g_strdup(arg->call),
g_strdup(call_string));
g_free(call_string);
call_string = NULL;
g_free(parsed_complex);
parsed_complex = NULL;
}
return ret_hash;
}
static void extcap_gtk_treeview_vscroll_map_handler(GtkTreeView *treeView,
gpointer data) {
GtkWidget *padBox = (GtkWidget*) data;
gint x, y;
g_assert(GTK_IS_BOX(padBox));
/* Set the padding above the scrollbar to the height of the tree header window */
gtk_tree_view_convert_bin_window_to_widget_coords(GTK_TREE_VIEW(treeView),
0, 0, &x, &y);
gtk_widget_set_size_request(padBox, -1, y);
}
static GtkWidget *extcap_gtk_wrap_scroll_treeview(GtkWidget *view) {
GtkWidget *vscroll, *padbox, *hbox, *vbox;
GtkAdjustment *padj;
#if GTK_CHECK_VERSION(3, 0, 0)
padj = gtk_scrollable_get_vadjustment(GTK_SCROLLABLE(view));
#if GTK_CHECK_VERSION(3, 2, 0)
vscroll = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, padj);
#else
vscroll = gtk_vscrollbar_new(padj);
#endif
#else
padj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(view));
vscroll = gtk_vscrollbar_new(padj);
#endif
hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
/* First insert the tree view */
gtk_box_pack_start(GTK_BOX(hbox), view, TRUE, TRUE, 0);
gtk_widget_show(view);
/* Pack to the right a vbox containing a box for padding at top and scrollbar */
vbox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
gtk_widget_show(vbox);
padbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
gtk_box_pack_start(GTK_BOX(vbox), padbox, FALSE, FALSE, 0);
gtk_widget_show(padbox);
gtk_box_pack_start(GTK_BOX(vbox), vscroll, TRUE, TRUE, 0);
gtk_widget_show(vscroll);
g_object_set_data(G_OBJECT(hbox), EXTCAP_GTK_DATA_KEY_TREEVIEW, view);
g_signal_connect(view, "map",
G_CALLBACK(extcap_gtk_treeview_vscroll_map_handler), padbox);
return hbox;
}
GtkWidget *extcap_create_gtk_listwidget(extcap_arg *argument,
GHashTable *prev_map) {
GtkCellRenderer *renderer;
GtkTreeModel *model;
GtkWidget *view, *retview;
GtkListStore *store;
GtkTreeIter iter;
GtkTreeSelection *selection;
extcap_value *v = NULL;
GList * walker = NULL;
gchar *prev_item = NULL;
if (g_list_length(argument->values) == 0)
return NULL ;
view = gtk_tree_view_new();
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
store = gtk_list_store_new(EXTCAP_GTK_NUM_COLS, G_TYPE_STRING,
G_TYPE_POINTER);
model = GTK_TREE_MODEL(store);
gtk_tree_view_set_model(GTK_TREE_VIEW(view), model);
gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
if (prev_map != NULL)
prev_item = (gchar *) g_hash_table_lookup(prev_map, argument->call);
for (walker = g_list_first(argument->values); walker != NULL ; walker =
walker->next) {
v = (extcap_value *) walker->data;
if (v->display == NULL)
break;
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, EXTCAP_GTK_COL_DISPLAY, v->display,
EXTCAP_GTK_COL_VALUE, v, -1);
if (prev_item != NULL) {
if (g_ascii_strcasecmp(prev_item, v->call) == 0) {
gtk_tree_selection_select_iter(selection, &iter);
}
} else if (v->is_default) {
gtk_tree_selection_select_iter(selection, &iter);
}
}
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, "Name",
renderer, "text", EXTCAP_GTK_COL_DISPLAY, NULL);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
retview = extcap_gtk_wrap_scroll_treeview(view);
if (gtk_tree_model_iter_n_children(model, NULL) > 3)
gtk_widget_set_size_request(retview, 0, 100);
/* Tree view has own reference */
g_object_unref(model);
return retview;
}
GtkWidget *extcap_create_gtk_radiowidget(extcap_arg *argument,
GHashTable *prev_map) {
GtkWidget *radiobox = NULL, *last_radio = NULL;
extcap_value *v = NULL;
GList * walker = NULL;
gchar *prev_item = NULL;
if (g_list_length(argument->values) == 0)
return NULL ;
if (prev_map != NULL)
prev_item = (gchar *) g_hash_table_lookup(prev_map, argument->call);
radiobox = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 1, FALSE);
for (walker = g_list_first(argument->values); walker != NULL ; walker =
walker->next) {
v = (extcap_value *) walker->data;
if (last_radio == NULL) {
last_radio = gtk_radio_button_new_with_label(NULL, v->display);
/* Set a pointer to the first radio button */
g_object_set_data(G_OBJECT(radiobox),
EXTCAP_GTK_DATA_KEY_FIRSTRADIO, last_radio);
} else {
last_radio = gtk_radio_button_new_with_label_from_widget(
GTK_RADIO_BUTTON(last_radio), v->display);
}
/* Set a pointer to the value used in this radio */
g_object_set_data(G_OBJECT(last_radio), EXTCAP_GTK_DATA_KEY_VALPTR, v);
if (prev_item != NULL) {
if (g_ascii_strcasecmp(prev_item, v->call) == 0) {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(last_radio),
TRUE);
}
} else if (v->is_default) {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(last_radio), TRUE);
}
gtk_box_pack_start(GTK_BOX(radiobox), last_radio, TRUE, TRUE, 0);
gtk_widget_show(last_radio);
}
return radiobox;
}
static void extcap_gtk_multicheck_toggled(GtkCellRendererToggle *cell _U_,
gchar *path_str, gpointer data) {
GtkTreeModel *model = (GtkTreeModel *) data;
GtkTreeIter iter;
GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
gboolean enabled;
gtk_tree_model_get_iter(model, &iter, path);
gtk_tree_model_get(model, &iter, EXTCAP_GTK_MULTI_COL_CHECK, &enabled, -1);
enabled ^= 1;
gtk_list_store_set(GTK_LIST_STORE(model), &iter, EXTCAP_GTK_MULTI_COL_CHECK,
enabled, -1);
gtk_tree_path_free(path);
}
GtkWidget *extcap_create_gtk_rangewidget(extcap_arg *argument,
GHashTable *prev_map _U_) {
GtkWidget *spinButton;
GtkAdjustment *adjustment;
gfloat def = 0.0, min = 0.0, max = 0.0;
switch (argument->arg_type) {
case EXTCAP_ARG_INTEGER:
def = (gfloat) extcap_complex_get_int(argument->default_complex);
min = (gfloat) extcap_complex_get_int(argument->range_start);
max = (gfloat) extcap_complex_get_int(argument->range_end);
break;
case EXTCAP_ARG_UNSIGNED:
def = (gfloat) extcap_complex_get_uint(argument->default_complex);
min = (gfloat) extcap_complex_get_uint(argument->range_start);
max = (gfloat) extcap_complex_get_uint(argument->range_end);
break;
case EXTCAP_ARG_LONG:
def = (gfloat) extcap_complex_get_long(argument->default_complex);
min = (gfloat) extcap_complex_get_long(argument->range_start);
max = (gfloat) extcap_complex_get_long(argument->range_end);
break;
case EXTCAP_ARG_DOUBLE:
def = (gfloat) extcap_complex_get_double(argument->default_complex);
min = (gfloat) extcap_complex_get_double(argument->range_start);
max = (gfloat) extcap_complex_get_double(argument->range_end);
break;
default:
return NULL ;
break;
}
adjustment = (GtkAdjustment *)gtk_adjustment_new(def, min, max, 1.0, 10.0, 0.0);
spinButton = gtk_spin_button_new(adjustment, 0, 0);
gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spinButton), TRUE);
gtk_widget_set_size_request(spinButton, 80, -1);
return spinButton;
}
static void extcap_file_selectiondialog( GtkWidget *widget _U_, gpointer data )
{
GtkWidget * filechooser = NULL;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
gchar *filename = NULL;
gint res = 0;
extcap_arg *argument = NULL;
if ( GTK_ENTRY(data) == NULL )
return;
argument = (extcap_arg *)g_object_get_data(G_OBJECT(data), EXTCAP_GTK_DATA_KEY_ARGUMENT);
if ( argument != NULL && argument->fileexists == TRUE )
action = GTK_FILE_CHOOSER_ACTION_OPEN;
filechooser = gtk_file_chooser_dialog_new("Select file path", NULL, action,
"_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL);
res = gtk_dialog_run (GTK_DIALOG (filechooser));
if (res == GTK_RESPONSE_ACCEPT)
{
GtkFileChooser *chooser = GTK_FILE_CHOOSER (filechooser);
filename = gtk_file_chooser_get_filename (chooser);
/* this check might not be necessary, but just to be on the safe side */
if ( action == GTK_FILE_CHOOSER_ACTION_OPEN && ! file_exists ( filename ) )
filename = g_strdup ( " " );
gtk_entry_set_text(GTK_ENTRY(data), filename);
}
gtk_widget_destroy (filechooser);
}
static GtkWidget *extcap_create_gtk_fileselect(extcap_arg *argument,
GHashTable *prev_map _U_, gchar * file _U_) {
GtkWidget * entry = NULL;
GtkWidget * button = NULL;
GtkWidget * ret_box = NULL;
button = gtk_button_new_with_label ("...");
entry = gtk_entry_new();
if (file != NULL)
gtk_entry_set_text(GTK_ENTRY(entry), file);
gtk_editable_set_editable (GTK_EDITABLE (entry), FALSE);
g_object_set_data(G_OBJECT(entry), EXTCAP_GTK_DATA_KEY_ARGUMENT, argument);
#if GTK_CHECK_VERSION(3, 0, 0)
ret_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3);
#else
ret_box = gtk_hbox_new(FALSE, 3);
#endif
gtk_box_pack_start ( GTK_BOX(ret_box), entry, TRUE, TRUE, 5 );
gtk_widget_show(entry);
gtk_box_pack_end ( GTK_BOX(ret_box), button, FALSE, FALSE, 5 );
gtk_widget_show(button);
g_signal_connect (button, "clicked",
G_CALLBACK (extcap_file_selectiondialog), (gpointer) entry);
g_object_set_data(G_OBJECT(ret_box), EXTCAP_GTK_DATA_KEY_FILENAME, entry);
return ret_box;
}
GtkWidget *extcap_create_gtk_multicheckwidget(extcap_arg *argument,
GHashTable *prev_map) {
GtkCellRenderer *renderer, *togglerenderer;
GtkTreeModel *model;
GtkWidget *view, *retview;
GtkListStore *store;
GtkTreeIter iter;
GtkTreeSelection *selection;
extcap_value *v = NULL;
GList * walker = NULL;
gchar *prev_item = NULL;
gchar **prev_list = NULL, **prev_iter = NULL;
gboolean prev_value, prev_matched;
if (g_list_length(argument->values) == 0)
return NULL ;
view = gtk_tree_view_new();
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
store = gtk_list_store_new(EXTCAP_GTK_MULTI_NUM_COLS, G_TYPE_BOOLEAN,
G_TYPE_STRING, G_TYPE_POINTER);
model = GTK_TREE_MODEL(store);
gtk_tree_view_set_model(GTK_TREE_VIEW(view), model);
gtk_tree_selection_set_mode(selection, GTK_SELECTION_NONE);
if (prev_map != NULL)
prev_item = (gchar *) g_hash_table_lookup(prev_map, argument->call);
if (prev_item != NULL)
prev_list = g_strsplit(prev_item, ",", 0);
for (walker = g_list_first(argument->values); walker != NULL ; walker =
walker->next) {
v = (extcap_value *) walker->data;
if (v->display == NULL)
break;
prev_value = FALSE;
prev_matched = FALSE;
gtk_list_store_append(store, &iter);
if (prev_list != NULL) {
prev_matched = FALSE;
prev_iter = prev_list;
while (*prev_iter != NULL ) {
if (g_strcmp0(*prev_iter, v->call) == 0) {
prev_matched = TRUE;
prev_value = TRUE;
break;
}
prev_iter++;
}
}
if (prev_matched == FALSE)
prev_value = v->enabled;
gtk_list_store_set(store, &iter, EXTCAP_GTK_MULTI_COL_CHECK, prev_value,
EXTCAP_GTK_MULTI_COL_DISPLAY, v->display,
EXTCAP_GTK_MULTI_COL_VALUE, v, -1);
}
if (prev_list != NULL)
g_strfreev(prev_list);
renderer = gtk_cell_renderer_text_new();
togglerenderer = gtk_cell_renderer_toggle_new();
g_signal_connect(togglerenderer, "toggled",
G_CALLBACK(extcap_gtk_multicheck_toggled), model);
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1,
"Enabled", togglerenderer, "active", EXTCAP_GTK_MULTI_COL_CHECK,
NULL);
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), -1, "Name",
renderer, "text", EXTCAP_GTK_MULTI_COL_DISPLAY,
NULL);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
retview = extcap_gtk_wrap_scroll_treeview(view);
if (gtk_tree_model_iter_n_children(model, NULL) > 3)
gtk_widget_set_size_request(retview, 0, 100);
/* Tree view has own reference */
g_object_unref(model);
return retview;
}
void extcap_gtk_free_args(GtkWidget *vbox) {
GList *arguments = (GList *) g_object_get_data(G_OBJECT(vbox),
EXTCAP_GTK_DATA_KEY_ARGPTR);
extcap_free_arg_list(arguments);
g_object_set_data(G_OBJECT(vbox), EXTCAP_GTK_DATA_KEY_ARGPTR, NULL);
}
GSList *extcap_populate_gtk_vbox(GList *arguments, GtkWidget *vbox,
GHashTable *prev_map) {
GSList *widget_toplist = NULL;
extcap_arg *arg_iter = NULL;
extcap_complex *prev_complex = NULL;
gchar *prev_call, *default_str;
GList * arg_list = g_list_first(arguments);
if ( arg_list == NULL )
return NULL;
arg_iter = (extcap_arg*) (arg_list->data);
g_object_set_data(G_OBJECT(vbox), EXTCAP_GTK_DATA_KEY_ARGPTR, arguments);
while (arg_list != NULL ) {
GtkWidget *hbox = NULL, *label = NULL, *item = NULL;
arg_iter = (extcap_arg*) (arg_list->data);
/* A new storage box for label + element */
hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5, FALSE);
if (prev_map != NULL
&& (prev_call = (gchar *) g_hash_table_lookup(prev_map,
arg_iter->call)) != NULL) {
prev_complex = extcap_parse_complex(arg_iter->arg_type, prev_call);
} else {
prev_complex = NULL;
}
switch (arg_iter->arg_type) {
case EXTCAP_ARG_INTEGER:
case EXTCAP_ARG_UNSIGNED:
case EXTCAP_ARG_LONG:
case EXTCAP_ARG_DOUBLE:
label = gtk_label_new(arg_iter->display);
gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.1f);
item = extcap_create_gtk_rangewidget(arg_iter, prev_map);
if (item == NULL) {
item = gtk_entry_new();
if (prev_complex != NULL) {
default_str = extcap_get_complex_as_string(prev_complex);
gtk_entry_set_text(GTK_ENTRY(item), default_str);
g_free(default_str);
} else if (arg_iter->default_complex != NULL) {
default_str = extcap_get_complex_as_string(
arg_iter->default_complex);
gtk_entry_set_text(GTK_ENTRY(item), default_str);
g_free(default_str);
}
}
break;
case EXTCAP_ARG_STRING:
label = gtk_label_new(arg_iter->display);
item = gtk_entry_new();
default_str = NULL;
if (prev_complex != NULL)
default_str = extcap_get_complex_as_string(prev_complex);
else if (arg_iter->default_complex != NULL)
default_str = extcap_get_complex_as_string(
arg_iter->default_complex);
if (default_str != NULL) {
gtk_entry_set_text(GTK_ENTRY(item), default_str);
g_free(default_str);
}
break;
case EXTCAP_ARG_FILESELECT:
label = gtk_label_new(arg_iter->display);
default_str = NULL;
if (prev_complex != NULL)
default_str = extcap_get_complex_as_string(prev_complex);
else if (arg_iter->default_complex != NULL)
default_str = extcap_get_complex_as_string(
arg_iter->default_complex);
gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.1f);
item = extcap_create_gtk_fileselect(arg_iter, prev_map, default_str);
if (default_str != NULL)
g_free(default_str);
break;
case EXTCAP_ARG_BOOLEAN:
case EXTCAP_ARG_BOOLFLAG:
item = gtk_check_button_new_with_label(arg_iter->display);
if (prev_complex != NULL) {
if (extcap_complex_get_bool(prev_complex))
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item), TRUE);
} else if (arg_iter->default_complex != NULL
&& extcap_complex_get_bool(arg_iter->default_complex)) {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item), TRUE);
}
break;
case EXTCAP_ARG_MENU:
break;
case EXTCAP_ARG_RADIO:
label = gtk_label_new(arg_iter->display);
gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.1f);
item = extcap_create_gtk_radiowidget(arg_iter, prev_map);
break;
case EXTCAP_ARG_SELECTOR:
label = gtk_label_new(arg_iter->display);
gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.1f);
item = extcap_create_gtk_listwidget(arg_iter, prev_map);
break;
case EXTCAP_ARG_MULTICHECK:
label = gtk_label_new(arg_iter->display);
gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.1f);
item = extcap_create_gtk_multicheckwidget(arg_iter, prev_map);
break;
default:
break;
}
if (prev_complex != NULL)
extcap_free_complex(prev_complex);
if (label != NULL) {
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
gtk_widget_show(label);
}
if (item != NULL) {
gtk_box_pack_start(GTK_BOX(hbox), item, TRUE, TRUE, 0);
gtk_widget_show(item);
g_object_set_data(G_OBJECT(item), EXTCAP_GTK_DATA_KEY_ARGPTR,
arg_iter);
if (arg_iter->tooltip != NULL) {
gtk_widget_set_tooltip_text(item, arg_iter->tooltip);
}
widget_toplist = g_slist_append(widget_toplist, item);
}
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 1);
gtk_widget_show(hbox);
arg_list = arg_list->next;
}
return widget_toplist;
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=4 tabstop=4 noexpandtab:
* :indentSize=4:tabSize=4:noTabs=false:
*/

122
ui/gtk/extcap_gtk.h Normal file
View File

@ -0,0 +1,122 @@
/* extcap_gtk.c
*
* 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.
*/
#ifndef __EXTCAP_GTK_H__
#define __EXTCAP_GTK_H__
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <extcap_parser.h>
/*
* GObject data keys for linking argument records to the gtk
* UI
*/
#define EXTCAP_GTK_DATA_KEY_ARGPTR "EXTCAP_ARGPTR"
#define EXTCAP_GTK_DATA_KEY_VALPTR "EXTCAP_VALPTR"
#define EXTCAP_GTK_DATA_KEY_FIRSTRADIO "EXTCAP_FIRSTRADIO"
#define EXTCAP_GTK_DATA_KEY_WIDGETLIST "EXTCAP_WIDGETLIST"
#define EXTCAP_GTK_DATA_KEY_TREEVIEW "EXTCAP_TREEVIEW"
#define EXTCAP_GTK_DATA_KEY_FILENAME "EXTCAP_FILENAME"
#define EXTCAP_GTK_DATA_KEY_ARGUMENT "EXTCAP_ARGUMENT"
/*
* GTK UI / EXTCAP Linkage:
*
* Packed vbox of widgets
* Contains EXTCAP_WIDGETLIST pointing to enclosed widget list
*
* GSList gtk_ui_widgets
* Linked list of drawable widgets in the UI
*
* GtkWidget contained in GSList
* Drawn GTK UI element. If UI element is directly linked
* to argument, will contain EXTCAP_ARGPTR.
*
* Top-level GTK widgets will include text boxes, sliders
* (if supported), and checkboxes.
*
* If the top level widget contains radio buttons, it will
* contain an EXTCAP_ARGPTR *and* an EXTCAP_FIRSTRADIO
*
* Radio buttons
* Each radio button will contain an EXTCAP_VALPTR reference
* to the extcap_value * value being used.
*
* Selectors
* Each selector row contains a pointer to the value, in the
* column COL_VALUE
*
*/
enum extcap_gtk_col_types {
EXTCAP_GTK_COL_DISPLAY = 0, EXTCAP_GTK_COL_VALUE = 1, EXTCAP_GTK_NUM_COLS
};
enum extcap_gtk_multi_col_types {
EXTCAP_GTK_MULTI_COL_CHECK = 0,
EXTCAP_GTK_MULTI_COL_DISPLAY = 1,
EXTCAP_GTK_MULTI_COL_VALUE = 2,
EXTCAP_GTK_MULTI_NUM_COLS
};
/* Get a hash map of calls and values from the top widget */
GHashTable *extcap_gtk_get_state(GtkWidget *widget);
GtkWidget *extcap_create_gtk_rangewidget(extcap_arg *argument,
GHashTable *prev_map);
GtkWidget *extcap_create_gtk_listwidget(extcap_arg *argument,
GHashTable *prev_map);
GtkWidget *extcap_create_gtk_radiowidget(extcap_arg *argument,
GHashTable *prev_map);
GtkWidget *extcap_create_gtk_multicheckwidget(extcap_arg *argument,
GHashTable *prev_map);
/*
* Populate a (pre-created) container widget based on an arguments record.
* For secondary repopulations, a saved state can be passed to populate
* with known values. This should occur when setting interface options
* repeatedly, for example
*/
GSList *extcap_populate_gtk_vbox(GList *arguments, GtkWidget *vbox,
GHashTable *prev_map);
/* Free args associated with a GTK item */
void extcap_gtk_free_args(GtkWidget *vbox);
#endif
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=4 tabstop=4 noexpandtab:
* :indentSize=4:tabSize=4:noTabs=false:
*/

View File

@ -136,6 +136,9 @@ scan_local_interfaces(void (*update_cb)(void))
temp->vendor_description = g_strdup(if_info->vendor_description);
temp->loopback = if_info->loopback;
temp->type = if_info->type;
#ifdef HAVE_EXTCAP
temp->extcap = g_strdup(if_info->extcap);
#endif
/* Is this interface hidden and, if so, should we include it anyway? */
/* Do we have a user-supplied description? */
@ -318,6 +321,11 @@ scan_local_interfaces(void (*update_cb)(void))
}
}
}
#ifdef HAVE_EXTCAP
/* Extcap devices start with no cached args */
device.external_cap_args_settings = NULL;
#endif
if (global_capture_opts.all_ifaces->len <= count) {
g_array_append_val(global_capture_opts.all_ifaces, device);
count = global_capture_opts.all_ifaces->len;
@ -374,6 +382,9 @@ scan_local_interfaces(void (*update_cb)(void))
device.if_info.vendor_description = g_strdup(interface_opts.descr);
device.if_info.addrs = NULL;
device.if_info.loopback = FALSE;
#ifdef HAVE_EXTCAP
device.if_info.extcap = g_strdup(interface_opts.extcap);
#endif
g_array_append_val(global_capture_opts.all_ifaces, device);
global_capture_opts.num_selected++;

View File

@ -192,6 +192,8 @@ SOURCES_WS_C = \
../../capture_opts.c \
../../cfile.c \
../../color_filters.c \
../../extcap.c \
../../extcap_parser.c \
../../file.c \
../../fileset.c \
../../frame_tvbuff.c \

View File

@ -239,6 +239,19 @@ AboutDialog::AboutDialog(QWidget *parent) :
g_free(path);
#endif
#ifdef HAVE_EXTCAP
/* Extcap */
constpath = get_extcap_dir();
resultArray = g_strsplit(constpath, G_SEARCHPATH_SEPARATOR_S, 10);
for(i = 0; resultArray[i]; i++) {
message += about_folders_row("Extcap path", g_strstrip(resultArray[i]),
"Extcap Plugins search path");
}
g_strfreev(resultArray);
#endif
message += "</table>";
ui->label_folders->setText(message);

View File

@ -1062,6 +1062,117 @@ get_plugin_dir(void)
#endif
}
#if defined(HAVE_EXTCAP)
/*
* Find the directory where the extcap hooks are stored.
*
* On Windows, we use the "extcap" subdirectory of the datafile directory.
*
* On UN*X, we use the EXTCAP_DIR value supplied by the configure
* script, unless we think we're being run from the build directory,
* in which case we use the "extcap" subdirectory of the datafile directory.
*
* In both cases, we then use the subdirectory of that directory whose
* name is the version number.
*
* XXX - if we think we're being run from the build directory, perhaps we
* should have the extcap code not look in the version subdirectory
* of the extcap directory, but look in all of the subdirectories
* of the extcap directory, so it can just fetch the extcap hooks built
* as part of the build process.
*/
static const char *extcap_dir = NULL;
static void init_extcap_dir(void) {
#ifdef _WIN32
/*
* On Windows, the data file directory is the installation
* directory; the extcap hooks are stored under it.
*
* Assume we're running the installed version of Wireshark;
* on Windows, the data file directory is the directory
* in which the Wireshark binary resides.
*/
extcap_dir = g_strdup_printf("%s\\extcap\\%s", get_datafile_dir(),
VERSION);
/*
* Make sure that pathname refers to a directory.
*/
if (test_for_directory(extcap_dir) != EISDIR) {
/*
* Either it doesn't refer to a directory or it
* refers to something that doesn't exist.
*
* Assume that means we're running a version of
* Wireshark we've built in a build directory,
* in which case {datafile dir}\plugins is the
* top-level extcap hooks source directory, and use
* that directory and set the "we're running in
* a build directory" flag, so the plugin
* scanner will check all subdirectories of that
* directory for extcap hooks.
*/
g_free( (gpointer) extcap_dir);
extcap_dir = g_strdup_printf("%s\\extcap", get_datafile_dir());
running_in_build_directory_flag = TRUE;
}
#else
if (running_in_build_directory_flag) {
/*
* We're (probably) being run from the build directory and
* weren't started with special privileges, so we'll use
* the "extcap hooks" subdirectory of the directory where the program
* we're running is (that's the build directory).
*/
extcap_dir = g_strdup_printf("%s/extcap", get_progfile_dir());
} else {
if (getenv("WIRESHARK_EXTCAP_DIR") && !started_with_special_privs()) {
/*
* The user specified a different directory for extcap hooks
* and we aren't running with special privileges.
*/
extcap_dir = g_strdup(getenv("WIRESHARK_EXTCAP_DIR"));
}
#ifdef __APPLE__
/*
* If we're running from an app bundle and weren't started
* with special privileges, use the Contents/Resources/lib/wireshark/extcap
* subdirectory of the app bundle.
*
* (appbundle_dir is not set to a non-null value if we're
* started with special privileges, so we need only check
* it; we don't need to call started_with_special_privs().)
*/
else if (appbundle_dir != NULL) {
extcap_dir = g_strdup_printf("%s/Contents/Resources/lib/wireshark/extcap",
appbundle_dir);
}
#endif
else {
extcap_dir = EXTCAP_DIR;
}
}
#endif
}
#endif /* HAVE_EXTCAP */
/*
* Get the directory in which the extcap hooks are stored.
*
* XXX - A fix instead of HAVE_EXTCAP must be found
*/
const char *
get_extcap_dir(void) {
#if defined(HAVE_EXTCAP)
if (!extcap_dir)
init_extcap_dir();
return extcap_dir;
#else
return NULL;
#endif
}
/*
* Get the flag indicating whether we're running from a build
* directory.

View File

@ -54,6 +54,13 @@ WS_DLL_PUBLIC const char *get_progfile_dir(void);
*/
WS_DLL_PUBLIC const char *get_plugin_dir(void);
/*
* Get the directory in which extcap hooks are stored; this must not be called
* before init_progfile_dir() is called, as they might be stored in a
* subdirectory of the program file directory.
*/
WS_DLL_PUBLIC const char *get_extcap_dir(void);
/*
* Get the flag indicating whether we're running from a build
* directory.