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.
This commit is contained in:
parent
bbb102c1bb
commit
21e5c610c2
|
@ -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;
|
||||
|
|
|
@ -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,12 +782,37 @@ 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;
|
||||
|
||||
/* need to find a replacement and then fix it */
|
||||
llist_for_each_entry(entry, list, 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, number, 2, matches, 0) == 0 &&
|
||||
matches[1].rm_eo != -1)
|
||||
new_number = talloc_asprintf(ctx, "%s%s",
|
||||
entry->replace,
|
||||
&number[matches[1].rm_so]);
|
||||
if (new_number)
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -795,25 +821,8 @@ static char *rewrite_non_international(struct bsc_nat *nat, void *ctx, const cha
|
|||
if (called->type == 1)
|
||||
return NULL;
|
||||
|
||||
/* need to find a replacement and then fix it */
|
||||
llist_for_each_entry(entry, &nat->num_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, called->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]);
|
||||
if (new_number)
|
||||
break;
|
||||
}
|
||||
|
||||
return new_number;
|
||||
return match_and_rewrite_number(ctx, called->number,
|
||||
imsi, &nat->num_rewr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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].
|
||||
*/
|
||||
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);
|
||||
sms_encode_addr_element(out, new_number, 0x91, 0);
|
||||
|
||||
/* patch in the new TPDU header value */
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue