diff options
Diffstat (limited to 'framework/src/suricata/src/runmodes.c')
-rw-r--r-- | framework/src/suricata/src/runmodes.c | 927 |
1 files changed, 927 insertions, 0 deletions
diff --git a/framework/src/suricata/src/runmodes.c b/framework/src/suricata/src/runmodes.c new file mode 100644 index 00000000..5a9f9762 --- /dev/null +++ b/framework/src/suricata/src/runmodes.c @@ -0,0 +1,927 @@ +/* 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 "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 "alert-fastlog.h" +#include "alert-prelude.h" +#include "alert-unified2-alert.h" +#include "alert-debuglog.h" + +#include "log-httplog.h" + +#include "output.h" + +#include "source-pfring.h" + +int debuglog_enabled = 0; + +/** + * \brief Holds description for a runmode. + */ +typedef struct RunMode_ { + /* the runmode type */ + int runmode; + const char *name; + const char *description; + /* runmode function */ + int (*RunModeFunc)(void); +} RunMode; + +typedef struct RunModes_ { + int no_of_runmodes; + RunMode *runmodes; +} RunModes; + +/** + * A list of output modules that will be active for the run mode. + */ +typedef struct RunModeOutput_ { + const char *name; + TmModule *tm_module; + OutputCtx *output_ctx; + + TAILQ_ENTRY(RunModeOutput_) entries; +} RunModeOutput; +TAILQ_HEAD(, RunModeOutput_) RunModeOutputs = + TAILQ_HEAD_INITIALIZER(RunModeOutputs); + +static RunModes runmodes[RUNMODE_USER_MAX]; + +static char *active_runmode; + +/* free list for our outputs */ +typedef struct OutputFreeList_ { + TmModule *tm_module; + OutputCtx *output_ctx; + + TAILQ_ENTRY(OutputFreeList_) entries; +} OutputFreeList; +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_TILERA_MPIPE: + return "MPIPE"; + 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"; + default: + SCLogError(SC_ERR_UNKNOWN_RUN_MODE, "Unknown runtime mode. Aborting"); + exit(EXIT_FAILURE); + } +} + +/** + * \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(int runmode, const char *custom_mode) +{ + int i; + + for (i = 0; i < runmodes[runmode].no_of_runmodes; 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(); + RunModeTileMpipeRegister(); + RunModeUnixSocketRegister(); +#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].no_of_runmodes; 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) { + 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_TILERA_MPIPE: + custom_mode = RunModeTileMpipeGetDefaultMode(); + 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; + 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; + } + } + +#ifdef __SC_CUDA_SUPPORT__ + if (PatternMatchDefaultMatcher() == MPM_AC_CUDA && + strcasecmp(custom_mode, "autofp") != 0) { + SCLogError(SC_ERR_RUNMODE, "When using a cuda mpm, the only runmode we " + "support is autofp."); + exit(EXIT_FAILURE); + } +#endif + + 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 */ + active_runmode = SCStrdup(custom_mode); + if (unlikely(active_runmode == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup active mode"); + exit(EXIT_FAILURE); + } + + mode->RunModeFunc(); + + if (local_custom_mode != NULL) + SCFree(local_custom_mode); + return; +} + +/** + * \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(int runmode, const char *name, + const char *description, + int (*RunModeFunc)(void)) +{ + void *ptmp; + if (RunModeGetCustomMode(runmode, name) != NULL) { + SCLogError(SC_ERR_RUNMODE, "A runmode by this custom name has already " + "been registered. Please use an unique name"); + return; + } + + ptmp = SCRealloc(runmodes[runmode].runmodes, + (runmodes[runmode].no_of_runmodes + 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].no_of_runmodes]; + runmodes[runmode].no_of_runmodes++; + + mode->runmode = runmode; + mode->name = SCStrdup(name); + if (unlikely(mode->name == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate string"); + exit(EXIT_FAILURE); + } + mode->description = SCStrdup(description); + if (unlikely(mode->description == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate string"); + exit(EXIT_FAILURE); + } + mode->RunModeFunc = RunModeFunc; + + return; +} + +/** + * Setup the outputs for this run mode. + * + * \param tv The ThreadVars for the thread the outputs will be + * appended to. + */ +void RunOutputFreeList(void) +{ + OutputFreeList *output; + while ((output = TAILQ_FIRST(&output_free_list))) { + SCLogDebug("output %s %p %p", output->tm_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 TmModule *pkt_logger_module = NULL; +static TmModule *tx_logger_module = NULL; +static TmModule *file_logger_module = NULL; +static TmModule *filedata_logger_module = NULL; +static TmModule *streaming_logger_module = NULL; + +int RunModeOutputFileEnabled(void) +{ + return (file_logger_module != NULL); +} + +int RunModeOutputFiledataEnabled(void) +{ + return (filedata_logger_module != NULL); +} + +/** + * Cleanup the run mode. + */ +void RunModeShutDown(void) +{ + RunOutputFreeList(); + + OutputPacketShutdown(); + OutputTxShutdown(); + OutputFileShutdown(); + OutputFiledataShutdown(); + OutputStreamingShutdown(); + OutputStatsShutdown(); + OutputFlowShutdown(); + + /* Close any log files. */ + RunModeOutput *output; + while ((output = TAILQ_FIRST(&RunModeOutputs))) { + SCLogDebug("Shutting down output %s.", output->tm_module->name); + TAILQ_REMOVE(&RunModeOutputs, output, entries); + SCFree(output); + } + + /* reset logger pointers */ + pkt_logger_module = NULL; + tx_logger_module = NULL; + file_logger_module = NULL; + filedata_logger_module = NULL; + streaming_logger_module = NULL; +} + +/** \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) +{ + TmModule *tm_module = TmModuleGetByName(module->name); + if (tm_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "TmModuleGetByName for %s failed", module->name); + exit(EXIT_FAILURE); + } + OutputFreeList *fl_output = SCCalloc(1, sizeof(OutputFreeList)); + if (unlikely(fl_output == NULL)) + return; + fl_output->tm_module = tm_module; + fl_output->output_ctx = output_ctx; + TAILQ_INSERT_TAIL(&output_free_list, fl_output, entries); +} + + +static int GetRunModeOutputPriority(RunModeOutput *module) +{ + TmModule *tm = TmModuleGetByName(module->name); + if (tm == NULL) + return 0; + + return tm->priority; +} + +static void InsertInRunModeOutputs(RunModeOutput *runmode_output) +{ + RunModeOutput *r_output = NULL; + int output_priority = GetRunModeOutputPriority(runmode_output); + + TAILQ_FOREACH(r_output, &RunModeOutputs, entries) { + if (GetRunModeOutputPriority(r_output) < output_priority) + break; + } + if (r_output) { + TAILQ_INSERT_BEFORE(r_output, runmode_output, entries); + } else { + TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_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); + return; + } + /* stats logger doesn't run in the packet path */ + if (module->StatsLogFunc) { + OutputRegisterStatsLogger(module->name, module->StatsLogFunc, output_ctx); + return; + } + + TmModule *tm_module = TmModuleGetByName(module->name); + if (tm_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "TmModuleGetByName for %s failed", module->name); + exit(EXIT_FAILURE); + } + if (strcmp(tmm_modules[TMM_ALERTDEBUGLOG].name, tm_module->name) == 0) + debuglog_enabled = 1; + + if (module->PacketLogFunc) { + SCLogDebug("%s is a packet logger", module->name); + OutputRegisterPacketLogger(module->name, module->PacketLogFunc, + module->PacketConditionFunc, output_ctx); + + /* need one instance of the packet logger module */ + if (pkt_logger_module == NULL) { + pkt_logger_module = TmModuleGetByName("__packet_logger__"); + if (pkt_logger_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "TmModuleGetByName for __packet_logger__ failed"); + exit(EXIT_FAILURE); + } + + RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); + if (unlikely(runmode_output == NULL)) + return; + runmode_output->name = module->name; + runmode_output->tm_module = pkt_logger_module; + runmode_output->output_ctx = NULL; + InsertInRunModeOutputs(runmode_output); + SCLogDebug("__packet_logger__ added"); + } + } else if (module->TxLogFunc) { + SCLogDebug("%s is a tx logger", module->name); + OutputRegisterTxLogger(module->name, module->alproto, + module->TxLogFunc, output_ctx); + + /* need one instance of the tx logger module */ + if (tx_logger_module == NULL) { + tx_logger_module = TmModuleGetByName("__tx_logger__"); + if (tx_logger_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "TmModuleGetByName for __tx_logger__ failed"); + exit(EXIT_FAILURE); + } + + RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); + if (unlikely(runmode_output == NULL)) + return; + runmode_output->name = module->name; + runmode_output->tm_module = tx_logger_module; + runmode_output->output_ctx = NULL; + InsertInRunModeOutputs(runmode_output); + SCLogDebug("__tx_logger__ added"); + } + } else if (module->FiledataLogFunc) { + SCLogDebug("%s is a filedata logger", module->name); + OutputRegisterFiledataLogger(module->name, module->FiledataLogFunc, output_ctx); + + /* need one instance of the tx logger module */ + if (filedata_logger_module == NULL) { + filedata_logger_module = TmModuleGetByName("__filedata_logger__"); + if (filedata_logger_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "TmModuleGetByName for __filedata_logger__ failed"); + exit(EXIT_FAILURE); + } + + RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); + if (unlikely(runmode_output == NULL)) + return; + runmode_output->name = module->name; + runmode_output->tm_module = filedata_logger_module; + runmode_output->output_ctx = NULL; + InsertInRunModeOutputs(runmode_output); + SCLogDebug("__filedata_logger__ added"); + } + } else if (module->FileLogFunc) { + SCLogDebug("%s is a file logger", module->name); + OutputRegisterFileLogger(module->name, module->FileLogFunc, output_ctx); + + /* need one instance of the tx logger module */ + if (file_logger_module == NULL) { + file_logger_module = TmModuleGetByName("__file_logger__"); + if (file_logger_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "TmModuleGetByName for __file_logger__ failed"); + exit(EXIT_FAILURE); + } + + RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); + if (unlikely(runmode_output == NULL)) + return; + runmode_output->name = module->name; + runmode_output->tm_module = file_logger_module; + runmode_output->output_ctx = NULL; + InsertInRunModeOutputs(runmode_output); + SCLogDebug("__file_logger__ added"); + } + } else if (module->StreamingLogFunc) { + SCLogDebug("%s is a streaming logger", module->name); + OutputRegisterStreamingLogger(module->name, module->StreamingLogFunc, + output_ctx, module->stream_type); + + /* need one instance of the streaming logger module */ + if (streaming_logger_module == NULL) { + streaming_logger_module = TmModuleGetByName("__streaming_logger__"); + if (streaming_logger_module == NULL) { + SCLogError(SC_ERR_INVALID_ARGUMENT, + "TmModuleGetByName for __streaming_logger__ failed"); + exit(EXIT_FAILURE); + } + + RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); + if (unlikely(runmode_output == NULL)) + return; + runmode_output->name = module->name; + runmode_output->tm_module = streaming_logger_module; + runmode_output->output_ctx = NULL; + InsertInRunModeOutputs(runmode_output); + SCLogDebug("__streaming_logger__ added"); + } + } else { + SCLogDebug("%s is a regular logger", module->name); + + RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput)); + if (unlikely(runmode_output == NULL)) + return; + runmode_output->name = module->name; + runmode_output->tm_module = tm_module; + runmode_output->output_ctx = output_ctx; + InsertInRunModeOutputs(runmode_output); + } +} + +/** + * 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; + + 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 (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, "eve-log") == 0) { +#ifndef HAVE_LIBJANSSON + SCLogWarning(SC_ERR_NOT_SUPPORTED, + "Eve-log support not compiled in. Reconfigure/" + "recompile with libjansson and its development " + "files installed to add eve-log 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, "tls-log") == 0) { + tls_log_enabled = 1; + } + + OutputModule *module = OutputGetModuleByConfName(output->val); + if (module == NULL) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, + "No output module named %s", output->val); + continue; + } + + OutputCtx *output_ctx = NULL; + if (module->InitFunc != NULL) { + output_ctx = module->InitFunc(output_config); + if (output_ctx == NULL) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, "output module setup failed"); + continue; + } + } else if (module->InitSubFunc != NULL) { + SCLogInfo("skipping submodule"); + continue; + } + + // TODO if module == parent, find it's children + if (strcmp(output->val, "eve-log") == 0) { + ConfNode *types = ConfNodeLookupChild(output_config, "types"); + SCLogDebug("types %p", types); + if (types != NULL) { + ConfNode *type = NULL; + TAILQ_FOREACH(type, &types->head, next) { + SCLogInfo("enabling 'eve-log' module '%s'", type->val); + + char subname[256]; + snprintf(subname, sizeof(subname), "%s.%s", output->val, type->val); + + OutputModule *sub_module = OutputGetModuleByConfName(subname); + if (sub_module == NULL) { + FatalErrorOnInit(SC_ERR_INVALID_ARGUMENT, + "No output module named %s", subname); + continue; + } + if (sub_module->parent_name == NULL || + strcmp(sub_module->parent_name,output->val) != 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); + } + ConfNode *sub_output_config = ConfNodeLookupChild(type, type->val); + // sub_output_config may be NULL if no config + + /* pass on parent output_ctx */ + OutputCtx *sub_output_ctx = + sub_module->InitSubFunc(sub_output_config, output_ctx); + if (sub_output_ctx == NULL) { + continue; + } + + AddOutputToFreeList(sub_module, sub_output_ctx); + SetupOutput(sub_module->name, sub_module, sub_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"); + + ConfNode *scripts = ConfNodeLookupChild(output_config, "scripts"); + BUG_ON(scripts == NULL); //TODO + + OutputModule *m; + TAILQ_FOREACH(m, &output_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 */ + OutputCtx *sub_output_ctx = + m->InitSubFunc(script, output_ctx); + if (sub_output_ctx == NULL) { + SCLogInfo("sub_output_ctx NULL, skipping"); + continue; + } + + SetupOutput(m->name, m, sub_output_ctx); + } + + } else { + AddOutputToFreeList(module, output_ctx); + SetupOutput(module->name, module, output_ctx); + } + } + + /* 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) { + output_ctx = module->InitFunc(output_config); + if (output_ctx == NULL) { + continue; + } + } + + AddOutputToFreeList(module, output_ctx); + SetupOutput(module->name, module, output_ctx); + } + } + } + +} + +/** + * Setup the outputs for this run mode. + * + * \param tv The ThreadVars for the thread the outputs will be + * appended to. + */ +void SetupOutputs(ThreadVars *tv) +{ + RunModeOutput *output; + TAILQ_FOREACH(output, &RunModeOutputs, entries) { + tv->cap_flags |= output->tm_module->cap_flags; + TmSlotSetFuncAppend(tv, output->tm_module, output->output_ctx); + } +} + +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); +} |