mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr.git
synced 2025-11-02 13:13:29 +00:00
Compare commits
5 Commits
1.6.2
...
osmith/ims
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6da2af924a | ||
|
|
fca8a0a935 | ||
|
|
7b4e5b1390 | ||
|
|
502f10fb0c | ||
|
|
e2c192e8c8 |
@@ -80,6 +80,10 @@ struct osmo_gsup_req {
|
||||
/* A decoded GSUP message still points into the received msgb. For a decoded osmo_gsup_message to remain valid,
|
||||
* we also need to keep the msgb. */
|
||||
struct msgb *msg;
|
||||
|
||||
/* The pseudonymous IMSI in gsup->imsi is replaced with the real IMSI right after receiving the message. A
|
||||
* copy of the pseudonymous IMSI is stored here for the reply. */
|
||||
char imsi_pseudo[OSMO_IMSI_BUF_SIZE];
|
||||
};
|
||||
|
||||
struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id *from_peer, struct msgb *msg,
|
||||
|
||||
@@ -9,6 +9,7 @@ noinst_HEADERS = \
|
||||
hlr_ussd.h \
|
||||
hlr_vty.h \
|
||||
hlr_vty_subscr.h \
|
||||
imsi_pseudo.h \
|
||||
logging.h \
|
||||
lu_fsm.h \
|
||||
mslookup_server.h \
|
||||
|
||||
@@ -33,6 +33,11 @@ enum stmt_idx {
|
||||
DB_STMT_SET_LAST_LU_SEEN_PS,
|
||||
DB_STMT_EXISTS_BY_IMSI,
|
||||
DB_STMT_EXISTS_BY_MSISDN,
|
||||
DB_STMT_PSEUDO_BY_ID,
|
||||
DB_STMT_PSEUDO_INSERT,
|
||||
DB_STMT_PSEUDO_DELETE,
|
||||
DB_STMT_PSEUDO_NEXT,
|
||||
DB_STMT_PSEUDO_RESOLVE,
|
||||
_NUM_DB_STMT
|
||||
};
|
||||
|
||||
|
||||
@@ -74,5 +74,7 @@ int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup,
|
||||
uint8_t *msisdn_enc, size_t msisdn_enc_size,
|
||||
uint8_t *apn_buf, size_t apn_buf_size,
|
||||
enum osmo_gsup_cn_domain cn_domain);
|
||||
void osmo_gsup_create_location_cancel_msg(struct osmo_gsup_message *gsup, const char *imsi,
|
||||
enum osmo_gsup_cn_domain cn_domain, enum osmo_gsup_cancel_type cancel_type);
|
||||
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_cni_peer_id *to_peer,
|
||||
struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup);
|
||||
|
||||
@@ -71,6 +71,8 @@ struct hlr {
|
||||
uint8_t subscr_create_on_demand_flags;
|
||||
unsigned int subscr_create_on_demand_rand_msisdn_len;
|
||||
|
||||
bool imsi_pseudo;
|
||||
|
||||
struct {
|
||||
bool allow_startup;
|
||||
struct {
|
||||
|
||||
20
include/osmocom/hlr/imsi_pseudo.h
Normal file
20
include/osmocom/hlr/imsi_pseudo.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <osmocom/hlr/db.h>
|
||||
|
||||
#define LOGPSEUDO(id, level, fmt, args ...) LOGP(DPSEUDO, level, "subscriber_id='%" PRId64 "': " fmt, id, ## args)
|
||||
|
||||
struct imsi_pseudo_data {
|
||||
int alloc_count; /* 0: none, 1: only current is allocated, 2: current and previous are allocated */
|
||||
int64_t i; /* current imsi_pseudo_i */
|
||||
char current[GSM23003_IMSI_MAX_DIGITS+1];
|
||||
char previous[GSM23003_IMSI_MAX_DIGITS+1];
|
||||
};
|
||||
|
||||
int db_get_imsi_pseudo_data(struct db_context *dbc, int64_t subscr_id, struct imsi_pseudo_data *data);
|
||||
int db_alloc_imsi_pseudo(struct db_context *dbc, int64_t subscr_id, const char *imsi_pseudo, int64_t imsi_pseudo_i);
|
||||
int db_dealloc_imsi_pseudo(struct db_context *dbc, const char *imsi_pseudo);
|
||||
int db_get_imsi_pseudo_next(struct db_context *dbc, char *imsi_pseudo);
|
||||
int db_get_imsi_pseudo_resolve(struct db_context *dbc, const char *imsi_pseudo, char *imsi);
|
||||
@@ -8,6 +8,7 @@ enum {
|
||||
DGSUP,
|
||||
DAUC,
|
||||
DSS,
|
||||
DPSEUDO,
|
||||
DMSLOOKUP,
|
||||
DLU,
|
||||
DDGSM,
|
||||
|
||||
12
sql/hlr.sql
12
sql/hlr.sql
@@ -62,6 +62,16 @@ CREATE TABLE subscriber_multi_msisdn (
|
||||
msisdn VARCHAR(15) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE subscriber_imsi_pseudo (
|
||||
-- https://osmocom.org/projects/imsi-pseudo/wiki
|
||||
id INTEGER PRIMARY KEY,
|
||||
subscriber_id INTEGER NOT NULL, -- subscriber.id
|
||||
imsi_pseudo VARCHAR(15) UNIQUE NOT NULL,
|
||||
imsi_pseudo_i INTEGER default 0 NOT NULL
|
||||
);
|
||||
|
||||
/* FIXME: index for imsi_pseudo and subscriber_id for better performance */
|
||||
|
||||
CREATE TABLE auc_2g (
|
||||
subscriber_id INTEGER PRIMARY KEY, -- subscriber.id
|
||||
algo_id_2g INTEGER NOT NULL, -- enum osmo_auth_algo value
|
||||
@@ -83,4 +93,4 @@ CREATE UNIQUE INDEX idx_subscr_imsi ON subscriber (imsi);
|
||||
|
||||
-- Set HLR database schema version number
|
||||
-- Note: This constant is currently duplicated in src/db.c and must be kept in sync!
|
||||
PRAGMA user_version = 5;
|
||||
PRAGMA user_version = 6;
|
||||
|
||||
@@ -44,6 +44,7 @@ osmo_hlr_SOURCES = \
|
||||
db.c \
|
||||
db_auc.c \
|
||||
db_hlr.c \
|
||||
db_imsi_pseudo.c \
|
||||
gsup_router.c \
|
||||
gsup_server.c \
|
||||
hlr.c \
|
||||
|
||||
47
src/db.c
47
src/db.c
@@ -28,7 +28,7 @@
|
||||
#include "db_bootstrap.h"
|
||||
|
||||
/* This constant is currently duplicated in sql/hlr.sql and must be kept in sync! */
|
||||
#define CURRENT_SCHEMA_VERSION 5
|
||||
#define CURRENT_SCHEMA_VERSION 6
|
||||
|
||||
#define SEL_COLUMNS \
|
||||
"id," \
|
||||
@@ -85,6 +85,28 @@ static const char *stmt_sql[] = {
|
||||
[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_BY_MSISDN] = "SELECT 1 FROM subscriber WHERE msisdn = $msisdn",
|
||||
[DB_STMT_PSEUDO_BY_ID] =
|
||||
"SELECT imsi_pseudo, imsi_pseudo_i"
|
||||
" FROM subscriber_imsi_pseudo"
|
||||
" WHERE subscriber_id = $subscriber_id"
|
||||
" ORDER BY imsi_pseudo_i DESC",
|
||||
[DB_STMT_PSEUDO_INSERT] =
|
||||
"INSERT INTO subscriber_imsi_pseudo (subscriber_id, imsi_pseudo, imsi_pseudo_i)"
|
||||
" VALUES($subscriber_id, $imsi_pseudo, $imsi_pseudo_i)",
|
||||
[DB_STMT_PSEUDO_DELETE] =
|
||||
"DELETE FROM subscriber_imsi_pseudo WHERE imsi_pseudo = $imsi_pseudo",
|
||||
[DB_STMT_PSEUDO_NEXT] = /* Proof of concept! Verify performance and entropy usage before using in real world! */
|
||||
"SELECT imsi"
|
||||
" FROM subscriber"
|
||||
" LEFT JOIN subscriber_imsi_pseudo ON imsi = imsi_pseudo"
|
||||
" WHERE imsi_pseudo IS NULL"
|
||||
" ORDER BY RANDOM()"
|
||||
" LIMIT 1",
|
||||
[DB_STMT_PSEUDO_RESOLVE] =
|
||||
"SELECT imsi"
|
||||
" FROM subscriber"
|
||||
" LEFT JOIN subscriber_imsi_pseudo ON subscriber_id = subscriber.id"
|
||||
" WHERE imsi_pseudo = $imsi_pseudo",
|
||||
};
|
||||
|
||||
static void sql3_error_log_cb(void *arg, int err_code, const char *msg)
|
||||
@@ -479,6 +501,28 @@ static int db_upgrade_v5(struct db_context *dbc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int db_upgrade_v6(struct db_context *dbc)
|
||||
{
|
||||
int rc;
|
||||
const char *statements[] = {
|
||||
"CREATE TABLE subscriber_imsi_pseudo (\n"
|
||||
"-- https://osmocom.org/projects/imsi-pseudo/wiki\n"
|
||||
"id INTEGER PRIMARY KEY,\n"
|
||||
"subscriber_id INTEGER NOT NULL, -- subscriber.id\n"
|
||||
"imsi_pseudo VARCHAR(15) UNIQUE NOT NULL,\n"
|
||||
"imsi_pseudo_i INTEGER default 0 NOT NULL\n"
|
||||
")",
|
||||
"PRAGMA user_version = 6"
|
||||
};
|
||||
|
||||
rc = db_run_statements(dbc, statements, ARRAY_SIZE(statements));
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DDB, LOGL_ERROR, "Unable to update HLR database schema to version 6\n");
|
||||
return rc;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
typedef int (*db_upgrade_func_t)(struct db_context *dbc);
|
||||
static db_upgrade_func_t db_upgrade_path[] = {
|
||||
db_upgrade_v1,
|
||||
@@ -486,6 +530,7 @@ static db_upgrade_func_t db_upgrade_path[] = {
|
||||
db_upgrade_v3,
|
||||
db_upgrade_v4,
|
||||
db_upgrade_v5,
|
||||
db_upgrade_v6,
|
||||
};
|
||||
|
||||
static int db_get_user_version(struct db_context *dbc)
|
||||
|
||||
177
src/db_imsi_pseudo.c
Normal file
177
src/db_imsi_pseudo.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/* (C) 2020 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <osmocom/hlr/logging.h>
|
||||
#include <osmocom/hlr/db.h>
|
||||
#include <osmocom/hlr/imsi_pseudo.h>
|
||||
|
||||
int db_get_imsi_pseudo_data(struct db_context *dbc, int64_t subscr_id, struct imsi_pseudo_data *data)
|
||||
{
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_PSEUDO_BY_ID];
|
||||
int i, rc, ret = 0;
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
|
||||
if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))
|
||||
return -EIO;
|
||||
|
||||
/* Retrieve up to two allocated pseudo IMSIs in three sqlite3 steps */
|
||||
for (i = 0; i < 3; i++) {
|
||||
rc = sqlite3_step(stmt);
|
||||
switch (rc) {
|
||||
case SQLITE_ROW:
|
||||
data->alloc_count = i + 1;
|
||||
switch (i) {
|
||||
case 0:
|
||||
/* First entry is always current (ORDER BY in SQL statement) */
|
||||
copy_sqlite3_text_to_buf(data->current, stmt, 0);
|
||||
data->i = sqlite3_column_int(stmt, 1);
|
||||
break;
|
||||
case 1:
|
||||
copy_sqlite3_text_to_buf(data->previous, stmt, 0);
|
||||
break;
|
||||
case 2:
|
||||
LOGPSEUDO(subscr_id, LOGL_ERROR, "more than two pseudonymous IMSI allocated\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case SQLITE_DONE:
|
||||
goto out;
|
||||
default:
|
||||
LOGPSEUDO(subscr_id, LOGL_ERROR, "error executing SQL: %d\n", rc);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
db_remove_reset(stmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int db_alloc_imsi_pseudo(struct db_context *dbc, int64_t subscr_id, const char *imsi_pseudo, int64_t imsi_pseudo_i)
|
||||
{
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_PSEUDO_INSERT];
|
||||
int rc, ret = 0;
|
||||
|
||||
if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))
|
||||
return -EIO;
|
||||
if (!db_bind_text(stmt, "$imsi_pseudo", imsi_pseudo))
|
||||
return -EIO;
|
||||
if (!db_bind_int64(stmt, "$imsi_pseudo_i", imsi_pseudo_i))
|
||||
return -EIO;
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGPSEUDO(subscr_id, LOGL_ERROR, "imsi_pseudo='%s', imsi_pseudo_i='%" PRId64 "': SQL error during"
|
||||
" allocate: %d\n", imsi_pseudo, imsi_pseudo_i, rc);
|
||||
ret = -EIO;
|
||||
}
|
||||
db_remove_reset(stmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int db_dealloc_imsi_pseudo(struct db_context *dbc, const char *imsi_pseudo)
|
||||
{
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_PSEUDO_DELETE];
|
||||
int rc, ret = 0;
|
||||
|
||||
if (!db_bind_text(stmt, "$imsi_pseudo", imsi_pseudo))
|
||||
return -EIO;
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc != SQLITE_DONE) {
|
||||
LOGP(DPSEUDO, LOGL_ERROR, "imsi_pseudo='%s': SQL error during deallocate: %d\n", imsi_pseudo, rc);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
db_remove_reset(stmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Get the next random free pseudo IMSI.
|
||||
* \param[in] dbc database context.
|
||||
* \param[out] imsi_pseudo buffer with length GSM23003_IMSI_MAX_DIGITS+1.
|
||||
* \returns 0: success, -1: no next IMSI available, -2: SQL error. */
|
||||
int db_get_imsi_pseudo_next(struct db_context *dbc, char *imsi_pseudo)
|
||||
{
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_PSEUDO_NEXT];
|
||||
const char *imsi;
|
||||
int rc, ret = 0;
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
switch (rc) {
|
||||
case SQLITE_ROW:
|
||||
/* Can't use copy_sqlite3_text_to_buf, as it assumes the wrong size for imsi_pseudo */
|
||||
imsi = (const char *)sqlite3_column_text(stmt, 0);
|
||||
osmo_strlcpy(imsi_pseudo, imsi, GSM23003_IMSI_MAX_DIGITS+1);
|
||||
break;
|
||||
case SQLITE_DONE:
|
||||
LOGP(DPSEUDO, LOGL_ERROR, "failed to get next pseudonymous IMSI: all IMSIs are already allocated as"
|
||||
" pseudo IMSI\n");
|
||||
ret = -1;
|
||||
break;
|
||||
default:
|
||||
LOGP(DPSEUDO, LOGL_ERROR, "failed to get next pseudonymous IMSI, SQL error: %d\n", rc);
|
||||
ret = -2;
|
||||
break;
|
||||
}
|
||||
|
||||
db_remove_reset(stmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Resolve a pseudo IMSI to the real IMSI.
|
||||
* \param[in] dbc database context.
|
||||
* \param[in] imsi_pseudo the IMSI to be resolved
|
||||
* \param[out] imsi buffer with length GSM23003_IMSI_MAX_DIGITS+1.
|
||||
* \returns 0: success, -1: no associated real IMSI, -2: SQL error. */
|
||||
int db_get_imsi_pseudo_resolve(struct db_context *dbc, const char *imsi_pseudo, char *imsi)
|
||||
{
|
||||
sqlite3_stmt *stmt = dbc->stmt[DB_STMT_PSEUDO_RESOLVE];
|
||||
int rc, ret=0;
|
||||
|
||||
if (!db_bind_text(stmt, "$imsi_pseudo", imsi_pseudo))
|
||||
return -EIO;
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
switch (rc) {
|
||||
case SQLITE_ROW:
|
||||
/* Can't use copy_sqlite3_text_to_buf, as it assumes the wrong size for imsi_pseudo */
|
||||
osmo_strlcpy(imsi, (const char *)sqlite3_column_text(stmt, 0), GSM23003_IMSI_MAX_DIGITS + 1);
|
||||
break;
|
||||
case SQLITE_DONE:
|
||||
LOGP(DPSEUDO, LOGL_NOTICE, "cannot resolve pseudonymous IMSI '%s': no associated real IMSI found\n",
|
||||
imsi_pseudo);
|
||||
ret = -1;
|
||||
break;
|
||||
default:
|
||||
LOGP(DPSEUDO, LOGL_ERROR, "cannot resolve pseudonymous IMSI '%s': SQL error: %d\n", imsi_pseudo, rc);
|
||||
ret = -2;
|
||||
break;
|
||||
}
|
||||
|
||||
db_remove_reset(stmt);
|
||||
return ret;
|
||||
}
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <osmocom/hlr/gsup_server.h>
|
||||
#include <osmocom/hlr/gsup_router.h>
|
||||
#include <osmocom/hlr/logging.h>
|
||||
|
||||
#define LOG_GSUP_CONN(conn, level, fmt, args...) \
|
||||
LOGP(DLGSUP, level, "GSUP peer %s: " fmt, \
|
||||
@@ -95,6 +96,11 @@ static void gsup_server_send_req_response(struct osmo_gsup_req *req, struct osmo
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->imsi_pseudo[0]) {
|
||||
LOGP(DPSEUDO, LOGL_DEBUG, "pseudo IMSI scramble: '%s' => '%s'\n", response->imsi, req->imsi_pseudo);
|
||||
strncpy(response->imsi, req->imsi_pseudo, sizeof(response->imsi));
|
||||
}
|
||||
|
||||
rc = osmo_gsup_encode(msg, response);
|
||||
if (rc) {
|
||||
LOG_GSUP_REQ(req, LOGL_ERROR, "Unable to encode: {%s}\n",
|
||||
@@ -514,6 +520,29 @@ int osmo_gsup_create_insert_subscriber_data_msg(struct osmo_gsup_message *gsup,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate a gsup message structure with a Location Cancel Message.
|
||||
* All required memory buffers for data pointed to by pointers in struct omso_gsup_message
|
||||
* must be allocated by the caller and should have the same lifetime as the gsup parameter.
|
||||
*
|
||||
* \param[out] gsup The gsup message to populate.
|
||||
* \param[in] imsi The subscriber's IMSI.
|
||||
* \param[in] cn_domain The CN Domain of the subscriber connection.
|
||||
* \param[in] cancel_type The cancellation type.
|
||||
*/
|
||||
void osmo_gsup_create_location_cancel_msg(struct osmo_gsup_message *gsup, const char *imsi,
|
||||
enum osmo_gsup_cn_domain cn_domain, enum osmo_gsup_cancel_type cancel_type)
|
||||
{
|
||||
OSMO_ASSERT(gsup);
|
||||
*gsup = (struct osmo_gsup_message){
|
||||
.message_type = OSMO_GSUP_MSGT_LOCATION_CANCEL_REQUEST,
|
||||
.cn_domain = cn_domain,
|
||||
.cancel_type = cancel_type
|
||||
};
|
||||
|
||||
osmo_strlcpy(gsup->imsi, imsi, sizeof(gsup->imsi));
|
||||
}
|
||||
|
||||
int osmo_gsup_forward_to_local_peer(struct osmo_gsup_server *server, const struct osmo_cni_peer_id *to_peer,
|
||||
struct osmo_gsup_req *req, struct osmo_gsup_message *modified_gsup)
|
||||
{
|
||||
|
||||
14
src/hlr.c
14
src/hlr.c
@@ -48,6 +48,7 @@
|
||||
#include <osmocom/hlr/rand.h>
|
||||
#include <osmocom/hlr/hlr_vty.h>
|
||||
#include <osmocom/hlr/hlr_ussd.h>
|
||||
#include <osmocom/hlr/imsi_pseudo.h>
|
||||
#include <osmocom/hlr/dgsm.h>
|
||||
#include <osmocom/hlr/proxy.h>
|
||||
#include <osmocom/hlr/lu_fsm.h>
|
||||
@@ -512,6 +513,19 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resolve pseudonymous IMSI */
|
||||
if (g_hlr->imsi_pseudo) {
|
||||
char imsi[OSMO_IMSI_BUF_SIZE];
|
||||
if (db_get_imsi_pseudo_resolve(g_hlr->dbc, req->gsup.imsi, imsi) == 0) {
|
||||
LOGP(DPSEUDO, LOGL_DEBUG, "pseudo IMSI resolve: '%s' => '%s'\n", req->gsup.imsi, imsi);
|
||||
strncpy(req->imsi_pseudo, req->gsup.imsi, sizeof(req->imsi_pseudo));
|
||||
strncpy((char *)req->gsup.imsi, imsi, sizeof(req->gsup.imsi));
|
||||
} else {
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "pseudonymous IMSI unknown");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* HLR related messages that are handled at this HLR instance */
|
||||
switch (req->gsup.message_type) {
|
||||
/* requests sent to us */
|
||||
|
||||
@@ -94,6 +94,8 @@ static int config_write_hlr(struct vty *vty)
|
||||
else
|
||||
vty_out(vty, " subscriber-create-on-demand no-msisdn %s%s", flags_str, VTY_NEWLINE);
|
||||
}
|
||||
if (g_hlr->imsi_pseudo)
|
||||
vty_out(vty, " imsi-pseudo%s", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -408,6 +410,21 @@ DEFUN(cfg_no_subscr_create_on_demand, cfg_no_subscr_create_on_demand_cmd,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_imsi_pseudo, cfg_imsi_pseudo_cmd,
|
||||
"imsi-pseudo",
|
||||
"Enable IMSI Pseudonymization\n")
|
||||
{
|
||||
g_hlr->imsi_pseudo = true;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_no_imsi_pseudo, cfg_no_imsi_pseudo_cmd,
|
||||
"no imsi-pseudo",
|
||||
"Disable IMSI Pseudonymization\n")
|
||||
{
|
||||
g_hlr->imsi_pseudo = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
/***********************************************************************
|
||||
* Common Code
|
||||
***********************************************************************/
|
||||
@@ -479,6 +496,8 @@ void hlr_vty_init(void)
|
||||
install_element(HLR_NODE, &cfg_no_store_imei_cmd);
|
||||
install_element(HLR_NODE, &cfg_subscr_create_on_demand_cmd);
|
||||
install_element(HLR_NODE, &cfg_no_subscr_create_on_demand_cmd);
|
||||
install_element(HLR_NODE, &cfg_imsi_pseudo_cmd);
|
||||
install_element(HLR_NODE, &cfg_no_imsi_pseudo_cmd);
|
||||
|
||||
hlr_vty_subscriber_init();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
#include <osmocom/hlr/db.h>
|
||||
#include <osmocom/hlr/timestamp.h>
|
||||
#include <osmocom/hlr/imsi_pseudo.h>
|
||||
|
||||
struct vty;
|
||||
|
||||
@@ -69,6 +70,18 @@ static void dump_last_lu_seen(struct vty *vty, const char *domain_label, time_t
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_imsi_pseudo(struct vty *vty, struct hlr_subscriber *subscr)
|
||||
{
|
||||
struct imsi_pseudo_data data;
|
||||
|
||||
if (db_get_imsi_pseudo_data(g_hlr->dbc, subscr->id, &data) != 0)
|
||||
return;
|
||||
if (data.alloc_count >= 1)
|
||||
vty_out(vty, " Pseudonymous IMSI (current): %s, i: %" PRId64 "%s", data.current, data.i, VTY_NEWLINE);
|
||||
if (data.alloc_count == 2)
|
||||
vty_out(vty, " Pseudonymous IMSI (previous): %s%s", data.previous, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
||||
{
|
||||
int rc;
|
||||
@@ -78,6 +91,7 @@ static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
|
||||
vty_out(vty, " ID: %"PRIu64"%s", subscr->id, VTY_NEWLINE);
|
||||
|
||||
vty_out(vty, " IMSI: %s%s", *subscr->imsi ? subscr->imsi : "none", VTY_NEWLINE);
|
||||
dump_imsi_pseudo(vty, subscr);
|
||||
vty_out(vty, " MSISDN: %s%s", *subscr->msisdn ? subscr->msisdn : "none", VTY_NEWLINE);
|
||||
|
||||
if (*subscr->imei) {
|
||||
@@ -203,6 +217,7 @@ static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id,
|
||||
#define SUBSCR_UPDATE SUBSCR "update "
|
||||
#define SUBSCR_UPDATE_HELP SUBSCR_HELP "Set or update subscriber data\n"
|
||||
#define SUBSCR_MSISDN_HELP "Set MSISDN (phone number) of the subscriber\n"
|
||||
#define SUBSCR_IMSI_PSEUDO_HELP "Allocate or deallocate pseudonymous IMSI of the subscriber\n"
|
||||
|
||||
DEFUN(subscriber_show,
|
||||
subscriber_show_cmd,
|
||||
@@ -625,6 +640,85 @@ DEFUN(subscriber_nam,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(subscriber_imsi_pseudo_alloc,
|
||||
subscriber_imsi_pseudo_alloc_cmd,
|
||||
SUBSCR_UPDATE "imsi-pseudo alloc",
|
||||
SUBSCR_UPDATE_HELP
|
||||
SUBSCR_IMSI_PSEUDO_HELP
|
||||
"Allocate a new pseudonymous IMSI (max. 2)\n")
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct imsi_pseudo_data pseudo;
|
||||
const char *id_type = argv[0];
|
||||
const char *id = argv[1];
|
||||
char imsi_pseudo[GSM23003_IMSI_MAX_DIGITS+1];
|
||||
int rc;
|
||||
|
||||
if (get_subscr_by_argv(vty, id_type, id, &subscr))
|
||||
return CMD_WARNING;
|
||||
|
||||
if (db_get_imsi_pseudo_data(g_hlr->dbc, subscr.id, &pseudo) != 0)
|
||||
return CMD_WARNING;
|
||||
|
||||
if (pseudo.alloc_count == 2) {
|
||||
vty_out(vty, "%% Error: subscriber already has two pseudonymous IMSI allocated%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
rc = db_get_imsi_pseudo_next(g_hlr->dbc, imsi_pseudo);
|
||||
switch (rc) {
|
||||
case -1:
|
||||
vty_out(vty, "%% Error: all IMSIs are already allocated as pseudonymous IMSI%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
case -2:
|
||||
vty_out(vty, "%% Error: failed to get next pseudonymous IMSI (SQL error)%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (db_alloc_imsi_pseudo(g_hlr->dbc, subscr.id, imsi_pseudo, pseudo.i + 1) != 0) {
|
||||
vty_out(vty, "%% Error: failed to allocate pseudonymous IMSI '%s'%s", imsi_pseudo, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
vty_out(vty, "%% New pseudonymous IMSI allocated: %s%s", imsi_pseudo, VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(subscriber_imsi_pseudo_dealloc,
|
||||
subscriber_imsi_pseudo_dealloc_cmd,
|
||||
SUBSCR_UPDATE "imsi-pseudo dealloc IMSI_PSEUDO",
|
||||
SUBSCR_UPDATE_HELP
|
||||
SUBSCR_IMSI_PSEUDO_HELP
|
||||
"Deallocate a pseudonymous IMSI\n"
|
||||
"Pseudonymous IMSI to deallocate\n")
|
||||
{
|
||||
struct hlr_subscriber subscr;
|
||||
struct imsi_pseudo_data pseudo;
|
||||
const char *id_type = argv[0];
|
||||
const char *id = argv[1];
|
||||
const char *imsi_pseudo = argv[2];
|
||||
|
||||
if (get_subscr_by_argv(vty, id_type, id, &subscr))
|
||||
return CMD_WARNING;
|
||||
|
||||
if (db_get_imsi_pseudo_data(g_hlr->dbc, subscr.id, &pseudo) != 0)
|
||||
return CMD_WARNING;
|
||||
|
||||
if ((pseudo.alloc_count >= 1 && strcmp(imsi_pseudo, pseudo.current) == 0) ||
|
||||
(pseudo.alloc_count == 2 && strcmp(imsi_pseudo, pseudo.previous) == 0)) {
|
||||
/* Pseudonymous IMSI is allocated for given subscriber */
|
||||
if (db_dealloc_imsi_pseudo(g_hlr->dbc, imsi_pseudo) != 0) {
|
||||
vty_out(vty, "Failed to deallocate pseudonymous IMSI%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
} else {
|
||||
vty_out(vty, "%% Error: pseudonymous IMSI '%s' is not allocated to given subscriber%s", imsi_pseudo,
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
void hlr_vty_subscriber_init(void)
|
||||
{
|
||||
@@ -639,4 +733,6 @@ void hlr_vty_subscriber_init(void)
|
||||
install_element(ENABLE_NODE, &subscriber_aud3g_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_imei_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_nam_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_imsi_pseudo_alloc_cmd);
|
||||
install_element(ENABLE_NODE, &subscriber_imsi_pseudo_dealloc_cmd);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,12 @@ const struct log_info_cat hlr_log_info_cat[] = {
|
||||
.color = "\033[1;34m",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DPSEUDO] = {
|
||||
.name = "DPSEUDO",
|
||||
.description = "IMSI Pseudonymization",
|
||||
.color = "\033[1;36m",
|
||||
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||
},
|
||||
[DMSLOOKUP] = {
|
||||
.name = "DMSLOOKUP",
|
||||
.description = "Mobile Subscriber Lookup",
|
||||
|
||||
104
src/lu_fsm.c
104
src/lu_fsm.c
@@ -31,6 +31,7 @@
|
||||
#include <osmocom/hlr/logging.h>
|
||||
#include <osmocom/hlr/hlr.h>
|
||||
#include <osmocom/hlr/gsup_server.h>
|
||||
#include <osmocom/hlr/imsi_pseudo.h>
|
||||
|
||||
#include <osmocom/hlr/db.h>
|
||||
|
||||
@@ -80,6 +81,48 @@ static struct osmo_tdef_state_timeout lu_fsm_timeouts[32] = {
|
||||
[LU_ST_WAIT_LOCATION_CANCEL_RESULT] = { .T = -4222 },
|
||||
};
|
||||
|
||||
/*! Deallocate the previous pseudonymous IMSI, if the subscriber has two allocated ones and has initiated the LU with
|
||||
* the newer pseudonymous IMSI.
|
||||
* \param[in] subscr The subscriber.
|
||||
* \param[in] imsi_pseudo The pseudonymous IMSI used in the location update.
|
||||
* \param[out] imsi_pseudo_prev The pseudonymous IMSI that was deallocated if return == 0. Must be a buffer of size
|
||||
* OSMO_IMSI_BUF.
|
||||
* \returns 0: successful deallocation, >0: successful, no pseudo IMSI to deallocate, <0: error
|
||||
*/
|
||||
int imsi_pseudo_prev_dealloc(struct hlr_subscriber *subscr, const char *imsi_pseudo, char *imsi_pseudo_prev)
|
||||
{
|
||||
struct imsi_pseudo_data data;
|
||||
|
||||
if (db_get_imsi_pseudo_data(g_hlr->dbc, subscr->id, &data) != 0) {
|
||||
LOGPSEUDO(subscr->id, LOGL_ERROR, "failed to get pseudo IMSI data from DB\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (data.alloc_count == 0) {
|
||||
LOGPSEUDO(subscr->id, LOGL_ERROR, "does not have any pseudo IMSI allocated\n");
|
||||
return -EIO;
|
||||
}
|
||||
if (data.alloc_count != 2) {
|
||||
LOGPSEUDO(subscr->id, LOGL_DEBUG, "has only one pseudo IMSI allocated, not deallocating any\n");
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(data.previous, imsi_pseudo) == 0) {
|
||||
LOGPSEUDO(subscr->id, LOGL_NOTICE, "did LU with previous pseudo IMSI (next pseudo IMSI SMS did not"
|
||||
" arrive?)\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
LOGPSEUDO(subscr->id, LOGL_DEBUG, "used current pseudo IMSI '%s' in LU, deallocating previous: '%s'\n",
|
||||
imsi_pseudo, data.previous);
|
||||
|
||||
if (db_dealloc_imsi_pseudo(g_hlr->dbc, data.previous) != 0) {
|
||||
LOGPSEUDO(subscr->id, LOGL_ERROR, "failed to deallocate previous pseudo IMSI '%s'\n", data.previous);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
strncpy(imsi_pseudo_prev, data.previous, OSMO_IMSI_BUF_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define lu_state_chg(lu, state) \
|
||||
osmo_tdef_fsm_inst_state_chg((lu)->fi, state, lu_fsm_timeouts, g_hlr_tdefs, 5)
|
||||
|
||||
@@ -197,6 +240,32 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
|
||||
/* TODO: Reset Flag MS Purged (cs/ps) */
|
||||
/* TODO: Control_Tracing_HLR / Control_Tracing_HLR_with_SGSN */
|
||||
|
||||
/* IMSI pseudonymization: deallocate and cancel previous pseudo IMSI */
|
||||
if (g_hlr->imsi_pseudo) {
|
||||
char imsi_pseudo_prev[OSMO_IMSI_BUF_SIZE];
|
||||
int rc = imsi_pseudo_prev_dealloc(&lu->subscr, update_location_req->imsi_pseudo, imsi_pseudo_prev);
|
||||
|
||||
if (rc < 0) {
|
||||
lu_failure(lu, GMM_CAUSE_NET_FAIL, "Failed to deallocate previous pseudonymous IMSI");
|
||||
return;
|
||||
}
|
||||
if (rc == 0) {
|
||||
struct osmo_gsup_message gsup;
|
||||
enum osmo_gsup_cn_domain cn_domain = lu->is_ps
|
||||
? OSMO_GSUP_CN_DOMAIN_PS
|
||||
: OSMO_GSUP_CN_DOMAIN_CS;
|
||||
|
||||
osmo_gsup_create_location_cancel_msg(&gsup, imsi_pseudo_prev, cn_domain,
|
||||
OSMO_GSUP_CANCEL_TYPE_WITHDRAW);
|
||||
|
||||
/* FIXME: _osmo_gsup_req_respond() fails with 'Invalid response (rc=1)' */
|
||||
osmo_gsup_req_respond(update_location_req, &gsup, false, false);
|
||||
|
||||
lu_state_chg(lu, LU_ST_WAIT_LOCATION_CANCEL_RESULT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lu_state_chg(lu, LU_ST_WAIT_INSERT_DATA_RESULT);
|
||||
}
|
||||
|
||||
@@ -285,6 +354,33 @@ void lu_fsm_wait_insert_data_result(struct osmo_fsm_inst *fi, uint32_t event, vo
|
||||
}
|
||||
}
|
||||
|
||||
void lu_fsm_wait_location_cancel_result(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct lu *lu = fi->priv;
|
||||
struct osmo_gsup_req *req;
|
||||
|
||||
switch (event) {
|
||||
case LU_EV_RX_GSUP:
|
||||
req = data;
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(false);
|
||||
}
|
||||
|
||||
switch (req->gsup.message_type) {
|
||||
case OSMO_GSUP_MSGT_LOCATION_CANCEL_ERROR:
|
||||
LOG_LU(lu, LOGL_DEBUG, "got a location cancel error (but this is fine, remote didn't even know the"
|
||||
" subscriber we tried to make it forget)\n");
|
||||
/* fall through */
|
||||
case OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT:
|
||||
lu_state_chg(lu, LU_ST_WAIT_INSERT_DATA_RESULT);
|
||||
break;
|
||||
default:
|
||||
osmo_gsup_req_respond_err(req, GMM_CAUSE_MSGT_INCOMP_P_STATE, "unexpected message type in this state");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define S(x) (1 << (x))
|
||||
|
||||
static const struct osmo_fsm_state lu_fsm_states[] = {
|
||||
@@ -292,6 +388,7 @@ static const struct osmo_fsm_state lu_fsm_states[] = {
|
||||
.name = "UNVALIDATED",
|
||||
.out_state_mask = 0
|
||||
| S(LU_ST_WAIT_INSERT_DATA_RESULT)
|
||||
| S(LU_ST_WAIT_LOCATION_CANCEL_RESULT)
|
||||
,
|
||||
},
|
||||
[LU_ST_WAIT_INSERT_DATA_RESULT] = {
|
||||
@@ -302,6 +399,13 @@ static const struct osmo_fsm_state lu_fsm_states[] = {
|
||||
.onenter = lu_fsm_wait_insert_data_result_onenter,
|
||||
.action = lu_fsm_wait_insert_data_result,
|
||||
},
|
||||
[LU_ST_WAIT_LOCATION_CANCEL_RESULT] = {
|
||||
.name = "WAIT_LOCATION_CANCEL_RESULT",
|
||||
.in_event_mask = 0
|
||||
| S(LU_EV_RX_GSUP)
|
||||
,
|
||||
.action = lu_fsm_wait_location_cancel_result,
|
||||
},
|
||||
};
|
||||
|
||||
static struct osmo_fsm lu_fsm = {
|
||||
|
||||
@@ -45,6 +45,7 @@ if ENABLE_EXT_TESTS
|
||||
python-tests:
|
||||
# don't run vty and ctrl tests concurrently so that the ports don't conflict
|
||||
$(MAKE) vty-test
|
||||
$(MAKE) vty-test-imsi-pseudo
|
||||
$(MAKE) ctrl-test
|
||||
$(MAKE) db-upgrade-equivalence-test
|
||||
else
|
||||
@@ -68,6 +69,16 @@ vty-test:
|
||||
$(U) $(srcdir)/$(VTY_TEST)
|
||||
-rm -f $(VTY_TEST_DB) $(VTY_TEST_DB)-*
|
||||
|
||||
# IMSI pseudon VTY tests: don't share the DB with other VTY tests, so we can have deterministic "random" pseudo IMSIs
|
||||
vty-test-imsi-pseudo:
|
||||
-rm -f $(VTY_TEST_DB)
|
||||
sqlite3 $(VTY_TEST_DB) < $(top_srcdir)/sql/hlr.sql
|
||||
osmo_verify_transcript_vty.py -v \
|
||||
-n OsmoHLR -p 4258 \
|
||||
-r "$(top_builddir)/src/osmo-hlr -c $(top_srcdir)/doc/examples/osmo-hlr.cfg -l $(VTY_TEST_DB)" \
|
||||
$(U) $(srcdir)/imsi_pseudo/imsi_pseudo.vty
|
||||
-rm -f $(VTY_TEST_DB) $(VTY_TEST_DB)-*
|
||||
|
||||
CTRL_TEST_DB = hlr_ctrl_test.db
|
||||
|
||||
# To update the CTRL script from current application behavior,
|
||||
|
||||
@@ -85,6 +85,7 @@ DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 2
|
||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 3
|
||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 4
|
||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 5
|
||||
DDB Database <PATH>test.db' has been upgraded to HLR DB schema version 6
|
||||
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
|
||||
|
||||
Resulting db:
|
||||
@@ -159,6 +160,15 @@ subscriber_id|INTEGER|0||0
|
||||
|
||||
Table subscriber_apn contents:
|
||||
|
||||
Table: subscriber_imsi_pseudo
|
||||
name|type|notnull|dflt_value|pk
|
||||
id|INTEGER|0||1
|
||||
imsi_pseudo|VARCHAR(15)|1||0
|
||||
imsi_pseudo_i|INTEGER|1|0|0
|
||||
subscriber_id|INTEGER|1||0
|
||||
|
||||
Table subscriber_imsi_pseudo contents:
|
||||
|
||||
Table: subscriber_multi_msisdn
|
||||
name|type|notnull|dflt_value|pk
|
||||
msisdn|VARCHAR(15)|1||0
|
||||
@@ -171,5 +181,5 @@ osmo-hlr --database $db --db-check --config-file $srcdir/osmo-hlr.cfg
|
||||
rc = 0
|
||||
DMAIN hlr starting
|
||||
DDB using database: <PATH>test.db
|
||||
DDB Database <PATH>test.db' has HLR DB schema version 5
|
||||
DDB Database <PATH>test.db' has HLR DB schema version 6
|
||||
DMAIN Cmdline option --db-check: Database was opened successfully, quitting.
|
||||
|
||||
42
tests/imsi_pseudo/imsi_pseudo.vty
Normal file
42
tests/imsi_pseudo/imsi_pseudo.vty
Normal file
@@ -0,0 +1,42 @@
|
||||
OsmoHLR> enable
|
||||
OsmoHLR# subscriber imsi 111111111111111 create
|
||||
...
|
||||
OsmoHLR# subscriber id 1 update imsi-pseudo alloc
|
||||
% New pseudonymous IMSI allocated: 111111111111111
|
||||
OsmoHLR# subscriber imsi 222222222222222 create
|
||||
...
|
||||
OsmoHLR# subscriber id 1 update imsi-pseudo alloc
|
||||
% New pseudonymous IMSI allocated: 222222222222222
|
||||
OsmoHLR# subscriber id 1 update imsi-pseudo dealloc 111111111111111
|
||||
OsmoHLR# subscriber id 2 update imsi-pseudo alloc
|
||||
% New pseudonymous IMSI allocated: 111111111111111
|
||||
OsmoHLR# subscriber imsi 333333333333333 create
|
||||
...
|
||||
OsmoHLR# subscriber id 1 update imsi-pseudo alloc
|
||||
% New pseudonymous IMSI allocated: 333333333333333
|
||||
OsmoHLR# subscriber id 1 show
|
||||
ID: 1
|
||||
IMSI: 111111111111111
|
||||
Pseudonymous IMSI (current): 333333333333333, i: 3
|
||||
Pseudonymous IMSI (previous): 222222222222222
|
||||
MSISDN: none
|
||||
OsmoHLR# subscriber id 2 show
|
||||
ID: 2
|
||||
IMSI: 222222222222222
|
||||
Pseudonymous IMSI (current): 111111111111111, i: 1
|
||||
MSISDN: none
|
||||
OsmoHLR# subscriber id 3 show
|
||||
ID: 3
|
||||
IMSI: 333333333333333
|
||||
MSISDN: none
|
||||
|
||||
OsmoHLR# subscriber id 3 update imsi-pseudo alloc
|
||||
% Error: all IMSIs are already allocated as pseudonymous IMSI
|
||||
|
||||
OsmoHLR# subscriber id 1 update imsi-pseudo dealloc 123
|
||||
% Error: pseudonymous IMSI '123' is not allocated to given subscriber
|
||||
|
||||
OsmoHLR# subscriber imsi 444444444444444 create
|
||||
...
|
||||
OsmoHLR# subscriber id 1 update imsi-pseudo alloc
|
||||
% Error: subscriber already has two pseudonymous IMSI allocated
|
||||
@@ -41,6 +41,7 @@ OsmoHLR(config-hlr)# ?
|
||||
ncss-guard-timeout Set guard timer for NCSS (call independent SS) session activity
|
||||
store-imei Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send Check IMEI requests (for OsmoMSC, you may want to set 'check-imei-rqd 1').
|
||||
subscriber-create-on-demand Make a new record when a subscriber is first seen.
|
||||
imsi-pseudo Enable IMSI Pseudonymization
|
||||
OsmoHLR(config-hlr)# list
|
||||
...
|
||||
gsup
|
||||
@@ -57,6 +58,8 @@ OsmoHLR(config-hlr)# list
|
||||
no store-imei
|
||||
subscriber-create-on-demand (no-msisdn|<3-15>) (none|cs|ps|cs+ps)
|
||||
no subscriber-create-on-demand
|
||||
imsi-pseudo
|
||||
no imsi-pseudo
|
||||
|
||||
OsmoHLR(config-hlr)# gsup
|
||||
OsmoHLR(config-hlr-gsup)# ?
|
||||
@@ -90,6 +93,7 @@ log stderr
|
||||
logging level db notice
|
||||
logging level auc notice
|
||||
logging level ss info
|
||||
logging level pseudo notice
|
||||
logging level mslookup notice
|
||||
logging level lu notice
|
||||
logging level dgsm notice
|
||||
|
||||
@@ -13,6 +13,8 @@ OsmoHLR# list
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update aud3g milenage k K (op|opc) OP_C [ind-bitlen] [<0-28>]
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update imei (none|IMEI)
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update network-access-mode (none|cs|ps|cs+ps)
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update imsi-pseudo alloc
|
||||
subscriber (imsi|msisdn|id|imei) IDENT update imsi-pseudo dealloc IMSI_PSEUDO
|
||||
show mslookup services
|
||||
|
||||
OsmoHLR# subscriber?
|
||||
@@ -132,6 +134,7 @@ OsmoHLR# subscriber imsi 123456789023000 update ?
|
||||
aud3g Set UMTS authentication data (3G, and 2G with UMTS AKA)
|
||||
imei Set IMEI of the subscriber (normally populated from MSC, no need to set this manually)
|
||||
network-access-mode Set Network Access Mode (NAM) of the subscriber
|
||||
imsi-pseudo Allocate or deallocate pseudonymous IMSI of the subscriber
|
||||
|
||||
OsmoHLR# subscriber imsi 123456789023000 update msisdn ?
|
||||
none Remove MSISDN (phone number)
|
||||
|
||||
Reference in New Issue
Block a user