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.
pull/4785/head
Todd Mortimer 5 years ago committed by Victor Julien
parent 9fafc1031c
commit 82dc61f4c3

@ -174,7 +174,7 @@ static DetectThresholdEntry* ThresholdTimeoutCheck(DetectThresholdEntry *head, s
/* check if the 'check' timestamp is not before the creation ts. /* check if the 'check' timestamp is not before the creation ts.
* This can happen due to the async nature of the host timeout * This can happen due to the async nature of the host timeout
* code that also calls this code from a management thread. */ * 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; prev = tmp;
tmp = tmp->next; tmp = tmp->next;
continue; 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 * \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; int ret = 0;
/* Check if we have a timeout enabled, if so, /* Check if we have a timeout enabled, if so,
* we still matching (and enabling the new_action) */ * we still matching (and enabling the new_action) */
if (lookup_tsh->tv_timeout != 0) { 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 */ /* Ok, we are done, timeout reached */
lookup_tsh->tv_timeout = 0; lookup_tsh->tv_timeout = 0;
} }
@ -352,17 +352,17 @@ static int IsThresholdReached(DetectThresholdEntry* lookup_tsh, const DetectThre
} }
else { else {
/* Update the matching state with the timeout interval */ /* 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++; lookup_tsh->current_count++;
if (lookup_tsh->current_count > td->count) { if (lookup_tsh->current_count > td->count) {
/* Then we must enable the new action by setting a /* Then we must enable the new action by setting a
* timeout */ * timeout */
lookup_tsh->tv_timeout = packet_time; lookup_tsh->tv_timeout = packet_time.tv_sec;
ret = 1; ret = 1;
} }
} }
else { else {
lookup_tsh->tv_sec1 = packet_time; lookup_tsh->tv1 = packet_time;
lookup_tsh->current_count = 1; lookup_tsh->current_count = 1;
} }
} /* else - if (lookup_tsh->tv_timeout != 0) */ } /* else - if (lookup_tsh->tv_timeout != 0) */
@ -370,79 +370,49 @@ static int IsThresholdReached(DetectThresholdEntry* lookup_tsh, const DetectThre
return ret; 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) { if (h && e) {
e->current_count = 1; e->current_count = 1;
e->tv_sec1 = packet_time; e->tv1 = packet_time;
e->tv_timeout = 0; e->tv_timeout = 0;
e->next = HostGetStorageById(h, host_threshold_id); e->next = HostGetStorageById(h, host_threshold_id);
HostSetStorageById(h, host_threshold_id, e); 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) { if (pair && e) {
e->current_count = 1; e->current_count = 1;
e->tv_sec1 = packet_time; e->tv1 = packet_time;
e->tv_timeout = 0; e->tv_timeout = 0;
e->next = IPPairGetStorageById(pair, ippair_threshold_id); e->next = IPPairGetStorageById(pair, ippair_threshold_id);
IPPairSetStorageById(pair, ippair_threshold_id, e); 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 2 silent match (no alert but apply actions)
* \retval 1 normal match * \retval 1 normal match
* \retval 0 no 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) uint32_t sid, uint32_t gid, PacketAlert *pa)
{ {
int ret = 0; 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) { switch(td->type) {
case TYPE_LIMIT: case TYPE_LIMIT:
{ {
SCLogDebug("limit"); SCLogDebug("limit");
if (lookup_tsh != NULL) { 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++; lookup_tsh->current_count++;
if (lookup_tsh->current_count <= td->count) { if (lookup_tsh->current_count <= td->count) {
@ -451,24 +421,15 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
ret = 2; ret = 2;
} }
} else { } else {
lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->tv1 = p->ts;
lookup_tsh->current_count = 1; lookup_tsh->current_count = 1;
ret = 1; ret = 1;
} }
} else { } else {
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); *new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
if (e == NULL) {
break;
}
e->tv_sec1 = p->ts.tv_sec;
e->current_count = 1;
ret = 1; ret = 1;
e->next = HostGetStorageById(h, host_threshold_id);
HostSetStorageById(h, host_threshold_id, e);
} }
break; break;
} }
@ -477,7 +438,7 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
SCLogDebug("threshold"); SCLogDebug("threshold");
if (lookup_tsh != NULL) { 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++; lookup_tsh->current_count++;
if (lookup_tsh->current_count >= td->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; lookup_tsh->current_count = 0;
} }
} else { } else {
lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->tv1 = p->ts;
lookup_tsh->current_count = 1; lookup_tsh->current_count = 1;
} }
} else { } else {
if (td->count == 1) { if (td->count == 1) {
ret = 1; ret = 1;
} else { } else {
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); *new_tsh = 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);
} }
} }
break; break;
@ -511,7 +463,7 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
SCLogDebug("both"); SCLogDebug("both");
if (lookup_tsh != NULL) { 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 */ /* within time limit */
lookup_tsh->current_count++; lookup_tsh->current_count++;
@ -523,7 +475,7 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
} }
} else { } else {
/* expired, so reset */ /* expired, so reset */
lookup_tsh->tv_sec1 = p->ts.tv_sec; lookup_tsh->tv1 = p->ts;
lookup_tsh->current_count = 1; lookup_tsh->current_count = 1;
/* if we have a limit of 1, this is a match */ /* 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 { } else {
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); *new_tsh = 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);
/* for the first match we return 1 to /* for the first match we return 1 to
* indicate we should alert */ * indicate we should alert */
@ -557,35 +500,19 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
SCLogDebug("detection_filter"); SCLogDebug("detection_filter");
if (lookup_tsh != NULL) { if (lookup_tsh != NULL) {
long double time_diff = ((p->ts.tv_sec + p->ts.tv_usec/1000000.0) - if (TIMEVAL_DIFF_SEC(p->ts, lookup_tsh->tv1) < td->seconds) {
(lookup_tsh->tv_sec1 + lookup_tsh->tv_usec1/1000000.0));
if (time_diff < td->seconds) {
/* within timeout */ /* within timeout */
lookup_tsh->current_count++; lookup_tsh->current_count++;
if (lookup_tsh->current_count > td->count) { if (lookup_tsh->current_count > td->count) {
ret = 1; ret = 1;
} }
} else { } else {
/* expired, reset */ /* expired, reset */
lookup_tsh->tv1 = p->ts;
lookup_tsh->tv_sec1 = p->ts.tv_sec;
lookup_tsh->tv_usec1 = p->ts.tv_usec;
lookup_tsh->current_count = 1; lookup_tsh->current_count = 1;
} }
} else { } else {
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); *new_tsh = 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);
} }
break; break;
} }
@ -594,11 +521,10 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
{ {
SCLogDebug("rate_filter"); SCLogDebug("rate_filter");
ret = 1; 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); RateFilterSetAction(p, pa, td->new_action);
} else if (!lookup_tsh) { } else if (!lookup_tsh) {
DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid); *new_tsh = DetectThresholdEntryAlloc(td, p, sid, gid);
AddEntryToHostStorage(h, e, p->ts.tv_sec);
} }
break; break;
} }
@ -606,7 +532,43 @@ static int ThresholdHandlePacketHost(Host *h, Packet *p, const DetectThresholdDa
default: default:
SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type); 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; 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]; DetectThresholdEntry* lookup_tsh = (DetectThresholdEntry *)de_ctx->ths_ctx.th_entry[s->num];
SCLogDebug("by_rule lookup_tsh %p num %u", lookup_tsh, s->num); SCLogDebug("by_rule lookup_tsh %p num %u", lookup_tsh, s->num);
switch (td->type) { DetectThresholdEntry *new_tsh = NULL;
case TYPE_RATE: ret = ThresholdHandlePacket(p, lookup_tsh, &new_tsh, td, s->id, s->gid, pa);
{ if (new_tsh != NULL) {
ret = 1; new_tsh->tv1 = p->ts;
if (lookup_tsh && IsThresholdReached(lookup_tsh, td, p->ts.tv_sec)) { new_tsh->current_count = 1;
RateFilterSetAction(p, pa, td->new_action); new_tsh->tv_timeout = 0;
} de_ctx->ths_ctx.th_entry[s->num] = new_tsh;
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;
}
} }
return ret; return ret;

@ -72,11 +72,10 @@ typedef struct DetectThresholdEntry_ {
uint32_t tv_timeout; /**< Timeout for new_action (for rate_filter) uint32_t tv_timeout; /**< Timeout for new_action (for rate_filter)
its not "seconds", that define the time interval */ its not "seconds", that define the time interval */
uint32_t seconds; /**< Event seconds */ 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 */ uint32_t current_count; /**< Var for count control */
int track; /**< Track type: by_src, by_src */ int track; /**< Track type: by_src, by_src */
struct timeval tv1; /**< Var for time control */
struct DetectThresholdEntry_ *next; struct DetectThresholdEntry_ *next;
} DetectThresholdEntry; } DetectThresholdEntry;

Loading…
Cancel
Save