Skip to content

Commit

Permalink
plugins/ndpi: stub in dummy ndpi plugin
Browse files Browse the repository at this point in the history
This plugin stub shows how a plugin like nDPI might be use the flow
init and flow update callbacks to do its work. Also shows usage of
FlowStorage to avoid modifying the Flow struct directly.
  • Loading branch information
jasonish committed Oct 11, 2024
1 parent fa7a531 commit 6607ef3
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 0 deletions.
40 changes: 40 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2293,6 +2293,42 @@ fi
])
AC_SUBST(RUST_FEATURES)

# nDPI support (no library checks for this stub)
NDPI_HOME=
AC_ARG_ENABLE(ndpi,
AS_HELP_STRING([--enable-ndpi], [Enable nDPI support]),
[enable_ndpi=$enableval],[enable_ndpi=no])
AC_ARG_WITH([ndpi],
[ --with-ndpi=<path> path to nDPI source tree.],
[NDPI_HOME="$withval"])

if ! test -z "${NDPI_HOME}" = "yes"; then
AC_MSG_CHECKING(for nDPI source)
if test ! -z "$NDPI_HOME" ; then :
AC_MSG_RESULT(found in $NDPI_HOME)
NDPI_LIB=$NDPI_HOME/src/lib/libndpi.a
AC_MSG_CHECKING(for $NDPI_LIB)
if test -r $NDPI_LIB ; then :
AC_MSG_RESULT(found $NDPI_LIB)
fi
CPPFLAGS="${CPPFLAGS} -I$NDPI_HOME/src/include"
NDPI_LIB="$NDPI_HOME/src/lib/libndpi.a"
AC_SUBST([NDPI_LIB])
else
AC_MSG_RESULT(not found)
enable_ndpi="no"
fi
fi

if test "x$enable_ndpi" = "xyes"; then
AM_CONDITIONAL([BUILD_NDPI], [true])
ndpi_comment=""
else
AM_CONDITIONAL([BUILD_NDPI], [false])
ndpi_comment="#"
fi
AC_SUBST([ndpi_comment])

AC_ARG_ENABLE(warnings,
AS_HELP_STRING([--enable-warnings], [Enable supported C compiler warnings]),[enable_warnings=$enableval],[enable_warnings=no])
AS_IF([test "x$enable_warnings" = "xyes"], [
Expand Down Expand Up @@ -2513,6 +2549,7 @@ 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)
AC_CONFIG_FILES(plugins/pfring/Makefile)
AC_CONFIG_FILES(plugins/ndpi-dummy/Makefile)

AC_OUTPUT

Expand Down Expand Up @@ -2569,6 +2606,9 @@ SURICATA_BUILD_CONF="Suricata Configuration:
Plugin support (experimental): ${plugin_support}
DPDK Bond PMD: ${enable_dpdk_bond_pmd}

Plugins:
nDPI ${enable_ndpi}

Development settings:
Coccinelle / spatch: ${enable_coccinelle}
Unit tests enabled: ${enable_unittests}
Expand Down
4 changes: 4 additions & 0 deletions plugins/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ SUBDIRS =
if BUILD_PFRING
SUBDIRS += pfring
endif

if BUILD_NDPI
SUBDIRS += ndpi-dummy
endif
13 changes: 13 additions & 0 deletions plugins/ndpi-dummy/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
pkglib_LTLIBRARIES = ndpi.la

ndpi_la_LDFLAGS = -module -avoid-version -shared
ndpi_la_LIBADD = @NDPI_LIB@

# Only required to find these headers when building plugins from the
# source directory.
ndpi_la_CFLAGS = -I../../rust/gen -I../../rust/dist

ndpi_la_SOURCES = ndpi.c

install-exec-hook:
cd $(DESTDIR)$(pkglibdir) && $(RM) $(pkglib_LTLIBRARIES)
174 changes: 174 additions & 0 deletions plugins/ndpi-dummy/ndpi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/* Copyright (C) 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.
*/

/* License note: While this "glue" code to the nDPI library is GPLv2,
* nDPI is itself LGPLv3 which is known to be incompatible with the
* GPLv2. */

#include "output-eve.h"
#include "rust-bindings.h"
#include "suricata-common.h"
#include "suricata-plugin.h"
#include "util-debug.h"

#include "thread-callbacks.h"
#include "thread-storage.h"

#include "flow-callbacks.h"
#include "flow-storage.h"

#include "rust.h"

#include "ndpi_api.h"

static ThreadStorageId thread_storage_id = { .id = -1 };
static FlowStorageId flow_storage_id = { .id = -1 };

struct NdpiThreadContext {
struct ndpi_detection_module_struct *ndpi;
};

struct NdpiFlowContext {
struct ndpi_flow_struct *ndpi;
ndpi_protocol detect_l7_protocol;
uint8_t detection_completed;
};

static void ThreadStorageFree(void *ptr)
{
SCLogNotice("Free'ing nDPI thread storage");
struct NdpiThreadContext *context = ptr;
ndpi_exit_detection_module(context->ndpi);
SCFree(context);
}

static void FlowStorageFree(void *ptr)
{
struct NdpiFlowContext *ctx = ptr;
ndpi_flow_free(ctx->ndpi);
SCFree(ctx);
}

static void OnFlowInit(ThreadVars *tv, Flow *f, const Packet *p, void *_data)
{
struct NdpiFlowContext *flowctx = SCCalloc(1, sizeof(*flowctx));
if (flowctx == NULL) {
FatalError("Failed to allocate nDPI flow context");
}

flowctx->ndpi = ndpi_flow_malloc(SIZEOF_FLOW_STRUCT);
if (flowctx->ndpi == NULL) {
FatalError("Failed to allocate nDPI flow");
}

memset(flowctx->ndpi, 0, SIZEOF_FLOW_STRUCT);
flowctx->detection_completed = 0;
FlowSetStorageById(f, flow_storage_id, flowctx);
}

static void OnFlowUpdate(ThreadVars *tv, Flow *f, Packet *p, void *_data)
{
struct NdpiThreadContext *threadctx = ThreadGetStorageById(tv, thread_storage_id);
struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id);

if (threadctx->ndpi && flowctx->ndpi) {
SCLogNotice("Performing nDPI detection...");
}
}

