|
@@ -58,6 +58,14 @@ MODULE_VERSION
|
|
|
|
|
|
#define MAXNUMBERLEN 31
|
|
|
|
|
|
+#define BLACKLISTED_S "blacklisted"
|
|
|
+#define BLACKLISTED_LEN (sizeof(BLACKLISTED_S)-1)
|
|
|
+#define WHITELISTED_S "whitelisted"
|
|
|
+#define WHITELISTED_LEN (sizeof(WHITELISTED_S)-1)
|
|
|
+#define TRUE_S "true"
|
|
|
+#define TRUE_LEN (sizeof(TRUE_S)-1)
|
|
|
+#define FALSE_S "false"
|
|
|
+#define FALSE_LEN (sizeof(FALSE_S)-1)
|
|
|
|
|
|
typedef struct _avp_check
|
|
|
{
|
|
@@ -71,7 +79,7 @@ struct check_blacklist_fs_t {
|
|
|
};
|
|
|
|
|
|
str userblacklist_db_url = str_init(DEFAULT_RODB_URL);
|
|
|
-int use_domain = 0;
|
|
|
+int use_domain = 0;
|
|
|
int match_mode = 10; /* numeric */
|
|
|
static struct dtrie_node_t *gnode = NULL;
|
|
|
|
|
@@ -100,6 +108,11 @@ static void mod_destroy(void);
|
|
|
|
|
|
/* --- fifo functions */
|
|
|
struct mi_root * mi_reload_blacklist(struct mi_root* cmd, void* param); /* usage: kamctl fifo reload_blacklist */
|
|
|
+struct mi_root * mi_dump_blacklist(struct mi_root* cmd, void* param); /* usage: kamctl fifo dump_blacklist */
|
|
|
+struct mi_root * mi_check_blacklist(struct mi_root* cmd, void* param); /* usage: kamctl fifo check_blacklist prefix */
|
|
|
+struct mi_root * mi_check_whitelist(struct mi_root* cmd, void* param); /* usage: kamctl fifo check_whitelist prefix */
|
|
|
+struct mi_root * mi_check_userblacklist(struct mi_root* cmd, void* param); /* usage: kamctl fifo check_userblacklist */
|
|
|
+struct mi_root * mi_check_userwhitelist(struct mi_root* cmd, void* param); /* usage: kamctl fifo check_userwhitelist */
|
|
|
|
|
|
|
|
|
static cmd_export_t cmds[]={
|
|
@@ -123,15 +136,20 @@ static param_export_t params[] = {
|
|
|
userblacklist_DB_COLS
|
|
|
globalblacklist_DB_COLS
|
|
|
{ "use_domain", INT_PARAM, &use_domain },
|
|
|
- { "match_mode", INT_PARAM, &match_mode},
|
|
|
- { 0, 0, 0}
|
|
|
+ { "match_mode", INT_PARAM, &match_mode },
|
|
|
+ { 0, 0, 0 }
|
|
|
};
|
|
|
|
|
|
|
|
|
/* Exported MI functions */
|
|
|
static mi_export_t mi_cmds[] = {
|
|
|
{ "reload_blacklist", mi_reload_blacklist, MI_NO_INPUT_FLAG, 0, mi_child_init },
|
|
|
- { 0, 0, 0, 0, 0}
|
|
|
+ { "dump_blacklist", mi_dump_blacklist, MI_NO_INPUT_FLAG, 0, 0},
|
|
|
+ { "check_blacklist", mi_check_blacklist, 0, 0, 0 },
|
|
|
+ { "check_whitelist", mi_check_whitelist, 0, 0, 0 },
|
|
|
+ { "check_userblacklist", mi_check_userblacklist, 0, 0, 0 },
|
|
|
+ { "check_userwhitelist", mi_check_userwhitelist, 0, 0, 0 },
|
|
|
+ { 0, 0, 0, 0, 0 }
|
|
|
};
|
|
|
|
|
|
|
|
@@ -673,6 +691,332 @@ static void destroy_shmlock(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void dump_dtrie_mi(const struct dtrie_node_t *root,
|
|
|
+ const unsigned int branches, char *prefix, int *length, struct mi_root *reply)
|
|
|
+{
|
|
|
+ struct mi_node *crt_node;
|
|
|
+ unsigned int i;
|
|
|
+ char digit, *val;
|
|
|
+ int val_len;
|
|
|
+
|
|
|
+ /* Sanity check - should not reach here anyway */
|
|
|
+ if (NULL == root) {
|
|
|
+ LM_ERR("root dtrie is NULL\n");
|
|
|
+ return ;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* If data found, add a new node to the reply tree */
|
|
|
+ if (root->data) {
|
|
|
+ /* Create new node and add it to the roots's kids */
|
|
|
+ if(!(crt_node = add_mi_node_child(&reply->node, MI_DUP_NAME, prefix,
|
|
|
+ *length, 0, 0)) ) {
|
|
|
+ LM_ERR("cannot add the child node to the tree\n");
|
|
|
+ return ;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Resolve the value of the whitelist attribute */
|
|
|
+ if (root->data == (void *)MARK_BLACKLIST) {
|
|
|
+ val = int2str(0, &val_len);
|
|
|
+ } else if (root->data == (void *)MARK_WHITELIST) {
|
|
|
+ val = int2str(1, &val_len);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Add the attribute to the current node */
|
|
|
+ if((add_mi_attr(crt_node, MI_DUP_VALUE,
|
|
|
+ userblacklist_whitelist_col.s,
|
|
|
+ userblacklist_whitelist_col.len,
|
|
|
+ val, val_len)) == 0) {
|
|
|
+ LM_ERR("cannot add attributes to the node\n");
|
|
|
+ return ;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Perform a DFS search */
|
|
|
+ for (i = 0; i < branches; i++) {
|
|
|
+ /* If child branch found, traverse it */
|
|
|
+ if (root->child[i]) {
|
|
|
+ if (branches == 10) {
|
|
|
+ digit = i + '0';
|
|
|
+ } else {
|
|
|
+ digit = i;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Push digit in prefix stack */
|
|
|
+ if (*length >= MAXNUMBERLEN + 1) {
|
|
|
+ LM_ERR("prefix length exceeds %d\n", MAXNUMBERLEN + 1);
|
|
|
+ return ;
|
|
|
+ }
|
|
|
+ prefix[(*length)++] = digit;
|
|
|
+
|
|
|
+ /* Recursive DFS call */
|
|
|
+ dump_dtrie_mi(root->child[i], branches, prefix, length, reply);
|
|
|
+
|
|
|
+ /* Pop digit from prefix stack */
|
|
|
+ (*length)--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static struct mi_root * check_list_mi(struct mi_root* cmd, int list_type)
|
|
|
+{
|
|
|
+ struct mi_root *tmp = NULL;
|
|
|
+ struct mi_node *crt_node, *node;
|
|
|
+ struct mi_attr *crt_attr;
|
|
|
+ void **nodeflags;
|
|
|
+ int ret = -1;
|
|
|
+ char *ptr;
|
|
|
+ char req_prefix[MAXNUMBERLEN + 1];
|
|
|
+ str prefix, val, attr;
|
|
|
+
|
|
|
+ node = cmd->node.kids;
|
|
|
+
|
|
|
+ /* Get the prefix number */
|
|
|
+ if (NULL == node)
|
|
|
+ return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
|
|
|
+
|
|
|
+ if (NULL == node->value.s || node->value.len == 0)
|
|
|
+ return init_mi_tree(400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
|
|
|
+ prefix = node->value;
|
|
|
+ strncpy(req_prefix, prefix.s, prefix.len);
|
|
|
+ req_prefix[prefix.len] = '\0';
|
|
|
+
|
|
|
+ /* Check that just 1 argument is given */
|
|
|
+ node = node->next;
|
|
|
+ if (node)
|
|
|
+ return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
|
|
|
+
|
|
|
+ /* Check that global blacklist exists */
|
|
|
+ if (!gnode) {
|
|
|
+ LM_ERR("the global blacklist is NULL\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Check that reply tree is successfully initialized */
|
|
|
+ tmp = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
|
|
|
+ if (!tmp) {
|
|
|
+ LM_ERR("the MI tree cannot be initialized!\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Skip over non-digits. */
|
|
|
+ ptr = req_prefix;
|
|
|
+ while (match_mode == 10 && strlen(ptr) > 0 && !isdigit(*ptr)) {
|
|
|
+ ptr = ptr + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Avoids dirty reads when updating d-tree */
|
|
|
+ lock_get(lock);
|
|
|
+ nodeflags = dtrie_longest_match(gnode, ptr, strlen(ptr), NULL, match_mode);
|
|
|
+ if (nodeflags) {
|
|
|
+ if (*nodeflags == (void *)MARK_WHITELIST) {
|
|
|
+ LM_DBG("prefix %.*s is whitelisted in table %.*s\n",
|
|
|
+ prefix.len, prefix.s, globalblacklist_table.len, globalblacklist_table.s);
|
|
|
+ ret = MARK_WHITELIST;
|
|
|
+ } else if (*nodeflags == (void *)MARK_BLACKLIST) {
|
|
|
+ LM_DBG("prefix %.*s is blacklisted in table %.*s\n",
|
|
|
+ prefix.len, prefix.s, globalblacklist_table.len, globalblacklist_table.s);
|
|
|
+ ret = MARK_BLACKLIST;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ LM_DBG("prefix %.*s not found in table %.*s\n",
|
|
|
+ prefix.len, prefix.s, globalblacklist_table.len, globalblacklist_table.s);
|
|
|
+ }
|
|
|
+ lock_release(lock);
|
|
|
+
|
|
|
+ /* Create new node and add it to the reply roots's kids */
|
|
|
+ if(!(crt_node = add_mi_node_child(&tmp->node, MI_DUP_NAME,
|
|
|
+ prefix.s, prefix.len, 0, 0)) ) {
|
|
|
+ LM_ERR("cannot add the child node to the tree\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Resolve the value of the attribute to be returned */
|
|
|
+ val.s = FALSE_S;
|
|
|
+ val.len = FALSE_LEN;
|
|
|
+
|
|
|
+ switch (list_type) {
|
|
|
+ case MARK_WHITELIST:
|
|
|
+ attr.s = WHITELISTED_S;
|
|
|
+ attr.len = WHITELISTED_LEN;
|
|
|
+
|
|
|
+ if (ret == MARK_WHITELIST) {
|
|
|
+ val.s = TRUE_S;
|
|
|
+ val.len = TRUE_LEN;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ case MARK_BLACKLIST:
|
|
|
+ attr.s = BLACKLISTED_S;
|
|
|
+ attr.len = BLACKLISTED_LEN;
|
|
|
+
|
|
|
+ if (ret == MARK_BLACKLIST) {
|
|
|
+ val.s = TRUE_S;
|
|
|
+ val.len = TRUE_LEN;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ LM_ERR("list_type not found\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Add the attribute to the current node */
|
|
|
+ if (!(crt_attr = add_mi_attr(crt_node, MI_DUP_VALUE,
|
|
|
+ attr.s, attr.len, val.s, val.len))) {
|
|
|
+ LM_ERR("cannot add attribute to the node\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ return tmp;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static struct mi_root * check_userlist_mi(struct mi_root* cmd, int list_type)
|
|
|
+{
|
|
|
+ struct mi_root *tmp = NULL;
|
|
|
+ struct mi_node *crt_node, *node;
|
|
|
+ struct mi_attr *crt_attr;
|
|
|
+ void **nodeflags;
|
|
|
+ int ret = -1;
|
|
|
+ int local_use_domain = 0;
|
|
|
+ char *ptr;
|
|
|
+ char req_prefix[MAXNUMBERLEN + 1];
|
|
|
+ str user, prefix, table, val, attr, domain;
|
|
|
+
|
|
|
+ node = cmd->node.kids;
|
|
|
+
|
|
|
+ /* Get the user number */
|
|
|
+ if (NULL == node)
|
|
|
+ return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
|
|
|
+
|
|
|
+ if (NULL == node->value.s || node->value.len == 0)
|
|
|
+ return init_mi_tree(400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
|
|
|
+ user = node->value;
|
|
|
+
|
|
|
+ /* Get the domain name */
|
|
|
+ node = node->next;
|
|
|
+ if (NULL == node)
|
|
|
+ return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
|
|
|
+
|
|
|
+ if (NULL == node->value.s || node->value.len == 0)
|
|
|
+ return init_mi_tree(400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
|
|
|
+ domain = node->value;
|
|
|
+
|
|
|
+ /* Get the prefix number */
|
|
|
+ node = node->next;
|
|
|
+ if (node) {
|
|
|
+ /* Got 3 params, the third one is the prefix */
|
|
|
+ if (NULL == node->value.s || node->value.len == 0)
|
|
|
+ return init_mi_tree(400, MI_BAD_PARM_S, MI_BAD_PARM_LEN);
|
|
|
+ prefix = node->value;
|
|
|
+ local_use_domain = 1;
|
|
|
+ } else {
|
|
|
+ /* Got 2 params, the second one is the prefix */
|
|
|
+ prefix = domain;
|
|
|
+ local_use_domain = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ strncpy(req_prefix, prefix.s, prefix.len);
|
|
|
+ req_prefix[prefix.len] = '\0';
|
|
|
+
|
|
|
+ /* Check that a maximum of 3 arguments are given */
|
|
|
+ if (node)
|
|
|
+ node = node->next;
|
|
|
+ if (node)
|
|
|
+ return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
|
|
|
+
|
|
|
+ /* Build userblacklist dtrie */
|
|
|
+ table = userblacklist_table;
|
|
|
+ LM_DBG("check entry %s for user %.*s@%.*s in table %.*s, use domain=%d\n",
|
|
|
+ req_prefix, user.len, user.s, domain.len, domain.s,
|
|
|
+ table.len, table.s, local_use_domain);
|
|
|
+ if (db_build_userbl_tree(&user, &domain, &table, dtrie_root, local_use_domain) < 0) {
|
|
|
+ LM_ERR("cannot build d-tree\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Check that reply tree is successfully initialized */
|
|
|
+ tmp = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
|
|
|
+ if (!tmp) {
|
|
|
+ LM_ERR("the MI tree cannot be initialized!\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Skip over non-digits. */
|
|
|
+ ptr = req_prefix;
|
|
|
+ while (match_mode == 10 && strlen(ptr) > 0 && !isdigit(*ptr)) {
|
|
|
+ ptr = ptr + 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Search for a match in dtrie */
|
|
|
+ nodeflags = dtrie_longest_match(dtrie_root, ptr, strlen(ptr), NULL, match_mode);
|
|
|
+ if (nodeflags) {
|
|
|
+ if (*nodeflags == (void *)MARK_WHITELIST) {
|
|
|
+ LM_DBG("user %.*s is whitelisted for prefix %.*s in table %.*s\n",
|
|
|
+ user.len, user.s, prefix.len, prefix.s, table.len, table.s);
|
|
|
+ ret = MARK_WHITELIST;
|
|
|
+ } else if (*nodeflags == (void *)MARK_BLACKLIST) {
|
|
|
+ LM_DBG("user %.*s is blacklisted for prefix %.*s in table %.*s\n",
|
|
|
+ user.len, user.s, prefix.len, prefix.s, table.len, table.s);
|
|
|
+ ret = MARK_BLACKLIST;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ LM_DBG("user %.*s, prefix %.*s not found in table %.*s\n",
|
|
|
+ user.len, user.s, prefix.len, prefix.s, table.len, table.s);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /* Create new node and add it to the reply roots's kids */
|
|
|
+ if(!(crt_node = add_mi_node_child(&tmp->node, MI_DUP_NAME,
|
|
|
+ prefix.s, prefix.len, 0, 0)) ) {
|
|
|
+ LM_ERR("cannot add the child node to the tree\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Resolve the value of the attribute to be returned */
|
|
|
+ val.s = FALSE_S;
|
|
|
+ val.len = FALSE_LEN;
|
|
|
+
|
|
|
+ switch (list_type) {
|
|
|
+ case MARK_WHITELIST:
|
|
|
+ attr.s = WHITELISTED_S;
|
|
|
+ attr.len = WHITELISTED_LEN;
|
|
|
+
|
|
|
+ if (ret == MARK_WHITELIST) {
|
|
|
+ val.s = TRUE_S;
|
|
|
+ val.len = TRUE_LEN;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ case MARK_BLACKLIST:
|
|
|
+ attr.s = BLACKLISTED_S;
|
|
|
+ attr.len = BLACKLISTED_LEN;
|
|
|
+
|
|
|
+ if (ret == MARK_BLACKLIST) {
|
|
|
+ val.s = TRUE_S;
|
|
|
+ val.len = TRUE_LEN;
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ LM_ERR("list_type not found\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Add the attribute to the current node */
|
|
|
+ if (!(crt_attr = add_mi_attr(crt_node, MI_DUP_VALUE,
|
|
|
+ attr.s, attr.len, val.s, val.len))) {
|
|
|
+ LM_ERR("cannot add attribute to the node\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ return tmp;
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
struct mi_root * mi_reload_blacklist(struct mi_root* cmd, void* param)
|
|
|
{
|
|
@@ -687,6 +1031,54 @@ struct mi_root * mi_reload_blacklist(struct mi_root* cmd, void* param)
|
|
|
}
|
|
|
|
|
|
|
|
|
+struct mi_root * mi_dump_blacklist(struct mi_root* cmd, void* param)
|
|
|
+{
|
|
|
+ char prefix_buff[MAXNUMBERLEN + 1];
|
|
|
+ int length = 0;
|
|
|
+ struct mi_root *tmp = NULL;
|
|
|
+
|
|
|
+ /* Check that global blacklist exists */
|
|
|
+ if (!gnode) {
|
|
|
+ LM_ERR("the global blacklist is NULL\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ tmp = init_mi_tree(200, MI_OK_S, MI_OK_LEN);
|
|
|
+ if (!tmp) {
|
|
|
+ LM_ERR("the MI tree cannot be initialized!\n");
|
|
|
+ return init_mi_tree(500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
|
|
|
+ }
|
|
|
+
|
|
|
+ dump_dtrie_mi(gnode, match_mode, prefix_buff, &length, tmp);
|
|
|
+
|
|
|
+ return tmp;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+struct mi_root * mi_check_blacklist(struct mi_root* cmd, void* param)
|
|
|
+{
|
|
|
+ return check_list_mi(cmd, MARK_BLACKLIST);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+struct mi_root * mi_check_whitelist(struct mi_root* cmd, void* param)
|
|
|
+{
|
|
|
+ return check_list_mi(cmd, MARK_WHITELIST);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+struct mi_root * mi_check_userblacklist(struct mi_root* cmd, void* param)
|
|
|
+{
|
|
|
+ return check_userlist_mi(cmd, MARK_BLACKLIST);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+struct mi_root * mi_check_userwhitelist(struct mi_root* cmd, void* param)
|
|
|
+{
|
|
|
+ return check_userlist_mi(cmd, MARK_WHITELIST);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static int mod_init(void)
|
|
|
{
|
|
|
if(register_mi_mod(exports.name, mi_cmds)!=0)
|
|
@@ -710,11 +1102,17 @@ static int child_init(int rank)
|
|
|
return mi_child_init();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
static int userblacklist_child_initialized = 0;
|
|
|
+static int blacklist_child_initialized = 0;
|
|
|
|
|
|
static int mi_child_init(void)
|
|
|
{
|
|
|
+ /* global blacklist init */
|
|
|
+ if (check_globalblacklist_fixup(NULL, 0) != 0) {
|
|
|
+ LM_ERR("could not add global table when init the module");
|
|
|
+ }
|
|
|
+
|
|
|
+ /* user blacklist init */
|
|
|
if(userblacklist_child_initialized)
|
|
|
return 0;
|
|
|
if (userblacklist_db_open() != 0) return -1;
|
|
@@ -723,10 +1121,12 @@ static int mi_child_init(void)
|
|
|
LM_ERR("could not initialize data");
|
|
|
return -1;
|
|
|
}
|
|
|
+
|
|
|
/* because we've added new sources during the fixup */
|
|
|
if (reload_sources() != 0) return -1;
|
|
|
|
|
|
userblacklist_child_initialized = 1;
|
|
|
+ blacklist_child_initialized = 1;
|
|
|
|
|
|
return 0;
|
|
|
}
|