output: delayed initialization for custom loggers

When a plugin is first initialized, it is too early to register
transaction loggers. Instead, a plugin can register a callback to be
called when Suricata is ready for outputs like transaction loggers to
be registered.

Likewise for library users, there is a window in SuricataInit where
transaction loggers can be registered that library users don't have
access to. So a lifecycle callback useful here as well.

Ticket #7236
pull/13397/head
Jason Ish 6 months ago committed by Victor Julien
parent 656b24004e
commit 25e32f4f7a

@ -5,7 +5,7 @@
# 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
CPPFLAGS += -I@top_srcdir@/src -I@top_srcdir@/rust/gen -DHAVE_CONFIG_H
# Currently the Suricata logging system requires this to be even for
# plugins.
@ -26,7 +26,7 @@ distclean: clean
# 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
cd @top_builddir@ && ./config.status examples/plugins/c-custom-loggers/Makefile
# Dummy rules to satisfy make dist.
dist distdir:

@ -22,6 +22,7 @@
#include "output-flow.h"
#include "output-tx.h"
#include "util-print.h"
#include "output.h"
static int CustomPacketLogger(ThreadVars *tv, void *thread_data, const Packet *p)
{
@ -79,14 +80,12 @@ static int CustomFlowLogger(ThreadVars *tv, void *thread_data, Flow *f)
return 0;
}
#if 0
static int CustomDnsLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state,
void *tx, uint64_t tx_id)
{
SCLogNotice("We have a DNS transaction");
return 0;
}
#endif
static TmEcode ThreadInit(ThreadVars *tv, const void *initdata, void **data)
{
@ -100,21 +99,20 @@ static TmEcode ThreadDeinit(ThreadVars *tv, void *data)
return TM_ECODE_OK;
}
static void Init(void)
static void OnLoggingReady(void *arg)
{
SCOutputRegisterPacketLogger(LOGGER_USER, "custom-packet-logger", CustomPacketLogger,
CustomPacketLoggerCondition, NULL, ThreadInit, ThreadDeinit);
SCOutputRegisterFlowLogger(
"custom-flow-logger", CustomFlowLogger, NULL, ThreadInit, ThreadDeinit);
SCOutputRegisterTxLogger(LOGGER_USER, "custom-dns-logger", ALPROTO_DNS, CustomDnsLogger, NULL,
-1, -1, NULL, ThreadInit, ThreadDeinit);
}
/* Register a custom DNS transaction logger.
*
* Currently disabled due to https://redmine.openinfosecfoundation.org/issues/7236.
*/
#if 0
OutputRegisterTxLogger(LOGGER_USER, "custom-dns-logger", ALPROTO_DNS, CustomDnsLogger, NULL, -1,
-1, NULL, ThreadInit, ThreadDeinit);
#endif
static void Init(void)
{
// Register our callback for when logging is ready.
SCRegisterOnLoggingReady(OnLoggingReady, NULL);
}
const SCPlugin PluginRegistration = {

@ -132,6 +132,28 @@ static SCMutex output_file_rotation_mutex = SCMUTEX_INITIALIZER;
TAILQ_HEAD(, OutputFileRolloverFlag_) output_file_rotation_flags =
TAILQ_HEAD_INITIALIZER(output_file_rotation_flags);
/**
* Callback function to be called when logging is ready.
*/
typedef void (*SCOnLoggingReadyCallback)(void *arg);
/**
* List entries for callbacks registered to be called when the logging system is
* ready. This is useful for both plugins and library users who need to register
* application transaction loggers after logging initialization is complete.
*/
typedef struct OnLoggingReadyCallbackNode_ {
SCOnLoggingReadyCallback callback;
void *arg;
TAILQ_ENTRY(OnLoggingReadyCallbackNode_) entries;
} OnLoggingReadyCallbackNode;
/**
* The list of callbacks to be called when logging is ready.
*/
static TAILQ_HEAD(, OnLoggingReadyCallbackNode_)
on_logging_ready_callbacks = TAILQ_HEAD_INITIALIZER(on_logging_ready_callbacks);
void OutputRegisterRootLoggers(void);
void OutputRegisterLoggers(void);
@ -720,6 +742,49 @@ void OutputNotifyFileRotation(void) {
SCMutexUnlock(&output_file_rotation_mutex);
}
/**
* \brief Register a callback to be called when logging is ready.
*
* This function registers a callback that will be invoked when the logging
* system has been fully initialized. This is useful for both plugins and
* library users who need to register application transaction loggers after
* logging initialization is complete.
*
* \param callback The callback function to be called
* \param arg An argument to be passed to the callback function
* \return 0 on success, -1 on failure
*/
int SCRegisterOnLoggingReady(SCOnLoggingReadyCallback callback, void *arg)
{
OnLoggingReadyCallbackNode *node = SCCalloc(1, sizeof(*node));
if (node == NULL) {
SCLogError("Failed to allocate memory for callback node");
return -1;
}
node->callback = callback;
node->arg = arg;
TAILQ_INSERT_TAIL(&on_logging_ready_callbacks, node, entries);
return 0;
}
/**
* \brief Invokes all registered logging ready callbacks.
*
* This function should be called after the logging system has been fully
* initialized to notify all registered callbacks that logging is ready.
*/
void SCOnLoggingReady(void)
{
OnLoggingReadyCallbackNode *node = NULL;
TAILQ_FOREACH (node, &on_logging_ready_callbacks, entries) {
if (node->callback) {
(*node->callback)(node->arg);
}
}
}
TmEcode OutputLoggerFlush(ThreadVars *tv, Packet *p, void *thread_data)
{
LoggerThreadStore *thread_store = (LoggerThreadStore *)thread_data;

@ -159,6 +159,10 @@ void OutputRegisterFileRotationFlag(int *flag);
void OutputUnregisterFileRotationFlag(int *flag);
void OutputNotifyFileRotation(void);
typedef void (*SCOnLoggingReadyCallback)(void *arg);
int SCRegisterOnLoggingReady(SCOnLoggingReadyCallback callback, void *arg);
void SCOnLoggingReady(void);
void OutputRegisterRootLogger(ThreadInitFunc ThreadInit, ThreadDeinitFunc ThreadDeinit,
OutputLogFunc LogFunc, OutputGetActiveCountFunc ActiveCntFunc);
void TmModuleLoggerRegister(void);

@ -2995,6 +2995,8 @@ void SuricataInit(void)
PreRunPostPrivsDropInit(suricata.run_mode);
SCOnLoggingReady();
LandlockSandboxing(&suricata);
PostConfLoadedDetectSetup(&suricata);

Loading…
Cancel
Save