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.
suricata/src/runmodes.c

472 lines
14 KiB
C

/* Copyright (C) 2007-2010 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 "alert-fastlog.h"
#include "alert-prelude.h"
#include "alert-unified2-alert.h"
#include "alert-debuglog.h"
#include "log-httplog.h"
#include "output.h"
#include "cuda-packet-batcher.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)(DetectEngineCtx *);
} 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_ {
TmModule *tm_module;
OutputCtx *output_ctx;
TAILQ_ENTRY(RunModeOutput_) entries;
} RunModeOutput;
TAILQ_HEAD(, RunModeOutput_) RunModeOutputs =
TAILQ_HEAD_INITIALIZER(RunModeOutputs);
static RunModes runmodes[RUNMODE_MAX];
static char *active_runmode;
/**
* \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_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";
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.
* \param de_ctx Detection Engine Context.
*/
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;
}
/**
* \brief Register all runmodes in the engine.
*/
void RunModeRegisterRunModes(void)
{
memset(runmodes, 0, sizeof(runmodes));
RunModeIdsPcapRegister();
RunModeFilePcapRegister();
RunModeIdsPfringRegister();
RunModeIpsNFQRegister();
RunModeIpsIPFWRegister();
RunModeErfFileRegister();
RunModeErfDagRegister();
RunModeNapatechRegister();
RunModeIdsAFPRegister();
#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 ", "Descripition");
printf("|-----------------------------------------------------------------"
"-----------------------\n");
int i = RUNMODE_UNKNOWN + 1;
int j = 0;
for ( ; i < RUNMODE_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;
}
printf("|-----------------------------------------------------------------"
"-----------------------\n");
}
return;
}
void RunModeDispatch(int runmode, const char *custom_mode, DetectEngineCtx *de_ctx)
{
if (custom_mode == NULL) {
char *val = NULL;
if (ConfGet("runmode", &val) != 1) {
custom_mode = NULL;
} else {
custom_mode = val;
}
}
if (custom_mode == NULL) {
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;
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.");
custom_mode = SCStrdup("workers");
}
}
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);
mode->RunModeFunc(de_ctx);
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)(DetectEngineCtx *))
{
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;
}
runmodes[runmode].runmodes =
SCRealloc(runmodes[runmode].runmodes,
(runmodes[runmode].no_of_runmodes + 1) * sizeof(RunMode));
if (runmodes[runmode].runmodes == NULL) {
exit(EXIT_FAILURE);
}
RunMode *mode = &runmodes[runmode].runmodes[runmodes[runmode].no_of_runmodes];
runmodes[runmode].no_of_runmodes++;
mode->runmode = runmode;
mode->name = SCStrdup(name);
mode->description = SCStrdup(description);
mode->RunModeFunc = RunModeFunc;
return;
}
/**
* Cleanup the run mode.
*/
void RunModeShutDown(void)
{
/* 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);
if (output->output_ctx != NULL && output->output_ctx->DeInit != NULL)
output->output_ctx->DeInit(output->output_ctx);
SCFree(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;
TmModule *tm_module;
const char *enabled;
TAILQ_FOREACH(output, &outputs->head, next) {
15 years ago
if (strcmp(output->val, "stats") == 0)
continue;
output_config = ConfNodeLookupChild(output, output->val);
if (output_config == NULL) {
/* Shouldn't happen. */
SCLogError(SC_ERR_INVALID_ARGUMENT,
"Failed to lookup configuration child node: fast");
exit(1);
}
enabled = ConfNodeLookupChildValue(output_config, "enabled");
if (enabled == NULL || !ConfValIsTrue(enabled)) {
continue;
}
if (strncmp(output->val, "unified-", sizeof("unified-") - 1) == 0) {
SCLogWarning(SC_ERR_INVALID_ARGUMENT,
"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_INVALID_ARGUMENT,
"Prelude support not compiled in. Reconfigure/"
"recompile with --enable-prelude to add Prelude "
"support.");
continue;
#endif
}
OutputModule *module = OutputGetModuleByConfName(output->val);
if (module == NULL) {
SCLogWarning(SC_ERR_INVALID_ARGUMENT,
"No output module named %s, ignoring", output->val);
continue;
}
OutputCtx *output_ctx = NULL;
if (module->InitFunc != NULL) {
output_ctx = module->InitFunc(output_config);
if (output_ctx == NULL) {
/* In most cases the init function will have logged the
* error. Maybe we should exit on init errors? */
continue;
}
}
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;
RunModeOutput *runmode_output = SCCalloc(1, sizeof(RunModeOutput));
if (runmode_output == NULL)
return;
runmode_output->tm_module = tm_module;
runmode_output->output_ctx = output_ctx;
TAILQ_INSERT_TAIL(&RunModeOutputs, runmode_output, entries);
}
}
/**
* 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 the output modules.
*/
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) {
threading_detect_ratio = 1;
}
SCLogDebug("threading.detect-thread-ratio %f", threading_detect_ratio);
}