From: Todd Mortimer Date: Mon, 30 Mar 2020 23:45:50 +0000 (+0000) Subject: detect/threshold: Refactor threshold calculation to handle by_rule and by_both. X-Git-Tag: suricata-6.0.0-beta1~553 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=82dc61f4c3e3e845e752dde05da3dfbe0e7a5e25;p=thirdparty%2Fsuricata.git detect/threshold: Refactor threshold calculation to handle by_rule and by_both. 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. --- diff --git a/src/detect-engine-threshold.c b/src/detect-engine-threshold.c index c4229bd2cc..95f50463e1 100644 --- a/src/detect-engine-threshold.c +++ b/src/detect-engine-threshold.c @@ -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; diff --git a/src/detect-threshold.h b/src/detect-threshold.h index 534a6eb4ae..05ebe2e76a 100644 --- a/src/detect-threshold.h +++ b/src/detect-threshold.h @@ -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;