From 3268540fc38c5181921ad427f84f36d412d061f7 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 15 Sep 2010 05:20:40 +0800 Subject: [PATCH] nat: Parse the id response, extract the IMSI, compare it Add a test case and also add a basic check that we got some size checks correct. The next step is to act on the result. --- openbsc/src/nat/bsc_nat_utils.c | 59 +++++++++++++++++++++++++++- openbsc/tests/bsc-nat/bsc_data.c | 8 ++++ openbsc/tests/bsc-nat/bsc_nat_test.c | 54 +++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/openbsc/src/nat/bsc_nat_utils.c b/openbsc/src/nat/bsc_nat_utils.c index 7387b517a..a5917371b 100644 --- a/openbsc/src/nat/bsc_nat_utils.c +++ b/openbsc/src/nat/bsc_nat_utils.c @@ -369,6 +369,35 @@ static int _cr_check_pag_resp(struct bsc_connection *bsc, uint8_t *data, unsigne return auth_imsi(bsc, mi_string); } +static int _dt_check_id_resp(struct bsc_connection *bsc, + uint8_t *data, unsigned int length, + struct sccp_connections *con) +{ + char mi_string[GSM48_MI_SIZE]; + uint8_t mi_type; + int ret; + + if (length < 2) { + LOGP(DNAT, LOGL_ERROR, "mi does not fit.\n"); + return -1; + } + + if (data[0] < length - 1) { + LOGP(DNAT, LOGL_ERROR, "mi length too big.\n"); + return -2; + } + + mi_type = data[1] & GSM_MI_TYPE_MASK; + gsm48_mi_to_string(mi_string, sizeof(mi_string), &data[1], data[0]); + + if (mi_type != GSM_MI_TYPE_IMSI) + return 0; + + ret = auth_imsi(bsc, mi_string); + con->imsi_checked = 1; + return ret; +} + /* Filter out CR data... */ int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed, int *con_type) { @@ -434,10 +463,38 @@ int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, struct int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg, struct sccp_connections *con, struct bsc_nat_parsed *parsed) { + uint32_t len; + struct gsm48_hdr *hdr48; + if (con->imsi_checked) return 0; - return 0; + /* only care about DTAP messages */ + if (parsed->bssap != BSSAP_MSG_DTAP) + return 0; + + /* gsm_type is actually the size of the dtap */ + len = parsed->gsm_type; + if (len < msgb_l3len(msg) - 3) { + LOGP(DNAT, LOGL_ERROR, "Not enough space for DTAP.\n"); + return -1; + } + + if (len < sizeof(*hdr48)) { + LOGP(DNAT, LOGL_ERROR, "GSM48 header does not fit.\n"); + return -1; + } + + msg->l4h = &msg->l3h[3]; + hdr48 = (struct gsm48_hdr *) msg->l4h; + + if (hdr48->proto_discr == GSM48_PDISC_MM && + (hdr48->msg_type & 0xbf) == GSM48_MT_MM_ID_RESP) { + return _dt_check_id_resp(bsc, &hdr48->data[0], len - sizeof(*hdr48), con); + } else { + printf("%d %x\n", hdr48->proto_discr, hdr48->msg_type); + return 0; + } } void bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv) diff --git a/openbsc/tests/bsc-nat/bsc_data.c b/openbsc/tests/bsc-nat/bsc_data.c index a3239799c..1bc15c873 100644 --- a/openbsc/tests/bsc-nat/bsc_data.c +++ b/openbsc/tests/bsc-nat/bsc_data.c @@ -88,6 +88,14 @@ static const uint8_t ass_cmd[] = { 0x01, 0x0b, 0x03, 0x01, 0x0a, 0x11, 0x01, 0x00, 0x15 }; +/* identity response */ +static const uint8_t id_resp[] = { +0x00, 0x15, 0xfd, 0x06, 0x01, 0x1c, 0xdc, +0x00, 0x01, 0x0e, 0x01, 0x00, 0x0b, 0x05, 0x59, +0x08, 0x29, 0x40, 0x21, 0x03, 0x07, 0x48, 0x66, +0x31 +}; + /* * MGCP messages */ diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c index 0e936edfc..926c97cd7 100644 --- a/openbsc/tests/bsc-nat/bsc_nat_test.c +++ b/openbsc/tests/bsc-nat/bsc_nat_test.c @@ -31,6 +31,7 @@ #include #include +#include #include @@ -696,6 +697,58 @@ static void test_cr_filter() msgb_free(msg); } +static void test_dt_filter() +{ + int i; + struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); + struct bsc_nat_parsed *parsed; + + struct bsc_nat *nat = bsc_nat_alloc(); + struct bsc_connection *bsc = bsc_connection_alloc(nat); + struct sccp_connections *con = talloc_zero(0, struct sccp_connections); + + bsc->cfg = bsc_config_alloc(nat, "foo", 23); + con->bsc = bsc; + + msgb_reset(msg); + copy_to_msg(msg, id_resp, ARRAY_SIZE(id_resp)); + + parsed = bsc_nat_parse(msg); + if (!parsed) { + fprintf(stderr, "FAIL: Could not parse ID resp\n"); + abort(); + } + + if (parsed->bssap != BSSAP_MSG_DTAP) { + fprintf(stderr, "FAIL: It should be dtap\n"); + abort(); + } + + /* gsm_type is actually the size of the dtap */ + if (parsed->gsm_type < msgb_l3len(msg) - 3) { + fprintf(stderr, "FAIL: Not enough space for the content\n"); + abort(); + } + + if (bsc_nat_filter_dt(bsc, msg, con, parsed) != 1) { + fprintf(stderr, "FAIL: Should have passed..\n"); + abort(); + } + + /* just some basic length checking... */ + for (i = ARRAY_SIZE(id_resp); i >= 0; --i) { + msgb_reset(msg); + copy_to_msg(msg, id_resp, ARRAY_SIZE(id_resp)); + + parsed = bsc_nat_parse(msg); + if (!parsed) + continue; + + con->imsi_checked = 0; + bsc_nat_filter_dt(bsc, msg, con, parsed); + } +} + int main(int argc, char **argv) { struct log_target *stderr_target; @@ -714,6 +767,7 @@ int main(int argc, char **argv) test_mgcp_rewrite(); test_mgcp_parse(); test_cr_filter(); + test_dt_filter(); return 0; }