mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-hlr.git
synced 2025-11-02 13:13:29 +00:00
dgsm: osmo-hlr is opening mDNS server and client sockets
Change-Id: I377b3bab7334c3212e40c4cf19aa223ac1be1644
This commit is contained in:
@@ -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 (
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
6
src/db.c
6
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",
|
||||
};
|
||||
|
||||
|
||||
2
src/db.h
2
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)
|
||||
|
||||
17
src/db_hlr.c
17
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 */
|
||||
|
||||
225
src/dgsm.c
225
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();
|
||||
}
|
||||
|
||||
|
||||
51
src/dgsm.h
51
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_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();
|
||||
|
||||
182
src/dgsm_vty.c
182
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
12
src/hlr.c
12
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);
|
||||
|
||||
12
src/hlr.h
12
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -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
163
src/mslookup_server_mdns.c
Normal 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);
|
||||
}
|
||||
14
src/mslookup_server_mdns.h
Normal file
14
src/mslookup_server_mdns.h
Normal 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);
|
||||
94
src/proxy.c
94
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 = _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);
|
||||
}
|
||||
|
||||
43
src/proxy.h
43
src/proxy.h
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user