diff options
author | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2015-05-03 22:34:01 +0200 |
---|---|---|
committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2015-05-03 22:34:16 +0200 |
commit | 337343d159888886eaa68476b70dbe19db93845b (patch) | |
tree | 318a8135477e0dcc8f8e24d2380342c254ab9d60 | |
parent | 38159428d2b1e95a2c6fa91775f7b3678aef2f1f (diff) | |
parent | d26b8fcbe22eb4a56c87f0114a0e826551243511 (diff) |
Merge branch 'zecke/features/acc-list'
Integrate the change and see how it is going. The unit tests
for the NAT look good so we might not have regressions.
28 files changed, 1098 insertions, 713 deletions
diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 00d1b70c9..394972f46 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -179,6 +179,7 @@ AC_OUTPUT( src/libmsc/Makefile src/libmgcp/Makefile src/libcommon/Makefile + src/libfilter/Makefile src/osmo-nitb/Makefile src/osmo-bsc/Makefile src/osmo-bsc_nat/Makefile diff --git a/openbsc/doc/examples/osmo-bsc/osmo-bsc.cfg b/openbsc/doc/examples/osmo-bsc/osmo-bsc.cfg index d7461964f..fd4c3d726 100644 --- a/openbsc/doc/examples/osmo-bsc/osmo-bsc.cfg +++ b/openbsc/doc/examples/osmo-bsc/osmo-bsc.cfg @@ -98,3 +98,8 @@ msc timeout-ping 20 timeout-pong 5 dest 192.168.100.11 6666 0 + access-list-name msc-list + no access-list-name +bsc + no access-list-name + access-list-name bsc-list diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index d2b30de79..254f43dbe 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -16,7 +16,7 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \ arfcn_range_encode.h nat_rewrite_trie.h bsc_nat_callstats.h \ osmux.h mgcp_transcode.h gprs_utils.h \ gprs_gb_parse.h smpp.h meas_feed.h gprs_gsup_messages.h \ - gprs_gsup_client.h + gprs_gsup_client.h bsc_msg_filter.h openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h openbscdir = $(includedir)/openbsc diff --git a/openbsc/include/openbsc/bsc_msg_filter.h b/openbsc/include/openbsc/bsc_msg_filter.h new file mode 100644 index 000000000..a9dedf43c --- /dev/null +++ b/openbsc/include/openbsc/bsc_msg_filter.h @@ -0,0 +1,107 @@ +#pragma once + +#include <osmocom/core/msgb.h> +#include <osmocom/core/msgfile.h> +#include <osmocom/core/linuxrbtree.h> +#include <osmocom/core/linuxlist.h> + +#include <regex.h> + +struct vty; +struct gsm48_hdr; + +struct bsc_filter_reject_cause { + int lu_reject_cause; + int cm_reject_cause; +}; + +struct bsc_filter_barr_entry { + struct rb_node node; + + char *imsi; + int cm_reject_cause; + int lu_reject_cause; +}; + +enum bsc_filter_acc_ctr { + ACC_LIST_LOCAL_FILTER, + ACC_LIST_GLOBAL_FILTER, +}; + +struct bsc_msg_acc_lst { + struct llist_head list; + + /* counter */ + struct rate_ctr_group *stats; + + /* the name of the list */ + const char *name; + struct llist_head fltr_list; +}; + +struct bsc_msg_acc_lst_entry { + struct llist_head list; + + /* the filter */ + char *imsi_allow; + regex_t imsi_allow_re; + char *imsi_deny; + regex_t imsi_deny_re; + + /* reject reasons for the access lists */ + int cm_reject_cause; + int lu_reject_cause; +}; + +enum { + FLT_CON_TYPE_NONE, + FLT_CON_TYPE_LU, + FLT_CON_TYPE_CM_SERV_REQ, + FLT_CON_TYPE_PAG_RESP, + FLT_CON_TYPE_SSA, + FLT_CON_TYPE_LOCAL_REJECT, + FLT_CON_TYPE_OTHER, +}; + + +struct bsc_filter_state { + char *imsi; + int imsi_checked; + int con_type; +}; + +struct bsc_filter_request { + void *ctx; + struct rb_root *black_list; + struct llist_head *access_lists; + const char *local_lst_name; + const char *global_lst_name; + int bsc_nr; +}; + + +int bsc_filter_barr_adapt(void *ctx, struct rb_root *rbtree, const struct osmo_config_list *); +int bsc_filter_barr_find(struct rb_root *root, const char *imsi, int *cm, int *lu); + +/** + * Content filtering. + */ +int bsc_msg_filter_initial(struct gsm48_hdr *hdr, size_t size, + struct bsc_filter_request *req, + int *con_type, char **imsi, + struct bsc_filter_reject_cause *cause); +int bsc_msg_filter_data(struct gsm48_hdr *hdr, size_t size, + struct bsc_filter_request *req, + struct bsc_filter_state *state, + struct bsc_filter_reject_cause *cause); + +/* IMSI allow/deny handling */ +struct bsc_msg_acc_lst *bsc_msg_acc_lst_find(struct llist_head *lst, const char *name); +struct bsc_msg_acc_lst *bsc_msg_acc_lst_get(void *ctx, struct llist_head *lst, const char *name); +void bsc_msg_acc_lst_delete(struct bsc_msg_acc_lst *lst); + +struct bsc_msg_acc_lst_entry *bsc_msg_acc_lst_entry_create(struct bsc_msg_acc_lst *); +int bsc_msg_acc_lst_check_allow(struct bsc_msg_acc_lst *lst, const char *imsi); + +void bsc_msg_lst_vty_init(void *ctx, struct llist_head *lst, int node); +void bsc_msg_acc_lst_write(struct vty *vty, struct bsc_msg_acc_lst *lst); diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index 19144e3dd..ae940b390 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -22,6 +22,7 @@ #define BSC_NAT_H #include "mgcp.h" +#include "bsc_msg_filter.h" #include <osmocom/core/select.h> @@ -47,16 +48,6 @@ struct bsc_nat; struct bsc_nat_ussd_con; struct nat_rewrite_rule; -enum { - NAT_CON_TYPE_NONE, - NAT_CON_TYPE_LU, - NAT_CON_TYPE_CM_SERV_REQ, - NAT_CON_TYPE_PAG_RESP, - NAT_CON_TYPE_SSA, - NAT_CON_TYPE_LOCAL_REJECT, - NAT_CON_TYPE_OTHER, -}; - /* * Is this terminated to the MSC, to the local machine (release * handling for IMSI filtering) or to a USSD provider? @@ -229,36 +220,6 @@ struct bsc_nat_statistics { } ussd; }; -enum bsc_nat_acc_ctr { - ACC_LIST_BSC_FILTER, - ACC_LIST_NAT_FILTER, -}; - -struct bsc_nat_acc_lst { - struct llist_head list; - - /* counter */ - struct rate_ctr_group *stats; - - /* 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; - regex_t imsi_allow_re; - char *imsi_deny; - regex_t imsi_deny_re; - - /* reject reasons for the access lists */ - int cm_reject_cause; - int lu_reject_cause; -}; - /** * the structure of the "nat" network */ @@ -355,11 +316,6 @@ struct bsc_nat_ussd_con { struct osmo_timer_list auth_timeout; }; -struct bsc_nat_reject_cause { - int lu_reject_cause; - int cm_reject_cause; -}; - /* create and init the structures */ struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token); struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num); @@ -390,16 +346,6 @@ int bsc_nat_vty_init(struct bsc_nat *nat); int bsc_nat_find_paging(struct msgb *msg, const uint8_t **,int *len); /** - * Content filtering. - */ -int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, - struct bsc_nat_parsed *, int *con_type, char **imsi, - struct bsc_nat_reject_cause *cause); -int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg, - struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, - struct bsc_nat_reject_cause *cause); - -/** * SCCP patching and handling */ struct nat_sccp_connection *create_sccp_src_ref(struct bsc_connection *bsc, struct bsc_nat_parsed *parsed); @@ -435,14 +381,6 @@ int bsc_do_write(struct osmo_wqueue *queue, struct msgb *msg, int id); int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg); int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg); -/* IMSI allow/deny handling */ -struct bsc_nat_acc_lst *bsc_nat_acc_lst_find(struct bsc_nat *nat, const char *name); -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 *); -int bsc_nat_lst_check_allow(struct bsc_nat_acc_lst *lst, const char *imsi); - int bsc_nat_msc_is_connected(struct bsc_nat *nat); int bsc_conn_type_to_ctr(struct nat_sccp_connection *conn); @@ -478,17 +416,6 @@ 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); - void bsc_nat_send_mgcp_to_msc(struct bsc_nat *bsc_nat, struct msgb *msg); void bsc_nat_handle_mgcp(struct bsc_nat *bsc, struct msgb *msg); @@ -499,6 +426,13 @@ int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg); int bsc_nat_extract_lac(struct bsc_connection *bsc, struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, struct msgb *msg); +int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, + struct bsc_nat_parsed *, int *con_type, char **imsi, + struct bsc_filter_reject_cause *cause); +int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg, + struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, + struct bsc_filter_reject_cause *cause); + /** * CTRL interface helper */ diff --git a/openbsc/include/openbsc/bsc_nat_sccp.h b/openbsc/include/openbsc/bsc_nat_sccp.h index 0561df1f4..082466408 100644 --- a/openbsc/include/openbsc/bsc_nat_sccp.h +++ b/openbsc/include/openbsc/bsc_nat_sccp.h @@ -22,6 +22,8 @@ #ifndef BSC_NAT_SCCP_H #define BSC_NAT_SCCP_H +#include "bsc_msg_filter.h" + #include <osmocom/sccp/sccp_types.h> /* @@ -77,11 +79,10 @@ struct nat_sccp_connection { int has_remote_ref; /* status */ - int con_type; int con_local; int authorized; - int imsi_checked; - char *imsi; + + struct bsc_filter_state filter_state; uint16_t lac; uint16_t ci; diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index bbb3ee618..19d8fc2de 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -32,6 +32,7 @@ enum { DNAT, DCTRL, DSMPP, + DFILTER, Debug_LastEntry, }; diff --git a/openbsc/include/openbsc/osmo_bsc.h b/openbsc/include/openbsc/osmo_bsc.h index 19b879f56..fd5303dc6 100644 --- a/openbsc/include/openbsc/osmo_bsc.h +++ b/openbsc/include/openbsc/osmo_bsc.h @@ -4,6 +4,7 @@ #define OSMO_BSC_H #include "bsc_api.h" +#include "bsc_msg_filter.h" #define BSS_SEND_USSD 1 @@ -41,6 +42,8 @@ struct osmo_bsc_sccp_con { struct gsm_subscriber_connection *conn; uint8_t new_subscriber; + + struct bsc_filter_state filter_state; }; struct bsc_api *osmo_bsc_api(); @@ -63,4 +66,6 @@ int bsc_ctrl_cmds_install(); void bsc_gen_location_state_trap(struct gsm_bts *bts); +struct llist_head *bsc_access_lists(void); + #endif diff --git a/openbsc/include/openbsc/osmo_msc_data.h b/openbsc/include/openbsc/osmo_msc_data.h index bdc762aaf..2d863aa32 100644 --- a/openbsc/include/openbsc/osmo_msc_data.h +++ b/openbsc/include/openbsc/osmo_msc_data.h @@ -92,6 +92,8 @@ struct osmo_msc_data { /* ussd text when MSC has entered the grace period */ char *ussd_grace_txt; + + char *acc_lst_name; }; /* @@ -112,6 +114,8 @@ struct osmo_bsc_data { /* ussd text when there is no MSC available */ char *ussd_no_msc_txt; + + char *acc_lst_name; }; diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am index db7603b89..6f6174eb1 100644 --- a/openbsc/src/Makefile.am +++ b/openbsc/src/Makefile.am @@ -2,7 +2,7 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS) -SUBDIRS = libcommon libmgcp libbsc libmsc libtrau osmo-nitb osmo-bsc_mgcp utils ipaccess gprs +SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs # Conditional modules if BUILD_NAT diff --git a/openbsc/src/libcommon/debug.c b/openbsc/src/libcommon/debug.c index ca7ff5da6..7fb3ecb67 100644 --- a/openbsc/src/libcommon/debug.c +++ b/openbsc/src/libcommon/debug.c @@ -160,6 +160,11 @@ static const struct log_info_cat default_categories[] = { .description = "SMPP interface for external SMS apps", .enabled = 1, .loglevel = LOGL_DEBUG, }, + [DFILTER] = { + .name = "DFILTER", + .description = "BSC/NAT IMSI based filtering", + .enabled = 1, .loglevel = LOGL_DEBUG, + }, }; enum log_filter { diff --git a/openbsc/src/libfilter/Makefile.am b/openbsc/src/libfilter/Makefile.am new file mode 100644 index 000000000..4dbc59041 --- /dev/null +++ b/openbsc/src/libfilter/Makefile.am @@ -0,0 +1,11 @@ +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) \ + $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) + +noinst_LIBRARIES = libfilter.a + +libfilter_a_SOURCES = \ + bsc_msg_filter.c \ + bsc_msg_acc.c \ + bsc_msg_vty.c + diff --git a/openbsc/src/libfilter/bsc_msg_acc.c b/openbsc/src/libfilter/bsc_msg_acc.c new file mode 100644 index 000000000..6258b3577 --- /dev/null +++ b/openbsc/src/libfilter/bsc_msg_acc.c @@ -0,0 +1,116 @@ +/* + * (C) 2010-2015 by Holger Hans Peter Freyther <zecke@selfish.org> + * (C) 2010-2011 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <openbsc/bsc_msg_filter.h> +#include <openbsc/bsc_nat.h> + +#include <osmocom/core/rate_ctr.h> + +#include <string.h> + +static const struct rate_ctr_desc acc_list_ctr_description[] = { + [ACC_LIST_LOCAL_FILTER] = { "access-list.local-filter", "Rejected by rule for local"}, + [ACC_LIST_GLOBAL_FILTER]= { "access-list.global-filter", "Rejected by rule for global"}, +}; + +static const struct rate_ctr_group_desc bsc_cfg_acc_list_desc = { + .group_name_prefix = "nat.filter", + .group_description = "NAT Access-List Statistics", + .num_ctr = ARRAY_SIZE(acc_list_ctr_description), + .ctr_desc = acc_list_ctr_description, +}; + + +int bsc_msg_acc_lst_check_allow(struct bsc_msg_acc_lst *lst, const char *mi_string) +{ + struct bsc_msg_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; +} + +struct bsc_msg_acc_lst *bsc_msg_acc_lst_find(struct llist_head *head, const char *name) +{ + struct bsc_msg_acc_lst *lst; + + if (!name) + return NULL; + + llist_for_each_entry(lst, head, list) + if (strcmp(lst->name, name) == 0) + return lst; + + return NULL; +} + +struct bsc_msg_acc_lst *bsc_msg_acc_lst_get(void *ctx, struct llist_head *head, const char *name) +{ + struct bsc_msg_acc_lst *lst; + + lst = bsc_msg_acc_lst_find(head, name); + if (lst) + return lst; + + lst = talloc_zero(ctx, struct bsc_msg_acc_lst); + if (!lst) { + LOGP(DNAT, LOGL_ERROR, "Failed to allocate access list"); + return NULL; + } + + /* TODO: get the index right */ + lst->stats = rate_ctr_group_alloc(lst, &bsc_cfg_acc_list_desc, 0); + if (!lst->stats) { + talloc_free(lst); + return NULL; + } + + INIT_LLIST_HEAD(&lst->fltr_list); + lst->name = talloc_strdup(lst, name); + llist_add_tail(&lst->list, head); + return lst; +} + +void bsc_msg_acc_lst_delete(struct bsc_msg_acc_lst *lst) +{ + llist_del(&lst->list); + rate_ctr_group_free(lst->stats); + talloc_free(lst); +} + +struct bsc_msg_acc_lst_entry *bsc_msg_acc_lst_entry_create(struct bsc_msg_acc_lst *lst) +{ + struct bsc_msg_acc_lst_entry *entry; + + entry = talloc_zero(lst, struct bsc_msg_acc_lst_entry); + if (!entry) + return NULL; + + entry->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; + entry->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; + llist_add_tail(&entry->list, &lst->fltr_list); + return entry; +} + diff --git a/openbsc/src/libfilter/bsc_msg_filter.c b/openbsc/src/libfilter/bsc_msg_filter.c new file mode 100644 index 000000000..be518a478 --- /dev/null +++ b/openbsc/src/libfilter/bsc_msg_filter.c @@ -0,0 +1,401 @@ +/* + * Access filtering + */ +/* + * (C) 2010-2015 by Holger Hans Peter Freyther <zecke@selfish.org> + * (C) 2010-2012 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <openbsc/bsc_msg_filter.h> + +#include <openbsc/bsc_nat.h> +#include <openbsc/bsc_nat_sccp.h> +#include <openbsc/bsc_msc.h> +#include <openbsc/gsm_data.h> +#include <openbsc/debug.h> +#include <openbsc/ipaccess.h> + +#include <osmocom/core/talloc.h> +#include <osmocom/gsm/gsm0808.h> + +#include <osmocom/gsm/protocol/gsm_08_08.h> +#include <osmocom/gsm/protocol/gsm_04_11.h> + +#include <osmocom/sccp/sccp.h> + +int bsc_filter_barr_find(struct rb_root *root, const char *imsi, int *cm, int *lu) +{ + struct bsc_filter_barr_entry *n; + n = rb_entry(root->rb_node, struct bsc_filter_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_filter_barr_entry, node); + }; + + return 0; +} + +static int insert_barr_node(struct bsc_filter_barr_entry *entry, struct rb_root *root) +{ + struct rb_node **new = &root->rb_node, *parent = NULL; + + while (*new) { + int rc; + struct bsc_filter_barr_entry *this; + this = rb_entry(*new, struct bsc_filter_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(DFILTER, 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_filter_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_filter_barr_entry *entry; + entry = talloc_zero(ctx, struct bsc_filter_barr_entry); + if (!entry) { + LOGP(DFILTER, 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_msg_acc_lst *lst, const char *mi_string, + int *cm_cause, int *lu_cause) +{ + struct bsc_msg_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) { + *cm_cause = entry->cm_reject_cause; + *lu_cause = entry->lu_reject_cause; + return 0; + } + } + + return 1; +} + +/* apply white/black list */ +static int auth_imsi(struct bsc_filter_request *req, + const char *imsi, + struct bsc_filter_reject_cause *cause) +{ + /* + * Now apply blacklist/whitelist of the BSC and the NAT. + * 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_msg_acc_lst *nat_lst = NULL; + struct bsc_msg_acc_lst *bsc_lst = NULL; + + /* 1. global check for barred imsis */ + if (req->black_list && bsc_filter_barr_find(req->black_list, imsi, &cm, &lu)) { + cause->cm_reject_cause = cm; + cause->lu_reject_cause = lu; + LOGP(DFILTER, LOGL_DEBUG, + "Blocking subscriber IMSI %s with CM: %d LU: %d\n", + imsi, cm, lu); + return -4; + } + + + bsc_lst = bsc_msg_acc_lst_find(req->access_lists, req->local_lst_name); + nat_lst = bsc_msg_acc_lst_find(req->access_lists, req->global_lst_name); + + + if (bsc_lst) { + /* 2. BSC allow */ + if (bsc_msg_acc_lst_check_allow(bsc_lst, imsi) == 0) + return 1; + + /* 3. BSC deny */ + if (lst_check_deny(bsc_lst, imsi, &cm, &lu) == 0) { + LOGP(DFILTER, LOGL_ERROR, + "Filtering %s by imsi_deny on config nr: %d.\n", imsi, req->bsc_nr); + rate_ctr_inc(&bsc_lst->stats->ctr[ACC_LIST_LOCAL_FILTER]); + cause->cm_reject_cause = cm; + cause->lu_reject_cause = lu; + return -2; + } + + } + + /* 4. NAT deny */ + if (nat_lst) { + if (lst_check_deny(nat_lst, imsi, &cm, &lu) == 0) { + LOGP(DFILTER, LOGL_ERROR, + "Filtering %s global imsi_deny on bsc nr: %d.\n", imsi, req->bsc_nr); + rate_ctr_inc(&nat_lst->stats->ctr[ACC_LIST_GLOBAL_FILTER]); + cause->cm_reject_cause = cm; + cause->lu_reject_cause = lu; + return -3; + } + } + + return 1; +} + +static int _cr_check_loc_upd(void *ctx, + uint8_t *data, unsigned int length, + char **imsi) +{ + uint8_t mi_type; + struct gsm48_loc_upd_req *lu; + char mi_string[GSM48_MI_SIZE]; + + if (length < sizeof(*lu)) { + LOGP(DFILTER, LOGL_ERROR, + "LU does not fit. Length is %d \n", length); + return -1; + } + + lu = (struct gsm48_loc_upd_req *) data; + mi_type = lu->mi[0] & GSM_MI_TYPE_MASK; + + /* + * We can only deal with the IMSI. This will fail for a phone that + * will send the TMSI of a previous network to us. + */ + if (mi_type != GSM_MI_TYPE_IMSI) + return 0; + + gsm48_mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len); + *imsi = talloc_strdup(ctx, mi_string); + return 1; +} + +static int _cr_check_cm_serv_req(void *ctx, + uint8_t *data, unsigned int length, + int *con_type, char **imsi) +{ + static const uint32_t classmark_offset = + offsetof(struct gsm48_service_request, classmark); + + char mi_string[GSM48_MI_SIZE]; + uint8_t mi_type; + int rc; + struct gsm48_service_request *req; + + /* unfortunately in Phase1 the classmark2 length is variable */ + + if (length < sizeof(*req)) { + LOGP(DFILTER, LOGL_ERROR, + "CM Serv Req does not fit. Length is %d\n", length); + return -1; + } + + req = (struct gsm48_service_request *) data; + if (req->cm_service_type == 0x8) + *con_type = FLT_CON_TYPE_SSA; + rc = gsm48_extract_mi((uint8_t *) &req->classmark, + length - classmark_offset, mi_string, &mi_type); + if (rc < 0) { + LOGP(DFILTER, LOGL_ERROR, "Failed to parse the classmark2/mi. error: %d\n", rc); + return -1; + } + + /* we have to let the TMSI or such pass */ + if (mi_type != GSM_MI_TYPE_IMSI) + return 0; + + *imsi = talloc_strdup(ctx, mi_string); + return 1; +} + +static int _cr_check_pag_resp(void *ctx, + uint8_t *data, unsigned int length, char **imsi) +{ + struct gsm48_pag_resp *resp; + char mi_string[GSM48_MI_SIZE]; + uint8_t mi_type; + + if (length < sizeof(*resp)) { + LOGP(DFILTER, LOGL_ERROR, "PAG RESP does not fit. Length was %d.\n", length); + return -1; + } + + resp = (struct gsm48_pag_resp *) data; + if (gsm48_paging_extract_mi(resp, length, mi_string, &mi_type) < 0) { + LOGP(DFILTER, LOGL_ERROR, "Failed to extract the MI.\n"); + return -1; + } + + /* we need to let it pass for now */ + if (mi_type != GSM_MI_TYPE_IMSI) + return 0; + + *imsi = talloc_strdup(ctx, mi_string); + return 1; +} + +static int _dt_check_id_resp(struct bsc_filter_request *req, + uint8_t *data, unsigned int length, + struct bsc_filter_state *state, + struct bsc_filter_reject_cause *cause) +{ + char mi_string[GSM48_MI_SIZE]; + uint8_t mi_type; + + if (length < 2) { + LOGP(DFILTER, LOGL_ERROR, "mi does not fit.\n"); + return -1; + } + + if (data[0] < length - 1) { + LOGP(DFILTER, LOGL_ERROR, "mi length too big.\n"); + return -2; + } + + mi_type = data[1] & GSM_MI_TYPE_MASK; + gsm48_mi_to_string(mi_string, sizeof(mi_string), &data[1], data[0]); + + if (mi_type != GSM_MI_TYPE_IMSI) + return 0; + + state->imsi_checked = 1; + state->imsi = talloc_strdup(req->ctx, mi_string); + return auth_imsi(req, mi_string, cause); +} + + +/* Filter out CR data... */ +int bsc_msg_filter_initial(struct gsm48_hdr *hdr48, size_t hdr48_len, + struct bsc_filter_request *req, + int *con_type, + char **imsi, struct bsc_filter_reject_cause *cause) +{ + int ret = 0; + uint8_t msg_type, proto; + + *con_type = FLT_CON_TYPE_NONE; + cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; + cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; + *imsi = NULL; + + proto = hdr48->proto_discr & 0x0f; + msg_type = hdr48->msg_type & 0xbf; + if (proto == GSM48_PDISC_MM && + msg_type == GSM48_MT_MM_LOC_UPD_REQUEST) { + *con_type = FLT_CON_TYPE_LU; + ret = _cr_check_loc_upd(req->ctx, &hdr48->data[0], + hdr48_len - sizeof(*hdr48), imsi); + } else if (proto == GSM48_PDISC_MM && + msg_type == GSM48_MT_MM_CM_SERV_REQ) { + *con_type = FLT_CON_TYPE_CM_SERV_REQ; + ret = _cr_check_cm_serv_req(req->ctx, &hdr48->data[0], + hdr48_len - sizeof(*hdr48), + con_type, imsi); + } else if (proto == GSM48_PDISC_RR && + msg_type == GSM48_MT_RR_PAG_RESP) { + *con_type = FLT_CON_TYPE_PAG_RESP; + ret = _cr_check_pag_resp(req->ctx, &hdr48->data[0], + hdr48_len - sizeof(*hdr48), imsi); + } else { + /* We only want to filter the above, let other things pass */ + *con_type = FLT_CON_TYPE_OTHER; + return 0; + } + + /* check if we are done */ + if (ret != 1) + return ret; + + /* the memory allocation failed */ + if (!*imsi) + return -1; + + /* now check the imsi */ + return auth_imsi(req, *imsi, cause); +} + +int bsc_msg_filter_data(struct gsm48_hdr *hdr48, size_t len, + struct bsc_filter_request *req, + struct bsc_filter_state *state, + struct bsc_filter_reject_cause *cause) +{ + uint8_t msg_type, proto; + + cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; + cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; + + if (state->imsi_checked) + return 0; + + proto = hdr48->proto_discr & 0x0f; + msg_type = hdr48->msg_type & 0xbf; + if (proto != GSM48_PDISC_MM || msg_type != GSM48_MT_MM_ID_RESP) + return 0; + + return _dt_check_id_resp(req, &hdr48->data[0], + len - sizeof(*hdr48), state, cause); +} diff --git a/openbsc/src/libfilter/bsc_msg_vty.c b/openbsc/src/libfilter/bsc_msg_vty.c new file mode 100644 index 000000000..c342fdca0 --- /dev/null +++ b/openbsc/src/libfilter/bsc_msg_vty.c @@ -0,0 +1,140 @@ +/* (C) 2010-2015 by Holger Hans Peter Freyther + * (C) 2010-2013 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <openbsc/bsc_msg_filter.h> +#include <openbsc/gsm_data.h> +#include <openbsc/vty.h> + +#include <osmocom/vty/misc.h> + +static struct llist_head *_acc_lst; +static void *_ctx; + +DEFUN(cfg_lst_no, + cfg_lst_no_cmd, + "no access-list NAME", + NO_STR "Remove an access-list by name\n" + "The access-list to remove\n") +{ + struct bsc_msg_acc_lst *acc; + acc = bsc_msg_acc_lst_find(_acc_lst, argv[0]); + if (!acc) + return CMD_WARNING; + + bsc_msg_acc_lst_delete(acc); + return CMD_SUCCESS; +} + +DEFUN(show_acc_lst, + show_acc_lst_cmd, + "show access-list NAME", + SHOW_STR "IMSI access list\n" "Name of the access list\n") +{ + struct bsc_msg_acc_lst *acc; + acc = bsc_msg_acc_lst_find(_acc_lst, argv[0]); + if (!acc) + return CMD_WARNING; + + vty_out(vty, "access-list %s%s", acc->name, VTY_NEWLINE); + vty_out_rate_ctr_group(vty, " ", acc->stats); + + return CMD_SUCCESS; +} + +DEFUN(cfg_lst_imsi_allow, + cfg_lst_imsi_allow_cmd, + "access-list NAME imsi-allow [REGEXP]", + "Access list commands\n" + "Name of the access list\n" + "Add allowed IMSI to the list\n" + "Regexp for IMSIs\n") +{ + struct bsc_msg_acc_lst *acc; + struct bsc_msg_acc_lst_entry *entry; + + acc = bsc_msg_acc_lst_get(_ctx, _acc_lst, argv[0]); + if (!acc) + return CMD_WARNING; + + entry = bsc_msg_acc_lst_entry_create(acc); + if (!entry) + return CMD_WARNING; + + if (gsm_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, argc - 1, &argv[1]) != 0) + return CMD_WARNING; + return CMD_SUCCESS; +} + +DEFUN(cfg_lst_imsi_deny, + cfg_lst_imsi_deny_cmd, + "access-list NAME imsi-deny [REGEXP] (<0-256>) (<0-256>)", + "Access list commands\n" + "Name of the access list\n" + "Add denied IMSI to the list\n" + "Regexp for IMSIs\n" + "CM Service Reject reason\n" + "LU Reject reason\n") +{ + struct bsc_msg_acc_lst *acc; + struct bsc_msg_acc_lst_entry *entry; + + acc = bsc_msg_acc_lst_get(_ctx, _acc_lst, argv[0]); + if (!acc) + return CMD_WARNING; + + entry = bsc_msg_acc_lst_entry_create(acc); + if (!entry) + return CMD_WARNING; + + if (gsm_parse_reg(acc, &entry->imsi_deny_re, &entry->imsi_deny, argc - 1, &argv[1]) != 0) + return CMD_WARNING; + if (argc >= 3) + entry->cm_reject_cause = atoi(argv[2]); + if (argc >= 4) + entry->lu_reject_cause = atoi(argv[3]); + return CMD_SUCCESS; +} + +void bsc_msg_acc_lst_write(struct vty *vty, struct bsc_msg_acc_lst *lst) +{ + struct bsc_msg_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 %d %d%s", + lst->name, entry->imsi_deny, + entry->cm_reject_cause, entry->lu_reject_cause, + VTY_NEWLINE); + } +} + +void bsc_msg_lst_vty_init(void *ctx, struct llist_head *lst, int node) +{ + _ctx = ctx; + _acc_lst = lst; + install_element_ve(&show_acc_lst_cmd); + + /* access-list */ + install_element(node, &cfg_lst_imsi_allow_cmd); + install_element(node, &cfg_lst_imsi_deny_cmd); + install_element(node, &cfg_lst_no_cmd); +} diff --git a/openbsc/src/osmo-bsc/Makefile.am b/openbsc/src/osmo-bsc/Makefile.am index 6248fcd6f..b4a2cba64 100644 --- a/openbsc/src/osmo-bsc/Makefile.am +++ b/openbsc/src/osmo-bsc/Makefile.am @@ -9,7 +9,9 @@ osmo_bsc_SOURCES = osmo_bsc_main.c osmo_bsc_vty.c osmo_bsc_api.c \ osmo_bsc_grace.c osmo_bsc_msc.c osmo_bsc_sccp.c \ osmo_bsc_filter.c osmo_bsc_bssap.c osmo_bsc_audio.c osmo_bsc_ctrl.c # once again since TRAU uses CC symbol :( -osmo_bsc_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ +osmo_bsc_LDADD = \ + $(top_builddir)/src/libfilter/libfilter.a \ + $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libmsc/libmsc.a \ $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libtrau/libtrau.a \ diff --git a/openbsc/src/osmo-bsc/osmo_bsc_api.c b/openbsc/src/osmo-bsc/osmo_bsc_api.c index 18b9607a0..5a01d6b82 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_api.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_api.c @@ -1,4 +1,4 @@ -/* (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org> +/* (C) 2009-2015 by Holger Hans Peter Freyther <zecke@selfish.org> * (C) 2009-2011 by On-Waves * All Rights Reserved * @@ -79,6 +79,69 @@ static uint16_t get_ci_for_msc(struct osmo_msc_data *msc, struct gsm_bts *bts) return bts->cell_identity; } +static void bsc_maybe_lu_reject(struct gsm_subscriber_connection *conn, int con_type, int cause) +{ + struct msgb *msg; + + /* ignore cm service request or such */ + if (con_type != FLT_CON_TYPE_LU) + return; + + msg = gsm48_create_loc_upd_rej(cause); + if (!msg) { + LOGP(DMM, LOGL_ERROR, "Failed to create msg for LOCATION UPDATING REJECT.\n"); + return; + } + + msg->lchan = conn->lchan; + gsm0808_submit_dtap(conn, msg, 0, 0); +} + +static int bsc_filter_initial(struct osmo_bsc_data *bsc, + struct osmo_msc_data *msc, + struct gsm_subscriber_connection *conn, + struct msgb *msg, char **imsi, int *con_type, + int *lu_cause) +{ + struct bsc_filter_request req; + struct bsc_filter_reject_cause cause; + struct gsm48_hdr *gh = msgb_l3(msg); + int rc; + + req.ctx = conn; + req.black_list = NULL; + req.access_lists = bsc_access_lists(); + req.local_lst_name = msc->acc_lst_name; + req.global_lst_name = conn->bts->network->bsc_data->acc_lst_name; + req.bsc_nr = 0; + + rc = bsc_msg_filter_initial(gh, msgb_l3len(msg), &req, + con_type, imsi, &cause); + *lu_cause = cause.lu_reject_cause; + return rc; +} + +static int bsc_filter_data(struct gsm_subscriber_connection *conn, + struct msgb *msg, int *lu_cause) +{ + struct bsc_filter_request req; + struct gsm48_hdr *gh = msgb_l3(msg); + struct bsc_filter_reject_cause cause; + int rc; + + req.ctx = conn; + req.black_list = NULL; + req.access_lists = bsc_access_lists(); + req.local_lst_name = conn->sccp_con->msc->acc_lst_name; + req.global_lst_name = conn->bts->network->bsc_data->acc_lst_name; + req.bsc_nr = 0; + + rc = bsc_msg_filter_data(gh, msgb_l3len(msg), &req, + &conn->sccp_con->filter_state, + &cause); + *lu_cause = cause.lu_reject_cause; + return rc; +} static void bsc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci) { @@ -172,6 +235,8 @@ static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg static int complete_layer3(struct gsm_subscriber_connection *conn, struct msgb *msg, struct osmo_msc_data *msc) { + int con_type, rc, lu_cause; + char *imsi = NULL; struct timeval tv; struct msgb *resp; uint16_t network_code; @@ -189,6 +254,14 @@ static int complete_layer3(struct gsm_subscriber_connection *conn, if (send_ping && osmo_timer_remaining(&msc->ping_timer, NULL, &tv) == -1) send_ping = 0; + /* Check the filter */ + rc = bsc_filter_initial(msc->network->bsc_data, msc, conn, msg, + &imsi, &con_type, &lu_cause); + if (rc < 0) { + bsc_maybe_lu_reject(conn, con_type, lu_cause); + return BSC_API_CONN_POL_REJECT; + } + /* allocate resource for a new connection */ ret = bsc_create_new_connection(conn, msc, send_ping); @@ -202,6 +275,10 @@ static int complete_layer3(struct gsm_subscriber_connection *conn, return BSC_API_CONN_POL_REJECT; } + if (imsi) + conn->sccp_con->filter_state.imsi = talloc_steal(conn, imsi); + conn->sccp_con->filter_state.con_type = con_type; + /* check return value, if failed check msg for and send USSD */ network_code = get_network_code_for_msc(conn->sccp_con->msc); @@ -210,6 +287,7 @@ static int complete_layer3(struct gsm_subscriber_connection *conn, ci = get_ci_for_msc(conn->sccp_con->msc, conn->bts); bsc_scan_bts_msg(conn, msg); + resp = gsm0808_create_layer3(msg, network_code, country_code, lac, ci); if (!resp) { LOGP(DMSC, LOGL_DEBUG, "Failed to create layer3 message.\n"); @@ -320,6 +398,7 @@ static int handle_cc_setup(struct gsm_subscriber_connection *conn, static void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) { + int lu_cause; struct msgb *resp; return_when_not_connected(conn); @@ -332,8 +411,16 @@ static void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, st if (handle_cc_setup(conn, msg) >= 1) return; - bsc_scan_bts_msg(conn, msg); + /* Check the filter */ + if (bsc_filter_data(conn, msg, &lu_cause) < 0) { + bsc_maybe_lu_reject(conn, + conn->sccp_con->filter_state.con_type, + lu_cause); + bsc_clear_request(conn, 0); + return; + } + bsc_scan_bts_msg(conn, msg); resp = gsm0808_create_dtap(msg, link_id); queue_msg_or_return(resp); diff --git a/openbsc/src/osmo-bsc/osmo_bsc_main.c b/openbsc/src/osmo-bsc/osmo_bsc_main.c index 5c3885575..ee86cb647 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_main.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_main.c @@ -59,6 +59,12 @@ static const char *config_file = "openbsc.cfg"; static const char *rf_ctrl = NULL; extern const char *openbsc_copyright; static int daemonize = 0; +static struct llist_head access_lists; + +struct llist_head *bsc_access_lists(void) +{ + return &access_lists; +} static void print_usage() { @@ -196,6 +202,9 @@ int main(int argc, char **argv) vty_info.copyright = openbsc_copyright; vty_init(&vty_info); bsc_vty_init(&log_info); + bsc_msg_lst_vty_init(tall_bsc_ctx, &access_lists, BSC_NODE); + + INIT_LLIST_HEAD(&access_lists); /* parse options */ handle_options(argc, argv); diff --git a/openbsc/src/osmo-bsc/osmo_bsc_vty.c b/openbsc/src/osmo-bsc/osmo_bsc_vty.c index bbbba1cd2..06ad77d59 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_vty.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_vty.c @@ -1,5 +1,5 @@ /* Osmo BSC VTY Configuration */ -/* (C) 2009-2014 by Holger Hans Peter Freyther +/* (C) 2009-2015 by Holger Hans Peter Freyther * (C) 2009-2014 by On-Waves * All Rights Reserved * @@ -24,6 +24,7 @@ #include <openbsc/vty.h> #include <openbsc/gsm_subscriber.h> #include <openbsc/debug.h> +#include <openbsc/bsc_msg_filter.h> #include <osmocom/core/talloc.h> #include <osmocom/vty/logging.h> @@ -175,6 +176,9 @@ static void write_msc(struct vty *vty, struct osmo_msc_data *msc) if (msc->local_pref) vty_out(vty, " local-prefix %s%s", msc->local_pref, VTY_NEWLINE); + if (msc->acc_lst_name) + vty_out(vty, " access-list-name %s%s", msc->acc_lst_name, VTY_NEWLINE); + /* write amr options */ write_msc_amr_options(vty, msc); } @@ -210,6 +214,8 @@ static int config_write_bsc(struct vty *vty) vty_out(vty, " missing-msc-text %s%s", bsc->ussd_no_msc_txt, VTY_NEWLINE); else vty_out(vty, " no missing-msc-text%s", VTY_NEWLINE); + if (bsc->acc_lst_name) + vty_out(vty, " access-list-name %s%s", bsc->acc_lst_name, VTY_NEWLINE); return CMD_SUCCESS; } @@ -625,6 +631,33 @@ AMR_COMMAND(5_90) AMR_COMMAND(5_15) AMR_COMMAND(4_75) +DEFUN(cfg_msc_acc_lst_name, + cfg_msc_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 osmo_msc_data *msc = osmo_msc_data(vty); + + bsc_replace_string(msc, &msc->acc_lst_name, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_msc_no_acc_lst_name, + cfg_msc_no_acc_lst_name_cmd, + "no access-list-name", + NO_STR "Remove the access list from the NAT.\n") +{ + struct osmo_msc_data *msc = osmo_msc_data(vty); + + if (msc->acc_lst_name) { + talloc_free(msc->acc_lst_name); + msc->acc_lst_name = NULL; + } + + return CMD_SUCCESS; +} + DEFUN(cfg_net_bsc_mid_call_text, cfg_net_bsc_mid_call_text_cmd, "mid-call-text .TEXT", @@ -681,6 +714,33 @@ DEFUN(cfg_net_no_rf_off_time, 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 osmo_bsc_data *bsc = osmo_bsc_data(vty); + + bsc_replace_string(bsc, &bsc->acc_lst_name, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_bsc_no_acc_lst_name, + cfg_bsc_no_acc_lst_name_cmd, + "no access-list-name", + NO_STR "Remove the access list from the BSC\n") +{ + struct osmo_bsc_data *bsc = osmo_bsc_data(vty); + + if (bsc->acc_lst_name) { + talloc_free(bsc->acc_lst_name); + bsc->acc_lst_name = NULL; + } + + return CMD_SUCCESS; +} + DEFUN(show_statistics, show_statistics_cmd, "show statistics", @@ -805,6 +865,8 @@ int bsc_vty_init_extra(void) install_element(BSC_NODE, &cfg_net_no_rf_off_time_cmd); install_element(BSC_NODE, &cfg_net_bsc_missing_msc_ussd_cmd); install_element(BSC_NODE, &cfg_net_bsc_no_missing_msc_text_cmd); + install_element(BSC_NODE, &cfg_bsc_acc_lst_name_cmd); + install_element(BSC_NODE, &cfg_bsc_no_acc_lst_name_cmd); install_node(&msc_node, config_write_msc); vty_install_default(MSC_NODE); @@ -839,6 +901,8 @@ int bsc_vty_init_extra(void) install_element(MSC_NODE, &cfg_net_msc_amr_5_90_cmd); install_element(MSC_NODE, &cfg_net_msc_amr_5_15_cmd); install_element(MSC_NODE, &cfg_net_msc_amr_4_75_cmd); + install_element(MSC_NODE, &cfg_msc_acc_lst_name_cmd); + install_element(MSC_NODE, &cfg_msc_no_acc_lst_name_cmd); install_element_ve(&show_statistics_cmd); install_element_ve(&show_mscs_cmd); diff --git a/openbsc/src/osmo-bsc_nat/Makefile.am b/openbsc/src/osmo-bsc_nat/Makefile.am index ca103a4ff..d96a3911f 100644 --- a/openbsc/src/osmo-bsc_nat/Makefile.am +++ b/openbsc/src/osmo-bsc_nat/Makefile.am @@ -7,12 +7,13 @@ bin_PROGRAMS = osmo-bsc_nat osmo_bsc_nat_SOURCES = bsc_filter.c bsc_mgcp_utils.c bsc_nat.c bsc_nat_utils.c \ bsc_nat_vty.c bsc_sccp.c bsc_ussd.c bsc_nat_ctrl.c \ - bsc_nat_rewrite.c bsc_nat_filter.c bsc_nat_rewrite_trie.c + bsc_nat_rewrite.c bsc_nat_rewrite_trie.c bsc_nat_filter.c osmo_bsc_nat_LDADD = \ $(top_builddir)/src/libmgcp/libmgcp.a \ $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libtrau/libtrau.a \ $(top_builddir)/src/libcommon/libcommon.a \ + $(top_builddir)/src/libfilter/libfilter.a \ -lrt $(LIBOSMOSCCP_LIBS) $(LIBOSMOCORE_LIBS) \ $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCTRL_LIBS) \ $(LIBOSMOABIS_LIBS) $(LIBOSMONETIF_LIBS) diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat.c b/openbsc/src/osmo-bsc_nat/bsc_nat.c index 5c3b696e2..4357485ff 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat.c @@ -39,6 +39,7 @@ #include <openbsc/bsc_msc.h> #include <openbsc/bsc_nat.h> #include <openbsc/bsc_nat_sccp.h> +#include <openbsc/bsc_msg_filter.h> #include <openbsc/ipaccess.h> #include <openbsc/abis_nm.h> #include <openbsc/socket.h> @@ -425,7 +426,7 @@ static void bsc_stat_reject(int filter, struct bsc_connection *bsc, int normal) */ static void bsc_send_con_release(struct bsc_connection *bsc, struct nat_sccp_connection *con, - struct bsc_nat_reject_cause *cause) + struct bsc_filter_reject_cause *cause) { struct msgb *rlsd; /* 1. release the network */ @@ -441,7 +442,7 @@ static void bsc_send_con_release(struct bsc_connection *bsc, con->msc_con = NULL; /* 2. release the BSC side */ - if (con->con_type == NAT_CON_TYPE_LU) { + if (con->filter_state.con_type == FLT_CON_TYPE_LU) { struct msgb *payload, *udt; payload = gsm48_create_loc_upd_rej(cause->lu_reject_cause); @@ -469,20 +470,20 @@ static void bsc_send_con_release(struct bsc_connection *bsc, return; } - con->con_type = NAT_CON_TYPE_LOCAL_REJECT; + con->filter_state.con_type = FLT_CON_TYPE_LOCAL_REJECT; bsc_write(bsc, rlsd, IPAC_PROTO_SCCP); } static void bsc_send_con_refuse(struct bsc_connection *bsc, struct bsc_nat_parsed *parsed, int con_type, - struct bsc_nat_reject_cause *cause) + struct bsc_filter_reject_cause *cause) { struct msgb *payload; struct msgb *refuse; - if (con_type == NAT_CON_TYPE_LU) + if (con_type == FLT_CON_TYPE_LU) payload = gsm48_create_loc_upd_rej(cause->lu_reject_cause); - else if (con_type == NAT_CON_TYPE_CM_SERV_REQ || con_type == NAT_CON_TYPE_SSA) + else if (con_type == FLT_CON_TYPE_CM_SERV_REQ || con_type == FLT_CON_TYPE_SSA) payload = gsm48_create_mm_serv_rej(cause->cm_reject_cause); else { LOGP(DNAT, LOGL_ERROR, "Unknown connection type: %d\n", con_type); @@ -503,7 +504,7 @@ static void bsc_send_con_refuse(struct bsc_connection *bsc, goto send_refuse; /* declare it local and assign a unique remote_ref */ - con->con_type = NAT_CON_TYPE_LOCAL_REJECT; + con->filter_state.con_type = FLT_CON_TYPE_LOCAL_REJECT; con->con_local = NAT_CON_END_LOCAL; con->has_remote_ref = 1; con->remote_ref = con->patched_ref; @@ -1025,7 +1026,7 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) struct bsc_connection *con_bsc = NULL; int con_type; struct bsc_nat_parsed *parsed; - struct bsc_nat_reject_cause cause; + struct bsc_filter_reject_cause cause; /* Parse and filter messages */ parsed = bsc_nat_parse(msg); @@ -1071,11 +1072,11 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) con = patch_sccp_src_ref_to_msc(msg, parsed, bsc); con->msc_con = bsc->nat->msc_con; con_msc = con->msc_con; - con->con_type = con_type; - con->imsi_checked = filter; + con->filter_state.con_type = con_type; + con->filter_state.imsi_checked = filter; bsc_nat_extract_lac(bsc, con, parsed, msg); if (imsi) - con->imsi = talloc_steal(con, imsi); + con->filter_state.imsi = talloc_steal(con, imsi); imsi = NULL; con_bsc = con->bsc; handle_con_stats(con); @@ -1093,8 +1094,9 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) filter = bsc_nat_filter_dt(bsc, msg, con, parsed, &cause); if (filter < 0) { - if (con->imsi) - bsc_nat_inform_reject(bsc, con->imsi); + if (con->filter_state.imsi) + bsc_nat_inform_reject(bsc, + con->filter_state.imsi); bsc_stat_reject(filter, bsc, 1); bsc_send_con_release(bsc, con, &cause); con = NULL; @@ -1110,7 +1112,8 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) * replace the msg and the parsed structure becomes * invalid. */ - msg = bsc_nat_rewrite_msg(bsc->nat, msg, parsed, con->imsi); + msg = bsc_nat_rewrite_msg(bsc->nat, msg, parsed, + con->filter_state.imsi); talloc_free(parsed); parsed = NULL; } else if (con->con_local == NAT_CON_END_USSD) { diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c b/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c index 4b59b404f..f3ca92400 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_ctrl.c @@ -29,6 +29,7 @@ #include <openbsc/ctrl.h> #include <openbsc/bsc_nat.h> +#include <openbsc/bsc_msg_filter.h> #include <openbsc/vty.h> #include <openbsc/gsm_data.h> @@ -404,19 +405,19 @@ static int get_net_cfg_acc_cmd(struct ctrl_cmd *cmd, void *data) static int set_net_cfg_acc_cmd(struct ctrl_cmd *cmd, void *data) { const char *access_name = extract_acc_name(cmd->variable); - struct bsc_nat_acc_lst *acc; - struct bsc_nat_acc_lst_entry *entry; + struct bsc_msg_acc_lst *acc; + struct bsc_msg_acc_lst_entry *entry; const char *value = cmd->value; int rc; /* Should have been caught by verify_net_cfg_acc_cmd */ - acc = bsc_nat_acc_lst_find(g_nat, access_name); + acc = bsc_msg_acc_lst_find(&g_nat->access_lists, access_name); if (!acc) { cmd->reply = "Access list not found"; return CTRL_CMD_ERROR; } - entry = bsc_nat_acc_lst_entry_create(acc); + entry = bsc_msg_acc_lst_entry_create(acc); if (!entry) { cmd->reply = "OOM"; return CTRL_CMD_ERROR; @@ -435,7 +436,7 @@ static int set_net_cfg_acc_cmd(struct ctrl_cmd *cmd, void *data) static int verify_net_cfg_acc_cmd(struct ctrl_cmd *cmd, const char *value, void *data) { const char *access_name = extract_acc_name(cmd->variable); - struct bsc_nat_acc_lst *acc = bsc_nat_acc_lst_find(g_nat, access_name); + struct bsc_msg_acc_lst *acc = bsc_msg_acc_lst_find(&g_nat->access_lists, access_name); if (!acc) { cmd->reply = "Access list not known"; diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c b/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c index 64f6d7347..393aea3ce 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c @@ -1,8 +1,5 @@ /* - * Access filtering - */ -/* - * (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org> + * (C) 2010-2015 by Holger Hans Peter Freyther <zecke@selfish.org> * (C) 2010-2012 by On-Waves * All Rights Reserved * @@ -23,13 +20,9 @@ #include <openbsc/bsc_nat.h> #include <openbsc/bsc_nat_sccp.h> -#include <openbsc/bsc_msc.h> -#include <openbsc/gsm_data.h> +#include <openbsc/bsc_msg_filter.h> #include <openbsc/debug.h> -#include <openbsc/ipaccess.h> -#include <osmocom/core/linuxlist.h> -#include <osmocom/core/talloc.h> #include <osmocom/gsm/gsm0808.h> #include <osmocom/gsm/protocol/gsm_08_08.h> @@ -37,307 +30,18 @@ #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, - int *cm_cause, int *lu_cause) -{ - 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) { - *cm_cause = entry->cm_reject_cause; - *lu_cause = entry->lu_reject_cause; - return 0; - } - } - - return 1; -} - -/* apply white/black list */ -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.) 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 -4; - } - - - 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) { - /* 2. BSC allow */ - if (bsc_nat_lst_check_allow(bsc_lst, imsi) == 0) - return 1; - - /* 3. BSC deny */ - if (lst_check_deny(bsc_lst, imsi, &cm, &lu) == 0) { - LOGP(DNAT, LOGL_ERROR, - "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]); - cause->cm_reject_cause = cm; - cause->lu_reject_cause = lu; - return -2; - } - - } - - /* 4. NAT deny */ - if (nat_lst) { - if (lst_check_deny(nat_lst, imsi, &cm, &lu) == 0) { - LOGP(DNAT, LOGL_ERROR, - "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]); - cause->cm_reject_cause = cm; - cause->lu_reject_cause = lu; - return -3; - } - } - - return 1; -} - -static int _cr_check_loc_upd(struct bsc_connection *bsc, - uint8_t *data, unsigned int length, - char **imsi) -{ - uint8_t mi_type; - struct gsm48_loc_upd_req *lu; - char mi_string[GSM48_MI_SIZE]; - - if (length < sizeof(*lu)) { - LOGP(DNAT, LOGL_ERROR, - "LU does not fit. Length is %d \n", length); - return -1; - } - - lu = (struct gsm48_loc_upd_req *) data; - mi_type = lu->mi[0] & GSM_MI_TYPE_MASK; - - /* - * We can only deal with the IMSI. This will fail for a phone that - * will send the TMSI of a previous network to us. - */ - if (mi_type != GSM_MI_TYPE_IMSI) - return 0; - - gsm48_mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len); - *imsi = talloc_strdup(bsc, mi_string); - return 1; -} - -static int _cr_check_cm_serv_req(struct bsc_connection *bsc, - uint8_t *data, unsigned int length, - int *con_type, char **imsi) -{ - static const uint32_t classmark_offset = - offsetof(struct gsm48_service_request, classmark); - - char mi_string[GSM48_MI_SIZE]; - uint8_t mi_type; - int rc; - struct gsm48_service_request *req; - - /* unfortunately in Phase1 the classmark2 length is variable */ - - if (length < sizeof(*req)) { - LOGP(DNAT, LOGL_ERROR, - "CM Serv Req does not fit. Length is %d\n", length); - return -1; - } - - req = (struct gsm48_service_request *) data; - if (req->cm_service_type == 0x8) - *con_type = NAT_CON_TYPE_SSA; - rc = gsm48_extract_mi((uint8_t *) &req->classmark, - length - classmark_offset, mi_string, &mi_type); - if (rc < 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to parse the classmark2/mi. error: %d\n", rc); - return -1; - } - - /* we have to let the TMSI or such pass */ - if (mi_type != GSM_MI_TYPE_IMSI) - return 0; - - *imsi = talloc_strdup(bsc, mi_string); - return 1; -} - -static int _cr_check_pag_resp(struct bsc_connection *bsc, - uint8_t *data, unsigned int length, char **imsi) -{ - struct gsm48_pag_resp *resp; - char mi_string[GSM48_MI_SIZE]; - uint8_t mi_type; - - if (length < sizeof(*resp)) { - LOGP(DNAT, LOGL_ERROR, "PAG RESP does not fit. Length was %d.\n", length); - return -1; - } - - resp = (struct gsm48_pag_resp *) data; - if (gsm48_paging_extract_mi(resp, length, mi_string, &mi_type) < 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to extract the MI.\n"); - return -1; - } - - /* we need to let it pass for now */ - if (mi_type != GSM_MI_TYPE_IMSI) - return 0; - - *imsi = talloc_strdup(bsc, mi_string); - return 1; -} - -static int _dt_check_id_resp(struct bsc_connection *bsc, - uint8_t *data, unsigned int length, - struct nat_sccp_connection *con, - struct bsc_nat_reject_cause *cause) -{ - char mi_string[GSM48_MI_SIZE]; - uint8_t mi_type; - - if (length < 2) { - LOGP(DNAT, LOGL_ERROR, "mi does not fit.\n"); - return -1; - } - - if (data[0] < length - 1) { - LOGP(DNAT, LOGL_ERROR, "mi length too big.\n"); - return -2; - } - - mi_type = data[1] & GSM_MI_TYPE_MASK; - gsm48_mi_to_string(mi_string, sizeof(mi_string), &data[1], data[0]); - - if (mi_type != GSM_MI_TYPE_IMSI) - return 0; - - con->imsi_checked = 1; - con->imsi = talloc_strdup(con, mi_string); - return auth_imsi(bsc, mi_string, cause); -} - - /* Filter out CR data... */ int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed, int *con_type, - char **imsi, struct bsc_nat_reject_cause *cause) + char **imsi, struct bsc_filter_reject_cause *cause) { + struct bsc_filter_request req; struct tlv_parsed tp; struct gsm48_hdr *hdr48; int hdr48_len; - int len, ret = 0; - uint8_t msg_type, proto; + int len; - *con_type = NAT_CON_TYPE_NONE; + *con_type = FLT_CON_TYPE_NONE; cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; *imsi = NULL; @@ -374,55 +78,27 @@ int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, } hdr48 = (struct gsm48_hdr *) TLVP_VAL(&tp, GSM0808_IE_LAYER_3_INFORMATION); - - proto = hdr48->proto_discr & 0x0f; - msg_type = hdr48->msg_type & 0xbf; - if (proto == GSM48_PDISC_MM && - msg_type == GSM48_MT_MM_LOC_UPD_REQUEST) { - *con_type = NAT_CON_TYPE_LU; - ret = _cr_check_loc_upd(bsc, &hdr48->data[0], - hdr48_len - sizeof(*hdr48), imsi); - } else if (proto == GSM48_PDISC_MM && - msg_type == GSM48_MT_MM_CM_SERV_REQ) { - *con_type = NAT_CON_TYPE_CM_SERV_REQ; - ret = _cr_check_cm_serv_req(bsc, &hdr48->data[0], - hdr48_len - sizeof(*hdr48), - con_type, imsi); - } else if (proto == GSM48_PDISC_RR && - msg_type == GSM48_MT_RR_PAG_RESP) { - *con_type = NAT_CON_TYPE_PAG_RESP; - ret = _cr_check_pag_resp(bsc, &hdr48->data[0], - hdr48_len - sizeof(*hdr48), imsi); - } else { - /* We only want to filter the above, let other things pass */ - *con_type = NAT_CON_TYPE_OTHER; - return 0; - } - - /* check if we are done */ - if (ret != 1) - return ret; - - /* the memory allocation failed */ - if (!*imsi) - return -1; - - /* now check the imsi */ - return auth_imsi(bsc, *imsi, cause); + req.ctx = bsc; + req.black_list = &bsc->nat->imsi_black_list; + req.access_lists = &bsc->nat->access_lists; + req.local_lst_name = bsc->cfg->acc_lst_name; + req.global_lst_name = bsc->nat->acc_lst_name; + req.bsc_nr = bsc->cfg->nr; + return bsc_msg_filter_initial(hdr48, hdr48_len, &req, con_type, imsi, cause); } int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg, struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, - struct bsc_nat_reject_cause *cause) + struct bsc_filter_reject_cause *cause) { uint32_t len; - uint8_t msg_type, proto; struct gsm48_hdr *hdr48; + struct bsc_filter_request req; cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - if (con->imsi_checked) + if (con->filter_state.imsi_checked) return 0; /* only care about DTAP messages */ @@ -433,11 +109,11 @@ int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg, if (!hdr48) return -1; - proto = hdr48->proto_discr & 0x0f; - msg_type = hdr48->msg_type & 0xbf; - if (proto != GSM48_PDISC_MM || msg_type != GSM48_MT_MM_ID_RESP) - return 0; - - return _dt_check_id_resp(bsc, &hdr48->data[0], - len - sizeof(*hdr48), con, cause); + req.ctx = bsc; + req.black_list = &bsc->nat->imsi_black_list; + req.access_lists = &bsc->nat->access_lists; + req.local_lst_name = bsc->cfg->acc_lst_name; + req.global_lst_name = bsc->nat->acc_lst_name; + req.bsc_nr = bsc->cfg->nr; + return bsc_msg_filter_data(hdr48, len, &req, &con->filter_state, cause); } diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c index 70ad577b9..d95227dca 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c @@ -23,6 +23,7 @@ #include <openbsc/bsc_nat.h> #include <openbsc/bsc_nat_sccp.h> +#include <openbsc/bsc_msg_filter.h> #include <openbsc/bsc_msc.h> #include <openbsc/gsm_data.h> #include <openbsc/debug.h> @@ -66,18 +67,6 @@ static const struct rate_ctr_group_desc bsc_cfg_ctrg_desc = { .ctr_desc = bsc_cfg_ctr_description, }; -static const struct rate_ctr_desc acc_list_ctr_description[] = { - [ACC_LIST_BSC_FILTER] = { "access-list.bsc-filter", "Rejected by rule for BSC"}, - [ACC_LIST_NAT_FILTER] = { "access-list.nat-filter", "Rejected by rule for NAT"}, -}; - -static const struct rate_ctr_group_desc bsc_cfg_acc_list_desc = { - .group_name_prefix = "nat.filter", - .group_description = "NAT Access-List Statistics", - .num_ctr = ARRAY_SIZE(acc_list_ctr_description), - .ctr_desc = acc_list_ctr_description, -}; - struct bsc_nat *bsc_nat_alloc(void) { struct bsc_nat *nat = talloc_zero(tall_bsc_ctx, struct bsc_nat); @@ -123,12 +112,12 @@ struct bsc_nat *bsc_nat_alloc(void) void bsc_nat_free(struct bsc_nat *nat) { struct bsc_config *cfg, *tmp; - struct bsc_nat_acc_lst *lst, *tmp_lst; + struct bsc_msg_acc_lst *lst, *tmp_lst; llist_for_each_entry_safe(cfg, tmp, &nat->bsc_configs, entry) bsc_config_free(cfg); llist_for_each_entry_safe(lst, tmp_lst, &nat->access_lists, list) - bsc_nat_acc_lst_delete(lst); + bsc_msg_acc_lst_delete(lst); bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL); bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr_post, NULL); @@ -392,20 +381,6 @@ int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg) return 0; } -int bsc_nat_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; -} - struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed, struct msgb *msg, uint32_t *len) { @@ -428,13 +403,13 @@ struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed, } static const char *con_types [] = { - [NAT_CON_TYPE_NONE] = "n/a", - [NAT_CON_TYPE_LU] = "Location Update", - [NAT_CON_TYPE_CM_SERV_REQ] = "CM Serv Req", - [NAT_CON_TYPE_PAG_RESP] = "Paging Response", - [NAT_CON_TYPE_SSA] = "Supplementar Service Activation", - [NAT_CON_TYPE_LOCAL_REJECT] = "Local Reject", - [NAT_CON_TYPE_OTHER] = "Other", + [FLT_CON_TYPE_NONE] = "n/a", + [FLT_CON_TYPE_LU] = "Location Update", + [FLT_CON_TYPE_CM_SERV_REQ] = "CM Serv Req", + [FLT_CON_TYPE_PAG_RESP] = "Paging Response", + [FLT_CON_TYPE_SSA] = "Supplementar Service Activation", + [FLT_CON_TYPE_LOCAL_REJECT] = "Local Reject", + [FLT_CON_TYPE_OTHER] = "Other", }; const char *bsc_con_type_to_string(int type) @@ -442,86 +417,24 @@ const char *bsc_con_type_to_string(int type) return con_types[type]; } -struct bsc_nat_acc_lst *bsc_nat_acc_lst_find(struct bsc_nat *nat, const char *name) -{ - struct bsc_nat_acc_lst *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_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *name) -{ - struct bsc_nat_acc_lst *lst; - - lst = bsc_nat_acc_lst_find(nat, name); - if (lst) - return lst; - - lst = talloc_zero(nat, struct bsc_nat_acc_lst); - if (!lst) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate access list"); - return NULL; - } - - /* TODO: get the index right */ - lst->stats = rate_ctr_group_alloc(lst, &bsc_cfg_acc_list_desc, 0); - if (!lst->stats) { - talloc_free(lst); - return NULL; - } - - INIT_LLIST_HEAD(&lst->fltr_list); - lst->name = talloc_strdup(lst, name); - llist_add_tail(&lst->list, &nat->access_lists); - return lst; -} - -void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst) -{ - llist_del(&lst->list); - rate_ctr_group_free(lst->stats); - 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; - - entry->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - entry->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - llist_add_tail(&entry->list, &lst->fltr_list); - return entry; -} - int bsc_nat_msc_is_connected(struct bsc_nat *nat) { return nat->msc_con->is_connected; } static const int con_to_ctr[] = { - [NAT_CON_TYPE_NONE] = -1, - [NAT_CON_TYPE_LU] = BCFG_CTR_CON_TYPE_LU, - [NAT_CON_TYPE_CM_SERV_REQ] = BCFG_CTR_CON_CMSERV_RQ, - [NAT_CON_TYPE_PAG_RESP] = BCFG_CTR_CON_PAG_RESP, - [NAT_CON_TYPE_SSA] = BCFG_CTR_CON_SSA, - [NAT_CON_TYPE_LOCAL_REJECT] = -1, - [NAT_CON_TYPE_OTHER] = BCFG_CTR_CON_OTHER, + [FLT_CON_TYPE_NONE] = -1, + [FLT_CON_TYPE_LU] = BCFG_CTR_CON_TYPE_LU, + [FLT_CON_TYPE_CM_SERV_REQ] = BCFG_CTR_CON_CMSERV_RQ, + [FLT_CON_TYPE_PAG_RESP] = BCFG_CTR_CON_PAG_RESP, + [FLT_CON_TYPE_SSA] = BCFG_CTR_CON_SSA, + [FLT_CON_TYPE_LOCAL_REJECT] = -1, + [FLT_CON_TYPE_OTHER] = BCFG_CTR_CON_OTHER, }; int bsc_conn_type_to_ctr(struct nat_sccp_connection *conn) { - return con_to_ctr[conn->con_type]; + return con_to_ctr[conn->filter_state.con_type]; } int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg) diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c index 9e66cdc28..821e5226a 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c @@ -22,6 +22,7 @@ #include <openbsc/gsm_data.h> #include <openbsc/bsc_nat.h> #include <openbsc/bsc_nat_sccp.h> +#include <openbsc/bsc_msg_filter.h> #include <openbsc/bsc_msc.h> #include <openbsc/gsm_04_08.h> #include <openbsc/mgcp.h> @@ -70,22 +71,6 @@ static int config_write_pgroup(struct vty *vty) return CMD_SUCCESS; } -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 %d %d%s", - lst->name, entry->imsi_deny, - entry->cm_reject_cause, entry->lu_reject_cause, - VTY_NEWLINE); - } -} - static void dump_lac(struct vty *vty, struct llist_head *head) { struct bsc_lac_entry *lac; @@ -102,7 +87,7 @@ static void write_pgroup_lst(struct vty *vty, struct bsc_nat_paging_group *pgrou static int config_write_nat(struct vty *vty) { - struct bsc_nat_acc_lst *lst; + struct bsc_msg_acc_lst *lst; struct bsc_nat_paging_group *pgroup; vty_out(vty, "nat%s", VTY_NEWLINE); @@ -151,7 +136,7 @@ static int config_write_nat(struct vty *vty) _nat->num_rewr_trie_name, VTY_NEWLINE); llist_for_each_entry(lst, &_nat->access_lists, list) - write_acc_lst(vty, lst); + bsc_msg_acc_lst_write(vty, lst); llist_for_each_entry(pgroup, &_nat->paging_groups, entry) write_pgroup_lst(vty, pgroup); if (_nat->mgcp_ipa) @@ -204,7 +189,7 @@ DEFUN(show_sccp, show_sccp_cmd, "show sccp connections", con->has_remote_ref, sccp_src_ref_to_int(&con->remote_ref), con->msc_endp, con->bsc_endp, - bsc_con_type_to_string(con->con_type), + bsc_con_type_to_string(con->filter_state.con_type), VTY_NEWLINE); } @@ -518,7 +503,7 @@ DEFUN(cfg_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); + rc = bsc_filter_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); @@ -528,7 +513,7 @@ DEFUN(cfg_nat_imsi_black_list_fn, return CMD_SUCCESS; } - bsc_nat_barr_adapt(_nat, &_nat->imsi_black_list, NULL); + bsc_filter_barr_adapt(_nat, &_nat->imsi_black_list, NULL); return CMD_SUCCESS; } @@ -539,7 +524,7 @@ DEFUN(cfg_nat_no_imsi_black_list_fn, { talloc_free(_nat->imsi_black_list_fn); _nat->imsi_black_list_fn = NULL; - bsc_nat_barr_adapt(_nat, &_nat->imsi_black_list, NULL); + bsc_filter_barr_adapt(_nat, &_nat->imsi_black_list, NULL); return CMD_SUCCESS; } @@ -867,94 +852,6 @@ DEFUN(cfg_bsc_no_lac, cfg_bsc_no_lac_cmd, return CMD_SUCCESS; } - - -DEFUN(cfg_lst_imsi_allow, - cfg_lst_imsi_allow_cmd, - "access-list NAME imsi-allow [REGEXP]", - "Access list commands\n" - "Name of the access list\n" - "Add allowed IMSI to the list\n" - "Regexp for 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; - - entry = bsc_nat_acc_lst_entry_create(acc); - if (!entry) - return CMD_WARNING; - - if (gsm_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, argc - 1, &argv[1]) != 0) - return CMD_WARNING; - return CMD_SUCCESS; -} - -DEFUN(cfg_lst_imsi_deny, - cfg_lst_imsi_deny_cmd, - "access-list NAME imsi-deny [REGEXP] (<0-256>) (<0-256>)", - "Access list commands\n" - "Name of the access list\n" - "Add denied IMSI to the list\n" - "Regexp for IMSIs\n" - "CM Service Reject reason\n" - "LU Reject reason\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; - - entry = bsc_nat_acc_lst_entry_create(acc); - if (!entry) - return CMD_WARNING; - - if (gsm_parse_reg(acc, &entry->imsi_deny_re, &entry->imsi_deny, argc - 1, &argv[1]) != 0) - return CMD_WARNING; - if (argc >= 3) - entry->cm_reject_cause = atoi(argv[2]); - if (argc >= 4) - entry->lu_reject_cause = atoi(argv[3]); - return CMD_SUCCESS; -} - -/* naming to follow Zebra... */ -DEFUN(cfg_lst_no, - cfg_lst_no_cmd, - "no access-list NAME", - NO_STR "Remove an access-list by name\n" - "The access-list to remove\n") -{ - struct bsc_nat_acc_lst *acc; - acc = bsc_nat_acc_lst_find(_nat, argv[0]); - if (!acc) - return CMD_WARNING; - - bsc_nat_acc_lst_delete(acc); - return CMD_SUCCESS; -} - -DEFUN(show_acc_lst, - show_acc_lst_cmd, - "show access-list NAME", - SHOW_STR "IMSI access list\n" "Name of the access list\n") -{ - struct bsc_nat_acc_lst *acc; - acc = bsc_nat_acc_lst_find(_nat, argv[0]); - if (!acc) - return CMD_WARNING; - - vty_out(vty, "access-list %s%s", acc->name, VTY_NEWLINE); - vty_out_rate_ctr_group(vty, " ", acc->stats); - - return CMD_SUCCESS; -} - DEFUN(show_bar_lst, show_bar_lst_cmd, "show imsi-black-list", @@ -965,8 +862,8 @@ DEFUN(show_bar_lst, 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); + struct bsc_filter_barr_entry *entry; + entry = rb_entry(node, struct bsc_filter_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, @@ -1245,7 +1142,6 @@ int bsc_nat_vty_init(struct bsc_nat *nat) install_element_ve(&show_msc_cmd); 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_ve(&show_prefix_tree_cmd); install_element_ve(&show_ussd_connection_cmd); @@ -1275,10 +1171,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat) install_element(NAT_NODE, &cfg_nat_ussd_local_cmd); install_element(NAT_NODE, &cfg_nat_use_ipa_for_mgcp_cmd); - /* access-list */ - install_element(NAT_NODE, &cfg_lst_imsi_allow_cmd); - install_element(NAT_NODE, &cfg_lst_imsi_deny_cmd); - install_element(NAT_NODE, &cfg_lst_no_cmd); + bsc_msg_lst_vty_init(nat, &nat->access_lists, NAT_NODE); /* number rewriting */ install_element(NAT_NODE, &cfg_nat_number_rewrite_cmd); diff --git a/openbsc/src/osmo-bsc_nat/bsc_ussd.c b/openbsc/src/osmo-bsc_nat/bsc_ussd.c index 67844b812..108241421 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_ussd.c +++ b/openbsc/src/osmo-bsc_nat/bsc_ussd.c @@ -22,6 +22,7 @@ #include <openbsc/bsc_nat.h> #include <openbsc/bsc_nat_sccp.h> +#include <openbsc/bsc_msg_filter.h> #include <openbsc/ipaccess.h> #include <openbsc/socket.h> @@ -350,7 +351,7 @@ static int forward_ussd(struct nat_sccp_connection *con, const struct ussd_reque state->invoke_id = req->invoke_id; memcpy(&state->src_ref, &con->remote_ref, sizeof(con->remote_ref)); memcpy(&state->dst_ref, &con->real_ref, sizeof(con->real_ref)); - memcpy(state->imsi, con->imsi, strlen(con->imsi)); + memcpy(state->imsi, con->filter_state.imsi, strlen(con->filter_state.imsi)); /* add additional tag/values */ lac = htons(con->lac); @@ -373,7 +374,7 @@ int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parse uint8_t proto; uint8_t ti; struct gsm48_hdr *hdr48; - struct bsc_nat_acc_lst *lst; + struct bsc_msg_acc_lst *lst; struct ussd_request req; /* @@ -381,10 +382,10 @@ int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parse * decode if the connection was created for USSD, we do have a USSD access * list, a query, a IMSI and such... */ - if (con->con_type != NAT_CON_TYPE_SSA) + if (con->filter_state.con_type != FLT_CON_TYPE_SSA) return 0; - if (!con->imsi) + if (!con->filter_state.imsi) return 0; /* We have not verified the IMSI yet */ @@ -399,7 +400,7 @@ int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parse if (parsed->bssap != BSSAP_MSG_DTAP) return 0; - if (strlen(con->imsi) >= GSM_IMSI_LENGTH) + if (strlen(con->filter_state.imsi) >= GSM_IMSI_LENGTH) return 0; hdr48 = bsc_unpack_dtap(parsed, msg, &len); @@ -415,12 +416,12 @@ int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parse if (msg_type == GSM0480_MTYPE_REGISTER) { /* now check if it is a IMSI we care about */ - lst = bsc_nat_acc_lst_find(con->bsc->nat, + lst = bsc_msg_acc_lst_find(&con->bsc->nat->access_lists, con->bsc->nat->ussd_lst_name); if (!lst) return 0; - if (bsc_nat_lst_check_allow(lst, con->imsi) != 0) + if (bsc_msg_acc_lst_check_allow(lst, con->filter_state.imsi) != 0) return 0; /* now decode the message and see if we really want to handle it */ @@ -435,14 +436,15 @@ int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parse return 0; /* found a USSD query for our subscriber */ - LOGP(DNAT, LOGL_NOTICE, "Found USSD query for %s\n", con->imsi); + LOGP(DNAT, LOGL_NOTICE, "Found USSD query for %s\n", + con->filter_state.imsi); con->ussd_ti[ti] = 1; if (forward_ussd(con, &req, msg) != 0) return 0; return 1; } else if (msg_type == GSM0480_MTYPE_FACILITY && con->ussd_ti[ti]) { LOGP(DNAT, LOGL_NOTICE, "Forwarding message part of TI: %d %s\n", - ti, con->imsi); + ti, con->filter_state.imsi); if (forward_ussd_simple(con, msg) != 0) return 0; return 1; diff --git a/openbsc/tests/bsc-nat/Makefile.am b/openbsc/tests/bsc-nat/Makefile.am index b620d9649..26e550098 100644 --- a/openbsc/tests/bsc-nat/Makefile.am +++ b/openbsc/tests/bsc-nat/Makefile.am @@ -10,11 +10,13 @@ bsc_nat_test_SOURCES = bsc_nat_test.c \ $(top_srcdir)/src/osmo-bsc_nat/bsc_filter.c \ $(top_srcdir)/src/osmo-bsc_nat/bsc_sccp.c \ $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_utils.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_filter.c \ $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite.c \ $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_mgcp_utils.c -bsc_nat_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ + $(top_srcdir)/src/osmo-bsc_nat/bsc_mgcp_utils.c \ + $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_filter.c +bsc_nat_test_LDADD = \ + $(top_builddir)/src/libfilter/libfilter.a \ + $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libmgcp/libmgcp.a \ $(top_builddir)/src/libtrau/libtrau.a \ $(top_builddir)/src/libcommon/libcommon.a \ diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c index 5b01cc3cd..b830eb0df 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.c +++ b/openbsc/tests/bsc-nat/bsc_nat_test.c @@ -26,6 +26,7 @@ #include <openbsc/gsm_data.h> #include <openbsc/bsc_nat.h> #include <openbsc/bsc_nat_sccp.h> +#include <openbsc/bsc_msg_filter.h> #include <openbsc/nat_rewrite_trie.h> #include <osmocom/core/application.h> @@ -710,7 +711,7 @@ static struct cr_filter cr_filter[] = { .data = bssmap_cr, .length = sizeof(bssmap_cr), .result = 1, - .contype = NAT_CON_TYPE_CM_SERV_REQ, + .contype = FLT_CON_TYPE_CM_SERV_REQ, .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, @@ -722,7 +723,7 @@ static struct cr_filter cr_filter[] = { .data = bss_lu, .length = sizeof(bss_lu), .result = 1, - .contype = NAT_CON_TYPE_LU, + .contype = FLT_CON_TYPE_LU, .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, @@ -734,7 +735,7 @@ static struct cr_filter cr_filter[] = { .data = pag_resp, .length = sizeof(pag_resp), .result = 1, - .contype = NAT_CON_TYPE_PAG_RESP, + .contype = FLT_CON_TYPE_PAG_RESP, .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, @@ -748,7 +749,7 @@ static struct cr_filter cr_filter[] = { .length = sizeof(bss_lu), .result = -3, .nat_imsi_deny = "[0-9]*", - .contype = NAT_CON_TYPE_LU, + .contype = FLT_CON_TYPE_LU, .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, @@ -763,7 +764,7 @@ static struct cr_filter cr_filter[] = { .result = 1, .nat_imsi_deny = "[0-9]*", .bsc_imsi_allow = "2440[0-9]*", - .contype = NAT_CON_TYPE_LU, + .contype = FLT_CON_TYPE_LU, .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, @@ -778,7 +779,7 @@ static struct cr_filter cr_filter[] = { .result = 1, .bsc_imsi_allow = "[0-9]*", .nat_imsi_deny = "[0-9]*", - .contype = NAT_CON_TYPE_LU, + .contype = FLT_CON_TYPE_LU, .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, @@ -794,7 +795,7 @@ static struct cr_filter cr_filter[] = { .bsc_imsi_deny = "[0-9]*", .bsc_imsi_allow = "[0-9]*", .nat_imsi_deny = "[0-9]*", - .contype = NAT_CON_TYPE_LU, + .contype = FLT_CON_TYPE_LU, .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, @@ -809,7 +810,7 @@ static struct cr_filter cr_filter[] = { .result = -3, .bsc_imsi_deny = "000[0-9]*", .nat_imsi_deny = "[0-9]*", - .contype = NAT_CON_TYPE_LU, + .contype = FLT_CON_TYPE_LU, .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, @@ -824,7 +825,7 @@ static struct cr_filter cr_filter[] = { .result = -3, .bsc_imsi_deny = "000[0-9]*", .nat_imsi_deny = "[0-9]*", - .contype = NAT_CON_TYPE_LU, + .contype = FLT_CON_TYPE_LU, .nat_cm_reject_cause = 0x23, .nat_lu_reject_cause = 0x42, .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, @@ -838,7 +839,7 @@ static struct cr_filter cr_filter[] = { .length = sizeof(bss_lu), .result = -2, .bsc_imsi_deny = "[0-9]*", - .contype = NAT_CON_TYPE_LU, + .contype = FLT_CON_TYPE_LU, .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, @@ -852,7 +853,7 @@ static struct cr_filter cr_filter[] = { .length = sizeof(bss_lu), .result = -2, .bsc_imsi_deny = "[0-9]*", - .contype = NAT_CON_TYPE_LU, + .contype = FLT_CON_TYPE_LU, .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, .bsc_cm_reject_cause = 0x42, @@ -867,9 +868,9 @@ 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_acc_lst *nat_lst, *bsc_lst; - struct bsc_nat_acc_lst_entry *nat_entry, *bsc_entry; - struct bsc_nat_reject_cause cause; + struct bsc_msg_acc_lst *nat_lst, *bsc_lst; + struct bsc_msg_acc_lst_entry *nat_entry, *bsc_entry; + struct bsc_filter_reject_cause cause; struct bsc_nat *nat = bsc_nat_alloc(); struct bsc_connection *bsc = bsc_connection_alloc(nat); @@ -878,11 +879,11 @@ 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"); + nat_lst = bsc_msg_acc_lst_get(nat, &nat->access_lists, "nat"); + bsc_lst = bsc_msg_acc_lst_get(nat, &nat->access_lists, "bsc"); - bsc_entry = bsc_nat_acc_lst_entry_create(bsc_lst); - nat_entry = bsc_nat_acc_lst_entry_create(nat_lst); + bsc_entry = bsc_msg_acc_lst_entry_create(bsc_lst); + nat_entry = bsc_msg_acc_lst_entry_create(nat_lst); /* test the default value as we are going to overwrite it */ OSMO_ASSERT(bsc_entry->cm_reject_cause == GSM48_REJECT_PLMN_NOT_ALLOWED); @@ -946,7 +947,7 @@ static void test_dt_filter() int i; struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); struct bsc_nat_parsed *parsed; - struct bsc_nat_reject_cause cause; + struct bsc_filter_reject_cause cause; struct bsc_nat *nat = bsc_nat_alloc(); struct bsc_connection *bsc = bsc_connection_alloc(nat); @@ -991,7 +992,7 @@ static void test_dt_filter() if (!parsed) continue; - con->imsi_checked = 0; + con->filter_state.imsi_checked = 0; memset(&cause, 0, sizeof(cause)); bsc_nat_filter_dt(bsc, msg, con, parsed, &cause); } @@ -1453,21 +1454,21 @@ static void test_barr_list_parsing(void) if (lst == NULL) abort(); - rc = bsc_nat_barr_adapt(NULL, &root, lst); + rc = bsc_filter_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); + struct bsc_filter_barr_entry *entry; + entry = rb_entry(node, struct bsc_filter_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); + rc = bsc_filter_barr_find(&root, "12123119", &cm, &lu); if (!rc) { printf("Failed to find the IMSI.\n"); abort(); @@ -1479,7 +1480,7 @@ static void test_barr_list_parsing(void) } /* empty and check that it is empty */ - bsc_nat_barr_adapt(NULL, &root, NULL); + bsc_filter_barr_adapt(NULL, &root, NULL); if (!RB_EMPTY_ROOT(&root)) { printf("Failed to empty the list.\n"); abort(); @@ -1492,7 +1493,7 @@ static void test_barr_list_parsing(void) abort(); } - rc = bsc_nat_barr_adapt(NULL, &root, lst); + rc = bsc_filter_barr_adapt(NULL, &root, lst); if (rc != -1) { printf("It should have failed due dup\n"); abort(); @@ -1501,13 +1502,13 @@ static void test_barr_list_parsing(void) /* 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); + struct bsc_filter_barr_entry *entry; + entry = rb_entry(node, struct bsc_filter_barr_entry, node); printf("IMSI: %s CM: %d LU: %d\n", entry->imsi, entry->cm_reject_cause, entry->lu_reject_cause); } - rc = bsc_nat_barr_adapt(NULL, &root, NULL); + rc = bsc_filter_barr_adapt(NULL, &root, NULL); } static void test_nat_extract_lac() |