[nat] Introduce the concept of access-list

One can set one access-list to one BSC and one
access-list to one NAT. The matching of IMSIs
remains the same for now, also applying the
white/blacklist. Access lists can not be deleted
for now and no perf opt is done (e.g. one could
cache the result of the last lookup in the bsc
struct).
This commit is contained in:
Holger Hans Peter Freyther 2010-06-01 01:03:13 +08:00
parent 078321aaae
commit 8affef5059
4 changed files with 152 additions and 51 deletions

View File

@ -165,10 +165,7 @@ struct bsc_config {
char *description; char *description;
/* imsi white and blacklist */ /* imsi white and blacklist */
char *imsi_allow; char *acc_lst_name;
regex_t imsi_allow_re;
char *imsi_deny;
regex_t imsi_deny_re;
int forbid_paging; int forbid_paging;
@ -207,6 +204,19 @@ struct bsc_nat_statistics {
} msc; } msc;
}; };
struct bsc_nat_access_list {
struct llist_head list;
/* the name of the list */
const char *name;
/* the filter */
char *imsi_allow;
regex_t imsi_allow_re;
char *imsi_deny;
regex_t imsi_deny_re;
};
/** /**
* the structure of the "nat" network * the structure of the "nat" network
*/ */
@ -217,6 +227,9 @@ struct bsc_nat {
/* active BSC connections that need patching */ /* active BSC connections that need patching */
struct llist_head bsc_connections; struct llist_head bsc_connections;
/* access lists */
struct llist_head access_lists;
/* known BSC's */ /* known BSC's */
struct llist_head bsc_configs; struct llist_head bsc_configs;
int num_bsc; int num_bsc;
@ -243,8 +256,7 @@ struct bsc_nat {
struct bsc_endpoint *bsc_endpoints; struct bsc_endpoint *bsc_endpoints;
/* filter */ /* filter */
char *imsi_deny; char *acc_lst_name;
regex_t imsi_deny_re;
/* statistics */ /* statistics */
struct bsc_nat_statistics stats; struct bsc_nat_statistics stats;
@ -310,7 +322,9 @@ int bsc_mgcp_extract_ci(const char *resp);
int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id); int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id);
/* regexp handling */ /* IMSI allow/deny handling */
void bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv); void bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv);
struct bsc_nat_access_list *bsc_nat_accs_list_find(struct bsc_nat *nat, const char *name);
struct bsc_nat_access_list *bsc_nat_accs_list_get(struct bsc_nat *nat, const char *name);
#endif #endif

View File

