blob: 970f2f62c294800ea96ab2422edf731b602dcac2 [file] [log] [blame]
Jacob Erlbeck9114bee2014-08-19 12:21:01 +02001/* Gb-proxy message patching */
2
3/* (C) 2014 by On-Waves
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21#include <openbsc/gb_proxy.h>
22
23#include <openbsc/gprs_utils.h>
24#include <openbsc/gprs_gb_parse.h>
25
Jacob Erlbeck9114bee2014-08-19 12:21:01 +020026#include <openbsc/gsm_04_08_gprs.h>
27#include <openbsc/debug.h>
28
29#include <osmocom/gprs/protocol/gsm_08_18.h>
30#include <osmocom/core/rate_ctr.h>
31
32/* check whether patching is enabled at this level */
33static int patching_is_enabled(struct gbproxy_peer *peer,
34 enum gbproxy_patch_mode need_at_least)
35{
36 enum gbproxy_patch_mode patch_mode = peer->cfg->patch_mode;
37 if (patch_mode == GBPROX_PATCH_DEFAULT)
38 patch_mode = GBPROX_PATCH_LLC;
39
40 return need_at_least <= patch_mode;
41}
42
43/* check whether patching is enabled at this level */
44static int patching_is_required(struct gbproxy_peer *peer,
45 enum gbproxy_patch_mode need_at_least)
46{
47 return need_at_least <= peer->cfg->patch_mode;
48}
49
50static int allow_message_patching(struct gbproxy_peer *peer, int msg_type)
51{
52 if (msg_type >= GSM48_MT_GSM_ACT_PDP_REQ) {
53 return patching_is_enabled(peer, GBPROX_PATCH_LLC_GSM);
54 } else if (msg_type > GSM48_MT_GMM_ATTACH_REJ) {
55 return patching_is_enabled(peer, GBPROX_PATCH_LLC);
56 } else if (msg_type > GSM48_MT_GMM_ATTACH_REQ) {
57 return patching_is_enabled(peer, GBPROX_PATCH_LLC_ATTACH);
58 } else {
59 return patching_is_enabled(peer, GBPROX_PATCH_LLC_ATTACH_REQ);
60 }
61}
62
63/* patch RA identifier in place */
64static void gbproxy_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer,
65 int to_bss, const char *log_text)
66{
67 struct gbproxy_patch_state *state = &peer->patch_state;
68 int old_mcc;
69 int old_mnc;
70 struct gprs_ra_id raid;
71
72 gsm48_parse_ra(&raid, raid_enc);
73
74 old_mcc = raid.mcc;
75 old_mnc = raid.mnc;
76
77 if (!to_bss) {
78 /* BSS -> SGSN */
79 if (state->local_mcc)
80 raid.mcc = peer->cfg->core_mcc;
81
82 if (state->local_mnc)
83 raid.mnc = peer->cfg->core_mnc;
84 } else {
85 /* SGSN -> BSS */
86 if (state->local_mcc)
87 raid.mcc = state->local_mcc;
88
89 if (state->local_mnc)
90 raid.mnc = state->local_mnc;
91 }
92
93 if (state->local_mcc || state->local_mnc) {
94 enum gbproxy_peer_ctr counter =
95 to_bss ?
96 GBPROX_PEER_CTR_RAID_PATCHED_SGSN :
97 GBPROX_PEER_CTR_RAID_PATCHED_BSS;
98
99 LOGP(DGPRS, LOGL_DEBUG,
100 "Patching %s to %s: "
101 "%d-%d-%d-%d -> %d-%d-%d-%d\n",
102 log_text,
103 to_bss ? "BSS" : "SGSN",
104 old_mcc, old_mnc, raid.lac, raid.rac,
105 raid.mcc, raid.mnc, raid.lac, raid.rac);
106
107 gsm48_construct_ra(raid_enc, &raid);
108 rate_ctr_inc(&peer->ctrg->ctr[counter]);
109 }
110}
111
112static void gbproxy_patch_apn_ie(struct msgb *msg,
113 uint8_t *apn_ie, size_t apn_ie_len,
114 struct gbproxy_peer *peer,
115 size_t *new_apn_ie_len, const char *log_text)
116{
117 struct apn_ie_hdr {
118 uint8_t iei;
119 uint8_t apn_len;
120 uint8_t apn[0];
121 } *hdr = (void *)apn_ie;
122
123 size_t apn_len = hdr->apn_len;
124 uint8_t *apn = hdr->apn;
125
126 OSMO_ASSERT(apn_ie_len == apn_len + sizeof(struct apn_ie_hdr));
127 OSMO_ASSERT(apn_ie_len > 2 && apn_ie_len <= 102);
128
129 if (peer->cfg->core_apn_size == 0) {
130 char str1[110];
131 /* Remove the IE */
132 LOGP(DGPRS, LOGL_DEBUG,
133 "Patching %s to SGSN: Removing APN '%s'\n",
134 log_text,
135 gprs_apn_to_str(str1, apn, apn_len));
136
137 *new_apn_ie_len = 0;
138 gprs_msgb_resize_area(msg, apn_ie, apn_ie_len, 0);
139 } else {
140 /* Resize the IE */
141 char str1[110];
142 char str2[110];
143
144 OSMO_ASSERT(peer->cfg->core_apn_size <= 100);
145
146 LOGP(DGPRS, LOGL_DEBUG,
147 "Patching %s to SGSN: "
148 "Replacing APN '%s' -> '%s'\n",
149 log_text,
150 gprs_apn_to_str(str1, apn, apn_len),
151 gprs_apn_to_str(str2, peer->cfg->core_apn,
152 peer->cfg->core_apn_size));
153
154 *new_apn_ie_len = peer->cfg->core_apn_size + 2;
155 gprs_msgb_resize_area(msg, apn, apn_len, peer->cfg->core_apn_size);
156 memcpy(apn, peer->cfg->core_apn, peer->cfg->core_apn_size);
157 hdr->apn_len = peer->cfg->core_apn_size;
158 }
159
160 rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]);
161}
162
163static int gbproxy_patch_tlli(uint8_t *tlli_enc,
164 struct gbproxy_peer *peer,
165 uint32_t new_tlli,
166 int to_bss, const char *log_text)
167{
168 uint32_t tlli_be;
169 uint32_t tlli;
170 enum gbproxy_peer_ctr counter =
171 to_bss ?
172 GBPROX_PEER_CTR_TLLI_PATCHED_SGSN :
173 GBPROX_PEER_CTR_TLLI_PATCHED_BSS;
174
175 memcpy(&tlli_be, tlli_enc, sizeof(tlli_be));
176 tlli = ntohl(tlli_be);
177
178 if (tlli == new_tlli)
179 return 0;
180
181 LOGP(DGPRS, LOGL_DEBUG,
182 "Patching %ss: "
183 "Replacing %08x -> %08x\n",
184 log_text, tlli, new_tlli);
185
186 tlli_be = htonl(new_tlli);
187 memcpy(tlli_enc, &tlli_be, sizeof(tlli_be));
188
189 rate_ctr_inc(&peer->ctrg->ctr[counter]);
190
191 return 1;
192}
193
194static int gbproxy_patch_ptmsi(uint8_t *ptmsi_enc,
195 struct gbproxy_peer *peer,
196 uint32_t new_ptmsi,
197 int to_bss, const char *log_text)
198{
199 uint32_t ptmsi_be;
200 uint32_t ptmsi;
201 enum gbproxy_peer_ctr counter =
202 to_bss ?
203 GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN :
204 GBPROX_PEER_CTR_PTMSI_PATCHED_BSS;
205 memcpy(&ptmsi_be, ptmsi_enc + 1, sizeof(ptmsi_be));
206 ptmsi = ntohl(ptmsi_be);
207
208 if (ptmsi == new_ptmsi)
209 return 0;
210
211 LOGP(DGPRS, LOGL_DEBUG,
212 "Patching %ss: "
213 "Replacing %08x -> %08x\n",
214 log_text, ptmsi, new_ptmsi);
215
216 ptmsi_be = htonl(new_ptmsi);
217 memcpy(ptmsi_enc + 1, &ptmsi_be, sizeof(ptmsi_be));
218
219 rate_ctr_inc(&peer->ctrg->ctr[counter]);
220
221 return 1;
222}
223
224int gbproxy_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
225 struct gbproxy_peer *peer,
226 struct gbproxy_tlli_info *tlli_info, int *len_change,
227 struct gprs_gb_parse_context *parse_ctx)
228{
229 struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
230 int have_patched = 0;
231 int fcs;
232
233 if (parse_ctx->g48_hdr && !allow_message_patching(peer, parse_ctx->g48_hdr->msg_type))
234 return have_patched;
235
236 if (parse_ctx->ptmsi_enc && tlli_info) {
237 uint32_t ptmsi;
238 if (parse_ctx->to_bss)
239 ptmsi = tlli_info->tlli.ptmsi;
240 else
241 ptmsi = tlli_info->sgsn_tlli.ptmsi;
242
243 if (ptmsi != GSM_RESERVED_TMSI) {
244 if (gbproxy_patch_ptmsi(parse_ctx->ptmsi_enc, peer,
245 ptmsi, parse_ctx->to_bss, "P-TMSI"))
246 have_patched = 1;
247 } else {
248 /* TODO: invalidate old RAI if present (see below) */
249 }
250 }
251
252 if (parse_ctx->new_ptmsi_enc && tlli_info) {
253 uint32_t ptmsi;
254 if (parse_ctx->to_bss)
255 ptmsi = tlli_info->tlli.ptmsi;
256 else
257 ptmsi = tlli_info->sgsn_tlli.ptmsi;
258
259 OSMO_ASSERT(ptmsi);
260 if (gbproxy_patch_ptmsi(parse_ctx->new_ptmsi_enc, peer,
261 ptmsi, parse_ctx->to_bss, "new P-TMSI"))
262 have_patched = 1;
263 }
264
265 if (parse_ctx->raid_enc) {
266 gbproxy_patch_raid(parse_ctx->raid_enc, peer, parse_ctx->to_bss,
267 parse_ctx->llc_msg_name);
268 have_patched = 1;
269 }
270
271 if (parse_ctx->old_raid_enc && parse_ctx->old_raid_matches) {
272 /* TODO: Patch to invalid if P-TMSI unknown. */
273 gbproxy_patch_raid(parse_ctx->old_raid_enc, peer, parse_ctx->to_bss,
274 parse_ctx->llc_msg_name);
275 have_patched = 1;
276 }
277
278 if (parse_ctx->apn_ie &&
279 peer->cfg->core_apn &&
280 !parse_ctx->to_bss &&
Jacob Erlbeck18a37872014-09-08 09:59:16 +0200281 gbproxy_check_tlli(peer, tlli_info)) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200282 size_t new_len;
283 gbproxy_patch_apn_ie(msg,
284 parse_ctx->apn_ie, parse_ctx->apn_ie_len,
285 peer, &new_len, parse_ctx->llc_msg_name);
286 *len_change += (int)new_len - (int)parse_ctx->apn_ie_len;
287
288 have_patched = 1;
289 }
290
291 if (have_patched) {
292 llc_len += *len_change;
293 ghp->crc_length += *len_change;
294
295 /* Fix FCS */
296 fcs = gprs_llc_fcs(llc, ghp->crc_length);
297 LOGP(DLLC, LOGL_DEBUG, "Updated LLC message, CRC: %06x -> %06x\n",
298 ghp->fcs, fcs);
299
300 llc[llc_len - 3] = fcs & 0xff;
301 llc[llc_len - 2] = (fcs >> 8) & 0xff;
302 llc[llc_len - 1] = (fcs >> 16) & 0xff;
303 }
304
305 return have_patched;
306}
307
308/* patch BSSGP message to use core_mcc/mnc on the SGSN side */
309void gbproxy_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
310 struct gbproxy_peer *peer,
311 struct gbproxy_tlli_info *tlli_info, int *len_change,
312 struct gprs_gb_parse_context *parse_ctx)
313{
314 const char *err_info = NULL;
315 int err_ctr = -1;
316
317 if (!patching_is_enabled(peer, GBPROX_PATCH_BSSGP))
318 return;
319
320 if (parse_ctx->bssgp_raid_enc)
321 gbproxy_patch_raid(parse_ctx->bssgp_raid_enc, peer,
322 parse_ctx->to_bss, "BSSGP");
323
324 if (!patching_is_enabled(peer, GBPROX_PATCH_LLC_ATTACH_REQ))
325 return;
326
327 if (parse_ctx->need_decryption &&
328 patching_is_required(peer, GBPROX_PATCH_LLC_ATTACH)) {
329 /* Patching LLC messages has been requested
330 * explicitly, but the message (including the
331 * type) is encrypted, so we possibly fail to
332 * patch the LLC part of the message. */
333 err_ctr = GBPROX_PEER_CTR_PATCH_CRYPT_ERR;
334 err_info = "GMM message is encrypted";
335 goto patch_error;
336 }
337
Jacob Erlbeck37fda772014-09-05 10:22:27 +0200338 if (!tlli_info && parse_ctx->tlli_enc && parse_ctx->to_bss) {
339 /* Happens with unknown (not cached) TLLI coming from
340 * the SGSN */
341 /* TODO: What shall be done with the message in this case? */
342 err_ctr = GBPROX_PEER_CTR_TLLI_UNKNOWN;
343 err_info = "TLLI sent by the SGSN is unknown";
344 goto patch_error;
345 }
346
Jacob Erlbeckecbd56c2014-08-26 10:01:57 +0200347 if (!tlli_info)
348 return;
349
350 if (parse_ctx->tlli_enc) {
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200351 uint32_t tlli = gbproxy_map_tlli(parse_ctx->tlli,
352 tlli_info, parse_ctx->to_bss);
353
354 if (tlli) {
355 gbproxy_patch_tlli(parse_ctx->tlli_enc, peer, tlli,
356 parse_ctx->to_bss, "TLLI");
357 parse_ctx->tlli = tlli;
Jacob Erlbeck9114bee2014-08-19 12:21:01 +0200358 } else {
359 /* Internal error */
360 err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
361 err_info = "Replacement TLLI is 0";
362 goto patch_error;
363 }
364 }
365
366 if (parse_ctx->llc) {
367 uint8_t *llc = parse_ctx->llc;
368 size_t llc_len = parse_ctx->llc_len;
369 int llc_len_change = 0;
370
371 gbproxy_patch_llc(msg, llc, llc_len, peer, tlli_info,
372 &llc_len_change, parse_ctx);
373 /* Note that the APN might have been resized here, but no
374 * pointer int the parse_ctx will refer to an adress after the
375 * APN. So it's possible to patch first and do the TLLI
376 * handling afterwards. */
377
378 if (llc_len_change) {
379 llc_len += llc_len_change;
380
381 /* Fix LLC IE len */
382 /* TODO: This is a kludge, but the a pointer to the
383 * start of the IE is not available here */
384 if (llc[-2] == BSSGP_IE_LLC_PDU && llc[-1] & 0x80) {
385 /* most probably a one byte length */
386 if (llc_len > 127) {
387 err_info = "Cannot increase size";
388 err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
389 goto patch_error;
390 }
391 llc[-1] = llc_len | 0x80;
392 } else {
393 llc[-2] = (llc_len >> 8) & 0x7f;
394 llc[-1] = llc_len & 0xff;
395 }
396 *len_change += llc_len_change;
397 }
398 /* Note that the tp struct might contain invalid pointers here
399 * if the LLC field has changed its size */
400 parse_ctx->llc_len = llc_len;
401 }
402 return;
403
404patch_error:
405 OSMO_ASSERT(err_ctr >= 0);
406 rate_ctr_inc(&peer->ctrg->ctr[err_ctr]);
407 LOGP(DGPRS, LOGL_ERROR,
408 "NSEI=%u(%s) failed to patch BSSGP message as requested: %s.\n",
409 msgb_nsei(msg), parse_ctx->to_bss ? "SGSN" : "BSS",
410 err_info);
411}
412
413void gbproxy_clear_patch_filter(struct gbproxy_config *cfg)
414{
415 if (cfg->check_imsi) {
416 regfree(&cfg->imsi_re_comp);
417 cfg->check_imsi = 0;
418 }
419}
420
421int gbproxy_set_patch_filter(struct gbproxy_config *cfg, const char *filter,
422 const char **err_msg)
423{
424 static char err_buf[300];
425 int rc;
426
427 gbproxy_clear_patch_filter(cfg);
428
429 if (!filter)
430 return 0;
431
432 rc = regcomp(&cfg->imsi_re_comp, filter,
433 REG_EXTENDED | REG_NOSUB | REG_ICASE);
434
435 if (rc == 0) {
436 cfg->check_imsi = 1;
437 return 0;
438 }
439
440 if (err_msg) {
441 regerror(rc, &cfg->imsi_re_comp,
442 err_buf, sizeof(err_buf));
443 *err_msg = err_buf;
444 }
445
446 return -1;
447}
448
449int gbproxy_check_imsi(struct gbproxy_peer *peer,
450 const uint8_t *imsi, size_t imsi_len)
451{
452 char mi_buf[200];
453 int rc;
454
455 if (!peer->cfg->check_imsi)
456 return 1;
457
458 rc = gprs_is_mi_imsi(imsi, imsi_len);
459 if (rc > 0)
460 rc = gsm48_mi_to_string(mi_buf, sizeof(mi_buf), imsi, imsi_len);
461 if (rc <= 0) {
462 LOGP(DGPRS, LOGL_NOTICE, "Invalid IMSI %s\n",
463 osmo_hexdump(imsi, imsi_len));
464 return -1;
465 }
466
467 LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi_buf, rc);
468
469 rc = regexec(&peer->cfg->imsi_re_comp, mi_buf, 0, NULL, 0);
470 if (rc == REG_NOMATCH) {
471 LOGP(DGPRS, LOGL_INFO,
472 "IMSI '%s' doesn't match pattern '%s'\n",
473 mi_buf, peer->cfg->match_re);
474 return 0;
475 }
476
477 return 1;
478}
479