Added a rule to restrict queries during certain hours of the day
This commit is contained in:
@ -38,7 +38,8 @@
|
|||||||
#include <session.h>
|
#include <session.h>
|
||||||
#include <plugin.h>
|
#include <plugin.h>
|
||||||
#include <skygw_types.h>
|
#include <skygw_types.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
MODULE_INFO info = {
|
MODULE_INFO info = {
|
||||||
MODULE_API_FILTER,
|
MODULE_API_FILTER,
|
||||||
@ -92,20 +93,18 @@ typedef enum{
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
RT_UNDEFINED,
|
RT_UNDEFINED,
|
||||||
RT_USER,
|
RT_USER,
|
||||||
RT_COLUMN
|
RT_COLUMN,
|
||||||
|
RT_TIME
|
||||||
}ruletype_t;
|
}ruletype_t;
|
||||||
|
|
||||||
/**
|
typedef struct timerange_t{
|
||||||
* Generic linked list of string values
|
struct timerange_t* next;
|
||||||
*/
|
struct tm start;
|
||||||
|
struct tm end;
|
||||||
typedef struct item_t{
|
}TIMERANGE;
|
||||||
struct item_t* next;
|
|
||||||
char* value;
|
|
||||||
}ITEM;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A link in a list of IP adresses and subnet masks
|
* Linked list of IP adresses and subnet masks
|
||||||
*/
|
*/
|
||||||
typedef struct iprange_t{
|
typedef struct iprange_t{
|
||||||
struct iprange_t* next;
|
struct iprange_t* next;
|
||||||
@ -117,9 +116,9 @@ typedef struct iprange_t{
|
|||||||
* The Firewall filter instance.
|
* The Firewall filter instance.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HASHTABLE* htable;
|
HASHTABLE* htable; /**Usernames and forbidden columns*/
|
||||||
IPRANGE* networks;
|
IPRANGE* networks;
|
||||||
int column_count, column_size, user_count, user_size;
|
TIMERANGE* times;
|
||||||
bool require_where[QUERY_TYPES];
|
bool require_where[QUERY_TYPES];
|
||||||
bool block_wildcard, whitelist_users,whitelist_networks,def_op;
|
bool block_wildcard, whitelist_users,whitelist_networks,def_op;
|
||||||
|
|
||||||
@ -138,40 +137,40 @@ static int hashkeyfun(void* key);
|
|||||||
static int hashcmpfun (void *, void *);
|
static int hashcmpfun (void *, void *);
|
||||||
|
|
||||||
static int hashkeyfun(
|
static int hashkeyfun(
|
||||||
void* key)
|
void* key)
|
||||||
{
|
{
|
||||||
if(key == NULL){
|
if(key == NULL){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
unsigned int hash = 0,c = 0;
|
unsigned int hash = 0,c = 0;
|
||||||
char* ptr = (char*)key;
|
char* ptr = (char*)key;
|
||||||
while((c = *ptr++)){
|
while((c = *ptr++)){
|
||||||
hash = c + (hash << 6) + (hash << 16) - hash;
|
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||||
}
|
}
|
||||||
return (int)hash > 0 ? hash : -hash;
|
return (int)hash > 0 ? hash : -hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hashcmpfun(
|
static int hashcmpfun(
|
||||||
void* v1,
|
void* v1,
|
||||||
void* v2)
|
void* v2)
|
||||||
{
|
{
|
||||||
char* i1 = (char*) v1;
|
char* i1 = (char*) v1;
|
||||||
char* i2 = (char*) v2;
|
char* i2 = (char*) v2;
|
||||||
|
|
||||||
return strcmp(i1,i2);
|
return strcmp(i1,i2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* hstrdup(void* fval)
|
static void* hstrdup(void* fval)
|
||||||
{
|
{
|
||||||
char* str = (char*)fval;
|
char* str = (char*)fval;
|
||||||
return strdup(str);
|
return strdup(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void* hfree(void* fval)
|
static void* hfree(void* fval)
|
||||||
{
|
{
|
||||||
free (fval);
|
free (fval);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -182,6 +181,8 @@ static void* hfree(void* fval)
|
|||||||
*/
|
*/
|
||||||
bool valid_ip(char* str)
|
bool valid_ip(char* str)
|
||||||
{
|
{
|
||||||
|
assert(str != NULL);
|
||||||
|
|
||||||
int octval = 0;
|
int octval = 0;
|
||||||
bool valid = true;
|
bool valid = true;
|
||||||
char cmpbuff[32];
|
char cmpbuff[32];
|
||||||
@ -226,10 +227,16 @@ bool valid_ip(char* str)
|
|||||||
*/
|
*/
|
||||||
char* strip_tags(char* str)
|
char* strip_tags(char* str)
|
||||||
{
|
{
|
||||||
|
assert(str != NULL);
|
||||||
|
|
||||||
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 == '.' || *ptr == '/'){
|
if(isalnum(*ptr) ||
|
||||||
|
*ptr == '.' ||
|
||||||
|
*ptr == '/' ||
|
||||||
|
*ptr == ':' ||
|
||||||
|
*ptr == '-' ){
|
||||||
ptr++;
|
ptr++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -260,6 +267,8 @@ char* strip_tags(char* str)
|
|||||||
*/
|
*/
|
||||||
int get_octet(char* str)
|
int get_octet(char* str)
|
||||||
{
|
{
|
||||||
|
assert(str != NULL);
|
||||||
|
|
||||||
int octval = 0,retval = -1;
|
int octval = 0,retval = -1;
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
char cmpbuff[32];
|
char cmpbuff[32];
|
||||||
@ -312,6 +321,8 @@ int get_octet(char* str)
|
|||||||
*/
|
*/
|
||||||
uint32_t strtoip(char* str)
|
uint32_t strtoip(char* str)
|
||||||
{
|
{
|
||||||
|
assert(str != NULL);
|
||||||
|
|
||||||
uint32_t ip = 0,octet = 0;
|
uint32_t ip = 0,octet = 0;
|
||||||
char* tok = str;
|
char* tok = str;
|
||||||
if(!valid_ip(str)){
|
if(!valid_ip(str)){
|
||||||
@ -337,6 +348,8 @@ uint32_t strtoip(char* str)
|
|||||||
*/
|
*/
|
||||||
uint32_t strtosubmask(char* str)
|
uint32_t strtosubmask(char* str)
|
||||||
{
|
{
|
||||||
|
assert(str != NULL);
|
||||||
|
|
||||||
uint32_t mask = 0;
|
uint32_t mask = 0;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
@ -351,7 +364,98 @@ uint32_t strtosubmask(char* str)
|
|||||||
return ~mask;
|
return ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a null-terminated string contains two ISO-8601 compliant times separated
|
||||||
|
* by a single dash.
|
||||||
|
* @param str String to check
|
||||||
|
* @return True if the string is valid
|
||||||
|
*/
|
||||||
|
bool check_time(char* str)
|
||||||
|
{
|
||||||
|
assert(str != NULL);
|
||||||
|
|
||||||
|
char* ptr = str;
|
||||||
|
int colons = 0,numbers = 0,dashes = 0;
|
||||||
|
while(*ptr){
|
||||||
|
if(isdigit(*ptr)){numbers++;}
|
||||||
|
else if(*ptr == ':'){colons++;}
|
||||||
|
else if(*ptr == '-'){dashes++;}
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
return numbers == 12 && colons == 4 && dashes == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHK_TIMES(t)(assert(t->tm_sec > -1 && t->tm_sec < 62 \
|
||||||
|
&& t->tm_min > -1 && t->tm_min < 60 \
|
||||||
|
&& t->tm_hour > -1 && t->tm_hour < 24))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a null-terminated string into two time_t structs and adds the
|
||||||
|
* TIMERANGE into the FW_FILTER instance.
|
||||||
|
* @param str String to parse
|
||||||
|
* @param instance FW_FILTER instance
|
||||||
|
*/
|
||||||
|
void parse_time(char* str, FW_INSTANCE* instance)
|
||||||
|
{
|
||||||
|
|
||||||
|
TIMERANGE* tr = (TIMERANGE*)malloc(sizeof(TIMERANGE));
|
||||||
|
int intbuffer[3];
|
||||||
|
int* idest = intbuffer;
|
||||||
|
char strbuffer[3];
|
||||||
|
char *ptr,*sdest;
|
||||||
|
struct tm* tmptr;
|
||||||
|
|
||||||
|
assert(str != NULL && tr != NULL && instance != NULL);
|
||||||
|
|
||||||
|
memset(&tr->start,0,sizeof(struct tm));
|
||||||
|
memset(&tr->end,0,sizeof(struct tm));
|
||||||
|
ptr = str;
|
||||||
|
sdest = strbuffer;
|
||||||
|
tmptr = &tr->start;
|
||||||
|
tr->next = instance->times;
|
||||||
|
instance->times = tr;
|
||||||
|
|
||||||
|
while(ptr - str < 19){
|
||||||
|
if(isdigit(*ptr)){
|
||||||
|
*sdest = *ptr;
|
||||||
|
}else if(*ptr == ':' ||*ptr == '-' || *ptr == '\0'){
|
||||||
|
*sdest = '\0';
|
||||||
|
*idest++ = atoi(strbuffer);
|
||||||
|
sdest = strbuffer;
|
||||||
|
|
||||||
|
if(*ptr == '-' || *ptr == '\0'){
|
||||||
|
|
||||||
|
tmptr->tm_hour = intbuffer[0];
|
||||||
|
tmptr->tm_min = intbuffer[1];
|
||||||
|
tmptr->tm_sec = intbuffer[2];
|
||||||
|
|
||||||
|
CHK_TIMES(tmptr);
|
||||||
|
|
||||||
|
idest = intbuffer;
|
||||||
|
tmptr = &tr->end;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
sdest++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**The timerange is reversed*/
|
||||||
|
if(mktime(&tr->end) < mktime(&tr->start)){
|
||||||
|
tr = (TIMERANGE*)malloc(sizeof(TIMERANGE));
|
||||||
|
tr->next = instance->times;
|
||||||
|
tr->start.tm_hour = 0;
|
||||||
|
tr->start.tm_min = 0;
|
||||||
|
tr->start.tm_sec = 0;
|
||||||
|
tr->end = instance->times->end;
|
||||||
|
instance->times->end.tm_hour = 23;
|
||||||
|
instance->times->end.tm_min = 59;
|
||||||
|
instance->times->end.tm_sec = 59;
|
||||||
|
instance->times = tr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the mandatory version entry point
|
* Implementation of the mandatory version entry point
|
||||||
@ -374,13 +478,13 @@ ModuleInit()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The module entry point routine. It is this routine that
|
* The module entry point routine. It is this routine that
|
||||||
* must populate the structure that is referred to as the
|
* must populate the structure that is referred to as the
|
||||||
* "module object", this is a structure with the set of
|
* "module object", this is a structure with the set of
|
||||||
* external entry points for this module.
|
* external entry points for this module.
|
||||||
*
|
*
|
||||||
* @return The module object
|
* @return The module object
|
||||||
*/
|
*/
|
||||||
FILTER_OBJECT *
|
FILTER_OBJECT *
|
||||||
GetModuleObject()
|
GetModuleObject()
|
||||||
{
|
{
|
||||||
@ -403,7 +507,7 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
|
|||||||
}
|
}
|
||||||
ptr++;
|
ptr++;
|
||||||
|
|
||||||
if(valid_ip(ptr)){ /**Add IP address range*/
|
if(valid_ip(ptr)){ /**Add IP address range*/
|
||||||
|
|
||||||
instance->whitelist_networks = mode;
|
instance->whitelist_networks = mode;
|
||||||
IPRANGE* rng = calloc(1,sizeof(IPRANGE));
|
IPRANGE* rng = calloc(1,sizeof(IPRANGE));
|
||||||
@ -429,20 +533,33 @@ void parse_rule(char* rule, FW_INSTANCE* instance)
|
|||||||
is_user = true;
|
is_user = true;
|
||||||
}else if(strcmp(tok,"columns") == 0){/**Adding Columns*/
|
}else if(strcmp(tok,"columns") == 0){/**Adding Columns*/
|
||||||
is_column = true;
|
is_column = true;
|
||||||
|
}else if(strcmp(tok,"times") == 0){
|
||||||
|
is_time = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
tok = strtok(NULL," ,\0");
|
tok = strtok(NULL," ,\0");
|
||||||
|
|
||||||
if(is_user || is_column){
|
if(is_user || is_column || is_time){
|
||||||
while(tok){
|
while(tok){
|
||||||
|
|
||||||
/**Add value to hashtable*/
|
/**Add value to hashtable*/
|
||||||
|
|
||||||
ruletype_t rtype = is_user ? RT_USER : is_column ? RT_COLUMN: RT_UNDEFINED;
|
ruletype_t rtype =
|
||||||
hashtable_add(instance->htable,
|
is_user ? RT_USER :
|
||||||
(void *)tok,
|
is_column ? RT_COLUMN:
|
||||||
(void *)rtype);
|
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");
|
tok = strtok(NULL," ,\0");
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -595,14 +712,24 @@ GWBUF* gen_dummy_error(FW_SESSION* session)
|
|||||||
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;
|
||||||
|
|
||||||
sprintf(errmsg,"Access denied for user '%s'@'%s' to database '%s' ",
|
if(mysql_session->db[0] == '\0')
|
||||||
dcb->user,
|
{
|
||||||
dcb->remote,
|
sprintf(errmsg,
|
||||||
mysql_session->db);
|
"Access denied for user '%s'@'%s'",
|
||||||
|
dcb->user,
|
||||||
|
dcb->remote);
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
sprintf(errmsg,
|
||||||
|
"Access denied for user '%s'@'%s' to database '%s' ",
|
||||||
|
dcb->user,
|
||||||
|
dcb->remote,
|
||||||
|
mysql_session->db);
|
||||||
|
}
|
||||||
errlen = strlen(errmsg);
|
errlen = strlen(errmsg);
|
||||||
pktlen = errlen + 9;
|
pktlen = errlen + 9;
|
||||||
buf = gwbuf_alloc(13 + errlen);
|
buf = gwbuf_alloc(13 + errlen);
|
||||||
|
|
||||||
if(buf){
|
if(buf){
|
||||||
strcpy(buf->start + 7,"#HY000");
|
strcpy(buf->start + 7,"#HY000");
|
||||||
memcpy(buf->start + 13,errmsg,errlen);
|
memcpy(buf->start + 13,errmsg,errlen);
|
||||||
@ -633,15 +760,25 @@ 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;
|
IPRANGE* ipranges = my_instance->networks;
|
||||||
|
TIMERANGE* times = my_instance->times;
|
||||||
|
time_t time_now;
|
||||||
|
struct tm* tm_now;
|
||||||
|
struct tm tm_before,tm_after;
|
||||||
bool accept = false, match = false;
|
bool accept = false, match = false;
|
||||||
char *where;
|
char *where;
|
||||||
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;
|
||||||
ip = strtoip(dcb->remote);
|
|
||||||
|
|
||||||
|
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);
|
rtype = (ruletype_t)hashtable_fetch(my_instance->htable, dcb->user);
|
||||||
|
|
||||||
if(rtype == RT_USER){
|
if(rtype == RT_USER){
|
||||||
match = true;
|
match = true;
|
||||||
accept = my_instance->whitelist_users;
|
accept = my_instance->whitelist_users;
|
||||||
@ -652,6 +789,9 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!match){
|
if(!match){
|
||||||
|
|
||||||
|
ip = strtoip(dcb->remote);
|
||||||
|
|
||||||
while(ipranges){
|
while(ipranges){
|
||||||
if(ip >= ipranges->ip && ip <= ipranges->ip + ipranges->mask){
|
if(ip >= ipranges->ip && ip <= ipranges->ip + ipranges->mask){
|
||||||
match = true;
|
match = true;
|
||||||
@ -663,6 +803,32 @@ routeQuery(FILTER *instance, void *session, GWBUF *queue)
|
|||||||
ipranges = ipranges->next;
|
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);
|
||||||
|
/**Restricted time*/
|
||||||
|
if(to_before > 0.0 && to_after < 0.0){
|
||||||
|
match = true;
|
||||||
|
accept = false;
|
||||||
|
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(modutil_is_SQL(queue)){
|
||||||
|
Reference in New Issue
Block a user