aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2011-05-27 17:14:15 +0200
committerHolger Hans Peter Freyther <zecke@selfish.org>2011-06-01 20:45:03 +0200
commit9c20571280fb7cf61bb7211cce0dbbfed9fad7b9 (patch)
tree8fa179b3cc133b597f45687df502bef54c699207
parent2e2ff340216b015c71537daf3a4103bacc95cc14 (diff)
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.
-rw-r--r--openbsc/include/openbsc/bsc_nat.h5
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_nat_utils.c137
-rw-r--r--openbsc/src/osmo-bsc_nat/bsc_nat_vty.c4
-rw-r--r--openbsc/tests/bsc-nat/bsc_data.c22
-rw-r--r--openbsc/tests/bsc-nat/bsc_nat_test.c50
5 files changed, 208 insertions, 10 deletions
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index bf88e0af4..4506160e6 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -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
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
index 293271204..ae9891e04 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c
@@ -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);
}
}
diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
index 38b5a0905..f05ccaab1 100644
--- a/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
+++ b/openbsc/src/osmo-bsc_nat/bsc_nat_vty.c
@@ -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;
}
}
diff --git a/openbsc/tests/bsc-nat/bsc_data.c b/openbsc/tests/bsc-nat/bsc_data.c
index 04755233c..8a06348fd 100644
--- a/openbsc/tests/bsc-nat/bsc_data.c
+++ b/openbsc/tests/bsc-nat/bsc_data.c
@@ -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
*/
diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c
index c9432fefd..a31efcaef 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);
- 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;
}