diff --git a/server/modules/filter/fwfilter.c b/server/modules/filter/fwfilter.c index 7766521cf..016fe16e1 100644 --- a/server/modules/filter/fwfilter.c +++ b/server/modules/filter/fwfilter.c @@ -625,6 +625,95 @@ void add_users(char* rule, FW_INSTANCE* instance) instance->userstrings = link; } +bool check_throttle_timers(FW_INSTANCE* my_instance, FW_SESSION* my_session, USER* user, RULELIST *rulelist) +{ + RULELIST* rlist = rulelist; + QUERYSPEED* queryspeed = NULL; + QUERYSPEED* rule_qs = NULL; + time_t time_now = time(NULL); + bool rval = false; + while(rlist) + { + if(rlist->rule->type == RT_THROTTLE) + { + spinlock_acquire(my_instance->lock); + rule_qs = (QUERYSPEED*) rlist->rule->data; + spinlock_release(my_instance->lock); + + spinlock_acquire(user->lock); + queryspeed = user->qs_limit; + spinlock_release(user->lock); + + while(queryspeed) + { + if(queryspeed->id == rule_qs->id) + { + break; + } + queryspeed = queryspeed->next; + } + if(queryspeed) + { + if(difftime(time_now,queryspeed->triggered) < queryspeed->cooldown) + { + rval = true; + } + else + { + queryspeed->triggered = 0; + queryspeed->first_query = 0; + queryspeed->count = 0; + } + } + } + rlist = rlist->next; + } + return rval; +} + +bool +is_throttle_active(FW_INSTANCE* my_instance, FW_SESSION* my_session, USER* user, RULELIST *rulelist) +{ + bool rval = false; + QUERYSPEED* queryspeed = NULL; + QUERYSPEED* rule_qs = NULL; + time_t time_now; + char emsg[1024]; + + if(rulelist->rule->type == RT_THROTTLE) + { + time(&time_now); + + spinlock_acquire(my_instance->lock); + rule_qs = (QUERYSPEED*) rulelist->rule->data; + spinlock_release(my_instance->lock); + + spinlock_acquire(user->lock); + queryspeed = user->qs_limit; + spinlock_release(user->lock); + + while(queryspeed) + { + if(queryspeed->id == rule_qs->id) + { + break; + } + queryspeed = queryspeed->next; + } + + if(queryspeed && difftime(time_now,queryspeed->triggered) < queryspeed->cooldown) + { + rval = true; + double blocked_for = queryspeed->cooldown - difftime(time_now,queryspeed->triggered); + + sprintf(emsg,"Queries denied for %f seconds",blocked_for); + skygw_log_write(LOGFILE_TRACE, "fwfilter: rule '%s': user denied for %f seconds",rulelist->rule->name,blocked_for); + my_session->errmsg = strdup(emsg); + } + } + return rval; +} + /** * Parses the list of rule strings for users and links them against the listed rules. * Only adds those rules that are found. If the rule isn't found a message is written to the error log. @@ -1439,8 +1528,15 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue queryspeed->next = user->qs_limit; user->qs_limit = queryspeed; } - - if(queryspeed->count > queryspeed->limit) + + block_triggered: + + if(queryspeed->limit == 1) + { + matches = true; + } + + if(queryspeed->count >= queryspeed->limit) { queryspeed->triggered = time_now; queryspeed->count = 0; @@ -1468,15 +1564,20 @@ bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue matches = true; } - else if(difftime(time_now,queryspeed->first_query) < queryspeed->period) + else if(difftime(time_now,queryspeed->first_query) <= queryspeed->period) { - queryspeed->count++; + queryspeed->count++; } else { - queryspeed->first_query = time_now; + queryspeed->first_query = time_now; } + if(!matches && queryspeed->count >= queryspeed->limit) + { + goto block_triggered; + } + break; case RT_CLAUSE: @@ -1536,7 +1637,10 @@ bool check_match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *qu memset(fullquery + qlen,0,1); } - rulelist = user->rules_or; + if((rulelist = user->rules_or) == NULL) + { + goto retblock; + } while(rulelist){ @@ -1544,9 +1648,19 @@ bool check_match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *qu rulelist = rulelist->next; continue; } - if((rval = rule_matches(my_instance,my_session,queue,user,rulelist,fullquery))){ - goto retblock; + if((rval = rule_matches(my_instance,my_session,queue,user,rulelist,fullquery))){ + goto retblock; } + + if(rulelist->rule->type == RT_THROTTLE) + { + if(is_throttle_active(my_instance,my_session,user,rulelist)) + { + rval = true; + goto retblock; + } + } + rulelist = rulelist->next; } @@ -1567,7 +1681,7 @@ bool check_match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *qu */ bool check_match_all(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *queue, USER* user) { - bool is_sql, rval = 0; + bool is_sql, rval = true; int qlen; char *fullquery = NULL,*ptr; @@ -1586,22 +1700,32 @@ bool check_match_all(FW_INSTANCE* my_instance, FW_SESSION* my_session, GWBUF *qu } - rulelist = user->rules_or; - + if((rulelist = user->rules_and) == NULL) + { + rval = false; + goto retblock; + } + while(rulelist){ if(!rule_is_active(rulelist->rule)){ rulelist = rulelist->next; continue; } + if(!rule_matches(my_instance,my_session,queue,user,rulelist,fullquery)){ rval = false; - goto retblock; } rulelist = rulelist->next; } + if(rval == false) + { + rulelist = user->rules_and; + rval = check_throttle_timers(my_instance,my_session,user,rulelist); + } + retblock: free(fullquery);