From 16492f2b7e588bca1c7e10f0ddf5b515aa50ddc3 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 15 Sep 2023 14:57:52 -0600 Subject: [PATCH] plugins: add example low level flow logging pluging This is an example what adding plugin examples to the Suricata repo could look like. This plugin is integrated in with autoconf/automake. A standalone Makefile should be provided, perhaps with a cmake example as well. Note that the examples directory was added as EXTRA_DIST as we don't want normal builds to recurse into it and attempt to build the plugin, its just an example. --- Makefile.am | 3 +- configure.ac | 2 + examples/plugins/c-flow-logger/Makefile.am | 17 +++++ examples/plugins/c-flow-logger/README.md | 26 +++++++ examples/plugins/c-flow-logger/flowlogger.c | 83 +++++++++++++++++++++ 5 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 examples/plugins/c-flow-logger/Makefile.am create mode 100644 examples/plugins/c-flow-logger/README.md create mode 100644 examples/plugins/c-flow-logger/flowlogger.c diff --git a/Makefile.am b/Makefile.am index 67963ed32fcf..00503e21f9a4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,8 @@ EXTRA_DIST = ChangeLog COPYING LICENSE suricata.yaml.in \ $(SURICATA_UPDATE_DIR) \ lua \ acsite.m4 \ - scripts/generate-images.sh + scripts/generate-images.sh \ + examples SUBDIRS = $(HTP_DIR) rust src qa rules doc contrib etc python ebpf \ $(SURICATA_UPDATE_DIR) diff --git a/configure.ac b/configure.ac index 8bb752715f53..ef4e1858b1ea 100644 --- a/configure.ac +++ b/configure.ac @@ -2612,6 +2612,8 @@ AC_CONFIG_FILES(suricata.yaml etc/Makefile etc/suricata.logrotate etc/suricata.s AC_CONFIG_FILES(python/Makefile python/suricata/config/defaults.py) AC_CONFIG_FILES(ebpf/Makefile) AC_CONFIG_FILES(libsuricata-config) +AC_CONFIG_FILES(examples/plugins/c-flow-logger/Makefile) + AC_OUTPUT SURICATA_BUILD_CONF="Suricata Configuration: diff --git a/examples/plugins/c-flow-logger/Makefile.am b/examples/plugins/c-flow-logger/Makefile.am new file mode 100644 index 000000000000..58f795b24add --- /dev/null +++ b/examples/plugins/c-flow-logger/Makefile.am @@ -0,0 +1,17 @@ +plugindir = ${libdir}/suricata/plugins + +if BUILD_SHARED_LIBRARY +plugin_LTLIBRARIES = flowlogger.la +flowlogger_la_LDFLAGS = -module -shared +flowlogger_la_SOURCES = flowlogger.c + +flowlogger_la_CPPFLAGS = -I$(abs_top_srcdir)/rust/gen -I$(abs_top_srcdir)/rust/dist + +else + +all-local: + @echo + @echo "Shared library support must be enabled to build plugins." + @echo + +endif diff --git a/examples/plugins/c-flow-logger/README.md b/examples/plugins/c-flow-logger/README.md new file mode 100644 index 000000000000..65a84ddc1459 --- /dev/null +++ b/examples/plugins/c-flow-logger/README.md @@ -0,0 +1,26 @@ +# Example Flow Logging Plugin + +This is an example of a low level flow logging plugin for Suricata +8.0. + +## Building + +In in the Suricata source code and you did not use the +`--disable-shared` `./configure` option, you should be able to just +run `make` to build the plugin. + +Note that due to Automake and friends, the plugin will be compiled to +`.libs/flowlogger.so.0.0.0`. + +### Standalone Building + +The file `Makefile.example` is an example of how you might build a +plugin that is distributed separately from the Suricata source code. +It has the following dependencies: + +- Suricata is installed +- The Suricata library is installed: `make install-library` +- The Suricata development headers are installed: `make install-headers` +- The program `libsuricata-config` is in your path (installed with `make install-library`) + +Then run: `make -f Makefile.example` diff --git a/examples/plugins/c-flow-logger/flowlogger.c b/examples/plugins/c-flow-logger/flowlogger.c new file mode 100644 index 000000000000..d0eb205cf69e --- /dev/null +++ b/examples/plugins/c-flow-logger/flowlogger.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "suricata-common.h" +#include "suricata-plugin.h" + +#include "output-flow.h" +#include "util-print.h" + +static TmEcode ThreadInit(ThreadVars *tv, const void *initdata, void **data) +{ + return TM_ECODE_OK; +} + +static TmEcode ThreadDeinit(ThreadVars *tv, void *data) +{ + // Nothing to do. If we allocated data in ThreadInit we would free + // it here. + return TM_ECODE_OK; +} + +static int FlowLogger(ThreadVars *tv, void *thread_data, Flow *f) +{ + char src_ip[46] = { 0 }, dst_ip[46] = { 0 }; + Port sp, dp; + + if ((f->flags & FLOW_DIR_REVERSED) == 0) { + if (FLOW_IS_IPV4(f)) { + PrintInet(AF_INET, (const void *)&(f->src.addr_data32[0]), src_ip, sizeof(src_ip)); + PrintInet(AF_INET, (const void *)&(f->dst.addr_data32[0]), dst_ip, sizeof(dst_ip)); + } else if (FLOW_IS_IPV6(f)) { + PrintInet(AF_INET6, (const void *)&(f->src.address), src_ip, sizeof(src_ip)); + PrintInet(AF_INET6, (const void *)&(f->dst.address), dst_ip, sizeof(dst_ip)); + } + sp = f->sp; + dp = f->dp; + } else { + if (FLOW_IS_IPV4(f)) { + PrintInet(AF_INET, (const void *)&(f->dst.addr_data32[0]), src_ip, sizeof(src_ip)); + PrintInet(AF_INET, (const void *)&(f->src.addr_data32[0]), dst_ip, sizeof(dst_ip)); + } else if (FLOW_IS_IPV6(f)) { + PrintInet(AF_INET6, (const void *)&(f->dst.address), src_ip, sizeof(src_ip)); + PrintInet(AF_INET6, (const void *)&(f->src.address), dst_ip, sizeof(dst_ip)); + } + sp = f->dp; + dp = f->sp; + } + + SCLogNotice("Flow: %s:%u -> %s:%u", src_ip, sp, dst_ip, dp); + + return 0; +} + +static void Init(void) +{ + SCOutputRegisterFlowLogger("custom-flow-logger", FlowLogger, NULL, ThreadInit, ThreadDeinit); +} + +const SCPlugin PluginRegistration = { + .name = "FlowLogger", + .author = "Jason Ish", + .license = "GPLv2", + .Init = Init, +}; + +static const SCPlugin *SCPluginRegister(void) +{ + return &PluginRegistration; +}