mirror of https://github.com/OISF/suricata
examples: add custom logging plugin
Add an example custom logger that hooks into the low level packet and flow logging callbacks. Ticket: #7227pull/11689/head
parent
3d2820ba39
commit
cdcb395142
@ -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…
Reference in New Issue