nat: Patch the destination SMS address of a message
Use the same filtering infrasturcture to patch the SMSC address in a CP-DATA/RP-DATA message. Add a very simple testcase for this code.
This commit is contained in:
parent
2e2ff34021
commit
9c20571280
|
@ -269,6 +269,9 @@ struct bsc_nat {
|
|||
char *num_rewr_name;
|
||||
struct llist_head num_rewr;
|
||||
|
||||
char *smsc_rewr_name;
|
||||
struct llist_head smsc_rewr;
|
||||
|
||||
/* USSD messages we want to match */
|
||||
char *ussd_lst_name;
|
||||
char *ussd_query;
|
||||
|
@ -406,6 +409,6 @@ struct bsc_nat_num_rewr_entry {
|
|||
char *replace;
|
||||
};
|
||||
|
||||
void bsc_nat_num_rewr_entry_adapt(struct bsc_nat *nat, const struct osmo_config_list *);
|
||||
void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head, const struct osmo_config_list *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#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>
|
||||
|
||||
|
@ -95,6 +96,7 @@ struct bsc_nat *bsc_nat_alloc(void)
|
|||
INIT_LLIST_HEAD(&nat->access_lists);
|
||||
INIT_LLIST_HEAD(&nat->dests);
|
||||
INIT_LLIST_HEAD(&nat->num_rewr);
|
||||
INIT_LLIST_HEAD(&nat->smsc_rewr);
|
||||
|
||||
nat->stats.sccp.conn = osmo_counter_alloc("nat.sccp.conn");
|
||||
nat->stats.sccp.calls = osmo_counter_alloc("nat.sccp.calls");
|
||||
|
@ -919,6 +921,130 @@ static struct msgb *rewrite_setup(struct bsc_nat *nat, struct msgb *msg,
|
|||
return out;
|
||||
}
|
||||
|
||||
static struct msgb *rewrite_smsc(struct bsc_nat *nat, struct msgb *msg,
|
||||
struct bsc_nat_parsed *parsed, const char *imsi,
|
||||
struct gsm48_hdr *hdr48, const uint32_t len)
|
||||
{
|
||||
unsigned int payload_len;
|
||||
unsigned int cp_len;
|
||||
|
||||
uint8_t ref;
|
||||
uint8_t orig_addr_len, *orig_addr_ptr;
|
||||
uint8_t dest_addr_len, *dest_addr_ptr;
|
||||
uint8_t data_len, *data_ptr;
|
||||
char smsc_addr[30];
|
||||
uint8_t new_addr[12];
|
||||
|
||||
struct bsc_nat_num_rewr_entry *entry;
|
||||
char *new_number = NULL;
|
||||
uint8_t new_addr_len;
|
||||
struct gsm48_hdr *new_hdr48;
|
||||
struct msgb *out;
|
||||
|
||||
payload_len = len - sizeof(*hdr48);
|
||||
if (payload_len < 1) {
|
||||
LOGP(DNAT, LOGL_ERROR, "SMS too short for things. %d\n", payload_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cp_len = hdr48->data[0];
|
||||
if (payload_len + 1 < cp_len) {
|
||||
LOGP(DNAT, LOGL_ERROR, "SMS RPDU can not fit in: %d %d\n", cp_len, payload_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (hdr48->data[1] != GSM411_MT_RP_DATA_MO)
|
||||
return NULL;
|
||||
|
||||
if (cp_len < 5) {
|
||||
LOGP(DNAT, LOGL_ERROR, "RD-DATA can not fit in the CP len: %d\n", cp_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ref = hdr48->data[2];
|
||||
orig_addr_len = hdr48->data[3];
|
||||
orig_addr_ptr = &hdr48->data[4];
|
||||
|
||||
/* the +1 is for checking if the following element has some space */
|
||||
if (cp_len < 3 + orig_addr_len + 1) {
|
||||
LOGP(DNAT, LOGL_ERROR, "RP-Originator addr does not fit: %d\n", orig_addr_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dest_addr_len = hdr48->data[3 + orig_addr_len + 1];
|
||||
dest_addr_ptr = &hdr48->data[3 + orig_addr_len + 2];
|
||||
|
||||
if (cp_len < 3 + orig_addr_len + 1 + dest_addr_len + 1) {
|
||||
LOGP(DNAT, LOGL_ERROR, "RP-Destination addr does not fit: %d\n", dest_addr_len);
|
||||
return NULL;
|
||||
}
|
||||
gsm48_decode_bcd_number(smsc_addr, ARRAY_SIZE(smsc_addr), dest_addr_ptr - 1, 1);
|
||||
|
||||
data_len = hdr48->data[3 + orig_addr_len + 1 + dest_addr_len + 1];
|
||||
data_ptr = &hdr48->data[3 + orig_addr_len + 1 + dest_addr_len + 2];
|
||||
|
||||
if (cp_len < 3 + orig_addr_len + 1 + dest_addr_len + 1 + data_len) {
|
||||
LOGP(DNAT, LOGL_ERROR, "RP-Data does not fit: %d\n", data_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We will find a new number now */
|
||||
llist_for_each_entry(entry, &nat->smsc_rewr, list) {
|
||||
regmatch_t matches[2];
|
||||
|
||||
/* check the IMSI match */
|
||||
if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0)
|
||||
continue;
|
||||
|
||||
/* this regexp matches... */
|
||||
if (regexec(&entry->num_reg, smsc_addr, 2, matches, 0) == 0 &&
|
||||
matches[1].rm_eo != -1)
|
||||
new_number = talloc_asprintf(msg, "%s%s",
|
||||
entry->replace,
|
||||
&smsc_addr[matches[1].rm_so]);
|
||||
if (new_number)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!new_number)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* We need to re-create the patched structure. This is why we have
|
||||
* saved the above pointers.
|
||||
*/
|
||||
out = msgb_alloc_headroom(4096, 128, "changed-smsc");
|
||||
if (!out) {
|
||||
LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out->l3h = out->data;
|
||||
msgb_v_put(out, GSM411_MT_RP_DATA_MO);
|
||||
msgb_v_put(out, ref);
|
||||
msgb_lv_put(out, orig_addr_len, orig_addr_ptr);
|
||||
|
||||
/*
|
||||
* Copy the new number. We let libosmocore encode it, then set
|
||||
* the extension followed after the length. For our convenience
|
||||
* we let the TLV code re-add the length so we start copying
|
||||
* from &new_addr[1].
|
||||
*/
|
||||
new_addr_len = gsm48_encode_bcd_number(new_addr, ARRAY_SIZE(new_addr),
|
||||
1, new_number);
|
||||
new_addr[1] = 0x91;
|
||||
msgb_lv_put(out, new_addr_len - 1, new_addr + 1);
|
||||
|
||||
msgb_lv_put(out, data_len, data_ptr);
|
||||
|
||||
new_hdr48 = (struct gsm48_hdr *) msgb_push(out, sizeof(*hdr48) + 1);
|
||||
memcpy(new_hdr48, hdr48, sizeof(*hdr48));
|
||||
new_hdr48->data[0] = msgb_l3len(out);
|
||||
|
||||
talloc_free(new_number);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct msgb *bsc_nat_rewrite_msg(struct bsc_nat *nat, struct msgb *msg, struct bsc_nat_parsed *parsed, const char *imsi)
|
||||
{
|
||||
struct gsm48_hdr *hdr48;
|
||||
|
@ -944,6 +1070,8 @@ struct msgb *bsc_nat_rewrite_msg(struct bsc_nat *nat, struct msgb *msg, struct b
|
|||
|
||||
if (proto == GSM48_PDISC_CC && msg_type == GSM48_MT_CC_SETUP)
|
||||
new_msg = rewrite_setup(nat, msg, parsed, imsi, hdr48, len);
|
||||
else if (proto == GSM48_PDISC_SMS && msg_type == GSM411_MT_CP_DATA)
|
||||
new_msg = rewrite_smsc(nat, msg, parsed, imsi, hdr48, len);
|
||||
|
||||
if (!new_msg)
|
||||
return msg;
|
||||
|
@ -973,13 +1101,14 @@ static void num_rewr_free_data(struct bsc_nat_num_rewr_entry *entry)
|
|||
talloc_free(entry->replace);
|
||||
}
|
||||
|
||||
void bsc_nat_num_rewr_entry_adapt(struct bsc_nat *nat, const struct osmo_config_list *list)
|
||||
void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head,
|
||||
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) {
|
||||
llist_for_each_entry_safe(entry, tmp, head, list) {
|
||||
num_rewr_free_data(entry);
|
||||
llist_del(&entry->list);
|
||||
talloc_free(entry);
|
||||
|
@ -997,7 +1126,7 @@ void bsc_nat_num_rewr_entry_adapt(struct bsc_nat *nat, const struct osmo_config_
|
|||
continue;
|
||||
}
|
||||
|
||||
entry = talloc_zero(nat, struct bsc_nat_num_rewr_entry);
|
||||
entry = talloc_zero(ctx, struct bsc_nat_num_rewr_entry);
|
||||
if (!entry) {
|
||||
LOGP(DNAT, LOGL_ERROR,
|
||||
"Allication of the num_rewr entry failed.\n");
|
||||
|
@ -1047,6 +1176,6 @@ void bsc_nat_num_rewr_entry_adapt(struct bsc_nat *nat, const struct osmo_config_
|
|||
}
|
||||
|
||||
/* we have copied the number */
|
||||
llist_add_tail(&entry->list, &nat->num_rewr);
|
||||
llist_add_tail(&entry->list, head);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -466,11 +466,11 @@ DEFUN(cfg_nat_number_rewrite,
|
|||
bsc_replace_string(_nat, &_nat->num_rewr_name, argv[0]);
|
||||
if (_nat->num_rewr_name) {
|
||||
rewr = osmo_config_list_parse(_nat, _nat->num_rewr_name);
|
||||
bsc_nat_num_rewr_entry_adapt(_nat, rewr);
|
||||
bsc_nat_num_rewr_entry_adapt(_nat, &_nat->num_rewr, rewr);
|
||||
talloc_free(rewr);
|
||||
return CMD_SUCCESS;
|
||||
} else {
|
||||
bsc_nat_num_rewr_entry_adapt(_nat, NULL);
|
||||
bsc_nat_num_rewr_entry_adapt(_nat, &_nat->num_rewr, NULL);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,28 @@ static const uint8_t id_resp[] = {
|
|||
0x31
|
||||
};
|
||||
|
||||
/* sms code msg */
|
||||
static const uint8_t smsc_rewrite[] = {
|
||||
0x00, 0x30, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00,
|
||||
0x01, 0x29, 0x01, 0x03, 0x26, 0x09, 0x01, 0x23,
|
||||
0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08,
|
||||
0x00, 0x10, 0x50, 0x17, 0x01, 0x0c, 0x0f, 0x81,
|
||||
0x00, 0x94, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5,
|
||||
0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca,
|
||||
0xbf, 0xeb, 0x20
|
||||
};
|
||||
|
||||
static const uint8_t smsc_rewrite_patched[] = {
|
||||
0x00, 0x31, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00,
|
||||
0x01, 0x2a, 0x01, 0x00, 0x27, 0x09, 0x01, 0x24,
|
||||
0x00, 0x0c, 0x00, 0x08, 0x91, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x66, 0xf7, 0x17, 0x01, 0x0c, 0x0f,
|
||||
0x81, 0x00, 0x94, 0x51, 0x87, 0x86, 0x78, 0x46,
|
||||
0xf5, 0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c,
|
||||
0xca, 0xbf, 0xeb, 0x20
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* MGCP messages
|
||||
*/
|
||||
|
|
|
@ -854,7 +854,7 @@ static void test_setup_rewrite()
|
|||
entry.option = "^0([1-9])";
|
||||
entry.text = "0049";
|
||||
llist_add_tail(&entry.list, &entries.entry);
|
||||
bsc_nat_num_rewr_entry_adapt(nat, &entries);
|
||||
bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries);
|
||||
|
||||
/* verify that nothing changed */
|
||||
msgb_reset(msg);
|
||||
|
@ -917,7 +917,7 @@ static void test_setup_rewrite()
|
|||
|
||||
/* Make sure that a wildcard is matching */
|
||||
entry.mnc = "*";
|
||||
bsc_nat_num_rewr_entry_adapt(nat, &entries);
|
||||
bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &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);
|
||||
|
@ -952,7 +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);
|
||||
bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &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);
|
||||
|
@ -980,6 +980,49 @@ static void test_setup_rewrite()
|
|||
msgb_free(out);
|
||||
}
|
||||
|
||||
static void test_smsc_rewrite()
|
||||
{
|
||||
struct msgb *msg = msgb_alloc(4096, "SMSC rewrite"), *out;
|
||||
struct bsc_nat_parsed *parsed;
|
||||
const char *imsi = "515039900406700";
|
||||
|
||||
struct bsc_nat *nat = bsc_nat_alloc();
|
||||
|
||||
/* a fake list */
|
||||
struct osmo_config_list entries;
|
||||
struct osmo_config_entry entry;
|
||||
|
||||
INIT_LLIST_HEAD(&entries.entry);
|
||||
entry.mcc = "^515039";
|
||||
entry.option = "639180000105()";
|
||||
entry.text = "6666666666667";
|
||||
llist_add_tail(&entry.list, &entries.entry);
|
||||
bsc_nat_num_rewr_entry_adapt(nat, &nat->smsc_rewr, &entries);
|
||||
|
||||
copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite));
|
||||
parsed = bsc_nat_parse(msg);
|
||||
if (!parsed) {
|
||||
fprintf(stderr, "FAIL: Could not parse SMS\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi);
|
||||
if (out == msg) {
|
||||
fprintf(stderr, "FAIL: This should have changed.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (out->len != ARRAY_SIZE(smsc_rewrite_patched)) {
|
||||
fprintf(stderr, "FAIL: The size should match.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (memcmp(out->data, smsc_rewrite_patched, out->len) != 0) {
|
||||
fprintf(stderr, "FAIL: the data should be changed.\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
sccp_set_log_area(DSCCP);
|
||||
|
@ -995,6 +1038,7 @@ int main(int argc, char **argv)
|
|||
test_cr_filter();
|
||||
test_dt_filter();
|
||||
test_setup_rewrite();
|
||||
test_smsc_rewrite();
|
||||
test_mgcp_allocations();
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue