From 594956178d41ba005806e39ba06d91951f6a74d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20M=C3=A4kel=C3=A4?= Date: Fri, 1 Sep 2017 22:34:09 +0300 Subject: [PATCH] MXS-1346: Implement LimitQueriesRule::matches_query Moved the code into the LimitQueriesRule class and cleaned it up. Renamed the QUERYSPEED struct and added simple constructor. --- .../modules/filter/dbfwfilter/dbfwfilter.cc | 121 +----------------- .../modules/filter/dbfwfilter/dbfwfilter.hh | 18 ++- server/modules/filter/dbfwfilter/rules.cc | 58 +++++++++ 3 files changed, 75 insertions(+), 122 deletions(-) diff --git a/server/modules/filter/dbfwfilter/dbfwfilter.cc b/server/modules/filter/dbfwfilter/dbfwfilter.cc index 5058d7b45..ede98db23 100644 --- a/server/modules/filter/dbfwfilter/dbfwfilter.cc +++ b/server/modules/filter/dbfwfilter/dbfwfilter.cc @@ -1073,15 +1073,7 @@ void define_limit_queries_rule(void* scanner, int max, int timeperiod, int holdo { struct parser_stack* rstack = (struct parser_stack*)dbfw_yyget_extra((yyscan_t) scanner); ss_dassert(rstack); - QUERYSPEED* qs = new QUERYSPEED; - Rule* rule = create_rule(rstack->name); - - qs->limit = max; - qs->period = timeperiod; - qs->cooldown = holdoff; - rule->type = RT_THROTTLE; - rule->data = qs; - rstack->rule.push_front(SRule(rule)); + rstack->rule.push_front(SRule(new LimitQueriesRule(rstack->name, max, timeperiod, holdoff))); } /** @@ -1366,7 +1358,7 @@ freeSession(MXS_FILTER *instance, MXS_FILTER_SESSION *session) { FW_SESSION *my_session = (FW_SESSION *) session; MXS_FREE(my_session->errmsg); - MXS_FREE(my_session->query_speed); + delete my_session->query_speed; MXS_FREE(my_session); } @@ -1573,70 +1565,6 @@ static char* create_parse_error(FW_INSTANCE* my_instance, return msg; } -bool match_throttle(FW_SESSION* my_session, SRule rule, char **msg) -{ - bool matches = false; - QUERYSPEED* rule_qs = (QUERYSPEED*)rule->data; - QUERYSPEED* queryspeed = my_session->query_speed; - time_t time_now = time(NULL); - - if (queryspeed == NULL) - { - /**No match found*/ - queryspeed = new QUERYSPEED; - queryspeed->period = rule_qs->period; - queryspeed->cooldown = rule_qs->cooldown; - queryspeed->limit = rule_qs->limit; - my_session->query_speed = queryspeed; - } - - if (queryspeed->active) - { - if (difftime(time_now, queryspeed->triggered) < queryspeed->cooldown) - { - double blocked_for = queryspeed->cooldown - difftime(time_now, queryspeed->triggered); - *msg = create_error("Queries denied for %f seconds", blocked_for); - matches = true; - - MXS_INFO("rule '%s': user denied for %f seconds", - rule->name.c_str(), blocked_for); - } - else - { - queryspeed->active = false; - queryspeed->count = 0; - } - } - else - { - if (queryspeed->count >= queryspeed->limit) - { - MXS_INFO("rule '%s': query limit triggered (%d queries in %d seconds), " - "denying queries from user for %d seconds.", rule->name.c_str(), - queryspeed->limit, queryspeed->period, queryspeed->cooldown); - - queryspeed->triggered = time_now; - queryspeed->active = true; - matches = true; - - double blocked_for = queryspeed->cooldown - difftime(time_now, queryspeed->triggered); - *msg = create_error("Queries denied for %f seconds", blocked_for); - } - else if (queryspeed->count > 0 && - difftime(time_now, queryspeed->first_query) <= queryspeed->period) - { - queryspeed->count++; - } - else - { - queryspeed->first_query = time_now; - queryspeed->count = 1; - } - } - - return matches; -} - /** * Check if a query matches a single rule * @param my_instance Fwfilter instance @@ -1681,51 +1609,6 @@ bool rule_matches(FW_INSTANCE* my_instance, matches = true; goto queryresolved; } - - /** No match, try old the style rule */ - switch (rule->type) - { - case RT_UNDEFINED: - ss_dassert(false); - MXS_ERROR("Undefined rule type found."); - break; - - case RT_REGEX: - /** Handled in RegexRule::query_matches */ - break; - - case RT_PERMISSION: - /** Handled in Rule::matches_query */ - break; - - case RT_COLUMN: - /** Handled in ColumnsRule::matches_query */ - break; - - case RT_FUNCTION: - /** Handled in FunctionRule::matches_query */ - break; - - case RT_USES_FUNCTION: - /** Handled in FunctionUsageRule::matches_query */ - break; - - case RT_WILDCARD: - /** Handled in WildCardRule::query_matches */ - break; - - case RT_THROTTLE: - matches = match_throttle(my_session, rule, &msg); - break; - - case RT_CLAUSE: - /** Handled in WhereClauseRule::query_matches */ - break; - - default: - break; - - } } queryresolved: diff --git a/server/modules/filter/dbfwfilter/dbfwfilter.hh b/server/modules/filter/dbfwfilter/dbfwfilter.hh index b7b092609..ada73620c 100644 --- a/server/modules/filter/dbfwfilter/dbfwfilter.hh +++ b/server/modules/filter/dbfwfilter/dbfwfilter.hh @@ -159,8 +159,20 @@ typedef struct timerange_t /** * Query speed measurement and limitation structure */ -typedef struct queryspeed_t +struct QuerySpeed { + QuerySpeed(int period = 0, int cooldown = 0, int limit = 0): + first_query(0), + triggered(0), + period(period), + cooldown(cooldown), + count(0), + limit(limit), + id(0), + active(false) + { + } + time_t first_query; /*< Time when the first query occurred */ time_t triggered; /*< Time when the limit was exceeded */ int period; /*< Measurement interval in seconds */ @@ -169,7 +181,7 @@ typedef struct queryspeed_t int limit; /*< Maximum number of queries */ long id; /*< Unique id of the rule */ bool active; /*< If the rule has been triggered */ -} QUERYSPEED; +}; /** * The Firewall filter instance. @@ -191,7 +203,7 @@ typedef struct { MXS_SESSION *session; /*< Client session structure */ char *errmsg; /*< Rule specific error message */ - QUERYSPEED *query_speed; /*< How fast the user has executed queries */ + QuerySpeed *query_speed; /*< How fast the user has executed queries */ MXS_DOWNSTREAM down; /*< Next object in the downstream chain */ MXS_UPSTREAM up; /*< Next object in the upstream chain */ FW_INSTANCE *instance; /*< Router instance */ diff --git a/server/modules/filter/dbfwfilter/rules.cc b/server/modules/filter/dbfwfilter/rules.cc index 790f4296e..dd3ba0b63 100644 --- a/server/modules/filter/dbfwfilter/rules.cc +++ b/server/modules/filter/dbfwfilter/rules.cc @@ -245,3 +245,61 @@ bool FunctionUsageRule::matches_query(FW_SESSION* session, GWBUF* buffer, char** return false; } + +bool LimitQueriesRule::matches_query(FW_SESSION* session, GWBUF* buffer, char** msg) +{ + if (session->query_speed == NULL) + { + session->query_speed = new QuerySpeed(m_timeperiod, m_holdoff, m_max); + } + + QuerySpeed* queryspeed = session->query_speed; + time_t time_now = time(NULL); + bool matches = false; + + if (queryspeed->active) + { + if (difftime(time_now, queryspeed->triggered) < queryspeed->cooldown) + { + double blocked_for = queryspeed->cooldown - difftime(time_now, queryspeed->triggered); + *msg = create_error("Queries denied for %f seconds", blocked_for); + matches = true; + + MXS_INFO("rule '%s': user denied for %f seconds", + name.c_str(), blocked_for); + } + else + { + queryspeed->active = false; + queryspeed->count = 0; + } + } + else + { + if (queryspeed->count >= queryspeed->limit) + { + MXS_INFO("rule '%s': query limit triggered (%d queries in %d seconds), " + "denying queries from user for %d seconds.", name.c_str(), + queryspeed->limit, queryspeed->period, queryspeed->cooldown); + + queryspeed->triggered = time_now; + queryspeed->active = true; + matches = true; + + double blocked_for = queryspeed->cooldown - difftime(time_now, queryspeed->triggered); + *msg = create_error("Queries denied for %f seconds", blocked_for); + } + else if (queryspeed->count > 0 && + difftime(time_now, queryspeed->first_query) <= queryspeed->period) + { + queryspeed->count++; + } + else + { + queryspeed->first_query = time_now; + queryspeed->count = 1; + } + } + + return matches; +}