From 67030d0019d93e84aa722d393729f02bb77cd1d7 Mon Sep 17 00:00:00 2001 From: Markus Makela Date: Mon, 17 Nov 2014 14:52:26 +0200 Subject: [PATCH] Updated test harness. --- server/modules/filter/fwfilter.c | 60 ++++++++++----------- server/modules/filter/test/CMakeLists.txt | 2 +- server/modules/filter/test/harness.h | 14 ++++- server/modules/filter/test/harness_common.c | 60 ++++++++++++++++++--- server/modules/filter/test/harness_ui.c | 4 +- server/modules/filter/test/harness_util.c | 6 ++- 6 files changed, 103 insertions(+), 43 deletions(-) diff --git a/server/modules/filter/fwfilter.c b/server/modules/filter/fwfilter.c index e3a3fe720..2aadec959 100644 --- a/server/modules/filter/fwfilter.c +++ b/server/modules/filter/fwfilter.c @@ -20,25 +20,37 @@ * @file fwfilter.c * Firewall Filter * - * A filter that acts as a firewall, denying queries that do not meet a set requirements. + * A filter that acts as a firewall, denying queries that do not meet a set of rules. * - * This filter uses "rules" to define the blcking parameters. Write the rules to a separate file and - * set the path to the file: + * Filter configuration parameters: * - * rules= + * rules= Location of the rule file * - * - * For example, to define a rule denying users from accessing the column 'salary' between 15:00 and 17:00, the following is needed in the configuration file: + * Rules are defined in a separate rule file that lists all the rules and the users to whom the rules are applied. + * Rules follow a simple syntax that denies the queries that meet the requirements of the rules. + * For example, to define a rule denying users from accessing the column 'salary' between + * the times 15:00 and 17:00, the following rule is to be configured into the configuration file: * * rule block_salary deny columns salary at_times 15:00:00-17:00:00 * - * To apply this rule to users John, connecting from any address, and Jane, connecting from the address 192.168.0.1, use the following: + * The users are matched by username and network address. Wildcard values can be provided by using the '%' character. + * For example, to apply this rule to users John, connecting from any address + * that starts with the octets 198.168.%, and Jane, connecting from the address 192.168.0.1: * - * users John@% Jane@192.168.0.1 match any rules block_salary + * users John@192.168.% Jane@192.168.0.1 match any rules block_salary * - * Rule syntax TODO: update the documentation * - * rule NAME deny|allow [wildcard | columns VALUE ... | regex REGEX | limit_queries COUNT TIMEPERIOD HOLDOFF|no_where_clause [select|insert|delete|update]] [at_times VALUE...] + * The 'match' keyword controls the way rules are matched. If it is set to 'any' the first active rule that is triggered will cause the query to be denied. + * If it is set to 'all' all the active rules need to match before the query is denied. + * + * Rule syntax + * + * rule NAME deny [wildcard | columns VALUE ... | regex REGEX | limit_queries COUNT TIMEPERIOD HOLDOFF | no_where_clause] [at_times VALUE...] [on_queries [select|update|insert|delete]] + * + * User syntax + * + * users NAME ... match [any|all] rules RULE ... + * */ #include #include @@ -91,20 +103,7 @@ static FILTER_OBJECT MyObject = { diagnostic, }; -#define QUERY_TYPES 5 -/** - * Query types - */ -/*typedef enum{ - NONE = 0, - ALL = (1), - SELECT = (1<<1), - INSERT = (1<<2), - UPDATE = (1<<3), - DELETE = (1<<4) -}querytype_t; -*/ /** * Rule types */ @@ -259,12 +258,6 @@ void* rlistdup(void* fval) return (void*)rule; } -/* - static void* hruledup(void* fval) - { - return fval; - }*/ - static void* hrulefree(void* fval) { @@ -291,6 +284,7 @@ static void* hrulefree(void* fval) * Replace all non-essential characters with whitespace from a null-terminated string. * This function modifies the passed string. * @param str String to purify + * @return Pointer to the modified string */ char* strip_tags(char* str) { @@ -354,7 +348,12 @@ char* next_ip_class(char* str) return str; } - +/** + * Parses the strign for the types of queries this rule should be applied to. + * @param str String to parse + * @param rule Poiter to a rule + * @return True if the string was parses successfully, false if an error occurred + */ bool parse_querytypes(char* str,RULE* rule) { char buffer[512]; @@ -562,6 +561,7 @@ RULE* find_rule(char* tok, FW_INSTANCE* instance) skygw_log_write(LOGFILE_ERROR, "fwfilter: Rule not found: %s",tok); return NULL; } + /** * Adds the given rule string to the list of strings to be parsed for users. * @param rule The rule string, assumed to be null-terminated diff --git a/server/modules/filter/test/CMakeLists.txt b/server/modules/filter/test/CMakeLists.txt index 1813a5a26..b24a2b2bc 100644 --- a/server/modules/filter/test/CMakeLists.txt +++ b/server/modules/filter/test/CMakeLists.txt @@ -10,4 +10,4 @@ add_executable(harness_ui harness_ui.c harness_common.c) add_executable(harness harness_util.c harness_common.c ${CORE}) target_link_libraries(harness_ui fullcore log_manager utils) target_link_libraries(harness fullcore) -add_test(TestHintfilter /bin/sh -c "MAXSCALE_HOME=\"${CMAKE_BINARY_DIR}\" ${CMAKE_CURRENT_BINARY_DIR}/harness -i ${CMAKE_CURRENT_SOURCE_DIR}/hint_testing.input -o ${CMAKE_CURRENT_BINARY_DIR}/hint_testing.output -c ${CMAKE_CURRENT_SOURCE_DIR}/hint_testing.cnf -t 1 -s 1 && diff ${CMAKE_CURRENT_SOURCE_DIR}/hint_testing.expected ${CMAKE_CURRENT_BINARY_DIR}/hint_testing.output;exit $?") \ No newline at end of file +add_test(TestHintfilter /bin/sh -c "MAXSCALE_HOME=\"${CMAKE_BINARY_DIR}\" ${CMAKE_CURRENT_BINARY_DIR}/harness -i ${CMAKE_CURRENT_SOURCE_DIR}/hint_testing.input -o ${CMAKE_CURRENT_BINARY_DIR}/hint_testing.output -c ${CMAKE_CURRENT_SOURCE_DIR}/hint_testing.cnf -t 1 -s 1 -e ${CMAKE_CURRENT_SOURCE_DIR}/hint_testing.expected") \ No newline at end of file diff --git a/server/modules/filter/test/harness.h b/server/modules/filter/test/harness.h index c30c266c2..a306a6811 100644 --- a/server/modules/filter/test/harness.h +++ b/server/modules/filter/test/harness.h @@ -69,6 +69,7 @@ #include #include #include +#include /** * A single name-value pair and a link to the next item in the * configuration. @@ -117,6 +118,7 @@ typedef struct int running; int verbose; /**Whether to print to stdout*/ int infile; /**A file where the queries are loaded from*/ + int expected; int error; char* mod_dir; /**Module directory absolute path*/ char* infile_name; @@ -172,7 +174,7 @@ typedef packet_t PACKET; /** * Initialize the static instance. */ -int harness_init(int argc,char** argv); +int harness_init(int argc,char** argv,HARNESS_INSTANCE** inst); /** * Frees all the query buffers @@ -359,4 +361,14 @@ GWBUF* gen_packet(PACKET pkt); */ int process_opts(int argc, char** argv); +/** + * Compares the contents of two files. + * This function resets the offsets of the file descriptors and leaves them in an + * undefined state. + * @param a The first file + * @param b The second file + * @return 0 if the files do not differ and 1 if they do or an error occurred. + */ +int compare_files(int a, int b); + #endif diff --git a/server/modules/filter/test/harness_common.c b/server/modules/filter/test/harness_common.c index fe782bc0d..7564a891d 100644 --- a/server/modules/filter/test/harness_common.c +++ b/server/modules/filter/test/harness_common.c @@ -1,6 +1,6 @@ #include -int harness_init(int argc, char** argv){ +int harness_init(int argc, char** argv, HARNESS_INSTANCE** inst){ int i = 0; if(!(argc == 2 && strcmp(argv[1],"-h") == 0)){ skygw_logmanager_init(0,NULL); @@ -14,9 +14,11 @@ int harness_init(int argc, char** argv){ return 1; } + *inst = &instance; instance.running = 1; instance.infile = -1; instance.outfile = -1; + instance.expected = -1; instance.buff_ind = -1; instance.last_ind = -1; instance.sess_ind = -1; @@ -84,15 +86,17 @@ void free_buffers() } int open_file(char* str, unsigned int write) { - int mode; + int mode,fd; if(write){ mode = O_RDWR|O_CREAT; }else{ mode = O_RDONLY; } - - return open(str,mode,S_IRWXU|S_IRGRP|S_IXGRP|S_IXOTH); + if((fd = open(str,mode,S_IRWXU|S_IRGRP|S_IXGRP|S_IXOTH)) < 0){ + printf("Error %d: %s\n",errno,strerror(errno)); + } + return fd; } @@ -863,9 +867,14 @@ void work_buffer(void* thr_num) index < instance.session_count && instance.buff_ind < instance.buffer_count) { - instance.head->instance->routeQuery(instance.head->filter, + if(instance.head->instance->routeQuery(instance.head->filter, instance.head->session[index], - instance.buffer[instance.buff_ind]); + instance.buffer[instance.buff_ind]) == 0){ + if(instance.outfile > 0){ + const char* msg = "Query returned 0.\n"; + write(instance.outfile,msg,strlen(msg)); + } + } if(instance.tail->instance->clientReply){ instance.tail->instance->clientReply(instance.tail->filter, instance.tail->session[index], @@ -929,10 +938,11 @@ GWBUF* gen_packet(PACKET pkt) } + int process_opts(int argc, char** argv) { int fd, buffsize = 1024; - int rd,rdsz, rval; + int rd,rdsz, rval = 0; size_t fsize; char *buff = calloc(buffsize,sizeof(char)), *tok = NULL; @@ -985,10 +995,18 @@ int process_opts(int argc, char** argv) close(fd); return 1; } + char* conf_name = NULL; - while((rd = getopt(argc,argv,"m:c:i:o:s:t:d:qh")) > 0){ + rval = 0; + + while((rd = getopt(argc,argv,"e:m:c:i:o:s:t:d:qh")) > 0){ switch(rd){ + case 'e': + instance.expected = open_file(optarg,0); + printf("Expected output is read from: %s\n",optarg); + break; + case 'o': instance.outfile = open_file(optarg,1); printf("Output is written to: %s\n",optarg); @@ -1053,6 +1071,7 @@ int process_opts(int argc, char** argv) } } printf("\n"); + if(conf_name && load_config(conf_name)){ load_query(); }else{ @@ -1061,5 +1080,30 @@ int process_opts(int argc, char** argv) free(conf_name); close(fd); + return rval; +} + +int compare_files(int a,int b) +{ + char in[4098]; + char exp[4098]; + int line = 1; + + if(a < 1 || b < 1){ + return 1; + } + + if(lseek(a,0,SEEK_SET) < 0 || + lseek(b,0,SEEK_SET) < 0){ + return 1; + } + + while(fdgets(a,in,4098) && fdgets(b,exp,4098)){ + if(strcmp(in,exp)){ + printf("The files differ at line %d:\n%s\n-------------------------------------\n%s\n",line,in,exp); + return 1; + } + line++; + } return 0; } diff --git a/server/modules/filter/test/harness_ui.c b/server/modules/filter/test/harness_ui.c index 9b38f648c..8921a88bc 100755 --- a/server/modules/filter/test/harness_ui.c +++ b/server/modules/filter/test/harness_ui.c @@ -6,9 +6,9 @@ int main(int argc, char** argv){ char* tk; FILTERCHAIN* tmp_chn; FILTERCHAIN* del_chn; - + HARNESS_INSTANCE* hinstance; - if(harness_init(argc,argv)){ + if(harness_init(argc,argv,&hinstance)){ printf("Error: Initialization failed.\n"); skygw_log_write(LOGFILE_ERROR,"Error: Initialization failed.\n"); skygw_logmanager_done(); diff --git a/server/modules/filter/test/harness_util.c b/server/modules/filter/test/harness_util.c index fb6905445..705bc3c3b 100644 --- a/server/modules/filter/test/harness_util.c +++ b/server/modules/filter/test/harness_util.c @@ -1,7 +1,8 @@ #include int main(int argc,char** argv) { - if(harness_init(argc,argv) || instance.error){ + HARNESS_INSTANCE* inst; + if(harness_init(argc,argv,&inst) || inst->error){ printf("Error: Initialization failed.\n"); skygw_log_write(LOGFILE_ERROR,"Error: Initialization failed.\n"); skygw_logmanager_done(); @@ -10,5 +11,8 @@ int main(int argc,char** argv) } route_buffers(); + if(inst->expected){ + return compare_files(inst->outfile,inst->expected); + } return 0; }