@ -46,6 +46,8 @@ struct bsc_nat *bsc_nat_alloc(void)
INIT_LLIST_HEAD(&nat->sccp_connections); INIT_LLIST_HEAD(&nat->sccp_connections);
INIT_LLIST_HEAD(&nat->bsc_connections); INIT_LLIST_HEAD(&nat->bsc_connections);
INIT_LLIST_HEAD(&nat->bsc_configs); INIT_LLIST_HEAD(&nat->bsc_configs);
INIT_LLIST_HEAD(&nat->access_lists);
nat->stats.sccp.conn = counter_alloc("nat.sccp.conn"); nat->stats.sccp.conn = counter_alloc("nat.sccp.conn");
nat->stats.sccp.calls = counter_alloc("nat.sccp.calls"); nat->stats.sccp.calls = counter_alloc("nat.sccp.calls");
nat->stats.bsc.reconn = counter_alloc("nat.bsc.conn"); nat->stats.bsc.reconn = counter_alloc("nat.bsc.conn");
@ -203,10 +205,16 @@ static int auth_imsi(struct bsc_connection *bsc, const char *mi_string)
* 3.) Reject if the IMSI not allowed at the global level. * 3.) Reject if the IMSI not allowed at the global level.
* 4.) Allow directly if the IMSI is allowed at the global level * 4.) Allow directly if the IMSI is allowed at the global level
*/ */
struct bsc_nat_access_list *nat_lst = NULL;
struct bsc_nat_access_list *bsc_lst = NULL;
bsc_lst = bsc_nat_accs_list_find(bsc->nat, bsc->cfg->acc_lst_name);
nat_lst = bsc_nat_accs_list_find(bsc->nat, bsc->nat->acc_lst_name);
/* 1. BSC deny */ /* 1. BSC deny */
if (bsc->cfg->imsi_deny) { if (bsc_lst && bsc_lst->imsi_deny) {
if (regexec(&bsc->cfg->imsi_deny_re, mi_string, 0, NULL, 0) == 0) { if (regexec(&bsc_lst->imsi_deny_re, mi_string, 0, NULL, 0) == 0) {
LOGP(DNAT, LOGL_ERROR, 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", mi_string, bsc->cfg->nr);
return -2; return -2;
@ -214,14 +222,14 @@ static int auth_imsi(struct bsc_connection *bsc, const char *mi_string)
} }
/* 2. BSC allow */ /* 2. BSC allow */
if (bsc->cfg->imsi_allow) { if (bsc_lst && bsc_lst->imsi_allow) {
if (regexec(&bsc->cfg->imsi_allow_re, mi_string, 0, NULL, 0) == 0) if (regexec(&bsc_lst->imsi_allow_re, mi_string, 0, NULL, 0) == 0)
return 0; return 0;
} }
/* 3. NAT deny */ /* 3. NAT deny */
if (bsc->nat->imsi_deny) { if (nat_lst && nat_lst->imsi_deny) {
if (regexec(&bsc->nat->imsi_deny_re, mi_string, 0, NULL, 0) == 0) { if (regexec(&nat_lst->imsi_deny_re, mi_string, 0, NULL, 0) == 0) {
LOGP(DNAT, LOGL_ERROR, 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", mi_string, bsc->cfg->nr);
return -3; return -3;
@ -402,4 +410,37 @@ static const char *con_types [] = {
const char *bsc_con_type_to_string(int type) const char *bsc_con_type_to_string(int type)
{ {
return con_types[type]; return con_types[type];
}
struct bsc_nat_access_list *bsc_nat_accs_list_find(struct bsc_nat *nat, const char *name)
{
struct bsc_nat_access_list *lst;
if (!name)
return NULL;
llist_for_each_entry(lst, &nat->access_lists, list)
if (strcmp(lst->name, name) == 0)
return lst;
return NULL;
}
struct bsc_nat_access_list *bsc_nat_accs_list_get(struct bsc_nat *nat, const char *name)
{
struct bsc_nat_access_list *lst;
lst = bsc_nat_accs_list_find(nat, name);
if (lst)
return lst;
lst = talloc_zero(nat, struct bsc_nat_access_list);
if (!lst) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate access list");
return NULL;
}
lst->name = talloc_strdup(lst, name);
llist_add(&lst->list, &nat->access_lists);
return lst;
} }

View File

@ -51,9 +51,9 @@ static struct cmd_node bsc_node = {
static int config_write_nat(struct vty *vty) static int config_write_nat(struct vty *vty)
{ {
struct bsc_nat_access_list *lst;
vty_out(vty, "nat%s", VTY_NEWLINE); vty_out(vty, "nat%s", VTY_NEWLINE);
if (_nat->imsi_deny)
vty_out(vty, " imsi deny %s%s", _nat->imsi_deny, VTY_NEWLINE);
vty_out(vty, " msc ip %s%s", _nat->msc_ip, VTY_NEWLINE); vty_out(vty, " msc ip %s%s", _nat->msc_ip, VTY_NEWLINE);
vty_out(vty, " msc port %d%s", _nat->msc_port, VTY_NEWLINE); vty_out(vty, " msc port %d%s", _nat->msc_port, VTY_NEWLINE);
vty_out(vty, " timeout auth %d%s", _nat->auth_timeout, VTY_NEWLINE); vty_out(vty, " timeout auth %d%s", _nat->auth_timeout, VTY_NEWLINE);
@ -62,6 +62,18 @@ static int config_write_nat(struct vty *vty)
if (_nat->token) if (_nat->token)
vty_out(vty, " token %s%s", _nat->token, VTY_NEWLINE); vty_out(vty, " token %s%s", _nat->token, VTY_NEWLINE);
vty_out(vty, " ip-tos %d%s", _nat->bsc_ip_tos, VTY_NEWLINE); vty_out(vty, " ip-tos %d%s", _nat->bsc_ip_tos, VTY_NEWLINE);
if (_nat->acc_lst_name)
vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE);
llist_for_each_entry(lst, &_nat->access_lists, list) {
if (lst->imsi_allow)
vty_out(vty, " access-list %s imsi-allow %s%s",
lst->name, lst->imsi_allow, VTY_NEWLINE);
if (lst->imsi_deny)
vty_out(vty, " access-list %s imsi-deny %s%s",
lst->name, lst->imsi_deny, VTY_NEWLINE);
}
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -70,13 +82,11 @@ static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
vty_out(vty, " bsc %u%s", bsc->nr, VTY_NEWLINE); vty_out(vty, " bsc %u%s", bsc->nr, VTY_NEWLINE);
vty_out(vty, " token %s%s", bsc->token, VTY_NEWLINE); vty_out(vty, " token %s%s", bsc->token, VTY_NEWLINE);
vty_out(vty, " location_area_code %u%s", bsc->lac, VTY_NEWLINE); vty_out(vty, " location_area_code %u%s", bsc->lac, VTY_NEWLINE);
if (bsc->imsi_allow)
vty_out(vty, " imsi allow %s%s", bsc->imsi_allow, VTY_NEWLINE);
if (bsc->imsi_deny)
vty_out(vty, " imsi deny %s%s", bsc->imsi_deny, VTY_NEWLINE);
vty_out(vty, " paging forbidden %d%s", bsc->forbid_paging, VTY_NEWLINE); vty_out(vty, " paging forbidden %d%s", bsc->forbid_paging, VTY_NEWLINE);
if (bsc->description) if (bsc->description)
vty_out(vty, " description %s%s", bsc->description, VTY_NEWLINE); vty_out(vty, " description %s%s", bsc->description, VTY_NEWLINE);
if (bsc->acc_lst_name)
vty_out(vty, " access-list-name %s%s", bsc->acc_lst_name, VTY_NEWLINE);
} }
static int config_write_bsc(struct vty *vty) static int config_write_bsc(struct vty *vty)
@ -137,10 +147,9 @@ DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "show bsc config",
llist_for_each_entry(conf, &_nat->bsc_configs, entry) { llist_for_each_entry(conf, &_nat->bsc_configs, entry) {
vty_out(vty, "BSC token: '%s' lac: %u nr: %u%s", vty_out(vty, "BSC token: '%s' lac: %u nr: %u%s",
conf->token, conf->lac, conf->nr, VTY_NEWLINE); conf->token, conf->lac, conf->nr, VTY_NEWLINE);
vty_out(vty, " imsi_allow: '%s' imsi_deny: '%s'%s", if (conf->acc_lst_name)
conf->imsi_allow ? conf->imsi_allow: "any", vty_out(vty, " access-list: %s%s",
conf->imsi_deny ? conf->imsi_deny : "none", conf->acc_lst_name, VTY_NEWLINE);
VTY_NEWLINE);
vty_out(vty, " paging forbidden: %d%s", vty_out(vty, " paging forbidden: %d%s",
conf->forbid_paging, VTY_NEWLINE); conf->forbid_paging, VTY_NEWLINE);
if (conf->description) if (conf->description)
@ -233,16 +242,6 @@ DEFUN(cfg_nat, cfg_nat_cmd, "nat", "Configute the NAT")
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_nat_imsi_deny,
cfg_nat_imsi_deny_cmd,
"imsi deny [REGEXP]",
"Deny matching IMSIs to talk to the MSC. "
"The defualt is to not deny.")
{
bsc_parse_reg(_nat, &_nat->imsi_deny_re, &_nat->imsi_deny, argc, argv);
return CMD_SUCCESS;
}
DEFUN(cfg_nat_msc_ip, DEFUN(cfg_nat_msc_ip,
cfg_nat_msc_ip_cmd, cfg_nat_msc_ip_cmd,
"msc ip A.B.C.D", "msc ip A.B.C.D",
@ -306,6 +305,18 @@ DEFUN(cfg_nat_bsc_ip_tos, cfg_nat_bsc_ip_tos_cmd,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_nat_acc_lst_name,
cfg_nat_acc_lst_name_cmd,
"access-list-name NAME",
"Set the name of the access list to use.\n"
"The name of the to be used access list.")
{
if (_nat->acc_lst_name)
talloc_free(_nat->acc_lst_name);
_nat->acc_lst_name = talloc_strdup(_nat, argv[0]);
return CMD_SUCCESS;
}
/* per BSC configuration */ /* per BSC configuration */
DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "Select a BSC to configure") DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "Select a BSC to configure")
{ {
@ -368,27 +379,53 @@ DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>",
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_bsc_imsi_allow, DEFUN(cfg_lst_imsi_allow,
cfg_bsc_imsi_allow_cmd, cfg_lst_imsi_allow_cmd,
"imsi allow [REGEXP]", "access-list NAME imsi-allow [REGEXP]",
"Allow IMSIs with the following network to talk to the MSC." "Allow IMSIs matching the REGEXP\n"
"The default is to allow everyone)") "The name of the access-list\n"
"The regexp of allowed IMSIs\n")
{ {
struct bsc_nat_access_list *acc;
struct bsc_config *conf = vty->index; struct bsc_config *conf = vty->index;
bsc_parse_reg(conf, &conf->imsi_allow_re, &conf->imsi_allow, argc, argv); acc = bsc_nat_accs_list_get(conf->nat, argv[0]);
if (!acc)
return CMD_WARNING;
bsc_parse_reg(acc, &acc->imsi_allow_re, &acc->imsi_allow, argc, argv);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_bsc_imsi_deny, DEFUN(cfg_lst_imsi_deny,
cfg_bsc_imsi_deny_cmd, cfg_lst_imsi_deny_cmd,
"imsi deny [REGEXP]", "access-list NAME imsi-deny [REGEXP]",
"Deny IMSIs with the following network to talk to the MSC." "Allow IMSIs matching the REGEXP\n"
"The default is to not deny anyone.)") "The name of the access-list\n"
"The regexp of to be denied IMSIs\n")
{
struct bsc_nat_access_list *acc;
struct bsc_config *conf = vty->index;
acc = bsc_nat_accs_list_get(conf->nat, argv[0]);
if (!acc)
return CMD_WARNING;
bsc_parse_reg(acc, &acc->imsi_deny_re, &acc->imsi_deny, argc, argv);
return CMD_SUCCESS;
}
DEFUN(cfg_bsc_acc_lst_name,
cfg_bsc_acc_lst_name_cmd,
"access-list-name NAME",
"Set the name of the access list to use.\n"
"The name of the to be used access list.")
{ {
struct bsc_config *conf = vty->index; struct bsc_config *conf = vty->index;
bsc_parse_reg(conf, &conf->imsi_deny_re, &conf->imsi_deny, argc, argv); if (conf->acc_lst_name)
talloc_free(conf->acc_lst_name);
conf->acc_lst_name = talloc_strdup(conf, argv[0]);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -460,7 +497,6 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(CONFIG_NODE, &cfg_nat_cmd); install_element(CONFIG_NODE, &cfg_nat_cmd);
install_node(&nat_node, config_write_nat); install_node(&nat_node, config_write_nat);
install_default(NAT_NODE); install_default(NAT_NODE);
install_element(NAT_NODE, &cfg_nat_imsi_deny_cmd);
install_element(NAT_NODE, &cfg_nat_msc_ip_cmd); install_element(NAT_NODE, &cfg_nat_msc_ip_cmd);
install_element(NAT_NODE, &cfg_nat_msc_port_cmd); install_element(NAT_NODE, &cfg_nat_msc_port_cmd);
install_element(NAT_NODE, &cfg_nat_auth_time_cmd); install_element(NAT_NODE, &cfg_nat_auth_time_cmd);
@ -468,6 +504,11 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(NAT_NODE, &cfg_nat_pong_time_cmd); install_element(NAT_NODE, &cfg_nat_pong_time_cmd);
install_element(NAT_NODE, &cfg_nat_token_cmd); install_element(NAT_NODE, &cfg_nat_token_cmd);
install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd); install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd);
install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd);
/* access-list */
install_element(NAT_NODE, &cfg_lst_imsi_allow_cmd);
install_element(NAT_NODE, &cfg_lst_imsi_deny_cmd);
/* BSC subgroups */ /* BSC subgroups */
install_element(NAT_NODE, &cfg_bsc_cmd); install_element(NAT_NODE, &cfg_bsc_cmd);
@ -475,10 +516,9 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_default(BSC_NODE); install_default(BSC_NODE);
install_element(BSC_NODE, &cfg_bsc_token_cmd); install_element(BSC_NODE, &cfg_bsc_token_cmd);
install_element(BSC_NODE, &cfg_bsc_lac_cmd); install_element(BSC_NODE, &cfg_bsc_lac_cmd);
install_element(BSC_NODE, &cfg_bsc_imsi_allow_cmd);
install_element(BSC_NODE, &cfg_bsc_imsi_deny_cmd);
install_element(BSC_NODE, &cfg_bsc_paging_cmd); install_element(BSC_NODE, &cfg_bsc_paging_cmd);
install_element(BSC_NODE, &cfg_bsc_desc_cmd); install_element(BSC_NODE, &cfg_bsc_desc_cmd);
install_element(NAT_NODE, &cfg_bsc_acc_lst_name_cmd);
mgcp_vty_init(); mgcp_vty_init();

View File

@ -640,22 +640,28 @@ static void test_cr_filter()
int i, res, contype; int i, res, contype;
struct msgb *msg = msgb_alloc(4096, "test_cr_filter"); struct msgb *msg = msgb_alloc(4096, "test_cr_filter");
struct bsc_nat_parsed *parsed; struct bsc_nat_parsed *parsed;
struct bsc_nat_access_list *nat_lst, *bsc_lst;
struct bsc_nat *nat = bsc_nat_alloc(); struct bsc_nat *nat = bsc_nat_alloc();
struct bsc_connection *bsc = bsc_connection_alloc(nat); struct bsc_connection *bsc = bsc_connection_alloc(nat);
bsc->cfg = bsc_config_alloc(nat, "foo", 1234); bsc->cfg = bsc_config_alloc(nat, "foo", 1234);
bsc->cfg->acc_lst_name = "bsc";
nat->acc_lst_name = "nat";
for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) { for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) {
msgb_reset(msg); msgb_reset(msg);
copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length); copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length);
bsc_parse_reg(nat, &nat->imsi_deny_re, &nat->imsi_deny, nat_lst = bsc_nat_accs_list_get(nat, "nat");
bsc_lst = bsc_nat_accs_list_get(nat, "bsc");
bsc_parse_reg(nat_lst, &nat_lst->imsi_deny_re, &nat_lst->imsi_deny,
cr_filter[i].nat_imsi_deny ? 1 : 0, cr_filter[i].nat_imsi_deny ? 1 : 0,
&cr_filter[i].nat_imsi_deny); &cr_filter[i].nat_imsi_deny);
bsc_parse_reg(bsc->cfg, &bsc->cfg->imsi_allow_re, &bsc->cfg->imsi_allow, bsc_parse_reg(bsc_lst, &bsc_lst->imsi_allow_re, &bsc_lst->imsi_allow,
cr_filter[i].bsc_imsi_allow ? 1 : 0, cr_filter[i].bsc_imsi_allow ? 1 : 0,
&cr_filter[i].bsc_imsi_allow); &cr_filter[i].bsc_imsi_allow);
bsc_parse_reg(bsc->cfg, &bsc->cfg->imsi_deny_re, &bsc->cfg->imsi_deny, bsc_parse_reg(bsc_lst, &bsc_lst->imsi_deny_re, &bsc_lst->imsi_deny,
cr_filter[i].bsc_imsi_deny ? 1 : 0, cr_filter[i].bsc_imsi_deny ? 1 : 0,
&cr_filter[i].bsc_imsi_deny); &cr_filter[i].bsc_imsi_deny);