mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr.git
				synced 2025-11-03 21:53:30 +00:00 
			
		
		
		
	Compare commits
	
		
			11 Commits
		
	
	
		
			1.9.1
			...
			rhizomatic
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					945cc067b3 | ||
| 
						 | 
					ff058aac73 | ||
| 
						 | 
					caee387b7e | ||
| 
						 | 
					7dbe2b1fa4 | ||
| 
						 | 
					081990e4ff | ||
| 
						 | 
					b8fbb709fa | ||
| 
						 | 
					b3f6229953 | ||
| 
						 | 
					9e2beaffc2 | ||
| 
						 | 
					1c84633350 | ||
| 
						 | 
					5225de1474 | ||
| 
						 | 
					d4b4548589 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -86,3 +86,5 @@ contrib/osmo-hlr.spec
 | 
			
		||||
/debian/osmo-mslookup-utils/
 | 
			
		||||
/debian/*.log
 | 
			
		||||
/debian/*.substvars
 | 
			
		||||
 | 
			
		||||
include/osmocom/*/version.h
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,25 @@
 | 
			
		||||
SUBDIRS = osmocom
 | 
			
		||||
 | 
			
		||||
osmocom/%/version.h: osmocom/%/version.h.tpl
 | 
			
		||||
	$(AM_V_GEN)$(MKDIR_P) $(dir $@)
 | 
			
		||||
	$(AM_V_GEN)sed \
 | 
			
		||||
		-e "s/{{VERSION}}/$$(echo '@VERSION@' | cut -d. -f1-3)/g" \
 | 
			
		||||
		-e "s/{{VERSION_MAJOR}}/$$(echo '@VERSION@' | cut -d. -f1)/g" \
 | 
			
		||||
		-e "s/{{VERSION_MINOR}}/$$(echo '@VERSION@' | cut -d. -f2)/g" \
 | 
			
		||||
		-e "s/{{VERSION_PATCH}}/$$(echo '@VERSION@' | cut -d. -f3)/g" \
 | 
			
		||||
		$< > $@
 | 
			
		||||
 | 
			
		||||
nobase_include_HEADERS = \
 | 
			
		||||
	osmocom/gsupclient/cni_peer_id.h \
 | 
			
		||||
	osmocom/gsupclient/gsup_client.h \
 | 
			
		||||
	osmocom/gsupclient/gsup_client_mux.h \
 | 
			
		||||
	osmocom/gsupclient/gsup_req.h \
 | 
			
		||||
	osmocom/gsupclient/version.h \
 | 
			
		||||
	osmocom/mslookup/mdns.h \
 | 
			
		||||
	osmocom/mslookup/mdns_sock.h \
 | 
			
		||||
	osmocom/mslookup/mslookup_client_fake.h \
 | 
			
		||||
	osmocom/mslookup/mslookup_client.h \
 | 
			
		||||
	osmocom/mslookup/mslookup_client_mdns.h \
 | 
			
		||||
	osmocom/mslookup/mslookup.h \
 | 
			
		||||
	osmocom/mslookup/version.h \
 | 
			
		||||
	$(NULL)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								include/osmocom/gsupclient/version.h.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								include/osmocom/gsupclient/version.h.tpl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define LIBOSMO_GSUP_CLIENT_VERSION {{VERSION}}
 | 
			
		||||
#define LIBOSMO_GSUP_CLIENT_VERSION_STR "{{VERSION}}"
 | 
			
		||||
 | 
			
		||||
#define LIBOSMO_GSUP_CLIENT_VERSION_MAJOR {{VERSION_MAJOR}}
 | 
			
		||||
#define LIBOSMO_GSUP_CLIENT_VERSION_MINOR {{VERSION_MINOR}}
 | 
			
		||||
#define LIBOSMO_GSUP_CLIENT_VERSION_PATCH {{VERSION_PATCH}}
 | 
			
		||||
 | 
			
		||||
#define LIBOSMO_GSUP_CLIENT_VERSION_GREATER_EQUAL(major, minor, patch) \
 | 
			
		||||
	(LIBOSMO_GSUP_CLIENT_VERSION_MAJOR > (major) || \
 | 
			
		||||
	 (LIBOSMO_GSUP_CLIENT_VERSION_MAJOR == (major) && \
 | 
			
		||||
	  LIBOSMO_GSUP_CLIENT_VERSION_MINOR > (minor)) || \
 | 
			
		||||
	 (LIBOSMO_GSUP_CLIENT_VERSION_MAJOR == (major) && \
 | 
			
		||||
	  LIBOSMO_GSUP_CLIENT_VERSION_MINOR == (minor) && \
 | 
			
		||||
	  LIBOSMO_GSUP_CLIENT_VERSION_PATCH >= (patch)))
 | 
			
		||||
@@ -40,6 +40,8 @@ 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_IS_CREATED_ON_DEMAND_BY_IMSI,
 | 
			
		||||
	DB_STMT_EXISTS_BY_MSISDN,
 | 
			
		||||
	DB_STMT_IND_ADD,
 | 
			
		||||
	DB_STMT_IND_SELECT,
 | 
			
		||||
@@ -157,6 +159,8 @@ 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_is_created_on_demand_by_imsi(struct db_context *dbc, const char *imsi, unsigned int msisdn_len);
 | 
			
		||||
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,
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@
 | 
			
		||||
#include <osmocom/gsupclient/cni_peer_id.h>
 | 
			
		||||
#include <osmocom/gsupclient/gsup_req.h>
 | 
			
		||||
 | 
			
		||||
#define OSMO_DGSM_DEFAULT_LOCAL_ATTACH_MAX_AGE	60 * 60
 | 
			
		||||
#define OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS	2000
 | 
			
		||||
#define LOG_DGSM(imsi, level, fmt, args...) \
 | 
			
		||||
	LOGP(DDGSM, level, "(IMSI-%s) " fmt, imsi, ##args)
 | 
			
		||||
 
 | 
			
		||||
@@ -63,8 +63,16 @@ struct hlr {
 | 
			
		||||
 | 
			
		||||
	struct llist_head euse_list;
 | 
			
		||||
	struct hlr_euse *euse_default;
 | 
			
		||||
	enum gsm48_gmm_cause reject_cause;
 | 
			
		||||
	enum gsm48_gmm_cause no_proxy_reject_cause;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		enum gsm48_gmm_cause cs;
 | 
			
		||||
		enum gsm48_gmm_cause ps;
 | 
			
		||||
	} reject_cause;
 | 
			
		||||
	struct {
 | 
			
		||||
		enum gsm48_gmm_cause cs;
 | 
			
		||||
		enum gsm48_gmm_cause ps;
 | 
			
		||||
	} no_proxy_reject_cause;
 | 
			
		||||
 | 
			
		||||
	/* PS: APN default configuration used by Subscription Data on ISR */
 | 
			
		||||
	struct {
 | 
			
		||||
		struct {
 | 
			
		||||
@@ -132,7 +140,10 @@ struct hlr {
 | 
			
		||||
				char *domain_suffix;
 | 
			
		||||
				struct osmo_mslookup_client_method *running;
 | 
			
		||||
			} mdns;
 | 
			
		||||
			bool subscr_create_on_demand_fallback;
 | 
			
		||||
		} client;
 | 
			
		||||
		bool auth_imsi_only;
 | 
			
		||||
		bool ignore_created_on_demand;
 | 
			
		||||
	} mslookup;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -142,3 +153,4 @@ struct hlr_subscriber;
 | 
			
		||||
 | 
			
		||||
void osmo_hlr_subscriber_update_notify(struct hlr_subscriber *subscr);
 | 
			
		||||
int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val, bool is_ps);
 | 
			
		||||
