Make the dbfwfilter rule check a separate utility
The code for the utility is now stored in a separate file. This also removes the need to include testing headers from other directories. Also added a function to reload rules that uses the newly modified rule parsing mechanism. This can be used later on to update the rules at runtime.
This commit is contained in:
@ -11,12 +11,11 @@ if(BISON_FOUND AND FLEX_FOUND)
|
|||||||
set_target_properties(dbfwfilter PROPERTIES VERSION "1.0.0")
|
set_target_properties(dbfwfilter PROPERTIES VERSION "1.0.0")
|
||||||
install_module(dbfwfilter core)
|
install_module(dbfwfilter core)
|
||||||
|
|
||||||
if(BUILD_TOOLS)
|
# The offline rule check utility
|
||||||
add_executable(dbfwruleparser dbfwfilter.c ${BISON_ruleparser_OUTPUTS} ${FLEX_token_OUTPUTS})
|
add_executable(dbfwchk dbfw_rule_check.c ${BISON_ruleparser_OUTPUTS} ${FLEX_token_OUTPUTS})
|
||||||
target_compile_definitions(dbfwruleparser PUBLIC "BUILD_RULE_PARSER")
|
target_link_libraries(dbfwchk maxscale-common)
|
||||||
target_link_libraries(dbfwruleparser maxscale-common)
|
install_executable(dbfwchk core)
|
||||||
install_module(dbfwruleparser core)
|
|
||||||
endif()
|
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "Could not find Bison or Flex: ${BISON_EXECUTABLE} ${FLEX_EXECUTABLE}")
|
message(FATAL_ERROR "Could not find Bison or Flex: ${BISON_EXECUTABLE} ${FLEX_EXECUTABLE}")
|
||||||
endif()
|
endif()
|
||||||
|
55
server/modules/filter/dbfwfilter/dbfw_rule_check.c
Normal file
55
server/modules/filter/dbfwfilter/dbfw_rule_check.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||||
|
*
|
||||||
|
* Change Date: 2019-07-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2 or later of the General
|
||||||
|
* Public License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dbfwfilter.c"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int rval = 1;
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
printf("Usage: dbfw_rule_check FILE\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mxs_log_init("dbfwfilter_rule_parser", ".", MXS_LOG_TARGET_STDOUT);
|
||||||
|
|
||||||
|
if (access(argv[1], R_OK) == 0)
|
||||||
|
{
|
||||||
|
MXS_NOTICE("Parsing rule file: %s", argv[1]);
|
||||||
|
|
||||||
|
RULE* rules;
|
||||||
|
HASHTABLE *users;
|
||||||
|
|
||||||
|
if (process_rule_file(argv[1], &rules, &users))
|
||||||
|
{
|
||||||
|
MXS_NOTICE("Rule parsing was successful.");
|
||||||
|
rval = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_ERROR("Failed to parse rules.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_ERROR("Failed to read file '%s': %d, %s", argv[1], errno, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
mxs_log_finish();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
@ -424,6 +424,18 @@ static void dbfw_user_free(void* fval)
|
|||||||
MXS_FREE(value);
|
MXS_FREE(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HASHTABLE *dbfw_userlist_create()
|
||||||
|
{
|
||||||
|
HASHTABLE *ht = hashtable_alloc(100, hashtable_item_strhash, hashtable_item_strcmp);
|
||||||
|
|
||||||
|
if (ht)
|
||||||
|
{
|
||||||
|
hashtable_memory_fns(ht, hashtable_item_strdup, NULL, hashtable_item_free, dbfw_user_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ht;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a string that contains an IP address and converts the last octet to '%'.
|
* Parses a string that contains an IP address and converts the last octet to '%'.
|
||||||
* This modifies the string passed as the parameter.
|
* This modifies the string passed as the parameter.
|
||||||
@ -1204,7 +1216,7 @@ static RULE* find_rule_by_name(RULE* rules, const char* name)
|
|||||||
* @param rules List of all rules
|
* @param rules List of all rules
|
||||||
* @return True on success, false on error.
|
* @return True on success, false on error.
|
||||||
*/
|
*/
|
||||||
static bool process_user_templates(FW_INSTANCE *instance, user_template_t *templates,
|
static bool process_user_templates(HASHTABLE *users, user_template_t *templates,
|
||||||
RULE* rules)
|
RULE* rules)
|
||||||
{
|
{
|
||||||
bool rval = true;
|
bool rval = true;
|
||||||
@ -1217,7 +1229,7 @@ static bool process_user_templates(FW_INSTANCE *instance, user_template_t *templ
|
|||||||
|
|
||||||
while (templates)
|
while (templates)
|
||||||
{
|
{
|
||||||
DBFW_USER *user = hashtable_fetch(instance->users, templates->name);
|
DBFW_USER *user = hashtable_fetch(users, templates->name);
|
||||||
|
|
||||||
if (user == NULL)
|
if (user == NULL)
|
||||||
{
|
{
|
||||||
@ -1227,7 +1239,7 @@ static bool process_user_templates(FW_INSTANCE *instance, user_template_t *templ
|
|||||||
user->rules_or = NULL;
|
user->rules_or = NULL;
|
||||||
user->rules_strict_and = NULL;
|
user->rules_strict_and = NULL;
|
||||||
spinlock_init(&user->lock);
|
spinlock_init(&user->lock);
|
||||||
hashtable_add(instance->users, user->name, user);
|
hashtable_add(users, user->name, user);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1292,7 +1304,7 @@ static bool process_user_templates(FW_INSTANCE *instance, user_template_t *templ
|
|||||||
* @param instance Filter instance
|
* @param instance Filter instance
|
||||||
* @return True on success, false on error.
|
* @return True on success, false on error.
|
||||||
*/
|
*/
|
||||||
static bool process_rule_file(const char* filename, FW_INSTANCE* instance)
|
static bool process_rule_file(const char* filename, RULE** rules, HASHTABLE **users)
|
||||||
{
|
{
|
||||||
int rc = 1;
|
int rc = 1;
|
||||||
FILE *file = fopen(filename, "r");
|
FILE *file = fopen(filename, "r");
|
||||||
@ -1318,15 +1330,18 @@ static bool process_rule_file(const char* filename, FW_INSTANCE* instance)
|
|||||||
dbfw_yy_delete_buffer(buf, scanner);
|
dbfw_yy_delete_buffer(buf, scanner);
|
||||||
dbfw_yylex_destroy(scanner);
|
dbfw_yylex_destroy(scanner);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
HASHTABLE *new_users = dbfw_userlist_create();
|
||||||
|
|
||||||
if (rc == 0 && process_user_templates(instance, pstack.templates, pstack.rule))
|
if (rc == 0 && new_users && process_user_templates(new_users, pstack.templates, pstack.rule))
|
||||||
{
|
{
|
||||||
instance->rules = pstack.rule;
|
*rules = pstack.rule;
|
||||||
|
*users = new_users;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = 1;
|
rc = 1;
|
||||||
rule_free_all(pstack.rule);
|
rule_free_all(pstack.rule);
|
||||||
|
hashtable_free(new_users);
|
||||||
MXS_ERROR("Failed to process rule file '%s'.", filename);
|
MXS_ERROR("Failed to process rule file '%s'.", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1345,16 +1360,39 @@ static bool process_rule_file(const char* filename, FW_INSTANCE* instance)
|
|||||||
return rc == 0;
|
return rc == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
HASHTABLE *create_dbfw_users()
|
|
||||||
{
|
|
||||||
HASHTABLE *ht = hashtable_alloc(100, hashtable_item_strhash, hashtable_item_strcmp);
|
|
||||||
|
|
||||||
if (ht)
|
/**
|
||||||
|
* @brief Replace the rule file used by this filter instance
|
||||||
|
*
|
||||||
|
* This function does no locking. An external lock needs to protect this function
|
||||||
|
* call to prevent any connections from using the data when it is being replaced.
|
||||||
|
*
|
||||||
|
* @param filename File where the rules are located
|
||||||
|
* @param instance Filter instance
|
||||||
|
* @return True on success, false on error. If the return value is false, the
|
||||||
|
* old rules remain active.
|
||||||
|
*/
|
||||||
|
bool replace_rule_file(const char* filename, FW_INSTANCE* instance)
|
||||||
{
|
{
|
||||||
hashtable_memory_fns(ht, hashtable_item_strdup, NULL, hashtable_item_free, dbfw_user_free);
|
bool rval = false;
|
||||||
|
RULE *rules;
|
||||||
|
HASHTABLE *users;
|
||||||
|
|
||||||
|
if (process_rule_file(filename, &rules, &users))
|
||||||
|
{
|
||||||
|
/** Rules processed successfully, free the old ones */
|
||||||
|
rule_free_all(instance->rules);
|
||||||
|
hashtable_free(instance->users);
|
||||||
|
instance->rules = rules;
|
||||||
|
instance->users = users;
|
||||||
|
rval = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_ERROR("Failed to process rule file at '%s', old rules are still active.", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ht;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1382,14 +1420,6 @@ createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
|||||||
}
|
}
|
||||||
|
|
||||||
spinlock_init(&my_instance->lock);
|
spinlock_init(&my_instance->lock);
|
||||||
|
|
||||||
if ((my_instance->users = create_dbfw_user()) == NULL)
|
|
||||||
{
|
|
||||||
MXS_ERROR("Unable to allocate hashtable.");
|
|
||||||
MXS_FREE(my_instance);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
my_instance->action = FW_ACTION_BLOCK;
|
my_instance->action = FW_ACTION_BLOCK;
|
||||||
my_instance->log_match = FW_LOG_NONE;
|
my_instance->log_match = FW_LOG_NONE;
|
||||||
|
|
||||||
@ -1444,9 +1474,8 @@ createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
|||||||
err = true;
|
err = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err || !process_rule_file(filename, my_instance))
|
if (err || !process_rule_file(filename, &my_instance->rules, &my_instance->users))
|
||||||
{
|
{
|
||||||
hashtable_free(my_instance->users);
|
|
||||||
MXS_FREE(my_instance);
|
MXS_FREE(my_instance);
|
||||||
my_instance = NULL;
|
my_instance = NULL;
|
||||||
}
|
}
|
||||||
@ -2332,86 +2361,3 @@ static uint64_t getCapabilities(void)
|
|||||||
{
|
{
|
||||||
return RCAP_TYPE_STMT_INPUT;
|
return RCAP_TYPE_STMT_INPUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BUILD_RULE_PARSER
|
|
||||||
// TODO: Not ok to include file from other component's test directory.
|
|
||||||
#include "../../../core/test/test_utils.h"
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
char ch;
|
|
||||||
bool have_icase = false;
|
|
||||||
char *home;
|
|
||||||
char cwd[PATH_MAX];
|
|
||||||
char* opts[2] = {NULL, NULL};
|
|
||||||
FILTER_PARAMETER ruleparam;
|
|
||||||
FILTER_PARAMETER * paramlist[2];
|
|
||||||
|
|
||||||
opterr = 0;
|
|
||||||
while ((ch = getopt(argc, argv, "h?")) != -1)
|
|
||||||
{
|
|
||||||
switch (ch)
|
|
||||||
{
|
|
||||||
case '?':
|
|
||||||
case 'h':
|
|
||||||
printf("Usage: %s [OPTION]... RULEFILE\n"
|
|
||||||
"Options:\n"
|
|
||||||
"\t-?\tPrint this information\n",
|
|
||||||
argv[0]);
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
printf("Unknown option '%c'.\n", ch);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc < 2)
|
|
||||||
{
|
|
||||||
printf("Usage: %s [OPTION]... RULEFILE\n"
|
|
||||||
"-?\tPrint this information\n",
|
|
||||||
argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
home = MXS_MALLOC(sizeof(char) * (PATH_MAX + 1));
|
|
||||||
MXS_ABORT_IF_NULL(home);
|
|
||||||
if (getcwd(home, PATH_MAX) == NULL)
|
|
||||||
{
|
|
||||||
MXS_FREE(home);
|
|
||||||
home = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Log files written to: %s\n", home ? home : "/tpm");
|
|
||||||
|
|
||||||
int argc_ = 2;
|
|
||||||
char* argv_[] =
|
|
||||||
{
|
|
||||||
"log_manager",
|
|
||||||
"-o",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
mxs_log_init(NULL, NULL, MXS_LOG_TARGET_DEFAULT);
|
|
||||||
|
|
||||||
|
|
||||||
init_test_env(home);
|
|
||||||
ruleparam.name = MXS_STRDUP_A("rules");
|
|
||||||
ruleparam.value = MXS_STRDUP_A(argv[1]);
|
|
||||||
paramlist[0] = &ruleparam;
|
|
||||||
paramlist[1] = NULL;
|
|
||||||
|
|
||||||
if (createInstance(opts, paramlist))
|
|
||||||
{
|
|
||||||
printf("Rule parsing was successful.\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Failed to parse rule. Read the error log for the reason of the failure.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
mxs_log_flush_sync();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
Reference in New Issue
Block a user