From ad75eababc153d513e75f7f052818ca02acd9533 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 27 May 2011 12:38:58 +0200 Subject: nat: Allow to have a regexp to match the MSISDN The idea that MCC and MNC is enough to classify a subscriber turns out to be wrong. Certain operatos license a number range of IMSIs to others. When we see a '^' in the MCC field we treat it as a regexp. The code now turns the MCC/MNC into a regexp for the IMSI. It is not using extended POSIX regexp to match the behavior of the access list. --- openbsc/include/openbsc/bsc_nat.h | 16 ++++- openbsc/src/osmo-bsc_nat/bsc_nat_utils.c | 116 ++++++++++++++++++++++++------- openbsc/src/osmo-bsc_nat/bsc_nat_vty.c | 14 ++-- openbsc/tests/bsc-nat/bsc_nat_test.c | 4 +- 4 files changed, 117 insertions(+), 33 deletions(-) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index c3f32eb35..650d1133c 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -267,7 +267,7 @@ struct bsc_nat { /* number rewriting */ char *num_rewr_name; - struct osmo_config_list *num_rewr; + struct llist_head num_rewr; /* USSD messages we want to match */ char *ussd_lst_name; @@ -394,4 +394,18 @@ void bsc_nat_paging_group_delete(struct bsc_nat_paging_group *); void bsc_nat_paging_group_add_lac(struct bsc_nat_paging_group *grp, int lac); void bsc_nat_paging_group_del_lac(struct bsc_nat_paging_group *grp, int lac); +/** + * Number rewriting support below + */ +struct bsc_nat_num_rewr_entry { + struct llist_head list; + + regex_t msisdn_reg; + regex_t num_reg; + + char *replace; +}; + +void bsc_nat_num_rewr_entry_adapt(struct bsc_nat *nat, const struct osmo_config_list *); + #endif diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c index 76b56f627..a7b00440a 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c @@ -94,6 +94,7 @@ struct bsc_nat *bsc_nat_alloc(void) INIT_LLIST_HEAD(&nat->bsc_configs); INIT_LLIST_HEAD(&nat->access_lists); INIT_LLIST_HEAD(&nat->dests); + INIT_LLIST_HEAD(&nat->num_rewr); nat->stats.sccp.conn = osmo_counter_alloc("nat.sccp.conn"); nat->stats.sccp.calls = osmo_counter_alloc("nat.sccp.calls"); @@ -801,10 +802,10 @@ int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg) static char *rewrite_non_international(struct bsc_nat *nat, void *ctx, const char *imsi, struct gsm_mncc_number *called) { - struct osmo_config_entry *entry; + struct bsc_nat_num_rewr_entry *entry; char *new_number = NULL; - if (!nat->num_rewr) + if (llist_empty(&nat->num_rewr)) return NULL; if (called->plan != 1) @@ -813,36 +814,19 @@ static char *rewrite_non_international(struct bsc_nat *nat, void *ctx, const cha return NULL; /* need to find a replacement and then fix it */ - llist_for_each_entry(entry, &nat->num_rewr->entry, list) { - regex_t reg; + llist_for_each_entry(entry, &nat->num_rewr, list) { regmatch_t matches[2]; - if (entry->mcc[0] != '*' && strncmp(entry->mcc, imsi, 3) != 0) + /* check the IMSI match */ + if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0) continue; - if (entry->mnc[0] != '*' && strncmp(entry->mnc, imsi + 3, 2) != 0) - continue; - - if (entry->text[0] == '+') { - LOGP(DNAT, LOGL_ERROR, - "Plus is not allowed in the number"); - continue; - } - - /* We have an entry for the IMSI. Need to match now */ - if (regcomp(®, entry->option, REG_EXTENDED) != 0) { - LOGP(DNAT, LOGL_ERROR, - "Regexp '%s' is not valid.\n", entry->option); - continue; - } /* this regexp matches... */ - if (regexec(®, called->number, 2, matches, 0) == 0 && + if (regexec(&entry->num_reg, called->number, 2, matches, 0) == 0 && matches[1].rm_eo != -1) new_number = talloc_asprintf(ctx, "%s%s", - entry->text, + entry->replace, &called->number[matches[1].rm_so]); - regfree(®); - if (new_number) break; } @@ -973,3 +957,87 @@ struct msgb *bsc_nat_rewrite_setup(struct bsc_nat *nat, struct msgb *msg, struct return sccp; } +static void num_rewr_free_data(struct bsc_nat_num_rewr_entry *entry) +{ + regfree(&entry->msisdn_reg); + regfree(&entry->num_reg); + talloc_free(entry->replace); +} + +void bsc_nat_num_rewr_entry_adapt(struct bsc_nat *nat, const struct osmo_config_list *list) +{ + struct bsc_nat_num_rewr_entry *entry, *tmp; + struct osmo_config_entry *cfg_entry; + + /* free the old data */ + llist_for_each_entry_safe(entry, tmp, &nat->num_rewr, list) { + num_rewr_free_data(entry); + llist_del(&entry->list); + talloc_free(entry); + } + + + if (!list) + return; + + llist_for_each_entry(cfg_entry, &list->entry, list) { + char *regexp; + if (cfg_entry->text[0] == '+') { + LOGP(DNAT, LOGL_ERROR, + "Plus is not allowed in the number\n"); + continue; + } + + entry = talloc_zero(nat, struct bsc_nat_num_rewr_entry); + if (!entry) { + LOGP(DNAT, LOGL_ERROR, + "Allication of the num_rewr entry failed.\n"); + continue; + } + + entry->replace = talloc_strdup(entry, cfg_entry->text); + if (!entry->replace) { + LOGP(DNAT, LOGL_ERROR, + "Failed to copy the replacement text.\n"); + talloc_free(entry); + continue; + } + + /* we will now build a regexp string */ + if (cfg_entry->mcc[0] == '^') { + regexp = talloc_strdup(entry, cfg_entry->mcc); + } else { + regexp = talloc_asprintf(entry, "^%s%s", + cfg_entry->mcc[0] == '*' ? + "[0-9][0-9][0-9]" : cfg_entry->mcc, + cfg_entry->mnc[0] == '*' ? + "[0-9][0-9]" : cfg_entry->mnc); + } + + if (!regexp) { + LOGP(DNAT, LOGL_ERROR, "Failed to create a regexp string.\n"); + talloc_free(entry); + continue; + } + + if (regcomp(&entry->msisdn_reg, regexp, 0) != 0) { + LOGP(DNAT, LOGL_ERROR, + "Failed to compile regexp '%s'\n", regexp); + talloc_free(regexp); + talloc_free(entry); + continue; + } + + talloc_free(regexp); + if (regcomp(&entry->num_reg, cfg_entry->option, REG_EXTENDED) != 0) { + LOGP(DNAT, LOGL_ERROR, + "Failed to compile regexp '%s\n'", cfg_entry->option); + regfree(&entry->msisdn_reg); + talloc_free(entry); + continue; + } + + /* we have copied the number */ + llist_add_tail(&entry->list, &nat->num_rewr); + } +} diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c index 0375cf800..38b5a0905 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c @@ -461,16 +461,16 @@ DEFUN(cfg_nat_number_rewrite, "number-rewrite FILENAME", "Set the file with rewriting rules.\n" "Filename") { + struct osmo_config_list *rewr = NULL; + bsc_replace_string(_nat, &_nat->num_rewr_name, argv[0]); if (_nat->num_rewr_name) { - if (_nat->num_rewr) - talloc_free(_nat->num_rewr); - _nat->num_rewr = osmo_config_list_parse(_nat, _nat->num_rewr_name); - return _nat->num_rewr == NULL ? CMD_WARNING : CMD_SUCCESS; + rewr = osmo_config_list_parse(_nat, _nat->num_rewr_name); + bsc_nat_num_rewr_entry_adapt(_nat, rewr); + talloc_free(rewr); + return CMD_SUCCESS; } else { - if (_nat->num_rewr) - talloc_free(_nat->num_rewr); - _nat->num_rewr = NULL; + bsc_nat_num_rewr_entry_adapt(_nat, NULL); return CMD_SUCCESS; } } diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c index 1645f705f..32f4f72ff 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.c +++ b/openbsc/tests/bsc-nat/bsc_nat_test.c @@ -854,7 +854,7 @@ static void test_setup_rewrite() entry.option = "^0([1-9])"; entry.text = "0049"; llist_add_tail(&entry.list, &entries.entry); - nat->num_rewr = &entries; + bsc_nat_num_rewr_entry_adapt(nat, &entries); /* verify that nothing changed */ msgb_reset(msg); @@ -917,6 +917,7 @@ static void test_setup_rewrite() /* Make sure that a wildcard is matching */ entry.mnc = "*"; + bsc_nat_num_rewr_entry_adapt(nat, &entries); msg = msgb_alloc(4096, "test_dt_filter"); copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); parsed = bsc_nat_parse(msg); @@ -951,6 +952,7 @@ static void test_setup_rewrite() /* Make sure that a wildcard is matching */ entry.mnc = "09"; + bsc_nat_num_rewr_entry_adapt(nat, &entries); msg = msgb_alloc(4096, "test_dt_filter"); copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); parsed = bsc_nat_parse(msg); -- cgit v1.2.3