diff --git a/src/detect-engine-alert.c b/src/detect-engine-alert.c index bc37347626..e22bb2d292 100644 --- a/src/detect-engine-alert.c +++ b/src/detect-engine-alert.c @@ -69,27 +69,49 @@ static int PacketAlertHandle(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det SCEnter(); int ret = 1; DetectThresholdData *td = NULL; - SigMatch *sm = NULL; + SigMatch *sm; if (!(PKT_IS_IPV4(p) || PKT_IS_IPV6(p))) { SCReturnInt(1); } - do { - td = SigGetThresholdTypeIter(s, p, &sm); - if (td != NULL) { - SCLogDebug("td %p", td); - - /* PacketAlertThreshold returns 2 if the alert is suppressed but - * we do need to apply rule actions to the packet. */ - ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s); - if (ret == 0 || ret == 2) { - /* It doesn't match threshold, remove it */ - SCReturnInt(ret); + /* handle suppressions first */ + if (s->sm_lists[DETECT_SM_LIST_SUPPRESS] != NULL) { + sm = NULL; + do { + td = SigGetThresholdTypeIter(s, p, &sm, DETECT_SM_LIST_SUPPRESS); + if (td != NULL) { + SCLogDebug("td %p", td); + + /* PacketAlertThreshold returns 2 if the alert is suppressed but + * we do need to apply rule actions to the packet. */ + ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s); + if (ret == 0 || ret == 2) { + /* It doesn't match threshold, remove it */ + SCReturnInt(ret); + } } - } - } while (sm != NULL); + } while (sm != NULL); + } + /* if we're still here, consider thresholding */ + if (s->sm_lists[DETECT_SM_LIST_THRESHOLD] != NULL) { + sm = NULL; + do { + td = SigGetThresholdTypeIter(s, p, &sm, DETECT_SM_LIST_THRESHOLD); + if (td != NULL) { + SCLogDebug("td %p", td); + + /* PacketAlertThreshold returns 2 if the alert is suppressed but + * we do need to apply rule actions to the packet. */ + ret = PacketAlertThreshold(de_ctx, det_ctx, td, p, s); + if (ret == 0 || ret == 2) { + /* It doesn't match threshold, remove it */ + SCReturnInt(ret); + } + } + } while (sm != NULL); + } SCReturnInt(1); } diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index 1c0bb4c10f..ca715a3ce5 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -95,7 +95,7 @@ int ThresholdHostHasThreshold(Host *host) { * * */ -DetectThresholdData *SigGetThresholdTypeIter(Signature *sig, Packet *p, SigMatch **psm) +DetectThresholdData *SigGetThresholdTypeIter(Signature *sig, Packet *p, SigMatch **psm, int list) { SigMatch *sm = NULL; DetectThresholdData *tsh = NULL; @@ -104,7 +104,7 @@ DetectThresholdData *SigGetThresholdTypeIter(Signature *sig, Packet *p, SigMatch return NULL; if (*psm == NULL) { - sm = sig->sm_lists_tail[DETECT_SM_LIST_THRESHOLD]; + sm = sig->sm_lists_tail[list]; } else { /* Iteration in progress, using provided value */ sm = *psm; @@ -127,20 +127,6 @@ DetectThresholdData *SigGetThresholdTypeIter(Signature *sig, Packet *p, SigMatch return NULL; } -/** - * \brief Check if a certain signature has threshold option - * - * \param sig Signature pointer - * \param p Packet structure - * - * \retval tsh Return the threshold data from signature or NULL if not found - */ -DetectThresholdData *SigGetThresholdType(Signature *sig, Packet *p) -{ - SigMatch *psm = NULL; - return SigGetThresholdTypeIter(sig, p, &psm); -} - /** * \brief Remove timeout threshold hash elements * diff --git a/src/detect-engine-threshold.h b/src/detect-engine-threshold.h index 4ecc4f94aa..141d510a6e 100644 --- a/src/detect-engine-threshold.h +++ b/src/detect-engine-threshold.h @@ -31,8 +31,7 @@ int ThresholdHostStorageId(void); int ThresholdHostHasThreshold(Host *); -DetectThresholdData *SigGetThresholdType(Signature *, Packet *); -DetectThresholdData *SigGetThresholdTypeIter(Signature *, Packet *, SigMatch **); +DetectThresholdData *SigGetThresholdTypeIter(Signature *, Packet *, SigMatch **, int list); int PacketAlertThreshold(DetectEngineCtx *, DetectEngineThreadCtx *, DetectThresholdData *, Packet *, Signature *); diff --git a/src/detect.h b/src/detect.h index 9645f7e7a8..6733d5eaf0 100644 --- a/src/detect.h +++ b/src/detect.h @@ -122,7 +122,8 @@ enum { /* list for post match actions: flowbit set, flowint increment, etc */ DETECT_SM_LIST_POSTMATCH, - /* list for alert thresholding */ + /* lists for alert thresholding and suppression */ + DETECT_SM_LIST_SUPPRESS, DETECT_SM_LIST_THRESHOLD, DETECT_SM_LIST_MAX, diff --git a/src/util-threshold-config.c b/src/util-threshold-config.c index e064509056..2b17ba2a1d 100644 --- a/src/util-threshold-config.c +++ b/src/util-threshold-config.c @@ -255,339 +255,376 @@ void SCThresholdConfDeInitContext(DetectEngineCtx *de_ctx, FILE *fd) return; } -/** - * \brief Parses a line from the threshold file and adds it to Thresholdtype - * - * \param rawstr Pointer to the string to be parsed. - * \param de_ctx Pointer to the Detection Engine Context. - * - * \retval 0 On success. - * \retval -1 On failure. +/** \internal + * \brief setup suppress rules + * \retval 0 ok + * \retval -1 error */ -int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) +static int SetupSuppressRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, + uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count, + uint32_t parsed_seconds, uint32_t parsed_timeout, uint8_t parsed_new_action, + const char *th_ip) { - const char *th_rule_type = NULL; - const char *th_gid = NULL; - const char *th_sid = NULL; - const char *th_type = NULL; - 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; - const char *th_ip = NULL; - const char *rule_extend = 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; - DetectThresholdData *de = NULL; + Signature *s = NULL; SigMatch *sm = NULL; - SigMatch *m = NULL; -#define MAX_SUBSTRINGS 30 - int ret = 0; - int ov[MAX_SUBSTRINGS]; - uint32_t id = 0, gid = 0; - ThresholdRuleType rule_type; - int fret = -1; - - if (de_ctx == NULL) - return -1; - - ret = pcre_exec(regex_base, regex_base_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); - if (ret < 4) { - SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); - goto error; - } - - /* retrieve the classtype name */ - ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &th_rule_type); - 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; - } + DetectThresholdData *de = NULL; - ret = pcre_get_substring((char *)rawstr, ov, 30, 4, &rule_extend); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + BUG_ON(parsed_type != TYPE_SUPPRESS); - /* get type of rule */ - if (strncasecmp(th_rule_type,"event_filter",strlen("event_filter")) == 0) { - rule_type = THRESHOLD_TYPE_EVENT_FILTER; - } else if (strncasecmp(th_rule_type,"threshold",strlen("threshold")) == 0) { - rule_type = THRESHOLD_TYPE_THRESHOLD; - } else if (strncasecmp(th_rule_type,"rate",strlen("rate")) == 0) { - rule_type = THRESHOLD_TYPE_RATE; - } else if (strncasecmp(th_rule_type,"suppress",strlen("suppress")) == 0) { - rule_type = THRESHOLD_TYPE_SUPPRESS; - } else { - SCLogError(SC_ERR_INVALID_VALUE, "rule type %s is unknown", th_rule_type); - goto error; - } + /* Install it */ + if (id == 0 && gid == 0) { + if (parsed_track == TRACK_RULE) { + SCLogWarning(SC_ERR_EVENT_ENGINE, "suppressing all rules"); + } - /* get end of rule */ - switch(rule_type) { - case THRESHOLD_TYPE_EVENT_FILTER: - case THRESHOLD_TYPE_THRESHOLD: - if (strlen(rule_extend) > 0) { - ret = pcre_exec(regex_threshold, regex_threshold_study, - rule_extend, strlen(rule_extend), - 0, 0, ov, MAX_SUBSTRINGS); - if (ret < 4) { - SCLogError(SC_ERR_PCRE_MATCH, - "pcre_exec parse error, ret %" PRId32 ", string %s", - ret, rule_extend); - goto error; - } + /* update each sig with our suppress info */ + for (s = de_ctx->sig_list; s != NULL; s = s->next) { + /* tag the rule as noalert */ + if (parsed_track == TRACK_RULE) { + s->flags |= SIG_FLAG_NOALERT; + continue; + } - ret = pcre_get_substring((char *)rule_extend, ov, 30, 1, &th_type); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + de = SCMalloc(sizeof(DetectThresholdData)); + if (unlikely(de == NULL)) + goto error; + memset(de,0,sizeof(DetectThresholdData)); - ret = pcre_get_substring((char *)rule_extend, ov, 30, 2, &th_track); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + de->type = TYPE_SUPPRESS; + de->track = parsed_track; + de->count = parsed_count; + de->seconds = parsed_seconds; + de->new_action = parsed_new_action; + de->timeout = parsed_timeout; + de->addr = NULL; - ret = pcre_get_substring((char *)rule_extend, ov, 30, 3, &th_count); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + if (parsed_track != TRACK_RULE) { + de->addr = DetectAddressInit(); + if (de->addr == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); goto error; } - - ret = pcre_get_substring((char *)rule_extend, ov, 30, 4, &th_seconds); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { + SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); 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; - else { - SCLogError(SC_ERR_INVALID_ARGUMENTS, "limit type not supported: %s", th_type); - goto error; - } - } else { - SCLogError(SC_ERR_INVALID_ARGUMENTS, "rule invalid: %s", rawstr); + sm = SigMatchAlloc(); + if (sm == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch"); goto error; } - break; - case THRESHOLD_TYPE_SUPPRESS: - if (strlen(rule_extend) > 0) { - ret = pcre_exec(regex_suppress, regex_suppress_study, - rule_extend, strlen(rule_extend), - 0, 0, ov, MAX_SUBSTRINGS); - if (ret < 2) { - SCLogError(SC_ERR_PCRE_MATCH, - "pcre_exec parse error, ret %" PRId32 ", string %s", - ret, rule_extend); - goto error; - } - /* retrieve the track mode */ - ret = pcre_get_substring((char *)rule_extend, ov, 30, 1, &th_track); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } - /* retrieve the IP */ - ret = pcre_get_substring((char *)rule_extend, ov, 30, 2, &th_ip); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } - } else { - parsed_track = TRACK_RULE; + + sm->type = DETECT_THRESHOLD; + sm->ctx = (void *)de; + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_SUPPRESS); + } + } else if (id == 0 && gid > 0) { + if (parsed_track == TRACK_RULE) { + SCLogWarning(SC_ERR_EVENT_ENGINE, "suppressing all rules with gid %"PRIu32, gid); + } + /* set up suppression for each signature with a matching gid */ + for (s = de_ctx->sig_list; s != NULL; s = s->next) { + if (s->gid != gid) + continue; + + /* tag the rule as noalert */ + if (parsed_track == TRACK_RULE) { + s->flags |= SIG_FLAG_NOALERT; + continue; } - parsed_type = TYPE_SUPPRESS; - break; - case THRESHOLD_TYPE_RATE: - if (strlen(rule_extend) > 0) { - ret = pcre_exec(regex_rate, regex_rate_study, - rule_extend, strlen(rule_extend), - 0, 0, ov, MAX_SUBSTRINGS); - if (ret < 5) { - SCLogError(SC_ERR_PCRE_MATCH, - "pcre_exec parse error, ret %" PRId32 ", string %s", - ret, rule_extend); - goto error; - } - ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 1, &th_track); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + de = SCMalloc(sizeof(DetectThresholdData)); + if (unlikely(de == NULL)) + goto error; - ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 2, &th_count); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + memset(de,0,sizeof(DetectThresholdData)); - ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 3, &th_seconds); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); - goto error; - } + de->type = TYPE_SUPPRESS; + de->track = parsed_track; + de->count = parsed_count; + de->seconds = parsed_seconds; + de->new_action = parsed_new_action; + de->timeout = parsed_timeout; + de->addr = NULL; - ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 4, &th_new_action); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + if (parsed_track != TRACK_RULE) { + de->addr = DetectAddressInit(); + if (de->addr == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); goto error; } - - ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 5, &th_timeout); - if (ret < 0) { - SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { + SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); goto error; } + } - /* TODO: implement option "apply_to" */ + sm = SigMatchAlloc(); + if (sm == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch"); + goto error; + } - if (ByteExtractStringUint32(&parsed_timeout, 10, strlen(th_timeout), th_timeout) <= 0) { - goto error; - } + sm->type = DETECT_THRESHOLD; + sm->ctx = (void *)de; - /* 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; - } else { - SCLogError(SC_ERR_INVALID_ARGUMENTS, "rule invalid: %s", rawstr); - goto error; + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_SUPPRESS); + } + } else if (id > 0 && gid == 0) { + SCLogError(SC_ERR_INVALID_VALUE, "Can't use a event config that has " + "sid > 0 and gid == 0. Please fix this " + "in your threshold.conf file"); + goto error; + } else { + s = SigFindSignatureBySidGid(de_ctx, id, gid); + if (s == NULL) { + SCLogWarning(SC_ERR_EVENT_ENGINE, "can't suppress sid " + "%"PRIu32", gid %"PRIu32": unknown rule", id, gid); + } else { + if (parsed_track == TRACK_RULE) { + s->flags |= SIG_FLAG_NOALERT; + goto end; } - break; - default: - SCLogError(SC_ERR_PCRE_MATCH, "unable to find rule type for string %s", rawstr); - goto error; - } - switch (rule_type) { - /* This part is common to threshold/event_filter/rate_filter */ - case THRESHOLD_TYPE_EVENT_FILTER: - case THRESHOLD_TYPE_THRESHOLD: - case THRESHOLD_TYPE_RATE: - 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; - else { - SCLogError(SC_ERR_INVALID_VALUE, "Invalid track parameter %s in %s", th_track, rawstr); + de = SCMalloc(sizeof(DetectThresholdData)); + if (unlikely(de == NULL)) goto error; - } + memset(de,0,sizeof(DetectThresholdData)); - if (ByteExtractStringUint32(&parsed_count, 10, strlen(th_count), th_count) <= 0) { + de->type = TYPE_SUPPRESS; + de->track = parsed_track; + de->count = parsed_count; + de->seconds = parsed_seconds; + de->new_action = parsed_new_action; + de->timeout = parsed_timeout; + + de->addr = DetectAddressInit(); + if (de->addr == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); goto error; } - if (parsed_count == 0) { - SCLogError(SC_ERR_INVALID_VALUE, "rate filter count should be > 0"); + if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { + SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); goto error; } - if (ByteExtractStringUint32(&parsed_seconds, 10, strlen(th_seconds), th_seconds) <= 0) { + sm = SigMatchAlloc(); + if (sm == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch"); goto error; } - break; - case THRESHOLD_TYPE_SUPPRESS: - /* need to get IP if extension is provided */ - if (th_track != NULL) { - if (strcasecmp(th_track,"by_dst") == 0) - parsed_track = TRACK_DST; - else if (strcasecmp(th_track,"by_src") == 0) - parsed_track = TRACK_SRC; - else { - SCLogError(SC_ERR_INVALID_VALUE, "Invalid track parameter %s in %s", th_track, rule_extend); - goto error; - } - } - break; - } + sm->type = DETECT_THRESHOLD; + sm->ctx = (void *)de; - if (ByteExtractStringUint32(&id, 10, strlen(th_sid), th_sid) <= 0) { - goto error; + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_SUPPRESS); + } } - if (ByteExtractStringUint32(&gid, 10, strlen(th_gid), th_gid) <= 0) { - goto error; +end: + return 0; +error: + if (de != NULL) { + if (de->addr != NULL) + DetectAddressFree(de->addr); + SCFree(de); } + return -1; +} + +/** \internal + * \brief setup suppress rules + * \retval 0 ok + * \retval -1 error + */ +static int SetupThresholdRule(DetectEngineCtx *de_ctx, uint32_t id, uint32_t gid, + uint8_t parsed_type, uint8_t parsed_track, uint32_t parsed_count, + uint32_t parsed_seconds, uint32_t parsed_timeout, uint8_t parsed_new_action, + const char *th_ip) +{ + Signature *s = NULL; + SigMatch *sm = NULL; + DetectThresholdData *de = NULL; + + BUG_ON(parsed_type == TYPE_SUPPRESS); /* Install it */ if (id == 0 && gid == 0) { - for (s = de_ctx->sig_list; s != NULL;) { - ns = s->next; - if (parsed_type != TYPE_SUPPRESS) { - m = SigMatchGetLastSMFromLists(s, 2, + for (s = de_ctx->sig_list; s != NULL; s = s->next) { + sm = SigMatchGetLastSMFromLists(s, 2, + DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + if (sm != NULL) { + SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " + "an event var set. The signature event var is " + "given precedence over the threshold.conf one. " + "We'll change this in the future though.", s->id); + goto end; + } + + sm = SigMatchGetLastSMFromLists(s, 2, + DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + if (sm != NULL) { + SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " + "an event var set. The signature event var is " + "given precedence over the threshold.conf one. " + "We'll change this in the future though.", s->id); + goto end; + } + + de = SCMalloc(sizeof(DetectThresholdData)); + if (unlikely(de == NULL)) + goto error; + memset(de,0,sizeof(DetectThresholdData)); + + de->type = parsed_type; + de->track = parsed_track; + de->count = parsed_count; + de->seconds = parsed_seconds; + de->new_action = parsed_new_action; + de->timeout = parsed_timeout; + de->addr = NULL; + + sm = SigMatchAlloc(); + if (sm == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch"); + goto error; + } + + if (parsed_type == TYPE_RATE) + sm->type = DETECT_DETECTION_FILTER; + else + sm->type = DETECT_THRESHOLD; + sm->ctx = (void *)de; + + if (parsed_track == TRACK_RULE) { + de_ctx->ths_ctx.th_entry = SCRealloc(de_ctx->ths_ctx.th_entry, (de_ctx->ths_ctx.th_size + 1) * sizeof(DetectThresholdEntry *)); + if (de_ctx->ths_ctx.th_entry == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for threshold config" + " (tried to allocate %"PRIu32"th_entrys for rule tracking with rate_filter)", de_ctx->ths_ctx.th_size + 1); + } else { + de_ctx->ths_ctx.th_entry[de_ctx->ths_ctx.th_size] = NULL; + de_ctx->ths_ctx.th_size++; + } + } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); + } + + } else if (id == 0 && gid > 0) { + for (s = de_ctx->sig_list; s != NULL; s = s->next) { + if (s->gid == gid) { + sm = SigMatchGetLastSMFromLists(s, 2, + DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + if (sm != NULL) { + SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " + "an event var set. The signature event var is " + "given precedence over the threshold.conf one. " + "We'll change this in the future though.", id); + goto end; + } + + sm = SigMatchGetLastSMFromLists(s, 2, + DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + if (sm != NULL) { + SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " + "an event var set. The signature event var is " + "given precedence over the threshold.conf one. " + "We'll change this in the future though.", id); + goto end; + } + + de = SCMalloc(sizeof(DetectThresholdData)); + if (unlikely(de == NULL)) + goto error; + memset(de,0,sizeof(DetectThresholdData)); + + de->type = parsed_type; + de->track = parsed_track; + de->count = parsed_count; + de->seconds = parsed_seconds; + de->new_action = parsed_new_action; + de->timeout = parsed_timeout; + de->addr = NULL; + + sm = SigMatchAlloc(); + if (sm == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch"); + goto error; + } + + if (parsed_type == TYPE_RATE) + sm->type = DETECT_DETECTION_FILTER; + else + sm->type = DETECT_THRESHOLD; + sm->ctx = (void *)de; + + if (parsed_track == TRACK_RULE) { + de_ctx->ths_ctx.th_entry = SCRealloc(de_ctx->ths_ctx.th_entry, (de_ctx->ths_ctx.th_size + 1) * sizeof(DetectThresholdEntry *)); + if (de_ctx->ths_ctx.th_entry == NULL) { + SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for threshold config" + " (tried to allocate %"PRIu32"th_entrys for rule tracking with rate_filter)", de_ctx->ths_ctx.th_size + 1); + } else { + de_ctx->ths_ctx.th_entry[de_ctx->ths_ctx.th_size] = NULL; + de_ctx->ths_ctx.th_size++; + } + } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); + } + } + } else if (id > 0 && gid == 0) { + SCLogError(SC_ERR_INVALID_VALUE, "Can't use a event config that has " + "sid > 0 and gid == 0. Please fix this " + "in your threshold.conf file"); + } else { + s = SigFindSignatureBySidGid(de_ctx, id, gid); + if (s == NULL) { + SCLogWarning(SC_ERR_EVENT_ENGINE, "can't suppress sid " + "%"PRIu32", gid %"PRIu32": unknown rule", id, gid); + } else { + if (parsed_type != TYPE_SUPPRESS && parsed_type != TYPE_THRESHOLD && + parsed_type != TYPE_BOTH && parsed_type != TYPE_LIMIT) + { + sm = SigMatchGetLastSMFromLists(s, 2, DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); - - if (m != NULL) { + if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " - "an event var set. The signature event var is " - "given precedence over the threshold.conf one. " - "We'll change this in the future though.", s->id); + "a threshold set. The signature event var is " + "given precedence over the threshold.conf one. " + "Bug #425.", s->id); goto end; } - m = SigMatchGetLastSMFromLists(s, 2, + sm = SigMatchGetLastSMFromLists(s, 2, DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); - - if (m != NULL) { + if (sm != NULL) { SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " - "an event var set. The signature event var is " - "given precedence over the threshold.conf one. " - "We'll change this in the future though.", s->id); + "a detection_filter set. The signature event var is " + "given precedence over the threshold.conf one. " + "Bug #425.", s->id); goto end; } + + /* replace threshold on sig if we have a global override for it */ +#if 1 + } else if (parsed_type == TYPE_THRESHOLD || parsed_type == TYPE_BOTH || parsed_type == TYPE_LIMIT) { + sm = SigMatchGetLastSMFromLists(s, 2, + DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + if (sm == NULL) { + sm = SigMatchGetLastSMFromLists(s, 2, + DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + } + if (sm != NULL) { + SigMatchRemoveSMFromList(s, sm, DETECT_SM_LIST_THRESHOLD); + SigMatchFree(sm); + sm = NULL; + } +#endif } de = SCMalloc(sizeof(DetectThresholdData)); if (unlikely(de == NULL)) goto error; - memset(de,0,sizeof(DetectThresholdData)); de->type = parsed_type; @@ -598,18 +635,6 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) de->timeout = parsed_timeout; de->addr = NULL; - if ((parsed_type == TYPE_SUPPRESS) && (parsed_track != TRACK_RULE)) { - de->addr = DetectAddressInit(); - if (de->addr == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); - goto error; - } - if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { - SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); - goto error; - } - } - sm = SigMatchAlloc(); if (sm == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch"); @@ -632,215 +657,351 @@ int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) de_ctx->ths_ctx.th_size++; } } + SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); - s = ns; } + } +end: + return 0; +error: + if (de != NULL) { + if (de->addr != NULL) + DetectAddressFree(de->addr); + SCFree(de); + } + return -1; +} - } else if (id == 0 && gid > 0) { - for (s = de_ctx->sig_list; s != NULL;) { - ns = s->next; - - if(s->gid == gid) { - if (parsed_type != TYPE_SUPPRESS) { - m = SigMatchGetLastSMFromLists(s, 2, - DETECT_THRESHOLD, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); - - if (m != NULL) { - SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " - "an event var set. The signature event var is " - "given precedence over the threshold.conf one. " - "We'll change this in the future though.", id); - goto end; - } +/** + * \brief Parses a line from the threshold file and adds it to Thresholdtype + * + * \param rawstr Pointer to the string to be parsed. + * \param de_ctx Pointer to the Detection Engine Context. + * + * \retval 0 On success. + * \retval -1 On failure. + */ +int SCThresholdConfAddThresholdtype(char *rawstr, DetectEngineCtx *de_ctx) +{ + const char *th_rule_type = NULL; + const char *th_gid = NULL; + const char *th_sid = NULL; + const char *th_type = NULL; + 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; + const char *th_ip = NULL; + const char *rule_extend = NULL; - m = SigMatchGetLastSMFromLists(s, 2, - DETECT_DETECTION_FILTER, s->sm_lists[DETECT_SM_LIST_THRESHOLD]); + 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; - if (m != NULL) { - SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " - "an event var set. The signature event var is " - "given precedence over the threshold.conf one. " - "We'll change this in the future though.", id); - goto end; - } - } +#define MAX_SUBSTRINGS 30 + int ret = 0; + int ov[MAX_SUBSTRINGS]; + uint32_t id = 0, gid = 0; + ThresholdRuleType rule_type; + int fret = -1; - de = SCMalloc(sizeof(DetectThresholdData)); - if (unlikely(de == NULL)) - goto error; + if (de_ctx == NULL) + return -1; - memset(de,0,sizeof(DetectThresholdData)); + ret = pcre_exec(regex_base, regex_base_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); + if (ret < 4) { + SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr); + goto error; + } - de->type = parsed_type; - de->track = parsed_track; - de->count = parsed_count; - de->seconds = parsed_seconds; - de->new_action = parsed_new_action; - de->timeout = parsed_timeout; - de->addr = NULL; + /* retrieve the classtype name */ + ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &th_rule_type); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - if ((parsed_type == TYPE_SUPPRESS) && (parsed_track != TRACK_RULE)) { - de->addr = DetectAddressInit(); - if (de->addr == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); - goto error; - } - if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { - SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); - 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; + } - sm = SigMatchAlloc(); - if (sm == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch"); + 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, &rule_extend); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + + /* get type of rule */ + if (strncasecmp(th_rule_type,"event_filter",strlen("event_filter")) == 0) { + rule_type = THRESHOLD_TYPE_EVENT_FILTER; + } else if (strncasecmp(th_rule_type,"threshold",strlen("threshold")) == 0) { + rule_type = THRESHOLD_TYPE_THRESHOLD; + } else if (strncasecmp(th_rule_type,"rate",strlen("rate")) == 0) { + rule_type = THRESHOLD_TYPE_RATE; + } else if (strncasecmp(th_rule_type,"suppress",strlen("suppress")) == 0) { + rule_type = THRESHOLD_TYPE_SUPPRESS; + } else { + SCLogError(SC_ERR_INVALID_VALUE, "rule type %s is unknown", th_rule_type); + goto error; + } + + /* get end of rule */ + switch(rule_type) { + case THRESHOLD_TYPE_EVENT_FILTER: + case THRESHOLD_TYPE_THRESHOLD: + if (strlen(rule_extend) > 0) { + ret = pcre_exec(regex_threshold, regex_threshold_study, + rule_extend, strlen(rule_extend), + 0, 0, ov, MAX_SUBSTRINGS); + if (ret < 4) { + SCLogError(SC_ERR_PCRE_MATCH, + "pcre_exec parse error, ret %" PRId32 ", string %s", + ret, rule_extend); goto error; } - if (parsed_type == TYPE_RATE) - sm->type = DETECT_DETECTION_FILTER; - else - sm->type = DETECT_THRESHOLD; - sm->ctx = (void *)de; + ret = pcre_get_substring((char *)rule_extend, ov, 30, 1, &th_type); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - if (parsed_track == TRACK_RULE) { - de_ctx->ths_ctx.th_entry = SCRealloc(de_ctx->ths_ctx.th_entry, (de_ctx->ths_ctx.th_size + 1) * sizeof(DetectThresholdEntry *)); - if (de_ctx->ths_ctx.th_entry == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for threshold config" - " (tried to allocate %"PRIu32"th_entrys for rule tracking with rate_filter)", de_ctx->ths_ctx.th_size + 1); - } else { - de_ctx->ths_ctx.th_entry[de_ctx->ths_ctx.th_size] = NULL; - de_ctx->ths_ctx.th_size++; - } + ret = pcre_get_substring((char *)rule_extend, ov, 30, 2, &th_track); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; } - SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_THRESHOLD); - } - s = ns; - } - } else if (id > 0 && gid == 0) { - SCLogError(SC_ERR_INVALID_VALUE, "Can't use a event config that has " - "sid > 0 and gid == 0. Please fix this " - "in your threshold.conf file"); - } else { - sig = SigFindSignatureBySidGid(de_ctx,id,gid); - if(sig != NULL) { - if ((parsed_type == TYPE_SUPPRESS) && (parsed_track == TRACK_RULE)) { - sig->flags |= SIG_FLAG_NOALERT; - goto end; - } + ret = pcre_get_substring((char *)rule_extend, ov, 30, 3, &th_count); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - if (parsed_type != TYPE_SUPPRESS && parsed_type != TYPE_THRESHOLD && - parsed_type != TYPE_BOTH && parsed_type != TYPE_LIMIT) - { - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + ret = pcre_get_substring((char *)rule_extend, ov, 30, 4, &th_seconds); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - if (m != NULL) { - SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " - "a threshold set. The signature event var is " - "given precedence over the threshold.conf one. " - "Bug #425.", sig->id); - goto end; + 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; + else { + SCLogError(SC_ERR_INVALID_ARGUMENTS, "limit type not supported: %s", th_type); + goto error; + } + } else { + SCLogError(SC_ERR_INVALID_ARGUMENTS, "rule invalid: %s", rawstr); + goto error; + } + break; + case THRESHOLD_TYPE_SUPPRESS: + if (strlen(rule_extend) > 0) { + ret = pcre_exec(regex_suppress, regex_suppress_study, + rule_extend, strlen(rule_extend), + 0, 0, ov, MAX_SUBSTRINGS); + if (ret < 2) { + SCLogError(SC_ERR_PCRE_MATCH, + "pcre_exec parse error, ret %" PRId32 ", string %s", + ret, rule_extend); + goto error; + } + /* retrieve the track mode */ + ret = pcre_get_substring((char *)rule_extend, ov, 30, 1, &th_track); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + /* retrieve the IP */ + ret = pcre_get_substring((char *)rule_extend, ov, 30, 2, &th_ip); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } + } else { + parsed_track = TRACK_RULE; + } + parsed_type = TYPE_SUPPRESS; + break; + case THRESHOLD_TYPE_RATE: + if (strlen(rule_extend) > 0) { + ret = pcre_exec(regex_rate, regex_rate_study, + rule_extend, strlen(rule_extend), + 0, 0, ov, MAX_SUBSTRINGS); + if (ret < 5) { + SCLogError(SC_ERR_PCRE_MATCH, + "pcre_exec parse error, ret %" PRId32 ", string %s", + ret, rule_extend); + goto error; } - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_DETECTION_FILTER, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); - - if (m != NULL) { - SCLogWarning(SC_ERR_EVENT_ENGINE, "signature sid:%"PRIu32 " has " - "a detection_filter set. The signature event var is " - "given precedence over the threshold.conf one. " - "Bug #425.", sig->id); - goto end; + ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 1, &th_track); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; } - /* replace threshold on sig if we have a global override for it */ - } else if (parsed_type == TYPE_THRESHOLD || parsed_type == TYPE_BOTH || parsed_type == TYPE_LIMIT) { - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); - if (m == NULL) { - m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_DETECTION_FILTER, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 2, &th_count); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; } - if (m != NULL) { - SigMatchRemoveSMFromList(sig, m, DETECT_SM_LIST_THRESHOLD); - SigMatchFree(m); - m = NULL; + + ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 3, &th_seconds); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; } - } - de = SCMalloc(sizeof(DetectThresholdData)); - if (unlikely(de == NULL)) - goto error; + ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 4, &th_new_action); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - memset(de,0,sizeof(DetectThresholdData)); + ret = pcre_get_substring((char *)rule_extend, ov, MAX_SUBSTRINGS, 5, &th_timeout); + if (ret < 0) { + SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); + goto error; + } - de->type = parsed_type; - de->track = parsed_track; - de->count = parsed_count; - de->seconds = parsed_seconds; - de->new_action = parsed_new_action; - de->timeout = parsed_timeout; - de->addr = NULL; + /* TODO: implement option "apply_to" */ - if ((parsed_type == TYPE_SUPPRESS) && (parsed_track != TRACK_RULE)) { - de->addr = DetectAddressInit(); - if (de->addr == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Can't init DetectAddress"); + if (ByteExtractStringUint32(&parsed_timeout, 10, strlen(th_timeout), th_timeout) <= 0) { goto error; } - if (DetectAddressParseString(de->addr, (char *)th_ip) < 0) { - SCLogError(SC_ERR_INVALID_IP_NETBLOCK, "Can't add %s to address group", th_ip); - 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; + } else { + SCLogError(SC_ERR_INVALID_ARGUMENTS, "rule invalid: %s", rawstr); + goto error; } + break; + default: + SCLogError(SC_ERR_PCRE_MATCH, "unable to find rule type for string %s", rawstr); + goto error; + } - sm = SigMatchAlloc(); - if (sm == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating SigMatch"); + switch (rule_type) { + /* This part is common to threshold/event_filter/rate_filter */ + case THRESHOLD_TYPE_EVENT_FILTER: + case THRESHOLD_TYPE_THRESHOLD: + case THRESHOLD_TYPE_RATE: + 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; + else { + SCLogError(SC_ERR_INVALID_VALUE, "Invalid track parameter %s in %s", th_track, rawstr); goto error; } - if (parsed_type == TYPE_RATE) - sm->type = DETECT_DETECTION_FILTER; - else - sm->type = DETECT_THRESHOLD; - sm->ctx = (void *)de; + if (ByteExtractStringUint32(&parsed_count, 10, strlen(th_count), th_count) <= 0) { + goto error; + } + if (parsed_count == 0) { + SCLogError(SC_ERR_INVALID_VALUE, "rate filter count should be > 0"); + goto error; + } - if (parsed_track == TRACK_RULE) { - de_ctx->ths_ctx.th_entry = SCRealloc(de_ctx->ths_ctx.th_entry, (de_ctx->ths_ctx.th_size + 1) * sizeof(DetectThresholdEntry *)); - if (de_ctx->ths_ctx.th_entry == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for threshold config" - " (tried to allocate %"PRIu32"th_entrys for rule tracking with rate_filter)", de_ctx->ths_ctx.th_size + 1); - } else { - de_ctx->ths_ctx.th_entry[de_ctx->ths_ctx.th_size] = NULL; - de_ctx->ths_ctx.th_size++; + if (ByteExtractStringUint32(&parsed_seconds, 10, strlen(th_seconds), th_seconds) <= 0) { + goto error; + } + + break; + case THRESHOLD_TYPE_SUPPRESS: + /* need to get IP if extension is provided */ + if (th_track != NULL) { + if (strcasecmp(th_track,"by_dst") == 0) + parsed_track = TRACK_DST; + else if (strcasecmp(th_track,"by_src") == 0) + parsed_track = TRACK_SRC; + else { + SCLogError(SC_ERR_INVALID_VALUE, "Invalid track parameter %s in %s", th_track, rule_extend); + goto error; } } + break; + } - SigMatchAppendSMToList(sig, sm, DETECT_SM_LIST_THRESHOLD); - } + if (ByteExtractStringUint32(&id, 10, strlen(th_sid), th_sid) <= 0) { + goto error; + } + + if (ByteExtractStringUint32(&gid, 10, strlen(th_gid), th_gid) <= 0) { + goto error; + } + + int r = 0; + if (parsed_type == TYPE_SUPPRESS) { + r = SetupSuppressRule(de_ctx, id, gid, parsed_type, parsed_track, + parsed_count, parsed_seconds, parsed_timeout, parsed_new_action, + th_ip); + } else { + r = SetupThresholdRule(de_ctx, id, gid, parsed_type, parsed_track, + parsed_count, parsed_seconds, parsed_timeout, parsed_new_action, + th_ip); + } + if (r < 0) { + goto error; } -end: fret = 0; error: - if (fret == -1) { - if (de != NULL) { - if (de->addr != NULL) DetectAddressFree(de->addr); - SCFree(de); - } - } - if(th_rule_type != NULL) SCFree((char *)th_rule_type); - if(th_sid != NULL) SCFree((char *)th_sid); - if(th_gid != NULL) SCFree((char *)th_gid); - if(th_track != NULL) SCFree((char *)th_track); - if(th_count != NULL) SCFree((char *)th_count); - if(th_seconds != NULL) SCFree((char *)th_seconds); - if(th_type != NULL) SCFree((char *)th_type); - if(th_ip != NULL) SCFree((char *)th_ip); - if(rule_extend != NULL) SCFree((char *)rule_extend); + if (th_rule_type != NULL) + SCFree((char *)th_rule_type); + if (th_sid != NULL) + SCFree((char *)th_sid); + if (th_gid != NULL) + SCFree((char *)th_gid); + if (th_track != NULL) + SCFree((char *)th_track); + if (th_count != NULL) + SCFree((char *)th_count); + if (th_seconds != NULL) + SCFree((char *)th_seconds); + if (th_type != NULL) + SCFree((char *)th_type); + if (th_ip != NULL) + SCFree((char *)th_ip); + if (rule_extend != NULL) + SCFree((char *)rule_extend); return fret; } @@ -2092,9 +2253,9 @@ int SCThresholdConfTest13(void) SCThresholdConfInitContext(de_ctx,fd); m = SigMatchGetLastSMFromLists(sig, 2, - DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_THRESHOLD]); + DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_SUPPRESS]); - if(m != NULL) { + if (m != NULL) { de = (DetectThresholdData *)m->ctx; if(de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) result = 1; @@ -2429,11 +2590,11 @@ static int SCThresholdConfTest18(void) SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); - if (s->sm_lists[DETECT_SM_LIST_THRESHOLD] == NULL) { + if (s->sm_lists[DETECT_SM_LIST_SUPPRESS] == NULL) { printf("no thresholds: "); goto end; } - sm = s->sm_lists[DETECT_SM_LIST_THRESHOLD]; + sm = s->sm_lists[DETECT_SM_LIST_SUPPRESS]; if (sm == NULL) { printf("no sm: "); goto end; @@ -2504,11 +2665,11 @@ static int SCThresholdConfTest19(void) SCThresholdConfInitContext(de_ctx,fd); SigGroupBuild(de_ctx); - if (s->sm_lists[DETECT_SM_LIST_THRESHOLD] == NULL) { + if (s->sm_lists[DETECT_SM_LIST_SUPPRESS] == NULL) { printf("no thresholds: "); goto end; } - sm = s->sm_lists[DETECT_SM_LIST_THRESHOLD]; + sm = s->sm_lists[DETECT_SM_LIST_SUPPRESS]; if (sm == NULL) { printf("no sm: "); goto end; @@ -2531,6 +2692,145 @@ end: return result; } +/** + * \brief Creates a dummy threshold file, with all valid options, for testing purposes. + * + * \retval fd Pointer to file descriptor. + */ +FILE *SCThresholdConfGenerateValidDummyFD20() +{ + FILE *fd = NULL; + const char *buffer = + "suppress gen_id 1, sig_id 1000, track by_src, ip 2.2.3.4\n" + "suppress gen_id 1, sig_id 1000, track by_src, ip 1.2.3.4\n" + "suppress gen_id 1, sig_id 1000, track by_src, ip 192.168.1.1\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 + * + * \retval 1 on succces + * \retval 0 on failure + */ +static int SCThresholdConfTest20(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + DetectThresholdData *de = NULL; + Signature *sig = NULL; + SigMatch *m = NULL; + int result = 0; + FILE *fd = NULL; + + HostInitConfig(HOST_QUIET); + + 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\"; content:\"abc\"; sid:1000;)"); + if (sig == NULL) { + goto end; + } + + fd = SCThresholdConfGenerateValidDummyFD20(); + SCThresholdConfInitContext(de_ctx,fd); + + m = SigMatchGetLastSMFromLists(sig, 2, + DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_SUPPRESS]); + if (m != NULL) { + de = (DetectThresholdData *)m->ctx; + if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { + m = m->next; + if (m != NULL) { + de = (DetectThresholdData *)m->ctx; + if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { + m = m->next; + if (m != NULL) { + de = (DetectThresholdData *)m->ctx; + if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { + result = 1; + } + } + } + } + } + } +end: + SigGroupBuild(de_ctx); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + HostShutdown(); + return result; +} + +/** + * \test Check if the threshold file is loaded and well parsed, and applied + * correctly to a rule with thresholding + * + * \retval 1 on succces + * \retval 0 on failure + */ +static int SCThresholdConfTest21(void) +{ + DetectEngineCtx *de_ctx = DetectEngineCtxInit(); + DetectThresholdData *de = NULL; + Signature *sig = NULL; + SigMatch *m = NULL; + int result = 0; + FILE *fd = NULL; + + HostInitConfig(HOST_QUIET); + + 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\"; content:\"abc\"; threshold: type limit, track by_dst, count 5, seconds 60; sid:1000;)"); + if (sig == NULL) { + goto end; + } + + fd = SCThresholdConfGenerateValidDummyFD20(); + SCThresholdConfInitContext(de_ctx,fd); + + m = SigMatchGetLastSMFromLists(sig, 2, + DETECT_THRESHOLD, sig->sm_lists[DETECT_SM_LIST_SUPPRESS]); + if (m != NULL) { + de = (DetectThresholdData *)m->ctx; + if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { + m = m->next; + if (m != NULL) { + de = (DetectThresholdData *)m->ctx; + if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { + m = m->next; + if (m != NULL) { + de = (DetectThresholdData *)m->ctx; + if (de != NULL && (de->type == TYPE_SUPPRESS && de->track == TRACK_SRC)) { + result = 1; + } + } + } + } + } + } +end: + SigGroupBuild(de_ctx); + SigGroupCleanup(de_ctx); + SigCleanSignatures(de_ctx); + DetectEngineCtxFree(de_ctx); + HostShutdown(); + return result; +} + #endif /* UNITTESTS */ /** @@ -2559,6 +2859,8 @@ void SCThresholdConfRegisterTests(void) UtRegisterTest("SCThresholdConfTest18 - suppress parsing", SCThresholdConfTest18, 1); UtRegisterTest("SCThresholdConfTest19 - suppress parsing", SCThresholdConfTest19, 1); + UtRegisterTest("SCThresholdConfTest20 - suppress parsing", SCThresholdConfTest20, 1); + UtRegisterTest("SCThresholdConfTest21 - suppress parsing", SCThresholdConfTest21, 1); #endif /* UNITTESTS */ }