examples: add custom logging plugin

Add an example custom logger that hooks into the low level packet and
flow logging callbacks.

Ticket: #7227
pull/11689/head
Jason Ish 11 months ago committed by Victor Julien
parent 3d2820ba39
commit cdcb395142

@ -194,6 +194,10 @@ jobs:
working-directory: examples/plugins/c-json-filetype
run: make clean all
- name: Build example C custom logger plugin
working-directory: examples/plugins/c-custom-loggers
run: make clean all
- name: Install Suricata and library
run: make install install-headers install-library

@ -2505,6 +2505,7 @@ 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-json-filetype/Makefile)
AC_CONFIG_FILES(examples/plugins/c-custom-loggers/Makefile)
AC_CONFIG_FILES(examples/plugins/ci-capture/Makefile)
AC_CONFIG_FILES(examples/lib/simple/Makefile examples/lib/simple/Makefile.example)
AC_CONFIG_FILES(plugins/Makefile)

@ -0,0 +1,3 @@
!/Makefile.in
*.la
*.so

@ -0,0 +1,32 @@
# If building a plugin out of the Suricata source tree, you can use
# libsuricata-config --cflags.
#LIBSURICATA_CONFIG ?= libsuricata-config
#CPPFLAGS += `$(LIBSURICATA_CONFIG) --cflags`
# But as this is an example in the Suricata source tree we'll look for
# includes in the source tree.
CPPFLAGS += -I@top_srcdir@/src -DHAVE_CONFIG_H
# Currently the Suricata logging system requires this to be even for
# plugins.
CPPFLAGS += "-D__SCFILENAME__=\"$(*F)\""
all: Makefile custom-logger.so
custom-logger.so: custom-logger.c
$(CC) $(CPPFLAGS) -fPIC -shared -o $@ $^
clean:
rm -f *.so *.o *.lo
rm -rf .deps
distclean: clean
rm -f Makefile.am
# Regenerate Makefile on change of Makefile.in since we're not using
# Makefile.am.
Makefile: Makefile.in
cd @top_builddir@ && ./config.status examples/plugins/c-custom-logger/Makefile
# Dummy rules to satisfy make dist.
dist distdir:

@ -0,0 +1,55 @@
# Example Custom Logging Plugin
This is an example of a low level logging plugin.
Currently implemented are packet and flow loggers.
## Building
If in the Suricata source directory, this plugin can be built by
running `make`'.
## Building Standalone
This Makefile is not generated by automake so it can serve as an
example for plugins created outside of the Suricata source tree.
Building a standalone plugin 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`)
Modify the Makefile to use `libsuricata-config`.
Before building this plugin you will need to build and install Suricata from the
git master branch and install the development tools and headers:
- `make install-library`
- `make install-headers`
then make sure the newly installed tool `libsuricata-config` can be
found in your path, for example:
```
libsuricata-config --cflags
```
Then a simple `make` should build this plugin.
Or if the Suricata installation is not in the path, a command like the following
can be used:
```
PATH=/opt/suricata/bin:$PATH make
```
## Usage
To run the plugin, first add the path to the plugin you just compiled to
your `suricata.yaml`, for example:
```
plugins:
- /usr/lib/suricata/plugins/c-custom-loggers/custom-loggers.so
```

@ -0,0 +1,110 @@
/* Copyright (C) 2023-2024 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-packet.h"
#include "output-flow.h"
#include "util-print.h"
static int CustomPacketLogger(ThreadVars *tv, void *thread_data, const Packet *p)
{
char src_ip[46] = { 0 }, dst_ip[46] = { 0 };
if (PacketIsIPv4(p)) {
PrintInet(AF_INET, (const void *)&(p->src.addr_data32[0]), src_ip, sizeof(src_ip));
PrintInet(AF_INET, (const void *)&(p->dst.addr_data32[0]), dst_ip, sizeof(dst_ip));
} else if (PacketIsIPv6(p)) {
PrintInet(AF_INET6, (const void *)&(p->src.address), src_ip, sizeof(src_ip));
PrintInet(AF_INET6, (const void *)&(p->dst.address), dst_ip, sizeof(dst_ip));
} else {
SCLogNotice("Packet is not IP");
return 0;
}
SCLogNotice("Packet: %s -> %s", src_ip, dst_ip);
return 0;
}
static bool CustomPacketLoggerCondition(ThreadVars *tv, void *thread_data, const Packet *)
{
/* Always true for this example. */
return true;
}
static int CustomFlowLogger(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 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 void Init(void)
{
OutputRegisterPacketLogger(LOGGER_USER, "custom-packet-logger", CustomPacketLogger,
CustomPacketLoggerCondition, NULL, ThreadInit, ThreadDeinit, NULL);
OutputRegisterFlowLogger("custom-flow-logger", CustomFlowLogger, NULL, ThreadInit, ThreadDeinit);
}
const SCPlugin PluginRegistration = {
.name = "CustomLogger",
.author = "Firstname Lastname",
.license = "GPLv2",
.Init = Init,
};
const SCPlugin *SCPluginRegister(void)
{
return &PluginRegistration;
}
Loading…
Cancel
Save