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:
parent
8ae76e3ced
commit
a018e732eb
@ -11,12 +11,11 @@ if(BISON_FOUND AND FLEX_FOUND)
|
||||
set_target_properties(dbfwfilter PROPERTIES VERSION "1.0.0")
|
||||
install_module(dbfwfilter core)
|
||||
|
||||
if(BUILD_TOOLS)
|
||||
add_executable(dbfwruleparser dbfwfilter.c ${BISON_ruleparser_OUTPUTS} ${FLEX_token_OUTPUTS})
|
||||
target_compile_definitions(dbfwruleparser PUBLIC "BUILD_RULE_PARSER")
|
||||
target_link_libraries(dbfwruleparser maxscale-common)
|
||||
install_module(dbfwruleparser core)
|
||||
endif()
|
||||
# The offline rule check utility
|
||||
add_executable(dbfwchk dbfw_rule_check.c ${BISON_ruleparser_OUTPUTS} ${FLEX_token_OUTPUTS})
|
||||
target_link_libraries(dbfwchk maxscale-common)
|
||||
install_executable(dbfwchk core)
|
||||
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find Bison or Flex: ${BISON_EXECUTABLE} ${FLEX_EXECUTABLE}")
|
||||
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);
|
||||
}
|
||||
|
||||
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 '%'.
|
||||
* 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
|
||||
* @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)
|
||||
{
|
||||
bool rval = true;
|
||||
@ -1217,7 +1229,7 @@ static bool process_user_templates(FW_INSTANCE *instance, user_template_t *templ
|
||||
|
||||
while (templates)
|
||||
{
|
||||
DBFW_USER *user = hashtable_fetch(instance->users, templates->name);
|
||||
DBFW_USER *user = hashtable_fetch(users, templates->name);
|
||||
|
||||
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_strict_and = NULL;
|
||||
spinlock_init(&user->lock);
|
||||
hashtable_add(instance->users, user->name, user);
|
||||
hashtable_add(users, user->name, user);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1292,7 +1304,7 @@ static bool process_user_templates(FW_INSTANCE *instance, user_template_t *templ
|
||||
* @param instance Filter instance
|
||||
* @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;
|
||||
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_yylex_destroy(scanner);
|
||||
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
|
||||
{
|
||||
rc = 1;
|
||||
rule_free_all(pstack.rule);
|
||||
hashtable_free(new_users);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
bool rval = false;
|
||||
RULE *rules;
|
||||
HASHTABLE *users;
|
||||
|
||||
if (process_rule_file(filename, &rules, &users))
|
||||
{
|
||||
hashtable_memory_fns(ht, hashtable_item_strdup, NULL, hashtable_item_free, dbfw_user_free);
|
||||
/** 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);
|
||||
|
||||
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->log_match = FW_LOG_NONE;
|
||||
|
||||
@ -1444,9 +1474,8 @@ createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||
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);
|
||||
my_instance = NULL;
|
||||
}
|
||||
@ -2332,86 +2361,3 @@ static uint64_t getCapabilities(void)
|
||||
{
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user