aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2019-11-05 21:24:45 +0100
committerNeels Hofmeyr <neels@hofmeyr.de>2019-11-11 05:31:59 +0100
commit0a5eac957a3997c1048396af0e69fcf914a17c9e (patch)
treebac05f196fe44ef09d5e6a23f03d945b32367629
parent82f4521319f37868a26b07ee89ea739e611cac98 (diff)
dgsm: osmo-hlr is opening mDNS server and client sockets
-rw-r--r--sql/hlr.sql3
-rw-r--r--src/Makefile.am3
-rw-r--r--src/db.c6
-rw-r--r--src/db.h2
-rw-r--r--src/db_hlr.c17
-rw-r--r--src/dgsm.c225
-rw-r--r--src/dgsm.h51
-rw-r--r--src/dgsm_vty.c182
-rw-r--r--src/global_title.c5
-rw-r--r--src/global_title.h1
-rw-r--r--src/hlr.c12
-rw-r--r--src/hlr.h12
-rw-r--r--src/mslookup_server.c269
-rw-r--r--src/mslookup_server.h10
-rw-r--r--src/mslookup_server_mdns.c163
-rw-r--r--src/mslookup_server_mdns.h14
-rw-r--r--src/proxy.c92
-rw-r--r--src/proxy.h37
-rw-r--r--tests/db/db_test.c2
-rw-r--r--tests/db_upgrade/db_upgrade_test.ok15
-rw-r--r--tests/test_nodes.vty14
21 files changed, 824 insertions, 311 deletions
diff --git a/sql/hlr.sql b/sql/hlr.sql
index b951632..1bfd86f 100644
--- a/sql/hlr.sql
+++ b/sql/hlr.sql
@@ -45,7 +45,8 @@ CREATE TABLE subscriber (
last_lu_seen TIMESTAMP default NULL,
-- When a LU was received via a proxy, that proxy's hlr_number is stored here,
-- while vlr_number reflects the MSC on the far side of that proxy.
- vlr_via_proxy VARCHAR
+ vlr_via_proxy VARCHAR,
+ sgsn_via_proxy VARCHAR
);
CREATE TABLE subscriber_apn (
diff --git a/src/Makefile.am b/src/Makefile.am
index 1b8e85c..3485ce6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -42,6 +42,8 @@ noinst_HEADERS = \
dgsm.h \
remote_hlr.h \
global_title.h \
+ mslookup_server.h \
+ mslookup_server_mdns.h \
$(NULL)
bin_PROGRAMS = \
@@ -71,6 +73,7 @@ osmo_hlr_SOURCES = \
dgsm_vty.c \
remote_hlr.c \
mslookup_server.c \
+ mslookup_server_mdns.c \
global_title.c \
$(NULL)
diff --git a/src/db.c b/src/db.c
index 4fcbad2..4d62aa0 100644
--- a/src/db.c
+++ b/src/db.c
@@ -47,7 +47,8 @@
"ms_purged_cs," \
"ms_purged_ps," \
"last_lu_seen," \
- "vlr_via_proxy"
+ "vlr_via_proxy," \
+ "sgsn_via_proxy"
static const char *stmt_sql[] = {
[DB_STMT_SEL_BY_IMSI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imsi = ?",
@@ -55,7 +56,7 @@ static const char *stmt_sql[] = {
[DB_STMT_SEL_BY_ID] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE id = ?",
[DB_STMT_SEL_BY_IMEI] = "SELECT " SEL_COLUMNS " FROM subscriber WHERE imei = ?",
[DB_STMT_UPD_VLR_BY_ID] = "UPDATE subscriber SET vlr_number = $number, vlr_via_proxy = $proxy WHERE id = $subscriber_id",
- [DB_STMT_UPD_SGSN_BY_ID] = "UPDATE subscriber SET sgsn_number = $number WHERE id = $subscriber_id",
+ [DB_STMT_UPD_SGSN_BY_ID] = "UPDATE subscriber SET sgsn_number = $number, sgsn_via_proxy = $proxy WHERE id = $subscriber_id",
[DB_STMT_UPD_IMEI_BY_IMSI] = "UPDATE subscriber SET imei = $imei WHERE imsi = $imsi",
[DB_STMT_AUC_BY_IMSI] =
"SELECT id, algo_id_2g, ki, algo_id_3g, k, op, opc, sqn, ind_bitlen"
@@ -456,6 +457,7 @@ static int db_upgrade_v4(struct db_context *dbc)
int rc;
const char *statements[] = {
"ALTER TABLE subscriber ADD COLUMN vlr_via_proxy VARCHAR",
+ "ALTER TABLE subscriber ADD COLUMN sgsn_via_proxy VARCHAR",
"PRAGMA user_version = 4",
};
diff --git a/src/db.h b/src/db.h
index ce11e11..3f7e5c4 100644
--- a/src/db.h
+++ b/src/db.h
@@ -185,5 +185,5 @@ int hlr_subscr_nam(struct hlr *hlr, struct hlr_subscriber *subscr, bool nam_val,
#define copy_sqlite3_text_to_gt(gt, stmt, idx) \
do { \
const char *_txt = (const char *) sqlite3_column_text(stmt, idx); \
- global_title_set(gt, (uint8_t*)_txt, _txt ? strlen(_txt)+1 : 0); \
+ global_title_set_str(gt, _txt); \
} while (0)
diff --git a/src/db_hlr.c b/src/db_hlr.c
index af1e1b2..8d606f8 100644
--- a/src/db_hlr.c
+++ b/src/db_hlr.c
@@ -739,15 +739,14 @@ int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
if (!db_bind_text(stmt, "$number", (char*)vlr_or_sgsn_number->val))
return -EIO;
- if (!is_ps) {
- if (gsup_peer && gsup_peer->len
- && global_title_cmp(gsup_peer, vlr_or_sgsn_number)) {
- if (!db_bind_text(stmt, "$proxy", (char*)gsup_peer->val))
- return -EIO;
- } else {
- if (!db_bind_null(stmt, "$proxy"))
- return -EIO;
- }
+ /* If the VLR/SGSN is not the direct GSUP peer, the gsup_peer is a proxy towards the actual VLR/SGSN.
+ * -> store the gsup_peer as proxy only when it differs from the vlr_or_sgsn_number. */
+ if (global_title_cmp(gsup_peer, vlr_or_sgsn_number)) {
+ if (!db_bind_text(stmt, "$proxy", (char*)gsup_peer->val))
+ return -EIO;
+ } else {
+ if (!db_bind_null(stmt, "$proxy"))
+ return -EIO;
}
/* execute the statement */
diff --git a/src/dgsm.c b/src/dgsm.c
index 0482523..a91ffc0 100644
--- a/src/dgsm.c
+++ b/src/dgsm.c
@@ -1,7 +1,7 @@
#include <errno.h>
#include <osmocom/core/logging.h>
#include <osmocom/mslookup/mslookup_client.h>
-#include <osmocom/mslookup/mslookup_client_dns.h>
+#include <osmocom/mslookup/mslookup_client_mdns.h>
#include <osmocom/gsupclient/gsup_client.h>
#include "logging.h"
#include "hlr.h"
@@ -10,36 +10,25 @@
#include "dgsm.h"
#include "proxy.h"
#include "remote_hlr.h"
-#include "mslookup_server.h"
+#include "mslookup_server_mdns.h"
+#include "global_title.h"
#define LOG_DGSM(imsi, level, fmt, args...) \
LOGP(DDGSM, level, "(IMSI-%s) " fmt, imsi, ##args)
void *dgsm_ctx = NULL;
-struct dgsm_config dgsm_config = {
- .server = {
- .dns = {
- .multicast_bind_addr = {
- .ip = OSMO_MSLOOKUP_MDNS_IP4,
- .port = OSMO_MSLOOKUP_MDNS_PORT,
- },
- },
- },
-};
+const struct global_title dgsm_config_msc_wildcard = {};
-struct dgsm_msc_config *dgsm_config_msc_get(const uint8_t *ipa_unit_name, size_t ipa_unit_name_len,
- bool create)
+struct dgsm_msc_config *dgsm_config_msc_get(const struct global_title *msc_name, bool create)
{
struct dgsm_msc_config *msc;
- if (!ipa_unit_name)
+ if (!msc_name)
return NULL;
- llist_for_each_entry(msc, &dgsm_config.server.msc_configs, entry) {
- if (ipa_unit_name_len != msc->unit_name_len)
- continue;
- if (memcmp(ipa_unit_name, msc->unit_name, ipa_unit_name_len))
+ llist_for_each_entry(msc, &g_hlr->mslookup.vty.server.msc_configs, entry) {
+ if (global_title_cmp(&msc->name, msc_name))
continue;
return msc;
}
@@ -48,18 +37,18 @@ struct dgsm_msc_config *dgsm_config_msc_get(const uint8_t *ipa_unit_name, size_t
msc = talloc_zero(dgsm_ctx, struct dgsm_msc_config);
OSMO_ASSERT(msc);
- INIT_LLIST_HEAD(&msc->service_addrs);
- msc->unit_name = talloc_memdup(msc, ipa_unit_name, ipa_unit_name_len);
- OSMO_ASSERT(msc->unit_name);
- msc->unit_name_len = ipa_unit_name_len;
+ INIT_LLIST_HEAD(&msc->service_hosts);
+ msc->name = *msc_name;
return msc;
}
-static struct dgsm_service_addr *dgsm_config_msc_service_get(struct dgsm_msc_config *msc, const char *service,
- bool create)
+struct dgsm_service_host *dgsm_config_msc_service_get(struct dgsm_msc_config *msc, const char *service, bool create)
{
- struct dgsm_service_addr *e;
- llist_for_each_entry(e, &msc->service_addrs, entry) {
+ struct dgsm_service_host *e;
+ if (!msc)
+ return NULL;
+
+ llist_for_each_entry(e, &msc->service_hosts, entry) {
if (!strcmp(e->service, service))
return e;
}
@@ -67,27 +56,24 @@ static struct dgsm_service_addr *dgsm_config_msc_service_get(struct dgsm_msc_con
if (!create)
return NULL;
- e = talloc_zero(msc, struct dgsm_service_addr);
+ e = talloc_zero(msc, struct dgsm_service_host);
OSMO_ASSERT(e);
OSMO_STRLCPY_ARRAY(e->service, service);
- llist_add_tail(&e->entry, &msc->service_addrs);
+ llist_add_tail(&e->entry, &msc->service_hosts);
return e;
}
-struct dgsm_service_addr *dgsm_config_service_get(const uint8_t *ipa_unit_name, size_t ipa_unit_name_len,
- const char *service)
+struct dgsm_service_host *dgsm_config_service_get(const struct global_title *msc_name, const char *service)
{
- struct dgsm_msc_config *msc = dgsm_config_msc_get(ipa_unit_name, ipa_unit_name_len, false);
+ struct dgsm_msc_config *msc = dgsm_config_msc_get(msc_name, false);
if (!msc)
return NULL;
return dgsm_config_msc_service_get(msc, service, false);
}
-int dgsm_config_service_set(const uint8_t *ipa_unit_name, size_t ipa_unit_name_len,
- const char *service, const struct osmo_sockaddr_str *addr)
+int dgsm_config_msc_service_set(struct dgsm_msc_config *msc, const char *service, const struct osmo_sockaddr_str *addr)
{
- struct dgsm_msc_config *msc;
- struct dgsm_service_addr *e;
+ struct dgsm_service_host *e;
if (!service || !service[0]
|| strlen(service) > OSMO_MSLOOKUP_SERVICE_MAXLEN)
@@ -95,20 +81,16 @@ int dgsm_config_service_set(const uint8_t *ipa_unit_name, size_t ipa_unit_name_l
if (!addr || !osmo_sockaddr_str_is_nonzero(addr))
return -EINVAL;
- msc = dgsm_config_msc_get(ipa_unit_name, ipa_unit_name_len, true);
- if (!msc)
- return -EINVAL;
-
e = dgsm_config_msc_service_get(msc, service, true);
if (!e)
return -EINVAL;
switch (addr->af) {
case AF_INET:
- e->addr_v4 = *addr;
+ e->host_v4 = *addr;
break;
case AF_INET6:
- e->addr_v6 = *addr;
+ e->host_v6 = *addr;
break;
default:
return -EINVAL;
@@ -116,30 +98,38 @@ int dgsm_config_service_set(const uint8_t *ipa_unit_name, size_t ipa_unit_name_l
return 0;
}
-int dgsm_config_service_del(const uint8_t *ipa_unit_name, size_t ipa_unit_name_len,
- const char *service, const struct osmo_sockaddr_str *addr)
+int dgsm_config_service_set(const struct global_title *msc_name, const char *service, const struct osmo_sockaddr_str *addr)
{
struct dgsm_msc_config *msc;
- struct dgsm_service_addr *e, *n;
- msc = dgsm_config_msc_get(ipa_unit_name, ipa_unit_name_len, false);
+ msc = dgsm_config_msc_get(msc_name, true);
+ if (!msc)
+ return -EINVAL;
+
+ return dgsm_config_msc_service_set(msc, service, addr);
+}
+
+int dgsm_config_msc_service_del(struct dgsm_msc_config *msc, const char *service, const struct osmo_sockaddr_str *addr)
+{
+ struct dgsm_service_host *e, *n;
+
if (!msc)
return -ENOENT;
- llist_for_each_entry_safe(e, n, &msc->service_addrs, entry) {
+ llist_for_each_entry_safe(e, n, &msc->service_hosts, entry) {
if (service && strcmp(service, e->service))
continue;
if (addr) {
- if (!osmo_sockaddr_str_cmp(addr, &e->addr_v4)) {
- e->addr_v4 = (struct osmo_sockaddr_str){};
+ if (!osmo_sockaddr_str_cmp(addr, &e->host_v4)) {
+ e->host_v4 = (struct osmo_sockaddr_str){};
/* Removed one addr. If the other is still there, keep the entry. */
- if (osmo_sockaddr_str_is_nonzero(&e->addr_v6))
+ if (osmo_sockaddr_str_is_nonzero(&e->host_v6))
continue;
- } else if (!osmo_sockaddr_str_cmp(addr, &e->addr_v6)) {
- e->addr_v6 = (struct osmo_sockaddr_str){};
+ } else if (!osmo_sockaddr_str_cmp(addr, &e->host_v6)) {
+ e->host_v6 = (struct osmo_sockaddr_str){};
/* Removed one addr. If the other is still there, keep the entry. */
- if (osmo_sockaddr_str_is_nonzero(&e->addr_v4))
+ if (osmo_sockaddr_str_is_nonzero(&e->host_v4))
continue;
} else
/* No addr match, keep the entry. */
@@ -152,8 +142,14 @@ int dgsm_config_service_del(const uint8_t *ipa_unit_name, size_t ipa_unit_name_l
return 0;
}
+int dgsm_config_service_del(const struct global_title *msc_name,
+ const char *service, const struct osmo_sockaddr_str *addr)
+{
+ return dgsm_config_msc_service_del(dgsm_config_msc_get(msc_name, false),
+ service, addr);
+}
+
static void *dgsm_pending_messages_ctx = NULL;
-static struct osmo_mslookup_client *mslookup_client = NULL;
struct pending_gsup_message {
struct llist_head entry;
@@ -212,13 +208,16 @@ void dgsm_send_to_remote_hlr(const struct proxy_subscr *ps, const struct osmo_gs
/* Return true when the message has been handled by D-GSM. */
bool dgsm_check_forward_gsup_msg(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup)
{
- const struct proxy_subscr *ps;
+ const struct proxy_subscr *proxy_subscr;
struct proxy_subscr ps_new;
struct gsup_route *r;
struct osmo_gsup_message gsup_copy;
+ struct proxy *proxy = g_hlr->gsup_proxy.cs;
+ if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS)
+ proxy = g_hlr->gsup_proxy.ps;
- ps = proxy_subscr_get(gsup->imsi);
- if (ps)
+ proxy_subscr = proxy_subscr_get_by_imsi(proxy, gsup->imsi);
+ if (proxy_subscr)
goto yes_we_are_proxying;
/* No proxy entry exists. If the IMSI is known in the local HLR, then we won't proxy. */
@@ -232,11 +231,11 @@ bool dgsm_check_forward_gsup_msg(struct osmo_gsup_conn *conn, const struct osmo_
/* Add a proxy entry without a remote address to indicate that we are busy querying for a remote HLR. */
ps_new = (struct proxy_subscr){};
OSMO_STRLCPY_ARRAY(ps_new.imsi, gsup->imsi);
- proxy_subscr_update(&ps_new);
- ps = &ps_new;
+ proxy_subscr_update(proxy, &ps_new);
+ proxy_subscr = &ps_new;
yes_we_are_proxying:
- OSMO_ASSERT(ps);
+ OSMO_ASSERT(proxy_subscr);
/* To forward to a remote HLR, we need to indicate the source MSC's name to make sure the reply can be routed
* back. Store the sender MSC in gsup->source_name -- the remote HLR is required to return this as
@@ -254,7 +253,7 @@ yes_we_are_proxying:
gsup_copy.source_name = r->addr;
gsup_copy.source_name_len = talloc_total_size(r->addr);
- dgsm_send_to_remote_hlr(ps, &gsup_copy);
+ dgsm_send_to_remote_hlr(proxy_subscr, &gsup_copy);
return true;
}
@@ -263,62 +262,96 @@ void dgsm_init(void *ctx)
{
dgsm_ctx = talloc_named_const(ctx, 0, "dgsm");
dgsm_pending_messages_ctx = talloc_named_const(dgsm_ctx, 0, "dgsm_pending_messages");
- INIT_LLIST_HEAD(&dgsm_config.server.msc_configs);
+ INIT_LLIST_HEAD(&g_hlr->mslookup.vty.server.msc_configs);
+ osmo_sockaddr_str_from_str(&g_hlr->mslookup.vty.server.mdns.bind_addr,
+ OSMO_MSLOOKUP_MDNS_IP4, OSMO_MSLOOKUP_MDNS_PORT);
+ osmo_sockaddr_str_from_str(&g_hlr->mslookup.vty.client.mdns.query_addr,
+ OSMO_MSLOOKUP_MDNS_IP4, OSMO_MSLOOKUP_MDNS_PORT);
}
void dgsm_start(void *ctx)
{
- mslookup_client = osmo_mslookup_client_new(dgsm_ctx);
- OSMO_ASSERT(mslookup_client);
+ g_hlr->mslookup.client.client = osmo_mslookup_client_new(dgsm_ctx);
+ OSMO_ASSERT(g_hlr->mslookup.client.client);
+ g_hlr->mslookup.allow_startup = true;
+ dgsm_config_apply();
}
-void dgsm_dns_server_config_apply()
+static void dgsm_mdns_server_config_apply()
{
- /* Check whether to start/stop/restart DNS server */
- bool should_run = dgsm_config.server.enable && dgsm_config.server.dns.enable;
- bool should_stop = g_hlr->mslookup.server.dns
+ /* Check whether to start/stop/restart mDNS server */
+ bool should_run;
+ bool should_stop;
+ if (!g_hlr->mslookup.allow_startup)
+ return;
+
+ g_hlr->mslookup.server.max_age = g_hlr->mslookup.vty.server.max_age;
+
+ should_run = g_hlr->mslookup.vty.server.enable && g_hlr->mslookup.vty.server.mdns.enable;
+ should_stop = g_hlr->mslookup.server.mdns
&& (!should_run
- || osmo_sockaddr_str_cmp(&dgsm_config.server.dns.multicast_bind_addr,
- &g_hlr->mslookup.server.dns->multicast_bind_addr));
+ || osmo_sockaddr_str_cmp(&g_hlr->mslookup.vty.server.mdns.bind_addr,
+ &g_hlr->mslookup.server.mdns->bind_addr));
if (should_stop) {
- osmo_mslookup_server_dns_stop(g_hlr->mslookup.server.dns);
- LOGP(DDGSM, LOGL_ERROR, "Stopped MS Lookup DNS server\n");
+ osmo_mslookup_server_mdns_stop(g_hlr->mslookup.server.mdns);
+ g_hlr->mslookup.server.mdns = NULL;
+ LOGP(DDGSM, LOGL_NOTICE, "Stopped mslookup mDNS server\n");
}
- if (should_run) {
- g_hlr->mslookup.server.dns =
- osmo_mslookup_server_dns_start(&dgsm_config.server.dns.multicast_bind_addr);
- if (!g_hlr->mslookup.server.dns)
- LOGP(DDGSM, LOGL_ERROR, "Failed to start MS Lookup DNS server\n");
+ if (should_run && !g_hlr->mslookup.server.mdns) {
+ g_hlr->mslookup.server.mdns =
+ osmo_mslookup_server_mdns_start(g_hlr, &g_hlr->mslookup.vty.server.mdns.bind_addr);
+ if (!g_hlr->mslookup.server.mdns)
+ LOGP(DDGSM, LOGL_ERROR, "Failed to start mslookup mDNS server on " OSMO_SOCKADDR_STR_FMT "\n",
+ OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.server.mdns->bind_addr));
else
- LOGP(DDGSM, LOGL_ERROR, "Started MS Lookup DNS server on " OSMO_SOCKADDR_STR_FMT "\n",
- OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.server.dns->multicast_bind_addr));
+ LOGP(DDGSM, LOGL_NOTICE, "Started mslookup mDNS server, receiving mDNS requests at multicast "
+ OSMO_SOCKADDR_STR_FMT "\n",
+ OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.server.mdns->bind_addr));
}
}
-void dgsm_dns_client_config_apply()
+static void dgsm_mdns_client_config_apply()
{
- /* Check whether to start/stop/restart DNS client */
- struct osmo_mslookup_client_method *dns_method = g_hlr->mslookup.client.dns;
- const struct osmo_sockaddr_str *current_bind_addr = osmo_mslookup_client_method_dns_get_bind_addr(dns_method);
+ if (!g_hlr->mslookup.allow_startup)
+ return;
- bool should_run = dgsm_config.client.enable && dgsm_config.client.dns.enable;
- bool should_stop = dns_method &&
+ /* Check whether to start/stop/restart mDNS client */
+ const struct osmo_sockaddr_str *current_bind_addr;
+ current_bind_addr = osmo_mslookup_client_method_mdns_get_bind_addr(g_hlr->mslookup.client.mdns);
+
+ bool should_run = g_hlr->mslookup.vty.client.enable && g_hlr->mslookup.vty.client.mdns.enable;
+ bool should_stop = g_hlr->mslookup.client.mdns &&
(!should_run
- || osmo_sockaddr_str_cmp(&dgsm_config.client.dns.multicast_query_addr,
+ || osmo_sockaddr_str_cmp(&g_hlr->mslookup.vty.client.mdns.query_addr,
current_bind_addr));
- if (should_stop)
- osmo_mslookup_client_method_del(mslookup_client, dns_method);
- if (should_run) {
- if (osmo_mslookup_client_add_dns(mslookup_client,
- dgsm_config.client.dns.multicast_query_addr.ip,
- dgsm_config.client.dns.multicast_query_addr.port,
- true))
- LOGP(DDGSM, LOGL_ERROR, "Failed to start MS Lookup DNS client\n");
+ if (should_stop) {
+ osmo_mslookup_client_method_del(g_hlr->mslookup.client.client, g_hlr->mslookup.client.mdns);
+ g_hlr->mslookup.client.mdns = NULL;
+ LOGP(DDGSM, LOGL_NOTICE, "Stopped mslookup mDNS client\n");
+ }
+
+ if (should_run && !g_hlr->mslookup.client.mdns) {
+ g_hlr->mslookup.client.mdns =
+ osmo_mslookup_client_add_mdns(g_hlr->mslookup.client.client,
+ g_hlr->mslookup.vty.client.mdns.query_addr.ip,
+ g_hlr->mslookup.vty.client.mdns.query_addr.port,
+ true);
+ if (!g_hlr->mslookup.client.mdns)
+ LOGP(DDGSM, LOGL_ERROR, "Failed to start mslookup mDNS client with target "
+ OSMO_SOCKADDR_STR_FMT "\n",
+ OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.vty.client.mdns.query_addr));
else
- LOGP(DDGSM, LOGL_ERROR, "Started MS Lookup DNS client with " OSMO_SOCKADDR_STR_FMT "\n",
- OSMO_SOCKADDR_STR_FMT_ARGS(&dgsm_config.client.dns.multicast_query_addr));
+ LOGP(DDGSM, LOGL_NOTICE, "Started mslookup mDNS client, sending mDNS requests to multicast " OSMO_SOCKADDR_STR_FMT "\n",
+ OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.vty.client.mdns.query_addr));
}
}
+
+void dgsm_config_apply()
+{
+ dgsm_mdns_server_config_apply();
+ dgsm_mdns_client_config_apply();
+}
+
diff --git a/src/dgsm.h b/src/dgsm.h
index 22486c8..704a225 100644
--- a/src/dgsm.h
+++ b/src/dgsm.h
@@ -2,32 +2,40 @@
#include <osmocom/mslookup/mslookup.h>
#include "gsup_server.h"
+#include "global_title.h"
+
+struct vty;
extern void *dgsm_ctx;
-struct dgsm_service_addr {
+struct dgsm_service_host {
struct llist_head entry;
char service[OSMO_MSLOOKUP_SERVICE_MAXLEN+1];
- struct osmo_sockaddr_str addr_v4;
- struct osmo_sockaddr_str addr_v6;
+ struct osmo_sockaddr_str host_v4;
+ struct osmo_sockaddr_str host_v6;
};
struct dgsm_msc_config {
struct llist_head entry;
- uint8_t *unit_name;
- size_t unit_name_len;
- struct llist_head service_addrs;
+ struct global_title name;
+ struct llist_head service_hosts;
};
+/* "Sketch pad" where the VTY can store config items without yet applying. The changes will be applied by e.g.
+ * dgsm_mdns_server_config_apply() and dgsm_mdns_client_config_apply(). */
struct dgsm_config {
struct {
/* Whether to listen for incoming MS Lookup requests */
bool enable;
+ /* If we have a local record of a LU, but it is older than max_age (in seconds),
+ * do not send it as mslookup result. */
+ uint32_t max_age;
+
struct {
bool enable;
- struct osmo_sockaddr_str multicast_bind_addr;
- } dns;
+ struct osmo_sockaddr_str bind_addr;
+ } mdns;
struct llist_head msc_configs;
} server;
@@ -35,30 +43,31 @@ struct dgsm_config {
struct {
/* Whether to ask remote HLRs via MS Lookup if an IMSI is not known locally. */
bool enable;
+ struct timeval timeout;
struct {
/* Whether to use mDNS for IMSI MS Lookup */
bool enable;
- struct osmo_sockaddr_str multicast_query_addr;
- } dns;
+ struct osmo_sockaddr_str query_addr;
+ } mdns;
} client;
};
-extern struct dgsm_config dgsm_config;
-void dgsm_dns_server_config_apply();
-void dgsm_dns_client_config_apply();
+void dgsm_config_apply();
+
+struct dgsm_service_host *dgsm_config_service_get(const struct global_title *msc_name, const char *service);
+int dgsm_config_service_set(const struct global_title *msc_name, const char *service, const struct osmo_sockaddr_str *addr);
+int dgsm_config_service_del(const struct global_title *msc_name, const char *service, const struct osmo_sockaddr_str *addr);
-struct dgsm_service_addr *dgsm_config_service_get(const uint8_t *ipa_unit_name, size_t ipa_unit_name_len,
- const char *service);
-int dgsm_config_service_set(const uint8_t *ipa_unit_name, size_t ipa_unit_name_len,
- const char *service, const struct osmo_sockaddr_str *addr);
-int dgsm_config_service_del(const uint8_t *ipa_unit_name, size_t ipa_unit_name_len,
- const char *service, const struct osmo_sockaddr_str *addr);
+struct dgsm_service_host *dgsm_config_msc_service_get(struct dgsm_msc_config *msc, const char *service, bool create);
+int dgsm_config_msc_service_set(struct dgsm_msc_config *msc, const char *service, const struct osmo_sockaddr_str *addr);
+int dgsm_config_msc_service_del(struct dgsm_msc_config *msc, const char *service, const struct osmo_sockaddr_str *addr);
-struct dgsm_msc_config *dgsm_config_msc_get(const uint8_t *ipa_unit_name, size_t ipa_unit_name_len,
- bool create);
+extern const struct global_title dgsm_config_msc_wildcard;
+struct dgsm_msc_config *dgsm_config_msc_get(const struct global_title *msc_name, bool create);
void dgsm_init(void *ctx);
+void dgsm_start(void *ctx);
bool dgsm_check_forward_gsup_msg(struct osmo_gsup_conn *conn, const struct osmo_gsup_message *gsup);
void dgsm_vty_init();
diff --git a/src/dgsm_vty.c b/src/dgsm_vty.c
index 4567be9..c3da81e 100644
--- a/src/dgsm_vty.c
+++ b/src/dgsm_vty.c
@@ -3,8 +3,6 @@
#include "hlr_vty.h"
#include "dgsm.h"
-static struct dgsm_config dgsm_config_vty = {};
-
struct cmd_node mslookup_node = {
MSLOOKUP_NODE,
"%s(config-mslookup)# ",
@@ -17,29 +15,30 @@ DEFUN(cfg_mslookup,
"Configure Distributed GSM / multicast MS Lookup")
{
vty->node = MSLOOKUP_NODE;
- printf("%s vty->node = %d\n", __func__, vty->node);
return CMD_SUCCESS;
}
-DEFUN(cfg_mslookup_dns,
- cfg_mslookup_dns_cmd,
- "dns",
+DEFUN(cfg_mslookup_mdns,
+ cfg_mslookup_mdns_cmd,
+ "mdns",
"Convenience shortcut: enable both server and client for DNS/mDNS MS Lookup with default config\n")
{
- dgsm_config_vty.server.enable = true;
- dgsm_config_vty.server.dns.enable = true;
- dgsm_config_vty.client.enable = true;
- dgsm_config_vty.client.dns.enable = true;
+ g_hlr->mslookup.vty.server.enable = true;
+ g_hlr->mslookup.vty.server.mdns.enable = true;
+ g_hlr->mslookup.vty.client.enable = true;
+ g_hlr->mslookup.vty.client.mdns.enable = true;
+ dgsm_config_apply();
return CMD_SUCCESS;
}
-DEFUN(cfg_mslookup_no_dns,
- cfg_mslookup_no_dns_cmd,
- "no dns",
+DEFUN(cfg_mslookup_no_mdns,
+ cfg_mslookup_no_mdns_cmd,
+ "no mdns",
NO_STR "Disable both server and client for DNS/mDNS MS Lookup\n")
{
- dgsm_config_vty.server.dns.enable = false;
- dgsm_config_vty.client.dns.enable = false;
+ g_hlr->mslookup.vty.server.mdns.enable = false;
+ g_hlr->mslookup.vty.client.mdns.enable = false;
+ dgsm_config_apply();
return CMD_SUCCESS;
}
@@ -55,8 +54,8 @@ DEFUN(cfg_mslookup_server,
"Enable and configure Distributed GSM / multicast MS Lookup server")
{
vty->node = MSLOOKUP_SERVER_NODE;
- dgsm_config_vty.server.enable = true;
- printf("%s vty->node = %d\n", __func__, vty->node);
+ g_hlr->mslookup.vty.server.enable = true;
+ dgsm_config_apply();
return CMD_SUCCESS;
}
@@ -65,41 +64,45 @@ DEFUN(cfg_mslookup_no_server,
"no server",
NO_STR "Disable Distributed GSM / multicast MS Lookup server")
{
- dgsm_config_vty.server.enable = false;
+ g_hlr->mslookup.vty.server.enable = false;
+ dgsm_config_apply();
return CMD_SUCCESS;
}
-#define DNS_STR "Configure DNS/mDNS MS Lookup\n"
-#define DNS_BIND_STR DNS_STR "Configure where the DNS/mDNS server listens for MS Lookup requests\n"
+#define MDNS_STR "Configure mslookup by multicast DNS\n"
+#define MDNS_BIND_STR MDNS_STR "Configure where the mDNS server listens for MS Lookup requests\n"
#define IP46_STR "IPv4 address like 1.2.3.4 or IPv6 address like a:b:c:d::1\n"
#define PORT_STR "Port number\n"
-DEFUN(cfg_mslookup_server_dns_bind_multicast,
- cfg_mslookup_server_dns_bind_multicast_cmd,
- "dns bind multicast IP <1-65535>",
- DNS_BIND_STR "Configure mDNS multicast listen address\n" IP46_STR PORT_STR)
+DEFUN(cfg_mslookup_server_mdns_bind,
+ cfg_mslookup_server_mdns_bind_cmd,
+ "mdns [bind] [IP] [<1-65535>]",
+ MDNS_BIND_STR IP46_STR PORT_STR)
{
- const char *ip_str = argv[1];
- const char *port_str = argv[2];
+ const char *ip_str = argc > 1? argv[1] : g_hlr->mslookup.vty.server.mdns.bind_addr.ip;
+ const char *port_str = argc > 2? argv[2] : NULL;
+ uint16_t port_nr = port_str ? atoi(port_str) : g_hlr->mslookup.vty.server.mdns.bind_addr.port;
struct osmo_sockaddr_str addr;
- if (osmo_sockaddr_str_from_str(&addr, ip_str, atoi(port_str))
+ if (osmo_sockaddr_str_from_str(&addr, ip_str, port_nr)
|| !osmo_sockaddr_str_is_nonzero(&addr)) {
- vty_out(vty, "%% MS Lookup server: Invalid mDNS bind address: %s %s%s",
- ip_str, port_str, VTY_NEWLINE);
+ vty_out(vty, "%% MS Lookup server: Invalid mDNS bind address: %s %u%s",
+ ip_str, port_nr, VTY_NEWLINE);
return CMD_WARNING;
}
- dgsm_config_vty.server.dns.multicast_bind_addr = addr;
- dgsm_config_vty.server.dns.enable = true;
+ g_hlr->mslookup.vty.server.mdns.bind_addr = addr;
+ g_hlr->mslookup.vty.server.mdns.enable = true;
+ dgsm_config_apply();
return CMD_SUCCESS;
}
-DEFUN(cfg_mslookup_server_no_dns,
- cfg_mslookup_server_no_dns_cmd,
- "no dns",
+DEFUN(cfg_mslookup_server_no_mdns,
+ cfg_mslookup_server_no_mdns_cmd,
+ "no mdns",
NO_STR "Disable server for DNS/mDNS MS Lookup (do not answer remote requests)\n")
{
- dgsm_config_vty.server.dns.enable = false;
+ g_hlr->mslookup.vty.server.mdns.enable = false;
+ dgsm_config_apply();
return CMD_SUCCESS;
}
@@ -115,17 +118,17 @@ DEFUN(cfg_mslookup_server_msc,
"Configure services for individual local MSCs\n"
"IPA Unit Name of the local MSC to configure\n")
{
- const char *unit_name = argv_concat(argv, argc, 0);
- struct dgsm_msc_config *msc = dgsm_config_msc_get((uint8_t*)unit_name, strlen(unit_name),
- true);
+ struct global_title msc_name;
+ struct dgsm_msc_config *msc;
+ global_title_set_str(&msc_name, argv_concat(argv, argc, 0));
+
+ msc = dgsm_config_msc_get(&msc_name, true);
if (!msc) {
- vty_out(vty, "%% Error creating MSC %s%s",
- osmo_quote_str(unit_name, -1), VTY_NEWLINE);
+ vty_out(vty, "%% Error creating MSC %s%s", global_title_name(&msc_name), VTY_NEWLINE);
return CMD_WARNING;
}
vty->node = MSLOOKUP_SERVER_MSC_NODE;
vty->index = msc;
- printf("%s vty->node = %d\n", __func__, vty->node);
return CMD_SUCCESS;
}
@@ -145,13 +148,20 @@ DEFUN(cfg_mslookup_server_msc_service,
/* If this command is run on the 'server' node, it produces an empty unit name and serves as wildcard for all
* MSCs. If on a 'server' / 'msc' node, set services only for that MSC Unit Name. */
struct dgsm_msc_config *msc = (vty->node == MSLOOKUP_SERVER_MSC_NODE) ? vty->index : NULL;
- uint8_t *unit_name = msc ? msc->unit_name : NULL;
- size_t unit_name_len = msc ? msc->unit_name_len : 0;
const char *service = argv[0];
const char *ip_str = argv[1];
const char *port_str = argv[2];
struct osmo_sockaddr_str addr;
+ /* On the mslookup.server node, set services on the wildcard msc, without a particular name. */
+ if (vty->node == MSLOOKUP_SERVER_NODE)
+ msc = dgsm_config_msc_get(&dgsm_config_msc_wildcard, true);
+
+ if (!msc) {
+ vty_out(vty, "%% Error: no MSC object on this node%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
if (osmo_sockaddr_str_from_str(&addr, ip_str, atoi(port_str))
|| !osmo_sockaddr_str_is_nonzero(&addr)) {
vty_out(vty, "%% MS Lookup server: Invalid address for service %s: %s %s%s",
@@ -159,7 +169,7 @@ DEFUN(cfg_mslookup_server_msc_service,
return CMD_WARNING;
}
- if (dgsm_config_service_set(unit_name, unit_name_len, service, &addr)) {
+ if (dgsm_config_msc_service_set(msc, service, &addr)) {
vty_out(vty, "%% MS Lookup server: Error setting service %s to %s %s%s",
service, ip_str, port_str, VTY_NEWLINE);
return CMD_WARNING;
@@ -177,11 +187,9 @@ DEFUN(cfg_mslookup_server_msc_no_service,
/* If this command is run on the 'server' node, it produces an empty unit name and serves as wildcard for all
* MSCs. If on a 'server' / 'msc' node, set services only for that MSC Unit Name. */
struct dgsm_msc_config *msc = (vty->node == MSLOOKUP_SERVER_MSC_NODE) ? vty->index : NULL;
- uint8_t *unit_name = msc ? msc->unit_name : NULL;
- size_t unit_name_len = msc ? msc->unit_name_len : 0;
const char *service = argv[0];
- if (dgsm_config_service_del(unit_name, unit_name_len, service, NULL)) {
+ if (dgsm_config_msc_service_del(msc, service, NULL)) {
vty_out(vty, "%% MS Lookup server: Error removing service %s%s",
service, VTY_NEWLINE);
return CMD_WARNING;
@@ -197,8 +205,6 @@ DEFUN(cfg_mslookup_server_msc_no_service_addr,
/* If this command is run on the 'server' node, it produces an empty unit name and serves as wildcard for all
* MSCs. If on a 'server' / 'msc' node, set services only for that MSC Unit Name. */
struct dgsm_msc_config *msc = (vty->node == MSLOOKUP_SERVER_MSC_NODE) ? vty->index : NULL;
- uint8_t *unit_name = msc ? msc->unit_name : NULL;
- size_t unit_name_len = msc ? msc->unit_name_len : 0;
const char *service = argv[0];
const char *ip_str = argv[1];
const char *port_str = argv[2];
@@ -211,7 +217,7 @@ DEFUN(cfg_mslookup_server_msc_no_service_addr,
return CMD_WARNING;
}
- if (dgsm_config_service_del(unit_name, unit_name_len, service, &addr)) {
+ if (dgsm_config_service_del(&msc->name, service, &addr)) {
vty_out(vty, "%% MS Lookup server: Error removing service %s to %s %s%s",
service, ip_str, port_str, VTY_NEWLINE);
return CMD_WARNING;
@@ -231,7 +237,8 @@ DEFUN(cfg_mslookup_client,
"Enable and configure Distributed GSM / multicast MS Lookup client")
{
vty->node = MSLOOKUP_CLIENT_NODE;
- dgsm_config.client.enable = true;
+ g_hlr->mslookup.vty.client.enable = true;
+ dgsm_config_apply();
return CMD_SUCCESS;
}
@@ -240,7 +247,58 @@ DEFUN(cfg_mslookup_no_client,
"no client",
NO_STR "Disable Distributed GSM / multicast MS Lookup client")
{
- dgsm_config.client.enable = false;
+ g_hlr->mslookup.vty.client.enable = false;
+ dgsm_config_apply();
+ return CMD_SUCCESS;
+}
+
+#define MDNS_TO_STR MDNS_STR "Configure to which multicast address mDNS MS Lookup requests are sent\n"
+
+DEFUN(cfg_mslookup_client_timeout,
+ cfg_mslookup_client_timeout_cmd,
+ "timeout <1-100000>",
+ "How long should the mslookup client wait for remote responses before evaluating received results\n"
+ "timeout in milliseconds\n")
+{
+ uint32_t val = atol(argv[0]);
+ g_hlr->mslookup.vty.client.timeout.tv_sec = val / 1000;
+ g_hlr->mslookup.vty.client.timeout.tv_usec = (val % 1000) * 1000;
+ return CMD_SUCCESS;
+}
+
+#define EXIT_HINT() \
+ if (vty->type != VTY_FILE) \
+ vty_out(vty, "%% 'exit' this node to apply changes%s", VTY_NEWLINE)
+
+DEFUN(cfg_mslookup_client_mdns,
+ cfg_mslookup_client_mdns_cmd,
+ "mdns [to] [IP] [<1-65535>]",
+ MDNS_STR "Configure multicast address to send mDNS mslookup requests to\n" IP46_STR PORT_STR)
+{
+ const char *ip_str = argc > 1? argv[1] : g_hlr->mslookup.vty.client.mdns.query_addr.ip;
+ const char *port_str = argc > 2? argv[2] : NULL;
+ uint16_t port_nr = port_str ? atoi(port_str) : g_hlr->mslookup.vty.client.mdns.query_addr.port;
+ struct osmo_sockaddr_str addr;
+ if (osmo_sockaddr_str_from_str(&addr, ip_str, port_nr)
+ || !osmo_sockaddr_str_is_nonzero(&addr)) {
+ vty_out(vty, "%% MS Lookup client: Invalid mDNS target address: %s %u%s",
+ ip_str, port_nr, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ g_hlr->mslookup.vty.client.mdns.query_addr = addr;
+ g_hlr->mslookup.vty.client.mdns.enable = true;
+ dgsm_config_apply();
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mslookup_client_no_mdns,
+ cfg_mslookup_client_no_mdns_cmd,
+ "no mdns",
+ NO_STR "Disable mDNS client, do not query remote services by mDNS\n")
+{
+ g_hlr->mslookup.vty.client.mdns.enable = false;
+ dgsm_config_apply();
return CMD_SUCCESS;
}
@@ -269,14 +327,14 @@ void dgsm_vty_init()
install_element(CONFIG_NODE, &cfg_mslookup_cmd);
install_node(&mslookup_node, config_write_mslookup);
- install_element(MSLOOKUP_NODE, &cfg_mslookup_dns_cmd);
- install_element(MSLOOKUP_NODE, &cfg_mslookup_no_dns_cmd);
+ install_element(MSLOOKUP_NODE, &cfg_mslookup_mdns_cmd);
+ install_element(MSLOOKUP_NODE, &cfg_mslookup_no_mdns_cmd);
install_element(MSLOOKUP_NODE, &cfg_mslookup_server_cmd);
install_element(MSLOOKUP_NODE, &cfg_mslookup_no_server_cmd);
install_node(&mslookup_server_node, config_write_mslookup_server);
- install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_dns_bind_multicast_cmd);
- install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_no_dns_cmd);
+ install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_mdns_bind_cmd);
+ install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_no_mdns_cmd);
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);
@@ -290,18 +348,12 @@ void dgsm_vty_init()
install_element(MSLOOKUP_NODE, &cfg_mslookup_client_cmd);
install_element(MSLOOKUP_NODE, &cfg_mslookup_no_client_cmd);
install_node(&mslookup_client_node, config_write_mslookup_client);
+ install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_timeout_cmd);
+ install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_mdns_cmd);
+ install_element(MSLOOKUP_CLIENT_NODE, &cfg_mslookup_client_no_mdns_cmd);
}
void dgsm_vty_go_parent_action(struct vty *vty)
{
- /* Exiting 'mslookup' VTY node, apply new config. */
- switch (vty->node) {
- case MSLOOKUP_SERVER_NODE:
- dgsm_dns_server_config_apply();
- break;
- case MSLOOKUP_CLIENT_NODE:
- dgsm_dns_client_config_apply();
- break;
- }
}
diff --git a/src/global_title.c b/src/global_title.c
index 9df45d6..10fbb11 100644
--- a/src/global_title.c
+++ b/src/global_title.c
@@ -16,6 +16,11 @@ int global_title_set(struct global_title *gt, const uint8_t *val, size_t len)
return 0;
}
+int global_title_set_str(struct global_title *gt, const char *str)
+{
+ return global_title_set(gt, (const uint8_t*)str, str ? strlen(str)+1 : 0);
+}
+
int global_title_cmp(const struct global_title *a, const struct global_title *b)
{
int cmp;
diff --git a/src/global_title.h b/src/global_title.h
index 017c7fe..54e23a3 100644
--- a/src/global_title.h
+++ b/src/global_title.h
@@ -12,5 +12,6 @@ struct global_title {
};
int global_title_set(struct global_title *gt, const uint8_t *val, size_t len);
+int global_title_set_str(struct global_title *gt, const char *str);
int global_title_cmp(const struct global_title *a, const struct global_title *b);
const char *global_title_name(const struct global_title *gt);
diff --git a/src/hlr.c b/src/hlr.c
index df72f04..7b24017 100644
--- a/src/hlr.c
+++ b/src/hlr.c
@@ -49,6 +49,7 @@
#include "hlr_vty.h"
#include "hlr_ussd.h"
#include "dgsm.h"
+#include "proxy.h"
struct hlr *g_hlr;
static void *hlr_ctx = NULL;
@@ -429,14 +430,14 @@ static int rx_purge_ms_req(struct osmo_gsup_conn *conn,
bool is_ps = false;
int rc;
- LOGP(DAUC, LOGL_INFO, "%s: Purge MS (%s)\n", gsup->imsi,
- is_ps ? "PS" : "CS");
-
memcpy(gsup_reply.imsi, gsup->imsi, sizeof(gsup_reply.imsi));
if (gsup->cn_domain == OSMO_GSUP_CN_DOMAIN_PS)
is_ps = true;
+ LOGP(DAUC, LOGL_INFO, "%s: Purge MS (%s)\n", gsup->imsi,
+ is_ps ? "PS" : "CS");
+
/* FIXME: check if the VLR that sends the purge is the same that
* we have on record. Only update if yes */
@@ -836,6 +837,9 @@ int main(int argc, char **argv)
/* Init default (call independent) SS session guard timeout value */
g_hlr->ncss_guard_timeout = NCSS_GUARD_TIMEOUT_DEFAULT;
+ g_hlr->gsup_proxy.cs = proxy_init(g_hlr);
+ g_hlr->gsup_proxy.ps = proxy_init(g_hlr);
+
rc = osmo_init_logging2(hlr_ctx, &hlr_log_info);
if (rc < 0) {
fprintf(stderr, "Error initializing logging\n");
@@ -903,6 +907,8 @@ int main(int argc, char **argv)
g_hlr->ctrl_bind_addr = ctrl_vty_get_bind_addr();
g_hlr->ctrl = hlr_controlif_setup(g_hlr);
+ dgsm_start(hlr_ctx);
+
osmo_init_ignore_signals();
signal(SIGINT, &signal_hdlr);
signal(SIGTERM, &signal_hdlr);
diff --git a/src/hlr.h b/src/hlr.h
index 9bf3786..52356af 100644
--- a/src/hlr.h
+++ b/src/hlr.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/ipa.h>
+#include "dgsm.h"
#define HLR_DEFAULT_DB_FILE_PATH "hlr.db"
@@ -66,19 +67,24 @@ struct hlr {
unsigned int subscr_create_on_demand_rand_msisdn_len;
struct {
+ bool allow_startup;
+ struct dgsm_config vty;
+
struct {
- struct osmo_mslookup_server_dns *dns;
+ struct osmo_mslookup_server_mdns *mdns;
+ uint32_t max_age;
} server;
struct {
struct osmo_mslookup_client *client;
-
- struct osmo_mslookup_client_method *dns;
+ struct osmo_mslookup_client_method *mdns;
} client;
} mslookup;
struct {
struct ipaccess_unit gsup_client_name;
+ struct proxy *cs;
+ struct proxy *ps;
} gsup_proxy;
};
diff --git a/src/mslookup_server.c b/src/mslookup_server.c
index e2f3b75..b426417 100644
--- a/src/mslookup_server.c
+++ b/src/mslookup_server.c
@@ -6,37 +6,32 @@
#include "db.h"
#include "dgsm.h"
#include "mslookup_server.h"
+#include "proxy.h"
static const struct osmo_mslookup_result not_found = {
- .ip_v4.rc = OSMO_MSLOOKUP_RC_NOT_FOUND,
- .ip_v6.rc = OSMO_MSLOOKUP_RC_NOT_FOUND,
+ .rc = OSMO_MSLOOKUP_RC_NOT_FOUND,
};
-static void set_result(struct osmo_mslookup_result_part *result,
- const struct osmo_sockaddr_str *addr,
+static void set_result(struct osmo_mslookup_result *result,
+ const struct dgsm_service_host *service_host,
uint32_t age)
{
- if (!osmo_sockaddr_str_is_nonzero(addr)) {
- result->rc = OSMO_MSLOOKUP_RC_NOT_FOUND;
+ if (!osmo_sockaddr_str_is_nonzero(&service_host->host_v4)
+ && !osmo_sockaddr_str_is_nonzero(&service_host->host_v6)) {
+ *result = not_found;
return;
}
result->rc = OSMO_MSLOOKUP_RC_OK;
- result->host = *addr;
+ result->host_v4 = service_host->host_v4;
+ result->host_v6 = service_host->host_v6;
result->age = age;
}
-static void set_results(struct osmo_mslookup_result *result,
- const struct dgsm_service_addr *service_addr,
- uint32_t age)
+/* A remote entity is asking us whether we are the home HLR of the given subscriber. */
+static void mslookup_server_rx_hlr_gsup(const struct osmo_mslookup_query *query,
+ struct osmo_mslookup_result *result)
{
- set_result(&result->ip_v4, &service_addr->addr_v4, age);
- set_result(&result->ip_v6, &service_addr->addr_v6, age);
-}
-
-void mslookup_server_rx_hlr_gsup(const struct osmo_mslookup_query *query,
- struct osmo_mslookup_result *result)
-{
- struct dgsm_service_addr *addr;
+ struct dgsm_service_host *host;
int rc;
switch (query->id.type) {
case OSMO_MSLOOKUP_ID_IMSI:
@@ -62,41 +57,203 @@ void mslookup_server_rx_hlr_gsup(const struct osmo_mslookup_query *query,
osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));
/* Find a HLR/GSUP service set for the server (no MSC unit name) */
- addr = dgsm_config_service_get(NULL, 0, OSMO_MSLOOKUP_SERVICE_HLR_GSUP);
- if (!addr) {
- LOGP(DDGSM, LOGL_ERROR,
- "Subscriber found, but no service '" OSMO_MSLOOKUP_SERVICE_HLR_GSUP "' configured,"
- " cannot service HLR lookup request\n");
- *result = not_found;
+ host = dgsm_config_service_get(&dgsm_config_msc_wildcard, OSMO_MSLOOKUP_SERVICE_HLR_GSUP);
+ if (!host) {
+ struct dgsm_service_host gsup_bind = {};
+ /* Try to use the locally configured GSUP bind address */
+ osmo_sockaddr_str_from_str(&gsup_bind.host_v4, g_hlr->gsup_bind_addr, OSMO_GSUP_PORT);
+ if (gsup_bind.host_v4.af == AF_INET6) {
+ gsup_bind.host_v6 = gsup_bind.host_v4;
+ gsup_bind.host_v4 = (struct osmo_sockaddr_str){};
+ }
+ set_result(result, &gsup_bind, 0);
+ if (result->rc != OSMO_MSLOOKUP_RC_OK) {
+ LOGP(DDGSM, LOGL_ERROR,
+ "Subscriber found, but no service '" OSMO_MSLOOKUP_SERVICE_HLR_GSUP "' configured,"
+ " and cannot use configured GSUP bind address %s in mslookup response."
+ " Cannot service HLR lookup request\n",
+ osmo_quote_str(g_hlr->gsup_bind_addr, -1));
+ }
return;
}
- set_results(result, addr, 0);
+ set_result(result, host, 0);
+ if (result->rc != OSMO_MSLOOKUP_RC_OK) {
+ LOGP(DDGSM, LOGL_ERROR,
+ "Subscriber found, but error in service '" OSMO_MSLOOKUP_SERVICE_HLR_GSUP "' config:"
+ " v4: " OSMO_SOCKADDR_STR_FMT " v6: " OSMO_SOCKADDR_STR_FMT "\n",
+ OSMO_SOCKADDR_STR_FMT_ARGS(&host->host_v4),
+ OSMO_SOCKADDR_STR_FMT_ARGS(&host->host_v6));
+ }
+}
+
+/* Look in the local HLR record: If the subscriber is "at home" in this HLR and is also currently located at a local
+ * MSC, we will find a valid location updating with vlr_number, and no vlr_via_proxy entry. */
+static bool subscriber_has_done_lu_here_hlr(const struct osmo_mslookup_query *query,
+ uint32_t *lu_age,
+ struct global_title *local_msc_name)
+{
+ struct hlr_subscriber subscr;
+ struct timeval age_tv;
+ int rc;
+ uint32_t age;
+
+ switch (query->id.type) {
+ case OSMO_MSLOOKUP_ID_IMSI:
+ rc = db_subscr_get_by_imsi(g_hlr->dbc, query->id.imsi, &subscr);
+ break;
+ case OSMO_MSLOOKUP_ID_MSISDN:
+ rc = db_subscr_get_by_msisdn(g_hlr->dbc, query->id.msisdn, &subscr);
+ break;
+ default:
+ LOGP(DDGSM, LOGL_ERROR, "Unknown mslookup ID type: %d\n", query->id.type);
+ return false;
+ }
+
+ if (rc) {
+ LOGP(DDGSM, LOGL_DEBUG, "%s: Does not exist in local HLR\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));
+ return false;
+ }
+
+ if (!subscr.vlr_number[0]) {
+ LOGP(DDGSM, LOGL_DEBUG, "%s: Not attached\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));
+ }
+
+ if (subscr.vlr_via_proxy.len) {
+ /* The MSC is behind a proxy, the subscriber is not attached to a local MSC but a remote one. That
+ * remote proxy should instead respond to the service lookup request. */
+ LOGP(DDGSM, LOGL_DEBUG, "%s: last attach is not at local MSC, but via proxy %s\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
+ global_title_name(&subscr.vlr_via_proxy));
+ return false;
+ }
+
+ age_tv = (struct timeval){ .tv_sec = subscr.last_lu_seen };
+ age = timestamp_age(&age_tv);
+
+ if (age > g_hlr->mslookup.server.max_age) {
+ LOGP(DDGSM, LOGL_ERROR, "%s: last attach was here, but too long ago: %us\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
+ age);
+ return false;
+ }
+
+ *lu_age = age;
+ global_title_set_str(local_msc_name, subscr.vlr_number);
+ LOGP(DDGSM, LOGL_DEBUG, "%s: attached %u seconds ago at local MSC %s\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
+ age, global_title_name(local_msc_name));
+
+ return true;
}
-/* Determine whether the subscriber with the given ID has routed a Location Updating via this HLR as first hop -- either
- * entirely here, or here first but proxying to a remote HLR. Do not return a match if the LU was registered here
- * (because this is the home HLR) but the LU was routed via a closer HLR first.
- * A proxy adds source_name IEs to forwarded GSUP requests that indicates the MSC where the subscriber is attached.
- * So a) if the LU that was received at the home HLR contained a source_name, we know that the LU happened at a remote
- * MSC. b) The source_name is stored as the vlr_number; hence if that vlr_number is not known locally, we know the LU
- * happened at a remote MSC. (at the time of writing it is not yet clear whether we'll use a or b).
+
+/* Determine whether the subscriber with the given ID has routed a Location Updating via this HLR as first hop. Return
+ * true if it is attached at a local MSC, and we are serving as proxy for a remote home HLR.
*/
-bool subscriber_has_done_location_updating_here(const struct osmo_mslookup_id *id,
- uint32_t *lu_age,
- const uint8_t **lu_msc_unit_name,
- size_t *lu_msc_unit_name_len)
+static bool subscriber_has_done_lu_here_proxy(const struct osmo_mslookup_query *query,
+ uint32_t *lu_age,
+ struct global_title *local_msc_name)
+{
+ const struct proxy_subscr *subscr;
+ uint32_t age;
+
+ /* See the local HLR record. If the subscriber is "at home" in this HLR and is also currently located here, we
+ * will find a valid location updating and no vlr_via_proxy entry. */
+ switch (query->id.type) {
+ case OSMO_MSLOOKUP_ID_IMSI:
+ subscr = proxy_subscr_get_by_imsi(g_hlr->gsup_proxy.cs, query->id.imsi);
+ break;
+ case OSMO_MSLOOKUP_ID_MSISDN:
+ subscr = proxy_subscr_get_by_msisdn(g_hlr->gsup_proxy.cs, query->id.msisdn);
+ break;
+ default:
+ LOGP(DDGSM, LOGL_ERROR, "Unknown mslookup ID type: %d\n", query->id.type);
+ return false;
+ }
+
+ if (!subscr) {
+ LOGP(DDGSM, LOGL_DEBUG, "%s: does not exist in GSUP proxy\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));
+ return false;
+ }
+
+ age = timestamp_age(&subscr->last_lu);
+
+ if (age > g_hlr->mslookup.server.max_age) {
+ LOGP(DDGSM, LOGL_ERROR, "%s: last attach was here (proxy), but too long ago: %us\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
+ age);
+ return false;
+ }
+
+ *lu_age = age;
+ *local_msc_name = subscr->vlr_name;
+ LOGP(DDGSM, LOGL_DEBUG, "%s: attached %u seconds ago at local MSC %s; proxying for remote HLR "
+ OSMO_SOCKADDR_STR_FMT "\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
+ age, global_title_name(local_msc_name),
+ OSMO_SOCKADDR_STR_FMT_ARGS(&subscr->remote_hlr));
+
+ return true;
+}
+
+static bool subscriber_has_done_lu_here(const struct osmo_mslookup_query *query,
+ uint32_t *lu_age_p,
+ struct global_title *local_msc_name)
{
- return false;
+ uint32_t lu_age = 0;
+ struct global_title msc_name = {};
+ uint32_t proxy_lu_age = 0;
+ struct global_title proxy_msc_name = {};
+
+ /* First ask the local HLR db, but if the local proxy record indicates a more recent LU, use that instead.
+ * For all usual cases, only one of these will reflect a LU, even if a subscriber had more than one home HLR:
+ * - if the subscriber is known here, we will never proxy.
+ * - if the subscriber is not known here, this local HLR db will never record a LU.
+ * However, if a subscriber was being proxied to a remote home HLR, and if then the subscriber was also added to
+ * the local HLR database, there might occur a situation where both reflect a LU. So, to be safe against all
+ * situations, compare the two entries.
+ */
+ if (!subscriber_has_done_lu_here_hlr(query, &lu_age, &msc_name))
+ lu_age = 0;
+ if (!subscriber_has_done_lu_here_proxy(query, &proxy_lu_age, &proxy_msc_name))
+ proxy_lu_age = 0;
+ if (lu_age && proxy_lu_age) {
+ LOGP(DDGSM, LOGL_DEBUG,
+ "%s: a LU is on record both in the local HLR (age %us) and the GSUP proxy (age %us)\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
+ lu_age, proxy_lu_age);
+ }
+ /* If proxy has a younger lu, replace. */
+ if (proxy_lu_age && (!lu_age || (proxy_lu_age < lu_age))) {
+ lu_age = proxy_lu_age;
+ msc_name = proxy_msc_name;
+ }
+
+ if (!lu_age || !msc_name.len) {
+ LOGP(DDGSM, LOGL_DEBUG, "%s: not attached here\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL));
+ return false;
+ }
+
+ LOGP(DDGSM, LOGL_DEBUG, "%s: attached here, at MSC %s\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
+ global_title_name(&msc_name));
+ *lu_age_p = lu_age;
+ *local_msc_name = msc_name;
+ return true;
}
-void mslookup_server_rx(const struct osmo_mslookup_query *query,
- struct osmo_mslookup_result *result)
+/* A remote entity is asking us whether we are providing the given service for the given subscriber. */
+void osmo_mslookup_server_rx(const struct osmo_mslookup_query *query,
+ struct osmo_mslookup_result *result)
{
- const uint8_t *msc_unit_name;
- size_t msc_unit_name_len;
- const struct dgsm_service_addr *service_addr;
+ const struct dgsm_service_host *service_host;
uint32_t age;
+ struct global_title msc_name;
/* A request for a home HLR: answer exactly if this is the subscriber's home HLR, i.e. the IMSI is listed in the
* HLR database. */
@@ -106,28 +263,28 @@ void mslookup_server_rx(const struct osmo_mslookup_query *query,
/* All other service types: answer when the subscriber has done a LU that is either listed in the local HLR or
* in the GSUP proxy database: i.e. if the subscriber has done a Location Updating at an MSC belonging to this
* HLR. Respond with whichever services are configured in the osmo-hlr.cfg. */
- if (!subscriber_has_done_location_updating_here(&query->id, &age, &msc_unit_name, &msc_unit_name_len)) {
+ if (!subscriber_has_done_lu_here(query, &age, &msc_name)) {
*result = not_found;
return;
}
/* We've detected a LU here. The MSC where the LU happened is stored in msc_unit_name, and the LU age is stored
* in 'age'. Figure out the address configured for that MSC and service name. */
- service_addr = dgsm_config_service_get(msc_unit_name, msc_unit_name_len, query->service);
- if (!service_addr) {
+ service_host = dgsm_config_service_get(&msc_name, query->service);
+
+ if (!service_host) {
+ /* Find such service set globally (no MSC unit name) */
+ service_host = dgsm_config_service_get(&dgsm_config_msc_wildcard, query->service);
+ }
+
+ if (!service_host) {
+ LOGP(DDGSM, LOGL_ERROR,
+ "%s: subscriber found, but no service %s configured, cannot service lookup request\n",
+ osmo_mslookup_result_name_c(OTC_SELECT, query, NULL),
+ osmo_quote_str_c(OTC_SELECT, query->service, -1));
*result = not_found;
return;
}
- set_results(result, service_addr, age);
-}
-
-struct osmo_mslookup_server_dns *osmo_mslookup_server_dns_start(const struct osmo_sockaddr_str *multicast_bind_addr)
-{
- return NULL;
+ set_result(result, service_host, age);
}
-
-void osmo_mslookup_server_dns_stop(struct osmo_mslookup_server_dns *server)
-{
-}
-
diff --git a/src/mslookup_server.h b/src/mslookup_server.h
index 2b8d494..c61792a 100644
--- a/src/mslookup_server.h
+++ b/src/mslookup_server.h
@@ -1,9 +1,7 @@
#pragma once
-struct osmo_mslookup_server_dns {
- bool running;
- struct osmo_sockaddr_str multicast_bind_addr;
-};
+struct osmo_mslookup_query;
+struct osmo_mslookup_result;
-struct osmo_mslookup_server_dns *osmo_mslookup_server_dns_start(const struct osmo_sockaddr_str *multicast_bind_addr);
-void osmo_mslookup_server_dns_stop(struct osmo_mslookup_server_dns *server);
+void osmo_mslookup_server_rx(const struct osmo_mslookup_query *query,
+ struct osmo_mslookup_result *result);
diff --git a/src/mslookup_server_mdns.c b/src/mslookup_server_mdns.c
new file mode 100644
index 0000000..982ba15
--- /dev/null
+++ b/src/mslookup_server_mdns.c
@@ -0,0 +1,163 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <osmocom/mslookup/mslookup.h>
+#include <osmocom/mslookup/mdns.h>
+#include "logging.h"
+#include "mslookup_server.h"
+#include "mslookup_server_mdns.h"
+
+static void osmo_mslookup_server_mdns_tx(struct osmo_mslookup_server_mdns *server,
+ const struct osmo_mdns_request *req,
+ const struct osmo_mslookup_query *query,
+ const struct osmo_mslookup_result *result)
+{
+ const char *errmsg = NULL;
+ struct msgb *msg;
+ struct osmo_mdns_answer ans;
+ struct osmo_mdns_record *rec_age;
+ struct osmo_mdns_record rec_ip_v4 = {};
+ struct osmo_mdns_record *rec_ip_v4_port;
+ struct osmo_mdns_record rec_ip_v6 = {};
+ struct osmo_mdns_record *rec_ip_v6_port;
+ uint32_t ip_v4;
+ struct in6_addr ip_v6;
+
+ void *ctx = talloc_named_const(server, 0, __func__);
+
+ osmo_mdns_answer_init(&ans);
+ ans.id = req->id;
+ ans.domain = req->domain;
+
+ rec_age = dns_encode_txt_record(ctx, "age", "%u", result->age);
+ llist_add(&rec_age->list, &ans.records);
+
+ if (osmo_sockaddr_str_is_nonzero(&result->host_v4)) {
+ if (osmo_sockaddr_str_to_32n(&result->host_v4, &ip_v4)) {
+ errmsg = "Error encoding IPv4 address";
+ goto clean_and_exit;
+ }
+ rec_ip_v4.type = OSMO_MSLOOKUP_MDNS_RECORD_TYPE_A;
+ rec_ip_v4.data = (void*)&ip_v4;
+ rec_ip_v4.length = sizeof(ip_v4);
+ llist_add(&rec_ip_v4.list, &ans.records);
+
+ rec_ip_v4_port = dns_encode_txt_record(ctx, "port", "%u", result->host_v4.port);
+ if (!rec_ip_v4_port) {
+ errmsg = "Error encoding IPv4 port";
+ goto clean_and_exit;
+ }
+ llist_add(&rec_ip_v4_port->list, &ans.records);
+ }
+
+ if (osmo_sockaddr_str_is_nonzero(&result->host_v6)) {
+ if (osmo_sockaddr_str_to_in6_addr(&result->host_v6, &ip_v6)) {
+ errmsg = "Error encoding IPv6 address";
+ goto clean_and_exit;
+ }
+
+ rec_ip_v6.type = OSMO_MSLOOKUP_MDNS_RECORD_TYPE_AAAA;
+ rec_ip_v6.data = (void*)&ip_v6;
+ rec_ip_v6.length = sizeof(ip_v6);
+ llist_add(&rec_ip_v6.list, &ans.records);
+
+ rec_ip_v6_port = dns_encode_txt_record(ctx, "port", "%u", result->host_v6.port);
+ if (!rec_ip_v6_port) {
+ errmsg = "Error encoding IPv6 port";
+ goto clean_and_exit;
+ }
+ llist_add(&rec_ip_v6_port->list, &ans.records);
+ }
+
+ msg = msgb_alloc(1024, __func__);
+ if (dns_encode_answer(ctx, msg, &ans)) {
+ errmsg = "Error encoding DNS answer packet";
+ goto clean_and_exit;
+ }
+
+ if (osmo_mdns_sock_send(server->sock, msg))
+ errmsg = "Error sending DNS answer";
+
+clean_and_exit:
+ if (errmsg)
+ LOGP(DDGSM, LOGL_ERROR, "%s: DNS: %s\n", osmo_mslookup_result_name_c(ctx, query, result), errmsg);
+ talloc_free(ctx);
+}
+
+static void osmo_mslookup_server_mdns_handle_request(struct osmo_mslookup_server_mdns *server,
+ const struct osmo_mdns_request *req)
+{
+ struct osmo_mslookup_query query;
+ struct osmo_mslookup_result result;
+
+ if (osmo_mslookup_query_from_domain_str(&query, req->domain)) {
+ LOGP(DDGSM, LOGL_ERROR, "mDNS mslookup server: unable to parse request domain string: %s\n",
+ osmo_quote_str_c(OTC_SELECT, req->domain, -1));
+ return;
+ }
+
+ osmo_mslookup_server_rx(&query, &result);
+ /* Error logging already happens in osmo_mslookup_server_rx() */
+ if (result.rc != OSMO_MSLOOKUP_RC_OK)
+ return;
+
+ osmo_mslookup_server_mdns_tx(server, req, &query, &result);
+}
+
+static int osmo_mslookup_server_mdns_rx(struct osmo_fd *osmo_fd, unsigned int what)
+{
+ struct osmo_mslookup_server_mdns *server = osmo_fd->data;
+ struct osmo_mdns_request *req;
+ int n;
+ uint8_t buffer[1024];
+ void *ctx;
+
+ /* Parse the message and print it */
+ n = read(osmo_fd->fd, buffer, sizeof(buffer));
+ if (n < 0)
+ return n;
+
+ ctx = talloc_named_const(server, 0, __func__);
+ req = dns_decode_request(ctx, buffer, n);
+ if (!req) {
+ LOGP(DDGSM, LOGL_DEBUG, "mDNS rx: ignoring: not a request\n");
+ talloc_free(ctx);
+ return -1;
+ }
+
+ LOGP(DDGSM, LOGL_DEBUG, "mDNS rx request: %s\n", osmo_quote_str_c(OTC_SELECT, req->domain, -1));
+ osmo_mslookup_server_mdns_handle_request(server, req);
+ talloc_free(ctx);
+ return n;
+}
+
+struct osmo_mslookup_server_mdns *osmo_mslookup_server_mdns_start(void *ctx, const struct osmo_sockaddr_str *bind_addr)
+{
+ struct osmo_mslookup_server_mdns *server = talloc_zero(ctx, struct osmo_mslookup_server_mdns);
+ OSMO_ASSERT(server);
+ *server = (struct osmo_mslookup_server_mdns){
+ .bind_addr = *bind_addr,
+ };
+
+ server->sock = osmo_mdns_sock_init(server,
+ bind_addr->ip, bind_addr->port, true,
+ osmo_mslookup_server_mdns_rx,
+ server, 0);
+ if (!server->sock) {
+ LOGP(DDGSM, LOGL_ERROR,
+ "mslookup mDNS server: error initializing multicast bind on " OSMO_SOCKADDR_STR_FMT "\n",
+ OSMO_SOCKADDR_STR_FMT_ARGS(bind_addr));
+ talloc_free(server);
+ return NULL;
+ }
+
+ return server;
+}
+
+void osmo_mslookup_server_mdns_stop(struct osmo_mslookup_server_mdns *server)
+{
+ if (!server)
+ return;
+ osmo_mdns_sock_cleanup(server->sock);
+ talloc_free(server);
+}
diff --git a/src/mslookup_server_mdns.h b/src/mslookup_server_mdns.h
new file mode 100644
index 0000000..8d4d4fc
--- /dev/null
+++ b/src/mslookup_server_mdns.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <stdbool.h>
+#include <osmocom/core/sockaddr_str.h>
+#include <osmocom/mslookup/mdns_sock.h>
+
+struct osmo_mslookup_server_mdns {
+ struct osmo_mslookup_server *mslookup;
+ struct osmo_sockaddr_str bind_addr;
+ struct osmo_mdns_sock *sock;
+};
+
+struct osmo_mslookup_server_mdns *osmo_mslookup_server_mdns_start(void *ctx, const struct osmo_sockaddr_str *bind_addr);
+void osmo_mslookup_server_mdns_stop(struct osmo_mslookup_server_mdns *server);
diff --git a/src/proxy.c b/src/proxy.c
index 7bcd080..a93c004 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -6,6 +6,7 @@
#include <osmocom/core/timer.h>
+#include "logging.h"
#include "proxy.h"
/* Why have a separate struct to add an llist_head entry?
@@ -17,14 +18,6 @@ struct proxy_subscr_listentry {
struct proxy_subscr data;
};
-static LLIST_HEAD(proxy_subscr_list);
-static void *proxy_ctx = NULL;
-
-/* How long to keep proxy entries without a refresh, in seconds. */
-static time_t proxy_fresh_time = 60 * 60;
-static time_t proxy_fresh_check_period = 60;
-static struct osmo_timer_list proxy_cleanup_timer;
-
/* Central implementation to set a timestamp to the current time, in case we want to modify this in the future. */
void timestamp_update(struct timeval *tv)
{
@@ -47,31 +40,56 @@ static bool proxy_subscr_matches_imsi(const struct proxy_subscr *proxy_subscr, c
return strcmp(proxy_subscr->imsi, imsi) == 0;
}
-static struct proxy_subscr_listentry *_proxy_get(const char *imsi)
+static bool proxy_subscr_matches_msisdn(const struct proxy_subscr *proxy_subscr, const char *msisdn)
+{
+ if (!proxy_subscr || !msisdn)
+ return false;
+ return strcmp(proxy_subscr->msisdn, msisdn) == 0;
+}
+
+static struct proxy_subscr_listentry *_proxy_get_by_imsi(struct proxy *proxy, const char *imsi)
{
struct proxy_subscr_listentry *e;
- llist_for_each_entry(e, &proxy_subscr_list, entry) {
+ llist_for_each_entry(e, &proxy->subscr_list, entry) {
if (proxy_subscr_matches_imsi(&e->data, imsi))
return e;
}
return NULL;
}
-const struct proxy_subscr *proxy_subscr_get(const char *imsi)
+static struct proxy_subscr_listentry *_proxy_get_by_msisdn(struct proxy *proxy, const char *msisdn)
+{
+ struct proxy_subscr_listentry *e;
+ llist_for_each_entry(e, &proxy->subscr_list, entry) {
+ if (proxy_subscr_matches_msisdn(&e->data, msisdn))
+ return e;
+ }
+ return NULL;
+}
+
+const struct proxy_subscr *proxy_subscr_get_by_imsi(struct proxy *proxy, const char *imsi)
+{
+ struct proxy_subscr_listentry *e = _proxy_get_by_imsi(proxy, imsi);
+ if (!e)
+ return NULL;
+ return &e->data;
+}
+
+const struct proxy_subscr *proxy_subscr_get_by_msisdn(struct proxy *proxy, const char *msisdn)
{
- struct proxy_subscr_listentry *e = _proxy_get(imsi);
+ struct proxy_subscr_listentry *e = _proxy_get_by_msisdn(proxy, msisdn);
if (!e)
return NULL;
return &e->data;
}
-int proxy_subscr_update(const struct proxy_subscr *proxy_subscr)
+int proxy_subscr_update(struct proxy *proxy, const struct proxy_subscr *proxy_subscr)
{
- struct proxy_subscr_listentry *e = _proxy_get(proxy_subscr->imsi);
+ struct proxy_subscr_listentry *e = _proxy_get_by_imsi(proxy, proxy_subscr->imsi);
if (!e) {
/* Does not exist yet */
- e = talloc_zero(proxy_ctx, struct proxy_subscr_listentry);
- llist_add(&e->entry, &proxy_subscr_list);
+ e = talloc_zero(proxy, struct proxy_subscr_listentry);
+ llist_add(&e->entry, &proxy->subscr_list);
}
e->data = *proxy_subscr;
timestamp_update(&e->last_update);
@@ -84,31 +102,53 @@ int _proxy_subscr_del(struct proxy_subscr_listentry *e)
return 0;
}
-int proxy_subscr_del(const char *imsi)
+int proxy_subscr_del(struct proxy *proxy, const char *imsi)
{
- struct proxy_subscr_listentry *e = _proxy_get(imsi);
+ struct proxy_subscr_listentry *e = _proxy_get_by_imsi(proxy, imsi);
if (!e)
return -ENOENT;
return _proxy_subscr_del(e);
}
/* Discard stale proxy entries. */
-static void proxy_cleanup(void *ignore)
+static void proxy_cleanup(void *proxy_v)
{
+ struct proxy *proxy = proxy_v;
struct proxy_subscr_listentry *e, *n;
- llist_for_each_entry_safe(e, n, &proxy_subscr_list, entry) {
- if (timestamp_age(&e->last_update) <= proxy_fresh_time)
+ llist_for_each_entry_safe(e, n, &proxy->subscr_list, entry) {
+ if (timestamp_age(&e->last_update) <= proxy->fresh_time)
continue;
_proxy_subscr_del(e);
}
- osmo_timer_schedule(&proxy_cleanup_timer, proxy_fresh_check_period, 0);
+ if (proxy->gc_period)
+ osmo_timer_schedule(&proxy->gc_timer, proxy->gc_period, 0);
+ else
+ LOGP(DDGSM, LOGL_NOTICE, "Proxy cleanup is switched off (gc_period == 0)\n");
+}
+
+void proxy_set_gc_period(struct proxy *proxy, uint32_t gc_period)
+{
+ proxy->gc_period = gc_period;
+ proxy_cleanup(proxy);
}
-void proxy_init(void *ctx)
+struct proxy *proxy_init(void *ctx)
{
- proxy_ctx = ctx;
- osmo_timer_setup(&proxy_cleanup_timer, &proxy_cleanup, NULL);
+ struct proxy *proxy = talloc_zero(ctx, struct proxy);
+ *proxy = (struct proxy){
+ .fresh_time = 60*60,
+ .gc_period = 60,
+ };
+ INIT_LLIST_HEAD(&proxy->subscr_list);
+
+ osmo_timer_setup(&proxy->gc_timer, proxy_cleanup, proxy);
/* Invoke to trigger the first timer schedule */
- proxy_cleanup(NULL);
+ proxy_set_gc_period(proxy, proxy->gc_period);
+ return proxy;
}
+void proxy_del(struct proxy *proxy)
+{
+ osmo_timer_del(&proxy->gc_timer);
+ talloc_free(proxy);
+}
diff --git a/src/proxy.h b/src/proxy.h
index 91d433d..4d332cf 100644
--- a/src/proxy.h
+++ b/src/proxy.h
@@ -3,16 +3,39 @@
#include <time.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/core/sockaddr_str.h>
+#include "global_title.h"
+
+void timestamp_update(struct timeval *timestamp);
+time_t timestamp_age(const struct timeval *timestamp);
+
+struct proxy {
+ struct llist_head subscr_list;
+
+ /* How long to keep proxy entries without a refresh, in seconds. */
+ uint32_t fresh_time;
+ /* How often to garbage collect the proxy cache, period in seconds.
+ * To change this and take effect immediately, rather use proxy_set_gc_period(). */
+ uint32_t gc_period;
+
+ struct osmo_timer_list gc_timer;
+};
struct proxy_subscr {
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
+ char msisdn[GSM23003_MSISDN_MAX_DIGITS+1];
+#if 0
+ /* Set if this is a middle proxy, i.e. a proxy behind another proxy. */
+ struct global_title vlr_via_proxy;
+#endif
+ struct global_title vlr_name;
struct osmo_sockaddr_str remote_hlr;
+ struct timeval last_lu;
};
-void proxy_init(void *ctx);
-const struct proxy_subscr *proxy_subscr_get(const char *imsi);
-int proxy_subscr_update(const struct proxy_subscr *proxy_subscr);
-int proxy_subscr_del(const char *imsi);
-
-void timestamp_update(struct timeval *timestamp);
-time_t timestamp_age(const struct timeval *timestamp);
+struct proxy *proxy_init(void *ctx);
+void proxy_del(struct proxy *proxy);
+void proxy_set_gc_period(struct proxy *proxy, uint32_t gc_period);
+const struct proxy_subscr *proxy_subscr_get_by_imsi(struct proxy *proxy, const char *imsi);
+const struct proxy_subscr *proxy_subscr_get_by_msisdn(struct proxy *proxy, const char *msisdn);
+int proxy_subscr_update(struct proxy *proxy, const struct proxy_subscr *proxy_subscr);
+int proxy_subscr_del(struct proxy *proxy, const char *imsi);
diff --git a/tests/db/db_test.c b/tests/db/db_test.c
index 8902998..94295e1 100644
--- a/tests/db/db_test.c
+++ b/tests/db/db_test.c
@@ -241,7 +241,7 @@ static int db_subscr_lu_str(struct db_context *dbc, int64_t subscr_id,
const char *vlr_or_sgsn_number, bool is_ps)
{
struct global_title vlr_nr;
- global_title_set(&vlr_nr, (uint8_t*)vlr_or_sgsn_number, vlr_or_sgsn_number ? strlen(vlr_or_sgsn_number)+1 : 0);
+ global_title_set_str(&vlr_nr, vlr_or_sgsn_number);
return db_subscr_lu(dbc, subscr_id, &vlr_nr, &vlr_nr, is_ps);
}
diff --git a/tests/db_upgrade/db_upgrade_test.ok b/tests/db_upgrade/db_upgrade_test.ok
index 52b6735..f467f06 100644
--- a/tests/db_upgrade/db_upgrade_test.ok
+++ b/tests/db_upgrade/db_upgrade_test.ok
@@ -136,18 +136,19 @@ periodic_lu_tmr|INTEGER|0||0
periodic_rau_tau_tmr|INTEGER|0||0
sgsn_address|VARCHAR|0||0
sgsn_number|VARCHAR(15)|0||0
+sgsn_via_proxy|VARCHAR|0||0
smsc_number|VARCHAR(15)|0||0
vlr_number|VARCHAR(15)|0||0
vlr_via_proxy|VARCHAR|0||0
Table subscriber contents:
-ggsn_number|gmlc_number|id|imei|imeisv|imsi|last_lu_seen|lmsi|ms_purged_cs|ms_purged_ps|msc_number|msisdn|nam_cs|nam_ps|periodic_lu_tmr|periodic_rau_tau_tmr|sgsn_address|sgsn_number|smsc_number|vlr_number|vlr_via_proxy
-||1|||123456789012345|||0|0||098765432109876|1|1||||||MSC-1|
-||2|||111111111|||1|0|||1|1|||||||
-||3|||222222222|||0|1||22222|1|1|||||||
-||4|||333333|||0|0||3|0|1|||||||
-||5|||444444444444444|||0|0||4444|1|0|||||||
-||6|||5555555|||0|0||55555555555555|0|0|||||||
+ggsn_number|gmlc_number|id|imei|imeisv|imsi|last_lu_seen|lmsi|ms_purged_cs|ms_purged_ps|msc_number|msisdn|nam_cs|nam_ps|periodic_lu_tmr|periodic_rau_tau_tmr|sgsn_address|sgsn_number|sgsn_via_proxy|smsc_number|vlr_number|vlr_via_proxy
+||1|||123456789012345|||0|0||098765432109876|1|1|||||||MSC-1|
+||2|||111111111|||1|0|||1|1||||||||
+||3|||222222222|||0|1||22222|1|1||||||||
+||4|||333333|||0|0||3|0|1||||||||
+||5|||444444444444444|||0|0||4444|1|0||||||||
+||6|||5555555|||0|0||55555555555555|0|0||||||||
Table: subscriber_apn
name|type|notnull|dflt_value|pk
diff --git a/tests/test_nodes.vty b/tests/test_nodes.vty
index 844b1fd..e36d6ad 100644
--- a/tests/test_nodes.vty
+++ b/tests/test_nodes.vty
@@ -119,8 +119,8 @@ OsmoHLR# configure terminal
OsmoHLR(config)# mslookup
OsmoHLR(config-mslookup)# list
...
- dns
- no dns
+ mdns
+ no mdns
server
no server
client
@@ -129,8 +129,8 @@ OsmoHLR(config-mslookup)# list
OsmoHLR(config-mslookup)# server
OsmoHLR(config-mslookup-server)# list
...
- dns bind multicast IP <1-65535>
- no dns
+ mdns bind IP <1-65535>
+ no mdns
service NAME at IP <1-65535>
no service NAME
no service NAME at IP <1-65535>
@@ -148,7 +148,7 @@ OsmoHLR(config-mslookup-server)# exit
OsmoHLR(config-mslookup)# client
OsmoHLR(config-mslookup-client)# list
...
- timeout <1-255>
- dns to multicast IP <1-65535>
- no dns
+ timeout <1-100000>
+ mdns to IP <1-65535>
+ no mdns