nat: Introduce a global IMSI barr list using red-black trees
This commit is contained in:
parent
0434faedc9
commit
1f8276e588
|
@ -287,6 +287,10 @@ struct bsc_nat {
|
|||
/* filter */
|
||||
char *acc_lst_name;
|
||||
|
||||
/* Barring of subscribers with a rb tree */
|
||||
struct rb_root imsi_black_list;
|
||||
char *imsi_black_list_fn;
|
||||
|
||||
/* number rewriting */
|
||||
char *num_rewr_name;
|
||||
struct llist_head num_rewr;
|
||||
|
@ -448,6 +452,17 @@ struct bsc_nat_num_rewr_entry {
|
|||
|
||||
void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head, const struct osmo_config_list *);
|
||||
|
||||
struct bsc_nat_barr_entry {
|
||||
struct rb_node node;
|
||||
|
||||
char *imsi;
|
||||
int cm_reject_cause;
|
||||
int lu_reject_cause;
|
||||
};
|
||||
|
||||
int bsc_nat_barr_adapt(void *ctx, struct rb_root *rbtree, const struct osmo_config_list *);
|
||||
int bsc_nat_barr_find(struct rb_root *root, const char *imsi, int *cm, int *lu);
|
||||
|
||||
struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, int port);
|
||||
void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending);
|
||||
int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg);
|
||||
|
|
|
@ -37,6 +37,91 @@
|
|||
|
||||
#include <osmocom/sccp/sccp.h>
|
||||
|
||||
int bsc_nat_barr_find(struct rb_root *root, const char *imsi, int *cm, int *lu)
|
||||
{
|
||||
struct bsc_nat_barr_entry *n;
|
||||
n = rb_entry(root->rb_node, struct bsc_nat_barr_entry, node);
|
||||
|
||||
while (n) {
|
||||
int rc = strcmp(imsi, n->imsi);
|
||||
if (rc == 0) {
|
||||
*cm = n->cm_reject_cause;
|
||||
*lu = n->lu_reject_cause;
|
||||
return 1;
|
||||
}
|
||||
|
||||
n = rb_entry(
|
||||
(rc < 0) ? n->node.rb_left : n->node.rb_right,
|
||||
struct bsc_nat_barr_entry, node);
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int insert_barr_node(struct bsc_nat_barr_entry *entry, struct rb_root *root)
|
||||
{
|
||||
struct rb_node **new = &root->rb_node, *parent = NULL;
|
||||
|
||||
while (*new) {
|
||||
int rc;
|
||||
struct bsc_nat_barr_entry *this;
|
||||
this = rb_entry(*new, struct bsc_nat_barr_entry, node);
|
||||
parent = *new;
|
||||
|
||||
rc = strcmp(entry->imsi, this->imsi);
|
||||
if (rc < 0)
|
||||
new = &((*new)->rb_left);
|
||||
else if (rc > 0)
|
||||
new = &((*new)->rb_right);
|
||||
else {
|
||||
LOGP(DNAT, LOGL_ERROR,
|
||||
"Duplicate entry for IMSI(%s)\n", entry->imsi);
|
||||
talloc_free(entry);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
rb_link_node(&entry->node, parent, new);
|
||||
rb_insert_color(&entry->node, root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bsc_nat_barr_adapt(void *ctx, struct rb_root *root,
|
||||
const struct osmo_config_list *list)
|
||||
{
|
||||
struct osmo_config_entry *cfg_entry;
|
||||
int err = 0;
|
||||
|
||||
/* free the old data */
|
||||
while (!RB_EMPTY_ROOT(root)) {
|
||||
struct rb_node *node = rb_first(root);
|
||||
rb_erase(node, root);
|
||||
talloc_free(node);
|
||||
}
|
||||
|
||||
if (!list)
|
||||
return 0;
|
||||
|
||||
/* now adapt the new list */
|
||||
llist_for_each_entry(cfg_entry, &list->entry, list) {
|
||||
struct bsc_nat_barr_entry *entry;
|
||||
entry = talloc_zero(ctx, struct bsc_nat_barr_entry);
|
||||
if (!entry) {
|
||||
LOGP(DNAT, LOGL_ERROR,
|
||||
"Allocation of the barr entry failed.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
entry->imsi = talloc_strdup(entry, cfg_entry->mcc);
|
||||
entry->cm_reject_cause = atoi(cfg_entry->mnc);
|
||||
entry->lu_reject_cause = atoi(cfg_entry->option);
|
||||
err |= insert_barr_node(entry, root);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int lst_check_deny(struct bsc_nat_acc_lst *lst, const char *mi_string)
|
||||
{
|
||||
struct bsc_nat_acc_lst_entry *entry;
|
||||
|
@ -52,43 +137,56 @@ static int lst_check_deny(struct bsc_nat_acc_lst *lst, const char *mi_string)
|
|||
}
|
||||
|
||||
/* apply white/black list */
|
||||
static int auth_imsi(struct bsc_connection *bsc, const char *mi_string,
|
||||
static int auth_imsi(struct bsc_connection *bsc, const char *imsi,
|
||||
struct bsc_nat_reject_cause *cause)
|
||||
{
|
||||
/*
|
||||
* Now apply blacklist/whitelist of the BSC and the NAT.
|
||||
* 1.) Allow directly if the IMSI is allowed at the BSC
|
||||
* 2.) Reject if the IMSI is not allowed at the BSC
|
||||
* 3.) Reject if the IMSI not allowed at the global level.
|
||||
* 4.) Allow directly if the IMSI is allowed at the global level
|
||||
* 1.) Check the global IMSI barr list
|
||||
* 2.) Allow directly if the IMSI is allowed at the BSC
|
||||
* 3.) Reject if the IMSI is not allowed at the BSC
|
||||
* 4.) Reject if the IMSI not allowed at the global level.
|
||||
* 5.) Allow directly if the IMSI is allowed at the global level
|
||||
*/
|
||||
int cm, lu;
|
||||
struct bsc_nat_acc_lst *nat_lst = NULL;
|
||||
struct bsc_nat_acc_lst *bsc_lst = NULL;
|
||||
|
||||
/* 1. global check for barred imsis */
|
||||
if (bsc_nat_barr_find(&bsc->nat->imsi_black_list, imsi, &cm, &lu)) {
|
||||
cause->cm_reject_cause = cm;
|
||||
cause->lu_reject_cause = lu;
|
||||
LOGP(DNAT, LOGL_DEBUG,
|
||||
"Blocking subscriber IMSI %s with CM: %d LU: %d\n",
|
||||
imsi, cm, lu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
bsc_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->cfg->acc_lst_name);
|
||||
nat_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->nat->acc_lst_name);
|
||||
|
||||
|
||||
if (bsc_lst) {
|
||||
/* 1. BSC allow */
|
||||
if (bsc_nat_lst_check_allow(bsc_lst, mi_string) == 0)
|
||||
/* 2. BSC allow */
|
||||
if (bsc_nat_lst_check_allow(bsc_lst, imsi) == 0)
|
||||
return 1;
|
||||
|
||||
/* 2. BSC deny */
|
||||
if (lst_check_deny(bsc_lst, mi_string) == 0) {
|
||||
/* 3. BSC deny */
|
||||
if (lst_check_deny(bsc_lst, imsi) == 0) {
|
||||
LOGP(DNAT, LOGL_ERROR,
|
||||
"Filtering %s by imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
|
||||
"Filtering %s by imsi_deny on bsc nr: %d.\n", imsi, bsc->cfg->nr);
|
||||
rate_ctr_inc(&bsc_lst->stats->ctr[ACC_LIST_BSC_FILTER]);
|
||||
return -2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* 3. NAT deny */
|
||||
/* 4. NAT deny */
|
||||
if (nat_lst) {
|
||||
if (lst_check_deny(nat_lst, mi_string) == 0) {
|
||||
if (lst_check_deny(nat_lst, imsi) == 0) {
|
||||
LOGP(DNAT, LOGL_ERROR,
|
||||
"Filtering %s by nat imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
|
||||
"Filtering %s by nat imsi_deny on bsc nr: %d.\n", imsi, bsc->cfg->nr);
|
||||
rate_ctr_inc(&nat_lst->stats->ctr[ACC_LIST_NAT_FILTER]);
|
||||
return -3;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* OpenBSC NAT interface to quagga VTY */
|
||||
/* (C) 2010-2011 by Holger Hans Peter Freyther
|
||||
* (C) 2010-2011 by On-Waves
|
||||
/* (C) 2010-2012 by Holger Hans Peter Freyther
|
||||
* (C) 2010-2012 by On-Waves
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -112,6 +112,9 @@ static int config_write_nat(struct vty *vty)
|
|||
vty_out(vty, " ip-dscp %d%s", _nat->bsc_ip_dscp, VTY_NEWLINE);
|
||||
if (_nat->acc_lst_name)
|
||||
vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE);
|
||||
if (_nat->imsi_black_list_fn)
|
||||
vty_out(vty, " imsi-black-list-file-name %s%s",
|
||||
_nat->imsi_black_list_fn, VTY_NEWLINE);
|
||||
if (_nat->ussd_lst_name)
|
||||
vty_out(vty, " ussd-list-name %s%s", _nat->ussd_lst_name, VTY_NEWLINE);
|
||||
if (_nat->ussd_query)
|
||||
|
@ -486,6 +489,42 @@ DEFUN(cfg_nat_no_acc_lst_name,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nat_imsi_black_list_fn,
|
||||
cfg_nat_imsi_black_list_fn_cmd,
|
||||
"imsi-black-list-file-name NAME",
|
||||
"IMSI black listing\n" "Filename IMSI and reject-cause\n")
|
||||
{
|
||||
|
||||
bsc_replace_string(_nat, &_nat->imsi_black_list_fn, argv[0]);
|
||||
if (_nat->imsi_black_list_fn) {
|
||||
int rc;
|
||||
struct osmo_config_list *rewr = NULL;
|
||||
rewr = osmo_config_list_parse(_nat, _nat->imsi_black_list_fn);
|
||||
rc = bsc_nat_barr_adapt(_nat, &_nat->imsi_black_list, rewr);
|
||||
if (rc != 0) {
|
||||
vty_out(vty, "%%There was an error parsing the list."
|
||||
" Please see the error log.%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
bsc_nat_barr_adapt(_nat, &_nat->imsi_black_list, NULL);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nat_no_imsi_black_list_fn,
|
||||
cfg_nat_no_imsi_black_list_fn_cmd,
|
||||
"no imsi-black-list-file-name",
|
||||
NO_STR "Remove the imsi-black-list\n")
|
||||
{
|
||||
talloc_free(_nat->imsi_black_list_fn);
|
||||
_nat->imsi_black_list_fn = NULL;
|
||||
bsc_nat_barr_adapt(_nat, &_nat->imsi_black_list, NULL);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int replace_rules(struct bsc_nat *nat, char **name,
|
||||
struct llist_head *head, const char *file)
|
||||
{
|
||||
|
@ -774,6 +813,27 @@ DEFUN(show_acc_lst,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(show_bar_lst,
|
||||
show_bar_lst_cmd,
|
||||
"show imsi-black-list",
|
||||
SHOW_STR "IMSIs barred from the network\n")
|
||||
{
|
||||
struct rb_node *node;
|
||||
|
||||
vty_out(vty, "IMSIs barred from the network:%s", VTY_NEWLINE);
|
||||
|
||||
for (node = rb_first(&_nat->imsi_black_list); node; node = rb_next(node)) {
|
||||
struct bsc_nat_barr_entry *entry;
|
||||
entry = rb_entry(node, struct bsc_nat_barr_entry, node);
|
||||
|
||||
vty_out(vty, " IMSI(%s) CM-Reject-Cause(%d) LU-Reject-Cause(%d)%s",
|
||||
entry->imsi, entry->cm_reject_cause, entry->lu_reject_cause,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DEFUN(cfg_bsc_acc_lst_name,
|
||||
cfg_bsc_acc_lst_name_cmd,
|
||||
|
@ -999,6 +1059,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
|
|||
install_element_ve(&test_regex_cmd);
|
||||
install_element_ve(&show_bsc_mgcp_cmd);
|
||||
install_element_ve(&show_acc_lst_cmd);
|
||||
install_element_ve(&show_bar_lst_cmd);
|
||||
|
||||
install_element(ENABLE_NODE, &set_last_endp_cmd);
|
||||
install_element(ENABLE_NODE, &block_new_conn_cmd);
|
||||
|
@ -1019,6 +1080,8 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
|
|||
install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_no_acc_lst_name_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_imsi_black_list_fn_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_no_imsi_black_list_fn_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_ussd_lst_name_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_ussd_query_cmd);
|
||||
install_element(NAT_NODE, &cfg_nat_ussd_token_cmd);
|
||||
|
|
|
@ -2,7 +2,7 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
|
|||
AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS)
|
||||
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
|
||||
|
||||
EXTRA_DIST = bsc_nat_test.ok bsc_data.c
|
||||
EXTRA_DIST = bsc_nat_test.ok bsc_data.c barr.cfg barr_dup.cfg
|
||||
|
||||
noinst_PROGRAMS = bsc_nat_test
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
12123124:3:2:
|
||||
12123123:3:1:
|
||||
12123128:3:6:
|
||||
12123125:3:3:
|
||||
12123127:3:5:
|
||||
12123126:3:4:
|
||||
12123120:3:4:
|
||||
12123119:3:4:
|
||||
12123118:3:4:
|
||||
12123117:3:4:
|
||||
12123116:3:4:
|
||||
12123115:3:4:
|
|
@ -0,0 +1,2 @@
|
|||
12123124:3:2:
|
||||
12123124:3:2:
|
|
@ -1153,6 +1153,72 @@ static void test_sms_number_rewrite(void)
|
|||
msgb_free(out);
|
||||
}
|
||||
|
||||
static void test_barr_list_parsing(void)
|
||||
{
|
||||
int rc;
|
||||
int cm, lu;
|
||||
struct rb_node *node;
|
||||
struct rb_root root = RB_ROOT;
|
||||
struct osmo_config_list *lst = osmo_config_list_parse(NULL, "barr.cfg");
|
||||
if (lst == NULL)
|
||||
abort();
|
||||
|
||||
rc = bsc_nat_barr_adapt(NULL, &root, lst);
|
||||
if (rc != 0)
|
||||
abort();
|
||||
talloc_free(lst);
|
||||
|
||||
|
||||
for (node = rb_first(&root); node; node = rb_next(node)) {
|
||||
struct bsc_nat_barr_entry *entry;
|
||||
entry = rb_entry(node, struct bsc_nat_barr_entry, node);
|
||||
printf("IMSI: %s CM: %d LU: %d\n", entry->imsi,
|
||||
entry->cm_reject_cause, entry->lu_reject_cause);
|
||||
}
|
||||
|
||||
/* do the look up now.. */
|
||||
rc = bsc_nat_barr_find(&root, "12123119", &cm, &lu);
|
||||
if (!rc) {
|
||||
printf("Failed to find the IMSI.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (cm != 3 || lu != 4) {
|
||||
printf("Found CM(%d) and LU(%d)\n", cm, lu);
|
||||
abort();
|
||||
}
|
||||
|
||||
/* empty and check that it is empty */
|
||||
bsc_nat_barr_adapt(NULL, &root, NULL);
|
||||
if (!RB_EMPTY_ROOT(&root)) {
|
||||
printf("Failed to empty the list.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
/* check that dup results in an error */
|
||||
lst = osmo_config_list_parse(NULL, "barr_dup.cfg");
|
||||
if (lst == NULL) {
|
||||
printf("Failed to parse list with dups\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
rc = bsc_nat_barr_adapt(NULL, &root, lst);
|
||||
if (rc != -1) {
|
||||
printf("It should have failed due dup\n");
|
||||
abort();
|
||||
}
|
||||
talloc_free(lst);
|
||||
|
||||
/* dump for reference */
|
||||
for (node = rb_first(&root); node; node = rb_next(node)) {
|
||||
struct bsc_nat_barr_entry *entry;
|
||||
entry = rb_entry(node, struct bsc_nat_barr_entry, node);
|
||||
printf("IMSI: %s CM: %d LU: %d\n", entry->imsi,
|
||||
entry->cm_reject_cause, entry->lu_reject_cause);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
sccp_set_log_area(DSCCP);
|
||||
|
@ -1171,6 +1237,7 @@ int main(int argc, char **argv)
|
|||
test_sms_smsc_rewrite();
|
||||
test_sms_number_rewrite();
|
||||
test_mgcp_allocations();
|
||||
test_barr_list_parsing();
|
||||
|
||||
printf("Testing execution completed.\n");
|
||||
return 0;
|
||||
|
|
|
@ -22,4 +22,17 @@ Testing SMSC rewriting.
|
|||
Attempting to only rewrite the HDR
|
||||
Attempting to change nothing.
|
||||
Testing SMS TP-DA rewriting.
|
||||
IMSI: 12123115 CM: 3 LU: 4
|
||||
IMSI: 12123116 CM: 3 LU: 4
|
||||
IMSI: 12123117 CM: 3 LU: 4
|
||||
IMSI: 12123118 CM: 3 LU: 4
|
||||
IMSI: 12123119 CM: 3 LU: 4
|
||||
IMSI: 12123120 CM: 3 LU: 4
|
||||
IMSI: 12123123 CM: 3 LU: 1
|
||||
IMSI: 12123124 CM: 3 LU: 2
|
||||
IMSI: 12123125 CM: 3 LU: 3
|
||||
IMSI: 12123126 CM: 3 LU: 4
|
||||
IMSI: 12123127 CM: 3 LU: 5
|
||||
IMSI: 12123128 CM: 3 LU: 6
|
||||
IMSI: 12123124 CM: 3 LU: 2
|
||||
Testing execution completed.
|
||||
|
|
|
@ -34,6 +34,8 @@ AT_CLEANUP
|
|||
AT_SETUP([bsc-nat])
|
||||
AT_KEYWORDS([bsc-nat])
|
||||
AT_CHECK([test "$enable_nat_test" != no || exit 77])
|
||||
cp $abs_srcdir/bsc-nat/barr.cfg .
|
||||
cp $abs_srcdir/bsc-nat/barr_dup.cfg .
|
||||
cat $abs_srcdir/bsc-nat/bsc_nat_test.ok > expout
|
||||
AT_CHECK([$abs_top_builddir/tests/bsc-nat/bsc_nat_test], [], [expout], [ignore])
|
||||
AT_CLEANUP
|
||||
|
|
Loading…
Reference in New Issue