From 1ae36b9a6a161f3bca80150c9397ea741f6c02b0 Mon Sep 17 00:00:00 2001 From: Pablo Rincon Date: Thu, 10 Jun 2010 23:49:27 +0200 Subject: [PATCH] Adding rate_filter support for threshold.config, multiline support and unittests --- src/detect-engine-alert.c | 2 +- src/detect-engine-threshold.c | 94 +++ src/detect-threshold.h | 28 +- src/util-fmemopen.c | 14 +- src/util-threshold-config.c | 1012 +++++++++++++++++++++++++++++++-- 5 files changed, 1089 insertions(+), 61 deletions(-) diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index 0fdeeb5f0d..c49c9440b8 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -59,7 +59,7 @@ int PacketAlertRemove(Packet *p, uint16_t pos) { uint16_t i = 0; int match = 0; - if (pos >= p->alerts.cnt) + if (pos > p->alerts.cnt) return 0; for (i = pos; i <= p->alerts.cnt - 1; i++) { diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index d1d21282d2..d44181e3eb 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -270,6 +270,7 @@ static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdDat ste->track = td->track; ste->seconds = td->seconds; + ste->tv_timeout = 0; SCReturnPtr(ste, "DetectThresholdEntry"); } @@ -453,6 +454,99 @@ int PacketAlertThreshold(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx } break; } + /* rate_filter */ + case TYPE_RATE: + { + SCLogDebug("rate_filter"); + + /* tracking by src/dst or by rule? */ + if (td->track != TRACK_RULE) + lookup_tsh = ThresholdHashSearch(de_ctx, &ste, p); + else + lookup_tsh = s->th_entry; + + if (lookup_tsh != NULL) { + /* Check if we have a timeout enabled, if so, + * we still matching (and enabling the new_action) */ + if ( (p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) { + /* Ok, we are done, timeout reached */ + td->timeout = 0; + } else { + /* Already matching */ + /* Take the action to perform */ + switch (td->new_action) { + case TH_ACTION_ALERT: + p->action |= ACTION_ALERT; + break; + case TH_ACTION_DROP: + p->action |= ACTION_DROP; + break; + case TH_ACTION_REJECT: + p->action |= ACTION_REJECT; + break; + case TH_ACTION_PASS: + p->action |= ACTION_PASS; + break; + default: + /* Weird, leave the default action */ + break; + } + ret = 1; + } + + /* Update the matching state with the timeout interval */ + if ( (p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) { + lookup_tsh->current_count++; + if (lookup_tsh->current_count >= td->count) { + /* Then we must enable the new action by setting a + * timeout */ + lookup_tsh->tv_timeout = p->ts.tv_sec; + /* Take the action to perform */ + switch (td->new_action) { + case TH_ACTION_ALERT: + p->action |= ACTION_ALERT; + break; + case TH_ACTION_DROP: + p->action |= ACTION_DROP; + break; + case TH_ACTION_REJECT: + p->action |= ACTION_REJECT; + break; + case TH_ACTION_PASS: + p->action |= ACTION_PASS; + break; + default: + /* Weird, leave the default action */ + break; + } + ret = 1; + } + } else { + lookup_tsh->tv_sec1 = p->ts.tv_sec; + lookup_tsh->current_count = 1; + } + } else { + if (td->count == 1) { + ret = 1; + } + + DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s); + if (e == NULL) { + break; + } + + e->current_count = 1; + e->tv_sec1 = p->ts.tv_sec; + e->tv_timeout = 0; + + /** The track is by src/dst or by rule? */ + if (td->track != TRACK_RULE) + ThresholdHashAdd(de_ctx, e, p); + else + s->th_entry = e; + } + break; + } } /* handle timing out entries */ diff --git a/src/detect-threshold.h b/src/detect-threshold.h index d72a8845dd..1daa4539a1 100644 --- a/src/detect-threshold.h +++ b/src/detect-threshold.h @@ -32,9 +32,19 @@ #define TYPE_BOTH 2 #define TYPE_THRESHOLD 3 #define TYPE_DETECTION 4 +#define TYPE_RATE 5 #define TRACK_DST 1 #define TRACK_SRC 2 +#define TRACK_RULE 3 + +/* Get the new action to take */ +#define TH_ACTION_ALERT 0x01 +#define TH_ACTION_DROP 0x02 +#define TH_ACTION_PASS 0x04 +#define TH_ACTION_LOG 0x08 +#define TH_ACTION_SDROP 0x10 +#define TH_ACTION_REJECT 0x20 /** * \typedef DetectThresholdData @@ -48,17 +58,21 @@ typedef struct DetectThresholdData_ { uint8_t gid; /**< Signature group id */ uint8_t type; /**< Threshold type : limit , threshold, both, detection_filter */ uint8_t track; /**< Track type: by_src, by_dst */ + uint8_t new_action; /**< new_action alert|drop|pass|log|sdrop|reject */ + uint32_t timeout; /**< timeout */ } DetectThresholdData; typedef struct DetectThresholdEntry_ { - uint32_t seconds; /**< Event seconds */ - uint32_t sid; /**< Signature id */ - uint32_t tv_sec1; /**< Var for time control */ + uint32_t tv_timeout; /**< Timeout for new_action (for rate_filter) + its not "seconds", that define the time interval */ + uint32_t seconds; /**< Event seconds */ + uint32_t sid; /**< Signature id */ + uint32_t tv_sec1; /**< Var for time control */ uint32_t current_count; /**< Var for count control */ - Address addr; /**< Var used to store dst or src addr */ - uint8_t gid; /**< Signature group id */ - uint8_t ipv; /**< Packet ip version */ - uint8_t track; /**< Track type: by_src, by_src */ + Address addr; /**< Var used to store dst or src addr */ + uint8_t gid; /**< Signature group id */ + uint8_t ipv; /**< Packet ip version */ + uint8_t track; /**< Track type: by_src, by_src */ } DetectThresholdEntry; diff --git a/src/util-fmemopen.c b/src/util-fmemopen.c index 1e0d6e28fc..d6dfab1243 100644 --- a/src/util-fmemopen.c +++ b/src/util-fmemopen.c @@ -84,12 +84,13 @@ static fpos_t SeekFn(void *handler, fpos_t offset, int whence) { switch (whence) { case SEEK_SET: - if (offset > 0 && (size_t)offset <= mem->size) + if (offset >= 0 && (size_t)offset <= mem->size) { return mem->pos = offset; + } break; case SEEK_CUR: if (mem->pos + offset <= mem->size) - return mem->pos = offset; + return mem->pos += offset; break; case SEEK_END: /* must be negative */ @@ -112,15 +113,22 @@ static int ReadFn(void *handler, char *buf, int size) { size_t count = 0; SCFmem *mem = handler; size_t available = mem->size - mem->pos; + int is_eof = 0; if (size < 0) return - 1; - if ((size_t)size > available) + if ((size_t)size > available) { size = available; + } else { + is_eof = 1; + } while (count < (size_t)size) buf[count++] = mem->buffer[mem->pos++]; + if (is_eof == 1) + return 0; + return count; } diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index 90aea17f79..42edae8152 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -34,7 +34,9 @@ #include "conf.h" #include "util-threshold-config.h" #include "util-unittest.h" +#include "util-unittest-helper.h" #include "util-byte.h" +#include "util-time.h" #include "util-error.h" #include "util-debug.h" #include "util-fmemopen.h" @@ -43,12 +45,18 @@ #define DETECT_THRESHOLD_REGEX "^\\s*(event_filter|threshold)\\s*gen_id\\s*(\\d+)\\s*,\\s*sig_id\\s*(\\d+)\\s*,\\s*type\\s*(limit|both|threshold)\\s*,\\s*track\\s*(by_dst|by_src)\\s*,\\s*count\\s*(\\d+)\\s*,\\s*seconds\\s*(\\d+)\\s*$" +/* TODO: "apply_to" */ +#define DETECT_RATE_REGEX "^\\s*(rate_filter)\\s*gen_id\\s*(\\d+)\\s*,\\s*sig_id\\s*(\\d+)\\s*,\\s*track\\s*(by_dst|by_src|by_rule)\\s*,\\s*count\\s*(\\d+)\\s*,\\s*seconds\\s*(\\d+)\\s*,\\s*new_action\\s*(alert|drop|pass|log|sdrop|reject)\\s*,\\s*timeout\\s*(\\d+)\\s*$" + /* Default path for the threshold.config file */ #define THRESHOLD_CONF_DEF_CONF_FILEPATH "threshold.config" static pcre *regex = NULL; static pcre_extra *regex_study = NULL; +static pcre *rate_regex = NULL; +static pcre_extra *rate_regex_study = NULL; + /** * \brief Returns the path for the Threshold Config file. We check if we * can retrieve the path from the yaml conf file. If it is not present, @@ -110,6 +118,18 @@ int SCThresholdConfInitContext(DetectEngineCtx *de_ctx, FILE *utfd) goto error; } + rate_regex = pcre_compile(DETECT_RATE_REGEX, opts, &eb, &eo, NULL); + if (regex == NULL) { + SCLogError(SC_ERR_PCRE_COMPILE, "Compile of \"%s\" failed at offset %" PRId32 ": %s",DETECT_RATE_REGEX, eo, eb); + goto error; + } + + rate_regex_study = pcre_study(rate_regex, 0, &eb); + if (eb != NULL) { + SCLogError(SC_ERR_PCRE_STUDY, "pcre study failed: %s", eb); + goto error; + } + SCThresholdConfParseFile(de_ctx, fd); SCThresholdConfDeInitContext(de_ctx, fd); @@ -152,11 +172,15 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) const char *th_track = NULL; const char *th_count = NULL; const char *th_seconds = NULL; + const char *th_new_action= NULL; + const char *th_timeout = NULL; uint8_t parsed_type = 0; uint8_t parsed_track = 0; + uint8_t parsed_new_action = 0; uint32_t parsed_count = 0; uint32_t parsed_seconds = 0; + uint32_t parsed_timeout = 0; Signature *sig = NULL; Signature *s = NULL, *ns = NULL; @@ -174,58 +198,138 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) ret = pcre_exec(regex, regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30); if (ret < 8) { - SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); - goto error; - } + /* Its not threshold/event_filter, so try rate_filter regexp */ + ret = pcre_exec(rate_regex, rate_regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30); + if (ret < 9) { + SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); + goto error; + } else { + /* Start rate_filter parsing */ + /* retrieve the classtype name */ + ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &th_gid); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - /* retrieve the classtype name */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &th_gid); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &th_sid); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &th_sid); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + ret = pcre_get_substring((char *)rawstr, ov, 30, 4, &th_track); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - ret = pcre_get_substring((char *)rawstr, ov, 30, 4, &th_type); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + ret = pcre_get_substring((char *)rawstr, ov, 30, 5, &th_count); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - ret = pcre_get_substring((char *)rawstr, ov, 30, 5, &th_track); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + ret = pcre_get_substring((char *)rawstr, ov, 30, 6, &th_seconds); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - ret = pcre_get_substring((char *)rawstr, ov, 30, 6, &th_count); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + ret = pcre_get_substring((char *)rawstr, ov, 30, 7, &th_new_action); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - ret = pcre_get_substring((char *)rawstr, ov, 30, 7, &th_seconds); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + ret = pcre_get_substring((char *)rawstr, ov, 30, 8, &th_timeout); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + /* TODO: implement option "apply_to" */ + + if (ByteExtractStringUint32(&parsed_timeout, 10, strlen(th_timeout), th_timeout) <= 0) { + goto error; + } + + /* Get the new action to take */ + if (strcasecmp(th_new_action, "alert") == 0) + parsed_new_action = TH_ACTION_ALERT; + if (strcasecmp(th_new_action, "drop") == 0) + parsed_new_action = TH_ACTION_DROP; + if (strcasecmp(th_new_action, "pass") == 0) + parsed_new_action = TH_ACTION_PASS; + if (strcasecmp(th_new_action, "reject") == 0) + parsed_new_action = TH_ACTION_REJECT; + if (strcasecmp(th_new_action, "log") == 0) { + SCLogInfo("log action for rate_filter not supported yet"); + parsed_new_action = TH_ACTION_LOG; + } + if (strcasecmp(th_new_action, "sdrop") == 0) { + SCLogInfo("sdrop action for rate_filter not supported yet"); + parsed_new_action = TH_ACTION_SDROP; + } + + parsed_type = TYPE_RATE; + + } /* End rate_filter parsing */ + } else { + /* Its a threshold/event_filter rule, Parse it */ + + /* retrieve the classtype name */ + ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &th_gid); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &th_sid); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + ret = pcre_get_substring((char *)rawstr, ov, 30, 4, &th_type); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + ret = pcre_get_substring((char *)rawstr, ov, 30, 5, &th_track); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + ret = pcre_get_substring((char *)rawstr, ov, 30, 6, &th_count); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + ret = pcre_get_substring((char *)rawstr, ov, 30, 7, &th_seconds); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - if (strcasecmp(th_type,"limit") == 0) - parsed_type = TYPE_LIMIT; - else if (strcasecmp(th_type,"both") == 0) - parsed_type = TYPE_BOTH; - else if (strcasecmp(th_type,"threshold") == 0) - parsed_type = TYPE_THRESHOLD; + if (strcasecmp(th_type,"limit") == 0) + parsed_type = TYPE_LIMIT; + else if (strcasecmp(th_type,"both") == 0) + parsed_type = TYPE_BOTH; + else if (strcasecmp(th_type,"threshold") == 0) + parsed_type = TYPE_THRESHOLD; + } /* End of threshold/event_filter parsing */ + /* This part is common to threshold/event_filter/rate_filter */ if (strcasecmp(th_track,"by_dst") == 0) parsed_track = TRACK_DST; else if (strcasecmp(th_track,"by_src") == 0) parsed_track = TRACK_SRC; + else if (strcasecmp(th_track,"by_rule") == 0) + parsed_track = TRACK_RULE; if (ByteExtractStringUint32(&parsed_count, 10, strlen(th_count), th_count) <= 0) { goto error; @@ -235,7 +339,6 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) goto error; } - if (ByteExtractStringUint32(&id, 10, strlen(th_sid), th_sid) <= 0) { goto error; } @@ -244,6 +347,8 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) goto error; } + + /* Install it */ if (id == 0 && gid == 0) { for (s = de_ctx->sig_list; s != NULL;) { @@ -270,6 +375,8 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) de->track = parsed_track; de->count = parsed_count; de->seconds = parsed_seconds; + de->new_action = parsed_new_action; + de->timeout = parsed_timeout; sm = SigMatchAlloc(); if (sm == NULL) { @@ -277,7 +384,10 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) goto error; } - sm->type = DETECT_THRESHOLD; + if (parsed_type == TYPE_RATE) + sm->type = DETECT_DETECTION_FILTER; + else + sm->type = DETECT_THRESHOLD; sm->ctx = (void *)de; SigMatchAppendPacket(s, sm); @@ -312,6 +422,8 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) de->track = parsed_track; de->count = parsed_count; de->seconds = parsed_seconds; + de->new_action = parsed_new_action; + de->timeout = parsed_timeout; sm = SigMatchAlloc(); if (sm == NULL) { @@ -319,7 +431,10 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) goto error; } - sm->type = DETECT_THRESHOLD; + if (parsed_type == TYPE_RATE) + sm->type = DETECT_DETECTION_FILTER; + else + sm->type = DETECT_THRESHOLD; sm->ctx = (void *)de; SigMatchAppendPacket(s, sm); @@ -351,6 +466,8 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) de->track = parsed_track; de->count = parsed_count; de->seconds = parsed_seconds; + de->new_action = parsed_new_action; + de->timeout = parsed_timeout; sm = SigMatchAlloc(); if (sm == NULL) { @@ -358,7 +475,10 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) goto error; } - sm->type = DETECT_THRESHOLD; + if (parsed_type == TYPE_RATE) + sm->type = DETECT_DETECTION_FILTER; + else + sm->type = DETECT_THRESHOLD; sm->ctx = (void *)de; SigMatchAppendPacket(sig, sm); @@ -417,6 +537,53 @@ int SCThresholdConfIsLineBlankOrComment(char *line) return 1; } +/** + * \brief Checks if the rule is multiline, by searching an ending slash + * + * \param line String that has to be checked + * + * \retval the position of the slash making it multiline + * \retval 0 Otherwise + */ +int SCThresholdConfLineIsMultiline(char *line) +{ + int flag = 0; + char *rline = line; + int len = strlen(line); + + while (line < rline + len && *line != '\n') { + /* we have a comment */ + if (*line == '\\') + flag = line - rline; + else + if (!isspace(*line)) + flag = 0; + + line++; + } + + /* we have a blank line */ + return flag; +} + +/** + * \brief Get the config line length to allocate the buffer needed + * + * \param fd Pointer to file descriptor. + * \retval int of the line length + */ +int SCThresholdConfLineLength(FILE *fd) { + int pos = ftell(fd); + int len = 0; + char c; + + while ( (c = fgetc(fd)) && c != '\n' && !feof(fd)) + len++; + + fseek(fd, pos, SEEK_SET); + return len; +} + /** * \brief Parses the Threshold Config file * @@ -425,18 +592,57 @@ int SCThresholdConfIsLineBlankOrComment(char *line) */ void SCThresholdConfParseFile(DetectEngineCtx *de_ctx, FILE *fd) { - char line[1024]; + char *line = NULL; + int len = 0; + char c; + int rule_num = 0; - if(fd == NULL) + /* position of "\", on multiline rules */ + int esc_pos = 0; + + if (fd == NULL) return; - while (fgets(line, sizeof(line), fd) != NULL) { - if (SCThresholdConfIsLineBlankOrComment(line)) - continue; + while (!feof(fd)) { + len = SCThresholdConfLineLength(fd); + + if (len > 0) { + if (line == NULL) + line = SCRealloc(line, len + 1); + else + line = SCRealloc(line, strlen(line) + len + 1); + + if (line == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory"); + break; + } + + if (fgets(line + esc_pos, len + 1, fd) == NULL) break; - SCThresholdConfAddThresholdtype(line, de_ctx); + /* Skip EOL to inspect the next line (or read EOF) */ + c = fgetc(fd); + + if (SCThresholdConfIsLineBlankOrComment(line)) { + continue; + } + + esc_pos = SCThresholdConfLineIsMultiline(line); + if (esc_pos == 0) { + rule_num++; + SCLogDebug("Adding threshold.config rule num %"PRIu32"( %s )", rule_num, line); + SCThresholdConfAddThresholdtype(line, de_ctx); + } + } else { + /* Skip EOL to inspect the next line (or read EOF) */ + c = fgetc(fd); + if (feof(fd)) + break; + } } + /* Free the last line */ + SCFree(line); + return; } @@ -499,6 +705,150 @@ FILE *SCThresholdConfGenerateValidDummyFD03() return fd; } +/** + * \brief Creates a dummy threshold file, with all valid options, but + * with splitted rules (multiline), for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +FILE *SCThresholdConfGenerateValidDummyFD04() +{ + FILE *fd = NULL; + const char *buffer = + "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 1, seconds 60\n" + "threshold gen_id 1, \\\nsig_id 100, type both\\\n, track by_dst, count 10, \\\n seconds 60\n" + "event_filter gen_id 1, sig_id 1000, \\\ntype threshold, track \\\nby_src, count 100, seconds 60\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +FILE *SCThresholdConfGenerateValidDummyFD05() +{ + FILE *fd = NULL; + const char *buffer = + "rate_filter gen_id 1, sig_id 10, track by_src, count 1, seconds 60, new_action drop, timeout 10\n" + "rate_filter gen_id 1, sig_id 100, track by_dst, count 10, seconds 60, new_action pass, timeout 5\n" + "rate_filter gen_id 1, sig_id 1000, track by_rule, count 100, seconds 60, new_action alert, timeout 30\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, but + * with splitted rules (multiline), for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +FILE *SCThresholdConfGenerateValidDummyFD06() +{ + FILE *fd = NULL; + const char *buffer = + "rate_filter \\\ngen_id 1, sig_id 10, track by_src, count 1, seconds 60\\\n, new_action drop, timeout 10\n" + "rate_filter gen_id 1, \\\nsig_id 100, track by_dst, \\\ncount 10, seconds 60, new_action pass, timeout 5\n" + "rate_filter gen_id 1, sig_id 1000, \\\ntrack by_rule, count 100, seconds 60, new_action alert, timeout 30\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, but + * with splitted rules (multiline), for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +FILE *SCThresholdConfGenerateValidDummyFD07() +{ + FILE *fd = NULL; + const char *buffer = + "rate_filter gen_id 1, sig_id 10, track by_src, count 3, seconds 3, new_action drop, timeout 10\n" + "rate_filter gen_id 1, sig_id 11, track by_src, count 3, seconds 1, new_action drop, timeout 5\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, but + * with splitted rules (multiline), for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +FILE *SCThresholdConfGenerateValidDummyFD08() +{ + FILE *fd = NULL; + const char *buffer = + "rate_filter gen_id 1, sig_id 10, track by_rule, count 3, seconds 3, new_action drop, timeout 10\n" + "rate_filter gen_id 1, sig_id 11, track by_src, count 3, seconds 1, new_action drop, timeout 5\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, but + * with splitted rules (multiline), for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +FILE *SCThresholdConfGenerateValidDummyFD09() +{ + FILE *fd = NULL; + const char *buffer = + "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 2, seconds 60\n" + "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 3, \\\n seconds 60\n" + "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 2, seconds 60\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + +/** + * \brief Creates a dummy threshold file, with all valid options, but + * with splitted rules (multiline), for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +FILE *SCThresholdConfGenerateValidDummyFD10() +{ + FILE *fd = NULL; + const char *buffer = + "event_filter gen_id 1 \\\n, sig_id 10, type limit, track by_src, \\\ncount 5, seconds 2\n" + "threshold gen_id 1, \\\nsig_id 11, type threshold\\\n, track by_dst, count 5, \\\n seconds 2\n" + "event_filter gen_id 1, sig_id 12, \\\ntype both, track \\\nby_src, count 5, seconds 2\n"; + + fd = SCFmemopen((void *)buffer, strlen(buffer), "r"); + if (fd == NULL) + SCLogDebug("Error with SCFmemopen() called by Threshold Config test code"); + + return fd; +} + /** * \test Check if the threshold file is loaded and well parsed * @@ -742,6 +1092,561 @@ end: DetectEngineCtxFree(de_ctx); return result; } + +/** + * \test Check if the threshold file is loaded and well parsed + * + * \retval 1 on succces + * \retval 0 on failure + */ +int SCThresholdConfTest06(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + DetectThresholdData *de = NULL; + Signature *sig = NULL; + SigMatch *m = NULL; + int result = 0; + FILE *fd = NULL; + + if (de_ctx == NULL) + return result; + + de_ctx->flags |= DE_QUIET; + + sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + if (sig == NULL) { + goto end; + } + + fd = SCThresholdConfGenerateValidDummyFD04(); + SCThresholdConfInitContext(de_ctx,fd); + + m = SigMatchGetLastSM(sig->match, DETECT_THRESHOLD); + + if(m != NULL) { + de = (DetectThresholdData *)m->ctx; + if(de != NULL && (de->type == TYPE_LIMIT && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) + result = 1; + } + +end: + SigGroupBuild(de_ctx); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +/** + * \test Check if the rate_filter rules are loaded and well parsed + * + * \retval 1 on succces + * \retval 0 on failure + */ +int SCThresholdConfTest07(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + DetectThresholdData *de = NULL; + Signature *sig = NULL; + SigMatch *m = NULL; + int result = 0; + FILE *fd = NULL; + + if (de_ctx == NULL) + return result; + + de_ctx->flags |= DE_QUIET; + + sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + if (sig == NULL) { + goto end; + } + + fd = SCThresholdConfGenerateValidDummyFD05(); + SCThresholdConfInitContext(de_ctx,fd); + + m = SigMatchGetLastSM(sig->match, DETECT_DETECTION_FILTER); + + if(m != NULL) { + de = (DetectThresholdData *)m->ctx; + if(de != NULL && (de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) + result = 1; + } + +end: + SigGroupBuild(de_ctx); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +/** + * \test Check if the rate_filter rules are loaded and well parsed + * with multilines + * + * \retval 1 on succces + * \retval 0 on failure + */ +int SCThresholdConfTest08(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + DetectThresholdData *de = NULL; + Signature *sig = NULL; + SigMatch *m = NULL; + int result = 0; + FILE *fd = NULL; + + if (de_ctx == NULL) + return result; + + de_ctx->flags |= DE_QUIET; + + sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"Threshold limit\"; gid:1; sid:10;)"); + if (sig == NULL) { + goto end; + } + + fd = SCThresholdConfGenerateValidDummyFD06(); + SCThresholdConfInitContext(de_ctx,fd); + + m = SigMatchGetLastSM(sig->match, DETECT_DETECTION_FILTER); + + if(m != NULL) { + de = (DetectThresholdData *)m->ctx; + if(de != NULL && (de->type == TYPE_RATE && de->track == TRACK_SRC && de->count == 1 && de->seconds == 60)) + result = 1; + } + +end: + SigGroupBuild(de_ctx); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + return result; +} + +/** + * \test Check if the rate_filter rules work + * + * \retval 1 on succces + * \retval 0 on failure + */ +int SCThresholdConfTest09(void) +{ + Signature *sig = NULL; + int result = 0; + FILE *fd = NULL; + + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + int alerts = 0; + + memset(&th_v, 0, sizeof(th_v)); + + struct timeval ts; + + memset (&ts, 0, sizeof(struct timeval)); + TimeGet(&ts); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL || p == NULL) + return result; + + de_ctx->flags |= DE_QUIET; + + sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); + if (sig == NULL) { + goto end; + } + + fd = SCThresholdConfGenerateValidDummyFD07(); + SCThresholdConfInitContext(de_ctx,fd); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts = PacketAlertCheck(p, 10); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts += PacketAlertCheck(p, 10); + if (alerts > 0) { + goto end; + result = 0; + } + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts += PacketAlertCheck(p, 10); + if (alerts != 1) { + result = 0; + goto end; + } + + TimeSetIncrementTime(2); + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts += PacketAlertCheck(p, 10); + if (alerts != 2) { + result = 0; + goto end; + } + + TimeSetIncrementTime(10); + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts += PacketAlertCheck(p, 10); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts += PacketAlertCheck(p, 10); + + if (alerts == 2) + result = 1; + +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Check if the rate_filter rules work with track by_rule + * + * \retval 1 on succces + * \retval 0 on failure + */ +int SCThresholdConfTest10(void) +{ + Signature *sig = NULL; + int result = 0; + FILE *fd = NULL; + + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + Packet *p2 = UTHBuildPacketSrcDst((uint8_t*)"lalala", 6, IPPROTO_TCP, "172.26.0.1", "172.26.0.10"); + + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + int alerts = 0; + + memset(&th_v, 0, sizeof(th_v)); + + struct timeval ts; + + memset (&ts, 0, sizeof(struct timeval)); + TimeGet(&ts); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL || p == NULL || p2 == NULL) + return result; + + de_ctx->flags |= DE_QUIET; + + sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"ratefilter test\"; gid:1; sid:10;)"); + if (sig == NULL) { + goto end; + } + + fd = SCThresholdConfGenerateValidDummyFD08(); + SCThresholdConfInitContext(de_ctx,fd); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts = PacketAlertCheck(p, 10); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + alerts += PacketAlertCheck(p2, 10); + if (alerts > 0) { + goto end; + result = 0; + } + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts += PacketAlertCheck(p, 10); + if (alerts != 1) { + result = 0; + goto end; + } + + TimeSetIncrementTime(2); + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p2); + alerts += PacketAlertCheck(p2, 10); + if (alerts != 2) { + result = 0; + goto end; + } + + TimeSetIncrementTime(10); + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts += PacketAlertCheck(p, 10); + + if (alerts == 2) + result = 1; + + /* Ensure that a Threshold entry was installed at the sig */ + if (sig->th_entry == NULL) { + result = 0; + goto end; + } + +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Check if the rate_filter rules work + * + * \retval 1 on succces + * \retval 0 on failure + */ +int SCThresholdConfTest11(void) +{ + Signature *sig = NULL; + int result = 0; + FILE *fd = NULL; + + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + int alerts10 = 0; + int alerts11 = 0; + int alerts12 = 0; + + memset(&th_v, 0, sizeof(th_v)); + + struct timeval ts; + + memset (&ts, 0, sizeof(struct timeval)); + TimeGet(&ts); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL || p == NULL) + return result; + + de_ctx->flags |= DE_QUIET; + + sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); + sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); + sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); + if (sig == NULL) { + goto end; + } + + fd = SCThresholdConfGenerateValidDummyFD09(); + SCThresholdConfInitContext(de_ctx,fd); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + + TimeSetIncrementTime(100); + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + + TimeSetIncrementTime(10); + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + + if (alerts10 == 4) + result = 1; + + /* One on the first interval, another on the second */ + if (alerts11 == 2) + result = 1; + + if (alerts12 == 2) + result = 1; + +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + +/** + * \test Check if the rate_filter rules work + * + * \retval 1 on succces + * \retval 0 on failure + */ +int SCThresholdConfTest12(void) +{ + Signature *sig = NULL; + int result = 0; + FILE *fd = NULL; + + Packet *p = UTHBuildPacket((uint8_t*)"lalala", 6, IPPROTO_TCP); + ThreadVars th_v; + DetectEngineThreadCtx *det_ctx; + int alerts10 = 0; + int alerts11 = 0; + int alerts12 = 0; + + memset(&th_v, 0, sizeof(th_v)); + + struct timeval ts; + + memset (&ts, 0, sizeof(struct timeval)); + TimeGet(&ts); + + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + if (de_ctx == NULL || p == NULL) + return result; + + de_ctx->flags |= DE_QUIET; + + sig = de_ctx->sig_list = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test limit\"; gid:1; sid:10;)"); + sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test threshold\"; gid:1; sid:11;)"); + sig = sig->next = SigInit(de_ctx,"alert tcp any any -> any any (msg:\"event_filter test both\"; gid:1; sid:12;)"); + if (sig == NULL) { + goto end; + } + + fd = SCThresholdConfGenerateValidDummyFD10(); + SCThresholdConfInitContext(de_ctx,fd); + + SigGroupBuild(de_ctx); + DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); + + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + + TimeSetIncrementTime(100); + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + + TimeSetIncrementTime(10); + TimeGet(&p->ts); + + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + SigMatchSignatures(&th_v, de_ctx, det_ctx, p); + alerts10 += PacketAlertCheck(p, 10); + alerts11 += PacketAlertCheck(p, 11); + alerts12 += PacketAlertCheck(p, 12); + + /* Yes, none of the alerts will be out of the count of the given interval for type limit */ + if (alerts10 == 10) + result = 1; + + /* One on the first interval, another on the second */ + if (alerts11 == 1) + result = 1; + + if (alerts12 == 1) + result = 1; + +end: + UTHFreePacket(p); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + + DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); + DetectEngineCtxFree(de_ctx); + + return result; +} + #endif /* UNITTESTS */ /** @@ -755,6 +1660,13 @@ void SCThresholdConfRegisterTests(void) UtRegisterTest("SCThresholdConfTest03", SCThresholdConfTest03, 1); UtRegisterTest("SCThresholdConfTest04", SCThresholdConfTest04, 0); UtRegisterTest("SCThresholdConfTest05", SCThresholdConfTest05, 1); + UtRegisterTest("SCThresholdConfTest06", SCThresholdConfTest06, 1); + UtRegisterTest("SCThresholdConfTest07", SCThresholdConfTest07, 1); + UtRegisterTest("SCThresholdConfTest08", SCThresholdConfTest08, 1); + UtRegisterTest("SCThresholdConfTest09 - rate_filter", SCThresholdConfTest09, 1); + UtRegisterTest("SCThresholdConfTest10 - rate_filter", SCThresholdConfTest10, 1); + UtRegisterTest("SCThresholdConfTest11 - event_filter", SCThresholdConfTest11, 1); + UtRegisterTest("SCThresholdConfTest12 - event_filter", SCThresholdConfTest12, 1); #endif /* UNITTESTS */ }