]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
Split Thresholds and Suppression
authorVictor Julien <victor@inliniac.net>
Thu, 19 Sep 2013 14:16:50 +0000 (16:16 +0200)
committerVictor Julien <victor@inliniac.net>
Tue, 1 Oct 2013 13:52:47 +0000 (15:52 +0200)
Thresholds and suppression can be handled independently. Suppression
only suppresses output, and is not related to Threshold state tracking.

This simplifies mixing suppression and thresholding rules.

Part of the Bug #425 effort.

src/detect-engine-alert.c
src/detect-engine-threshold.c
src/detect-engine-threshold.h
src/detect.h
src/util-threshold-config.c

index bc37347626dd26faff283380837b6884f8cda175..e22bb2d29245d428232530eee7bc48473f9beb1b 100644 (file)
@@ -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);
 }
 
index 1c0bb4c10f4e0ca6b87516063d8ec366fad05caf..ca715a3ce5e76f3ad0c67ab6f94e926381fbc8e2 100644 (file)
@@ -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
  *
index 4ecc4f94aa2ba25a2a2f1d32ba70b3e7eb47c184..141d510a6ebc1e454ac2a5948280a35a438c21e5 100644 (file)
@@ -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 *);
 
index 9645f7e7a86e96e6dab2289131c2f835b31161be..6733d5eaf0509d13dcf5bd9145c83c03d3d29aba 100644 (file)
@@ -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,
 
index e064509056071f49303c3845a8521a2995d2f710..2b17ba2a1dcf9b876d20ebb43658a9e6069d6420 100644 (file)
@@ -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 */
 }