summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2013-03-19 11:00:13 +0100
committerHarald Welte <laforge@gnumonks.org>2013-07-21 15:44:24 +0800
commit7f6da485f5af0ad5a5a5176c2fc3fe0550beac14 (patch)
treeb8182fc38ce459344c6f7dba8cc1a3e94c5fb1b7
parentcb5353d8511f7cd36472334402f7ac31dc26327b (diff)
sgsn: add a minimalistic ACL
This adds a minimalistic ACL by which certain, individual roaming IMSIs can be authorized to use the SGSN. So you can selectively bypass the 'MCC+MNC == first 5 digits of IMSI' checking for a couple of IMSIs
-rw-r--r--openbsc/include/openbsc/sgsn.h2
-rw-r--r--openbsc/src/gprs/gprs_gmm.c3
-rw-r--r--openbsc/src/gprs/sgsn_main.c1
-rw-r--r--openbsc/src/gprs/sgsn_vty.c80
4 files changed, 84 insertions, 2 deletions
diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h
index 48a7b3474..447bd2f1a 100644
--- a/openbsc/include/openbsc/sgsn.h
+++ b/openbsc/include/openbsc/sgsn.h
@@ -15,6 +15,8 @@ struct sgsn_config {
/* misc */
struct gprs_ns_inst *nsi;
+
+ struct llist_head imsi_acl;
};
struct sgsn_instance {
diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c
index bb61ab50a..36798e0ac 100644
--- a/openbsc/src/gprs/gprs_gmm.c
+++ b/openbsc/src/gprs/gprs_gmm.c
@@ -698,7 +698,8 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
* as long as it is part of 'our' network */
char mccmnc[16];
snprintf(mccmnc, sizeof(mccmnc), "%03d%02d", ra_id.mcc, ra_id.mnc);
- if (strncmp(mccmnc, mi_string, 5)) {
+ if (strncmp(mccmnc, mi_string, 5) &&
+ !sgsn_acl_lookup(mi_string)) {
LOGP(DMM, LOGL_INFO, "Rejecting ATTACH REQUESET IMSI=%s\n",
mi_string);
return gsm48_tx_gmm_att_rej_oldmsg(msg,
diff --git a/openbsc/src/gprs/sgsn_main.c b/openbsc/src/gprs/sgsn_main.c
index 08e0a85fa..9d42648a4 100644
--- a/openbsc/src/gprs/sgsn_main.c
+++ b/openbsc/src/gprs/sgsn_main.c
@@ -75,6 +75,7 @@ static struct sgsn_instance sgsn_inst = {
.config_file = "osmo_sgsn.cfg",
.cfg = {
.gtp_statedir = "./",
+ .acl_enabled = 1,
},
};
struct sgsn_instance *sgsn = &sgsn_inst;
diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c
index 9865fde0c..ce3b4da9e 100644
--- a/openbsc/src/gprs/sgsn_vty.c
+++ b/openbsc/src/gprs/sgsn_vty.c
@@ -1,5 +1,5 @@
/*
- * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010-2013 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by On-Waves
* All Rights Reserved
*
@@ -41,6 +41,10 @@
static struct sgsn_config *g_cfg = NULL;
+struct imsi_acl_entry {
+ struct llist_head list;
+ char imsi[16+1];
+};
#define GSM48_MAX_APN_LEN 102 /* 10.5.6.1 */
static char *gprs_apn2str(uint8_t *apn, unsigned int len)
@@ -113,6 +117,7 @@ static struct cmd_node sgsn_node = {
static int config_write_sgsn(struct vty *vty)
{
struct sgsn_ggsn_ctx *gctx;
+ struct imsi_acl_entry *acl;
vty_out(vty, "sgsn%s", VTY_NEWLINE);
@@ -126,6 +131,9 @@ static int config_write_sgsn(struct vty *vty)
gctx->gtp_version, VTY_NEWLINE);
}
+ llist_for_each_entry(acl, &g_cfg->imsi_acl, list)
+ vty_out(vty, " imsi-acl add %s%s", acl->imsi, VTY_NEWLINE);
+
return CMD_SUCCESS;
}
@@ -317,6 +325,73 @@ DEFUN(show_pdpctx_all, show_pdpctx_all_cmd,
return CMD_SUCCESS;
}
+/* temporary IMSI ACL hack */
+struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi)
+{
+ struct imsi_acl_entry *acl;
+ llist_for_each_entry(acl, &g_cfg->imsi_acl, list) {
+ if (!strcmp(imsi, acl->imsi))
+ return acl;
+ }
+ return NULL;
+}
+
+int sgsn_acl_add(const char *imsi)
+{
+ struct imsi_acl_entry *acl;
+
+ if (sgsn_acl_lookup(imsi))
+ return -EEXIST;
+
+ acl = talloc_zero(NULL, struct imsi_acl_entry);
+ if (!acl)
+ return -ENOMEM;
+ strncpy(acl->imsi, imsi, sizeof(acl->imsi));
+
+ llist_add(&acl->list, &g_cfg->imsi_acl);
+
+ return 0;
+}
+
+int sgsn_acl_del(const char *imsi)
+{
+ struct imsi_acl_entry *acl;
+
+ acl = sgsn_acl_lookup(imsi);
+ if (!acl)
+ return -ENODEV;
+
+ llist_del(&acl->list);
+ talloc_free(acl);
+
+ return 0;
+}
+
+
+DEFUN(imsi_acl, cfg_imsi_acl_cmd,
+ "imsi-acl (add|del) IMSI",
+ "Access Control List of foreign IMSIs\n"
+ "Add IMSI to ACL\n"
+ "Remove IMSI from ACL\n"
+ "IMSI of subscriber\n")
+{
+ const char *op = argv[0];
+ const char *imsi = argv[1];
+ int rc;
+
+ if (!strcmp(op, "add"))
+ rc = sgsn_acl_add(imsi);
+ else
+ rc = sgsn_acl_del(imsi);
+
+ if (rc < 0) {
+ vty_out(vty, "%% unable to %s ACL\n", op);
+ return CMD_WARNING;
+ }
+
+ return CMD_SUCCESS;
+}
+
int sgsn_vty_init(void)
{
install_element_ve(&show_sgsn_cmd);
@@ -334,6 +409,7 @@ int sgsn_vty_init(void)
install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd);
//install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd);
install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd);
+ install_element(SGSN_NODE, &cfg_imsi_acl_cmd);
return 0;
}
@@ -343,6 +419,8 @@ int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg)
int rc;
g_cfg = cfg;
+ INIT_LLIST_HEAD(&g_cfg->imsi_acl);
+
rc = vty_read_config_file(config_file, NULL);
if (rc < 0) {
fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);