void dgsm_fallback_to_hlr();
 | 
			
		||||
 
 | 
			
		||||
@@ -71,6 +71,8 @@ void proxy_init(struct osmo_gsup_server *gsup_server_to_vlr);
 | 
			
		||||
void proxy_del(struct proxy *proxy);
 | 
			
		||||
void proxy_set_gc_period(struct proxy *proxy, uint32_t gc_period);
 | 
			
		||||
 | 
			
		||||
struct osmo_gsup_req *proxy_deferred_gsup_req_get_by_imsi(struct proxy *proxy, const char *imsi);
 | 
			
		||||
 | 
			
		||||
/* The API to access / modify proxy entries keeps the implementation opaque, to make sure that we can easily move proxy
 | 
			
		||||
 * storage to SQLite db. */
 | 
			
		||||
int proxy_subscr_get_by_imsi(struct proxy_subscr *dst, struct proxy *proxy, const char *imsi);
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,7 @@ enum osmo_mslookup_id_type {
 | 
			
		||||
	OSMO_MSLOOKUP_ID_NONE = 0,
 | 
			
		||||
	OSMO_MSLOOKUP_ID_IMSI,
 | 
			
		||||
	OSMO_MSLOOKUP_ID_MSISDN,
 | 
			
		||||
	OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const struct value_string osmo_mslookup_id_type_names[];
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,8 @@ typedef void (*osmo_mslookup_cb_t)(struct osmo_mslookup_client *client,
 | 
			
		||||
 * This query handling info is not seen by the individual method implementations, to clarify that it is the
 | 
			
		||||
 * osmo_mslookup_client layer that takes care of these details. */
 | 
			
		||||
struct osmo_mslookup_query_handling {
 | 
			
		||||
	bool search_all;
 | 
			
		||||
 | 
			
		||||
	/*! Wait at least this long before returning any results.
 | 
			
		||||
	 *
 | 
			
		||||
	 * If nonzero, result_cb will be called as soon as this delay has elapsed, either with the so far youngest age
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								include/osmocom/mslookup/version.h.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								include/osmocom/mslookup/version.h.tpl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#define LIBOSMO_MSLOOKUP_VERSION {{VERSION}}
 | 
			
		||||
#define LIBOSMO_MSLOOKUP_VERSION_STR "{{VERSION}}"
 | 
			
		||||
 | 
			
		||||
#define LIBOSMO_MSLOOKUP_VERSION_MAJOR {{VERSION_MAJOR}}
 | 
			
		||||
#define LIBOSMO_MSLOOKUP_VERSION_MINOR {{VERSION_MINOR}}
 | 
			
		||||
#define LIBOSMO_MSLOOKUP_VERSION_PATCH {{VERSION_PATCH}}
 | 
			
		||||
 | 
			
		||||
#define LIBOSMO_MSLOOKUP_VERSION_GREATER_EQUAL(major, minor, patch) \
 | 
			
		||||
	(LIBOSMO_MSLOOKUP_VERSION_MAJOR > (major) || \
 | 
			
		||||
	 (LIBOSMO_MSLOOKUP_VERSION_MAJOR == (major) && \
 | 
			
		||||
	  LIBOSMO_MSLOOKUP_VERSION_MINOR > (minor)) || \
 | 
			
		||||
	 (LIBOSMO_MSLOOKUP_VERSION_MAJOR == (major) && \
 | 
			
		||||
	  LIBOSMO_MSLOOKUP_VERSION_MINOR == (minor) && \
 | 
			
		||||
	  LIBOSMO_MSLOOKUP_VERSION_PATCH >= (patch)))
 | 
			
		||||
							
								
								
									
										6
									
								
								src/db.c
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								src/db.c
									
									
									
									
									
								
							@@ -53,7 +53,7 @@
 | 
			
		||||
static const char *stmt_sql[] = {
 | 
			
		||||
	[DB_STMT_SEL_ALL] = "SELECT " SEL_COLUMNS " FROM subscriber;",
 | 
			
		||||
	[DB_STMT_SEL_ALL_ORDER_LAST_SEEN] = "SELECT " SEL_COLUMNS " FROM subscriber "
 | 
			
		||||
		"WHERE last_lu_seen IS NOT NULL ORDER BY last_lu_seen;",
 | 
			
		||||
		"WHERE last_lu_seen IS NOT NULL AND last_lu_seen > datetime('now','-1 month') ORDER BY last_lu_seen;",
 | 
			
		||||
	[DB_STMT_SEL_FILTER_MSISDN] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE msisdn LIKE $search ORDER BY msisdn",
 | 
			
		||||
	[DB_STMT_SEL_FILTER_IMSI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imsi LIKE $search ORDER BY imsi",
 | 
			
		||||
	[DB_STMT_SEL_FILTER_IMEI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imei LIKE $search ORDER BY imei",
 | 
			
		||||
@@ -92,6 +92,10 @@ 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_IS_CREATED_ON_DEMAND_BY_IMSI] =
 | 
			
		||||
		"SELECT 1 FROM subscriber WHERE imsi = $imsi AND length(msisdn) = $msisdn_len"
 | 
			
		||||
		" AND nam_cs = 0 AND nam_ps = 0 AND vlr_number IS NULL",
 | 
			
		||||
	[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",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								src/db_hlr.c
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								src/db_hlr.c
									
									
									
									
									
								
							@@ -555,6 +555,59 @@ 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*! Check if a subscriber exists and has ever been attached
 | 
			
		||||
 * \param[in, out] dbc  database context.
 | 
			
		||||
 * \param[in] imsi  ASCII string of IMSI digits.
 | 
			
		||||
 * \returns 0 if has vlr_number, -ENOENT if not, -EIO on database error.
 | 
			
		||||
 */
 | 
			
		||||
int db_subscr_is_created_on_demand_by_imsi(struct db_context *dbc, const char *imsi, unsigned int msisdn_len) {
 | 
			
		||||
	sqlite3_stmt *stmt = dbc->stmt[DB_STMT_IS_CREATED_ON_DEMAND_BY_IMSI];
 | 
			
		||||
	const char *err;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	if (!db_bind_text(stmt, "$imsi", imsi))
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	if (!db_bind_int(stmt, "$msisdn_len", msisdn_len))
 | 
			
		||||
		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 on demand 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.
 | 
			
		||||
@@ -700,9 +753,12 @@ int db_subscrs_get(struct db_context *dbc, const char *filter_type, const char *
 | 
			
		||||
		copy_sqlite3_text_to_buf(subscr.imei, stmt, 3);
 | 
			
		||||
		subscr.nam_cs = sqlite3_column_int(stmt, 9);
 | 
			
		||||
		subscr.nam_ps = sqlite3_column_int(stmt, 10);
 | 
			
		||||
		if (show_ls)
 | 
			
		||||
		if (show_ls) {
 | 
			
		||||
			parse_last_lu_seen(&subscr.last_lu_seen, (const char *)sqlite3_column_text(stmt, 14),
 | 
			
		||||
					   subscr.imsi, "CS");
 | 
			
		||||
			copy_sqlite3_text_to_buf(subscr.vlr_number, stmt, 4);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		get_cb(&subscr, data);
 | 
			
		||||
		rc = sqlite3_step(stmt);
 | 
			
		||||
		(*count)++;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										21
									
								
								src/dgsm.c
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								src/dgsm.c
									
									
									
									
									
								
							@@ -58,6 +58,12 @@ static void resolve_hlr_result_cb(struct osmo_mslookup_client *client,
 | 
			
		||||
	if (result->rc != OSMO_MSLOOKUP_RC_RESULT) {
 | 
			
		||||
		LOG_DGSM(query->id.imsi, LOGL_ERROR, "Failed to resolve remote HLR: %s\n",
 | 
			
		||||
			 osmo_mslookup_result_name_c(OTC_SELECT, query, result));
 | 
			
		||||
		if (g_hlr->mslookup.client.subscr_create_on_demand_fallback &&
 | 
			
		||||
		    db_subscr_exists_by_imsi(g_hlr->dbc, query->id.imsi) != 0) {
 | 
			
		||||
			struct osmo_gsup_req *req = proxy_deferred_gsup_req_get_by_imsi(proxy, query->id.imsi);
 | 
			
		||||
			if (req && req->gsup.message_type == OSMO_GSUP_MSGT_CHECK_IMEI_REQUEST)
 | 
			
		||||
				dgsm_fallback_to_hlr(req);
 | 
			
		||||
		}
 | 
			
		||||
		proxy_subscr_del(proxy, query->id.imsi);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
@@ -91,8 +97,17 @@ 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;
 | 
			
		||||
	/* unless configuration tells us to do otherwise. */
 | 
			
		||||
	if (!g_hlr->mslookup.ignore_created_on_demand && !g_hlr->mslookup.auth_imsi_only &&
 | 
			
		||||
	    db_subscr_exists_by_imsi(g_hlr->dbc, req->gsup.imsi) == 0)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	if (!g_hlr->mslookup.auth_imsi_only && !(g_hlr->mslookup.ignore_created_on_demand &&
 | 
			
		||||
	    db_subscr_is_created_on_demand_by_imsi(g_hlr->dbc, req->gsup.imsi,
 | 
			
		||||
						   g_hlr->subscr_create_on_demand.rand_msisdn_len) == 0))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	/* Are we already forwarding this IMSI to a remote HLR? */
 | 
			
		||||
@@ -168,7 +183,7 @@ void dgsm_init(void *ctx)
 | 
			
		||||
	dgsm_ctx = talloc_named_const(ctx, 0, "dgsm");
 | 
			
		||||
	INIT_LLIST_HEAD(&g_hlr->mslookup.server.local_site_services);
 | 
			
		||||
 | 
			
		||||
	g_hlr->mslookup.server.local_attach_max_age = 60 * 60;
 | 
			
		||||
	g_hlr->mslookup.server.local_attach_max_age = OSMO_DGSM_DEFAULT_LOCAL_ATTACH_MAX_AGE;
 | 
			
		||||
 | 
			
		||||
	g_hlr->mslookup.client.result_timeout_milliseconds = OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										181
									
								
								src/dgsm_vty.c
									
									
									
									
									
								
							
							
						
						
									
										181
									
								
								src/dgsm_vty.c
									
									
									
									
									
								
							@@ -22,9 +22,11 @@
 | 
			
		||||
#include <osmocom/mslookup/mslookup_client_mdns.h>
 | 
			
		||||
#include <osmocom/mslookup/mdns.h>
 | 
			
		||||
#include <osmocom/hlr/hlr_vty.h>
 | 
			
		||||
#include <osmocom/hlr/proxy.h>
 | 
			
		||||
#include <osmocom/hlr/mslookup_server.h>
 | 
			
		||||
#include <osmocom/hlr/mslookup_server_mdns.h>
 | 
			
		||||
#include <osmocom/gsupclient/cni_peer_id.h>
 | 
			
		||||
#include <osmocom/gsm/gsm23003.h>
 | 
			
		||||
 | 
			
		||||
struct cmd_node mslookup_node = {
 | 
			
		||||
	MSLOOKUP_NODE,
 | 
			
		||||
@@ -188,6 +190,53 @@ DEFUN(cfg_mslookup_server_no_mdns_bind,
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_mslookup_server_max_age,
 | 
			
		||||
      cfg_mslookup_server_max_age_cmd,
 | 
			
		||||
      "max-age <1-21600>",
 | 
			
		||||
      "How old can the Last Location Update be for the mslookup server to respond\n"
 | 
			
		||||
      "max age in seconds\n")
 | 
			
		||||
{
 | 
			
		||||
	uint32_t val = atol(argv[0]);
 | 
			
		||||
	g_hlr->mslookup.server.local_attach_max_age = val;
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_mslookup_cod,
 | 
			
		||||
      cfg_mslookup_cod_cmd,
 | 
			
		||||
      "ignore-created-on-demand",
 | 
			
		||||
      "Ignore IMSIs that were created-on-demand")
 | 
			
		||||
{
 | 
			
		||||
	g_hlr->mslookup.ignore_created_on_demand = true;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_mslookup_no_cod,
 | 
			
		||||
      cfg_mslookup_no_cod_cmd,
 | 
			
		||||
      "no ignore-created-on-demand",
 | 
			
		||||
      NO_STR "Answer mslookup and local GSUP for created on demand IMSIs")
 | 
			
		||||
{
 | 
			
		||||
	g_hlr->mslookup.ignore_created_on_demand = false;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct cmd_node mslookup_server_msc_node = {
 | 
			
		||||
	MSLOOKUP_SERVER_MSC_NODE,
 | 
			
		||||
	"%s(config-mslookup-server-msc)# ",
 | 
			
		||||
@@ -350,6 +399,24 @@ DEFUN(cfg_mslookup_no_client,
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_mslookup_client_subscr_cod_fallback,
 | 
			
		||||
      cfg_mslookup_client_subscr_cod_fallback_cmd,
 | 
			
		||||
      "create-on-demand-fallback",
 | 
			
		||||
      "If the msclient does not get a response from mDNS, proceed according to this HLR subscriber-create-on-demand config")
 | 
			
		||||
{
 | 
			
		||||
	g_hlr->mslookup.client.subscr_create_on_demand_fallback = true;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_mslookup_client_no_subscr_cod_fallback,
 | 
			
		||||
      cfg_mslookup_client_no_subscr_cod_fallback_cmd,
 | 
			
		||||
      "no create-on-demand-fallback",
 | 
			
		||||
      NO_STR "Return IMSI UNKNOWN if the mslookup client does not receive a response from mDNS")
 | 
			
		||||
{
 | 
			
		||||
	g_hlr->mslookup.client.subscr_create_on_demand_fallback = false;
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_mslookup_client_timeout,
 | 
			
		||||
      cfg_mslookup_client_timeout_cmd,
 | 
			
		||||
      "timeout <1-100000>",
 | 
			
		||||
@@ -421,6 +488,11 @@ 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.ignore_created_on_demand)
 | 
			
		||||
			vty_out(vty, " ignore-created-on-demand%s", VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
	if (g_hlr->mslookup.server.enable || !llist_empty(&g_hlr->mslookup.server.local_site_services)) {
 | 
			
		||||
		struct mslookup_server_msc_cfg *msc;
 | 
			
		||||
 | 
			
		||||
@@ -450,6 +522,9 @@ int config_write_mslookup(struct vty *vty)
 | 
			
		||||
			vty_out(vty, "  msc ipa-name %s%s", osmo_ipa_name_to_str(&msc->name), VTY_NEWLINE);
 | 
			
		||||
			config_write_msc_services(vty, "   ", msc);
 | 
			
		||||
		}
 | 
			
		||||
		if (g_hlr->mslookup.server.local_attach_max_age != OSMO_DGSM_DEFAULT_LOCAL_ATTACH_MAX_AGE)
 | 
			
		||||
			vty_out(vty, "  max-age %u%s",
 | 
			
		||||
				g_hlr->mslookup.server.local_attach_max_age, VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
		/* If the server is disabled, still output the above to not lose the service config. */
 | 
			
		||||
		if (!g_hlr->mslookup.server.enable)
 | 
			
		||||
@@ -479,6 +554,8 @@ int config_write_mslookup(struct vty *vty)
 | 
			
		||||
			vty_out(vty, "  timeout %u%s",
 | 
			
		||||
				g_hlr->mslookup.client.result_timeout_milliseconds,
 | 
			
		||||
				VTY_NEWLINE);
 | 
			
		||||
		if (g_hlr->mslookup.client.subscr_create_on_demand_fallback)
 | 
			
		||||
			vty_out(vty, "  create-on-demand-fallback%s", VTY_NEWLINE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
@@ -545,11 +622,110 @@ DEFUN(do_mslookup_show_services,
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct proxy_subscr_listentry {
 | 
			
		||||
	struct llist_head entry;
 | 
			
		||||
	timestamp_t last_update;
 | 
			
		||||
	struct proxy_subscr data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct proxy_pending_gsup_req {
 | 
			
		||||
	struct llist_head entry;
 | 
			
		||||
	struct osmo_gsup_req *req;
 | 
			
		||||
	timestamp_t received_at;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void write_one_proxy(struct vty *vty, struct proxy_subscr_listentry *e)
 | 
			
		||||
{
 | 
			
		||||
	struct proxy_subscr p = e->data;
 | 
			
		||||
	uint32_t age;
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, "%-12s  %-16s  %-12s:%-4u     ",
 | 
			
		||||
		strlen(p.msisdn) == 0 ? "Unknown" : p.msisdn,
 | 
			
		||||
		strlen(p.imsi) == 0 ? "Unknown" : p.imsi,
 | 
			
		||||
		p.remote_hlr_addr.ip ? p.remote_hlr_addr.ip : "Unknown",
 | 
			
		||||
		p.remote_hlr_addr.port);
 | 
			
		||||
 | 
			
		||||
	if (!timestamp_age(&e->last_update, &age)) {
 | 
			
		||||
		vty_out(vty, "Invalid%s", VTY_NEWLINE);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#define UNIT_AGO(UNITNAME, UNITVAL) \
 | 
			
		||||
		if (age >= (UNITVAL)) { \
 | 
			
		||||
			vty_out(vty, "%u%s", age / (UNITVAL), UNITNAME); \
 | 
			
		||||
			age = age % (UNITVAL); \
 | 
			
		||||
		}
 | 
			
		||||
		UNIT_AGO("d", 60*60*24);
 | 
			
		||||
		UNIT_AGO("h", 60*60);
 | 
			
		||||
		UNIT_AGO("m", 60);
 | 
			
		||||
		UNIT_AGO("s", 1);
 | 
			
		||||
		vty_out(vty, "%s", VTY_NEWLINE);
 | 
			
		||||
#undef UNIT_AGO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void write_one_proxy_request(struct vty *vty, struct osmo_gsup_req *r)
 | 
			
		||||
{
 | 
			
		||||
	vty_out(vty, "IMSI: %s TYPE: %s%s",
 | 
			
		||||
		r->gsup.imsi,
 | 
			
		||||
		osmo_gsup_message_type_name(r->gsup.message_type),
 | 
			
		||||
		VTY_NEWLINE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(do_proxy_del_sub,
 | 
			
		||||
      do_proxy_del_sub_cmd,
 | 
			
		||||
      "proxy subscriber-delete [IMSI]",
 | 
			
		||||
      "Subscriber Proxy \n"
 | 
			
		||||
      "Delete by IMSI\n"
 | 
			
		||||
      "IMSI of subscriber to delete from the Proxy"
 | 
			
		||||
      )
 | 
			
		||||
{
 | 
			
		||||
	const char *imsi = argv[0];
 | 
			
		||||
	if (!osmo_imsi_str_valid(imsi)) {
 | 
			
		||||
		vty_out(vty, "%% Not a valid IMSI: %s%s", imsi, VTY_NEWLINE);
 | 
			
		||||
		return CMD_WARNING;
 | 
			
		||||
	}
 | 
			
		||||
	if (proxy_subscr_del(g_hlr->gs->proxy, imsi) == 0)
 | 
			
		||||
		return CMD_SUCCESS;
 | 
			
		||||
	vty_out(vty, "%% Unable to delete a Proxy for: %s%s", imsi, VTY_NEWLINE);
 | 
			
		||||
	return CMD_WARNING;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEFUN(do_proxy_show,
 | 
			
		||||
      do_proxy_show_cmd,
 | 
			
		||||
      "show proxy",
 | 
			
		||||
      SHOW_STR "Proxy Entries\n")
 | 
			
		||||
{
 | 
			
		||||
	struct proxy_subscr_listentry *e;
 | 
			
		||||
	struct proxy_pending_gsup_req *p;
 | 
			
		||||
	unsigned int count = 0;
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, "MSISDN        IMSI              HLR                   AGE%s", VTY_NEWLINE);
 | 
			
		||||
	vty_out(vty, "------------  ----------------  --------------------  ------%s", VTY_NEWLINE);
 | 
			
		||||
	llist_for_each_entry(e, &g_hlr->gs->proxy->subscr_list, entry) {
 | 
			
		||||
		count++;
 | 
			
		||||
		write_one_proxy(vty, e);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, "%s%s",
 | 
			
		||||
		(count == 0) ? "% No proxy subscribers" : "", VTY_NEWLINE);
 | 
			
		||||
	if (!llist_count(&g_hlr->gs->proxy->pending_gsup_reqs))
 | 
			
		||||
		return CMD_SUCCESS;
 | 
			
		||||
	vty_out(vty, "In-flight Proxy Subscribers Requests:%s", VTY_NEWLINE);
 | 
			
		||||
	llist_for_each_entry(p, &g_hlr->gs->proxy->pending_gsup_reqs, entry) {
 | 
			
		||||
		write_one_proxy_request(vty, p->req);
 | 
			
		||||
	}
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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_cod_cmd);
 | 
			
		||||
	install_element(MSLOOKUP_NODE, &cfg_mslookup_no_cod_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);
 | 
			
		||||
@@ -563,6 +739,7 @@ void dgsm_vty_init(void)
 | 
			
		||||
	install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_service_cmd);
 | 
			
		||||
	install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_no_service_cmd);
 | 
			
		||||
	install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_no_service_addr_cmd);
 | 
			
		||||
	install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_max_age_cmd);
 | 
			
		||||
	install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_cmd);
 | 
			
		||||
 | 
			
		||||
	install_node(&mslookup_server_msc_node, NULL);
 | 
			
		||||
@@ -573,6 +750,8 @@ void dgsm_vty_init(void)
 | 
			
		||||
	install_element(MSLOOKUP_NODE, &cfg_mslookup_client_cmd);
 | 
			
		||||
	install_element(MSLOOKUP_NODE, &cfg_mslookup_no_client_cmd);
 | 
			
		||||
	install_node(&mslookup_client_node, NULL);
 | 
			
		||||
	install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_subscr_cod_fallback_cmd);
 | 
			
		||||
	install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_subscr_cod_fallback_cmd);
 | 
			
		||||
	install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_timeout_cmd);
 | 
			
		||||
	install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_mdns_bind_cmd);
 | 
			
		||||
	install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_mdns_domain_suffix_cmd);
 | 
			
		||||
@@ -581,4 +760,6 @@ void dgsm_vty_init(void)
 | 
			
		||||
	install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_gateway_proxy_cmd);
 | 
			
		||||
 | 
			
		||||
	install_element_ve(&do_mslookup_show_services_cmd);
 | 
			
		||||
	install_element_ve(&do_proxy_show_cmd);
 | 
			
		||||
	install_element_ve(&do_proxy_del_sub_cmd);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								src/hlr.c
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								src/hlr.c
									
									
									
									
									
								
							@@ -333,7 +333,11 @@ static int rx_send_auth_info(struct osmo_gsup_req *req)
 | 
			
		||||
						  " Returning slightly inaccurate cause 'IMSI Unknown' via GSUP");
 | 
			
		||||
			return rc;
 | 
			
		||||
		case -ENOENT:
 | 
			
		||||
			osmo_gsup_req_respond_err(req, g_hlr->reject_cause, "IMSI unknown");
 | 
			
		||||
			osmo_gsup_req_respond_err(req,
 | 
			
		||||
						  (req->gsup.cn_domain == OSMO_GSUP_CN_DOMAIN_CS) ?
 | 
			
		||||
						  g_hlr->no_proxy_reject_cause.cs :
 | 
			
		||||
						  g_hlr->no_proxy_reject_cause.ps,
 | 
			
		||||
						  "IMSI unknown");
 | 
			
		||||
			return rc;
 | 
			
		||||
		default:
 | 
			
		||||
			osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "failure to look up IMSI in db");
 | 
			
		||||
@@ -391,7 +395,7 @@ static int rx_purge_ms_req(struct osmo_gsup_req *req)
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int rx_check_imei_req(struct osmo_gsup_req *req)
 | 
			
		||||
static int rx_check_imei_req(struct osmo_gsup_req *req, bool final)
 | 
			
		||||
{
 | 
			
		||||
	struct osmo_gsup_message gsup_reply;
 | 
			
		||||
	char imei[GSM23003_IMEI_NUM_DIGITS_NO_CHK+1] = {0};
 | 
			
		||||
@@ -445,7 +449,7 @@ static int rx_check_imei_req(struct osmo_gsup_req *req)
 | 
			
		||||
		.message_type = OSMO_GSUP_MSGT_CHECK_IMEI_RESULT,
 | 
			
		||||
		.imei_result = OSMO_GSUP_IMEI_RESULT_ACK,
 | 
			
		||||
	};
 | 
			
		||||
	return osmo_gsup_req_respond(req, &gsup_reply, false, true);
 | 
			
		||||
	return osmo_gsup_req_respond(req, &gsup_reply, false, final);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char namebuf[255];
 | 
			
		||||
@@ -566,7 +570,7 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
 | 
			
		||||
		lu_rx_gsup(req);
 | 
			
		||||
		break;
 | 
			
		||||
	case OSMO_GSUP_MSGT_CHECK_IMEI_REQUEST:
 | 
			
		||||
		rx_check_imei_req(req);
 | 
			
		||||
		rx_check_imei_req(req, true);
 | 
			
		||||
		break;
 | 
			
		||||
	case OSMO_GSUP_MSGT_MO_FORWARD_SM_REQUEST:
 | 
			
		||||
		forward_mo_sms(req);
 | 
			
		||||
@@ -586,6 +590,12 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dgsm_fallback_to_hlr(struct osmo_gsup_req *req) {
 | 
			
		||||
	LOGP(DDGSM, LOGL_DEBUG, "Fall back to HLR from DGSM for [%s]\n",
 | 
			
		||||
	     osmo_gsup_message_type_name(req->gsup.message_type));
 | 
			
		||||
	rx_check_imei_req(req, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void print_usage(void)
 | 
			
		||||
{
 | 
			
		||||
	printf("Usage: osmo-hlr\n");
 | 
			
		||||
@@ -778,8 +788,10 @@ int main(int argc, char **argv)
 | 
			
		||||
	g_hlr->db_file_path = talloc_strdup(g_hlr, HLR_DEFAULT_DB_FILE_PATH);
 | 
			
		||||
	g_hlr->mslookup.server.mdns.domain_suffix = talloc_strdup(g_hlr, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT);
 | 
			
		||||
	g_hlr->mslookup.client.mdns.domain_suffix = talloc_strdup(g_hlr, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT);
 | 
			
		||||
	g_hlr->reject_cause = GMM_CAUSE_PLMN_NOTALLOWED;
 | 
			
		||||
	g_hlr->no_proxy_reject_cause = GMM_CAUSE_NET_FAIL;
 | 
			
		||||
	g_hlr->reject_cause.cs = GMM_CAUSE_PLMN_NOTALLOWED;
 | 
			
		||||
	g_hlr->no_proxy_reject_cause.cs = GMM_CAUSE_PLMN_NOTALLOWED;
 | 
			
		||||
	g_hlr->reject_cause.ps = GMM_CAUSE_NET_FAIL;
 | 
			
		||||
	g_hlr->no_proxy_reject_cause.ps = GMM_CAUSE_NET_FAIL;
 | 
			
		||||
 | 
			
		||||
	/* Init default (call independent) SS session guard timeout value */
 | 
			
		||||
	g_hlr->ncss_guard_timeout = NCSS_GUARD_TIMEOUT_DEFAULT;
 | 
			
		||||
 
 | 
			
		||||
@@ -320,12 +320,22 @@ static int config_write_hlr(struct vty *vty)
 | 
			
		||||
{
 | 
			
		||||
	vty_out(vty, "hlr%s", VTY_NEWLINE);
 | 
			
		||||
 | 
			
		||||
	vty_out(vty, " reject-cause not-found %s%s",
 | 
			
		||||
		get_value_string_or_null(gsm48_gmm_cause_vty_names,
 | 
			
		||||
					 (uint32_t) g_hlr->reject_cause), VTY_NEWLINE);
 | 
			
		||||
	vty_out(vty, " reject-cause no-proxy %s%s",
 | 
			
		||||
		get_value_string_or_null(gsm48_gmm_cause_vty_names,
 | 
			
		||||
					 (uint32_t) g_hlr->no_proxy_reject_cause), VTY_NEWLINE);
 | 
			
		||||
	if (g_hlr->reject_cause.cs != GMM_CAUSE_PLMN_NOTALLOWED)
 | 
			
		||||
		vty_out(vty, " reject-cause not-found cs %s%s",
 | 
			
		||||
			get_value_string_or_null(gsm48_gmm_cause_vty_names,
 | 
			
		||||
						 (uint32_t) g_hlr->reject_cause.cs), VTY_NEWLINE);
 | 
			
		||||
	if (g_hlr->reject_cause.ps != GMM_CAUSE_PLMN_NOTALLOWED)
 | 
			
		||||
		vty_out(vty, " reject-cause not-found ps %s%s",
 | 
			
		||||
			get_value_string_or_null(gsm48_gmm_cause_vty_names,
 | 
			
		||||
						 (uint32_t) g_hlr->reject_cause.ps), VTY_NEWLINE);
 | 
			
		||||
	if (g_hlr->no_proxy_reject_cause.cs != GMM_CAUSE_NET_FAIL)
 | 
			
		||||
		vty_out(vty, " reject-cause no-proxy cs %s%s",
 | 
			
		||||
			get_value_string_or_null(gsm48_gmm_cause_vty_names,
 | 
			
		||||
						 (uint32_t) g_hlr->no_proxy_reject_cause.cs), VTY_NEWLINE);
 | 
			
		||||
	if (g_hlr->no_proxy_reject_cause.ps != GMM_CAUSE_NET_FAIL)
 | 
			
		||||
		vty_out(vty, " reject-cause no-proxy ps %s%s",
 | 
			
		||||
			get_value_string_or_null(gsm48_gmm_cause_vty_names,
 | 
			
		||||
						 (uint32_t) g_hlr->no_proxy_reject_cause.ps), VTY_NEWLINE);
 | 
			
		||||
	if (g_hlr->store_imei)
 | 
			
		||||
		vty_out(vty, " store-imei%s", VTY_NEWLINE);
 | 
			
		||||
	if (g_hlr->db_file_path && strcmp(g_hlr->db_file_path, HLR_DEFAULT_DB_FILE_PATH))
 | 
			
		||||
@@ -782,17 +792,27 @@ static int config_write_smsc(struct vty *vty)
 | 
			
		||||
DEFUN(cfg_reject_cause, cfg_reject_cause_cmd,
 | 
			
		||||
      "reject-cause TYPE CAUSE", "") /* Dynamically Generated */
 | 
			
		||||
{
 | 
			
		||||
	int cause_code = get_string_value(gsm48_gmm_cause_vty_names, argv[1]);
 | 
			
		||||
	int cause_code = get_string_value(gsm48_gmm_cause_vty_names, argv[2]);
 | 
			
		||||
	OSMO_ASSERT(cause_code >= 0);
 | 
			
		||||
 | 
			
		||||
	if (strcmp(argv[0], "not-found") == 0)
 | 
			
		||||
		g_hlr->reject_cause = (enum gsm48_gmm_cause) cause_code;
 | 
			
		||||
	if (strcmp(argv[0], "no-proxy") == 0)
 | 
			
		||||
		g_hlr->no_proxy_reject_cause = (enum gsm48_gmm_cause) cause_code;
 | 
			
		||||
	if (strcmp(argv[0], "not-found") == 0) {
 | 
			
		||||
		if (strcmp(argv[1], "cs") == 0)
 | 
			
		||||
			g_hlr->reject_cause.cs = (enum gsm48_gmm_cause) cause_code;
 | 
			
		||||
		else
 | 
			
		||||
			g_hlr->reject_cause.ps = (enum gsm48_gmm_cause) cause_code;
 | 
			
		||||
	}
 | 
			
		||||
	if (strcmp(argv[0], "no-proxy") == 0) {
 | 
			
		||||
		if (strcmp(argv[1], "cs") == 0)
 | 
			
		||||
			g_hlr->no_proxy_reject_cause.cs = (enum gsm48_gmm_cause) cause_code;
 | 
			
		||||
		else
 | 
			
		||||
			g_hlr->no_proxy_reject_cause.ps = (enum gsm48_gmm_cause) cause_code;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return CMD_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DEFUN(cfg_store_imei, cfg_store_imei_cmd,
 | 
			
		||||
	"store-imei",
 | 
			
		||||
	"Save the IMEI in the database when receiving Check IMEI requests. Note that an MSC does not necessarily send"
 | 
			
		||||
@@ -886,7 +906,7 @@ void hlr_vty_init(void *hlr_ctx)
 | 
			
		||||
	cfg_reject_cause_cmd.string =
 | 
			
		||||
		vty_cmd_string_from_valstr(hlr_ctx,
 | 
			
		||||
					   gsm48_gmm_cause_vty_names,
 | 
			
		||||
					   "reject-cause (not-found|no-proxy) (", "|", ")",
 | 
			
		||||
					   "reject-cause (not-found|no-proxy) (cs|ps) (", "|", ")",
 | 
			
		||||
					   VTY_DO_LOWER);
 | 
			
		||||
 | 
			
		||||
	cfg_reject_cause_cmd.doc =
 | 
			
		||||
@@ -894,7 +914,9 @@ void hlr_vty_init(void *hlr_ctx)
 | 
			
		||||
					   gsm48_gmm_cause_vty_descs,
 | 
			
		||||
					   "GSUP/GMM cause to be sent\n"
 | 
			
		||||
					   "in the case the IMSI could not be found in the database\n"
 | 
			
		||||
					   "in the case no remote HLR reponded to mslookup GSUP request\n",
 | 
			
		||||
					   "in the case no remote HLR reponded to mslookup GSUP request\n"
 | 
			
		||||
					   "for CS domain\n"
 | 
			
		||||
					   "for PS domain\n",
 | 
			
		||||
					   "\n", "", 0);
 | 
			
		||||
 | 
			
		||||
	logging_vty_add_cmds();
 | 
			
		||||
 
 | 
			
		||||
@@ -182,8 +182,11 @@ static void subscr_dump_summary_vty(struct hlr_subscriber *subscr, void *data)
 | 
			
		||||
		vty_out(vty,"   ------------- ");
 | 
			
		||||
	}
 | 
			
		||||
	vty_out(vty, "   %-2s%-2s  ", subscr->nam_cs ? "CS" : "", subscr->nam_ps ? "PS" : "");
 | 
			
		||||
	if (subscr->last_lu_seen)
 | 
			
		||||
	if (subscr->last_lu_seen) {
 | 
			
		||||
		/* VLR Number is max length 32, possibly truncate here */
 | 
			
		||||
		vty_out(vty, " %.22s ", subscr->vlr_number);
 | 
			
		||||
		dump_last_lu_seen(vty, "CS", subscr->last_lu_seen, true);
 | 
			
		||||
	}
 | 
			
		||||
	vty_out_newline(vty);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -218,8 +221,8 @@ static void dump_summary_table_vty(struct vty *vty, bool header, bool show_ls)
 | 
			
		||||
{
 | 
			
		||||
	const char *texts = "ID     MSISDN        IMSI              IMEI              NAM";
 | 
			
		||||
	const char *lines = "-----  ------------  ----------------  ----------------  -----";
 | 
			
		||||
	const char *ls_text = "    LAST SEEN";
 | 
			
		||||
	const char *ls_line = "  ------------";
 | 
			
		||||
	const char *ls_text = "    VLR_NUMBER             LAST SEEN      ";
 | 
			
		||||
	const char *ls_line = "  ---------------------  ---------------------";
 | 
			
		||||
	if (header) {
 | 
			
		||||
		if (!show_ls)
 | 
			
		||||
			vty_out(vty, "%s%s%s%s", texts, VTY_NEWLINE, lines, VTY_NEWLINE);
 | 
			
		||||
 
 | 
			
		||||
@@ -136,7 +136,8 @@ static void lu_start(struct osmo_gsup_req *update_location_req)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (db_subscr_get_by_imsi(g_hlr->dbc, update_location_req->gsup.imsi, &lu->subscr) < 0) {
 | 
			
		||||
		lu_failure(lu, g_hlr->reject_cause, "Subscriber does not exist");
 | 
			
		||||
		lu_failure(lu, (lu->is_ps) ? g_hlr->reject_cause.ps : g_hlr->reject_cause.cs,
 | 
			
		||||
			   "Subscriber does not exist");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,7 @@ static char *domain_from_query(void *ctx, const struct osmo_mslookup_query *quer
 | 
			
		||||
	/* Get id from query */
 | 
			
		||||
	switch (query->id.type) {
 | 
			
		||||
		case OSMO_MSLOOKUP_ID_IMSI:
 | 
			
		||||
		case OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED:
 | 
			
		||||
			id = query->id.imsi;
 | 
			
		||||
			break;
 | 
			
		||||
		case OSMO_MSLOOKUP_ID_MSISDN:
 | 
			
		||||
 
 | 
			
		||||
@@ -91,6 +91,7 @@ const struct value_string osmo_mslookup_id_type_names[] = {
 | 
			
		||||
	{ OSMO_MSLOOKUP_ID_NONE, "none" },
 | 
			
		||||
	{ OSMO_MSLOOKUP_ID_IMSI, "imsi" },
 | 
			
		||||
	{ OSMO_MSLOOKUP_ID_MSISDN, "msisdn" },
 | 
			
		||||
	{ OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED, "imsiauth" },
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -134,6 +135,7 @@ bool osmo_mslookup_id_valid(const struct osmo_mslookup_id *id)
 | 
			
		||||
{
 | 
			
		||||
	switch (id->type) {
 | 
			
		||||
	case OSMO_MSLOOKUP_ID_IMSI:
 | 
			
		||||
	case OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED:
 | 
			
		||||
		return osmo_imsi_str_valid(id->imsi);
 | 
			
		||||
	case OSMO_MSLOOKUP_ID_MSISDN:
 | 
			
		||||
		return osmo_msisdn_str_valid(id->msisdn);
 | 
			
		||||
@@ -157,6 +159,7 @@ size_t osmo_mslookup_id_name_buf(char *buf, size_t buflen, const struct osmo_msl
 | 
			
		||||
	struct osmo_strbuf sb = { .buf = buf, .len = buflen };
 | 
			
		||||
	switch (id->type) {
 | 
			
		||||
	case OSMO_MSLOOKUP_ID_IMSI:
 | 
			
		||||
	case OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED:
 | 
			
		||||
		OSMO_STRBUF_PRINTF(sb, "%s", id->imsi);
 | 
			
		||||
		break;
 | 
			
		||||
	case OSMO_MSLOOKUP_ID_MSISDN:
 | 
			
		||||
@@ -298,6 +301,7 @@ int osmo_mslookup_query_init_from_domain_str(struct osmo_mslookup_query *q, cons
 | 
			
		||||
	id = second_last_dot + 1;
 | 
			
		||||
	switch (q->id.type) {
 | 
			
		||||
	case OSMO_MSLOOKUP_ID_IMSI:
 | 
			
		||||
	case OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED:
 | 
			
		||||
		rc = token(q->id.imsi, sizeof(q->id.imsi), id, last_dot);
 | 
			
		||||
		if (rc)
 | 
			
		||||
			return rc;
 | 
			
		||||
 
 | 
			
		||||
@@ -154,16 +154,20 @@ void osmo_mslookup_client_rx_result(struct osmo_mslookup_client *client, uint32_
 | 
			
		||||
	if (result->rc != OSMO_MSLOOKUP_RC_RESULT)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* If the client wants to see all results, send this result now */
 | 
			
		||||
	if (req->handling.search_all && result->age > 0)
 | 
			
		||||
		req->handling.result_cb(client, request_handle, &req->query, result);
 | 
			
		||||
 | 
			
		||||
	/* If we already stored an earlier successful result, keep that if its age is younger. */
 | 
			
		||||
	if (req->result.rc == OSMO_MSLOOKUP_RC_RESULT
 | 
			
		||||
	    && result->age >= req->result.age)
 | 
			
		||||
	    && result->age > req->result.age)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	req->result = *result;
 | 
			
		||||
 | 
			
		||||
	/* If age == 0, it doesn't get any better, so return the result immediately. */
 | 
			
		||||
	if (req->result.age == 0) {
 | 
			
		||||
		osmo_mslookup_request_send_result(req, true);
 | 
			
		||||
		osmo_mslookup_request_send_result(req, !req->handling.search_all);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -133,6 +133,10 @@ CSV_HEADERS "\n"
 | 
			
		||||
"		1000-5000@sip.voice.123.msisdn	Same, but silent for first second\n"
 | 
			
		||||
"		10000-@smpp.sms.567.msisdn	Return 1 result after 10 seconds\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"--search-all -A\n"
 | 
			
		||||
"	Do not stop when a response with age of zero comes in.\n"
 | 
			
		||||
"	This can be used to \"search\" the entire dGSM network if for\n"
 | 
			
		||||
"	example there is a need to track down so-called \"evil twin\" hlr entries.\n"
 | 
			
		||||
"--format -f csv (default)\n"
 | 
			
		||||
"	Format result lines in CSV format.\n"
 | 
			
		||||
"--no-csv-headers -H\n"
 | 
			
		||||
@@ -196,6 +200,7 @@ enum result_format {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
	bool search_all;
 | 
			
		||||
	bool daemon;
 | 
			
		||||
	struct osmo_sockaddr_str mdns_addr;
 | 
			
		||||
	uint32_t min_delay;
 | 
			
		||||
@@ -637,6 +642,7 @@ void start_query_str(const char *query_str)
 | 
			
		||||
	const char *domain_str = query_str;
 | 
			
		||||
	char *at;
 | 
			
		||||
	struct osmo_mslookup_query_handling h = {
 | 
			
		||||
		.search_all = cmdline_opts.search_all,
 | 
			
		||||
		.min_wait_milliseconds = cmdline_opts.min_delay,
 | 
			
		||||
		.result_timeout_milliseconds = cmdline_opts.timeout,
 | 
			
		||||
		.result_cb = mslookup_result_cb,
 | 
			
		||||
@@ -739,6 +745,7 @@ int main(int argc, char **argv)
 | 
			
		||||
		int option_index = 0;
 | 
			
		||||
 | 
			
		||||
		static struct option long_options[] = {
 | 
			
		||||
			{ "search-all", 0, 0, 'A' },
 | 
			
		||||
			{ "format", 1, 0, 'f' },
 | 
			
		||||
			{ "no-csv-headers", 0, 0, 'H' },
 | 
			
		||||
			{ "daemon", 0, 0, 'd' },
 | 
			
		||||
@@ -764,12 +771,15 @@ int main(int argc, char **argv)
 | 
			
		||||
		} \
 | 
			
		||||
	} while (0)
 | 
			
		||||
 | 
			
		||||
		c = getopt_long(argc, argv, "f:Hdm:M:D:t:T:s:SqhV", long_options, &option_index);
 | 
			
		||||
		c = getopt_long(argc, argv, "Af:Hdm:M:D:t:T:s:SqhV", long_options, &option_index);
 | 
			
		||||
 | 
			
		||||
		if (c == -1)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		switch (c) {
 | 
			
		||||
		case 'A':
 | 
			
		||||
			cmdline_opts.search_all = true;
 | 
			
		||||
			break;
 | 
			
		||||
		case 'f':
 | 
			
		||||
			cmdline_opts.format_str = optarg;
 | 
			
		||||
			break;
 | 
			
		||||
 
 | 
			
		||||
@@ -192,12 +192,37 @@ static void mslookup_server_rx_hlr_gsup(const struct osmo_mslookup_query *query,
 | 
			
		||||
{
 | 
			
		||||
	const struct mslookup_service_host *host;
 | 
			
		||||
	int rc;
 | 
			
		||||
	bool exists = false;
 | 
			
		||||
	bool auth_imsi_only = false;
 | 
			
		||||
	bool created_on_demand = false;
 | 
			
		||||
 | 
			
		||||
	switch (query->id.type) {
 | 
			
		||||
	case OSMO_MSLOOKUP_ID_IMSI_AUTHORIZED:
 | 
			
		||||
		auth_imsi_only = true;
 | 
			
		||||
	case OSMO_MSLOOKUP_ID_IMSI:
 | 
			
		||||
		/* Entries that have been created by subscriber create on demand
 | 
			
		||||
		   will have default msisdn length. and will not have any vlr_number entry.
 | 
			
		||||
		   We should not answer for these, unless they have CS/PS service. */
 | 
			
		||||
		if (g_hlr->mslookup.ignore_created_on_demand) {
 | 
			
		||||
			rc = db_subscr_is_created_on_demand_by_imsi(g_hlr->dbc, query->id.imsi,
 | 
			
		||||
								    g_hlr->subscr_create_on_demand.rand_msisdn_len);
 | 
			
		||||
			if (!rc) {
 | 
			
		||||
				exists = true;
 | 
			
		||||
				created_on_demand = true;
 | 
			
		||||
				rc = -ENOENT;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		rc = db_subscr_exists_by_imsi(g_hlr->dbc, query->id.imsi);
 | 
			
		||||
		if (g_hlr->mslookup.auth_imsi_only || 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);
 | 
			
		||||
		/* FIXME: The log message below might not match */
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		LOGP(DMSLOOKUP, LOGL_ERROR, "Unknown mslookup ID type: %d\n", query->id.type);
 | 
			
		||||
@@ -206,8 +231,11 @@ 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%s%s in local HLR\n",
 | 
			
		||||
		     osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
 | 
			
		||||
		     (exists) ? "exists but" : "does not exist",
 | 
			
		||||
		     (created_on_demand) ? " is created on demand and since untouched" : "",
 | 
			
		||||
		     (exists && !created_on_demand) ? " is not authorized" : "");
 | 
			
		||||
		*result = not_found;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								src/proxy.c
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/proxy.c
									
									
									
									
									
								
							@@ -92,7 +92,11 @@ static void proxy_pending_req_remote_hlr_connect_result(struct osmo_gsup_req *re
 | 
			
		||||
			osmo_gsup_req_respond(req, &gsup_reply, false, true);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		osmo_gsup_req_respond_err(req, g_hlr->no_proxy_reject_cause,
 | 
			
		||||
 | 
			
		||||
		osmo_gsup_req_respond_err(req,
 | 
			
		||||
					  (req->gsup.cn_domain == OSMO_GSUP_CN_DOMAIN_CS) ?
 | 
			
		||||
					  g_hlr->no_proxy_reject_cause.cs :
 | 
			
		||||
					  g_hlr->no_proxy_reject_cause.ps,
 | 
			
		||||
					  "Proxy: Failed to connect to home HLR");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
@@ -113,6 +117,19 @@ static bool proxy_deferred_gsup_req_waiting(struct proxy *proxy, const char *ims
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct osmo_gsup_req *proxy_deferred_gsup_req_get_by_imsi(struct proxy *proxy, const char *imsi)
 | 
			
		||||
{
 | 
			
		||||
	struct proxy_pending_gsup_req *p;
 | 
			
		||||
	OSMO_ASSERT(imsi);
 | 
			
		||||
 | 
			
		||||
	llist_for_each_entry(p, &proxy->pending_gsup_reqs, entry) {
 | 
			
		||||
		if (strcmp(p->req->gsup.imsi, imsi))
 | 
			
		||||
			continue;
 | 
			
		||||
		return p->req;
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Result of looking for remote HLR. If it failed, pass remote_hlr as NULL. On failure, the remote_hlr may be passed
 | 
			
		||||
 * NULL. */
 | 
			
		||||
static void proxy_deferred_gsup_req_pop(struct proxy *proxy, const char *imsi, struct remote_hlr *remote_hlr)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user