Added logging of matching and non-matching queries to dbfwfilter
When configured to log matching queries, the dbfwfilter will log all queries that match a rule. The rule name, user name and the query itself are logged. It is also possible to match all queries that do not match a rule. Only the user name and query is logged in this mode.
This commit is contained in:
parent
5efd5d8927
commit
6055ba25bf
@ -36,6 +36,18 @@ The database firewall filter has one mandatory parameter that defines the locati
|
||||
|
||||
This parameter is optional and determines what action is taken when a query matches a rule. The value can be either `allow`, which allows all matching queries to proceed but blocks those that don't match, or `block`, which blocks all matching queries, or `ignore` which allows all queries to proceed.
|
||||
|
||||
#### `log_match`
|
||||
|
||||
Log all queries that match a rule. For the `any` matching mode, the name of
|
||||
the rule that matched is logged and for other matching modes, the name of
|
||||
the last matching rule is logged. In addition to the rule name the matched
|
||||
user and the query itself is logged. The log messages are logged at the notice level.
|
||||
|
||||
#### `log_no_match`
|
||||
|
||||
Log all queries that do not match a rule. The matched user and the query is
|
||||
logged. The log messages are logged at the notice level.
|
||||
|
||||
## Rule syntax
|
||||
|
||||
The rules are defined by using the following syntax:
|
||||
|
@ -243,6 +243,16 @@ enum fw_actions
|
||||
FW_ACTION_IGNORE
|
||||
};
|
||||
|
||||
/**
|
||||
* Logging options for matched queries
|
||||
*/
|
||||
#define FW_LOG_NONE 0x00
|
||||
#define FW_LOG_MATCH 0x01
|
||||
#define FW_LOG_NO_MATCH 0x02
|
||||
|
||||
/** Maximum length of the match/nomatch messages */
|
||||
#define FW_MAX_SQL_LEN 400
|
||||
|
||||
/**
|
||||
* The Firewall filter instance.
|
||||
*/
|
||||
@ -252,6 +262,7 @@ typedef struct
|
||||
RULELIST* rules; /*< List of all the rules */
|
||||
STRLINK* userstrings; /*< Temporary list of raw strings of users */
|
||||
enum fw_actions action; /*< Default operation mode, defaults to deny */
|
||||
int log_match; /*< Log matching and/or non-matching queries */
|
||||
SPINLOCK* lock; /*< Instance spinlock */
|
||||
int idgen; /*< UID generator */
|
||||
int regflags;
|
||||
@ -1251,6 +1262,7 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
|
||||
my_instance->htable = ht;
|
||||
my_instance->action = FW_ACTION_BLOCK;
|
||||
my_instance->log_match = FW_LOG_NONE;
|
||||
my_instance->userstrings = NULL;
|
||||
my_instance->regflags = 0;
|
||||
|
||||
@ -1260,6 +1272,16 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
||||
{
|
||||
filename = params[i]->value;
|
||||
}
|
||||
else if (strcmp(params[i]->name, "log_match") == 0 &&
|
||||
config_truth_value(params[i]->value))
|
||||
{
|
||||
my_instance->log_match |= FW_LOG_MATCH;
|
||||
}
|
||||
else if (strcmp(params[i]->name, "log_no_match") == 0 &&
|
||||
config_truth_value(params[i]->value))
|
||||
{
|
||||
my_instance->log_match |= FW_LOG_NO_MATCH;
|
||||
}
|
||||
else if (strcmp(params[i]->name, "action") == 0)
|
||||
{
|
||||
if (strcmp(params[i]->value, "allow") == 0)
|
||||
@ -1874,49 +1896,34 @@ queryresolved:
|
||||
* @param user The user whose rulelist is 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, USER* user)
|
||||
bool check_match_any(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
GWBUF *queue, USER* user, char** rulename)
|
||||
{
|
||||
bool is_sql, rval = false;
|
||||
int qlen;
|
||||
char *fullquery = NULL, *ptr;
|
||||
unsigned char* memptr = (unsigned char*) queue->start;
|
||||
RULELIST* rulelist;
|
||||
is_sql = modutil_is_SQL(queue) || modutil_is_SQL_prepare(queue);
|
||||
bool rval = false;
|
||||
|
||||
if (is_sql)
|
||||
if ((rulelist = user->rules_or) &&
|
||||
(modutil_is_SQL(queue) || modutil_is_SQL_prepare(queue)))
|
||||
{
|
||||
qlen = gw_mysql_get_byte3(memptr);
|
||||
qlen = qlen < 0xffffff ? qlen : 0xffffff;
|
||||
fullquery = malloc((qlen) * sizeof(char));
|
||||
memcpy(fullquery, memptr + 5, qlen - 1);
|
||||
memset(fullquery + qlen - 1, 0, 1);
|
||||
}
|
||||
|
||||
if ((rulelist = user->rules_or) == NULL)
|
||||
{
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
while (rulelist)
|
||||
{
|
||||
|
||||
if (!rule_is_active(rulelist->rule))
|
||||
char *fullquery = modutil_get_SQL(queue);
|
||||
while (rulelist)
|
||||
{
|
||||
if (!rule_is_active(rulelist->rule))
|
||||
{
|
||||
rulelist = rulelist->next;
|
||||
continue;
|
||||
}
|
||||
if (rule_matches(my_instance, my_session, queue, user, rulelist, fullquery))
|
||||
{
|
||||
*rulename = rulelist->rule->name;
|
||||
rval = true;
|
||||
break;
|
||||
}
|
||||
rulelist = rulelist->next;
|
||||
continue;
|
||||
}
|
||||
if ((rval = rule_matches(my_instance, my_session, queue, user, rulelist, fullquery)))
|
||||
{
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
rulelist = rulelist->next;
|
||||
free(fullquery);
|
||||
}
|
||||
|
||||
retblock:
|
||||
|
||||
free(fullquery);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
@ -1928,75 +1935,47 @@ retblock:
|
||||
* @param user The user whose rulelist is checked
|
||||
* @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,
|
||||
USER* user,
|
||||
bool strict_all)
|
||||
bool check_match_all(FW_INSTANCE* my_instance, FW_SESSION* my_session,
|
||||
GWBUF *queue, USER* user, bool strict_all, char** rulename)
|
||||
{
|
||||
bool is_sql, rval = true;
|
||||
bool rval = false;
|
||||
bool have_active_rule = false;
|
||||
int qlen;
|
||||
unsigned char* memptr = (unsigned char*) queue->start;
|
||||
char *fullquery = NULL, *ptr;
|
||||
RULELIST* rulelist = strict_all ? user->rules_strict_and : user->rules_and;
|
||||
|
||||
RULELIST* rulelist;
|
||||
is_sql = modutil_is_SQL(queue) || modutil_is_SQL_prepare(queue);
|
||||
|
||||
if (is_sql)
|
||||
if (rulelist && (modutil_is_SQL(queue) || modutil_is_SQL_prepare(queue)))
|
||||
{
|
||||
qlen = gw_mysql_get_byte3(memptr);
|
||||
qlen = qlen < 0xffffff ? qlen : 0xffffff;
|
||||
fullquery = malloc((qlen) * sizeof(char));
|
||||
memcpy(fullquery, memptr + 5, qlen - 1);
|
||||
memset(fullquery + qlen - 1, 0, 1);
|
||||
}
|
||||
|
||||
if (strict_all)
|
||||
{
|
||||
rulelist = user->rules_strict_and;
|
||||
}
|
||||
else
|
||||
{
|
||||
rulelist = user->rules_and;
|
||||
}
|
||||
|
||||
if (rulelist == NULL)
|
||||
{
|
||||
rval = false;
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
while (rulelist)
|
||||
{
|
||||
|
||||
if (!rule_is_active(rulelist->rule))
|
||||
char *fullquery = modutil_get_SQL(queue);
|
||||
rval = true;
|
||||
while (rulelist)
|
||||
{
|
||||
rulelist = rulelist->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
have_active_rule = true;
|
||||
|
||||
if (!rule_matches(my_instance, my_session, queue, user, rulelist, fullquery))
|
||||
{
|
||||
rval = false;
|
||||
if (strict_all)
|
||||
if (!rule_is_active(rulelist->rule))
|
||||
{
|
||||
break;
|
||||
rulelist = rulelist->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
have_active_rule = true;
|
||||
|
||||
if (!rule_matches(my_instance, my_session, queue, user, rulelist, fullquery))
|
||||
{
|
||||
*rulename = rulelist->rule->name;
|
||||
rval = false;
|
||||
if (strict_all)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
rulelist = rulelist->next;
|
||||
}
|
||||
rulelist = rulelist->next;
|
||||
|
||||
if (!have_active_rule)
|
||||
{
|
||||
/** No active rules */
|
||||
rval = false;
|
||||
}
|
||||
free(fullquery);
|
||||
}
|
||||
|
||||
if (!have_active_rule)
|
||||
{
|
||||
/** No active rules */
|
||||
rval = false;
|
||||
}
|
||||
|
||||
retblock:
|
||||
free(fullquery);
|
||||
return rval;
|
||||
}
|
||||
|
||||
@ -2072,9 +2051,10 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
if (user)
|
||||
{
|
||||
bool match = false;
|
||||
if (check_match_any(my_instance, my_session, queue, user) ||
|
||||
check_match_all(my_instance, my_session, queue, user, false) ||
|
||||
check_match_all(my_instance, my_session, queue, user, true))
|
||||
char* rname;
|
||||
if (check_match_any(my_instance, my_session, queue, user, &rname) ||
|
||||
check_match_all(my_instance, my_session, queue, user, false, &rname) ||
|
||||
check_match_all(my_instance, my_session, queue, user, true, &rname))
|
||||
{
|
||||
match = true;
|
||||
}
|
||||
@ -2099,6 +2079,26 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
||||
query_ok = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (my_instance->log_match != FW_LOG_NONE)
|
||||
{
|
||||
char *sql;
|
||||
int len;
|
||||
if (modutil_extract_SQL(queue, &sql, &len))
|
||||
{
|
||||
len = MIN(len, FW_MAX_SQL_LEN);
|
||||
if (match && my_instance->log_match & FW_LOG_MATCH)
|
||||
{
|
||||
MXS_NOTICE("Rule '%s' matched by '%s': %.*s", rname,
|
||||
user->name, len, sql);
|
||||
}
|
||||
else if (!match && my_instance->log_match & FW_LOG_NO_MATCH)
|
||||
{
|
||||
MXS_NOTICE("Query by '%s' was not matched: %.*s",
|
||||
user->name, len, sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** If the instance is in whitelist mode, only users that have a rule
|
||||
* defined for them are allowed */
|
||||
|
Loading…
x
Reference in New Issue
Block a user