Redid some of the code to make it easier to add more rule types.
Added a timerange for the rules when they are active, defaults to always on. Added custom error messages.
This commit is contained in:
@ -109,9 +109,9 @@ typedef enum{
|
|||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RT_UNDEFINED,
|
RT_UNDEFINED,
|
||||||
RT_USER,
|
|
||||||
RT_COLUMN,
|
RT_COLUMN,
|
||||||
RT_TIME,
|
RT_TIME,
|
||||||
|
RT_PERMISSION,
|
||||||
RT_WILDCARD
|
RT_WILDCARD
|
||||||
}ruletype_t;
|
}ruletype_t;
|
||||||
|
|
||||||
@ -140,6 +140,8 @@ typedef struct rule_t{
|
|||||||
void* data;
|
void* data;
|
||||||
char* name;
|
char* name;
|
||||||
ruletype_t type;
|
ruletype_t type;
|
||||||
|
bool allow;
|
||||||
|
TIMERANGE* active;
|
||||||
}RULE;
|
}RULE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -490,7 +492,6 @@ TIMERANGE* parse_time(char* str, FW_INSTANCE* instance)
|
|||||||
|
|
||||||
assert(str != NULL && instance != NULL);
|
assert(str != NULL && instance != NULL);
|
||||||
|
|
||||||
|
|
||||||
tr = (TIMERANGE*)malloc(sizeof(TIMERANGE));
|
tr = (TIMERANGE*)malloc(sizeof(TIMERANGE));
|
||||||
|
|
||||||
if(tr == NULL){
|
if(tr == NULL){
|
||||||
@ -520,6 +521,10 @@ TIMERANGE* parse_time(char* str, FW_INSTANCE* instance)
|
|||||||
|
|
||||||
CHK_TIMES(tmptr);
|
CHK_TIMES(tmptr);
|
||||||
|
|
||||||
|
if(*ptr == '\0'){
|
||||||
|
return tr;
|
||||||
|
}
|
||||||
|
|
||||||
idest = intbuffer;
|
idest = intbuffer;
|
||||||
tmptr = &tr->end;
|
tmptr = &tr->end;
|
||||||
}
|
}
|
||||||
@ -617,7 +622,7 @@ void add_users(char* rule, FW_INSTANCE* instance)
|
|||||||
{
|
{
|
||||||
assert(rule != NULL && instance != NULL);
|
assert(rule != NULL && instance != NULL);
|
||||||
|
|
||||||
STRLINK* link = malloc(sizeof(STRLINK));
|
STRLINK* link = calloc(1,sizeof(STRLINK));
|
||||||
link->next = instance->userstrings;
|
link->next = instance->userstrings;
|
||||||
link->value = strdup(rule);
|
link->value = strdup(rule);
|
||||||
instance->userstrings = link;
|
instance->userstrings = link;
|
||||||
@ -687,7 +692,6 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
|
|||||||
assert(rule != NULL && instance != NULL);
|
assert(rule != NULL && instance != NULL);
|
||||||
|
|
||||||
char *rulecpy = strdup(rule);
|
char *rulecpy = strdup(rule);
|
||||||
char *ptr = rule;
|
|
||||||
char *tok = strtok(rulecpy," ,");
|
char *tok = strtok(rulecpy," ,");
|
||||||
bool allow,deny,mode;
|
bool allow,deny,mode;
|
||||||
RULE* ruledef = NULL;
|
RULE* ruledef = NULL;
|
||||||
@ -702,11 +706,10 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
|
|||||||
|
|
||||||
RULELIST* rlist = NULL;
|
RULELIST* rlist = NULL;
|
||||||
|
|
||||||
ruledef = (RULE*)malloc(sizeof(RULE));
|
ruledef = (RULE*)calloc(1,sizeof(RULE));
|
||||||
rlist = (RULELIST*)malloc(sizeof(RULELIST));
|
rlist = (RULELIST*)calloc(1,sizeof(RULELIST));
|
||||||
ruledef->name = strdup(tok);
|
ruledef->name = strdup(tok);
|
||||||
ruledef->type = RT_UNDEFINED;
|
ruledef->type = RT_UNDEFINED;
|
||||||
ruledef->data = NULL;
|
|
||||||
rlist->rule = ruledef;
|
rlist->rule = ruledef;
|
||||||
rlist->next = instance->rules;
|
rlist->next = instance->rules;
|
||||||
instance->rules = rlist;
|
instance->rules = rlist;
|
||||||
@ -720,27 +723,25 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
|
|||||||
|
|
||||||
tok = strtok(NULL, " ,");
|
tok = strtok(NULL, " ,");
|
||||||
|
|
||||||
/**IP range rules*/
|
|
||||||
if((allow = (strcmp(tok,"allow") == 0)) ||
|
if((allow = (strcmp(tok,"allow") == 0)) ||
|
||||||
(deny = (strcmp(tok,"deny") == 0))){
|
(deny = (strcmp(tok,"deny") == 0))){
|
||||||
|
|
||||||
mode = allow ? true:false;
|
mode = allow ? true:false;
|
||||||
|
ruledef->allow = mode;
|
||||||
|
ruledef->type = RT_PERMISSION;
|
||||||
tok = strtok(NULL, " ,");
|
tok = strtok(NULL, " ,");
|
||||||
|
|
||||||
|
|
||||||
bool is_user = false, is_column = false, is_time = false;
|
|
||||||
|
|
||||||
if(strcmp(tok,"wildcard") == 0)
|
if(strcmp(tok,"wildcard") == 0)
|
||||||
{
|
{
|
||||||
ruledef->type = RT_WILDCARD;
|
ruledef->type = RT_WILDCARD;
|
||||||
ruledef->data = (void*)mode;
|
|
||||||
}
|
}
|
||||||
else if(strcmp(tok,"columns") == 0)
|
else if(strcmp(tok,"columns") == 0)
|
||||||
{
|
{
|
||||||
STRLINK *tail = NULL,*current;
|
STRLINK *tail = NULL,*current;
|
||||||
ruledef->type = RT_COLUMN;
|
ruledef->type = RT_COLUMN;
|
||||||
tok = strtok(NULL, " ,");
|
tok = strtok(NULL, " ,");
|
||||||
while(tok){
|
while(tok && strcmp(tok,"times") != 0){
|
||||||
current = malloc(sizeof(STRLINK));
|
current = malloc(sizeof(STRLINK));
|
||||||
current->value = strdup(tok);
|
current->value = strdup(tok);
|
||||||
current->next = tail;
|
current->next = tail;
|
||||||
@ -755,78 +756,21 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
|
|||||||
{
|
{
|
||||||
|
|
||||||
tok = strtok(NULL, " ,");
|
tok = strtok(NULL, " ,");
|
||||||
ruledef->type = RT_TIME;
|
|
||||||
|
|
||||||
TIMERANGE *tr = parse_time(tok,instance);
|
TIMERANGE *tr = parse_time(tok,instance);
|
||||||
|
|
||||||
if(IS_RVRS_TIME(tr)){
|
if(IS_RVRS_TIME(tr)){
|
||||||
TIMERANGE *tmptr = split_reverse_time(tr);
|
tr = split_reverse_time(tr);
|
||||||
tr = tmptr;
|
|
||||||
}
|
}
|
||||||
ruledef->data = (void*)tr;
|
ruledef->active = tr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
goto retblock;
|
goto retblock;
|
||||||
|
|
||||||
tok = strtok(NULL," ,\0");
|
|
||||||
|
|
||||||
if(is_user || is_column || is_time){
|
|
||||||
while(tok){
|
|
||||||
|
|
||||||
/**Add value to hashtable*/
|
|
||||||
|
|
||||||
ruletype_t rtype =
|
|
||||||
is_user ? RT_USER :
|
|
||||||
is_column ? RT_COLUMN:
|
|
||||||
is_time ? RT_TIME :
|
|
||||||
RT_UNDEFINED;
|
|
||||||
|
|
||||||
if(rtype == RT_USER || rtype == RT_COLUMN)
|
|
||||||
{
|
|
||||||
hashtable_add(instance->htable,
|
|
||||||
(void *)tok,
|
|
||||||
(void *)rtype);
|
|
||||||
}
|
|
||||||
else if(rtype == RT_TIME && check_time(tok))
|
|
||||||
{
|
|
||||||
parse_time(tok,instance);
|
|
||||||
}
|
|
||||||
tok = strtok(NULL," ,\0");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}else if((ptr = strstr(rule,"require")) != NULL){
|
|
||||||
|
|
||||||
if((ptr = strstr(ptr,"where")) != NULL &&
|
|
||||||
(ptr = strchr(ptr,' ')) != NULL){
|
|
||||||
char* tok;
|
|
||||||
|
|
||||||
ptr++;
|
|
||||||
tok = strtok(ptr," ,\0");
|
|
||||||
while(tok){
|
|
||||||
if(strcmp(tok, "all") == 0){
|
|
||||||
instance->require_where[ALL] = true;
|
|
||||||
break;
|
|
||||||
}else if(strcmp(tok, "select") == 0){
|
|
||||||
instance->require_where[SELECT] = true;
|
|
||||||
}else if(strcmp(tok, "insert") == 0){
|
|
||||||
instance->require_where[INSERT] = true;
|
|
||||||
}else if(strcmp(tok, "update") == 0){
|
|
||||||
instance->require_where[UPDATE] = true;
|
|
||||||
}else if(strcmp(tok, "delete") == 0){
|
|
||||||
instance->require_where[DELETE] = true;
|
|
||||||
}
|
|
||||||
tok = strtok(NULL," ,\0");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
retblock:
|
retblock:
|
||||||
free(rulecpy);
|
free(rulecpy);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -862,6 +806,9 @@ createInstance(char **options, FILTER_PARAMETER **params)
|
|||||||
for(i = 0;params[i];i++){
|
for(i = 0;params[i];i++){
|
||||||
if(strstr(params[i]->name,"rule")){
|
if(strstr(params[i]->name,"rule")){
|
||||||
parse_rule(strip_tags(params[i]->value),my_instance);
|
parse_rule(strip_tags(params[i]->value),my_instance);
|
||||||
|
}else if(strcmp(params[i]->name,"mode") == 0 &&
|
||||||
|
strcmp(params[i]->value,"whitelist") == 0){
|
||||||
|
my_instance->def_op = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -949,14 +896,23 @@ setDownstream(FILTER *instance, void *session, DOWNSTREAM *downstream)
|
|||||||
* Generates a dummy error packet for the client.
|
* Generates a dummy error packet for the client.
|
||||||
* @return The dummy packet or NULL if an error occurred
|
* @return The dummy packet or NULL if an error occurred
|
||||||
*/
|
*/
|
||||||
GWBUF* gen_dummy_error(FW_SESSION* session)
|
GWBUF* gen_dummy_error(FW_SESSION* session, char* msg)
|
||||||
{
|
{
|
||||||
GWBUF* buf;
|
GWBUF* buf;
|
||||||
char errmsg[512];
|
char* errmsg;
|
||||||
DCB* dcb = session->session->client;
|
DCB* dcb = session->session->client;
|
||||||
MYSQL_session* mysql_session = (MYSQL_session*)session->session->data;
|
MYSQL_session* mysql_session = (MYSQL_session*)session->session->data;
|
||||||
unsigned int errlen, pktlen;
|
unsigned int errlen, pktlen;
|
||||||
|
|
||||||
|
errlen = msg != NULL ? strlen(msg) : 0;
|
||||||
|
errmsg = malloc((512 + errlen)*sizeof(char));
|
||||||
|
|
||||||
|
if(errmsg == NULL){
|
||||||
|
skygw_log_write_flush(LOGFILE_ERROR, "Fatal Error: malloc returned NULL.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(mysql_session->db[0] == '\0')
|
if(mysql_session->db[0] == '\0')
|
||||||
{
|
{
|
||||||
sprintf(errmsg,
|
sprintf(errmsg,
|
||||||
@ -971,6 +927,13 @@ GWBUF* gen_dummy_error(FW_SESSION* session)
|
|||||||
dcb->remote,
|
dcb->remote,
|
||||||
mysql_session->db);
|
mysql_session->db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(msg != NULL){
|
||||||
|
char* ptr = strchr(errmsg,'\0');
|
||||||
|
sprintf(ptr,": %s",msg);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
errlen = strlen(errmsg);
|
errlen = strlen(errmsg);
|
||||||
pktlen = errlen + 9;
|
pktlen = errlen + 9;
|
||||||
buf = gwbuf_alloc(13 + errlen);
|
buf = gwbuf_alloc(13 + errlen);
|
||||||
@ -989,6 +952,40 @@ GWBUF* gen_dummy_error(FW_SESSION* session)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool inside_timerange(TIMERANGE* comp)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct tm* tm_now;
|
||||||
|
struct tm tm_before,tm_after;
|
||||||
|
time_t before,after,now, time_now;
|
||||||
|
double to_before,to_after;
|
||||||
|
|
||||||
|
time(&time_now);
|
||||||
|
tm_now = localtime(&time_now);
|
||||||
|
memcpy(&tm_before,tm_now,sizeof(struct tm));
|
||||||
|
memcpy(&tm_after,tm_now,sizeof(struct tm));
|
||||||
|
|
||||||
|
|
||||||
|
tm_before.tm_sec = comp->start.tm_sec;
|
||||||
|
tm_before.tm_min = comp->start.tm_min;
|
||||||
|
tm_before.tm_hour = comp->start.tm_hour;
|
||||||
|
tm_after.tm_sec = comp->end.tm_sec;
|
||||||
|
tm_after.tm_min = comp->end.tm_min;
|
||||||
|
tm_after.tm_hour = comp->end.tm_hour;
|
||||||
|
|
||||||
|
|
||||||
|
before = mktime(&tm_before);
|
||||||
|
after = mktime(&tm_after);
|
||||||
|
now = mktime(tm_now);
|
||||||
|
to_before = difftime(now,before);
|
||||||
|
to_after = difftime(now,after);
|
||||||
|
|
||||||
|
if(to_before > 0.0 && to_after < 0.0){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The routeQuery entry point. This is passed the query buffer
|
* The routeQuery entry point. This is passed the query buffer
|
||||||
* to which the filter should be applied. Once processed the
|
* to which the filter should be applied. Once processed the
|
||||||
@ -1004,49 +1001,79 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
{
|
{
|
||||||
FW_SESSION *my_session = (FW_SESSION *)session;
|
FW_SESSION *my_session = (FW_SESSION *)session;
|
||||||
FW_INSTANCE *my_instance = (FW_INSTANCE *)instance;
|
FW_INSTANCE *my_instance = (FW_INSTANCE *)instance;
|
||||||
IPRANGE* ipranges = my_instance->networks;
|
|
||||||
TIMERANGE* times = my_instance->times;
|
|
||||||
time_t time_now;
|
time_t time_now;
|
||||||
struct tm* tm_now;
|
struct tm* tm_now;
|
||||||
struct tm tm_before,tm_after;
|
bool accept = my_instance->def_op;
|
||||||
bool accept = false, match = false;
|
char *where, *msg = NULL;
|
||||||
char *where;
|
char uname[128];
|
||||||
char username[128];
|
char uname_addr[128];
|
||||||
uint32_t ip;
|
char addr[128];
|
||||||
ruletype_t rtype = RT_UNDEFINED;
|
char emsg[1024];
|
||||||
skygw_query_op_t queryop;
|
|
||||||
DCB* dcb = my_session->session->client;
|
DCB* dcb = my_session->session->client;
|
||||||
RULELIST *rulelist = NULL;
|
RULELIST *rulelist = NULL;
|
||||||
STRLINK* strln = NULL;
|
STRLINK* strln = NULL;
|
||||||
|
TIMERANGE *times;
|
||||||
|
|
||||||
sprintf(username,"%s@%s",dcb->user,dcb->remote);
|
sprintf(uname_addr,"%s@%s",dcb->user,dcb->remote);
|
||||||
|
sprintf(uname,"%s@%%",dcb->user);
|
||||||
|
sprintf(addr,"%%@%s",dcb->remote);
|
||||||
|
|
||||||
rulelist = (RULELIST*)hashtable_fetch(my_instance->htable, username);
|
time(&time_now);
|
||||||
if(rulelist == NULL){
|
tm_now = localtime(&time_now);
|
||||||
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;
|
|
||||||
|
if((rulelist = (RULELIST*)hashtable_fetch(my_instance->htable, uname_addr)) == NULL &&
|
||||||
|
(rulelist = (RULELIST*)hashtable_fetch(my_instance->htable, uname)) == NULL &&
|
||||||
|
(rulelist = (RULELIST*)hashtable_fetch(my_instance->htable, addr)) == NULL &&
|
||||||
|
(rulelist = (RULELIST*)hashtable_fetch(my_instance->htable, "%@%")) == NULL)
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*No rules matched, do default operation.
|
||||||
|
* TODO: add incremental wildcard search of network addresses
|
||||||
|
* i.e. iteration from 127.0.0.1 all the way up to 127.%
|
||||||
|
*/
|
||||||
|
|
||||||
goto queryresolved;
|
goto queryresolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(rulelist){
|
while(rulelist){
|
||||||
|
|
||||||
|
if(rulelist->rule->active != NULL){
|
||||||
|
bool rule_active = false;
|
||||||
|
times = (TIMERANGE*)rulelist->rule->active;
|
||||||
|
|
||||||
|
while(times){
|
||||||
|
|
||||||
|
if(inside_timerange(times)){
|
||||||
|
rule_active = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
times = times->next;
|
||||||
|
}
|
||||||
|
if(!rule_active){
|
||||||
|
rulelist = rulelist->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch(rulelist->rule->type){
|
switch(rulelist->rule->type){
|
||||||
|
|
||||||
case RT_UNDEFINED:
|
case RT_UNDEFINED:
|
||||||
accept = true;
|
break;
|
||||||
|
|
||||||
|
case RT_PERMISSION:
|
||||||
|
if(!rulelist->rule->allow){
|
||||||
|
accept = false;
|
||||||
|
msg = strdup("Permission denied.");
|
||||||
goto queryresolved;
|
goto queryresolved;
|
||||||
|
}else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case RT_COLUMN:
|
case RT_COLUMN:
|
||||||
|
|
||||||
@ -1065,8 +1092,16 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
|
|
||||||
while(strln){
|
while(strln){
|
||||||
if(strstr(where,strln->value)){
|
if(strstr(where,strln->value)){
|
||||||
accept = false;
|
|
||||||
|
accept = rulelist->rule->allow;
|
||||||
|
|
||||||
|
if(!rulelist->rule->allow){
|
||||||
|
sprintf(emsg,"Permission denied to column '%s'.",strln->value);
|
||||||
|
msg = strdup(emsg);
|
||||||
goto queryresolved;
|
goto queryresolved;
|
||||||
|
}else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
strln = strln->next;
|
strln = strln->next;
|
||||||
}
|
}
|
||||||
@ -1075,141 +1110,61 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case RT_TIME: /**Obsolete*/
|
||||||
|
|
||||||
|
times = (TIMERANGE*)rulelist->rule->data;
|
||||||
|
|
||||||
|
while(times){
|
||||||
|
|
||||||
|
if(inside_timerange(times)){
|
||||||
|
accept = rulelist->rule->allow;
|
||||||
|
skygw_log_write(LOGFILE_TRACE, "Firewall: Query entered at %s, rule %s activated.",asctime(tm_now),rulelist->rule->name);
|
||||||
|
if(!rulelist->rule->allow){
|
||||||
|
goto queryresolved;
|
||||||
|
}else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
times = times->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RT_WILDCARD:
|
||||||
|
|
||||||
|
|
||||||
|
if(modutil_is_SQL(queue)){
|
||||||
|
|
||||||
|
if(!query_is_parsed(queue)){
|
||||||
|
parse_query(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(skygw_is_real_query(queue)){
|
||||||
|
|
||||||
|
where = skygw_get_affected_fields(queue);
|
||||||
|
|
||||||
|
if(where != NULL){
|
||||||
|
if(strchr(where,'*')){
|
||||||
|
|
||||||
|
accept = rulelist->rule->allow;
|
||||||
|
|
||||||
|
if(!rulelist->rule->allow){
|
||||||
|
msg = strdup("Usage of wildcard denied.");
|
||||||
|
goto queryresolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rulelist = rulelist->next;
|
rulelist = rulelist->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(rulelist == NULL){
|
|
||||||
accept = true;
|
|
||||||
goto queryresolved;
|
|
||||||
}
|
|
||||||
|
|
||||||
time(&time_now);
|
|
||||||
tm_now = localtime(&time_now);
|
|
||||||
memcpy(&tm_before,tm_now,sizeof(struct tm));
|
|
||||||
memcpy(&tm_after,tm_now,sizeof(struct tm));
|
|
||||||
|
|
||||||
rtype = (ruletype_t)hashtable_fetch(my_instance->htable, dcb->user);
|
|
||||||
|
|
||||||
if(rtype == RT_USER){
|
|
||||||
match = true;
|
|
||||||
accept = my_instance->whitelist_users;
|
|
||||||
skygw_log_write(LOGFILE_TRACE, "Firewall: %s@%s was %s.",
|
|
||||||
dcb->user, dcb->remote,
|
|
||||||
(my_instance->whitelist_users ?
|
|
||||||
"allowed":"denied"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!match){
|
|
||||||
|
|
||||||
ip = strtoip(dcb->remote);
|
|
||||||
|
|
||||||
while(ipranges){
|
|
||||||
if(ip >= ipranges->ip && ip <= ipranges->ip + ipranges->mask){
|
|
||||||
match = true;
|
|
||||||
accept = my_instance->whitelist_networks;
|
|
||||||
skygw_log_write(LOGFILE_TRACE, "Firewall: %s@%s was %s.",
|
|
||||||
dcb->user,dcb->remote,(my_instance->whitelist_networks ? "allowed":"denied"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ipranges = ipranges->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while(times){
|
|
||||||
|
|
||||||
tm_before.tm_sec = times->start.tm_sec;
|
|
||||||
tm_before.tm_min = times->start.tm_min;
|
|
||||||
tm_before.tm_hour = times->start.tm_hour;
|
|
||||||
tm_after.tm_sec = times->end.tm_sec;
|
|
||||||
tm_after.tm_min = times->end.tm_min;
|
|
||||||
tm_after.tm_hour = times->end.tm_hour;
|
|
||||||
|
|
||||||
|
|
||||||
time_t before = mktime(&tm_before);
|
|
||||||
time_t after = mktime(&tm_after);
|
|
||||||
time_t now = mktime(tm_now);
|
|
||||||
double to_before = difftime(now,before);
|
|
||||||
double to_after = difftime(now,after);
|
|
||||||
/**Inside time range*/
|
|
||||||
if(to_before > 0.0 && to_after < 0.0){
|
|
||||||
match = true;
|
|
||||||
accept = my_instance->whitelist_times;
|
|
||||||
skygw_log_write(LOGFILE_TRACE, "Firewall: Query entered during restricted time: %s.",asctime(tm_now));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
times = times->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(modutil_is_SQL(queue)){
|
|
||||||
|
|
||||||
if(!query_is_parsed(queue)){
|
|
||||||
parse_query(queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(skygw_is_real_query(queue)){
|
|
||||||
|
|
||||||
match = false;
|
|
||||||
|
|
||||||
if(!skygw_query_has_clause(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] ||
|
|
||||||
(my_instance->require_where[SELECT] && queryop == QUERY_OP_SELECT) ||
|
|
||||||
(my_instance->require_where[UPDATE] && queryop == QUERY_OP_UPDATE) ||
|
|
||||||
(my_instance->require_where[INSERT] && queryop == QUERY_OP_INSERT) ||
|
|
||||||
(my_instance->require_where[DELETE] && queryop == QUERY_OP_DELETE)){
|
|
||||||
match = true;
|
|
||||||
accept = false;
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!match){
|
|
||||||
|
|
||||||
where = skygw_get_affected_fields(queue);
|
|
||||||
|
|
||||||
if(my_instance->deny_wildcard &&
|
|
||||||
where && strchr(where,'*') != NULL)
|
|
||||||
{
|
|
||||||
match = true;
|
|
||||||
accept = false;
|
|
||||||
skygw_log_write(LOGFILE_TRACE, "Firewall: query contains wildcard, denying it: %.*s",GWBUF_LENGTH(queue),(char*)(queue->start + 5));
|
|
||||||
}
|
|
||||||
else if(where)
|
|
||||||
{
|
|
||||||
char* tok = strtok(where," ");
|
|
||||||
|
|
||||||
while(tok){
|
|
||||||
rtype = (ruletype_t)hashtable_fetch(my_instance->htable, tok);
|
|
||||||
if(rtype == RT_COLUMN){
|
|
||||||
match = true;
|
|
||||||
accept = false;
|
|
||||||
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," ");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
free(where);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**If no rules matched, do the default operation. (allow by default)*/
|
|
||||||
if(!match){
|
|
||||||
accept = my_instance->def_op;
|
|
||||||
}
|
|
||||||
|
|
||||||
queryresolved:
|
queryresolved:
|
||||||
|
|
||||||
if(accept){
|
if(accept){
|
||||||
@ -1219,7 +1174,10 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
}else{
|
}else{
|
||||||
|
|
||||||
gwbuf_free(queue);
|
gwbuf_free(queue);
|
||||||
GWBUF* forward = gen_dummy_error(my_session);
|
GWBUF* forward = gen_dummy_error(my_session,msg);
|
||||||
|
if(msg){
|
||||||
|
free(msg);
|
||||||
|
}
|
||||||
return dcb->func.write(dcb,forward);
|
return dcb->func.write(dcb,forward);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user