diff options
author | Harald Welte <laforge@gnumonks.org> | 2013-03-19 11:00:13 +0100 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2013-07-21 15:44:24 +0800 |
commit | 7f6da485f5af0ad5a5a5176c2fc3fe0550beac14 (patch) | |
tree | b8182fc38ce459344c6f7dba8cc1a3e94c5fb1b7 | |
parent | cb5353d8511f7cd36472334402f7ac31dc26327b (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.h | 2 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_gmm.c | 3 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_main.c | 1 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_vty.c | 80 |
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); |