aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2019-11-20 03:35:37 +0100
committerNeels Hofmeyr <neels@hofmeyr.de>2020-04-30 19:22:24 +0200
commit407925dcab8bdff8e3d6c2cf4ed7b73b7d69141e (patch)
treeea297f67ac74d6ffa9d498ad9b7d2da2264fcb9f
parentab7dc40f168da4326f207ef8aeeec40229c94486 (diff)
D-GSM 2/n: implement mDNS method of mslookup server
Implement the mslookup server's mDNS responder, to actually service remote mslookup requests: - VTY mslookup/server config with service names, - the mslookup_mdns_server listening for mslookup requests, For a detailed overview of the D-GSM and mslookup related files, please see the elaborate comment at the top of mslookup.c (already added in an earlier patch). Change-Id: I5cae6459090588b4dd292be90a5e8903432669d2
-rw-r--r--include/osmocom/hlr/Makefile.am1
-rw-r--r--include/osmocom/hlr/hlr.h12
-rw-r--r--include/osmocom/hlr/hlr_vty.h4
-rw-r--r--include/osmocom/hlr/mslookup_server.h3
-rw-r--r--include/osmocom/hlr/mslookup_server_mdns.h36
-rw-r--r--src/Makefile.am4
-rw-r--r--src/dgsm_vty.c382
-rw-r--r--src/hlr.c3
-rw-r--r--src/mslookup_server_mdns.c157
-rw-r--r--tests/test_nodes.vty3
-rw-r--r--tests/test_subscriber.vty1
11 files changed, 605 insertions, 1 deletions
diff --git a/include/osmocom/hlr/Makefile.am b/include/osmocom/hlr/Makefile.am
index 5c96ec8..b24f084 100644
--- a/include/osmocom/hlr/Makefile.am
+++ b/include/osmocom/hlr/Makefile.am
@@ -11,6 +11,7 @@ noinst_HEADERS = \
logging.h \
lu_fsm.h \
mslookup_server.h \
+ mslookup_server_mdns.h \
rand.h \
timestamp.h \
$(NULL)
diff --git a/include/osmocom/hlr/hlr.h b/include/osmocom/hlr/hlr.h
index 1269994..8f26704 100644
--- a/include/osmocom/hlr/hlr.h
+++ b/include/osmocom/hlr/hlr.h
@@ -26,6 +26,7 @@
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/ipa.h>
#include <osmocom/core/tdef.h>
+#include <osmocom/core/sockaddr_str.h>
#define HLR_DEFAULT_DB_FILE_PATH "hlr.db"
@@ -69,9 +70,20 @@ struct hlr {
unsigned int subscr_create_on_demand_rand_msisdn_len;
struct {
+ bool allow_startup;
struct {
+ /* Whether the mslookup server should be active in general (all lookup methods) */
+ bool enable;
uint32_t local_attach_max_age;
struct llist_head local_site_services;
+ struct {
+ /* Whether the mDNS method of the mslookup server should be active. */
+ bool enable;
+ /* The mDNS bind address and domain suffix as set by the VTY, not necessarily in use. */
+ struct osmo_sockaddr_str bind_addr;
+ char *domain_suffix;
+ struct osmo_mslookup_server_mdns *running;
+ } mdns;
} server;
} mslookup;
};
diff --git a/include/osmocom/hlr/hlr_vty.h b/include/osmocom/hlr/hlr_vty.h
index acd6510..0ba9821 100644
--- a/include/osmocom/hlr/hlr_vty.h
+++ b/include/osmocom/hlr/hlr_vty.h
@@ -31,8 +31,12 @@ enum hlr_vty_node {
HLR_NODE = _LAST_OSMOVTY_NODE + 1,
GSUP_NODE,
EUSE_NODE,
+ MSLOOKUP_NODE,
+ MSLOOKUP_SERVER_NODE,
+ MSLOOKUP_SERVER_MSC_NODE,
};
int hlr_vty_is_config_node(struct vty *vty, int node);
int hlr_vty_go_parent(struct vty *vty);
void hlr_vty_init(void);
+void dgsm_vty_init(void);
diff --git a/include/osmocom/hlr/mslookup_server.h b/include/osmocom/hlr/mslookup_server.h
index 5425328..440c451 100644
--- a/include/osmocom/hlr/mslookup_server.h
+++ b/include/osmocom/hlr/mslookup_server.h
@@ -19,6 +19,9 @@
#pragma once
+#include <osmocom/gsupclient/cni_peer_id.h>
+#include <osmocom/mslookup/mslookup.h>
+
struct osmo_mslookup_query;
struct osmo_mslookup_result;
diff --git a/include/osmocom/hlr/mslookup_server_mdns.h b/include/osmocom/hlr/mslookup_server_mdns.h
new file mode 100644
index 0000000..ef16e88
--- /dev/null
+++ b/include/osmocom/hlr/mslookup_server_mdns.h
@@ -0,0 +1,36 @@
+/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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;
+ char *domain_suffix;
+ struct osmo_mdns_sock *sock;
+};
+
+struct osmo_mslookup_server_mdns *osmo_mslookup_server_mdns_start(void *ctx, const struct osmo_sockaddr_str *bind_addr,
+ const char *domain_suffix);
+void osmo_mslookup_server_mdns_stop(struct osmo_mslookup_server_mdns *server);
+void mslookup_server_mdns_config_apply();
diff --git a/src/Makefile.am b/src/Makefile.am
index 571eaef..ceaa093 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -54,8 +54,10 @@ osmo_hlr_SOURCES = \
gsup_send.c \
hlr_ussd.c \
lu_fsm.c \
- mslookup_server.c \
timestamp.c \
+ mslookup_server.c \
+ mslookup_server_mdns.c \
+ dgsm_vty.c \
$(NULL)
osmo_hlr_LDADD = \
diff --git a/src/dgsm_vty.c b/src/dgsm_vty.c
new file mode 100644
index 0000000..facd2b7
--- /dev/null
+++ b/src/dgsm_vty.c
@@ -0,0 +1,382 @@
+/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/vty/vty.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/mslookup/mslookup_client_mdns.h>
+#include <osmocom/mslookup/mdns.h>
+#include <osmocom/hlr/hlr_vty.h>
+#include <osmocom/hlr/mslookup_server.h>
+#include <osmocom/hlr/mslookup_server_mdns.h>
+#include <osmocom/gsupclient/cni_peer_id.h>
+
+struct cmd_node mslookup_node = {
+ MSLOOKUP_NODE,
+ "%s(config-mslookup)# ",
+ 1,
+};
+
+DEFUN(cfg_mslookup,
+ cfg_mslookup_cmd,
+ "mslookup",
+ "Configure Distributed GSM mslookup")
+{
+ vty->node = MSLOOKUP_NODE;
+ return CMD_SUCCESS;
+}
+
+static int mslookup_server_mdns_bind(struct vty *vty, int argc, const char **argv)
+{
+ const char *ip_str = argc > 0? argv[0] : g_hlr->mslookup.server.mdns.bind_addr.ip;
+ const char *port_str = argc > 1? argv[1] : NULL;
+ uint16_t port_nr = port_str ? atoi(port_str) : g_hlr->mslookup.server.mdns.bind_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, "%% mslookup server: Invalid mDNS bind address: %s %u%s",
+ ip_str, port_nr, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ g_hlr->mslookup.server.mdns.bind_addr = addr;
+ g_hlr->mslookup.server.mdns.enable = true;
+ g_hlr->mslookup.server.enable = true;
+ mslookup_server_mdns_config_apply();
+ return CMD_SUCCESS;
+}
+
+#define MDNS_STR "Multicast DNS related configuration\n"
+#define MDNS_IP46_STR "multicast IPv4 address like " OSMO_MSLOOKUP_MDNS_IP4 \
+ " or IPv6 address like " OSMO_MSLOOKUP_MDNS_IP6 "\n"
+#define MDNS_PORT_STR "mDNS UDP Port number\n"
+#define MDNS_DOMAIN_SUFFIX_STR "mDNS domain suffix (default: " OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT "). This is appended" \
+ " and stripped from mDNS packets during encoding/decoding, so we don't collide with" \
+ " top-level domains administrated by IANA\n"
+#define IP46_STR "IPv4 address like 1.2.3.4 or IPv6 address like a:b:c:d::1\n"
+#define PORT_STR "Service-specific port number\n"
+
+struct cmd_node mslookup_server_node = {
+ MSLOOKUP_SERVER_NODE,
+ "%s(config-mslookup-server)# ",
+ 1,
+};
+
+DEFUN(cfg_mslookup_server,
+ cfg_mslookup_server_cmd,
+ "server",
+ "Enable and configure Distributed GSM mslookup server")
+{
+ vty->node = MSLOOKUP_SERVER_NODE;
+ g_hlr->mslookup.server.enable = true;
+ mslookup_server_mdns_config_apply();
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mslookup_no_server,
+ cfg_mslookup_no_server_cmd,
+ "no server",
+ NO_STR "Disable Distributed GSM mslookup server")
+{
+ g_hlr->mslookup.server.enable = false;
+ mslookup_server_mdns_config_apply();
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mslookup_server_mdns_bind,
+ cfg_mslookup_server_mdns_bind_cmd,
+ "mdns bind [IP] [<1-65535>]",
+ MDNS_STR
+ "Configure where the mDNS server listens for mslookup requests\n"
+ MDNS_IP46_STR MDNS_PORT_STR)
+{
+ return mslookup_server_mdns_bind(vty, argc, argv);
+}
+
+DEFUN(cfg_mslookup_server_mdns_domain_suffix,
+ cfg_mslookup_server_mdns_domain_suffix_cmd,
+ "mdns domain-suffix DOMAIN_SUFFIX",
+ MDNS_STR
+ MDNS_DOMAIN_SUFFIX_STR
+ MDNS_DOMAIN_SUFFIX_STR)
+{
+ osmo_talloc_replace_string(g_hlr, &g_hlr->mslookup.server.mdns.domain_suffix, argv[0]);
+ mslookup_server_mdns_config_apply();
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mslookup_server_no_mdns_bind,
+ cfg_mslookup_server_no_mdns_bind_cmd,
+ "no mdns bind",
+ NO_STR "Disable server for mDNS mslookup (do not answer remote requests)\n")
+{
+ g_hlr->mslookup.server.mdns.enable = false;
+ mslookup_server_mdns_config_apply();
+ return CMD_SUCCESS;
+}
+
+struct cmd_node mslookup_server_msc_node = {
+ MSLOOKUP_SERVER_MSC_NODE,
+ "%s(config-mslookup-server-msc)# ",
+ 1,
+};
+
+DEFUN(cfg_mslookup_server_msc,
+ cfg_mslookup_server_msc_cmd,
+ "msc ipa-name .IPA_NAME",
+ "Configure services for individual local MSCs\n"
+ "Identify locally connected MSC by IPA Unit Name\n"
+ "IPA Unit Name of the local MSC to configure\n")
+{
+ struct osmo_ipa_name msc_name;
+ struct mslookup_server_msc_cfg *msc;
+ osmo_ipa_name_set_str(&msc_name, argv_concat(argv, argc, 0));
+
+ msc = mslookup_server_msc_get(&msc_name, true);
+ if (!msc) {
+ vty_out(vty, "%% Error creating MSC %s%s", osmo_ipa_name_to_str(&msc_name), VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ vty->node = MSLOOKUP_SERVER_MSC_NODE;
+ vty->index = msc;
+ return CMD_SUCCESS;
+}
+
+#define SERVICE_NAME_STR \
+ "mslookup service name, e.g. sip.voice or smpp.sms\n"
+
+static struct mslookup_server_msc_cfg *msc_from_node(struct vty *vty)
+{
+ switch (vty->node) {
+ case MSLOOKUP_SERVER_NODE:
+ /* On the mslookup.server node, set services on the wildcard msc, without a particular name. */
+ return mslookup_server_msc_get(&mslookup_server_msc_wildcard, true);
+ case MSLOOKUP_SERVER_MSC_NODE:
+ return vty->index;
+ default:
+ return NULL;
+ }
+}
+
+DEFUN(cfg_mslookup_server_msc_service,
+ cfg_mslookup_server_msc_service_cmd,
+ "service NAME at IP <1-65535>",
+ "Configure addresses of local services, as sent in replies to remote mslookup requests.\n"
+ SERVICE_NAME_STR "at\n" IP46_STR PORT_STR)
+{
+ /* 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 mslookup_server_msc_cfg *msc = msc_from_node(vty);
+ const char *service = argv[0];
+ const char *ip_str = argv[1];
+ const char *port_str = argv[2];
+ struct osmo_sockaddr_str addr;
+
+ 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, "%% mslookup server: Invalid address for service %s: %s %s%s",
+ service, ip_str, port_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (mslookup_server_msc_service_set(msc, service, &addr)) {
+ vty_out(vty, "%% mslookup server: Error setting service %s to %s %s%s",
+ service, ip_str, port_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+#define NO_SERVICE_AND_NAME_STR NO_STR "Remove one or more service address entries\n" SERVICE_NAME_STR
+
+DEFUN(cfg_mslookup_server_msc_no_service,
+ cfg_mslookup_server_msc_no_service_cmd,
+ "no service NAME",
+ NO_SERVICE_AND_NAME_STR)
+{
+ /* 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 mslookup_server_msc_cfg *msc = msc_from_node(vty);
+ const char *service = argv[0];
+
+ if (!msc) {
+ vty_out(vty, "%% Error: no MSC object on this node%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (mslookup_server_msc_service_del(msc, service, NULL) < 1) {
+ vty_out(vty, "%% mslookup server: cannot remove service '%s'%s",
+ service, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mslookup_server_msc_no_service_addr,
+ cfg_mslookup_server_msc_no_service_addr_cmd,
+ "no service NAME at IP <1-65535>",
+ NO_SERVICE_AND_NAME_STR "at\n" IP46_STR PORT_STR)
+{
+ /* 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 mslookup_server_msc_cfg *msc = msc_from_node(vty);
+ const char *service = argv[0];
+ const char *ip_str = argv[1];
+ const char *port_str = argv[2];
+ struct osmo_sockaddr_str addr;
+
+ 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, "%% mslookup server: Invalid address for 'no service' %s: %s %s%s",
+ service, ip_str, port_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ if (mslookup_server_msc_service_del(msc, service, &addr) < 1) {
+ vty_out(vty, "%% mslookup server: cannot remove service '%s' to %s %s%s",
+ service, ip_str, port_str, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ return CMD_SUCCESS;
+}
+
+void config_write_msc_services(struct vty *vty, const char *indent, struct mslookup_server_msc_cfg *msc)
+{
+ struct mslookup_service_host *e;
+
+ llist_for_each_entry(e, &msc->service_hosts, entry) {
+ if (osmo_sockaddr_str_is_nonzero(&e->host_v4))
+ vty_out(vty, "%sservice %s at %s %u%s", indent, e->service, e->host_v4.ip, e->host_v4.port,
+ VTY_NEWLINE);
+ if (osmo_sockaddr_str_is_nonzero(&e->host_v6))
+ vty_out(vty, "%sservice %s at %s %u%s", indent, e->service, e->host_v6.ip, e->host_v6.port,
+ VTY_NEWLINE);
+ }
+}
+
+int config_write_mslookup(struct vty *vty)
+{
+ if (!g_hlr->mslookup.server.enable
+ && llist_empty(&g_hlr->mslookup.server.local_site_services))
+ return CMD_SUCCESS;
+
+ vty_out(vty, "mslookup%s", VTY_NEWLINE);
+
+ if (g_hlr->mslookup.server.enable || !llist_empty(&g_hlr->mslookup.server.local_site_services)) {
+ struct mslookup_server_msc_cfg *msc;
+
+ vty_out(vty, " server%s", VTY_NEWLINE);
+
+ if (g_hlr->mslookup.server.mdns.enable) {
+ vty_out(vty, " mdns bind");
+ if (osmo_sockaddr_str_is_nonzero(&g_hlr->mslookup.server.mdns.bind_addr)) {
+ vty_out(vty, " %s %u",
+ g_hlr->mslookup.server.mdns.bind_addr.ip,
+ g_hlr->mslookup.server.mdns.bind_addr.port);
+ }
+ vty_out(vty, "%s", VTY_NEWLINE);
+ }
+ if (strcmp(g_hlr->mslookup.server.mdns.domain_suffix, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT))
+ vty_out(vty, " mdns domain-suffix %s%s",
+ g_hlr->mslookup.server.mdns.domain_suffix,
+ VTY_NEWLINE);
+
+ msc = mslookup_server_msc_get(&mslookup_server_msc_wildcard, false);
+ if (msc)
+ config_write_msc_services(vty, " ", msc);
+
+ llist_for_each_entry(msc, &g_hlr->mslookup.server.local_site_services, entry) {
+ if (!osmo_ipa_name_cmp(&mslookup_server_msc_wildcard, &msc->name))
+ continue;
+ vty_out(vty, " msc %s%s", osmo_ipa_name_to_str(&msc->name), VTY_NEWLINE);
+ config_write_msc_services(vty, " ", msc);
+ }
+
+ /* If the server is disabled, still output the above to not lose the service config. */
+ if (!g_hlr->mslookup.server.enable)
+ vty_out(vty, " no server%s", VTY_NEWLINE);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(do_mslookup_show_services,
+ do_mslookup_show_services_cmd,
+ "show mslookup services",
+ SHOW_STR "Distributed GSM / mslookup related information\n"
+ "List configured service addresses as sent to remote mslookup requests\n")
+{
+ struct mslookup_server_msc_cfg *msc;
+ const struct mslookup_service_host *local_hlr = mslookup_server_get_local_gsup_addr();
+
+ vty_out(vty, "Local GSUP HLR address returned in mslookup responses for local IMSIs:");
+ if (osmo_sockaddr_str_is_nonzero(&local_hlr->host_v4))
+ vty_out(vty, " " OSMO_SOCKADDR_STR_FMT,
+ OSMO_SOCKADDR_STR_FMT_ARGS(&local_hlr->host_v4));
+ if (osmo_sockaddr_str_is_nonzero(&local_hlr->host_v6))
+ vty_out(vty, " " OSMO_SOCKADDR_STR_FMT,
+ OSMO_SOCKADDR_STR_FMT_ARGS(&local_hlr->host_v6));
+ vty_out(vty, "%s", VTY_NEWLINE);
+
+ msc = mslookup_server_msc_get(&mslookup_server_msc_wildcard, false);
+ if (msc)
+ config_write_msc_services(vty, "", msc);
+
+ llist_for_each_entry(msc, &g_hlr->mslookup.server.local_site_services, entry) {
+ if (!osmo_ipa_name_cmp(&mslookup_server_msc_wildcard, &msc->name))
+ continue;
+ vty_out(vty, "msc ipa-name %s%s", osmo_ipa_name_to_str(&msc->name), VTY_NEWLINE);
+ config_write_msc_services(vty, " ", msc);
+ }
+ return CMD_SUCCESS;
+}
+
+void dgsm_vty_init(void)
+{
+ install_element(CONFIG_NODE, &cfg_mslookup_cmd);
+
+ install_node(&mslookup_node, config_write_mslookup);
+ install_element(MSLOOKUP_NODE, &cfg_mslookup_server_cmd);
+ install_element(MSLOOKUP_NODE, &cfg_mslookup_no_server_cmd);
+
+ install_node(&mslookup_server_node, NULL);
+ install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_mdns_bind_cmd);
+ install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_mdns_domain_suffix_cmd);
+ install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_no_mdns_bind_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);
+ install_element(MSLOOKUP_SERVER_NODE, &cfg_mslookup_server_msc_cmd);
+
+ install_node(&mslookup_server_msc_node, NULL);
+ install_element(MSLOOKUP_SERVER_MSC_NODE, &cfg_mslookup_server_msc_service_cmd);
+ install_element(MSLOOKUP_SERVER_MSC_NODE, &cfg_mslookup_server_msc_no_service_cmd);
+ install_element(MSLOOKUP_SERVER_MSC_NODE, &cfg_mslookup_server_msc_no_service_addr_cmd);
+
+ install_element_ve(&do_mslookup_show_services_cmd);
+}
diff --git a/src/hlr.c b/src/hlr.c
index 2cabab4..5e015b3 100644
--- a/src/hlr.c
+++ b/src/hlr.c
@@ -48,6 +48,7 @@
#include <osmocom/hlr/hlr_vty.h>
#include <osmocom/hlr/hlr_ussd.h>
#include <osmocom/hlr/lu_fsm.h>
+#include <osmocom/mslookup/mdns.h>
struct hlr *g_hlr;
static void *hlr_ctx = NULL;
@@ -697,6 +698,7 @@ int main(int argc, char **argv)
INIT_LLIST_HEAD(&g_hlr->ussd_routes);
INIT_LLIST_HEAD(&g_hlr->mslookup.server.local_site_services);
g_hlr->db_file_path = talloc_strdup(g_hlr, HLR_DEFAULT_DB_FILE_PATH);
+ g_hlr->mslookup.server.mdns.domain_suffix = talloc_strdup(g_hlr, OSMO_MDNS_DOMAIN_SUFFIX_DEFAULT);
/* Init default (call independent) SS session guard timeout value */
g_hlr->ncss_guard_timeout = NCSS_GUARD_TIMEOUT_DEFAULT;
@@ -712,6 +714,7 @@ int main(int argc, char **argv)
ctrl_vty_init(hlr_ctx);
handle_options(argc, argv);
hlr_vty_init();
+ dgsm_vty_init();
rc = vty_read_config_file(cmdline_opts.config_file, NULL);
if (rc < 0) {
diff --git a/src/mslookup_server_mdns.c b/src/mslookup_server_mdns.c
new file mode 100644
index 0000000..0e94074
--- /dev/null
+++ b/src/mslookup_server_mdns.c
@@ -0,0 +1,157 @@
+/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <osmocom/mslookup/mslookup.h>
+#include <osmocom/mslookup/mdns.h>
+#include <osmocom/hlr/logging.h>
+#include <osmocom/hlr/hlr.h>
+#include <osmocom/hlr/mslookup_server.h>
+#include <osmocom/hlr/mslookup_server_mdns.h>
+
+static void osmo_mslookup_server_mdns_tx(struct osmo_mslookup_server_mdns *server,
+ uint16_t packet_id,
+ const struct osmo_mslookup_query *query,
+ const struct osmo_mslookup_result *result)
+{
+ struct msgb *msg;
+ const char *errmsg = NULL;
+ void *ctx = talloc_named_const(server, 0, __func__);
+
+ msg = osmo_mdns_result_encode(ctx, packet_id, query, result, server->domain_suffix);
+ if (!msg)
+ errmsg = "Error encoding mDNS answer packet";
+ else if (osmo_mdns_sock_send(server->sock, msg))
+ errmsg = "Error sending mDNS answer";
+ if (errmsg)
+ LOGP(DMSLOOKUP, LOGL_ERROR, "%s: mDNS: %s\n", osmo_mslookup_result_name_c(ctx, query, result), errmsg);
+ talloc_free(ctx);
+}
+
+static void osmo_mslookup_server_mdns_handle_request(uint16_t packet_id,
+ struct osmo_mslookup_server_mdns *server,
+ const struct osmo_mslookup_query *query)
+{
+ struct osmo_mslookup_result result;
+
+ mslookup_server_rx(query, &result);
+ /* Error logging already happens in mslookup_server_rx() */
+ if (result.rc != OSMO_MSLOOKUP_RC_RESULT)
+ return;
+
+ osmo_mslookup_server_mdns_tx(server, packet_id, 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_mslookup_query *query;
+ uint16_t packet_id;
+ 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__);
+ query = osmo_mdns_query_decode(ctx, buffer, n, &packet_id, server->domain_suffix);
+ if (!query) {
+ talloc_free(ctx);
+ return -1;
+ }
+
+ osmo_mslookup_id_name_buf((char *)buffer, sizeof(buffer), &query->id);
+ LOGP(DMSLOOKUP, LOGL_DEBUG, "mDNS rx request: %s.%s\n", query->service, buffer);
+ osmo_mslookup_server_mdns_handle_request(packet_id, server, query);
+ talloc_free(ctx);
+ return n;
+}
+
+struct osmo_mslookup_server_mdns *osmo_mslookup_server_mdns_start(void *ctx, const struct osmo_sockaddr_str *bind_addr,
+ const char *domain_suffix)
+{
+ 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,
+ .domain_suffix = talloc_strdup(server, domain_suffix)
+ };
+
+ server->sock = osmo_mdns_sock_init(server,
+ bind_addr->ip, bind_addr->port,
+ osmo_mslookup_server_mdns_rx,
+ server, 0);
+ if (!server->sock) {
+ LOGP(DMSLOOKUP, 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);
+}
+
+void mslookup_server_mdns_config_apply()
+{
+ /* Check whether to start/stop/restart mDNS server */
+ bool should_run;
+ bool should_stop;
+
+ should_run = g_hlr->mslookup.allow_startup
+ && g_hlr->mslookup.server.enable && g_hlr->mslookup.server.mdns.enable;
+ should_stop = g_hlr->mslookup.server.mdns.running
+ && (!should_run
+ || osmo_sockaddr_str_cmp(&g_hlr->mslookup.server.mdns.bind_addr,
+ &g_hlr->mslookup.server.mdns.running->bind_addr)
+ || strcmp(g_hlr->mslookup.server.mdns.domain_suffix,
+ g_hlr->mslookup.server.mdns.running->domain_suffix));
+
+ if (should_stop) {
+ osmo_mslookup_server_mdns_stop(g_hlr->mslookup.server.mdns.running);
+ g_hlr->mslookup.server.mdns.running = NULL;
+ LOGP(DMSLOOKUP, LOGL_NOTICE, "Stopped mslookup mDNS server\n");
+ }
+
+ if (should_run && !g_hlr->mslookup.server.mdns.running) {
+ g_hlr->mslookup.server.mdns.running =
+ osmo_mslookup_server_mdns_start(g_hlr, &g_hlr->mslookup.server.mdns.bind_addr,
+ g_hlr->mslookup.server.mdns.domain_suffix);
+ if (!g_hlr->mslookup.server.mdns.running)
+ LOGP(DMSLOOKUP, 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(DMSLOOKUP, 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.running->bind_addr));
+ }
+}
diff --git a/tests/test_nodes.vty b/tests/test_nodes.vty
index c056e4d..ee351e3 100644
--- a/tests/test_nodes.vty
+++ b/tests/test_nodes.vty
@@ -15,6 +15,7 @@ OsmoHLR> list
show gsup-connections
subscriber (imsi|msisdn|id|imei) IDENT show
show subscriber (imsi|msisdn|id|imei) IDENT
+ show mslookup services
OsmoHLR> enable
OsmoHLR# ?
@@ -25,9 +26,11 @@ OsmoHLR# configure terminal
OsmoHLR(config)# ?
...
hlr Configure the HLR
+ mslookup Configure Distributed GSM mslookup
OsmoHLR(config)# list
...
hlr
+ mslookup
OsmoHLR(config)# hlr
OsmoHLR(config-hlr)# ?
diff --git a/tests/test_subscriber.vty b/tests/test_subscriber.vty
index 8e9026d..fb5da0e 100644
--- a/tests/test_subscriber.vty
+++ b/tests/test_subscriber.vty
@@ -13,6 +13,7 @@ OsmoHLR# list
subscriber (imsi|msisdn|id|imei) IDENT update aud3g milenage k K (op|opc) OP_C [ind-bitlen] [<0-28>]
subscriber (imsi|msisdn|id|imei) IDENT update imei (none|IMEI)
subscriber (imsi|msisdn|id|imei) IDENT update network-access-mode (none|cs|ps|cs+ps)
+ show mslookup services
OsmoHLR# subscriber?
subscriber Subscriber management commands