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.
This commit is contained in:
parent
384ef09920
commit
ad75eababc
|
@ -267,7 +267,7 @@ struct bsc_nat {
|
||||||
|
|
||||||
/* number rewriting */
|
/* number rewriting */
|
||||||
char *num_rewr_name;
|
char *num_rewr_name;
|
||||||
struct osmo_config_list *num_rewr;
|
struct llist_head num_rewr;
|
||||||
|
|
||||||
/* USSD messages we want to match */
|
/* USSD messages we want to match */
|
||||||
char *ussd_lst_name;
|
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_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);
|
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
|
#endif
|
||||||
|
|
|
@ -94,6 +94,7 @@ struct bsc_nat *bsc_nat_alloc(void)
|
||||||
INIT_LLIST_HEAD(&nat->bsc_configs);
|
INIT_LLIST_HEAD(&nat->bsc_configs);
|
||||||
INIT_LLIST_HEAD(&nat->access_lists);
|
INIT_LLIST_HEAD(&nat->access_lists);
|
||||||
INIT_LLIST_HEAD(&nat->dests);
|
INIT_LLIST_HEAD(&nat->dests);
|
||||||
|
INIT_LLIST_HEAD(&nat->num_rewr);
|
||||||
|
|
||||||
nat->stats.sccp.conn = osmo_counter_alloc("nat.sccp.conn");
|
nat->stats.sccp.conn = osmo_counter_alloc("nat.sccp.conn");
|
||||||
nat->stats.sccp.calls = osmo_counter_alloc("nat.sccp.calls");
|
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,
|
static char *rewrite_non_international(struct bsc_nat *nat, void *ctx, const char *imsi,
|
||||||
struct gsm_mncc_number *called)
|
struct gsm_mncc_number *called)
|
||||||
{
|
{
|
||||||
struct osmo_config_entry *entry;
|
struct bsc_nat_num_rewr_entry *entry;
|
||||||
char *new_number = NULL;
|
char *new_number = NULL;
|
||||||
|
|
||||||
if (!nat->num_rewr)
|
if (llist_empty(&nat->num_rewr))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (called->plan != 1)
|
if (called->plan != 1)
|
||||||
|
@ -813,36 +814,19 @@ static char *rewrite_non_international(struct bsc_nat *nat, void *ctx, const cha
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* need to find a replacement and then fix it */
|
/* need to find a replacement and then fix it */
|
||||||
llist_for_each_entry(entry, &nat->num_rewr->entry, list) {
|
llist_for_each_entry(entry, &nat->num_rewr, list) {
|
||||||
regex_t reg;
|
|
||||||
regmatch_t matches[2];
|
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;
|
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... */
|
/* 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)
|
matches[1].rm_eo != -1)
|
||||||
new_number = talloc_asprintf(ctx, "%s%s",
|
new_number = talloc_asprintf(ctx, "%s%s",
|
||||||
entry->text,
|
entry->replace,
|
||||||
&called->number[matches[1].rm_so]);
|
&called->number[matches[1].rm_so]);
|
||||||
regfree(®);
|
|
||||||
|
|
||||||
if (new_number)
|
if (new_number)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -973,3 +957,87 @@ struct msgb *bsc_nat_rewrite_setup(struct bsc_nat *nat, struct msgb *msg, struct
|
||||||
return sccp;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -461,16 +461,16 @@ DEFUN(cfg_nat_number_rewrite,
|
||||||
"number-rewrite FILENAME",
|
"number-rewrite FILENAME",
|
||||||
"Set the file with rewriting rules.\n" "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]);
|
bsc_replace_string(_nat, &_nat->num_rewr_name, argv[0]);
|
||||||
if (_nat->num_rewr_name) {
|
if (_nat->num_rewr_name) {
|
||||||
if (_nat->num_rewr)
|
rewr = osmo_config_list_parse(_nat, _nat->num_rewr_name);
|
||||||
talloc_free(_nat->num_rewr);
|
bsc_nat_num_rewr_entry_adapt(_nat, rewr);
|
||||||
_nat->num_rewr = osmo_config_list_parse(_nat, _nat->num_rewr_name);
|
talloc_free(rewr);
|
||||||
return _nat->num_rewr == NULL ? CMD_WARNING : CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
if (_nat->num_rewr)
|
bsc_nat_num_rewr_entry_adapt(_nat, NULL);
|
||||||
talloc_free(_nat->num_rewr);
|
|
||||||
_nat->num_rewr = NULL;
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -854,7 +854,7 @@ static void test_setup_rewrite()
|
||||||
entry.option = "^0([1-9])";
|
entry.option = "^0([1-9])";
|
||||||
entry.text = "0049";
|
entry.text = "0049";
|
||||||
llist_add_tail(&entry.list, &entries.entry);
|
llist_add_tail(&entry.list, &entries.entry);
|
||||||
nat->num_rewr = &entries;
|
bsc_nat_num_rewr_entry_adapt(nat, &entries);
|
||||||
|
|
||||||
/* verify that nothing changed */
|
/* verify that nothing changed */
|
||||||
msgb_reset(msg);
|
msgb_reset(msg);
|
||||||
|
@ -917,6 +917,7 @@ static void test_setup_rewrite()
|
||||||
|
|
||||||
/* Make sure that a wildcard is matching */
|
/* Make sure that a wildcard is matching */
|
||||||
entry.mnc = "*";
|
entry.mnc = "*";
|
||||||
|
bsc_nat_num_rewr_entry_adapt(nat, &entries);
|
||||||
msg = msgb_alloc(4096, "test_dt_filter");
|
msg = msgb_alloc(4096, "test_dt_filter");
|
||||||
copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national));
|
copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national));
|
||||||
parsed = bsc_nat_parse(msg);
|
parsed = bsc_nat_parse(msg);
|
||||||
|
@ -951,6 +952,7 @@ static void test_setup_rewrite()
|
||||||
|
|
||||||
/* Make sure that a wildcard is matching */
|
/* Make sure that a wildcard is matching */
|
||||||
entry.mnc = "09";
|
entry.mnc = "09";
|
||||||
|
bsc_nat_num_rewr_entry_adapt(nat, &entries);
|
||||||
msg = msgb_alloc(4096, "test_dt_filter");
|
msg = msgb_alloc(4096, "test_dt_filter");
|
||||||
copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national));
|
copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national));
|
||||||
parsed = bsc_nat_parse(msg);
|
parsed = bsc_nat_parse(msg);
|
||||||
|
|
Loading…
Reference in New Issue