MXS-1346: Move rule matching into the User class
The User class now only exposes the `match` method which can be used to check if any of the rules for a user match a query. Further cleanup is required once individual rule classes have been implemented.
This commit is contained in:
@ -1917,146 +1917,6 @@ queryresolved:
|
|||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the query matches any of the rules in the user's rules.
|
|
||||||
* @param my_instance Fwfilter instance
|
|
||||||
* @param my_session Fwfilter session
|
|
||||||
* @param queue The GWBUF containing the query
|
|
||||||
* @param user The user whose rules are checked
|
|
||||||
* @return True if the query matches at least one of the rules otherwise false
|
|
||||||
*/
|
|
||||||
bool check_match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
|
||||||
GWBUF *queue, SUser user, char** rulename)
|
|
||||||
{
|
|
||||||
|
|
||||||
bool rval = false;
|
|
||||||
|
|
||||||
if (!user->rules_or.empty() &&
|
|
||||||
(modutil_is_SQL(queue) || modutil_is_SQL_prepare(queue) ||
|
|
||||||
MYSQL_IS_COM_INIT_DB((uint8_t*)GWBUF_DATA(queue))))
|
|
||||||
{
|
|
||||||
char *fullquery = modutil_get_SQL(queue);
|
|
||||||
|
|
||||||
if (fullquery)
|
|
||||||
{
|
|
||||||
for (RuleList::iterator it = user->rules_or.begin(); it != user->rules_or.end(); it++)
|
|
||||||
{
|
|
||||||
if (rule_is_active(*it))
|
|
||||||
{
|
|
||||||
if (rule_matches(my_instance, my_session, queue, *it, fullquery))
|
|
||||||
{
|
|
||||||
*rulename = MXS_STRDUP_A((*it)->name.c_str());
|
|
||||||
rval = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MXS_FREE(fullquery);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Append and possibly reallocate string
|
|
||||||
* @param dest Destination where the string is appended or NULL if nothing has
|
|
||||||
* been allocated yet
|
|
||||||
* @param size Size of @c dest
|
|
||||||
* @param src String to append to @c dest
|
|
||||||
*/
|
|
||||||
void append_string(char** dest, size_t* size, const char* src)
|
|
||||||
{
|
|
||||||
if (*dest == NULL)
|
|
||||||
{
|
|
||||||
*dest = MXS_STRDUP_A(src);
|
|
||||||
*size = strlen(src);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (*size < strlen(*dest) + strlen(src) + 3)
|
|
||||||
{
|
|
||||||
size_t newsize = strlen(*dest) + strlen(src) + 3;
|
|
||||||
char* tmp = (char*)MXS_REALLOC(*dest, newsize);
|
|
||||||
if (tmp)
|
|
||||||
{
|
|
||||||
*size = newsize;
|
|
||||||
*dest = tmp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strcat(*dest, ", ");
|
|
||||||
strcat(*dest, src);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the query matches all rules in the user's rules
|
|
||||||
*
|
|
||||||
* @param my_instance Filter instance
|
|
||||||
* @param my_session Filter session
|
|
||||||
* @param queue Buffer containing the query
|
|
||||||
* @param user The user whose rules are checked
|
|
||||||
* @param strict_all Whether the first match stops the processing
|
|
||||||
* @param rulename Pointer where error messages are stored
|
|
||||||
*
|
|
||||||
* @return True if the query matches all of the rules otherwise false
|
|
||||||
*/
|
|
||||||
bool check_match_all(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
|
||||||
GWBUF *queue, SUser user, bool strict_all, char** rulename)
|
|
||||||
{
|
|
||||||
bool rval = false;
|
|
||||||
bool have_active_rule = false;
|
|
||||||
RuleList& rules = strict_all ? user->rules_strict_and : user->rules_and;
|
|
||||||
char *matched_rules = NULL;
|
|
||||||
size_t size = 0;
|
|
||||||
|
|
||||||
if (!rules.empty() && (modutil_is_SQL(queue) || modutil_is_SQL_prepare(queue)))
|
|
||||||
{
|
|
||||||
char *fullquery = modutil_get_SQL(queue);
|
|
||||||
|
|
||||||
if (fullquery)
|
|
||||||
{
|
|
||||||
rval = true;
|
|
||||||
for (RuleList::iterator it = rules.begin(); it != rules.end(); it++)
|
|
||||||
{
|
|
||||||
if (!rule_is_active(*it))
|
|
||||||
{
|
|
||||||
have_active_rule = true;
|
|
||||||
|
|
||||||
if (rule_matches(my_instance, my_session, queue, *it, fullquery))
|
|
||||||
{
|
|
||||||
append_string(&matched_rules, &size, (*it)->name.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rval = false;
|
|
||||||
if (strict_all)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!have_active_rule)
|
|
||||||
{
|
|
||||||
/** No active rules */
|
|
||||||
rval = false;
|
|
||||||
}
|
|
||||||
MXS_FREE(fullquery);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Set the list of matched rule names */
|
|
||||||
*rulename = matched_rules;
|
|
||||||
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the user specific data for this session
|
* Retrieve the user specific data for this session
|
||||||
*
|
*
|
||||||
@ -2178,15 +2038,8 @@ routeQuery(MXS_FILTER *instance, MXS_FILTER_SESSION *session, GWBUF *queue)
|
|||||||
|
|
||||||
if (user)
|
if (user)
|
||||||
{
|
{
|
||||||
bool match = false;
|
|
||||||
char* rname = NULL;
|
char* rname = NULL;
|
||||||
|
bool match = user->match(my_instance, my_session, analyzed_queue, &rname);
|
||||||
if (check_match_any(my_instance, my_session, analyzed_queue, user, &rname) ||
|
|
||||||
check_match_all(my_instance, my_session, analyzed_queue, user, false, &rname) ||
|
|
||||||
check_match_all(my_instance, my_session, analyzed_queue, user, true, &rname))
|
|
||||||
{
|
|
||||||
match = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (my_instance->action)
|
switch (my_instance->action)
|
||||||
{
|
{
|
||||||
|
@ -199,5 +199,16 @@ typedef struct
|
|||||||
/** Typedef for a list of strings */
|
/** Typedef for a list of strings */
|
||||||
typedef std::list<std::string> ValueList;
|
typedef std::list<std::string> ValueList;
|
||||||
|
|
||||||
|
/** Temporary typedef for SRule */
|
||||||
|
class Rule;
|
||||||
|
typedef std::tr1::shared_ptr<Rule> SRule;
|
||||||
|
|
||||||
/** Helper function for strdup'ing in printf style */
|
/** Helper function for strdup'ing in printf style */
|
||||||
char* create_error(const char* format, ...);
|
char* create_error(const char* format, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a rule matches
|
||||||
|
*/
|
||||||
|
bool rule_matches(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||||
|
GWBUF *queue, SRule rule, char* query);
|
||||||
|
bool rule_is_active(SRule rule);
|
@ -13,6 +13,10 @@
|
|||||||
|
|
||||||
#include "users.hh"
|
#include "users.hh"
|
||||||
|
|
||||||
|
#include <maxscale/alloc.h>
|
||||||
|
#include <maxscale/modutil.h>
|
||||||
|
#include <maxscale/protocol/mysql.h>
|
||||||
|
|
||||||
User::User(std::string name):
|
User::User(std::string name):
|
||||||
m_name(name)
|
m_name(name)
|
||||||
{
|
{
|
||||||
@ -48,3 +52,123 @@ void User::append_rules(match_type mode, const RuleList& rules)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool should_match(GWBUF* buffer)
|
||||||
|
{
|
||||||
|
return modutil_is_SQL(buffer) || modutil_is_SQL_prepare(buffer) ||
|
||||||
|
MYSQL_IS_COM_INIT_DB(GWBUF_DATA(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the query matches any of the rules in the user's rules.
|
||||||
|
* @param my_instance Fwfilter instance
|
||||||
|
* @param my_session Fwfilter session
|
||||||
|
* @param queue The GWBUF containing the query
|
||||||
|
* @param user The user whose rules are checked
|
||||||
|
* @return True if the query matches at least one of the rules otherwise false
|
||||||
|
*/
|
||||||
|
bool User::match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||||
|
GWBUF *queue, char** rulename)
|
||||||
|
{
|
||||||
|
|
||||||
|
bool rval = false;
|
||||||
|
|
||||||
|
if (rules_or.size() > 0 && should_match(queue))
|
||||||
|
{
|
||||||
|
char *fullquery = modutil_get_SQL(queue);
|
||||||
|
|
||||||
|
if (fullquery)
|
||||||
|
{
|
||||||
|
for (RuleList::iterator it = rules_or.begin(); it != rules_or.end(); it++)
|
||||||
|
{
|
||||||
|
if (rule_is_active(*it))
|
||||||
|
{
|
||||||
|
if (rule_matches(my_instance, my_session, queue, *it, fullquery))
|
||||||
|
{
|
||||||
|
*rulename = MXS_STRDUP_A((*it)->name.c_str());
|
||||||
|
rval = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MXS_FREE(fullquery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the query matches all rules in the user's rules
|
||||||
|
*
|
||||||
|
* @param my_instance Filter instance
|
||||||
|
* @param my_session Filter session
|
||||||
|
* @param queue Buffer containing the query
|
||||||
|
* @param user The user whose rules are checked
|
||||||
|
* @param strict_all Whether the first match stops the processing
|
||||||
|
* @param rulename Pointer where error messages are stored
|
||||||
|
*
|
||||||
|
* @return True if the query matches all of the rules otherwise false
|
||||||
|
*/
|
||||||
|
bool User::do_match(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||||
|
GWBUF *queue, match_mode mode, char** rulename)
|
||||||
|
{
|
||||||
|
bool rval = false;
|
||||||
|
bool have_active_rule = false;
|
||||||
|
std::string matching_rules;
|
||||||
|
RuleList& rules = mode == User::ALL ? rules_and : rules_strict_and;
|
||||||
|
|
||||||
|
if (rules.size() > 0 && should_match(queue))
|
||||||
|
{
|
||||||
|
char *fullquery = modutil_get_SQL(queue);
|
||||||
|
|
||||||
|
if (fullquery)
|
||||||
|
{
|
||||||
|
rval = true;
|
||||||
|
for (RuleList::iterator it = rules.begin(); it != rules.end(); it++)
|
||||||
|
{
|
||||||
|
if (!rule_is_active(*it))
|
||||||
|
{
|
||||||
|
have_active_rule = true;
|
||||||
|
|
||||||
|
if (rule_matches(my_instance, my_session, queue, *it, fullquery))
|
||||||
|
{
|
||||||
|
matching_rules += (*it)->name;
|
||||||
|
matching_rules += " ";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rval = false;
|
||||||
|
|
||||||
|
if (mode == User::STRICT)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!have_active_rule)
|
||||||
|
{
|
||||||
|
/** No active rules */
|
||||||
|
rval = false;
|
||||||
|
}
|
||||||
|
MXS_FREE(fullquery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set the list of matched rule names */
|
||||||
|
if (matching_rules.length() > 0)
|
||||||
|
{
|
||||||
|
*rulename = MXS_STRDUP_A(matching_rules.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool User::match(FW_INSTANCE* instance, FW_SESSION* session, GWBUF* buffer, char** rulename)
|
||||||
|
{
|
||||||
|
return match_any(instance, session, buffer, rulename) ||
|
||||||
|
do_match(instance, session, buffer, User::ALL, rulename) ||
|
||||||
|
do_match(instance, session, buffer, User::STRICT, rulename);
|
||||||
|
}
|
||||||
|
@ -57,13 +57,39 @@ public:
|
|||||||
*/
|
*/
|
||||||
void append_rules(match_type mode, const RuleList& rules);
|
void append_rules(match_type mode, const RuleList& rules);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a query matches some rule
|
||||||
|
*
|
||||||
|
* @param instance Filter instance
|
||||||
|
* @param session Filter session
|
||||||
|
* @param buffer Buffer containing the query
|
||||||
|
* @param rulename Names of rules that this query matched
|
||||||
|
*
|
||||||
|
* @return True if query matches
|
||||||
|
*/
|
||||||
|
bool match(FW_INSTANCE* instance, FW_SESSION* session, GWBUF* buffer, char** rulename);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum match_mode
|
||||||
|
{
|
||||||
|
ALL,
|
||||||
|
STRICT
|
||||||
|
};
|
||||||
|
|
||||||
RuleList rules_or; /*< If any of these rules match the action is triggered */
|
RuleList rules_or; /*< If any of these rules match the action is triggered */
|
||||||
RuleList rules_and; /*< All of these rules must match for the action to trigger */
|
RuleList rules_and; /*< All of these rules must match for the action to trigger */
|
||||||
RuleList rules_strict_and; /*< rules that skip the rest of the rules if one of them
|
RuleList rules_strict_and; /*< rules that skip the rest of the rules if one of them
|
||||||
* fails. This is only for rules paired with 'match strict_all'. */
|
* fails. This is only for rules paired with 'match strict_all'. */
|
||||||
|
std::string m_name; /*< Name of the user */
|
||||||
|
|
||||||
private:
|
/**
|
||||||
std::string m_name; /*< Name of the user */
|
* Functions for matching rules
|
||||||
|
*/
|
||||||
|
bool match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||||
|
GWBUF *queue, char** rulename);
|
||||||
|
bool do_match(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||||
|
GWBUF *queue, match_mode mode, char** rulename);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::tr1::shared_ptr<User> SUser;
|
typedef std::tr1::shared_ptr<User> SUser;
|
||||||
|
Reference in New Issue
Block a user