aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2013-01-01 11:25:09 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2013-01-07 15:02:34 +0100
commit1f8276e5885f070ec1b0d74c28fc9464bbfe5f8a (patch)
tree6a0f7b3b5d57a009935dd268e1e1c5eb80740c03 /openbsc/src/osmo-bsc_nat/bsc_nat_filter.c
parent0434faedc947d92a5e575c20cf3c4da568a4615a (diff)
nat: Introduce a global IMSI barr list using red-black trees
Diffstat (limited to 'openbsc/src/osmo-bsc_nat/bsc_nat_filter.c')
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_nat_filter.c124
1 files changed, 111 insertions, 13 deletions
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c b/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c
index e3e63d13d..5ab3a971d 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_filter.c
@@ -37,6 +37,91 @@
#include <osmocom/sccp/sccp.h>
+int bsc_nat_barr_find(struct rb_root *root, const char *imsi, int *cm, int *lu)
+{
+ struct bsc_nat_barr_entry *n;
+ n = rb_entry(root->rb_node, struct bsc_nat_barr_entry, node);
+
+ while (n) {
+ int rc = strcmp(imsi, n->imsi);
+ if (rc == 0) {
+ *cm = n->cm_reject_cause;
+ *lu = n->lu_reject_cause;
+ return 1;
+ }
+
+ n = rb_entry(
+ (rc < 0) ? n->node.rb_left : n->node.rb_right,
+ struct bsc_nat_barr_entry, node);
+ };
+
+ return 0;
+}
+
+static int insert_barr_node(struct bsc_nat_barr_entry *entry, struct rb_root *root)
+{
+ struct rb_node **new = &root->rb_node, *parent = NULL;
+
+ while (*new) {
+ int rc;
+ struct bsc_nat_barr_entry *this;
+ this = rb_entry(*new, struct bsc_nat_barr_entry, node);
+ parent = *new;
+
+ rc = strcmp(entry->imsi, this->imsi);
+ if (rc < 0)
+ new = &((*new)->rb_left);
+ else if (rc > 0)
+ new = &((*new)->rb_right);
+ else {
+ LOGP(DNAT, LOGL_ERROR,
+ "Duplicate entry for IMSI(%s)\n", entry->imsi);
+ talloc_free(entry);
+ return -1;
+ }
+ }
+
+ rb_link_node(&entry->node, parent, new);
+ rb_insert_color(&entry->node, root);
+ return 0;
+}
+
+int bsc_nat_barr_adapt(void *ctx, struct rb_root *root,
+ const struct osmo_config_list *list)
+{
+ struct osmo_config_entry *cfg_entry;
+ int err = 0;
+
+ /* free the old data */
+ while (!RB_EMPTY_ROOT(root)) {
+ struct rb_node *node = rb_first(root);
+ rb_erase(node, root);
+ talloc_free(node);
+ }
+
+ if (!list)
+ return 0;
+
+ /* now adapt the new list */
+ llist_for_each_entry(cfg_entry, &list->entry, list) {
+ struct bsc_nat_barr_entry *entry;
+ entry = talloc_zero(ctx, struct bsc_nat_barr_entry);
+ if (!entry) {
+ LOGP(DNAT, LOGL_ERROR,
+ "Allocation of the barr entry failed.\n");
+ continue;
+ }
+
+ entry->imsi = talloc_strdup(entry, cfg_entry->mcc);
+ entry->cm_reject_cause = atoi(cfg_entry->mnc);
+ entry->lu_reject_cause = atoi(cfg_entry->option);
+ err |= insert_barr_node(entry, root);
+ }
+
+ return err;
+}
+
+
static int lst_check_deny(struct bsc_nat_acc_lst *lst, const char *mi_string)
{
struct bsc_nat_acc_lst_entry *entry;
@@ -52,43 +137,56 @@ static int lst_check_deny(struct bsc_nat_acc_lst *lst, const char *mi_string)
}
/* apply white/black list */
-static int auth_imsi(struct bsc_connection *bsc, const char *mi_string,
+static int auth_imsi(struct bsc_connection *bsc, const char *imsi,
struct bsc_nat_reject_cause *cause)
{
/*
* Now apply blacklist/whitelist of the BSC and the NAT.
- * 1.) Allow directly if the IMSI is allowed at the BSC
- * 2.) Reject if the IMSI is not allowed at the BSC
- * 3.) Reject if the IMSI not allowed at the global level.
- * 4.) Allow directly if the IMSI is allowed at the global level
+ * 1.) Check the global IMSI barr list
+ * 2.) Allow directly if the IMSI is allowed at the BSC
+ * 3.) Reject if the IMSI is not allowed at the BSC
+ * 4.) Reject if the IMSI not allowed at the global level.
+ * 5.) Allow directly if the IMSI is allowed at the global level
*/
+ int cm, lu;
struct bsc_nat_acc_lst *nat_lst = NULL;
struct bsc_nat_acc_lst *bsc_lst = NULL;
+ /* 1. global check for barred imsis */
+ if (bsc_nat_barr_find(&bsc->nat->imsi_black_list, imsi, &cm, &lu)) {
+ cause->cm_reject_cause = cm;
+ cause->lu_reject_cause = lu;
+ LOGP(DNAT, LOGL_DEBUG,
+ "Blocking subscriber IMSI %s with CM: %d LU: %d\n",
+ imsi, cm, lu);
+ return -1;
+ }
+
+
bsc_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->cfg->acc_lst_name);
nat_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->nat->acc_lst_name);
if (bsc_lst) {
- /* 1. BSC allow */
- if (bsc_nat_lst_check_allow(bsc_lst, mi_string) == 0)
+ /* 2. BSC allow */
+ if (bsc_nat_lst_check_allow(bsc_lst, imsi) == 0)
return 1;
- /* 2. BSC deny */
- if (lst_check_deny(bsc_lst, mi_string) == 0) {
+ /* 3. BSC deny */
+ if (lst_check_deny(bsc_lst, imsi) == 0) {
LOGP(DNAT, LOGL_ERROR,
- "Filtering %s by imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
+ "Filtering %s by imsi_deny on bsc nr: %d.\n", imsi, bsc->cfg->nr);
rate_ctr_inc(&bsc_lst->stats->ctr[ACC_LIST_BSC_FILTER]);
return -2;
}
}
- /* 3. NAT deny */
+ /* 4. NAT deny */
if (nat_lst) {
- if (lst_check_deny(nat_lst, mi_string) == 0) {
+ if (lst_check_deny(nat_lst, imsi) == 0) {
LOGP(DNAT, LOGL_ERROR,
- "Filtering %s by nat imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
+ "Filtering %s by nat imsi_deny on bsc nr: %d.\n", imsi, bsc->cfg->nr);
rate_ctr_inc(&nat_lst->stats->ctr[ACC_LIST_NAT_FILTER]);
return -3;
}