]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
detect/threshold: Refactor threshold calculation to handle by_rule and by_both.
authorTodd Mortimer <todd@opennet.ca>
Mon, 30 Mar 2020 23:45:50 +0000 (23:45 +0000)
committerVictor Julien <victor@inliniac.net>
Tue, 7 Apr 2020 05:40:51 +0000 (07:40 +0200)
The only difference between threshold calculations for by_src/by_dst,
by_rule or by_both is which table stores the DetectThresholdEntry.
Refactor the ThresholdHandlePacket* functions to do table lookup and
storage individually, but calculate thresholds in a common function.

src/detect-engine-threshold.c
src/detect-threshold.h

index c4229bd2cc14f6eca32121fe7cf948355afe67ed..95f50463e1ef0bc37d8419545f0b28ace119e940 100644 (file)
@@ -174,7 +174,7 @@ static DetectThresholdEntry* ThresholdTimeoutCheck(DetectThresholdEntry *head, s
         /* check if the 'check' timestamp is not before the creation ts.
          * This can happen due to the async nature of the host timeout
          * code that also calls this code from a management thread. */
-        if (((uint32_t)tv->tv_sec < tmp->tv_sec1) || (tv->tv_sec - tmp->tv_sec1) <= tmp->seconds) {
+        if (TIMEVAL_EARLIER(*tv, tmp->tv1) || TIMEVAL_DIFF_SEC(*tv, tmp->tv1) <= tmp->seconds) {
             prev = tmp;
             tmp = tmp->next;
             continue;
@@ -333,14 +333,14 @@ static inline void RateFilterSetAction(Packet *p, PacketAlert *pa, uint8_t new_a
 * \retval int 1 if threshold reached for this entry
 *
 */
-static int IsThresholdReached(DetectThresholdEntry* lookup_tsh, const DetectThresholdData *td, uint32_t packet_time)
+static int IsThresholdReached(DetectThresholdEntry* lookup_tsh, const DetectThresholdData *td, struct timeval packet_time)
 {
     int ret = 0;
 
     /* Check if we have a timeout enabled, if so,
     * we still matching (and enabling the new_action) */
     if (lookup_tsh->tv_timeout != 0) {
-        if ((packet_time - lookup_tsh->tv_timeout) > td->timeout) {
+        if ((packet_time.tv_sec - lookup_tsh->tv_timeout) > td->timeout) {
             /* Ok, we are done, timeout reached */
             lookup_tsh->tv_timeout = 0;
         }
@@ -352,17 +352,17 @@ static int IsThresholdReached(DetectThresholdEntry* lookup_tsh, const DetectThre
     }
     else {
         /* Update the matching state with the timeout interval */
-        if ((packet_time - lookup_tsh->tv_sec1) < td->seconds) {
+        if (TIMEVAL_DIFF_SEC(packet_time, lookup_tsh->tv1) < td->seconds) {
             lookup_tsh->current_count++;
             if (lookup_tsh->current_count > td->count) {
                 /* Then we must enable the new action by setting a
                 * timeout */
-                lookup_tsh->tv_timeout = packet_time;
+                lookup_tsh->tv_timeout = packet_time.tv_sec;
                 ret = 1;
             }
         }
         else {
-            lookup_tsh->tv_sec1 = packet_time;
+            lookup_tsh->tv1 = packet_time;
             lookup_tsh->current_count = 1;
         }
     } /* else - if (lookup_tsh->tv_timeout != 0) */
@@ -370,79 +370,49 @@ static int IsThresholdReached(DetectThresholdEntry* lookup_tsh, const DetectThre
     return ret;
 }
 
-static void AddEntryToHostStorage(Host *h, DetectThresholdEntry *e, uint32_t packet_time)
+static void AddEntryToHostStorage(Host *h, DetectThresholdEntry *e, struct timeval packet_time)
 {
     if (h && e) {
         e->current_count = 1;
-        e->tv_sec1 = packet_time;
+        e->tv1 = packet_time;
         e->tv_timeout = 0;
         e->next = HostGetStorageById(h, host_threshold_id);
         HostSetStorageById(h, host_threshold_id, e);
     }
 }
 
-static void AddEntryToIPPairStorage(IPPair *pair, DetectThresholdEntry *e, uint32_t packet_time)
+static void AddEntryToIPPairStorage(IPPair *pair, DetectThresholdEntry *e, struct timeval packet_time)
 {
     if (pair && e) {
         e->current_count = 1;
-        e->tv_sec1 = packet_time;
+        e->tv1 = packet_time;
         e->tv_timeout = 0;
         e->next = IPPairGetStorageById(pair, ippair_threshold_id);
         IPPairSetStorageById(pair, ippair_threshold_id, e);
     }
 }
 
-static int ThresholdHandlePacketIPPair(IPPair *pair, Packet *p, const DetectThresholdData *td,
-    uint32_t sid, uint32_t gid, PacketAlert *pa)
-{
-    int ret = 0;
-
-    DetectThresholdEntry *lookup_tsh = ThresholdIPPairLookupEntry(pair, sid, gid);
-    SCLogDebug("ippair lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid);
-
-    switch (td->type) {
-        case TYPE_RATE:
-        {
-            SCLogDebug("rate_filter");
-            ret = 1;
-            if (lookup_tsh && IsThresholdReached(lookup_tsh, td, p->ts.tv_sec)) {
-                RateFilterSetAction(p, pa, td->new_action);
-            } else if (!lookup_tsh) {
-                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
-                AddEntryToIPPairStorage(pair, e, p->ts.tv_sec);
-            }
-            break;
-        }
-        default:
-        {
-            SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type);
-            break;
-        }
-    }
-
-    return ret;
-}
-
 /**
  *  \retval 2 silent match (no alert but apply actions)
  *  \retval 1 normal match
  *  \retval 0 no match
+ *
+ *  If a new DetectThresholdEntry is generated to track the threshold
+ *  for this rule, then it will be returned in new_tsh.
  */
-static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdData *td,
+static int ThresholdHandlePacket(Packet *p, DetectThresholdEntry *lookup_tsh,
+        DetectThresholdEntry **new_tsh, const DetectThresholdData *td,
         uint32_t sid, uint32_t gid, PacketAlert *pa)
 {
     int ret = 0;
 
-    DetectThresholdEntry *lookup_tsh = ThresholdHostLookupEntry(h, sid, gid);
-    SCLogDebug("lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid);
-
     switch(td->type)   {
         case TYPE_LIMIT:
         {
             SCLogDebug("limit");
 
             if (lookup_tsh != NULL)  {
-                if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
+                if (TIMEVAL_DIFF_SEC(p->ts, lookup_tsh->tv1) < td->seconds) {
                     lookup_tsh->current_count++;
 
                     if (lookup_tsh->current_count <= td->count) {
@@ -451,24 +421,15 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
                         ret = 2;
                     }
                 } else    {
-                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
+                    lookup_tsh->tv1 = p->ts;
                     lookup_tsh->current_count = 1;
 
                     ret = 1;
                 }
             } else {
-                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
-                if (e == NULL) {
-                    break;
-                }
-
-                e->tv_sec1 = p->ts.tv_sec;
-                e->current_count = 1;
+                *new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
 
                 ret = 1;
-
-                e->next = HostGetStorageById(h, host_threshold_id);
-                HostSetStorageById(h, host_threshold_id, e);
             }
             break;
         }
@@ -477,7 +438,7 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
             SCLogDebug("threshold");
 
             if (lookup_tsh != NULL)  {
-                if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
+                if (TIMEVAL_DIFF_SEC(p->ts, lookup_tsh->tv1) < td->seconds) {
                     lookup_tsh->current_count++;
 
                     if (lookup_tsh->current_count >= td->count) {
@@ -485,23 +446,14 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
                         lookup_tsh->current_count = 0;
                     }
                 } else {
-                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
+                    lookup_tsh->tv1 = p->ts;
                     lookup_tsh->current_count = 1;
                 }
             } else {
                 if (td->count == 1)  {
                     ret = 1;
                 } else {
-                    DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
-                    if (e == NULL) {
-                        break;
-                    }
-
-                    e->current_count = 1;
-                    e->tv_sec1 = p->ts.tv_sec;
-
-                    e->next = HostGetStorageById(h, host_threshold_id);
-                    HostSetStorageById(h, host_threshold_id, e);
+                    *new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
                 }
             }
             break;
@@ -511,7 +463,7 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
             SCLogDebug("both");
 
             if (lookup_tsh != NULL) {
-                if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
+                if (TIMEVAL_DIFF_SEC(p->ts, lookup_tsh->tv1) < td->seconds) {
                     /* within time limit */
 
                     lookup_tsh->current_count++;
@@ -523,7 +475,7 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
                     }
                 } else {
                     /* expired, so reset */
-                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
+                    lookup_tsh->tv1 = p->ts;
                     lookup_tsh->current_count = 1;
 
                     /* if we have a limit of 1, this is a match */
@@ -532,16 +484,7 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
                     }
                 }
             } else {
-                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
-                if (e == NULL) {
-                    break;
-                }
-
-                e->current_count = 1;
-                e->tv_sec1 = p->ts.tv_sec;
-
-                e->next = HostGetStorageById(h, host_threshold_id);
-                HostSetStorageById(h, host_threshold_id, e);
+                *new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
 
                 /* for the first match we return 1 to
                  * indicate we should alert */
@@ -557,35 +500,19 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
             SCLogDebug("detection_filter");
 
             if (lookup_tsh != NULL) {
-                long double time_diff = ((p->ts.tv_sec + p->ts.tv_usec/1000000.0) -
-                                         (lookup_tsh->tv_sec1 + lookup_tsh->tv_usec1/1000000.0));
-
-                if (time_diff < td->seconds) {
+                if (TIMEVAL_DIFF_SEC(p->ts, lookup_tsh->tv1) < td->seconds) {
                     /* within timeout */
-
                     lookup_tsh->current_count++;
                     if (lookup_tsh->current_count > td->count) {
                         ret = 1;
                     }
                 } else {
                     /* expired, reset */
-
-                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
-                    lookup_tsh->tv_usec1 = p->ts.tv_usec;
+                    lookup_tsh->tv1 = p->ts;
                     lookup_tsh->current_count = 1;
                 }
             } else {
-                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
-                if (e == NULL) {
-                    break;
-                }
-
-                e->current_count = 1;
-                e->tv_sec1 = p->ts.tv_sec;
-                e->tv_usec1 = p->ts.tv_usec;
-
-                e->next = HostGetStorageById(h, host_threshold_id);
-                HostSetStorageById(h, host_threshold_id, e);
+                *new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
             }
             break;
         }
@@ -594,11 +521,10 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
         {
             SCLogDebug("rate_filter");
             ret = 1;
-            if (lookup_tsh && IsThresholdReached(lookup_tsh, td, p->ts.tv_sec)) {
+            if (lookup_tsh && IsThresholdReached(lookup_tsh, td, p->ts)) {
                 RateFilterSetAction(p, pa, td->new_action);
             } else if (!lookup_tsh) {
-                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
-                AddEntryToHostStorage(h, e, p->ts.tv_sec);
+                *new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
             }
             break;
         }
@@ -606,7 +532,43 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
         default:
             SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type);
     }
+    return ret;
+}
+
+static int ThresholdHandlePacketIPPair(IPPair *pair, Packet *p, const DetectThresholdData *td,
+    uint32_t sid, uint32_t gid, PacketAlert *pa)
+{
+    int ret = 0;
+
+    DetectThresholdEntry *lookup_tsh = ThresholdIPPairLookupEntry(pair, sid, gid);
+    SCLogDebug("ippair lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid);
+
+    DetectThresholdEntry *new_tsh = NULL;
+    ret = ThresholdHandlePacket(p, lookup_tsh, &new_tsh, td, sid, gid, pa);
+    if (new_tsh != NULL) {
+        AddEntryToIPPairStorage(pair, new_tsh, p->ts);
+    }
+
+    return ret;
+}
+
+/**
+ *  \retval 2 silent match (no alert but apply actions)
+ *  \retval 1 normal match
+ *  \retval 0 no match
+ */
+static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdData *td,
+        uint32_t sid, uint32_t gid, PacketAlert *pa)
+{
+    int ret = 0;
+    DetectThresholdEntry *lookup_tsh = ThresholdHostLookupEntry(h, sid, gid);
+    SCLogDebug("lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid);
 
+    DetectThresholdEntry *new_tsh = NULL;
+    ret = ThresholdHandlePacket(p, lookup_tsh, &new_tsh, td, sid, gid, pa);
+    if (new_tsh != NULL) {
+        AddEntryToHostStorage(h, new_tsh, p->ts);
+    }
     return ret;
 }
 
@@ -618,30 +580,13 @@ static int ThresholdHandlePacketRule(DetectEngineCtx *de_ctx, Packet *p,
     DetectThresholdEntry* lookup_tsh = (DetectThresholdEntry *)de_ctx->ths_ctx.th_entry[s->num];
     SCLogDebug("by_rule lookup_tsh %p num %u", lookup_tsh, s->num);
 
-    switch (td->type) {
-        case TYPE_RATE:
-        {
-            ret = 1;
-            if (lookup_tsh && IsThresholdReached(lookup_tsh, td, p->ts.tv_sec)) {
-                RateFilterSetAction(p, pa, td->new_action);
-            }
-            else if (!lookup_tsh) {
-                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, s->id, s->gid);
-                if (e != NULL) {
-                    e->current_count = 1;
-                    e->tv_sec1 = p->ts.tv_sec;
-                    e->tv_timeout = 0;
-
-                    de_ctx->ths_ctx.th_entry[s->num] = e;
-                }
-            }
-            break;
-        }
-        default:
-        {
-            SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type);
-            break;
-        }
+    DetectThresholdEntry *new_tsh = NULL;
+    ret = ThresholdHandlePacket(p, lookup_tsh, &new_tsh, td, s->id, s->gid, pa);
+    if (new_tsh != NULL) {
+        new_tsh->tv1 = p->ts;
+        new_tsh->current_count = 1;
+        new_tsh->tv_timeout = 0;
+        de_ctx->ths_ctx.th_entry[s->num] = new_tsh;
     }
 
     return ret;
index 534a6eb4aedb0b2c5a87f66c65e4cce4beb66812..05ebe2e76ac5a9f38a8e869fec65061a10a4962b 100644 (file)
@@ -72,11 +72,10 @@ typedef struct DetectThresholdEntry_ {
     uint32_t tv_timeout;    /**< Timeout for new_action (for rate_filter)
                                  its not "seconds", that define the time interval */
     uint32_t seconds;       /**< Event seconds */
-    uint32_t tv_sec1;       /**< Var for time control */
-    uint32_t tv_usec1;       /**< Var for time control */
     uint32_t current_count; /**< Var for count control */
     int track;          /**< Track type: by_src, by_src */
 
+    struct timeval tv1;     /**< Var for time control */
     struct DetectThresholdEntry_ *next;
 } DetectThresholdEntry;