dgsm: osmo-hlr is opening mDNS server and client sockets

Change-Id: I377b3bab7334c3212e40c4cf19aa223ac1be1644
This commit is contained in:
Neels Hofmeyr
2019-11-05 21:24:45 +01:00
parent 82f4521319
commit 0a5eac957a
21 changed files with 832 additions and 319 deletions

View File

@@ -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 (

View File

@@ -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)

View File

@@ -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",
};

View File

@@ -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)

View File

@@ -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 */

View File

@@ -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();
}

View File

@@ -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_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_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_msc_config *dgsm_config_msc_get(const uint8_t *ipa_unit_name, size_t ipa_unit_name_len,
bool create);
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);
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();

View File

@@ -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;
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -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,42 +57,204 @@ 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));
}
}
/* 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).
*/
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)
/* 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)
{
return false;
}
void 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;
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. Return
* true if it is attached at a local MSC, and we are serving as proxy for a remote home HLR.
*/
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)
{
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;
}
/* 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 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. */
if (strcmp(query->service, OSMO_MSLOOKUP_SERVICE_HLR_GSUP) != 0)
@@ -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);
set_result(result, service_host, age);
}
struct osmo_mslookup_server_dns *osmo_mslookup_server_dns_start(const struct osmo_sockaddr_str *multicast_bind_addr)
{
return NULL;
}
void osmo_mslookup_server_dns_stop(struct osmo_mslookup_server_dns *server)
{
}

View File

@@ -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);

163
src/mslookup_server_mdns.c Normal file
View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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 = _proxy_get(imsi);
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;
}
int proxy_subscr_update(const struct proxy_subscr *proxy_subscr)
const struct proxy_subscr *proxy_subscr_get_by_msisdn(struct proxy *proxy, const char *msisdn)
{
struct proxy_subscr_listentry *e = _proxy_get(proxy_subscr->imsi);
struct proxy_subscr_listentry *e = _proxy_get_by_msisdn(proxy, msisdn);
if (!e)
return NULL;
return &e->data;
}
int proxy_subscr_update(struct proxy *proxy, const struct proxy_subscr *proxy_subscr)
{
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_init(void *ctx)
void proxy_set_gc_period(struct proxy *proxy, uint32_t gc_period)
{
proxy_ctx = ctx;
osmo_timer_setup(&proxy_cleanup_timer, &proxy_cleanup, NULL);
/* Invoke to trigger the first timer schedule */
proxy_cleanup(NULL);
proxy->gc_period = gc_period;
proxy_cleanup(proxy);
}
struct proxy *proxy_init(void *ctx)
{
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_set_gc_period(proxy, proxy->gc_period);
return proxy;
}
void proxy_del(struct proxy *proxy)
{
osmo_timer_del(&proxy->gc_timer);
talloc_free(proxy);
}

View File

@@ -3,16 +3,39 @@
#include <time.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/core/sockaddr_str.h>
struct proxy_subscr {
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
struct osmo_sockaddr_str remote_hlr;
};
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);
#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;
};
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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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