MXS-1346: Move matching implementation into classes
Added the implementations of the query_matches method for the RegexRule, WhereClauseRule and WildCardRule classes and moved the query matching code into these functions.
This commit is contained in:
@ -130,11 +130,6 @@ static void rule_free_all(Rule* rule);
|
|||||||
static bool process_rule_file(const char* filename, RuleList* rules, UserMap* users);
|
static bool process_rule_file(const char* filename, RuleList* rules, UserMap* users);
|
||||||
bool replace_rules(FW_INSTANCE* instance);
|
bool replace_rules(FW_INSTANCE* instance);
|
||||||
|
|
||||||
static inline bool query_is_sql(GWBUF* query)
|
|
||||||
{
|
|
||||||
return modutil_is_SQL(query) || modutil_is_SQL_prepare(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_rule(Rule *rules, char *dest)
|
static void print_rule(Rule *rules, char *dest)
|
||||||
{
|
{
|
||||||
int type = 0;
|
int type = 0;
|
||||||
@ -1017,9 +1012,7 @@ void define_wildcard_rule(void* scanner)
|
|||||||
{
|
{
|
||||||
struct parser_stack* rstack = (struct parser_stack*)dbfw_yyget_extra((yyscan_t) scanner);
|
struct parser_stack* rstack = (struct parser_stack*)dbfw_yyget_extra((yyscan_t) scanner);
|
||||||
ss_dassert(rstack);
|
ss_dassert(rstack);
|
||||||
Rule* rule = create_rule(rstack->name);
|
rstack->rule.push_front(SRule(new WildCardRule(rstack->name)));
|
||||||
rule->type = RT_WILDCARD;
|
|
||||||
rstack->rule.push_front(SRule(rule));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1081,10 +1074,7 @@ void define_where_clause_rule(void* scanner)
|
|||||||
{
|
{
|
||||||
struct parser_stack* rstack = (struct parser_stack*)dbfw_yyget_extra((yyscan_t) scanner);
|
struct parser_stack* rstack = (struct parser_stack*)dbfw_yyget_extra((yyscan_t) scanner);
|
||||||
ss_dassert(rstack);
|
ss_dassert(rstack);
|
||||||
Rule* rule = create_rule(rstack->name);
|
rstack->rule.push_front(SRule(new NoWhereClauseRule(rstack->name)));
|
||||||
|
|
||||||
rule->type = RT_CLAUSE;
|
|
||||||
rstack->rule.push_front(SRule(rule));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1124,10 +1114,7 @@ bool define_regex_rule(void* scanner, char* pattern)
|
|||||||
{
|
{
|
||||||
struct parser_stack* rstack = (struct parser_stack*)dbfw_yyget_extra((yyscan_t) scanner);
|
struct parser_stack* rstack = (struct parser_stack*)dbfw_yyget_extra((yyscan_t) scanner);
|
||||||
ss_dassert(rstack);
|
ss_dassert(rstack);
|
||||||
Rule* rule = create_rule(rstack->name);
|
rstack->rule.push_front(SRule(new RegexRule(rstack->name, re)));
|
||||||
rule->type = RT_REGEX;
|
|
||||||
rule->data = re;
|
|
||||||
rstack->rule.push_front(SRule(rule));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1661,31 +1648,6 @@ bool match_throttle(FW_SESSION* my_session, SRule rule, char **msg)
|
|||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
void match_regex(SRule rule, const char *query, bool *matches, char **msg)
|
|
||||||
{
|
|
||||||
|
|
||||||
pcre2_match_data *mdata = pcre2_match_data_create_from_pattern((pcre2_code*)rule->data, NULL);
|
|
||||||
|
|
||||||
if (mdata)
|
|
||||||
{
|
|
||||||
if (pcre2_match((pcre2_code*)rule->data,
|
|
||||||
(PCRE2_SPTR)query, PCRE2_ZERO_TERMINATED,
|
|
||||||
0, 0, mdata, NULL) > 0)
|
|
||||||
{
|
|
||||||
MXS_NOTICE("rule '%s': regex matched on query", rule->name.c_str());
|
|
||||||
*matches = true;
|
|
||||||
*msg = create_error("Permission denied, query matched regular expression.");
|
|
||||||
}
|
|
||||||
|
|
||||||
pcre2_match_data_free(mdata);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MXS_ERROR("Allocation of matching data for PCRE2 failed."
|
|
||||||
" This is most likely caused by a lack of memory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void match_column(SRule rule, GWBUF *queue, bool *matches, char **msg)
|
void match_column(SRule rule, GWBUF *queue, bool *matches, char **msg)
|
||||||
{
|
{
|
||||||
const QC_FIELD_INFO* infos;
|
const QC_FIELD_INFO* infos;
|
||||||
@ -1772,23 +1734,6 @@ void match_function_usage(SRule rule, GWBUF *queue, enum fw_actions mode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void match_wildcard(SRule rule, GWBUF *queue, bool *matches, char **msg)
|
|
||||||
{
|
|
||||||
const QC_FIELD_INFO* infos;
|
|
||||||
size_t n_infos;
|
|
||||||
qc_get_field_info(queue, &infos, &n_infos);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < n_infos; ++i)
|
|
||||||
{
|
|
||||||
if (strcmp(infos[i].column, "*") == 0)
|
|
||||||
{
|
|
||||||
MXS_NOTICE("rule '%s': query contains a wildcard.", rule->name.c_str());
|
|
||||||
*matches = true;
|
|
||||||
*msg = create_error("Usage of wildcard denied.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a query matches a single rule
|
* Check if a query matches a single rule
|
||||||
* @param my_instance Fwfilter instance
|
* @param my_instance Fwfilter instance
|
||||||
@ -1843,7 +1788,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RT_REGEX:
|
case RT_REGEX:
|
||||||
match_regex(rule, query, &matches, &msg);
|
/** Handled in RegexRule::query_matches */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RT_PERMISSION:
|
case RT_PERMISSION:
|
||||||
@ -1872,10 +1817,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RT_WILDCARD:
|
case RT_WILDCARD:
|
||||||
if (is_sql)
|
/** Handled in WildCardRule::query_matches */
|
||||||
{
|
|
||||||
match_wildcard(rule, queue, &matches, &msg);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RT_THROTTLE:
|
case RT_THROTTLE:
|
||||||
@ -1883,13 +1825,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case RT_CLAUSE:
|
case RT_CLAUSE:
|
||||||
if (is_sql && !qc_query_has_clause(queue))
|
/** Handled in WhereClauseRule::query_matches */
|
||||||
{
|
|
||||||
matches = true;
|
|
||||||
msg = create_error("Required WHERE/HAVING clause is missing.");
|
|
||||||
MXS_NOTICE("rule '%s': query has no where/having "
|
|
||||||
"clause, query is denied.", rule->name.c_str());
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -13,10 +13,17 @@
|
|||||||
|
|
||||||
#include "rules.hh"
|
#include "rules.hh"
|
||||||
|
|
||||||
|
#include <maxscale/alloc.h>
|
||||||
#include <maxscale/buffer.h>
|
#include <maxscale/buffer.h>
|
||||||
#include <maxscale/log_manager.h>
|
#include <maxscale/log_manager.h>
|
||||||
|
#include <maxscale/modutil.h>
|
||||||
#include <maxscale/protocol/mysql.h>
|
#include <maxscale/protocol/mysql.h>
|
||||||
|
|
||||||
|
static inline bool query_is_sql(GWBUF* query)
|
||||||
|
{
|
||||||
|
return modutil_is_SQL(query) || modutil_is_SQL_prepare(query);
|
||||||
|
}
|
||||||
|
|
||||||
Rule::Rule(std::string name):
|
Rule::Rule(std::string name):
|
||||||
data(NULL),
|
data(NULL),
|
||||||
name(name),
|
name(name),
|
||||||
@ -74,3 +81,69 @@ bool Rule::matches_query_type(GWBUF* buffer)
|
|||||||
(MYSQL_IS_COM_INIT_DB(GWBUF_DATA(buffer)) &&
|
(MYSQL_IS_COM_INIT_DB(GWBUF_DATA(buffer)) &&
|
||||||
(on_queries & FW_OP_CHANGE_DB));
|
(on_queries & FW_OP_CHANGE_DB));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WildCardRule::matches_query(GWBUF *queue, char **msg)
|
||||||
|
{
|
||||||
|
bool rval = false;
|
||||||
|
|
||||||
|
if (query_is_sql(queue))
|
||||||
|
{
|
||||||
|
const QC_FIELD_INFO* infos;
|
||||||
|
size_t n_infos;
|
||||||
|
qc_get_field_info(queue, &infos, &n_infos);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n_infos; ++i)
|
||||||
|
{
|
||||||
|
if (strcmp(infos[i].column, "*") == 0)
|
||||||
|
{
|
||||||
|
MXS_NOTICE("rule '%s': query contains a wildcard.", name.c_str());
|
||||||
|
rval = true;
|
||||||
|
*msg = create_error("Usage of wildcard denied.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoWhereClauseRule::matches_query(GWBUF* buffer, char** msg)
|
||||||
|
{
|
||||||
|
bool rval = false;
|
||||||
|
|
||||||
|
if (query_is_sql(buffer) && !qc_query_has_clause(buffer))
|
||||||
|
{
|
||||||
|
rval = true;
|
||||||
|
*msg = create_error("Required WHERE/HAVING clause is missing.");
|
||||||
|
MXS_NOTICE("rule '%s': query has no where/having "
|
||||||
|
"clause, query is denied.", name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RegexRule::matches_query(GWBUF* buffer, char** msg)
|
||||||
|
{
|
||||||
|
bool rval = false;
|
||||||
|
|
||||||
|
if (query_is_sql(buffer))
|
||||||
|
{
|
||||||
|
pcre2_code* re = m_re.get();
|
||||||
|
pcre2_match_data *mdata = pcre2_match_data_create_from_pattern(re, NULL);
|
||||||
|
MXS_ABORT_IF_NULL(mdata);
|
||||||
|
|
||||||
|
char* sql;
|
||||||
|
int len;
|
||||||
|
modutil_extract_SQL(buffer, &sql, &len);
|
||||||
|
|
||||||
|
if (pcre2_match(re, (PCRE2_SPTR)sql, (size_t)len, 0, 0, mdata, NULL) > 0)
|
||||||
|
{
|
||||||
|
MXS_NOTICE("rule '%s': regex matched on query", name.c_str());
|
||||||
|
rval = true;
|
||||||
|
*msg = create_error("Permission denied, query matched regular expression.");
|
||||||
|
}
|
||||||
|
|
||||||
|
pcre2_match_data_free(mdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
@ -71,18 +71,18 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Matches if a query has no WHERE clause
|
* Matches if a query has no WHERE clause
|
||||||
*/
|
*/
|
||||||
class WhereClauseRule: public Rule
|
class NoWhereClauseRule: public Rule
|
||||||
{
|
{
|
||||||
WhereClauseRule(const WhereClauseRule&);
|
NoWhereClauseRule(const NoWhereClauseRule&);
|
||||||
WhereClauseRule& operator=(const WhereClauseRule&);
|
NoWhereClauseRule& operator=(const NoWhereClauseRule&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WhereClauseRule(std::string name):
|
NoWhereClauseRule(std::string name):
|
||||||
Rule(name)
|
Rule(name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
~WhereClauseRule()
|
~NoWhereClauseRule()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user