Redid the rules to make it easier to apply different rules to different users
This commit is contained in:
@ -20,19 +20,25 @@
|
|||||||
* @file fwfilter.c
|
* @file fwfilter.c
|
||||||
* Firewall Filter
|
* Firewall Filter
|
||||||
*
|
*
|
||||||
* A filter that acts as a firewall, blocking queries that do not meet the set requirements.
|
* A filter that acts as a firewall, denying queries that do not meet the set requirements.
|
||||||
*
|
*
|
||||||
* This filter uses "rules" to define the blcking parameters. To configure rules into the configuration file,
|
* This filter uses "rules" to define the blcking parameters. To configure rules into the configuration file,
|
||||||
* give each rule a unique name and assing the rule contents by passing a string enclosed in quotes.
|
* give each rule a unique name and assing the rule contents by passing a string enclosed in quotes.
|
||||||
*
|
*
|
||||||
* For example, to block users John and Jane and all users from address range 192.168.0.0/24, the following is needed in the configuration file:
|
* For example, to define a rule denying users from accessing the column 'salary', the following is needed in the configuration file:
|
||||||
* rule1="block users John Jane"
|
|
||||||
* rule2="block 192.168.0.0/255.255.255.0"
|
|
||||||
*
|
*
|
||||||
* Rule syntax
|
* rule1="rule block_salary deny columns salary"
|
||||||
*
|
*
|
||||||
* [block|allow] [users|columns|times] value ... Blocks or allows the given list of values interpreted as certain type
|
* To apply this rule to users John, connecting from any address, and Jane, connecting from the address 192.168.0.1, use the following:
|
||||||
* require where [all|select|update|insert|delete] ... Requires a where clause for the list of query types
|
*
|
||||||
|
* rule2="users John@% Jane@192.168.0.1 rules block_salary"
|
||||||
|
*
|
||||||
|
* Rule syntax TODO: implement timeranges, query type restrictions
|
||||||
|
*
|
||||||
|
* rule NAME deny|allow|require
|
||||||
|
* [wildcard|columns VALUE ...]
|
||||||
|
* [times VALUE...]
|
||||||
|
* [on_queries [all|select|update|delete|insert]...]
|
||||||
*/
|
*/
|
||||||
#include <my_config.h>
|
#include <my_config.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -73,7 +79,6 @@ static void setDownstream(FILTER *instance, void *fsession, DOWNSTREAM *downstre
|
|||||||
static int routeQuery(FILTER *instance, void *fsession, GWBUF *queue);
|
static int routeQuery(FILTER *instance, void *fsession, GWBUF *queue);
|
||||||
static void diagnostic(FILTER *instance, void *fsession, DCB *dcb);
|
static void diagnostic(FILTER *instance, void *fsession, DCB *dcb);
|
||||||
|
|
||||||
|
|
||||||
static FILTER_OBJECT MyObject = {
|
static FILTER_OBJECT MyObject = {
|
||||||
createInstance,
|
createInstance,
|
||||||
newSession,
|
newSession,
|
||||||
@ -106,15 +111,45 @@ typedef enum {
|
|||||||
RT_UNDEFINED,
|
RT_UNDEFINED,
|
||||||
RT_USER,
|
RT_USER,
|
||||||
RT_COLUMN,
|
RT_COLUMN,
|
||||||
RT_TIME
|
RT_TIME,
|
||||||
|
RT_WILDCARD
|
||||||
}ruletype_t;
|
}ruletype_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Linked list of strings.
|
||||||
|
*/
|
||||||
|
typedef struct strlink_t{
|
||||||
|
struct strlink_t *next;
|
||||||
|
char* value;
|
||||||
|
}STRLINK;
|
||||||
|
|
||||||
|
|
||||||
typedef struct timerange_t{
|
typedef struct timerange_t{
|
||||||
struct timerange_t* next;
|
struct timerange_t* next;
|
||||||
struct tm start;
|
struct tm start;
|
||||||
struct tm end;
|
struct tm end;
|
||||||
}TIMERANGE;
|
}TIMERANGE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A structure used to identify individual rules and to store their contents
|
||||||
|
*
|
||||||
|
* Each type of rule has different requirements that are expressed as void pointers.
|
||||||
|
* This allows to match an arbitrary set of rules against a user.
|
||||||
|
*/
|
||||||
|
typedef struct rule_t{
|
||||||
|
void* data;
|
||||||
|
char* name;
|
||||||
|
ruletype_t type;
|
||||||
|
}RULE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Linked list of pointers to a global pool of RULE structs
|
||||||
|
*/
|
||||||
|
typedef struct rulelist_t{
|
||||||
|
RULE* rule;
|
||||||
|
struct rulelist_t* next;
|
||||||
|
}RULELIST;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Linked list of IP adresses and subnet masks
|
* Linked list of IP adresses and subnet masks
|
||||||
*/
|
*/
|
||||||
@ -129,10 +164,12 @@ typedef struct iprange_t{
|
|||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HASHTABLE* htable; /**Usernames and forbidden columns*/
|
HASHTABLE* htable; /**Usernames and forbidden columns*/
|
||||||
|
RULELIST* rules;
|
||||||
IPRANGE* networks;
|
IPRANGE* networks;
|
||||||
TIMERANGE* times;
|
TIMERANGE* times;
|
||||||
|
STRLINK* userstrings;
|
||||||
bool require_where[QUERY_TYPES];
|
bool require_where[QUERY_TYPES];
|
||||||
bool block_wildcard, whitelist_users,whitelist_networks,def_op;
|
bool deny_wildcard, whitelist_users,whitelist_networks,whitelist_times,def_op;
|
||||||
|
|
||||||
} FW_INSTANCE;
|
} FW_INSTANCE;
|
||||||
|
|
||||||
@ -179,12 +216,46 @@ static void* hstrdup(void* fval)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void* hfree(void* fval)
|
static void* hstrfree(void* fval)
|
||||||
{
|
{
|
||||||
free (fval);
|
free (fval);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void* hruledup(void* fval)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(fval == NULL){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
RULELIST *rule = NULL,
|
||||||
|
*ptr = (RULELIST*)fval;
|
||||||
|
|
||||||
|
while(ptr){
|
||||||
|
RULELIST* tmp = (RULELIST*)malloc(sizeof(RULELIST));
|
||||||
|
tmp->next = rule;
|
||||||
|
tmp->rule = ptr->rule;
|
||||||
|
rule = tmp;
|
||||||
|
ptr = ptr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void* hrulefree(void* fval)
|
||||||
|
{
|
||||||
|
RULELIST *ptr = (RULELIST*)fval,*tmp;
|
||||||
|
while(ptr){
|
||||||
|
tmp = ptr;
|
||||||
|
ptr = ptr->next;
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility function to check if a string contains a valid IP address.
|
* Utility function to check if a string contains a valid IP address.
|
||||||
* The string handled as a null-terminated string.
|
* The string handled as a null-terminated string.
|
||||||
@ -244,15 +315,13 @@ char* strip_tags(char* str)
|
|||||||
char *ptr = str, *lead = str, *tail = NULL;
|
char *ptr = str, *lead = str, *tail = NULL;
|
||||||
int len = 0;
|
int len = 0;
|
||||||
while(*ptr != '\0'){
|
while(*ptr != '\0'){
|
||||||
if(isalnum(*ptr) ||
|
|
||||||
*ptr == '.' ||
|
if(*ptr == '"' ||
|
||||||
*ptr == '/' ||
|
*ptr == '\''){
|
||||||
*ptr == ':' ||
|
*ptr = ' ';
|
||||||
*ptr == '-' ){
|
|
||||||
ptr++;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
*ptr++ = ' ';
|
ptr++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Strip leading and trailing whitespace*/
|
/**Strip leading and trailing whitespace*/
|
||||||
@ -401,31 +470,39 @@ bool check_time(char* str)
|
|||||||
&& t->tm_min > -1 && t->tm_min < 60 \
|
&& t->tm_min > -1 && t->tm_min < 60 \
|
||||||
&& t->tm_hour > -1 && t->tm_hour < 24))
|
&& t->tm_hour > -1 && t->tm_hour < 24))
|
||||||
|
|
||||||
|
#define IS_RVRS_TIME(tr) (mktime(&tr->end) < mktime(&tr->start))
|
||||||
/**
|
/**
|
||||||
* Parses a null-terminated string into two time_t structs and adds the
|
* Parses a null-terminated string into two tm_t structs that mark a timerange
|
||||||
* TIMERANGE into the FW_FILTER instance.
|
|
||||||
* @param str String to parse
|
* @param str String to parse
|
||||||
* @param instance FW_FILTER instance
|
* @param instance FW_FILTER instance
|
||||||
|
* @return If successful returns a pointer to the new TIMERANGE instance. If errors occurred or
|
||||||
|
* the timerange was invalid, a NULL pointer is returned.
|
||||||
*/
|
*/
|
||||||
void parse_time(char* str, FW_INSTANCE* instance)
|
TIMERANGE* parse_time(char* str, FW_INSTANCE* instance)
|
||||||
{
|
{
|
||||||
|
|
||||||
TIMERANGE* tr = (TIMERANGE*)malloc(sizeof(TIMERANGE));
|
TIMERANGE* tr = NULL;
|
||||||
int intbuffer[3];
|
int intbuffer[3];
|
||||||
int* idest = intbuffer;
|
int* idest = intbuffer;
|
||||||
char strbuffer[3];
|
char strbuffer[3];
|
||||||
char *ptr,*sdest;
|
char *ptr,*sdest;
|
||||||
struct tm* tmptr;
|
struct tm* tmptr;
|
||||||
|
|
||||||
assert(str != NULL && tr != NULL && instance != NULL);
|
assert(str != NULL && instance != NULL);
|
||||||
|
|
||||||
|
|
||||||
|
tr = (TIMERANGE*)malloc(sizeof(TIMERANGE));
|
||||||
|
|
||||||
|
if(tr == NULL){
|
||||||
|
skygw_log_write(LOGFILE_ERROR, "fwfilter error: malloc returned NULL.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&tr->start,0,sizeof(struct tm));
|
memset(&tr->start,0,sizeof(struct tm));
|
||||||
memset(&tr->end,0,sizeof(struct tm));
|
memset(&tr->end,0,sizeof(struct tm));
|
||||||
ptr = str;
|
ptr = str;
|
||||||
sdest = strbuffer;
|
sdest = strbuffer;
|
||||||
tmptr = &tr->start;
|
tmptr = &tr->start;
|
||||||
tr->next = instance->times;
|
|
||||||
instance->times = tr;
|
|
||||||
|
|
||||||
while(ptr - str < 19){
|
while(ptr - str < 19){
|
||||||
if(isdigit(*ptr)){
|
if(isdigit(*ptr)){
|
||||||
@ -453,20 +530,33 @@ void parse_time(char* str, FW_INSTANCE* instance)
|
|||||||
sdest++;
|
sdest++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**The timerange is reversed*/
|
|
||||||
if(mktime(&tr->end) < mktime(&tr->start)){
|
return tr;
|
||||||
tr = (TIMERANGE*)malloc(sizeof(TIMERANGE));
|
}
|
||||||
tr->next = instance->times;
|
|
||||||
tr->start.tm_hour = 0;
|
|
||||||
tr->start.tm_min = 0;
|
/**
|
||||||
tr->start.tm_sec = 0;
|
* Splits the reversed timerange into two.
|
||||||
tr->end = instance->times->end;
|
*@param tr A reversed timerange
|
||||||
instance->times->end.tm_hour = 23;
|
*@return If the timerange is reversed, returns a pointer to the new TIMERANGE otherwise returns a NULL pointer
|
||||||
instance->times->end.tm_min = 59;
|
*/
|
||||||
instance->times->end.tm_sec = 59;
|
TIMERANGE* split_reverse_time(TIMERANGE* tr)
|
||||||
instance->times = tr;
|
{
|
||||||
|
TIMERANGE* tmp = NULL;
|
||||||
|
|
||||||
|
if(IS_RVRS_TIME(tr)){
|
||||||
|
tmp = (TIMERANGE*)malloc(sizeof(TIMERANGE));
|
||||||
|
tmp->next = tr;
|
||||||
|
tmp->start.tm_hour = 0;
|
||||||
|
tmp->start.tm_min = 0;
|
||||||
|
tmp->start.tm_sec = 0;
|
||||||
|
tmp->end = tr->end;
|
||||||
|
tr->end.tm_hour = 23;
|
||||||
|
tr->end.tm_min = 59;
|
||||||
|
tr->end.tm_sec = 59;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -503,51 +593,181 @@ GetModuleObject()
|
|||||||
return &MyObject;
|
return &MyObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the rule with a name matching the passed string.
|
||||||
|
*
|
||||||
|
* @param tok Name to search for
|
||||||
|
* @param instance A valid FW_FILTER instance
|
||||||
|
* @return A pointer to the matching RULE if found, else returns NULL
|
||||||
|
*/
|
||||||
|
RULE* find_rule(char* tok, FW_INSTANCE* instance)
|
||||||
|
{
|
||||||
|
RULELIST* rlist = instance->rules;
|
||||||
|
|
||||||
|
while(rlist){
|
||||||
|
if(strcmp(rlist->rule->name,tok) == 0){
|
||||||
|
return rlist->rule;
|
||||||
|
}
|
||||||
|
rlist = rlist->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_users(char* rule, FW_INSTANCE* instance)
|
||||||
|
{
|
||||||
|
assert(rule != NULL && instance != NULL);
|
||||||
|
|
||||||
|
STRLINK* link = malloc(sizeof(STRLINK));
|
||||||
|
link->next = instance->userstrings;
|
||||||
|
link->value = strdup(rule);
|
||||||
|
instance->userstrings = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
void link_rules(char* rule, FW_INSTANCE* instance)
|
||||||
|
{
|
||||||
|
assert(rule != NULL && instance != NULL);
|
||||||
|
|
||||||
|
/**Apply rules to users*/
|
||||||
|
|
||||||
|
char *tok, *ruleptr, *userptr;
|
||||||
|
RULELIST* rulelist = NULL;
|
||||||
|
|
||||||
|
userptr = strstr(rule,"users");
|
||||||
|
ruleptr = strstr(rule,"rules");
|
||||||
|
|
||||||
|
if(userptr == NULL || ruleptr == NULL) {
|
||||||
|
/**No rules to apply were found*/
|
||||||
|
skygw_log_write(LOGFILE_TRACE, "Rule syntax was not proper, 'user' or 'rules' was found but not the other: %s",rule);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tok = strtok(ruleptr," ,");
|
||||||
|
tok = strtok(NULL," ,");
|
||||||
|
|
||||||
|
while(tok)
|
||||||
|
{
|
||||||
|
RULE* rule_found = NULL;
|
||||||
|
|
||||||
|
if((rule_found = find_rule(tok,instance)) != NULL)
|
||||||
|
{
|
||||||
|
RULELIST* tmp_rl = (RULELIST*)calloc(1,sizeof(RULELIST));
|
||||||
|
tmp_rl->rule = rule_found;
|
||||||
|
tmp_rl->next = rulelist;
|
||||||
|
rulelist = tmp_rl;
|
||||||
|
|
||||||
|
}
|
||||||
|
tok = strtok(NULL," ,");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply this list of rules to all the listed users
|
||||||
|
*/
|
||||||
|
|
||||||
|
*(ruleptr) = '\0';
|
||||||
|
userptr = strtok(rule," ,");
|
||||||
|
userptr = strtok(NULL," ,");
|
||||||
|
|
||||||
|
while(userptr)
|
||||||
|
{
|
||||||
|
if(hashtable_add(instance->htable,
|
||||||
|
(void *)userptr,
|
||||||
|
(void *)rulelist) == 0)
|
||||||
|
{
|
||||||
|
skygw_log_write(LOGFILE_TRACE, "Name conflict in fwfilter: %s was found twice.",tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
userptr = strtok(NULL," ,");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void parse_rule(char* rule, FW_INSTANCE* instance)
|
void parse_rule(char* rule, FW_INSTANCE* instance)
|
||||||
{
|
{
|
||||||
char* ptr = rule;
|
assert(rule != NULL && instance != NULL);
|
||||||
bool allow,block,mode;
|
|
||||||
|
char *rulecpy = strdup(rule);
|
||||||
|
char *ptr = rule;
|
||||||
|
char *tok = strtok(rulecpy," ,");
|
||||||
|
bool allow,deny,mode;
|
||||||
|
RULE* ruledef = NULL;
|
||||||
|
|
||||||
|
if(tok == NULL) goto retblock;
|
||||||
|
|
||||||
|
if(strcmp("rule",tok) == 0){ /**Define a new rule*/
|
||||||
|
|
||||||
|
tok = strtok(NULL," ,");
|
||||||
|
|
||||||
|
if(tok == NULL) goto retblock;
|
||||||
|
|
||||||
|
RULELIST* rlist = NULL;
|
||||||
|
|
||||||
|
ruledef = (RULE*)malloc(sizeof(RULE));
|
||||||
|
rlist = (RULELIST*)malloc(sizeof(RULELIST));
|
||||||
|
ruledef->name = strdup(tok);
|
||||||
|
ruledef->type = RT_UNDEFINED;
|
||||||
|
ruledef->data = NULL;
|
||||||
|
rlist->rule = ruledef;
|
||||||
|
rlist->next = instance->rules;
|
||||||
|
instance->rules = rlist;
|
||||||
|
|
||||||
|
}else if(strcmp("users",tok) == 0){
|
||||||
|
|
||||||
|
/**Apply rules to users*/
|
||||||
|
add_users(rule, instance);
|
||||||
|
goto retblock;
|
||||||
|
}
|
||||||
|
|
||||||
|
tok = strtok(NULL, " ,");
|
||||||
|
|
||||||
/**IP range rules*/
|
/**IP range rules*/
|
||||||
if((allow = (strstr(rule,"allow") != NULL)) ||
|
if((allow = (strcmp(tok,"allow") == 0)) ||
|
||||||
(block = (strstr(rule,"block") != NULL))){
|
(deny = (strcmp(tok,"deny") == 0))){
|
||||||
|
|
||||||
mode = allow ? true:false;
|
mode = allow ? true:false;
|
||||||
|
tok = strtok(NULL, " ,");
|
||||||
|
|
||||||
if((ptr = strchr(rule,' ')) == NULL){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ptr++;
|
|
||||||
|
|
||||||
if(valid_ip(ptr)){ /**Add IP address range*/
|
|
||||||
|
|
||||||
instance->whitelist_networks = mode;
|
|
||||||
IPRANGE* rng = calloc(1,sizeof(IPRANGE));
|
|
||||||
if(rng){
|
|
||||||
rng->ip = strtoip(ptr);
|
|
||||||
rng->mask = strtosubmask(ptr);
|
|
||||||
rng->next = instance->networks;
|
|
||||||
instance->networks = rng;
|
|
||||||
}
|
|
||||||
|
|
||||||
}else{ /**Add rules on usernames or columns*/
|
|
||||||
|
|
||||||
char *tok = strtok(ptr," ,\0");
|
|
||||||
bool is_user = false, is_column = false, is_time = false;
|
bool is_user = false, is_column = false, is_time = false;
|
||||||
|
|
||||||
if(strcmp(tok,"wildcard") == 0){
|
if(strcmp(tok,"wildcard") == 0)
|
||||||
instance->block_wildcard = block ? true : false;
|
{
|
||||||
return;
|
ruledef->type = RT_WILDCARD;
|
||||||
|
ruledef->data = (void*)mode;
|
||||||
|
}
|
||||||
|
else if(strcmp(tok,"columns") == 0)
|
||||||
|
{
|
||||||
|
STRLINK *tail = NULL,*current;
|
||||||
|
ruledef->type = RT_COLUMN;
|
||||||
|
tok = strtok(NULL, " ,");
|
||||||
|
while(tok){
|
||||||
|
current = malloc(sizeof(STRLINK));
|
||||||
|
current->value = strdup(tok);
|
||||||
|
current->next = tail;
|
||||||
|
tail = current;
|
||||||
|
tok = strtok(NULL, " ,");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strcmp(tok,"users") == 0){/**Adding users*/
|
ruledef->data = (void*)tail;
|
||||||
instance->whitelist_users = mode;
|
|
||||||
is_user = true;
|
|
||||||
}else if(strcmp(tok,"columns") == 0){/**Adding Columns*/
|
|
||||||
is_column = true;
|
|
||||||
}else if(strcmp(tok,"times") == 0){
|
|
||||||
is_time = true;
|
|
||||||
}
|
}
|
||||||
|
else if(strcmp(tok,"times") == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
tok = strtok(NULL, " ,");
|
||||||
|
ruledef->type = RT_TIME;
|
||||||
|
|
||||||
|
TIMERANGE *tr = parse_time(tok,instance);
|
||||||
|
|
||||||
|
if(IS_RVRS_TIME(tr)){
|
||||||
|
TIMERANGE *tmptr = split_reverse_time(tr);
|
||||||
|
tr = tmptr;
|
||||||
|
}
|
||||||
|
ruledef->data = (void*)tr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
goto retblock;
|
||||||
|
|
||||||
tok = strtok(NULL," ,\0");
|
tok = strtok(NULL," ,\0");
|
||||||
|
|
||||||
@ -576,7 +796,7 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}else if((ptr = strstr(rule,"require")) != NULL){
|
}else if((ptr = strstr(rule,"require")) != NULL){
|
||||||
|
|
||||||
@ -605,7 +825,8 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
retblock:
|
||||||
|
free(rulecpy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -626,13 +847,14 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
|||||||
}
|
}
|
||||||
int i;
|
int i;
|
||||||
HASHTABLE* ht;
|
HASHTABLE* ht;
|
||||||
|
STRLINK *ptr,*tmp;
|
||||||
|
|
||||||
if((ht = hashtable_alloc(7, hashkeyfun, hashcmpfun)) == NULL){
|
if((ht = hashtable_alloc(7, hashkeyfun, hashcmpfun)) == NULL){
|
||||||
skygw_log_write(LOGFILE_ERROR, "Unable to allocate hashtable.");
|
skygw_log_write(LOGFILE_ERROR, "Unable to allocate hashtable.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
hashtable_memory_fns(ht,hstrdup,NULL,hfree,NULL);
|
hashtable_memory_fns(ht,hstrdup,hruledup,hstrfree,hrulefree);
|
||||||
|
|
||||||
my_instance->htable = ht;
|
my_instance->htable = ht;
|
||||||
my_instance->def_op = true;
|
my_instance->def_op = true;
|
||||||
@ -642,6 +864,17 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
|||||||
parse_rule(strip_tags(params[i]->value),my_instance);
|
parse_rule(strip_tags(params[i]->value),my_instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**Apply the rules to users*/
|
||||||
|
ptr = my_instance->userstrings;
|
||||||
|
while(ptr){
|
||||||
|
link_rules(ptr->value,my_instance);
|
||||||
|
tmp = ptr;
|
||||||
|
ptr = ptr->next;
|
||||||
|
free(tmp->value);
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
return (FILTER *)my_instance;
|
return (FILTER *)my_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,11 +1011,79 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
struct tm tm_before,tm_after;
|
struct tm tm_before,tm_after;
|
||||||
bool accept = false, match = false;
|
bool accept = false, match = false;
|
||||||
char *where;
|
char *where;
|
||||||
|
char username[128];
|
||||||
uint32_t ip;
|
uint32_t ip;
|
||||||
ruletype_t rtype = RT_UNDEFINED;
|
ruletype_t rtype = RT_UNDEFINED;
|
||||||
skygw_query_op_t queryop;
|
skygw_query_op_t queryop;
|
||||||
DCB* dcb = my_session->session->client;
|
DCB* dcb = my_session->session->client;
|
||||||
|
RULELIST* rulelist = NULL;
|
||||||
|
STRLINK* strln = NULL;
|
||||||
|
|
||||||
|
sprintf(username,"%s@%s",dcb->user,dcb->remote);
|
||||||
|
|
||||||
|
rulelist = (RULELIST*)hashtable_fetch(my_instance->htable, username);
|
||||||
|
if(rulelist == NULL){
|
||||||
|
sprintf(username,"%s@%%",dcb->user);
|
||||||
|
rulelist = (RULELIST*)hashtable_fetch(my_instance->htable, username);
|
||||||
|
}
|
||||||
|
if(rulelist == NULL){
|
||||||
|
sprintf(username,"%%@%s",dcb->remote);
|
||||||
|
rulelist = (RULELIST*)hashtable_fetch(my_instance->htable, username);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rulelist == NULL){
|
||||||
|
sprintf(username,"%%@%%");
|
||||||
|
rulelist = (RULELIST*)hashtable_fetch(my_instance->htable, username);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rulelist == NULL){
|
||||||
|
accept = true;
|
||||||
|
goto queryresolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(rulelist){
|
||||||
|
switch(rulelist->rule->type){
|
||||||
|
|
||||||
|
case RT_UNDEFINED:
|
||||||
|
accept = true;
|
||||||
|
goto queryresolved;
|
||||||
|
|
||||||
|
case RT_COLUMN:
|
||||||
|
|
||||||
|
if(modutil_is_SQL(queue)){
|
||||||
|
|
||||||
|
if(!query_is_parsed(queue)){
|
||||||
|
parse_query(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(skygw_is_real_query(queue)){
|
||||||
|
|
||||||
|
strln = (STRLINK*)rulelist->rule->data;
|
||||||
|
where = skygw_get_affected_fields(queue);
|
||||||
|
|
||||||
|
if(where != NULL){
|
||||||
|
|
||||||
|
while(strln){
|
||||||
|
if(strstr(where,strln->value)){
|
||||||
|
accept = false;
|
||||||
|
goto queryresolved;
|
||||||
|
}
|
||||||
|
strln = strln->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
rulelist = rulelist->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rulelist == NULL){
|
||||||
|
accept = true;
|
||||||
|
goto queryresolved;
|
||||||
|
}
|
||||||
|
|
||||||
time(&time_now);
|
time(&time_now);
|
||||||
tm_now = localtime(&time_now);
|
tm_now = localtime(&time_now);
|
||||||
@ -797,7 +1098,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
skygw_log_write(LOGFILE_TRACE, "Firewall: %s@%s was %s.",
|
skygw_log_write(LOGFILE_TRACE, "Firewall: %s@%s was %s.",
|
||||||
dcb->user, dcb->remote,
|
dcb->user, dcb->remote,
|
||||||
(my_instance->whitelist_users ?
|
(my_instance->whitelist_users ?
|
||||||
"allowed":"blocked"));
|
"allowed":"denied"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!match){
|
if(!match){
|
||||||
@ -809,7 +1110,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
match = true;
|
match = true;
|
||||||
accept = my_instance->whitelist_networks;
|
accept = my_instance->whitelist_networks;
|
||||||
skygw_log_write(LOGFILE_TRACE, "Firewall: %s@%s was %s.",
|
skygw_log_write(LOGFILE_TRACE, "Firewall: %s@%s was %s.",
|
||||||
dcb->user,dcb->remote,(my_instance->whitelist_networks ? "allowed":"blocked"));
|
dcb->user,dcb->remote,(my_instance->whitelist_networks ? "allowed":"denied"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ipranges = ipranges->next;
|
ipranges = ipranges->next;
|
||||||
@ -831,10 +1132,10 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
time_t now = mktime(tm_now);
|
time_t now = mktime(tm_now);
|
||||||
double to_before = difftime(now,before);
|
double to_before = difftime(now,before);
|
||||||
double to_after = difftime(now,after);
|
double to_after = difftime(now,after);
|
||||||
/**Restricted time*/
|
/**Inside time range*/
|
||||||
if(to_before > 0.0 && to_after < 0.0){
|
if(to_before > 0.0 && to_after < 0.0){
|
||||||
match = true;
|
match = true;
|
||||||
accept = false;
|
accept = my_instance->whitelist_times;
|
||||||
skygw_log_write(LOGFILE_TRACE, "Firewall: Query entered during restricted time: %s.",asctime(tm_now));
|
skygw_log_write(LOGFILE_TRACE, "Firewall: Query entered during restricted time: %s.",asctime(tm_now));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -857,6 +1158,10 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
|
|
||||||
queryop = query_classifier_get_operation(queue);
|
queryop = query_classifier_get_operation(queue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*TODO: Add column name requirement in addition to query type, match rules against users
|
||||||
|
*/
|
||||||
|
|
||||||
if(my_instance->require_where[ALL] ||
|
if(my_instance->require_where[ALL] ||
|
||||||
(my_instance->require_where[SELECT] && queryop == QUERY_OP_SELECT) ||
|
(my_instance->require_where[SELECT] && queryop == QUERY_OP_SELECT) ||
|
||||||
(my_instance->require_where[UPDATE] && queryop == QUERY_OP_UPDATE) ||
|
(my_instance->require_where[UPDATE] && queryop == QUERY_OP_UPDATE) ||
|
||||||
@ -864,7 +1169,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
(my_instance->require_where[DELETE] && queryop == QUERY_OP_DELETE)){
|
(my_instance->require_where[DELETE] && queryop == QUERY_OP_DELETE)){
|
||||||
match = true;
|
match = true;
|
||||||
accept = false;
|
accept = false;
|
||||||
skygw_log_write(LOGFILE_TRACE, "Firewall: query does not have a where clause or a having clause, blocking it: %.*s",GWBUF_LENGTH(queue),(char*)(queue->start + 5));
|
skygw_log_write(LOGFILE_TRACE, "Firewall: query does not have a where clause or a having clause, denying it: %.*s",GWBUF_LENGTH(queue) - 5,(char*)(queue->start + 5));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,12 +1177,12 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
|
|
||||||
where = skygw_get_affected_fields(queue);
|
where = skygw_get_affected_fields(queue);
|
||||||
|
|
||||||
if(my_instance->block_wildcard &&
|
if(my_instance->deny_wildcard &&
|
||||||
where && strchr(where,'*') != NULL)
|
where && strchr(where,'*') != NULL)
|
||||||
{
|
{
|
||||||
match = true;
|
match = true;
|
||||||
accept = false;
|
accept = false;
|
||||||
skygw_log_write(LOGFILE_TRACE, "Firewall: query contains wildcard, blocking it: %.*s",GWBUF_LENGTH(queue),(char*)(queue->start + 5));
|
skygw_log_write(LOGFILE_TRACE, "Firewall: query contains wildcard, denying it: %.*s",GWBUF_LENGTH(queue),(char*)(queue->start + 5));
|
||||||
}
|
}
|
||||||
else if(where)
|
else if(where)
|
||||||
{
|
{
|
||||||
@ -888,7 +1193,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
if(rtype == RT_COLUMN){
|
if(rtype == RT_COLUMN){
|
||||||
match = true;
|
match = true;
|
||||||
accept = false;
|
accept = false;
|
||||||
skygw_log_write(LOGFILE_TRACE, "Firewall: query contains a forbidden column %s, blocking it: %.*s",tok,GWBUF_LENGTH(queue),(char*)(queue->start + 5));
|
skygw_log_write(LOGFILE_TRACE, "Firewall: query contains a forbidden column %s, denying it: %.*s",tok,GWBUF_LENGTH(queue),(char*)(queue->start + 5));
|
||||||
}
|
}
|
||||||
tok = strtok(NULL," ");
|
tok = strtok(NULL," ");
|
||||||
}
|
}
|
||||||
@ -905,6 +1210,8 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
accept = my_instance->def_op;
|
accept = my_instance->def_op;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queryresolved:
|
||||||
|
|
||||||
if(accept){
|
if(accept){
|
||||||
|
|
||||||
return my_session->down.routeQuery(my_session->down.instance,
|
return my_session->down.routeQuery(my_session->down.instance,
|
||||||
@ -913,9 +1220,7 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
|
|
||||||
gwbuf_free(queue);
|
gwbuf_free(queue);
|
||||||
GWBUF* forward = gen_dummy_error(my_session);
|
GWBUF* forward = gen_dummy_error(my_session);
|
||||||
dcb->func.write(dcb,forward);
|
return dcb->func.write(dcb,forward);
|
||||||
//gwbuf_free(forward);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user