blob: f96bca6e8a8365e5d31a30455f6bf586510bca1b [file] [log] [blame]
Neels Hofmeyr76328bd2019-11-20 03:35:37 +01001/* Copyright 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
2 *
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20#include <errno.h>
21#include <osmocom/core/logging.h>
22#include <osmocom/mslookup/mslookup_client.h>
23#include <osmocom/mslookup/mslookup_client_mdns.h>
24#include <osmocom/gsupclient/gsup_client.h>
25#include <osmocom/gsupclient/cni_peer_id.h>
26#include <osmocom/hlr/logging.h>
27#include <osmocom/hlr/hlr.h>
28#include <osmocom/hlr/db.h>
29#include <osmocom/hlr/gsup_router.h>
30#include <osmocom/hlr/gsup_server.h>
31#include <osmocom/hlr/dgsm.h>
32#include <osmocom/hlr/proxy.h>
33#include <osmocom/hlr/remote_hlr.h>
34#include <osmocom/hlr/mslookup_server.h>
35#include <osmocom/hlr/mslookup_server_mdns.h>
36#include <osmocom/hlr/dgsm.h>
37
38void *dgsm_ctx = NULL;
39
40static void resolve_hlr_result_cb(struct osmo_mslookup_client *client,
41 uint32_t request_handle,
42 const struct osmo_mslookup_query *query,
43 const struct osmo_mslookup_result *result)
44{
45 struct proxy *proxy = g_hlr->gs->proxy;
46 struct proxy_subscr proxy_subscr;
47 const struct osmo_sockaddr_str *remote_hlr_addr;
48
49 /* A remote HLR is answering back, indicating that it is the home HLR for a given IMSI.
50 * There should be a mostly empty proxy entry for that IMSI.
51 * Add the remote address data in the proxy. */
52 if (query->id.type != OSMO_MSLOOKUP_ID_IMSI) {
53 LOGP(DDGSM, LOGL_ERROR, "Expected IMSI ID type in mslookup query+result: %s\n",
54 osmo_mslookup_result_name_c(OTC_SELECT, query, result));
55 return;
56 }
57
58 if (result->rc != OSMO_MSLOOKUP_RC_RESULT) {
59 LOG_DGSM(query->id.imsi, LOGL_ERROR, "Failed to resolve remote HLR: %s\n",
60 osmo_mslookup_result_name_c(OTC_SELECT, query, result));
61 proxy_subscr_del(proxy, query->id.imsi);
62 return;
63 }
64
65 if (osmo_sockaddr_str_is_nonzero(&result->host_v4))
66 remote_hlr_addr = &result->host_v4;
67 else if (osmo_sockaddr_str_is_nonzero(&result->host_v6))
68 remote_hlr_addr = &result->host_v6;
69 else {
70 LOG_DGSM(query->id.imsi, LOGL_ERROR, "Invalid address for remote HLR: %s\n",
71 osmo_mslookup_result_name_c(OTC_SELECT, query, result));
72 proxy_subscr_del(proxy, query->id.imsi);
73 return;
74 }
75
76 if (proxy_subscr_get_by_imsi(&proxy_subscr, proxy, query->id.imsi)) {
77 LOG_DGSM(query->id.imsi, LOGL_ERROR, "No proxy entry for mslookup result: %s\n",
78 osmo_mslookup_result_name_c(OTC_SELECT, query, result));
79 return;
80 }
81
82 proxy_subscr_remote_hlr_resolved(proxy, &proxy_subscr, remote_hlr_addr);
83}
84
85/* Return true when the message has been handled by D-GSM. */
86bool dgsm_check_forward_gsup_msg(struct osmo_gsup_req *req)
87{
88 struct proxy_subscr proxy_subscr;
89 struct proxy *proxy = g_hlr->gs->proxy;
90 struct osmo_mslookup_query query;
91 struct osmo_mslookup_query_handling handling;
92 uint32_t request_handle;
93
94 /* If the IMSI is known in the local HLR, then we won't proxy. */
95 if (db_subscr_exists_by_imsi(g_hlr->dbc, req->gsup.imsi) == 0)
96 return false;
97
98 /* Are we already forwarding this IMSI to a remote HLR? */
99 if (proxy_subscr_get_by_imsi(&proxy_subscr, proxy, req->gsup.imsi) == 0) {
100 proxy_subscr_forward_to_remote_hlr(proxy, &proxy_subscr, req);
101 return true;
102 }
103
104 /* The IMSI is not known locally, so we want to proxy to a remote HLR, but no proxy entry exists yet. We need to
105 * look up the subscriber in remote HLRs via D-GSM mslookup, forward GSUP and reply once a result is back from
106 * there. Defer message and kick off MS lookup. */
107
108 /* Add a proxy entry without a remote address to indicate that we are busy querying for a remote HLR. */
109 proxy_subscr = (struct proxy_subscr){};
110 OSMO_STRLCPY_ARRAY(proxy_subscr.imsi, req->gsup.imsi);
111 if (proxy_subscr_create_or_update(proxy, &proxy_subscr)) {
112 osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Failed to create proxy entry\n");
113 return true;
114 }
115
116 /* Is a fixed gateway proxy configured? */
117 if (osmo_sockaddr_str_is_nonzero(&g_hlr->mslookup.client.gsup_gateway_proxy)) {
118 proxy_subscr_remote_hlr_resolved(proxy, &proxy_subscr, &g_hlr->mslookup.client.gsup_gateway_proxy);
119
120 /* Proxy database modified, update info */
121 if (proxy_subscr_get_by_imsi(&proxy_subscr, proxy, req->gsup.imsi)) {
122 osmo_gsup_req_respond_err(req, GMM_CAUSE_NET_FAIL, "Internal proxy error\n");
123 return true;
124 }
125
126 proxy_subscr_forward_to_remote_hlr(proxy, &proxy_subscr, req);
127 return true;
128 }
129
130 /* Kick off an mslookup for the remote HLR? This check could be up first on the top, but do it only now so that
131 * if the mslookup client disconnected, we still continue to service open proxy entries. */
132 if (!osmo_mslookup_client_active(g_hlr->mslookup.client.client)) {
133 LOG_GSUP_REQ(req, LOGL_DEBUG, "mslookup client not running, cannot query remote home HLR\n");
134 return false;
135 }
136
137 /* First spool message, then kick off mslookup. If the proxy denies this message type, then don't do anything. */
138 if (proxy_subscr_forward_to_remote_hlr(proxy, &proxy_subscr, req)) {
139 /* If the proxy denied forwarding, an error response was already generated. */
140 return true;
141 }
142
143 query = (struct osmo_mslookup_query){
144 .id = {
145 .type = OSMO_MSLOOKUP_ID_IMSI,
146 },
147 };
148 OSMO_STRLCPY_ARRAY(query.id.imsi, req->gsup.imsi);
149 OSMO_STRLCPY_ARRAY(query.service, OSMO_MSLOOKUP_SERVICE_HLR_GSUP);
150 handling = (struct osmo_mslookup_query_handling){
151 .min_wait_milliseconds = g_hlr->mslookup.client.result_timeout_milliseconds,
152 .result_cb = resolve_hlr_result_cb,
153 };
154 request_handle = osmo_mslookup_client_request(g_hlr->mslookup.client.client, &query, &handling);
155 if (!request_handle) {
156 LOG_DGSM(req->gsup.imsi, LOGL_ERROR, "Error dispatching mslookup query for home HLR: %s\n",
157 osmo_mslookup_result_name_c(OTC_SELECT, &query, NULL));
158 proxy_subscr_del(proxy, req->gsup.imsi);
159 /* mslookup seems to not be working. Try handling it locally. */
160 return false;
161 }
162
163 return true;
164}
165
166void dgsm_init(void *ctx)
167{
168 dgsm_ctx = talloc_named_const(ctx, 0, "dgsm");
169 INIT_LLIST_HEAD(&g_hlr->mslookup.server.local_site_services);
170
171 g_hlr->mslookup.server.local_attach_max_age = 60 * 60;
172
Keithc27bc902022-12-19 19:54:04 +0100173 g_hlr->mslookup.client.result_timeout_milliseconds = OSMO_DGSM_DEFAULT_RESULT_TIMEOUT_MS;
Neels Hofmeyr76328bd2019-11-20 03:35:37 +0100174
175 g_hlr->gsup_unit_name.unit_name = "HLR";
176 g_hlr->gsup_unit_name.serno = "unnamed-HLR";
177 g_hlr->gsup_unit_name.swversion = PACKAGE_NAME "-" PACKAGE_VERSION;
178
179 osmo_sockaddr_str_from_str(&g_hlr->mslookup.server.mdns.bind_addr,
180 OSMO_MSLOOKUP_MDNS_IP4, OSMO_MSLOOKUP_MDNS_PORT);
181 osmo_sockaddr_str_from_str(&g_hlr->mslookup.client.mdns.query_addr,
182 OSMO_MSLOOKUP_MDNS_IP4, OSMO_MSLOOKUP_MDNS_PORT);
183}
184
185void dgsm_start(void *ctx)
186{
187 g_hlr->mslookup.client.client = osmo_mslookup_client_new(dgsm_ctx);
188 OSMO_ASSERT(g_hlr->mslookup.client.client);
189 g_hlr->mslookup.allow_startup = true;
190 mslookup_server_mdns_config_apply();
191 dgsm_mdns_client_config_apply();
192}
193
Harald Welte7a476532022-11-03 11:38:41 +0100194void dgsm_stop(void)
Neels Hofmeyr76328bd2019-11-20 03:35:37 +0100195{
196 g_hlr->mslookup.allow_startup = false;
197 mslookup_server_mdns_config_apply();
198 dgsm_mdns_client_config_apply();
199}
200
201void dgsm_mdns_client_config_apply(void)
202{
203 /* Check whether to start/stop/restart mDNS client */
204 const struct osmo_sockaddr_str *current_bind_addr;
205 const char *current_domain_suffix;
206 current_bind_addr = osmo_mslookup_client_method_mdns_get_bind_addr(g_hlr->mslookup.client.mdns.running);
207 current_domain_suffix = osmo_mslookup_client_method_mdns_get_domain_suffix(g_hlr->mslookup.client.mdns.running);
208
209 bool should_run = g_hlr->mslookup.allow_startup
210 && g_hlr->mslookup.client.enable && g_hlr->mslookup.client.mdns.enable;
211
212 bool should_stop = g_hlr->mslookup.client.mdns.running &&
213 (!should_run
214 || osmo_sockaddr_str_cmp(&g_hlr->mslookup.client.mdns.query_addr,
215 current_bind_addr)
216 || strcmp(g_hlr->mslookup.client.mdns.domain_suffix,
217 current_domain_suffix));
218
219 if (should_stop) {
220 osmo_mslookup_client_method_del(g_hlr->mslookup.client.client, g_hlr->mslookup.client.mdns.running);
221 g_hlr->mslookup.client.mdns.running = NULL;
222 LOGP(DDGSM, LOGL_NOTICE, "Stopped mslookup mDNS client\n");
223 }
224
225 if (should_run && !g_hlr->mslookup.client.mdns.running) {
226 g_hlr->mslookup.client.mdns.running =
227 osmo_mslookup_client_add_mdns(g_hlr->mslookup.client.client,
228 g_hlr->mslookup.client.mdns.query_addr.ip,
229 g_hlr->mslookup.client.mdns.query_addr.port,
230 -1,
231 g_hlr->mslookup.client.mdns.domain_suffix);
232 if (!g_hlr->mslookup.client.mdns.running)
233 LOGP(DDGSM, LOGL_ERROR, "Failed to start mslookup mDNS client with target "
234 OSMO_SOCKADDR_STR_FMT "\n",
235 OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.client.mdns.query_addr));
236 else
237 LOGP(DDGSM, LOGL_NOTICE, "Started mslookup mDNS client, sending mDNS requests to multicast "
238 OSMO_SOCKADDR_STR_FMT "\n",
239 OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.client.mdns.query_addr));
240 }
241
242 if (g_hlr->mslookup.client.enable && osmo_sockaddr_str_is_nonzero(&g_hlr->mslookup.client.gsup_gateway_proxy))
243 LOGP(DDGSM, LOGL_NOTICE,
244 "mslookup client: all GSUP requests for unknown IMSIs will be forwarded to"
245 " gateway-proxy " OSMO_SOCKADDR_STR_FMT "\n",
246 OSMO_SOCKADDR_STR_FMT_ARGS(&g_hlr->mslookup.client.gsup_gateway_proxy));
247}