diff options
author | Holger Hans Peter Freyther <zecke@selfish.org> | 2012-01-18 20:00:28 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <zecke@selfish.org> | 2012-01-18 20:14:58 +0100 |
commit | 8e60f629e27f6a4cbb47479a1a69966c01890201 (patch) | |
tree | 7de85ad2d7cbe0d8f83eff89970f74229eede7c3 /openbsc | |
parent | be53012f9c14b1bf27b16f4fa2d0f58f8f0393ca (diff) |
nat: Prepare to rewrite the TP-DA number of a SMS submit.
Introduce number rewriting of SMS-SUBMIT. Introduce a new list,
move code around to help with finding a new number, somehow the
number encoding for TP-DA is borked, 03.40 references 04.11 but
the length appears to be strlen(number) without taken the type
field into account.
Diffstat (limited to 'openbsc')
-rw-r--r-- | openbsc/include/openbsc/bsc_nat.h | 2 | ||||
-rw-r--r-- | openbsc/src/osmo-bsc_nat/bsc_nat_utils.c | 149 | ||||
-rw-r--r-- | openbsc/tests/bsc-nat/bsc_data.c | 9 | ||||
-rw-r--r-- | openbsc/tests/bsc-nat/bsc_nat_test.c | 48 | ||||
-rw-r--r-- | openbsc/tests/bsc-nat/bsc_nat_test.ok | 1 |
5 files changed, 172 insertions, 37 deletions
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index b890a6842..df3841e6b 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -297,6 +297,8 @@ struct bsc_nat { struct llist_head tpdest_match; char *sms_clear_tp_srr_name; struct llist_head sms_clear_tp_srr; + char *sms_num_rewr_name; + struct llist_head sms_num_rewr; /* USSD messages we want to match */ char *ussd_lst_name; diff --git a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c index 8553113f2..36a7cfb07 100644 --- a/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c +++ b/openbsc/src/osmo-bsc_nat/bsc_nat_utils.c @@ -99,6 +99,7 @@ struct bsc_nat *bsc_nat_alloc(void) INIT_LLIST_HEAD(&nat->smsc_rewr); INIT_LLIST_HEAD(&nat->tpdest_match); INIT_LLIST_HEAD(&nat->sms_clear_tp_srr); + INIT_LLIST_HEAD(&nat->sms_num_rewr); nat->stats.sccp.conn = osmo_counter_alloc("nat.sccp.conn"); nat->stats.sccp.calls = osmo_counter_alloc("nat.sccp.calls"); @@ -781,22 +782,15 @@ int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg) return rc; } -static char *rewrite_non_international(struct bsc_nat *nat, void *ctx, const char *imsi, - struct gsm_mncc_number *called) +static char *match_and_rewrite_number(void *ctx, const char *number, + const char *imsi, + struct llist_head *list) { struct bsc_nat_num_rewr_entry *entry; char *new_number = NULL; - if (llist_empty(&nat->num_rewr)) - return NULL; - - if (called->plan != 1) - return NULL; - if (called->type == 1) - return NULL; - /* need to find a replacement and then fix it */ - llist_for_each_entry(entry, &nat->num_rewr, list) { + llist_for_each_entry(entry, list, list) { regmatch_t matches[2]; /* check the IMSI match */ @@ -804,11 +798,11 @@ static char *rewrite_non_international(struct bsc_nat *nat, void *ctx, const cha continue; /* this regexp matches... */ - if (regexec(&entry->num_reg, called->number, 2, matches, 0) == 0 && + if (regexec(&entry->num_reg, number, 2, matches, 0) == 0 && matches[1].rm_eo != -1) new_number = talloc_asprintf(ctx, "%s%s", entry->replace, - &called->number[matches[1].rm_so]); + &number[matches[1].rm_so]); if (new_number) break; } @@ -816,6 +810,21 @@ static char *rewrite_non_international(struct bsc_nat *nat, void *ctx, const cha return new_number; } +static char *rewrite_non_international(struct bsc_nat *nat, void *ctx, const char *imsi, + struct gsm_mncc_number *called) +{ + if (llist_empty(&nat->num_rewr)) + return NULL; + + if (called->plan != 1) + return NULL; + if (called->type == 1) + return NULL; + + return match_and_rewrite_number(ctx, called->number, + imsi, &nat->num_rewr); +} + /** * Rewrite non global numbers... according to rules based on the IMSI @@ -978,16 +987,53 @@ static uint8_t sms_new_tpdu_hdr(struct bsc_nat *nat, const char *imsi, return hdr; } +/** + * Check if we need to rewrite the number. For this SMS. + */ +static char *sms_new_dest_nr(struct bsc_nat *nat, void *ctx, + const char *imsi, const char *dest_nr) +{ + return match_and_rewrite_number(ctx, dest_nr, imsi, + &nat->sms_num_rewr); +} + +/** + * This is a helper for GSM 04.11 8.2.5.2 Destination address element + */ +void sms_encode_addr_element(struct msgb *out, const char *new_number, + int format, int tp_data) +{ + uint8_t new_addr_len; + uint8_t new_addr[26]; + + /* + * Copy the new number. We let libosmocore encode it, then set + * the extension followed after the length. Depending on if + * we want to write RP we will let the TLV code add the + * length for us or we need to use strlen... This is not very clear + * as of 03.40 and 04.11. + */ + new_addr_len = gsm48_encode_bcd_number(new_addr, ARRAY_SIZE(new_addr), + 1, new_number); + new_addr[1] = format; + if (tp_data) { + uint8_t *data = msgb_put(out, new_addr_len); + memcpy(data, new_addr, new_addr_len); + data[0] = strlen(new_number); + } else { + msgb_lv_put(out, new_addr_len - 1, new_addr + 1); + } +} + static struct msgb *sms_create_new(uint8_t type, uint8_t ref, struct gsm48_hdr *old_hdr48, const uint8_t *orig_addr_ptr, int orig_addr_len, const char *new_number, const uint8_t *data_ptr, int data_len, - uint8_t tpdu_first_byte) + uint8_t tpdu_first_byte, + const int old_dest_len, const char *new_dest_nr) { - uint8_t new_addr_len; struct gsm48_hdr *new_hdr48; - uint8_t new_addr[12]; struct msgb *out; /* @@ -1000,30 +1046,48 @@ static struct msgb *sms_create_new(uint8_t type, uint8_t ref, return NULL; } - out->l3h = out->data; + out->l2h = 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]. + sms_encode_addr_element(out, new_number, 0x91, 0); + + + /* Patch the TPDU from here on */ + + /** + * Do we need to put a new TP-Destination-Address (TP-DA) here or + * can we copy the old thing? For the TP-DA we need to find out the + * new size. */ - 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); + if (new_dest_nr) { + uint8_t *data, *new_size; + + /* reserve the size and write the header */ + new_size = msgb_put(out, 1); + out->l3h = new_size + 1; + msgb_v_put(out, tpdu_first_byte); + msgb_v_put(out, data_ptr[1]); + + /* encode the new number and put it */ + sms_encode_addr_element(out, new_dest_nr, 0x81, 1); - /* patch in the new TPDU header value */ - msgb_v_put(out, data_len); - msgb_tv_fixed_put(out, tpdu_first_byte, data_len - 1, &data_ptr[1]); + /* Copy the rest after the TP-DS */ + data = msgb_put(out, data_len - 2 - 1 - old_dest_len); + memcpy(data, &data_ptr[2 + 1 + old_dest_len], data_len - 2 - 1 - old_dest_len); + + /* fill in the new size */ + new_size[0] = msgb_l3len(out); + } else { + msgb_v_put(out, data_len); + msgb_tv_fixed_put(out, tpdu_first_byte, data_len - 1, &data_ptr[1]); + } /* prepend GSM 04.08 header */ new_hdr48 = (struct gsm48_hdr *) msgb_push(out, sizeof(*new_hdr48) + 1); memcpy(new_hdr48, old_hdr48, sizeof(*old_hdr48)); - new_hdr48->data[0] = msgb_l3len(out); + new_hdr48->data[0] = msgb_l2len(out); return out; } @@ -1045,9 +1109,10 @@ static struct msgb *rewrite_sms(struct bsc_nat *nat, struct msgb *msg, char smsc_addr[30]; - uint8_t dest_len; + uint8_t dest_len, orig_dest_len; char _dest_nr[30]; char *dest_nr; + char *new_dest_nr; char *new_number = NULL; uint8_t tpdu_hdr; @@ -1110,8 +1175,12 @@ static struct msgb *rewrite_sms(struct bsc_nat *nat, struct msgb *msg, if ((data_ptr[0] & 0x03) != GSM340_SMS_SUBMIT_MS2SC) return NULL; - /* look into the phone number */ - dest_len = data_ptr[2]; + /* + * look into the phone number. The length is in semi-octets, we will + * need to add the byte for the number type as well. + */ + orig_dest_len = data_ptr[2]; + dest_len = ((orig_dest_len + 1) / 2) + 1; if (data_len < dest_len + 3 || dest_len < 2) { LOGP(DNAT, LOGL_ERROR, "SMS-SUBMIT can not have TP-DestAddr.\n"); return NULL; @@ -1127,8 +1196,15 @@ static struct msgb *rewrite_sms(struct bsc_nat *nat, struct msgb *msg, return NULL; } + /** + * Besides of what I think I read in GSM 03.40 and 04.11 the TP-DA + * contains the semi-octets as length (strlen), change it to the + * the number of bytes, but then change it back. + */ + data_ptr[2] = dest_len; gsm48_decode_bcd_number(_dest_nr + 2, ARRAY_SIZE(_dest_nr) - 2, &data_ptr[2], 1); + data_ptr[2] = orig_dest_len; if ((data_ptr[3] & 0x70) == 0x10) { _dest_nr[0] = _dest_nr[1] = '0'; dest_nr = &_dest_nr[0]; @@ -1141,15 +1217,18 @@ static struct msgb *rewrite_sms(struct bsc_nat *nat, struct msgb *msg, */ tpdu_hdr = sms_new_tpdu_hdr(nat, imsi, dest_nr, data_ptr[0]); new_number = find_new_smsc(nat, msg, imsi, smsc_addr, dest_nr); + new_dest_nr = sms_new_dest_nr(nat, msg, imsi, dest_nr); - if (tpdu_hdr == data_ptr[0] && !new_number) + if (tpdu_hdr == data_ptr[0] && !new_number && !new_dest_nr) return NULL; out = sms_create_new(GSM411_MT_RP_DATA_MO, ref, hdr48, orig_addr_ptr, orig_addr_len, new_number ? new_number : smsc_addr, - data_ptr, data_len, tpdu_hdr); + data_ptr, data_len, tpdu_hdr, + dest_len, new_dest_nr); talloc_free(new_number); + talloc_free(new_dest_nr); return out; } diff --git a/openbsc/tests/bsc-nat/bsc_data.c b/openbsc/tests/bsc-nat/bsc_data.c index 08b900b83..d8a0c8706 100644 --- a/openbsc/tests/bsc-nat/bsc_data.c +++ b/openbsc/tests/bsc-nat/bsc_data.c @@ -127,6 +127,15 @@ static const uint8_t smsc_rewrite_patched_hdr[] = { 0xbf, 0xeb, 0x20 }; +static const uint8_t smsc_rewrite_num_patched[] = { +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, 0x21, 0x0c, 0x0f, 0x81, +0x00, 0x23, 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 ab97db1ee..c6187f9c5 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.c +++ b/openbsc/tests/bsc-nat/bsc_nat_test.c @@ -981,7 +981,7 @@ static void test_setup_rewrite() msgb_free(out); } -static void test_smsc_rewrite() +static void test_sms_smsc_rewrite() { struct msgb *msg = msgb_alloc(4096, "SMSC rewrite"), *out; struct bsc_nat_parsed *parsed; @@ -1076,6 +1076,49 @@ static void test_smsc_rewrite() msgb_free(out); } +static void test_sms_number_rewrite(void) +{ + 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 num_entries; + struct osmo_config_entry num_entry; + + INIT_LLIST_HEAD(&num_entries.entry); + num_entry.mcc = "^515039"; + num_entry.option = "^0049()"; + num_entry.text = "0032"; + llist_add_tail(&num_entry.list, &num_entries.entry); + + bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_num_rewr, &num_entries); + + printf("Testing SMS TP-DA rewriting.\n"); + + /* + * Check if the SMSC address is changed + */ + copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); + parsed = bsc_nat_parse(msg); + if (!parsed) { + printf("FAIL: Could not parse SMS\n"); + abort(); + } + + out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); + if (out == msg) { + printf("FAIL: This should have changed.\n"); + abort(); + } + + verify_msg(out, smsc_rewrite_num_patched, + ARRAY_SIZE(smsc_rewrite_num_patched)); + msgb_free(out); +} + int main(int argc, char **argv) { sccp_set_log_area(DSCCP); @@ -1091,7 +1134,8 @@ int main(int argc, char **argv) test_cr_filter(); test_dt_filter(); test_setup_rewrite(); - test_smsc_rewrite(); + test_sms_smsc_rewrite(); + test_sms_number_rewrite(); test_mgcp_allocations(); printf("Testing execution completed.\n"); diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.ok b/openbsc/tests/bsc-nat/bsc_nat_test.ok index f8eee238d..db37ffae6 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.ok +++ b/openbsc/tests/bsc-nat/bsc_nat_test.ok @@ -21,4 +21,5 @@ Testing MGCP response parsing. Testing SMSC rewriting. Attempting to only rewrite the HDR Attempting to change nothing. +Testing SMS TP-DA rewriting. Testing execution completed. |