mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
922 lines
29 KiB
C
922 lines
29 KiB
C
/* Copyright (C) 2007-2013 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.
|
|
*/
|
|
|
|
/** \file
|
|
*
|
|
* \author Victor Julien <victor@inliniac.net>
|
|
*
|
|
* Pre-cooked threading runmodes.
|
|
*/
|
|
|
|
#include "suricata-common.h"
|
|
#include "detect.h"
|
|
#include "detect-engine.h"
|
|
#include "detect-engine-mpm.h"
|
|
#include "app-layer-parser.h"
|
|
#include "tm-threads.h"
|
|
#include "util-debug.h"
|
|
#include "util-time.h"
|
|
#include "util-cpu.h"
|
|
#include "util-byte.h"
|
|
#include "util-affinity.h"
|
|
#include "conf.h"
|
|
#include "queue.h"
|
|
#include "runmodes.h"
|
|
#include "util-unittest.h"
|
|
#include "util-misc.h"
|
|
|
|
#include "output.h"
|
|
|
|
#include "alert-fastlog.h"
|
|
#include "alert-prelude.h"
|
|
#include "alert-unified2-alert.h"
|
|
#include "alert-debuglog.h"
|
|
|
|
#include "log-httplog.h"
|
|
|
|
#include "source-pfring.h"
|
|
|
|
#include "tmqh-flow.h"
|
|
#include "flow-manager.h"
|
|
#include "flow-bypass.h"
|
|
#include "counters.h"
|
|
|
|
int debuglog_enabled = 0;
|
|
int threading_set_cpu_affinity = FALSE;
|
|
|
|
/* Runmode Global Thread Names */
|
|
const char *thread_name_autofp = "RX";
|
|
const char *thread_name_single = "W";
|
|
const char *thread_name_workers = "W";
|
|
const char *thread_name_verdict = "TX";
|
|
const char *thread_name_flow_mgr = "FM";
|
|
const char *thread_name_flow_rec = "FR";
|
|
const char *thread_name_flow_bypass = "FB";
|
|
const char *thread_name_unix_socket = "US";
|
|
const char *thread_name_detect_loader = "DL";
|
|
const char *thread_name_counter_stats = "CS";
|
|
const char *thread_name_counter_wakeup = "CW";
|
|
|
|
/**
|
|
* \brief Holds description for a runmode.
|
|
*/
|
|
typedef struct RunMode_ {
|
|
/* the runmode type */
|
|
enum RunModes runmode;
|
|
const char *name;
|
|
const char *description;
|
|
/* runmode function */
|
|
int (*RunModeFunc)(void);
|
|
} RunMode;
|
|
|
|
typedef struct RunModes_ {
|
|
int cnt;
|
|
RunMode *runmodes;
|
|
} RunModes;
|
|
|
|
static RunModes runmodes[RUNMODE_USER_MAX];
|
|
|
|
static char *active_runmode;
|
|
|
|
/* free list for our outputs */
|
|
typedef struct OutputFreeList_ {
|
|
OutputModule *output_module;
|
|
OutputCtx *output_ctx;
|
|
|
|
TAILQ_ENTRY(OutputFreeList_) entries;
|
|
} OutputFreeList;
|
|
static TAILQ_HEAD(, OutputFreeList_) output_free_list =
|
|
TAILQ_HEAD_INITIALIZER(output_free_list);
|
|
|
|
/**
|
|
* \internal
|
|
* \brief Translate a runmode mode to a printale string.
|
|
*
|
|
* \param runmode Runmode to be converted into a printable string.
|
|
*
|
|
* \retval string Printable string.
|
|
*/
|
|
static const char *RunModeTranslateModeToName(int runmode)
|
|
{
|
|
switch (runmode) {
|
|
case RUNMODE_PCAP_DEV:
|
|
return "PCAP_DEV";
|
|
case RUNMODE_PCAP_FILE:
|
|
return "PCAP_FILE";
|
|
case RUNMODE_PFRING:
|
|
#ifdef HAVE_PFRING
|
|
return "PFRING";
|
|
#else
|
|
return "PFRING(DISABLED)";
|
|
#endif
|
|
case RUNMODE_NFQ:
|
|
return "NFQ";
|
|
case RUNMODE_NFLOG:
|
|
return "NFLOG";
|
|
case RUNMODE_IPFW:
|
|
return "IPFW";
|
|
case RUNMODE_ERF_FILE:
|
|
return "ERF_FILE";
|
|
case RUNMODE_DAG:
|
|
return "ERF_DAG";
|
|
case RUNMODE_NAPATECH:
|
|
return "NAPATECH";
|
|
case RUNMODE_UNITTEST:
|
|
return "UNITTEST";
|
|
case RUNMODE_AFP_DEV:
|
|
return "AF_PACKET_DEV";
|
|
case RUNMODE_NETMAP:
|
|
#ifdef HAVE_NETMAP
|
|
return "NETMAP";
|
|
#else
|
|
return "NETMAP(DISABLED)";
|
|
#endif
|
|
case RUNMODE_UNIX_SOCKET:
|
|
return "UNIX_SOCKET";
|
|
case RUNMODE_WINDIVERT:
|
|
#ifdef WINDIVERT
|
|
return "WINDIVERT";
|
|
#else
|
|
return "WINDIVERT(DISABLED)";
|
|
#endif
|
|
default:
|
|
FatalError(SC_ERR_UNKNOWN_RUN_MODE, "Unknown runtime mode. Aborting");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \internal
|
|
* \brief Dispatcher function for runmodes. Calls the required runmode function
|
|
* based on runmode + runmode_custom_id.
|
|
*
|
|
* \param runmode The runmode type.
|
|
* \param runmode_customd_id The runmode custom id.
|
|
*/
|
|
static RunMode *RunModeGetCustomMode(enum RunModes runmode, const char *custom_mode)
|
|
{
|
|
if (runmode < RUNMODE_USER_MAX) {
|
|
for (int i = 0; i < runmodes[runmode].cnt; i++) {
|
|
if (strcmp(runmodes[runmode].runmodes[i].name, custom_mode) == 0)
|
|
return &runmodes[runmode].runmodes[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return the running mode
|
|
*
|
|
* The returned string must not be freed.
|
|
*
|
|
* \return a string containing the current running mode
|
|
*/
|
|
char *RunmodeGetActive(void)
|
|
{
|
|
return active_runmode;
|
|
}
|
|
|
|
/**
|
|
* Return the running mode
|
|
*
|
|
* The returned string must not be freed.
|
|
*
|
|
* \return a string containing the current running mode
|
|
*/
|
|
const char *RunModeGetMainMode(void)
|
|
{
|
|
int mainmode = RunmodeGetCurrent();
|
|
|
|
return RunModeTranslateModeToName(mainmode);
|
|
}
|
|
|
|
/**
|
|
* \brief Register all runmodes in the engine.
|
|
*/
|
|
void RunModeRegisterRunModes(void)
|
|
{
|
|
memset(runmodes, 0, sizeof(runmodes));
|
|
|
|
RunModeIdsPcapRegister();
|
|
RunModeFilePcapRegister();
|
|
RunModeIdsPfringRegister();
|
|
RunModeIpsNFQRegister();
|
|
RunModeIpsIPFWRegister();
|
|
RunModeErfFileRegister();
|
|
RunModeErfDagRegister();
|
|
RunModeNapatechRegister();
|
|
RunModeIdsAFPRegister();
|
|
RunModeIdsNetmapRegister();
|
|
RunModeIdsNflogRegister();
|
|
RunModeUnixSocketRegister();
|
|
RunModeIpsWinDivertRegister();
|
|
#ifdef UNITTESTS
|
|
UtRunModeRegister();
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* \brief Lists all registered runmodes.
|
|
*/
|
|
void RunModeListRunmodes(void)
|
|
{
|
|
printf("------------------------------------- Runmodes -------------------"
|
|
"-----------------------\n");
|
|
|
|
printf("| %-17s | %-17s | %-10s \n",
|
|
"RunMode Type", "Custom Mode ", "Description");
|
|
printf("|-----------------------------------------------------------------"
|
|
"-----------------------\n");
|
|
int i = RUNMODE_UNKNOWN + 1;
|
|
int j = 0;
|
|
for ( ; i < RUNMODE_USER_MAX; i++) {
|
|
int mode_displayed = 0;
|
|
for (j = 0; j < runmodes[i].cnt; j++) {
|
|
if (mode_displayed == 1) {
|
|
printf("| ----------------------------------------------"
|
|
"-----------------------\n");
|
|
RunMode *runmode = &runmodes[i].runmodes[j];
|
|
printf("| %-17s | %-17s | %-27s \n",
|
|
"",
|
|
runmode->name,
|
|
runmode->description);
|
|
} else {
|
|
RunMode *runmode = &runmodes[i].runmodes[j];
|
|
printf("| %-17s | %-17s | %-27s \n",
|
|
RunModeTranslateModeToName(runmode->runmode),
|
|
runmode->name,
|
|
runmode->description);
|
|
}
|
|
if (mode_displayed == 0)
|
|
mode_displayed = 1;
|
|
}
|
|
if (mode_displayed == 1) {
|
|
printf("|-----------------------------------------------------------------"
|
|
"-----------------------\n");
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
void RunModeDispatch(int runmode, const char *custom_mode)
|
|
{
|
|
char *local_custom_mode = NULL;
|
|
|
|
if (custom_mode == NULL) {
|
|
const char *val = NULL;
|
|
if (ConfGet("runmode", &val) != 1) {
|
|
custom_mode = NULL;
|
|
} else {
|
|
custom_mode = val;
|
|
}
|
|
}
|
|
|
|
if (custom_mode == NULL || strcmp(custom_mode, "auto") == 0) {
|
|
switch (runmode) {
|
|
case RUNMODE_PCAP_DEV:
|
|
custom_mode = RunModeIdsGetDefaultMode();
|
|
break;
|
|
case RUNMODE_PCAP_FILE:
|
|
custom_mode = RunModeFilePcapGetDefaultMode();
|
|
break;
|
|
#ifdef HAVE_PFRING
|
|
case RUNMODE_PFRING:
|
|
custom_mode = RunModeIdsPfringGetDefaultMode();
|
|
break;
|
|
#endif
|
|
case RUNMODE_NFQ:
|
|
custom_mode = RunModeIpsNFQGetDefaultMode();
|
|
break;
|
|
case RUNMODE_IPFW:
|
|
custom_mode = RunModeIpsIPFWGetDefaultMode();
|
|
break;
|
|
case RUNMODE_ERF_FILE:
|
|
custom_mode = RunModeErfFileGetDefaultMode();
|
|
break;
|
|
case RUNMODE_DAG:
|
|
custom_mode = RunModeErfDagGetDefaultMode();
|
|
break;
|
|
case RUNMODE_NAPATECH:
|
|
custom_mode = RunModeNapatechGetDefaultMode();
|
|
break;
|
|
case RUNMODE_AFP_DEV:
|
|
custom_mode = RunModeAFPGetDefaultMode();
|
|
break;
|
|
case RUNMODE_NETMAP:
|
|
custom_mode = RunModeNetmapGetDefaultMode();
|
|
break;
|
|
case RUNMODE_UNIX_SOCKET:
|
|
custom_mode = RunModeUnixSocketGetDefaultMode();
|
|
break;
|
|
case RUNMODE_NFLOG:
|
|
custom_mode = RunModeIdsNflogGetDefaultMode();
|
|
break;
|
|
#ifdef WINDIVERT
|
|
case RUNMODE_WINDIVERT:
|
|
custom_mode = RunModeIpsWinDivertGetDefaultMode();
|
|
break;
|
|
#endif
|
|
default:
|
|
SCLogError(SC_ERR_UNKNOWN_RUN_MODE, "Unknown runtime mode. Aborting");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
} else { /* if (custom_mode == NULL) */
|
|
/* Add compability with old 'worker' name */
|
|
if (!strcmp("worker", custom_mode)) {
|
|
SCLogWarning(SC_ERR_RUNMODE, "'worker' mode have been renamed "
|
|
"to 'workers', please modify your setup.");
|
|
local_custom_mode = SCStrdup("workers");
|
|
if (unlikely(local_custom_mode == NULL)) {
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup custom mode");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
custom_mode = local_custom_mode;
|
|
}
|
|
}
|
|
|
|
RunMode *mode = RunModeGetCustomMode(runmode, custom_mode);
|
|
if (mode == NULL) {
|
|
SCLogError(SC_ERR_RUNMODE, "The custom type \"%s\" doesn't exist "
|
|
"for this runmode type \"%s\". Please use --list-runmodes to "
|
|
"see available custom types for this runmode",
|
|
custom_mode, RunModeTranslateModeToName(runmode));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/* Export the custom mode */
|
|
if (active_runmode) {
|
|
SCFree(active_runmode);
|
|
}
|
|
active_runmode = SCStrdup(custom_mode);
|
|
if (unlikely(active_runmode == NULL)) {
|
|
SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup active mode");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (strcasecmp(active_runmode, "autofp") == 0) {
|
|
TmqhFlowPrintAutofpHandler();
|
|
}
|
|
|
|
mode->RunModeFunc();
|
|
|
|
if (local_custom_mode != NULL)
|
|
SCFree(local_custom_mode);
|
|
|
|
/* Check if the alloted queues have at least 1 reader and writer */
|
|
TmValidateQueueState();
|
|
|
|
if (runmode != RUNMODE_UNIX_SOCKET) {
|
|
/* spawn management threads */
|
|
FlowManagerThreadSpawn();
|
|
FlowRecyclerThreadSpawn();
|
|
if (RunModeNeedsBypassManager()) {
|
|
BypassedFlowManagerThreadSpawn();
|
|
}
|
|
StatsSpawnThreads();
|
|
}
|
|
}
|
|
|
|
static int g_runmode_needs_bypass = 0;
|
|
|
|
void RunModeEnablesBypassManager(void)
|
|
{
|
|
g_runmode_needs_bypass = 1;
|
|
}
|
|
|
|
int RunModeNeedsBypassManager(void)
|
|
{
|
|
return g_runmode_needs_bypass;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* \brief Registers a new runmode.
|
|
*
|
|
* \param runmode Runmode type.
|
|
* \param name Custom mode for this specific runmode type. Within each
|
|
* runmode type, each custom name is a primary key.
|
|
* \param description Description for this runmode.
|
|
* \param RunModeFunc The function to be run for this runmode.
|
|
*/
|
|
void RunModeRegisterNewRunMode(enum RunModes runmode,
|
|
const char *name,
|
|
const char *description,
|
|
int (*RunModeFunc)(void))
|
|
{
|
|
if (RunModeGetCustomMode(runmode, name) != NULL) {
|
|
FatalError(SC_ERR_RUNMODE, "runmode '%s' has already "
|
|
"been registered. Please use an unique name.", name);
|
|
}
|
|
|
|
void *ptmp = SCRealloc(runmodes[runmode].runmodes,
|
|
(runmodes[runmode].cnt + 1) * sizeof(RunMode));
|
|
if (ptmp == NULL) {
|
|
SCFree(runmodes[runmode].runmodes);
|
|
runmodes[runmode].runmodes = NULL;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
runmodes[runmode].runmodes = ptmp;
|
|
|
|
RunMode *mode = &runmodes[runmode].runmodes[runmodes[runmode].cnt];
|
|
runmodes[runmode].cnt++;
|
|
memset(mode, 0x00, sizeof(*mode));
|
|
|
|
mode->runmode = runmode;
|
|
mode->name = SCStrdup(name);
|
|
if (unlikely(mode->name == NULL)) {
|
|
FatalError(SC_ERR_MEM_ALLOC, "Failed to allocate string");
|
|
}
|
|
mode->description = SCStrdup(description);
|
|
if (unlikely(mode->description == NULL)) {
|
|
FatalError(SC_ERR_MEM_ALLOC, "Failed to allocate string");
|
|
}
|
|
mode->RunModeFunc = RunModeFunc;
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Setup the outputs for this run mode.
|
|
*
|
|
* \param tv The ThreadVars for the thread the outputs will be
|
|
* appended to.
|
|
*/
|
|
static void RunOutputFreeList(void)
|
|
{
|
|
OutputFreeList *output;
|
|
while ((output = TAILQ_FIRST(&output_free_list))) {
|
|
SCLogDebug("output %s %p %p", output->output_module->name, output,
|
|
output->output_ctx);
|
|
|
|
if (output->output_ctx != NULL && output->output_ctx->DeInit != NULL)
|
|
output->output_ctx->DeInit(output->output_ctx);
|
|
|
|
TAILQ_REMOVE(&output_free_list, output, entries);
|
|
SCFree(output);
|
|
}
|
|
}
|
|
|
|
static int file_logger_count = 0;
|
|
static int filedata_logger_count = 0;
|
|
static LoggerId logger_bits[ALPROTO_MAX];
|
|
|
|
int RunModeOutputFileEnabled(void)
|
|
{
|
|
return file_logger_count > 0;
|
|
}
|
|
|
|
int RunModeOutputFiledataEnabled(void)
|
|
{
|
|
return filedata_logger_count > 0;
|
|
}
|
|
|
|
bool IsRunModeSystem(enum RunModes run_mode_to_check)
|
|
{
|
|
switch (run_mode_to_check) {
|
|
case RUNMODE_PCAP_FILE:
|
|
case RUNMODE_ERF_FILE:
|
|
case RUNMODE_ENGINE_ANALYSIS:
|
|
return false;
|
|
break;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool IsRunModeOffline(enum RunModes run_mode_to_check)
|
|
{
|
|
switch(run_mode_to_check) {
|
|
case RUNMODE_CONF_TEST:
|
|
case RUNMODE_PCAP_FILE:
|
|
case RUNMODE_ERF_FILE:
|
|
case RUNMODE_ENGINE_ANALYSIS:
|
|
case RUNMODE_UNIX_SOCKET:
|
|
return true;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cleanup the run mode.
|
|
*/
|
|
void RunModeShutDown(void)
|
|
{
|
|
RunOutputFreeList();
|
|
|
|
OutputPacketShutdown();
|
|
OutputTxShutdown();
|
|
OutputFileShutdown();
|
|
OutputFiledataShutdown();
|
|
OutputStreamingShutdown();
|
|
OutputStatsShutdown();
|
|
OutputFlowShutdown();
|
|
|
|
OutputClearActiveLoggers();
|
|
|
|
/* Reset logger counts. */
|
|
file_logger_count = 0;
|
|
filedata_logger_count = 0;
|
|
}
|
|
|
|
/** \internal
|
|
* \brief add Sub RunModeOutput to list for Submodule so we can free
|
|
* the output ctx at shutdown and unix socket reload */
|
|
static void AddOutputToFreeList(OutputModule *module, OutputCtx *output_ctx)
|
|
{
|
|
OutputFreeList *fl_output = SCCalloc(1, sizeof(OutputFreeList));
|
|
if (unlikely(fl_output == NULL))
|
|
return;
|
|
fl_output->output_module = module;
|
|
fl_output->output_ctx = output_ctx;
|
|
TAILQ_INSERT_TAIL(&output_free_list, fl_output, entries);
|
|
}
|
|
|
|
/** \brief Turn output into thread module */
|
|
static void SetupOutput(const char *name, OutputModule *module, OutputCtx *output_ctx)
|
|
{
|
|
/* flow logger doesn't run in the packet path */
|
|
if (module->FlowLogFunc) {
|
|
OutputRegisterFlowLogger(module->name, module->FlowLogFunc,
|
|
output_ctx, module->ThreadInit, module->ThreadDeinit,
|
|
module->ThreadExitPrintStats);
|
|
return;
|
|
}
|
|
/* stats logger doesn't run in the packet path */
|
|
if (module->StatsLogFunc) {
|
|
OutputRegisterStatsLogger(module->name, module->StatsLogFunc,
|
|
output_ctx,module->ThreadInit, module->ThreadDeinit,
|
|
module->ThreadExitPrintStats);
|
|
return;
|
|
}
|
|
|
|
if (module->logger_id == LOGGER_ALERT_DEBUG) {
|
|
debuglog_enabled = 1;
|
|
}
|
|
|
|
if (module->PacketLogFunc) {
|
|
SCLogDebug("%s is a packet logger", module->name);
|
|
OutputRegisterPacketLogger(module->logger_id, module->name,
|
|
module->PacketLogFunc, module->PacketConditionFunc, output_ctx,
|
|
module->ThreadInit, module->ThreadDeinit,
|
|
module->ThreadExitPrintStats);
|
|
} else if (module->TxLogFunc) {
|
|
SCLogDebug("%s is a tx logger", module->name);
|
|
OutputRegisterTxLogger(module->logger_id, module->name, module->alproto,
|
|
module->TxLogFunc, output_ctx, module->tc_log_progress,
|
|
module->ts_log_progress, module->TxLogCondition,
|
|
module->ThreadInit, module->ThreadDeinit,
|
|
module->ThreadExitPrintStats);
|
|
/* Not used with wild card loggers */
|
|
if (module->alproto != ALPROTO_UNKNOWN) {
|
|
logger_bits[module->alproto] |= (1<<module->logger_id);
|
|
}
|
|
} else if (module->FiledataLogFunc) {
|
|
SCLogDebug("%s is a filedata logger", module->name);
|
|
OutputRegisterFiledataLogger(module->logger_id, module->name,
|
|
module->FiledataLogFunc, output_ctx, module->ThreadInit,
|
|
module->ThreadDeinit, module->ThreadExitPrintStats);
|
|
filedata_logger_count++;
|
|
} else if (module->FileLogFunc) {
|
|
SCLogDebug("%s is a file logger", module->name);
|
|
OutputRegisterFileLogger(module->logger_id, module->name,
|
|
module->FileLogFunc, output_ctx, module->ThreadInit,
|
|
module->ThreadDeinit, module->ThreadExitPrintStats);
|
|
file_logger_count++;
|
|
} else if (module->StreamingLogFunc) {
|
|
SCLogDebug("%s is a streaming logger", module->name);
|
|
OutputRegisterStreamingLogger(module->logger_id, module->name,
|
|
module->StreamingLogFunc, output_ctx, module->stream_type,
|
|
module->ThreadInit, module->ThreadDeinit,
|
|
module->ThreadExitPrintStats);
|
|
} else {
|
|
SCLogError(SC_ERR_INVALID_ARGUMENT, "Unknown logger type: name=%s",
|
|
module->name);
|
|
}
|
|
}
|
|
|
|
static void RunModeInitializeEveOutput(ConfNode *conf, OutputCtx *parent_ctx)
|
|
{
|
|
ConfNode *types = ConfNodeLookupChild(conf, "types");
|
|
SCLogDebug("types %p", types);
|
|
if (types == NULL) {
|
|
return;
|
|
}
|
|
|
|
ConfNode *type = NULL;
|
|
TAILQ_FOREACH(type, &types->head, next) {
|
|
SCLogConfig("enabling 'eve-log' module '%s'", type->val);
|
|
|
|
int sub_count = 0;
|
|
char subname[256];
|
|
snprintf(subname, sizeof(subname), "eve-log.%s", type->val);
|
|
|
|
ConfNode *sub_output_config = ConfNodeLookupChild(type, type->val);
|
|
if (sub_output_config != NULL) {
|
|
const char *enabled = ConfNodeLookupChildValue(
|
|
sub_output_config, "enabled");
|
|
if (enabled != NULL && !ConfValIsTrue(enabled)) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Now setup all registers logger of this name. */
|
|
OutputModule *sub_module;
|
|
TAILQ_FOREACH(sub_module, &output_modules, entries) {
|
|
if (strcmp(subname, sub_module->conf_name) == 0) {
|
|
sub_count++;
|
|
|
|
if (sub_module->parent_name == NULL ||
|
|
strcmp(sub_module->parent_name, "eve-log") != 0) {
|
|
FatalError(SC_ERR_INVALID_ARGUMENT,
|
|
"bad parent for %s", subname);
|
|
}
|
|
if (sub_module->InitSubFunc == NULL) {
|
|
FatalError(SC_ERR_INVALID_ARGUMENT,
|
|
"bad sub-module for %s", subname);
|
|
}
|
|
|
|
/* pass on parent output_ctx */
|
|
OutputInitResult result =
|
|
sub_module->InitSubFunc(sub_output_config, parent_ctx);
|
|
if (!result.ok || result.ctx == NULL) {
|
|
continue;
|
|
}
|
|
|
|
AddOutputToFreeList(sub_module, result.ctx);
|
|
SetupOutput(sub_module->name, sub_module,
|
|
result.ctx);
|
|
}
|
|
}
|
|
|
|
/* Error is no registered loggers with this name
|
|
* were found .*/
|
|
if (!sub_count) {
|
|
FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT,
|
|
"No output module named %s", subname);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void RunModeInitializeLuaOutput(ConfNode *conf, OutputCtx *parent_ctx)
|
|
{
|
|
OutputModule *lua_module = OutputGetModuleByConfName("lua");
|
|
BUG_ON(lua_module == NULL);
|
|
|
|
ConfNode *scripts = ConfNodeLookupChild(conf, "scripts");
|
|
BUG_ON(scripts == NULL); //TODO
|
|
|
|
OutputModule *m;
|
|
TAILQ_FOREACH(m, &parent_ctx->submodules, entries) {
|
|
SCLogDebug("m %p %s:%s", m, m->name, m->conf_name);
|
|
|
|
ConfNode *script = NULL;
|
|
TAILQ_FOREACH(script, &scripts->head, next) {
|
|
SCLogDebug("script %s", script->val);
|
|
if (strcmp(script->val, m->conf_name) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
BUG_ON(script == NULL);
|
|
|
|
/* pass on parent output_ctx */
|
|
OutputInitResult result = m->InitSubFunc(script, parent_ctx);
|
|
if (!result.ok || result.ctx == NULL) {
|
|
continue;
|
|
}
|
|
|
|
AddOutputToFreeList(m, result.ctx);
|
|
SetupOutput(m->name, m, result.ctx);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize the output modules.
|
|
*/
|
|
void RunModeInitializeOutputs(void)
|
|
{
|
|
ConfNode *outputs = ConfGetNode("outputs");
|
|
if (outputs == NULL) {
|
|
/* No "outputs" section in the configuration. */
|
|
return;
|
|
}
|
|
|
|
ConfNode *output, *output_config;
|
|
const char *enabled;
|
|
char tls_log_enabled = 0;
|
|
char tls_store_present = 0;
|
|
|
|
memset(&logger_bits, 0, sizeof(logger_bits));
|
|
|
|
TAILQ_FOREACH(output, &outputs->head, next) {
|
|
|
|
output_config = ConfNodeLookupChild(output, output->val);
|
|
if (output_config == NULL) {
|
|
/* Shouldn't happen. */
|
|
FatalError(SC_ERR_INVALID_ARGUMENT,
|
|
"Failed to lookup configuration child node: %s", output->val);
|
|
}
|
|
|
|
if (strcmp(output->val, "tls-store") == 0) {
|
|
tls_store_present = 1;
|
|
}
|
|
|
|
enabled = ConfNodeLookupChildValue(output_config, "enabled");
|
|
if (enabled == NULL || !ConfValIsTrue(enabled)) {
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(output->val, "file-log") == 0) {
|
|
SCLogWarning(SC_ERR_NOT_SUPPORTED,
|
|
"file-log is no longer supported,"
|
|
" use eve.files instead "
|
|
"(see https://redmine.openinfosecfoundation.org/issues/2376"
|
|
" for an explanation)");
|
|
continue;
|
|
} else if (strncmp(output->val, "unified-", sizeof("unified-") - 1) == 0) {
|
|
SCLogWarning(SC_ERR_NOT_SUPPORTED,
|
|
"Unified1 is no longer supported,"
|
|
" use Unified2 instead "
|
|
"(see https://redmine.openinfosecfoundation.org/issues/353"
|
|
" for an explanation)");
|
|
continue;
|
|
} else if (strcmp(output->val, "alert-prelude") == 0) {
|
|
#ifndef PRELUDE
|
|
SCLogWarning(SC_ERR_NOT_SUPPORTED,
|
|
"Prelude support not compiled in. Reconfigure/"
|
|
"recompile with --enable-prelude to add Prelude "
|
|
"support.");
|
|
continue;
|
|
#endif
|
|
} else if (strcmp(output->val, "lua") == 0) {
|
|
#ifndef HAVE_LUA
|
|
SCLogWarning(SC_ERR_NOT_SUPPORTED,
|
|
"lua support not compiled in. Reconfigure/"
|
|
"recompile with lua(jit) and its development "
|
|
"files installed to add lua support.");
|
|
continue;
|
|
#endif
|
|
} else if (strcmp(output->val, "dns-log") == 0) {
|
|
SCLogWarning(SC_ERR_NOT_SUPPORTED,
|
|
"dns-log is not longer available as of Suricata 5.0");
|
|
continue;
|
|
} else if (strcmp(output->val, "tls-log") == 0) {
|
|
tls_log_enabled = 1;
|
|
}
|
|
|
|
OutputModule *module;
|
|
int count = 0;
|
|
TAILQ_FOREACH(module, &output_modules, entries) {
|
|
if (strcmp(module->conf_name, output->val) != 0) {
|
|
continue;
|
|
}
|
|
|
|
count++;
|
|
|
|
OutputCtx *output_ctx = NULL;
|
|
if (module->InitFunc != NULL) {
|
|
OutputInitResult r = module->InitFunc(output_config);
|
|
if (!r.ok) {
|
|
FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT,
|
|
"output module \"%s\": setup failed", output->val);
|
|
continue;
|
|
} else if (r.ctx == NULL) {
|
|
continue;
|
|
}
|
|
output_ctx = r.ctx;
|
|
} else if (module->InitSubFunc != NULL) {
|
|
SCLogInfo("skipping submodule");
|
|
continue;
|
|
}
|
|
|
|
// TODO if module == parent, find it's children
|
|
if (strcmp(output->val, "eve-log") == 0) {
|
|
RunModeInitializeEveOutput(output_config, output_ctx);
|
|
|
|
/* add 'eve-log' to free list as it's the owner of the
|
|
* main output ctx from which the sub-modules share the
|
|
* LogFileCtx */
|
|
AddOutputToFreeList(module, output_ctx);
|
|
} else if (strcmp(output->val, "lua") == 0) {
|
|
SCLogDebug("handle lua");
|
|
if (output_ctx == NULL)
|
|
continue;
|
|
RunModeInitializeLuaOutput(output_config, output_ctx);
|
|
AddOutputToFreeList(module, output_ctx);
|
|
} else {
|
|
AddOutputToFreeList(module, output_ctx);
|
|
SetupOutput(module->name, module, output_ctx);
|
|
}
|
|
}
|
|
if (count == 0) {
|
|
FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT,
|
|
"No output module named %s", output->val);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Backward compatibility code */
|
|
if (!tls_store_present && tls_log_enabled) {
|
|
/* old YAML with no "tls-store" in outputs. "tls-log" value needs
|
|
* to be started using 'tls-log' config as own config */
|
|
SCLogWarning(SC_ERR_CONF_YAML_ERROR,
|
|
"Please use 'tls-store' in YAML to configure TLS storage");
|
|
|
|
TAILQ_FOREACH(output, &outputs->head, next) {
|
|
output_config = ConfNodeLookupChild(output, output->val);
|
|
|
|
if (strcmp(output->val, "tls-log") == 0) {
|
|
|
|
OutputModule *module = OutputGetModuleByConfName("tls-store");
|
|
if (module == NULL) {
|
|
SCLogWarning(SC_ERR_INVALID_ARGUMENT,
|
|
"No output module named %s, ignoring", "tls-store");
|
|
continue;
|
|
}
|
|
|
|
OutputCtx *output_ctx = NULL;
|
|
if (module->InitFunc != NULL) {
|
|
OutputInitResult r = module->InitFunc(output_config);
|
|
if (!r.ok) {
|
|
FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT,
|
|
"output module setup failed");
|
|
continue;
|
|
} else if (r.ctx == NULL) {
|
|
continue;
|
|
}
|
|
output_ctx = r.ctx;
|
|
}
|
|
|
|
AddOutputToFreeList(module, output_ctx);
|
|
SetupOutput(module->name, module, output_ctx);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* register the logger bits to the app-layer */
|
|
int a;
|
|
for (a = 0; a < ALPROTO_MAX; a++) {
|
|
if (logger_bits[a] == 0)
|
|
continue;
|
|
|
|
const int tcp = AppLayerParserProtocolHasLogger(IPPROTO_TCP, a);
|
|
const int udp = AppLayerParserProtocolHasLogger(IPPROTO_UDP, a);
|
|
|
|
SCLogDebug("logger for %s: %s %s", AppProtoToString(a),
|
|
tcp ? "true" : "false", udp ? "true" : "false");
|
|
|
|
SCLogDebug("logger bits for %s: %08x", AppProtoToString(a), logger_bits[a]);
|
|
if (tcp)
|
|
AppLayerParserRegisterLoggerBits(IPPROTO_TCP, a, logger_bits[a]);
|
|
if (udp)
|
|
AppLayerParserRegisterLoggerBits(IPPROTO_UDP, a, logger_bits[a]);
|
|
|
|
}
|
|
OutputSetupActiveLoggers();
|
|
}
|
|
|
|
float threading_detect_ratio = 1;
|
|
|
|
/**
|
|
* Initialize multithreading settings.
|
|
*/
|
|
void RunModeInitialize(void)
|
|
{
|
|
threading_set_cpu_affinity = FALSE;
|
|
if ((ConfGetBool("threading.set-cpu-affinity", &threading_set_cpu_affinity)) == 0) {
|
|
threading_set_cpu_affinity = FALSE;
|
|
}
|
|
/* try to get custom cpu mask value if needed */
|
|
if (threading_set_cpu_affinity == TRUE) {
|
|
AffinitySetupLoadFromConfig();
|
|
}
|
|
if ((ConfGetFloat("threading.detect-thread-ratio", &threading_detect_ratio)) != 1) {
|
|
if (ConfGetNode("threading.detect-thread-ratio") != NULL)
|
|
WarnInvalidConfEntry("threading.detect-thread-ratio", "%s", "1");
|
|
threading_detect_ratio = 1;
|
|
}
|
|
|
|
SCLogDebug("threading.detect-thread-ratio %f", threading_detect_ratio);
|
|
}
|