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:
Holger Hans Peter Freyther 2012-01-18 20:00:28 +01:00
parent be53012f9c
commit 8e60f629e2
5 changed files with 181 additions and 46 deletions

View File

@ -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;

View File

@ -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 */
msgb_v_put(out, data_len);
msgb_tv_fixed_put(out, tpdu_first_byte, data_len - 1, &data_ptr[1]);
/* 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;
}

View File

@ -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

View File

@ -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");

View File

@ -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.