diff options
author | Oliver Smith <osmith@sysmocom.de> | 2019-02-22 11:46:33 +0100 |
---|---|---|
committer | Neels Hofmeyr <neels@hofmeyr.de> | 2019-04-18 15:41:01 +0200 |
commit | 28f0af872e530480db9679beb2ed34a8a4893361 (patch) | |
tree | d63e68c618172395df40605f8895ed8193bd9a66 /src/hlr.c | |
parent | 9f6e558215b6862fdb6f4120f1f479f162d57634 (diff) |
hlr.c: forward GSUP messages between clients
Allow clients to forward any GSUP message between clients. Determine the
sender and receiver from the new {source,dest}_name{,_len} IEs. Reject
messages with a forged source name.
This will be used for the inter-MSC handover.
Depends: Ic00b0601eacff6d72927cea51767801142ee75db (libosmocore.git)
Related: OS#3793
Change-Id: Ia4f345abc877baaf0a8f73b8988e6514d9589bf5
Diffstat (limited to 'src/hlr.c')
-rw-r--r-- | src/hlr.c | 79 |
1 files changed, 79 insertions, 0 deletions
@@ -441,6 +441,82 @@ static int rx_check_imei_req(struct osmo_gsup_conn *conn, const struct osmo_gsup return osmo_gsup_conn_send(conn, msg_out); } +static char namebuf[255]; +#define LOGP_GSUP_FWD(gsup, level, fmt, args ...) \ + LOGP(DMAIN, level, "Forward %s (class=%s, IMSI=%s, %s->%s): " fmt, \ + osmo_gsup_message_type_name(gsup->message_type), \ + osmo_gsup_message_class_name(gsup->message_class), \ + gsup->imsi, \ + osmo_quote_str((const char *)gsup->source_name, gsup->source_name_len), \ + osmo_quote_str_buf2(namebuf, sizeof(namebuf), (const char *)gsup->destination_name, gsup->destination_name_len), \ + ## args) + +static int read_cb_forward(struct osmo_gsup_conn *conn, struct msgb *msg, const struct osmo_gsup_message *gsup) +{ + int ret = -EINVAL; + struct osmo_gsup_message *gsup_err; + + /* FIXME: it would be better if the msgb never were deallocated immediately by osmo_gsup_addr_send(), which a + * select-loop volatile talloc context could facilitate. Then we would still be able to access gsup-> members + * (pointing into the msgb) even after sending failed, and we wouldn't need to copy this data before sending: */ + /* Prepare error message (before IEs get deallocated) */ + gsup_err = talloc_zero(hlr_ctx, struct osmo_gsup_message); + OSMO_STRLCPY_ARRAY(gsup_err->imsi, gsup->imsi); + gsup_err->message_class = gsup->message_class; + gsup_err->destination_name = talloc_memdup(gsup_err, gsup->destination_name, gsup->destination_name_len); + gsup_err->destination_name_len = gsup->destination_name_len; + gsup_err->message_type = OSMO_GSUP_MSGT_E_ROUTING_ERROR; + gsup_err->session_id = gsup->session_id; + gsup_err->source_name = talloc_memdup(gsup_err, gsup->source_name, gsup->source_name_len); + gsup_err->source_name_len = gsup->source_name_len; + + /* Check for routing IEs */ + if (!gsup->source_name || !gsup->source_name_len || !gsup->destination_name || !gsup->destination_name_len) { + LOGP_GSUP_FWD(gsup, LOGL_ERROR, "missing routing IEs\n"); + goto end; + } + + /* Verify source name (e.g. "MSC-00-00-00-00-00-00") */ + if (gsup_route_find(conn->server, gsup->source_name, gsup->source_name_len) != conn) { + LOGP_GSUP_FWD(gsup, LOGL_ERROR, "mismatching source name\n"); + goto end; + } + + if (!msgb_l2(msg) || !msgb_l2len(msg)) { + LOGP_GSUP_FWD(gsup, LOGL_ERROR, "missing or empty l2 data\n"); + goto end; + } + + /* Forward message without re-encoding (so we don't remove unknown IEs) */ + LOGP_GSUP_FWD(gsup, LOGL_INFO, "checks passed, forwarding\n"); + + /* Remove incoming IPA header to be able to prepend an outgoing IPA header */ + msgb_pull_to_l2(msg); + ret = osmo_gsup_addr_send(g_hlr->gs, gsup->destination_name, gsup->destination_name_len, msg); + /* AT THIS POINT, THE msg MAY BE DEALLOCATED and the data like gsup->imsi, gsup->source_name etc may all be + * invalid and cause segfaults. */ + msg = NULL; + gsup = NULL; + if (ret == -ENODEV) + LOGP_GSUP_FWD(gsup_err, LOGL_ERROR, "destination not connected\n"); + else if (ret) + LOGP_GSUP_FWD(gsup_err, LOGL_ERROR, "unknown error %i\n", ret); + +end: + /* Send error back to source */ + if (ret) { + struct msgb *msg_err = msgb_alloc_headroom(1024+16, 16, "GSUP forward ERR response"); + OSMO_ASSERT(msg_err); + osmo_gsup_encode(msg_err, gsup_err); + LOGP_GSUP_FWD(gsup_err, LOGL_NOTICE, "Tx %s\n", osmo_gsup_message_type_name(gsup_err->message_type)); + osmo_gsup_conn_send(conn, msg_err); + } + talloc_free(gsup_err); + if (msg) + msgb_free(msg); + return ret; +} + static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg) { static struct osmo_gsup_message gsup; @@ -459,6 +535,9 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg) return gsup_send_err_reply(conn, gsup.imsi, gsup.message_type, GMM_CAUSE_INV_MAND_INFO); } + if (gsup.destination_name_len) + return read_cb_forward(conn, msg, &gsup); + switch (gsup.message_type) { /* requests sent to us */ case OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST: |