From 299d5aa2a4edd54c9fb08c0343b8f685499439eb Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 8 Jun 2010 10:53:39 +0800 Subject: nat: Allow to specify multiple entries in the access-list... Inside the access-list we have a list of entries that have either one allow or one deny rule... we do not allow to remove a single rule but one has to remove the whole list, in that case talloc will handle cleaning all entries. Right now the matching is O(n*m) as we traverse the list (multiple times) and run the regexp multiple times. One way to make it faster would be to concat all regexps into one. --- openbsc/include/openbsc/bsc_nat.h | 7 +++++ openbsc/src/nat/bsc_nat_utils.c | 57 ++++++++++++++++++++++++++++++------ openbsc/src/nat/bsc_nat_vty.c | 35 +++++++++++++++++----- openbsc/tests/bsc-nat/bsc_nat_test.c | 13 ++++++-- 4 files changed, 92 insertions(+), 20 deletions(-) (limited to 'openbsc') diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index 43b66007b..cb0f76188 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -209,6 +209,11 @@ struct bsc_nat_acc_lst { /* the name of the list */ const char *name; + struct llist_head fltr_list; +}; + +struct bsc_nat_acc_lst_entry { + struct llist_head list; /* the filter */ char *imsi_allow; @@ -328,4 +333,6 @@ struct bsc_nat_acc_lst *bsc_nat_acc_lst_find(struct bsc_nat *nat, const char *na struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *name); void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst); +struct bsc_nat_acc_lst_entry *bsc_nat_acc_lst_entry_create(struct bsc_nat_acc_lst *); + #endif diff --git a/openbsc/src/nat/bsc_nat_utils.c b/openbsc/src/nat/bsc_nat_utils.c index 41796f713..335b0e374 100644 --- a/openbsc/src/nat/bsc_nat_utils.c +++ b/openbsc/src/nat/bsc_nat_utils.c @@ -195,6 +195,34 @@ int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto) return 0; } +static int lst_check_allow(struct bsc_nat_acc_lst *lst, const char *mi_string) +{ + struct bsc_nat_acc_lst_entry *entry; + + llist_for_each_entry(entry, &lst->fltr_list, list) { + if (!entry->imsi_allow) + continue; + if (regexec(&entry->imsi_allow_re, mi_string, 0, NULL, 0) == 0) + return 0; + } + + return 1; +} + +static int lst_check_deny(struct bsc_nat_acc_lst *lst, const char *mi_string) +{ + struct bsc_nat_acc_lst_entry *entry; + + llist_for_each_entry(entry, &lst->fltr_list, list) { + if (!entry->imsi_deny) + continue; + if (regexec(&entry->imsi_deny_re, mi_string, 0, NULL, 0) == 0) + return 0; + } + + return 1; +} + /* apply white/black list */ static int auth_imsi(struct bsc_connection *bsc, const char *mi_string) { @@ -212,24 +240,22 @@ static int auth_imsi(struct bsc_connection *bsc, const char *mi_string) nat_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->nat->acc_lst_name); - /* 1. BSC deny */ - if (bsc_lst && bsc_lst->imsi_deny) { - if (regexec(&bsc_lst->imsi_deny_re, mi_string, 0, NULL, 0) == 0) { + if (bsc_lst) { + /* 1. BSC deny */ + if (lst_check_deny(bsc_lst, mi_string) == 0) { LOGP(DNAT, LOGL_ERROR, "Filtering %s by imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr); return -2; } - } - /* 2. BSC allow */ - if (bsc_lst && bsc_lst->imsi_allow) { - if (regexec(&bsc_lst->imsi_allow_re, mi_string, 0, NULL, 0) == 0) + /* 2. BSC allow */ + if (lst_check_allow(bsc_lst, mi_string) == 0) return 0; } /* 3. NAT deny */ - if (nat_lst && nat_lst->imsi_deny) { - if (regexec(&nat_lst->imsi_deny_re, mi_string, 0, NULL, 0) == 0) { + if (nat_lst) { + if (lst_check_deny(nat_lst, mi_string) == 0) { LOGP(DNAT, LOGL_ERROR, "Filtering %s by nat imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr); return -3; @@ -440,6 +466,7 @@ struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *nam return NULL; } + INIT_LLIST_HEAD(&lst->fltr_list); lst->name = talloc_strdup(lst, name); llist_add(&lst->list, &nat->access_lists); return lst; @@ -450,3 +477,15 @@ void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst) llist_del(&lst->list); talloc_free(lst); } + +struct bsc_nat_acc_lst_entry *bsc_nat_acc_lst_entry_create(struct bsc_nat_acc_lst *lst) +{ + struct bsc_nat_acc_lst_entry *entry; + + entry = talloc_zero(lst, struct bsc_nat_acc_lst_entry); + if (!entry) + return NULL; + + llist_add(&entry->list, &lst->fltr_list); + return entry; +} diff --git a/openbsc/src/nat/bsc_nat_vty.c b/openbsc/src/nat/bsc_nat_vty.c index fdd7886e5..22375a87a 100644 --- a/openbsc/src/nat/bsc_nat_vty.c +++ b/openbsc/src/nat/bsc_nat_vty.c @@ -49,6 +49,20 @@ static struct cmd_node bsc_node = { 1, }; +static void write_acc_lst(struct vty *vty, struct bsc_nat_acc_lst *lst) +{ + struct bsc_nat_acc_lst_entry *entry; + + llist_for_each_entry(entry, &lst->fltr_list, list) { + if (entry->imsi_allow) + vty_out(vty, " access-list %s imsi-allow %s%s", + lst->name, entry->imsi_allow, VTY_NEWLINE); + if (entry->imsi_deny) + vty_out(vty, " access-list %s imsi-deny %s%s", + lst->name, entry->imsi_deny, VTY_NEWLINE); + } +} + static int config_write_nat(struct vty *vty) { struct bsc_nat_acc_lst *lst; @@ -66,12 +80,7 @@ static int config_write_nat(struct vty *vty) 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); + write_acc_lst(vty, lst); } return CMD_SUCCESS; @@ -387,12 +396,17 @@ DEFUN(cfg_lst_imsi_allow, "The regexp of allowed IMSIs\n") { struct bsc_nat_acc_lst *acc; + struct bsc_nat_acc_lst_entry *entry; acc = bsc_nat_acc_lst_get(_nat, argv[0]); if (!acc) return CMD_WARNING; - bsc_parse_reg(acc, &acc->imsi_allow_re, &acc->imsi_allow, argc - 1, &argv[1]); + entry = bsc_nat_acc_lst_entry_create(acc); + if (!entry) + return CMD_WARNING; + + bsc_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, argc - 1, &argv[1]); return CMD_SUCCESS; } @@ -404,12 +418,17 @@ DEFUN(cfg_lst_imsi_deny, "The regexp of to be denied IMSIs\n") { struct bsc_nat_acc_lst *acc; + struct bsc_nat_acc_lst_entry *entry; acc = bsc_nat_acc_lst_get(_nat, argv[0]); if (!acc) return CMD_WARNING; - bsc_parse_reg(acc, &acc->imsi_deny_re, &acc->imsi_deny, argc - 1, &argv[1]); + entry = bsc_nat_acc_lst_entry_create(acc); + if (!entry) + return CMD_WARNING; + + bsc_parse_reg(acc, &entry->imsi_deny_re, &entry->imsi_deny, argc - 1, &argv[1]); return CMD_SUCCESS; } diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c index dfb77bfdb..0c5b8fd51 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.c +++ b/openbsc/tests/bsc-nat/bsc_nat_test.c @@ -641,6 +641,7 @@ static void test_cr_filter() struct msgb *msg = msgb_alloc(4096, "test_cr_filter"); struct bsc_nat_parsed *parsed; struct bsc_nat_acc_lst *nat_lst, *bsc_lst; + struct bsc_nat_acc_lst_entry *nat_entry, *bsc_entry; struct bsc_nat *nat = bsc_nat_alloc(); struct bsc_connection *bsc = bsc_connection_alloc(nat); @@ -648,6 +649,12 @@ static void test_cr_filter() bsc->cfg->acc_lst_name = "bsc"; nat->acc_lst_name = "nat"; + nat_lst = bsc_nat_acc_lst_get(nat, "nat"); + bsc_lst = bsc_nat_acc_lst_get(nat, "bsc"); + + bsc_entry = bsc_nat_acc_lst_entry_create(bsc_lst); + nat_entry = bsc_nat_acc_lst_entry_create(nat_lst); + for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) { msgb_reset(msg); copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length); @@ -655,13 +662,13 @@ static void test_cr_filter() nat_lst = bsc_nat_acc_lst_get(nat, "nat"); bsc_lst = bsc_nat_acc_lst_get(nat, "bsc"); - bsc_parse_reg(nat_lst, &nat_lst->imsi_deny_re, &nat_lst->imsi_deny, + bsc_parse_reg(nat_entry, &nat_entry->imsi_deny_re, &nat_entry->imsi_deny, cr_filter[i].nat_imsi_deny ? 1 : 0, &cr_filter[i].nat_imsi_deny); - bsc_parse_reg(bsc_lst, &bsc_lst->imsi_allow_re, &bsc_lst->imsi_allow, + bsc_parse_reg(bsc_entry, &bsc_entry->imsi_allow_re, &bsc_entry->imsi_allow, cr_filter[i].bsc_imsi_allow ? 1 : 0, &cr_filter[i].bsc_imsi_allow); - bsc_parse_reg(bsc_lst, &bsc_lst->imsi_deny_re, &bsc_lst->imsi_deny, + bsc_parse_reg(bsc_entry, &bsc_entry->imsi_deny_re, &bsc_entry->imsi_deny, cr_filter[i].bsc_imsi_deny ? 1 : 0, &cr_filter[i].bsc_imsi_deny); -- cgit v1.2.3