aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeith <keith@rhizomatica.org>2022-12-24 01:18:45 +0100
committerKeith Whyte <keith@rhizomatica.org>2023-11-22 19:56:48 +0000
commit2c82962c24623bd8972757144f1e07a42353eed3 (patch)
tree0b8ce733a14b99754f3fe475b33b16bcfb300bed
parentd052f076e385197998c4f05aa787927df2adfbff (diff)
DGSM: add option to respond only for authorized IMSIs
Adds a vty configuration option to the mslookup server which instructs the server to only reposnd to gsup.hlr queries for IMSIs that are both known AND have either Circuit Switched or Packet Switched access enabled. This helps in the case of so-called 'evil twin' IMSI entries, where, possibly due to subscriber-create-on-demand, as a result of a Location Update at a time when the home HLR was not reachable, the local hlr has an entry for an IMSI that in reality belongs to another HLR. NOTE: Network-wide concurrent use of subscriber-create-on-demand and the mslookup client is not currently possible, as the mslookup client has no fallback option to create-on-demand. A future commit, however will implement this fallback, thereby completing support for D-GSM with create-on-demand. Change-Id: I2643d6c93289ec0835fa1c00e275d627914775bc
-rw-r--r--include/osmocom/hlr/db.h2
-rw-r--r--include/osmocom/hlr/hlr.h1
-rw-r--r--src/db.c1
-rw-r--r--src/db_hlr.c25
-rw-r--r--src/dgsm.c8
-rw-r--r--src/dgsm_vty.c23
-rw-r--r--src/mslookup_server.c12
7 files changed, 68 insertions, 4 deletions
diff --git a/include/osmocom/hlr/db.h b/include/osmocom/hlr/db.h
index 588a96d..89b4fbc 100644
--- a/include/osmocom/hlr/db.h
+++ b/include/osmocom/hlr/db.h
@@ -40,6 +40,7 @@ enum stmt_idx {
DB_STMT_SET_LAST_LU_SEEN,
DB_STMT_SET_LAST_LU_SEEN_PS,
DB_STMT_EXISTS_BY_IMSI,
+ DB_STMT_EXISTS_AUTHORIZED_BY_IMSI,
DB_STMT_EXISTS_BY_MSISDN,
DB_STMT_IND_ADD,
DB_STMT_IND_SELECT,
@@ -157,6 +158,7 @@ int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
int db_subscr_update_imei_by_imsi(struct db_context *dbc, const char* imsi, const char *imei);
int db_subscr_exists_by_imsi(struct db_context *dbc, const char *imsi);
+int db_subscr_authorized_by_imsi(struct db_context *dbc, const char *imsi);
int db_subscr_exists_by_msisdn(struct db_context *dbc, const char *msisdn);
int db_subscrs_get(struct db_context *dbc, const char *filter_type, const char *filter,
diff --git a/include/osmocom/hlr/hlr.h b/include/osmocom/hlr/hlr.h
index dc0c77e..aa038df 100644
--- a/include/osmocom/hlr/hlr.h
+++ b/include/osmocom/hlr/hlr.h
@@ -120,6 +120,7 @@ struct hlr {
struct osmo_mslookup_client_method *running;
} mdns;
} client;
+ bool auth_imsi_only;
} mslookup;
};
diff --git a/src/db.c b/src/db.c
index 7b8a415..1ed8e06 100644
--- a/src/db.c
+++ b/src/db.c
@@ -92,6 +92,7 @@ static const char *stmt_sql[] = {
[DB_STMT_SET_LAST_LU_SEEN] = "UPDATE subscriber SET last_lu_seen = datetime($val, 'unixepoch') WHERE id = $subscriber_id",
[DB_STMT_SET_LAST_LU_SEEN_PS] = "UPDATE subscriber SET last_lu_seen_ps = datetime($val, 'unixepoch') WHERE id = $subscriber_id",
[DB_STMT_EXISTS_BY_IMSI] = "SELECT 1 FROM subscriber WHERE imsi = $imsi",
+ [DB_STMT_EXISTS_AUTHORIZED_BY_IMSI] = "SELECT 1 FROM subscriber WHERE imsi = $imsi AND (nam_cs = 1 OR nam_ps = 1)",
[DB_STMT_EXISTS_BY_MSISDN] = "SELECT 1 FROM subscriber WHERE msisdn = $msisdn",
[DB_STMT_IND_ADD] = "INSERT INTO ind (vlr) VALUES ($vlr)",
[DB_STMT_IND_SELECT] = "SELECT ind FROM ind WHERE vlr = $vlr",
diff --git a/src/db_hlr.c b/src/db_hlr.c
index aa2e365..3724797 100644
--- a/src/db_hlr.c
+++ b/src/db_hlr.c
@@ -555,6 +555,31 @@ int db_subscr_exists_by_imsi(struct db_context *dbc, const char *imsi) {
return rc;
}
+/*! Check if a subscriber exists and has CS or PS service in the HLR database.
+ * \param[in, out] dbc database context.
+ * \param[in] imsi ASCII string of IMSI digits.
+ * \returns 0 if exists & authorized, -ENOENT if not, -EIO on database error.
+ */
+int db_subscr_authorized_by_imsi(struct db_context *dbc, const char *imsi) {
+ sqlite3_stmt *stmt = dbc->stmt[DB_STMT_EXISTS_AUTHORIZED_BY_IMSI];
+ const char *err;
+ int rc;
+
+ if (!db_bind_text(stmt, NULL, imsi))
+ return -EIO;
+
+ rc = sqlite3_step(stmt);
+ db_remove_reset(stmt);
+ if (rc == SQLITE_ROW)
+ return 0; /* exists */
+ if (rc == SQLITE_DONE)
+ return -ENOENT; /* does not exist */
+
+ err = sqlite3_errmsg(dbc->db);
+ LOGP(DAUC, LOGL_ERROR, "Failed to check for authorized subscriber by IMSI='%s': %s\n", imsi, err);
+ return rc;
+}
+
/*! Retrieve subscriber data from the HLR database.
* \param[in,out] dbc database context.
* \param[in] imsi ASCII string of IMSI digits.
diff --git a/src/dgsm.c b/src/dgsm.c
index f96bca6..305020d 100644
--- a/src/dgsm.c
+++ b/src/dgsm.c
@@ -91,8 +91,12 @@ bool dgsm_check_forward_gsup_msg(struct osmo_gsup_req *req)
struct osmo_mslookup_query_handling handling;
uint32_t request_handle;
- /* If the IMSI is known in the local HLR, then we won't proxy. */
- if (db_subscr_exists_by_imsi(g_hlr->dbc, req->gsup.imsi) == 0)
+ /* If the IMSI is authorized in the local HLR, then we won't proxy. */
+ if (db_subscr_authorized_by_imsi(g_hlr->dbc, req->gsup.imsi) == 0)
+ return false;
+ /* If auth imsi is not set, then we won't proxy for ANY known IMSI */
+ if (!g_hlr->mslookup.auth_imsi_only &&
+ db_subscr_exists_by_imsi(g_hlr->dbc, req->gsup.imsi) == 0)
return false;
/* Are we already forwarding this IMSI to a remote HLR? */
diff --git a/src/dgsm_vty.c b/src/dgsm_vty.c
index 925545e..3e22023 100644
--- a/src/dgsm_vty.c
+++ b/src/dgsm_vty.c
@@ -188,6 +188,24 @@ DEFUN(cfg_mslookup_server_no_mdns_bind,
return CMD_SUCCESS;
}
+DEFUN(cfg_mslookup_auth_imsi_only,
+ cfg_mslookup_auth_imsi_only_cmd,
+ "authorized-imsi-only",
+ "On local GSUP, use mslookup ignoring local HLR + don't answer queries for IMSIs without PS or CS network access mode")
+{
+ g_hlr->mslookup.auth_imsi_only = true;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mslookup_no_auth_imsi_only,
+ cfg_mslookup_no_auth_imsi_only_cmd,
+ "no authorized-imsi-only",
+ NO_STR "Answer Local GSUP/mDNS queries for any IMSI in the local HLR database")
+{
+ g_hlr->mslookup.auth_imsi_only = false;
+ return CMD_SUCCESS;
+}
+
struct cmd_node mslookup_server_msc_node = {
MSLOOKUP_SERVER_MSC_NODE,
"%s(config-mslookup-server-msc)# ",
@@ -421,6 +439,9 @@ int config_write_mslookup(struct vty *vty)
vty_out(vty, "mslookup%s", VTY_NEWLINE);
+ if (g_hlr->mslookup.auth_imsi_only)
+ vty_out(vty, " authorized-imsi-only%s", VTY_NEWLINE);
+
if (g_hlr->mslookup.server.enable || !llist_empty(&g_hlr->mslookup.server.local_site_services)) {
struct mslookup_server_msc_cfg *msc;
@@ -550,6 +571,8 @@ void dgsm_vty_init(void)
install_element(CONFIG_NODE, &cfg_mslookup_cmd);
install_node(&mslookup_node, config_write_mslookup);
+ install_element(MSLOOKUP_NODE, &cfg_mslookup_auth_imsi_only_cmd);
+ install_element(MSLOOKUP_NODE, &cfg_mslookup_no_auth_imsi_only_cmd);
install_element(MSLOOKUP_NODE, &cfg_mslookup_mdns_cmd);
install_element(MSLOOKUP_NODE, &cfg_mslookup_mdns_domain_suffix_cmd);
install_element(MSLOOKUP_NODE, &cfg_mslookup_no_mdns_cmd);
diff --git a/src/mslookup_server.c b/src/mslookup_server.c
index 3771369..df59996 100644
--- a/src/mslookup_server.c
+++ b/src/mslookup_server.c
@@ -192,9 +192,16 @@ static void mslookup_server_rx_hlr_gsup(const struct osmo_mslookup_query *query,
{
const struct mslookup_service_host *host;
int rc;
+ bool exists = false;
+
switch (query->id.type) {
case OSMO_MSLOOKUP_ID_IMSI:
rc = db_subscr_exists_by_imsi(g_hlr->dbc, query->id.imsi);
+ if (g_hlr->mslookup.auth_imsi_only) {
+ if (!rc)
+ exists = true;
+ rc = db_subscr_authorized_by_imsi(g_hlr->dbc, query->id.imsi);
+ }
break;
case OSMO_MSLOOKUP_ID_MSISDN:
rc = db_subscr_exists_by_msisdn(g_hlr->dbc, query->id.msisdn);
@@ -206,8 +213,9 @@ static void mslookup_server_rx_hlr_gsup(const struct osmo_mslookup_query *query,
}
if (rc) {
- LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: does not exist in local HLR\n",
- osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));
+ LOGP(DMSLOOKUP, LOGL_DEBUG, "%s: %s in local HLR\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
+ (exists) ? "exists but is not authorized" : "does not exist");
*result = not_found;
return;
}