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.
443 lines
16 KiB
C
443 lines
16 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>
|
|
*/
|
|
|
|
#include "suricata-common.h"
|
|
#include "debug.h"
|
|
#include "detect.h"
|
|
#include "flow.h"
|
|
#include "conf.h"
|
|
|
|
#include "detect-parse.h"
|
|
#include "detect-engine-sigorder.h"
|
|
|
|
#include "detect-engine-siggroup.h"
|
|
#include "detect-engine-address.h"
|
|
#include "detect-engine-port.h"
|
|
#include "detect-engine-mpm.h"
|
|
#include "detect-engine-iponly.h"
|
|
|
|
#include "detect-engine.h"
|
|
|
|
#include "detect-content.h"
|
|
#include "detect-uricontent.h"
|
|
#include "detect-engine-threshold.h"
|
|
|
|
//#include "util-mpm.h"
|
|
#include "util-error.h"
|
|
#include "util-hash.h"
|
|
#include "util-byte.h"
|
|
#include "util-debug.h"
|
|
|
|
#include "util-var-name.h"
|
|
#include "tm-modules.h"
|
|
|
|
static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *);
|
|
DetectEngineCtx *DetectEngineCtxInit(void) {
|
|
DetectEngineCtx *de_ctx;
|
|
|
|
de_ctx = SCMalloc(sizeof(DetectEngineCtx));
|
|
if (de_ctx == NULL)
|
|
goto error;
|
|
|
|
memset(de_ctx,0,sizeof(DetectEngineCtx));
|
|
|
|
if (ConfGetBool("engine.init_failure_fatal", (int *)&(de_ctx->failure_fatal)) != 1) {
|
|
SCLogDebug("ConfGetBool could not load the value.");
|
|
}
|
|
|
|
de_ctx->mpm_matcher = PatternMatchDefaultMatcher();
|
|
DetectEngineCtxLoadConf(de_ctx);
|
|
|
|
SigGroupHeadHashInit(de_ctx);
|
|
SigGroupHeadMpmHashInit(de_ctx);
|
|
SigGroupHeadMpmUriHashInit(de_ctx);
|
|
SigGroupHeadSPortHashInit(de_ctx);
|
|
SigGroupHeadDPortHashInit(de_ctx);
|
|
DetectPortSpHashInit(de_ctx);
|
|
DetectPortDpHashInit(de_ctx);
|
|
ThresholdHashInit(de_ctx);
|
|
VariableNameInitHash(de_ctx);
|
|
|
|
de_ctx->mpm_pattern_id_store = MpmPatternIdTableInitHash();
|
|
if (de_ctx->mpm_pattern_id_store == NULL) {
|
|
goto error;
|
|
}
|
|
|
|
return de_ctx;
|
|
error:
|
|
return NULL;
|
|
}
|
|
|
|
void DetectEngineCtxFree(DetectEngineCtx *de_ctx) {
|
|
|
|
if (de_ctx == NULL)
|
|
return;
|
|
|
|
|
|
/* Normally the hashes are freed elsewhere, but
|
|
* to be sure look at them again here.
|
|
*/
|
|
MpmPatternIdTableFreeHash(de_ctx->mpm_pattern_id_store); /* normally cleaned up in SigGroupBuild */
|
|
|
|
SigGroupHeadHashFree(de_ctx);
|
|
SigGroupHeadMpmHashFree(de_ctx);
|
|
SigGroupHeadMpmUriHashFree(de_ctx);
|
|
SigGroupHeadSPortHashFree(de_ctx);
|
|
SigGroupHeadDPortHashFree(de_ctx);
|
|
SCSigSignatureOrderingModuleCleanup(de_ctx);
|
|
DetectPortSpHashFree(de_ctx);
|
|
DetectPortDpHashFree(de_ctx);
|
|
ThresholdContextDestroy(de_ctx);
|
|
SigCleanSignatures(de_ctx);
|
|
|
|
VariableNameFreeHash(de_ctx);
|
|
if (de_ctx->sig_array)
|
|
SCFree(de_ctx->sig_array);
|
|
|
|
if (de_ctx->class_conf_ht != NULL)
|
|
HashTableFree(de_ctx->class_conf_ht);
|
|
SCFree(de_ctx);
|
|
//DetectAddressGroupPrintMemory();
|
|
//DetectSigGroupPrintMemory();
|
|
//DetectPortPrintMemory();
|
|
}
|
|
|
|
/** \brief Function that load DetectEngineCtx config for grouping sigs
|
|
* used by the engine
|
|
* \retval 0 if no config provided, 1 if config was provided
|
|
* and loaded successfuly
|
|
*/
|
|
static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *de_ctx) {
|
|
uint8_t profile = ENGINE_PROFILE_UNKNOWN;
|
|
char *de_ctx_profile = NULL;
|
|
|
|
const char *max_uniq_toclient_src_groups_str = NULL;
|
|
const char *max_uniq_toclient_dst_groups_str = NULL;
|
|
const char *max_uniq_toclient_sp_groups_str = NULL;
|
|
const char *max_uniq_toclient_dp_groups_str = NULL;
|
|
|
|
const char *max_uniq_toserver_src_groups_str = NULL;
|
|
const char *max_uniq_toserver_dst_groups_str = NULL;
|
|
const char *max_uniq_toserver_sp_groups_str = NULL;
|
|
const char *max_uniq_toserver_dp_groups_str = NULL;
|
|
|
|
ConfNode *de_ctx_custom = ConfGetNode("detect-engine");
|
|
ConfNode *opt = NULL;
|
|
|
|
if (de_ctx_custom != NULL) {
|
|
TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
|
|
if (strncmp(opt->val, "profile", 3) == 0) {
|
|
de_ctx_profile = opt->head.tqh_first->val;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (de_ctx_profile != NULL) {
|
|
if (strncmp(de_ctx_profile, "low", 3) == 0) {
|
|
profile = ENGINE_PROFILE_LOW;
|
|
} else if (strncmp(de_ctx_profile, "medium", 6) == 0) {
|
|
profile = ENGINE_PROFILE_MEDIUM;
|
|
} else if (strncmp(de_ctx_profile, "high", 4) == 0) {
|
|
profile = ENGINE_PROFILE_HIGH;
|
|
} else if (strncmp(de_ctx_profile, "custom", 4) == 0) {
|
|
profile = ENGINE_PROFILE_CUSTOM;
|
|
}
|
|
|
|
SCLogDebug("Profile for detection engine groups is \"%s\"", de_ctx_profile);
|
|
} else {
|
|
SCLogDebug("Profile for detection engine groups not provided "
|
|
"at suricata.yaml. Using default (\"medium\").");
|
|
}
|
|
|
|
opt = NULL;
|
|
switch (profile) {
|
|
case ENGINE_PROFILE_LOW:
|
|
de_ctx->max_uniq_toclient_src_groups = 2;
|
|
de_ctx->max_uniq_toclient_dst_groups = 2;
|
|
de_ctx->max_uniq_toclient_sp_groups = 2;
|
|
de_ctx->max_uniq_toclient_dp_groups = 3;
|
|
de_ctx->max_uniq_toserver_src_groups = 2;
|
|
de_ctx->max_uniq_toserver_dst_groups = 2;
|
|
de_ctx->max_uniq_toserver_sp_groups = 2;
|
|
de_ctx->max_uniq_toserver_dp_groups = 3;
|
|
break;
|
|
|
|
case ENGINE_PROFILE_HIGH:
|
|
de_ctx->max_uniq_toclient_src_groups = 15;
|
|
de_ctx->max_uniq_toclient_dst_groups = 15;
|
|
de_ctx->max_uniq_toclient_sp_groups = 15;
|
|
de_ctx->max_uniq_toclient_dp_groups = 20;
|
|
de_ctx->max_uniq_toserver_src_groups = 15;
|
|
de_ctx->max_uniq_toserver_dst_groups = 15;
|
|
de_ctx->max_uniq_toserver_sp_groups = 15;
|
|
de_ctx->max_uniq_toserver_dp_groups = 40;
|
|
break;
|
|
|
|
case ENGINE_PROFILE_CUSTOM:
|
|
TAILQ_FOREACH(opt, &de_ctx_custom->head, next) {
|
|
if (strncmp(opt->val, "custom-values", 3) == 0) {
|
|
max_uniq_toclient_src_groups_str = ConfNodeLookupChildValue
|
|
(opt->head.tqh_first, "toclient_src_groups");
|
|
max_uniq_toclient_dst_groups_str = ConfNodeLookupChildValue
|
|
(opt->head.tqh_first, "toclient_dst_groups");
|
|
max_uniq_toclient_sp_groups_str = ConfNodeLookupChildValue
|
|
(opt->head.tqh_first, "toclient_sp_groups");
|
|
max_uniq_toclient_dp_groups_str = ConfNodeLookupChildValue
|
|
(opt->head.tqh_first, "toclient_dp_groups");
|
|
max_uniq_toserver_src_groups_str = ConfNodeLookupChildValue
|
|
(opt->head.tqh_first, "toserver_src_groups");
|
|
max_uniq_toserver_dst_groups_str = ConfNodeLookupChildValue
|
|
(opt->head.tqh_first, "toserver_dst_groups");
|
|
max_uniq_toserver_sp_groups_str = ConfNodeLookupChildValue
|
|
(opt->head.tqh_first, "toserver_sp_groups");
|
|
max_uniq_toserver_dp_groups_str = ConfNodeLookupChildValue
|
|
(opt->head.tqh_first, "toserver_dp_groups");
|
|
}
|
|
}
|
|
if (max_uniq_toclient_src_groups_str != NULL) {
|
|
if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_src_groups, 10,
|
|
strlen(max_uniq_toclient_src_groups_str),
|
|
(const char *)max_uniq_toclient_src_groups_str) <= 0)
|
|
de_ctx->max_uniq_toclient_src_groups = 2;
|
|
} else {
|
|
de_ctx->max_uniq_toclient_src_groups = 2;
|
|
}
|
|
if (max_uniq_toclient_dst_groups_str != NULL) {
|
|
if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_dst_groups, 10,
|
|
strlen(max_uniq_toclient_dst_groups_str),
|
|
(const char *)max_uniq_toclient_dst_groups_str) <= 0)
|
|
de_ctx->max_uniq_toclient_dst_groups = 2;
|
|
} else {
|
|
de_ctx->max_uniq_toclient_dst_groups = 2;
|
|
}
|
|
if (max_uniq_toclient_sp_groups_str != NULL) {
|
|
if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_sp_groups, 10,
|
|
strlen(max_uniq_toclient_sp_groups_str),
|
|
(const char *)max_uniq_toclient_sp_groups_str) <= 0)
|
|
de_ctx->max_uniq_toclient_sp_groups = 2;
|
|
} else {
|
|
de_ctx->max_uniq_toclient_sp_groups = 2;
|
|
}
|
|
if (max_uniq_toclient_dp_groups_str != NULL) {
|
|
if (ByteExtractStringUint16(&de_ctx->max_uniq_toclient_dp_groups, 10,
|
|
strlen(max_uniq_toclient_dp_groups_str),
|
|
(const char *)max_uniq_toclient_dp_groups_str) <= 0)
|
|
de_ctx->max_uniq_toclient_dp_groups = 2;
|
|
} else {
|
|
de_ctx->max_uniq_toclient_dp_groups = 2;
|
|
}
|
|
if (max_uniq_toserver_src_groups_str != NULL) {
|
|
if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_src_groups, 10,
|
|
strlen(max_uniq_toserver_src_groups_str),
|
|
(const char *)max_uniq_toserver_src_groups_str) <= 0)
|
|
de_ctx->max_uniq_toserver_src_groups = 2;
|
|
} else {
|
|
de_ctx->max_uniq_toserver_src_groups = 2;
|
|
}
|
|
if (max_uniq_toserver_dst_groups_str != NULL) {
|
|
if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_dst_groups, 10,
|
|
strlen(max_uniq_toserver_dst_groups_str),
|
|
(const char *)max_uniq_toserver_dst_groups_str) <= 0)
|
|
de_ctx->max_uniq_toserver_dst_groups = 2;
|
|
} else {
|
|
de_ctx->max_uniq_toserver_dst_groups = 2;
|
|
}
|
|
if (max_uniq_toserver_sp_groups_str != NULL) {
|
|
if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_sp_groups, 10,
|
|
strlen(max_uniq_toserver_sp_groups_str),
|
|
(const char *)max_uniq_toserver_sp_groups_str) <= 0)
|
|
de_ctx->max_uniq_toserver_sp_groups = 2;
|
|
} else {
|
|
de_ctx->max_uniq_toserver_sp_groups = 2;
|
|
}
|
|
if (max_uniq_toserver_dp_groups_str != NULL) {
|
|
if (ByteExtractStringUint16(&de_ctx->max_uniq_toserver_dp_groups, 10,
|
|
strlen(max_uniq_toserver_dp_groups_str),
|
|
(const char *)max_uniq_toserver_dp_groups_str) <= 0)
|
|
de_ctx->max_uniq_toserver_dp_groups = 2;
|
|
} else {
|
|
de_ctx->max_uniq_toserver_dp_groups = 2;
|
|
}
|
|
break;
|
|
|
|
/* Default (or no config provided) is profile medium */
|
|
case ENGINE_PROFILE_MEDIUM:
|
|
case ENGINE_PROFILE_UNKNOWN:
|
|
default:
|
|
de_ctx->max_uniq_toclient_src_groups = 4;
|
|
de_ctx->max_uniq_toclient_dst_groups = 4;
|
|
de_ctx->max_uniq_toclient_sp_groups = 4;
|
|
de_ctx->max_uniq_toclient_dp_groups = 6;
|
|
|
|
de_ctx->max_uniq_toserver_src_groups = 4;
|
|
de_ctx->max_uniq_toserver_dst_groups = 8;
|
|
de_ctx->max_uniq_toserver_sp_groups = 4;
|
|
de_ctx->max_uniq_toserver_dp_groups = 30;
|
|
break;
|
|
}
|
|
|
|
if (profile == ENGINE_PROFILE_UNKNOWN)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* getting & (re)setting the internal sig i
|
|
*/
|
|
|
|
//inline uint32_t DetectEngineGetMaxSigId(DetectEngineCtx *de_ctx) {
|
|
// return de_ctx->signum;
|
|
//}
|
|
|
|
void DetectEngineResetMaxSigId(DetectEngineCtx *de_ctx) {
|
|
de_ctx->signum = 0;
|
|
}
|
|
|
|
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data) {
|
|
DetectEngineCtx *de_ctx = (DetectEngineCtx *)initdata;
|
|
if (de_ctx == NULL)
|
|
return TM_ECODE_FAILED;
|
|
|
|
DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx));
|
|
if (det_ctx == NULL)
|
|
return TM_ECODE_FAILED;
|
|
memset(det_ctx, 0, sizeof(DetectEngineThreadCtx));
|
|
|
|
det_ctx->de_ctx = de_ctx;
|
|
|
|
/** \todo we still depend on the global mpm_ctx here
|
|
*
|
|
* Initialize the thread pattern match ctx with the max size
|
|
* of the content and uricontent id's so our match lookup
|
|
* table is always big enough
|
|
*/
|
|
PatternMatchThreadPrepare(&det_ctx->mtc, de_ctx->mpm_matcher, DetectContentMaxId(de_ctx));
|
|
PatternMatchThreadPrepare(&det_ctx->mtcu, de_ctx->mpm_matcher, DetectUricontentMaxId(de_ctx));
|
|
|
|
//PmqSetup(&det_ctx->pmq, DetectEngineGetMaxSigId(de_ctx), DetectContentMaxId(de_ctx));
|
|
PmqSetup(&det_ctx->pmq, 0, DetectContentMaxId(de_ctx));
|
|
int i;
|
|
for (i = 0; i < 256; i++) {
|
|
PmqSetup(&det_ctx->smsg_pmq[i], 0, DetectContentMaxId(de_ctx));
|
|
}
|
|
|
|
/* IP-ONLY */
|
|
DetectEngineIPOnlyThreadInit(de_ctx,&det_ctx->io_ctx);
|
|
|
|
/* DeState */
|
|
if (de_ctx->sig_array_len > 0) {
|
|
det_ctx->de_state_sig_array_len = de_ctx->sig_array_len;
|
|
det_ctx->de_state_sig_array = SCMalloc(det_ctx->de_state_sig_array_len * sizeof(uint8_t));
|
|
if (det_ctx->de_state_sig_array == NULL) {
|
|
SCLogError(SC_ERR_MEM_ALLOC, "malloc of %"PRIuMAX" failed: %s",
|
|
(uintmax_t)(det_ctx->de_state_sig_array_len * sizeof(uint8_t)), strerror(errno));
|
|
return TM_ECODE_FAILED;
|
|
}
|
|
}
|
|
|
|
/** alert counter setup */
|
|
det_ctx->counter_alerts = SCPerfTVRegisterCounter("detect.alert", tv,
|
|
SC_PERF_TYPE_UINT64, "NULL");
|
|
tv->sc_perf_pca = SCPerfGetAllCountersArray(&tv->sc_perf_pctx);
|
|
SCPerfAddToClubbedTMTable(tv->name, &tv->sc_perf_pctx);
|
|
|
|
/* this detection engine context belongs to this thread instance */
|
|
det_ctx->tv = tv;
|
|
|
|
*data = (void *)det_ctx;
|
|
|
|
#ifdef __SC_CUDA_SUPPORT__
|
|
if (PatternMatchDefaultMatcher() != MPM_B2G_CUDA)
|
|
return TM_ECODE_OK;
|
|
|
|
Tmq *tmq;
|
|
/* we would prepend this name to the the tv name, to obtain the final unique
|
|
* detection thread queue name */
|
|
char *cuda_outq_name = "cuda_mpm_rc_disp_outq";
|
|
uint8_t disp_outq_name_len = (strlen(tv->name) + strlen(cuda_outq_name) + 1);
|
|
|
|
char *disp_outq_name = SCMalloc(disp_outq_name_len * sizeof(char));
|
|
if (disp_outq_name == NULL)
|
|
goto error;
|
|
strcpy(disp_outq_name, tv->name);
|
|
strcpy(disp_outq_name + strlen(tv->name), cuda_outq_name);
|
|
disp_outq_name[disp_outq_name_len] = '\0';
|
|
|
|
tmq = TmqGetQueueByName(disp_outq_name);
|
|
if (tmq != NULL) {
|
|
SCLogError(SC_ERR_TMQ_ALREADY_REGISTERED, "A queue by the name \"%s\" "
|
|
"is already registered, which shouldn't be the case. Queue "
|
|
"name is duplicated. Please check if multiple instances of "
|
|
"detection module are given different names ",
|
|
disp_outq_name);
|
|
goto error;
|
|
}
|
|
tmq = TmqCreateQueue(disp_outq_name);
|
|
if (tmq == NULL)
|
|
goto error;
|
|
|
|
/* hold the queue instane we create under this detection thread instance */
|
|
det_ctx->cuda_mpm_rc_disp_outq = tmq;
|
|
det_ctx->cuda_mpm_rc_disp_outq->reader_cnt++;
|
|
det_ctx->cuda_mpm_rc_disp_outq->writer_cnt++;
|
|
|
|
return TM_ECODE_OK;
|
|
|
|
error:
|
|
return TM_ECODE_FAILED;
|
|
#endif
|
|
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data) {
|
|
DetectEngineThreadCtx *det_ctx = (DetectEngineThreadCtx *)data;
|
|
|
|
if (det_ctx == NULL) {
|
|
SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "argument \"data\" NULL");
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
DetectEngineIPOnlyThreadDeinit(&det_ctx->io_ctx);
|
|
|
|
/** \todo get rid of this static */
|
|
PatternMatchThreadDestroy(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
|
|
PatternMatchThreadDestroy(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
|
|
|
|
PmqFree(&det_ctx->pmq);
|
|
|
|
if (det_ctx->de_state_sig_array != NULL)
|
|
SCFree(det_ctx->de_state_sig_array);
|
|
|
|
SCFree(det_ctx);
|
|
|
|
return TM_ECODE_OK;
|
|
}
|
|
|
|
void DetectEngineThreadCtxInfo(ThreadVars *t, DetectEngineThreadCtx *det_ctx) {
|
|
/* XXX */
|
|
PatternMatchThreadPrint(&det_ctx->mtc, det_ctx->de_ctx->mpm_matcher);
|
|
PatternMatchThreadPrint(&det_ctx->mtcu, det_ctx->de_ctx->mpm_matcher);
|
|
}
|
|
|