static void OnFlowFinish(ThreadVars *tv, Flow *f, void *_data)
{
/* Nothing to do here, the storage API has taken care of cleaning
* up storage, just here for example purposes. */
SCLogNotice("Flow %p is now finished", f);
}

static void OnThreadInit(ThreadVars *tv, void *_data)
{
struct NdpiThreadContext *context = SCCalloc(1, sizeof(*context));
if (context == NULL) {
FatalError("Failed to allocate nDPI thread context");
}
context->ndpi = ndpi_init_detection_module(NULL);
if (context->ndpi == NULL) {
FatalError("Failed to initialize nDPI detection module");
}
NDPI_PROTOCOL_BITMASK protos;
NDPI_BITMASK_SET_ALL(protos);
ndpi_set_protocol_detection_bitmask2(context->ndpi, &protos);
ndpi_finalize_initialization(context->ndpi);
ThreadSetStorageById(tv, thread_storage_id, context);
}

static void EveCallback(ThreadVars *tv, const Packet *p, Flow *f, JsonBuilder *jb, void *data)
{
SCLogNotice("EveCallback: tv=%p, p=%p, f=%p", tv, p, f);
jb_open_object(jb, "ndpi");
jb_set_bool(jb, "packet", p == NULL ? false : true);
jb_set_bool(jb, "flow", f == NULL ? false : true);

if (f) {
struct NdpiFlowContext *flowctx = FlowGetStorageById(f, flow_storage_id);
if (flowctx->ndpi->risk) {
// ...
}
}

jb_close(jb);
}

static void NdpiInit(void)
{
SCLogNotice("Initializing nDPI plugin");

/* Register thread storage. */
thread_storage_id = ThreadStorageRegister("ndpi", sizeof(void *), NULL, ThreadStorageFree);
if (thread_storage_id.id < 0) {
FatalError("Failed to register nDPI thread storage");
}

/* Register flow storage. */
flow_storage_id = FlowStorageRegister("ndpi", sizeof(void *), NULL, FlowStorageFree);
if (flow_storage_id.id < 0) {
FatalError("Failed to register nDPI flow storage");
}

/* Register flow lifecycle callbacks. */
SCFlowRegisterInitCallback(OnFlowInit, NULL);
SCFlowRegisterUpdateCallback(OnFlowUpdate, NULL);

/* Not needed for nDPI, but exists for completeness. */
SCFlowRegisterFinishCallback(OnFlowFinish, NULL);

/* Register thread init callback. */
SCThreadRegisterInitCallback(OnThreadInit, NULL);

/* Register an EVE callback. */
EveRegisterCallback(EveCallback, NULL);
}

const SCPlugin PluginRegistration = {
.name = "ndpi-dummy",
.author = "FirstName LastName",
.license = "GPLv2",
.Init = NdpiInit,
};

const SCPlugin *SCPluginRegister()
{
return &PluginRegistration;
}
1 change: 1 addition & 0 deletions suricata.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ stats:
# Plugins -- Experimental -- specify the filename for each plugin shared object
plugins:
@pfring_comment@- @prefix@/lib/@PACKAGE_NAME@/pfring.so
@ndpi_comment@- @prefix@/lib/@PACKAGE_NAME@/ndpi.so
# - /path/to/plugin.so

# Configure the type of alert (and other) logging you would like.
Expand Down

0 comments on commit 6607ef3

Please sign in to comment.