From df342ea82bdca152c7ebfab91857e4a508b37597 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 1 Jun 2010 01:03:13 +0800 Subject: [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). --- openbsc/include/openbsc/bsc_nat.h | 28 ++++++--- openbsc/src/nat/bsc_nat_utils.c | 53 +++++++++++++++-- openbsc/src/nat/bsc_nat_vty.c | 110 ++++++++++++++++++++++++----------- openbsc/tests/bsc-nat/bsc_nat_test.c | 12 +++- 4 files changed, 152 insertions(+), 51 deletions(-) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index f39afafb7..5d28e4c9d 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -165,10 +165,7 @@ struct bsc_config { char *description; /* imsi white and blacklist */ - char *imsi_allow; - regex_t imsi_allow_re; - char *imsi_deny; - regex_t imsi_deny_re; + char *acc_lst_name; int forbid_paging; @@ -207,6 +204,19 @@ struct bsc_nat_statistics { } 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 */ @@ -217,6 +227,9 @@ struct bsc_nat { /* active BSC connections that need patching */ struct llist_head bsc_connections; + /* access lists */ + struct llist_head access_lists; + /* known BSC's */ struct llist_head bsc_configs; int num_bsc; @@ -243,8 +256,7 @@ struct bsc_nat { struct bsc_endpoint *bsc_endpoints; /* filter */ - char *imsi_deny; - regex_t imsi_deny_re; + char *acc_lst_name; /* statistics */ 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); -/* regexp handling */ +/* IMSI allow/deny handling */ 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 diff --git a/openbsc/src/nat/bsc_nat_utils.c b/openbsc/src/nat/bsc_nat_utils.c index 5890c07cb..eeb3198e1 100644 --- a/openbsc/src/nat/bsc_nat_utils.c +++ b/openbsc/src/nat/bsc_nat_utils.c @@ -46,6 +46,8 @@ struct bsc_nat *bsc_nat_alloc(void) INIT_LLIST_HEAD(&nat->sccp_connections); INIT_LLIST_HEAD(&nat->bsc_connections); INIT_LLIST_HEAD(&nat->bsc_configs); + INIT_LLIST_HEAD(&nat->access_lists); + nat->stats.sccp.conn = counter_alloc("nat.sccp.conn"); nat->stats.sccp.calls = counter_alloc("nat.sccp.calls"); 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. * 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 */ - if (bsc->cfg->imsi_deny) { - if (regexec(&bsc->cfg->imsi_deny_re, mi_string, 0, NULL, 0) == 0) { + if (bsc_lst && bsc_lst->imsi_deny) { + if (regexec(&bsc_lst->imsi_deny_re, mi_string, 0, NULL, 0) == 0) { LOGP(DNAT, LOGL_ERROR, "Filtering %s by imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr); return -2; @@ -214,14 +222,14 @@ static int auth_imsi(struct bsc_connection *bsc, const char *mi_string) } /* 2. BSC allow */ - if (bsc->cfg->imsi_allow) { - if (regexec(&bsc->cfg->imsi_allow_re, mi_string, 0, NULL, 0) == 0) + if (bsc_lst && bsc_lst->imsi_allow) { + if (regexec(&bsc_lst->imsi_allow_re, mi_string, 0, NULL, 0) == 0) return 0; } /* 3. NAT deny */ - if (bsc->nat->imsi_deny) { - if (regexec(&bsc->nat->imsi_deny_re, mi_string, 0, NULL, 0) == 0) { + if (nat_lst && nat_lst->imsi_deny) { + if (regexec(&nat_lst->imsi_deny_re, mi_string, 0, NULL, 0) == 0) { LOGP(DNAT, LOGL_ERROR, "Filtering %s by nat imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr); return -3; @@ -403,3 +411,36 @@ const char *bsc_con_type_to_string(int 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; +} diff --git a/openbsc/src/nat/bsc_nat_vty.c b/openbsc/src/nat/bsc_nat_vty.c index cef47d1b3..e77a896a2 100644 --- a/openbsc/src/nat/bsc_nat_vty.c +++ b/openbsc/src/nat/bsc_nat_vty.c @@ -51,9 +51,9 @@ static struct cmd_node bsc_node = { static int config_write_nat(struct vty *vty) { + struct bsc_nat_access_list *lst; + 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 port %d%s", _nat->msc_port, 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) vty_out(vty, " token %s%s", _nat->token, 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; } @@ -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, " token %s%s", bsc->token, 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); if (bsc->description) 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) @@ -137,10 +147,9 @@ DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "show bsc config", llist_for_each_entry(conf, &_nat->bsc_configs, entry) { vty_out(vty, "BSC token: '%s' lac: %u nr: %u%s", conf->token, conf->lac, conf->nr, VTY_NEWLINE); - vty_out(vty, " imsi_allow: '%s' imsi_deny: '%s'%s", - conf->imsi_allow ? conf->imsi_allow: "any", - conf->imsi_deny ? conf->imsi_deny : "none", - VTY_NEWLINE); + if (conf->acc_lst_name) + vty_out(vty, " access-list: %s%s", + conf->acc_lst_name, VTY_NEWLINE); vty_out(vty, " paging forbidden: %d%s", conf->forbid_paging, VTY_NEWLINE); if (conf->description) @@ -233,16 +242,6 @@ DEFUN(cfg_nat, cfg_nat_cmd, "nat", "Configute the NAT") 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, cfg_nat_msc_ip_cmd, "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; } +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 */ 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; } -DEFUN(cfg_bsc_imsi_allow, - cfg_bsc_imsi_allow_cmd, - "imsi allow [REGEXP]", - "Allow IMSIs with the following network to talk to the MSC." - "The default is to allow everyone)") +DEFUN(cfg_lst_imsi_allow, + cfg_lst_imsi_allow_cmd, + "access-list NAME imsi-allow [REGEXP]", + "Allow IMSIs matching the REGEXP\n" + "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; - 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; } -DEFUN(cfg_bsc_imsi_deny, - cfg_bsc_imsi_deny_cmd, - "imsi deny [REGEXP]", - "Deny IMSIs with the following network to talk to the MSC." - "The default is to not deny anyone.)") +DEFUN(cfg_lst_imsi_deny, + cfg_lst_imsi_deny_cmd, + "access-list NAME imsi-deny [REGEXP]", + "Allow IMSIs matching the REGEXP\n" + "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; - bsc_parse_reg(conf, &conf->imsi_deny_re, &conf->imsi_deny, argc, argv); + 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; + + if (conf->acc_lst_name) + talloc_free(conf->acc_lst_name); + conf->acc_lst_name = talloc_strdup(conf, argv[0]); return CMD_SUCCESS; } @@ -460,7 +497,6 @@ int bsc_nat_vty_init(struct bsc_nat *nat) install_element(CONFIG_NODE, &cfg_nat_cmd); install_node(&nat_node, config_write_nat); 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_port_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_token_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 */ 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_element(BSC_NODE, &cfg_bsc_token_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_desc_cmd); + install_element(NAT_NODE, &cfg_bsc_acc_lst_name_cmd); mgcp_vty_init(); diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c index 8f3f358fc..d01700f83 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.c +++ b/openbsc/tests/bsc-nat/bsc_nat_test.c @@ -640,22 +640,28 @@ static void test_cr_filter() int i, res, contype; struct msgb *msg = msgb_alloc(4096, "test_cr_filter"); struct bsc_nat_parsed *parsed; + struct bsc_nat_access_list *nat_lst, *bsc_lst; struct bsc_nat *nat = bsc_nat_alloc(); struct bsc_connection *bsc = bsc_connection_alloc(nat); 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) { msgb_reset(msg); 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); - 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); - 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); -- cgit v1.2.3