summaryrefslogtreecommitdiffstats
path: root/extcap/extcap-base.c
diff options
context:
space:
mode:
Diffstat (limited to 'extcap/extcap-base.c')
-rw-r--r--extcap/extcap-base.c427
1 files changed, 427 insertions, 0 deletions
diff --git a/extcap/extcap-base.c b/extcap/extcap-base.c
new file mode 100644
index 00000000..13d42b7a
--- /dev/null
+++ b/extcap/extcap-base.c
@@ -0,0 +1,427 @@
+/* extcap-base.c
+ * Base function for extcaps
+ *
+ * Copyright 2015, Dario Lombardo
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "config.h"
+#define WS_LOG_DOMAIN LOG_DOMAIN_EXTCAP
+
+#include "extcap-base.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <wsutil/wslog.h>
+
+#include <wsutil/ws_assert.h>
+
+#include "ws_attributes.h"
+
+enum extcap_options {
+ EXTCAP_BASE_OPTIONS_ENUM
+};
+
+typedef struct _extcap_interface
+{
+ char * interface;
+ char * description;
+
+ uint16_t dlt;
+ char * dltname;
+ char * dltdescription;
+} extcap_interface;
+
+typedef struct _extcap_option {
+ char * optname;
+ char * optdesc;
+} extcap_option_t;
+
+static FILE *custom_log = NULL;
+
+/* used to inform to extcap application that end of application is requested */
+bool extcap_end_application = false;
+/* graceful shutdown callback, can be null */
+void (*extcap_graceful_shutdown_cb)(void) = NULL;
+
+static void extcap_init_log_file(const char *filename);
+
+/* Called from signals */
+#ifdef _WIN32
+static BOOL WINAPI
+extcap_exit_from_loop(DWORD dwCtrlType _U_)
+#else
+static void extcap_exit_from_loop(int signo _U_)
+#endif /* _WIN32 */
+{
+ ws_debug("Exiting from main loop by signal");
+ extcap_end_application = true;
+ if (extcap_graceful_shutdown_cb != NULL) {
+ extcap_graceful_shutdown_cb();
+ }
+#ifdef _WIN32
+ return true;
+#endif /* _WIN32 */
+}
+
+void extcap_base_register_interface(extcap_parameters * extcap, const char * interface, const char * ifdescription, uint16_t dlt, const char * dltdescription )
+{
+ extcap_base_register_interface_ext(extcap, interface, ifdescription, dlt, NULL, dltdescription );
+}
+
+void extcap_base_register_interface_ext(extcap_parameters * extcap,
+ const char * interface, const char * ifdescription,
+ uint16_t dlt, const char * dltname, const char * dltdescription )
+{
+ extcap_interface * iface;
+
+ if (interface == NULL)
+ return;
+
+ iface = g_new0(extcap_interface, 1);
+
+ iface->interface = g_strdup(interface);
+ iface->description = g_strdup(ifdescription);
+ iface->dlt = dlt;
+ iface->dltname = g_strdup(dltname);
+ iface->dltdescription = g_strdup(dltdescription);
+
+ extcap->interfaces = g_list_append(extcap->interfaces, (void *) iface);
+}
+
+bool extcap_base_register_graceful_shutdown_cb(extcap_parameters * extcap _U_, void (*callback)(void))
+{
+#ifndef _WIN32
+ struct sigaction sig_handler = { .sa_handler = extcap_exit_from_loop };
+#endif
+
+ extcap_end_application = false;
+ extcap_graceful_shutdown_cb = callback;
+#ifdef _WIN32
+ if (!SetConsoleCtrlHandler(extcap_exit_from_loop, true)) {
+ ws_warning("Can't set console handler");
+ return false;
+ }
+#else
+ /* Catch signals to be able to cleanup config later */
+ if (sigaction(SIGINT, &sig_handler, NULL)) {
+ ws_warning("Can't set SIGINT signal handler");
+ return false;
+ }
+ if (sigaction(SIGTERM, &sig_handler, NULL)) {
+ ws_warning("Can't set SIGTERM signal handler");
+ return false;
+ }
+ if (sigaction(SIGPIPE, &sig_handler, NULL)) {
+ ws_warning("Can't set SIGPIPE signal handler");
+ return false;
+ }
+#endif /* _WIN32 */
+
+ return true;
+}
+
+void extcap_base_set_util_info(extcap_parameters * extcap, const char * exename, const char * major,
+ const char * minor, const char * release, const char * helppage)
+{
+ extcap->exename = g_path_get_basename(exename);
+
+ ws_assert(major);
+ if (!minor)
+ ws_assert(!release);
+
+ extcap->version = ws_strdup_printf("%s%s%s%s%s",
+ major,
+ minor ? "." : "",
+ minor ? minor : "",
+ release ? "." : "",
+ release ? release : "");
+ extcap->helppage = g_strdup(helppage);
+}
+
+void extcap_base_set_compiled_with(extcap_parameters * extcap, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ extcap->compiled_with = ws_strdup_vprintf(fmt, ap);
+ va_end(ap);
+}
+
+void extcap_base_set_running_with(extcap_parameters * extcap, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ extcap->running_with = ws_strdup_vprintf(fmt, ap);
+ va_end(ap);
+}
+
+void extcap_log_init(const char *progname)
+{
+ ws_log_init(progname, NULL);
+ /* extcaps cannot write debug information to parent on stderr. */
+ ws_log_console_writer_set_use_stdout(true);
+ ws_noisy("Extcap log initialization finished");
+}
+
+uint8_t extcap_base_parse_options(extcap_parameters * extcap, int result, char * optargument)
+{
+ uint8_t ret = 1;
+ enum ws_log_level level;
+
+ switch (result) {
+ case EXTCAP_OPT_LOG_LEVEL:
+ level = ws_log_set_level_str(optargument);
+ if (level == LOG_LEVEL_NONE) {
+ /* Invalid log level string. */
+ ret = 0;
+ }
+ else if (level <= LOG_LEVEL_DEBUG) {
+ extcap->debug = true;
+ }
+ break;
+ case EXTCAP_OPT_LOG_FILE:
+ extcap_init_log_file(optargument);
+ break;
+ case EXTCAP_OPT_LIST_INTERFACES:
+ extcap->do_list_interfaces = 1;
+ break;
+ case EXTCAP_OPT_VERSION:
+ extcap->ws_version = g_strdup(optargument);
+ extcap->do_version = 1;
+ break;
+ case EXTCAP_OPT_LIST_DLTS:
+ extcap->do_list_dlts = 1;
+ break;
+ case EXTCAP_OPT_INTERFACE:
+ extcap->interface = g_strdup(optargument);
+ break;
+ case EXTCAP_OPT_CONFIG:
+ extcap->show_config = 1;
+ break;
+ case EXTCAP_OPT_CAPTURE:
+ extcap->capture = 1;
+ break;
+ case EXTCAP_OPT_CAPTURE_FILTER:
+ extcap->capture_filter = g_strdup(optargument);
+ break;
+ case EXTCAP_OPT_FIFO:
+ extcap->fifo = g_strdup(optargument);
+ break;
+ default:
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void extcap_iface_print(void * data, void * userdata _U_)
+{
+ extcap_interface * iface = (extcap_interface *)data;
+
+ printf("interface {value=%s}", iface->interface);
+ if (iface->description != NULL)
+ printf ("{display=%s}\n", iface->description);
+ else
+ printf ("\n");
+}
+
+static int extcap_iface_compare(gconstpointer a, gconstpointer b)
+{
+ const extcap_interface * iface_a = (const extcap_interface *)a;
+
+ return (g_strcmp0(iface_a->interface, (const char *) b));
+}
+
+static void extcap_print_version(extcap_parameters * extcap)
+{
+ printf("extcap {version=%s}", extcap->version != NULL ? extcap->version : "unknown");
+ if (extcap->helppage != NULL)
+ printf("{help=%s}", extcap->helppage);
+ printf("\n");
+}
+
+static int extcap_iface_listall(extcap_parameters * extcap, uint8_t list_ifs)
+{
+ if (list_ifs) {
+ if (g_list_length(extcap->interfaces) > 0) {
+ extcap_print_version(extcap);
+ g_list_foreach(extcap->interfaces, extcap_iface_print, extcap);
+ }
+ } else if (extcap->do_version) {
+ extcap_print_version(extcap);
+ } else {
+ GList * element = NULL;
+ extcap_interface * iface = NULL;
+ if ((element = g_list_find_custom(extcap->interfaces, extcap->interface, extcap_iface_compare)) == NULL)
+ return 0;
+
+ iface = (extcap_interface *) element->data;
+ printf("dlt {number=%u}{name=%s}", iface->dlt, iface->dltname != NULL ? iface->dltname : iface->interface);
+ if (iface->description != NULL)
+ printf ("{display=%s}\n", iface->dltdescription);
+ else
+ printf ("\n");
+ }
+
+ return 1;
+}
+
+uint8_t extcap_base_handle_interface(extcap_parameters * extcap)
+{
+ /* A fifo must be provided for capture */
+ if (extcap->capture && (extcap->fifo == NULL || strlen(extcap->fifo) <= 0)) {
+ extcap->capture = 0;
+ ws_error("Extcap Error: No FIFO pipe provided");
+ return 0;
+ }
+
+ if (extcap->do_list_interfaces) {
+ return extcap_iface_listall(extcap, 1);
+ } else if (extcap->do_version || extcap->do_list_dlts) {
+ return extcap_iface_listall(extcap, 0);
+ }
+
+ return 0;
+}
+
+static void extcap_iface_free(void * data)
+{
+ extcap_interface * iface = (extcap_interface *)data;
+ g_free(iface->interface);
+ g_free(iface->description);
+ g_free(iface->dltname);
+ g_free(iface->dltdescription);
+ g_free(iface);
+}
+
+static void extcap_help_option_free(void * option)
+{
+ extcap_option_t* o = (extcap_option_t*)option;
+ g_free(o->optname);
+ g_free(o->optdesc);
+ g_free(o);
+}
+
+void extcap_base_cleanup(extcap_parameters ** extcap)
+{
+ g_list_free_full((*extcap)->interfaces, extcap_iface_free);
+ g_free((*extcap)->exename);
+ g_free((*extcap)->fifo);
+ g_free((*extcap)->interface);
+ g_free((*extcap)->version);
+ g_free((*extcap)->compiled_with);
+ g_free((*extcap)->running_with);
+ g_free((*extcap)->helppage);
+ g_free((*extcap)->help_header);
+ g_free((*extcap)->ws_version);
+ g_list_free_full((*extcap)->help_options, extcap_help_option_free);
+ g_free(*extcap);
+ *extcap = NULL;
+}
+
+static void extcap_print_option(void * option, void * user_data _U_)
+{
+ extcap_option_t* o = (extcap_option_t*)option;
+ printf("\t%s: %s\n", o->optname, o->optdesc);
+}
+
+void extcap_version_print(extcap_parameters * extcap)
+{
+ printf("%s version %s\n", extcap->exename, extcap->version);
+ if (extcap->compiled_with != NULL)
+ printf("Compiled with %s\n", extcap->compiled_with);
+ if (extcap->running_with != NULL)
+ printf("Running with %s\n", extcap->running_with);
+}
+
+void extcap_help_print(extcap_parameters * extcap)
+{
+ printf("\nWireshark - %s v%s\n\n", extcap->exename, extcap->version);
+ printf("Usage:\n");
+ printf("%s", extcap->help_header);
+ printf("\n");
+ printf("Options:\n");
+ g_list_foreach(extcap->help_options, extcap_print_option, NULL);
+ printf("\n");
+}
+
+void extcap_help_add_option(extcap_parameters * extcap, const char * help_option_name, const char * help_option_desc)
+{
+ extcap_option_t* o = g_new0(extcap_option_t, 1);
+ o->optname = g_strdup(help_option_name);
+ o->optdesc = g_strdup(help_option_desc);
+
+ extcap->help_options = g_list_append(extcap->help_options, o);
+}
+
+void extcap_help_add_header(extcap_parameters * extcap, char * help_header)
+{
+ extcap->help_header = g_strdup(help_header);
+ extcap_help_add_option(extcap, "--extcap-interfaces", "list the extcap Interfaces");
+ extcap_help_add_option(extcap, "--extcap-dlts", "list the DLTs");
+ extcap_help_add_option(extcap, "--extcap-interface <iface>", "specify the extcap interface");
+ extcap_help_add_option(extcap, "--extcap-config", "list the additional configuration for an interface");
+ extcap_help_add_option(extcap, "--capture", "run the capture");
+ extcap_help_add_option(extcap, "--extcap-capture-filter <filter>", "the capture filter");
+ extcap_help_add_option(extcap, "--fifo <file>", "dump data to file or fifo");
+ extcap_help_add_option(extcap, "--extcap-version", "print tool version");
+ extcap_help_add_option(extcap, "--log-level", "Set the log level");
+ extcap_help_add_option(extcap, "--log-file", "Set a log file to log messages in addition to the console");
+}
+
+static void extcap_init_log_file(const char* filename)
+{
+ if (!filename || strlen(filename) == 0)
+ ws_error("Missing log file name");
+ custom_log = fopen(filename, "w");
+ if (!custom_log)
+ ws_error("Can't open custom log file: %s (%s)", filename, strerror(errno));
+ ws_log_add_custom_file(custom_log);
+}
+
+void extcap_config_debug(unsigned* count)
+{
+ printf("arg {number=%u}{call=--log-level}{display=Set the log level}"
+ "{type=selector}{tooltip=Set the log level}{required=false}"
+ "{group=Debug}\n", *count);
+ printf("value {arg=%u}{value=message}{display=Message}{default=true}\n", *count);
+ printf("value {arg=%u}{value=info}{display=Info}\n", *count);
+ printf("value {arg=%u}{value=debug}{display=Debug}\n", *count);
+ printf("value {arg=%u}{value=noisy}{display=Noisy}\n", *count);
+ (*count)++;
+ printf("arg {number=%u}{call=--log-file}{display=Use a file for logging}"
+ "{type=fileselect}{tooltip=Set a file where log messages are written}{required=false}"
+ "{group=Debug}\n", (*count)++);
+}
+
+void extcap_cmdline_debug(char** ar, const unsigned n)
+{
+ GString* cmdline = g_string_new("cmdline: ");
+ unsigned i;
+ for (i = 0; i < n; i++)
+ g_string_append_printf(cmdline, "%s ", ar[i]);
+ ws_debug("%s", cmdline->str);
+ g_string_free(cmdline, true);
+}
+
+/*
+ * Editor modelines - https://www.wireshark.org/tools/modelines.html
+ *
+ * Local variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ *
+ * vi: set shiftwidth=4 tabstop=8 expandtab:
+ * :indentSize=4:tabSize=8:noTabs=true:
+ */