From 74dc3031347fa894bd2490512b8abeb44ecee961 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 29 Sep 2010 02:47:29 +0800 Subject: nat: Introduce a new connection type for Supplementary Services If we have a CM Service Request we will look into the message to see if it is a Supplementary Service Activation. --- openbsc/include/openbsc/bsc_nat.h | 2 ++ openbsc/src/nat/bsc_nat_utils.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index b6d040433..a364c17d7 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -49,6 +49,7 @@ enum { NAT_CON_TYPE_LU, NAT_CON_TYPE_CM_SERV_REQ, NAT_CON_TYPE_PAG_RESP, + NAT_CON_TYPE_SSA, NAT_CON_TYPE_LOCAL_REJECT, NAT_CON_TYPE_OTHER, }; @@ -102,6 +103,7 @@ enum bsc_cfg_ctr { BCFG_CTR_CON_TYPE_LU, BCFG_CTR_CON_CMSERV_RQ, BCFG_CTR_CON_PAG_RESP, + BCFG_CTR_CON_SSA, BCFG_CTR_CON_OTHER, }; diff --git a/openbsc/src/nat/bsc_nat_utils.c b/openbsc/src/nat/bsc_nat_utils.c index dc18cffec..f88e76697 100644 --- a/openbsc/src/nat/bsc_nat_utils.c +++ b/openbsc/src/nat/bsc_nat_utils.c @@ -54,6 +54,7 @@ static const struct rate_ctr_desc bsc_cfg_ctr_description[] = { [BCFG_CTR_CON_TYPE_LU] = { "conn.lu", "Conn Location Update "}, [BCFG_CTR_CON_CMSERV_RQ] = { "conn.rq", "Conn CM Service Req "}, [BCFG_CTR_CON_PAG_RESP] = { "conn.pag", "Conn Paging Response "}, + [BCFG_CTR_CON_SSA] = { "conn.ssa", "Conn USSD "}, [BCFG_CTR_CON_OTHER] = { "conn.other", "Conn Other "}, }; @@ -391,7 +392,7 @@ static int _cr_check_loc_upd(struct bsc_connection *bsc, static int _cr_check_cm_serv_req(struct bsc_connection *bsc, uint8_t *data, unsigned int length, - char **imsi) + int *con_type, char **imsi) { static const uint32_t classmark_offset = offsetof(struct gsm48_service_request, classmark); @@ -410,6 +411,8 @@ static int _cr_check_cm_serv_req(struct bsc_connection *bsc, } req = (struct gsm48_service_request *) data; + if (req->cm_service_type == 0x8) + *con_type = NAT_CON_TYPE_SSA; rc = gsm48_extract_mi((uint8_t *) &req->classmark, length - classmark_offset, mi_string, &mi_type); if (rc < 0) { @@ -537,7 +540,9 @@ int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, } else if (hdr48->proto_discr == GSM48_PDISC_MM && msg_type == GSM48_MT_MM_CM_SERV_REQ) { *con_type = NAT_CON_TYPE_CM_SERV_REQ; - return _cr_check_cm_serv_req(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48), imsi); + return _cr_check_cm_serv_req(bsc, &hdr48->data[0], + hdr48_len - sizeof(*hdr48), + con_type, imsi); } else if (hdr48->proto_discr == GSM48_PDISC_RR && msg_type == GSM48_MT_RR_PAG_RESP) { *con_type = NAT_CON_TYPE_PAG_RESP; @@ -614,6 +619,7 @@ static const char *con_types [] = { [NAT_CON_TYPE_LU] = "Location Update", [NAT_CON_TYPE_CM_SERV_REQ] = "CM Serv Req", [NAT_CON_TYPE_PAG_RESP] = "Paging Response", + [NAT_CON_TYPE_SSA] = "Supplementar Service Activation", [NAT_CON_TYPE_LOCAL_REJECT] = "Local Reject", [NAT_CON_TYPE_OTHER] = "Other", }; @@ -693,6 +699,7 @@ static const int con_to_ctr[] = { [NAT_CON_TYPE_LU] = BCFG_CTR_CON_TYPE_LU, [NAT_CON_TYPE_CM_SERV_REQ] = BCFG_CTR_CON_CMSERV_RQ, [NAT_CON_TYPE_PAG_RESP] = BCFG_CTR_CON_PAG_RESP, + [NAT_CON_TYPE_SSA] = BCFG_CTR_CON_SSA, [NAT_CON_TYPE_LOCAL_REJECT] = -1, [NAT_CON_TYPE_OTHER] = BCFG_CTR_CON_OTHER, }; -- cgit v1.2.3 From 17870cf5333736f6829e0add942df5b26382d97e Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 29 Sep 2010 19:32:55 +0800 Subject: nat: Create a USSD module to filter out USSDs... --- openbsc/include/openbsc/bsc_nat.h | 3 +++ openbsc/src/nat/Makefile.am | 2 +- openbsc/src/nat/bsc_nat.c | 7 +++++++ openbsc/src/nat/bsc_ussd.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 openbsc/src/nat/bsc_ussd.c diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index a364c17d7..baa950ccb 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -320,4 +320,7 @@ int bsc_conn_type_to_ctr(struct sccp_connections *conn); struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed, struct msgb *msg, uint32_t *len); +/** USSD filtering */ +int bsc_check_ussd(struct sccp_connections *con, struct bsc_nat_parsed *parsed, struct msgb *msg); + #endif diff --git a/openbsc/src/nat/Makefile.am b/openbsc/src/nat/Makefile.am index 2f37f5cd2..c7c4b0e9f 100644 --- a/openbsc/src/nat/Makefile.am +++ b/openbsc/src/nat/Makefile.am @@ -6,7 +6,7 @@ bin_PROGRAMS = bsc_nat bsc_nat_SOURCES = bsc_filter.c bsc_mgcp_utils.c bsc_nat.c bsc_nat_utils.c \ - bsc_nat_vty.c bsc_sccp.c \ + bsc_nat_vty.c bsc_sccp.c bsc_ussd.c \ $(top_srcdir)/src/debug.c $(top_srcdir)/src/bsc_msc.c bsc_nat_LDADD = $(top_builddir)/src/libvty.a \ $(top_builddir)/src/libmgcp.a $(top_builddir)/src/libbsc.a \ diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c index b82c4ef25..515278cba 100644 --- a/openbsc/src/nat/bsc_nat.c +++ b/openbsc/src/nat/bsc_nat.c @@ -854,12 +854,19 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) con = NULL; goto exit2; } + + /* hand data to a side channel */ + if (bsc_check_ussd(con, parsed, msg) == 1) { + /* we are going to take over the connection */ + /* TODO: */ + } } con_bsc = con->bsc; con_msc = con->msc_con; con_filter = con->con_local; } + break; case SCCP_MSG_TYPE_RLC: con = patch_sccp_src_ref_to_msc(msg, parsed, bsc); diff --git a/openbsc/src/nat/bsc_ussd.c b/openbsc/src/nat/bsc_ussd.c new file mode 100644 index 000000000..1812cf71d --- /dev/null +++ b/openbsc/src/nat/bsc_ussd.c @@ -0,0 +1,32 @@ +/* USSD Filter Code */ + +/* + * (C) 2010 by Holger Hans Peter Freyther + * (C) 2010 by On-Waves + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include + + +int bsc_check_ussd(struct sccp_connections *con, struct bsc_nat_parsed *parsed, + struct msgb *msg) +{ + return 0; +} -- cgit v1.2.3 From d1effd835fb8ca5df7d32db0eeee82c1939e1ab9 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sun, 10 Oct 2010 17:29:20 +0200 Subject: nat: Provide a USSD access list to check for which to play HLR. --- openbsc/include/openbsc/bsc_nat.h | 3 +++ openbsc/src/nat/bsc_nat_vty.c | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index baa950ccb..678f1895f 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -232,6 +232,9 @@ struct bsc_nat { /* filter */ char *acc_lst_name; + /* USSD messages we want to match */ + char *ussd_lst_name; + /* statistics */ struct bsc_nat_statistics stats; }; diff --git a/openbsc/src/nat/bsc_nat_vty.c b/openbsc/src/nat/bsc_nat_vty.c index 9822e5c57..de58bba07 100644 --- a/openbsc/src/nat/bsc_nat_vty.c +++ b/openbsc/src/nat/bsc_nat_vty.c @@ -78,6 +78,8 @@ static int config_write_nat(struct vty *vty) vty_out(vty, " ip-dscp %d%s", _nat->bsc_ip_dscp, VTY_NEWLINE); if (_nat->acc_lst_name) vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE); + if (_nat->ussd_lst_name) + vty_out(vty, " ussd-list-name %s%s", _nat->ussd_lst_name, VTY_NEWLINE); llist_for_each_entry(lst, &_nat->access_lists, list) { write_acc_lst(vty, lst); @@ -395,6 +397,18 @@ DEFUN(cfg_nat_acc_lst_name, return CMD_SUCCESS; } +DEFUN(cfg_nat_ussd_lst_name, + cfg_nat_ussd_lst_name_cmd, + "ussd-list-name NAME", + "Set the name of the access list to check for IMSIs for USSD message\n" + "The name of the access list for HLR USSD handling") +{ + if (_nat->ussd_lst_name) + talloc_free(_nat->ussd_lst_name); + _nat->ussd_lst_name = talloc_strdup(_nat, argv[0]); + return CMD_SUCCESS; +} + /* per BSC configuration */ DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "Select a BSC to configure") { @@ -632,6 +646,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat) install_element(NAT_NODE, &cfg_nat_bsc_ip_dscp_cmd); install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd); install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd); + install_element(NAT_NODE, &cfg_nat_ussd_lst_name_cmd); /* access-list */ install_element(NAT_NODE, &cfg_lst_imsi_allow_cmd); -- cgit v1.2.3 From c1cac1e31ac89ce533fea50eb1150b29ad260c8c Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 11 Oct 2010 09:50:31 +0200 Subject: nat: Make the imsi checking function public. We will use this method in the USSD module to check if the IMSI should be handled for USSD queries. --- openbsc/include/openbsc/bsc_nat.h | 1 + openbsc/src/nat/bsc_nat_utils.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index 678f1895f..e8a47525c 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -316,6 +316,7 @@ struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *nam void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst); struct bsc_nat_acc_lst_entry *bsc_nat_acc_lst_entry_create(struct bsc_nat_acc_lst *); +int bsc_nat_lst_check_allow(struct bsc_nat_acc_lst *lst, const char *imsi); int bsc_nat_msc_is_connected(struct bsc_nat *nat); diff --git a/openbsc/src/nat/bsc_nat_utils.c b/openbsc/src/nat/bsc_nat_utils.c index f88e76697..2fca31dcb 100644 --- a/openbsc/src/nat/bsc_nat_utils.c +++ b/openbsc/src/nat/bsc_nat_utils.c @@ -288,7 +288,7 @@ int bsc_write_msg(struct write_queue *queue, struct msgb *msg) return 0; } -static int lst_check_allow(struct bsc_nat_acc_lst *lst, const char *mi_string) +int bsc_nat_lst_check_allow(struct bsc_nat_acc_lst *lst, const char *mi_string) { struct bsc_nat_acc_lst_entry *entry; @@ -335,7 +335,7 @@ static int auth_imsi(struct bsc_connection *bsc, const char *mi_string) if (bsc_lst) { /* 1. BSC allow */ - if (lst_check_allow(bsc_lst, mi_string) == 0) + if (bsc_nat_lst_check_allow(bsc_lst, mi_string) == 0) return 1; /* 2. BSC deny */ -- cgit v1.2.3 From c1578bc74702ac879b7fbf6cab868770f268e3cd Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 11 Oct 2010 10:06:39 +0200 Subject: nat: Add an option to set the query string to match Allow the query string to be set. The ussd matching code will check for this string and then forward it to the bypass. --- openbsc/include/openbsc/bsc_nat.h | 1 + openbsc/src/nat/bsc_nat_vty.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index e8a47525c..61f19f27e 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -234,6 +234,7 @@ struct bsc_nat { /* USSD messages we want to match */ char *ussd_lst_name; + char *ussd_query; /* statistics */ struct bsc_nat_statistics stats; diff --git a/openbsc/src/nat/bsc_nat_vty.c b/openbsc/src/nat/bsc_nat_vty.c index de58bba07..940ebfdf2 100644 --- a/openbsc/src/nat/bsc_nat_vty.c +++ b/openbsc/src/nat/bsc_nat_vty.c @@ -80,6 +80,8 @@ static int config_write_nat(struct vty *vty) vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE); if (_nat->ussd_lst_name) vty_out(vty, " ussd-list-name %s%s", _nat->ussd_lst_name, VTY_NEWLINE); + if (_nat->ussd_query) + vty_out(vty, " ussd-query %s%s", _nat->ussd_query, VTY_NEWLINE); llist_for_each_entry(lst, &_nat->access_lists, list) { write_acc_lst(vty, lst); @@ -409,6 +411,18 @@ DEFUN(cfg_nat_ussd_lst_name, return CMD_SUCCESS; } +DEFUN(cfg_nat_ussd_query, + cfg_nat_ussd_query_cmd, + "ussd-query QUERY", + "Set the USSD query to match with the ussd-list-name\n" + "The query to match") +{ + if (_nat->ussd_query) + talloc_free(_nat->ussd_query); + _nat->ussd_query = talloc_strdup(_nat, argv[0]); + return CMD_SUCCESS; +} + /* per BSC configuration */ DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "Select a BSC to configure") { @@ -647,6 +661,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat) install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd); install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd); install_element(NAT_NODE, &cfg_nat_ussd_lst_name_cmd); + install_element(NAT_NODE, &cfg_nat_ussd_query_cmd); /* access-list */ install_element(NAT_NODE, &cfg_lst_imsi_allow_cmd); -- cgit v1.2.3 From 3229f442f46480551479b987f2f6a1b5c360e4d6 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 11 Oct 2010 10:07:37 +0200 Subject: nat: Implement the matching of certain USSD messages Have various checks, check if the IMSI should be handled, if there is a USSD query set and then decode and compare the value. --- openbsc/src/nat/bsc_ussd.c | 64 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/openbsc/src/nat/bsc_ussd.c b/openbsc/src/nat/bsc_ussd.c index 1812cf71d..c4e30d842 100644 --- a/openbsc/src/nat/bsc_ussd.c +++ b/openbsc/src/nat/bsc_ussd.c @@ -24,9 +24,71 @@ #include #include +#include + +#include + +#include + int bsc_check_ussd(struct sccp_connections *con, struct bsc_nat_parsed *parsed, struct msgb *msg) { - return 0; + uint32_t len; + uint8_t msg_type; + struct gsm48_hdr *hdr48; + struct bsc_nat_acc_lst *lst; + struct ussd_request req; + + /* + * various checks to avoid the decoding work. Right now we only want to + * decode if the connection was created for USSD, we do have a USSD access + * list, a query, a IMSI and such... + */ + if (con->con_type != NAT_CON_TYPE_SSA) + return 0; + + if (!con->imsi) + return 0; + + if (!con->bsc->nat->ussd_lst_name) + return 0; + if (!con->bsc->nat->ussd_query) + return 0; + + if (parsed->bssap != BSSAP_MSG_DTAP) + return 0; + + if (strlen(con->imsi) > GSM_IMSI_LENGTH) + return 0; + + hdr48 = bsc_unpack_dtap(parsed, msg, &len); + if (!hdr48) + return 0; + + msg_type = hdr48->msg_type & 0xbf; + if (hdr48->proto_discr != GSM48_PDISC_NC_SS || msg_type != GSM0480_MTYPE_REGISTER) + return 0; + + /* now check if it is a IMSI we care about */ + lst = bsc_nat_acc_lst_find(con->bsc->nat, con->bsc->nat->ussd_lst_name); + if (!lst) + return 0; + + if (bsc_nat_lst_check_allow(lst, con->imsi) != 0) + return 0; + + /* now decode the message and see if we really want to handle it */ + memset(&req, 0, sizeof(req)); + if (gsm0480_decode_ussd_request(hdr48, len, &req) != 1) + return 0; + if (req.text[0] == 0xff) + return 0; + + if (strcmp(req.text, con->bsc->nat->ussd_query) != 0) + return 0; + + /* found a USSD query for our subscriber */ + LOGP(DNAT, LOGL_NOTICE, "Found USSD query for %s\n", con->imsi); + return 1; } -- cgit v1.2.3 From e393f273e7c65edea09b12385ca648724c9c3825 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 12 Oct 2010 18:25:52 +0200 Subject: nat: Keep a ussd token in the config We will have the USSD provider connecting to us and we will use the IPA protocol, including the auth mechanism. --- openbsc/include/openbsc/bsc_nat.h | 2 ++ openbsc/src/nat/bsc_nat_vty.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index 61f19f27e..f718766a1 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -235,6 +235,8 @@ struct bsc_nat { /* USSD messages we want to match */ char *ussd_lst_name; char *ussd_query; + char *ussd_token; + char *ussd_local; /* statistics */ struct bsc_nat_statistics stats; diff --git a/openbsc/src/nat/bsc_nat_vty.c b/openbsc/src/nat/bsc_nat_vty.c index 940ebfdf2..b284fedd5 100644 --- a/openbsc/src/nat/bsc_nat_vty.c +++ b/openbsc/src/nat/bsc_nat_vty.c @@ -82,6 +82,10 @@ static int config_write_nat(struct vty *vty) vty_out(vty, " ussd-list-name %s%s", _nat->ussd_lst_name, VTY_NEWLINE); if (_nat->ussd_query) vty_out(vty, " ussd-query %s%s", _nat->ussd_query, VTY_NEWLINE); + if (_nat->ussd_token) + vty_out(vty, " ussd-token %s%s", _nat->ussd_token, VTY_NEWLINE); + if (_nat->ussd_local) + vty_out(vty, " ussd-local-ip %s%s", _nat->ussd_local, VTY_NEWLINE); llist_for_each_entry(lst, &_nat->access_lists, list) { write_acc_lst(vty, lst); @@ -423,6 +427,28 @@ DEFUN(cfg_nat_ussd_query, return CMD_SUCCESS; } +DEFUN(cfg_nat_ussd_token, + cfg_nat_ussd_token_cmd, + "ussd-token TOKEN", + "Set the token used to identify the USSD module\n" "Secret key\n") +{ + if (_nat->ussd_token) + talloc_free(_nat->ussd_token); + _nat->ussd_token = talloc_strdup(_nat, argv[0]); + return CMD_SUCCESS; +} + +DEFUN(cfg_nat_ussd_local, + cfg_nat_ussd_local_cmd, + "ussd-local-ip A.B.C.D", + "Set the IP to listen for the USSD Provider\n" "IP Address\n") +{ + if (_nat->ussd_local) + talloc_free(_nat->ussd_local); + _nat->ussd_local = talloc_strdup(_nat, argv[0]); + return CMD_SUCCESS; +} + /* per BSC configuration */ DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "Select a BSC to configure") { @@ -662,6 +688,8 @@ int bsc_nat_vty_init(struct bsc_nat *nat) install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd); install_element(NAT_NODE, &cfg_nat_ussd_lst_name_cmd); install_element(NAT_NODE, &cfg_nat_ussd_query_cmd); + install_element(NAT_NODE, &cfg_nat_ussd_token_cmd); + install_element(NAT_NODE, &cfg_nat_ussd_local_cmd); /* access-list */ install_element(NAT_NODE, &cfg_lst_imsi_allow_cmd); -- cgit v1.2.3 From 64b12924bfacaacda4eb5657ab6348a86db48753 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Tue, 12 Oct 2010 21:31:02 +0200 Subject: nat: Replace the idiom for replacing a string with a function call Remove a lot of code in favor of a new function that is freeing the old string and copying the new one. I should have gotten the context and the strings right. --- openbsc/src/nat/bsc_nat_vty.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/openbsc/src/nat/bsc_nat_vty.c b/openbsc/src/nat/bsc_nat_vty.c index b284fedd5..9eb8ebc75 100644 --- a/openbsc/src/nat/bsc_nat_vty.c +++ b/openbsc/src/nat/bsc_nat_vty.c @@ -409,9 +409,7 @@ DEFUN(cfg_nat_ussd_lst_name, "Set the name of the access list to check for IMSIs for USSD message\n" "The name of the access list for HLR USSD handling") { - if (_nat->ussd_lst_name) - talloc_free(_nat->ussd_lst_name); - _nat->ussd_lst_name = talloc_strdup(_nat, argv[0]); + bsc_replace_string(_nat, &_nat->ussd_lst_name, argv[0]); return CMD_SUCCESS; } @@ -421,9 +419,7 @@ DEFUN(cfg_nat_ussd_query, "Set the USSD query to match with the ussd-list-name\n" "The query to match") { - if (_nat->ussd_query) - talloc_free(_nat->ussd_query); - _nat->ussd_query = talloc_strdup(_nat, argv[0]); + bsc_replace_string(_nat, &_nat->ussd_query, argv[0]); return CMD_SUCCESS; } @@ -432,9 +428,7 @@ DEFUN(cfg_nat_ussd_token, "ussd-token TOKEN", "Set the token used to identify the USSD module\n" "Secret key\n") { - if (_nat->ussd_token) - talloc_free(_nat->ussd_token); - _nat->ussd_token = talloc_strdup(_nat, argv[0]); + bsc_replace_string(_nat, &_nat->ussd_token, argv[0]); return CMD_SUCCESS; } @@ -443,9 +437,7 @@ DEFUN(cfg_nat_ussd_local, "ussd-local-ip A.B.C.D", "Set the IP to listen for the USSD Provider\n" "IP Address\n") { - if (_nat->ussd_local) - talloc_free(_nat->ussd_local); - _nat->ussd_local = talloc_strdup(_nat, argv[0]); + bsc_replace_string(_nat, &_nat->ussd_local, argv[0]); return CMD_SUCCESS; } -- cgit v1.2.3 From c16c2dc5d35bce659cf4c9ab542054c9b57517aa Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Wed, 13 Oct 2010 20:22:36 +0200 Subject: nat: Implement accepting a USSD Provider connection, do authentication --- openbsc/include/openbsc/bsc_nat.h | 8 ++ openbsc/src/nat/bsc_nat.c | 6 ++ openbsc/src/nat/bsc_nat_utils.c | 1 + openbsc/src/nat/bsc_ussd.c | 191 +++++++++++++++++++++++++++++++++++++- 4 files changed, 205 insertions(+), 1 deletion(-) diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h index f718766a1..acecba7de 100644 --- a/openbsc/include/openbsc/bsc_nat.h +++ b/openbsc/include/openbsc/bsc_nat.h @@ -43,6 +43,7 @@ struct sccp_source_reference; struct sccp_connections; struct bsc_nat_parsed; struct bsc_nat; +struct bsc_nat_ussd_con; enum { NAT_CON_TYPE_NONE, @@ -165,6 +166,10 @@ struct bsc_nat_statistics { struct { struct counter *reconn; } msc; + + struct { + struct counter *reconn; + } ussd; }; enum bsc_nat_acc_ctr { @@ -237,6 +242,8 @@ struct bsc_nat { char *ussd_query; char *ussd_token; char *ussd_local; + struct bsc_fd ussd_listen; + struct bsc_nat_ussd_con *ussd_con; /* statistics */ struct bsc_nat_statistics stats; @@ -328,6 +335,7 @@ int bsc_conn_type_to_ctr(struct sccp_connections *conn); struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed, struct msgb *msg, uint32_t *len); /** USSD filtering */ +int bsc_ussd_init(struct bsc_nat *nat); int bsc_check_ussd(struct sccp_connections *con, struct bsc_nat_parsed *parsed, struct msgb *msg); #endif diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c index 515278cba..fb4c1507c 100644 --- a/openbsc/src/nat/bsc_nat.c +++ b/openbsc/src/nat/bsc_nat.c @@ -1279,6 +1279,12 @@ int main(int argc, char **argv) exit(1); } + rc = bsc_ussd_init(nat); + if (rc != 0) { + LOGP(DNAT, LOGL_ERROR, "Failed to bind the USSD socket.\n"); + exit(1); + } + signal(SIGABRT, &signal_handler); signal(SIGUSR1, &signal_handler); signal(SIGPIPE, SIG_IGN); diff --git a/openbsc/src/nat/bsc_nat_utils.c b/openbsc/src/nat/bsc_nat_utils.c index 2fca31dcb..0cef01b24 100644 --- a/openbsc/src/nat/bsc_nat_utils.c +++ b/openbsc/src/nat/bsc_nat_utils.c @@ -93,6 +93,7 @@ struct bsc_nat *bsc_nat_alloc(void) nat->stats.bsc.reconn = counter_alloc("nat.bsc.conn"); nat->stats.bsc.auth_fail = counter_alloc("nat.bsc.auth_fail"); nat->stats.msc.reconn = counter_alloc("nat.msc.conn"); + nat->stats.ussd.reconn = counter_alloc("nat.ussd.conn"); nat->msc_ip = talloc_strdup(nat, "127.0.0.1"); nat->msc_port = 5000; nat->auth_timeout = 2; diff --git a/openbsc/src/nat/bsc_ussd.c b/openbsc/src/nat/bsc_ussd.c index c4e30d842..6640635e8 100644 --- a/openbsc/src/nat/bsc_ussd.c +++ b/openbsc/src/nat/bsc_ussd.c @@ -23,13 +23,202 @@ #include #include +#include +#include #include - #include +#include +#include +#include #include +#include + +struct bsc_nat_ussd_con { + struct write_queue queue; + struct bsc_nat *nat; + int authorized; + + struct timer_list auth_timeout; +}; + +static void ussd_auth_con(struct tlv_parsed *, struct bsc_nat_ussd_con *); + +static struct bsc_nat_ussd_con *bsc_nat_ussd_alloc(struct bsc_nat *nat) +{ + struct bsc_nat_ussd_con *con; + + con = talloc_zero(nat, struct bsc_nat_ussd_con); + if (!con) + return NULL; + + con->nat = nat; + return con; +} + +static void bsc_nat_ussd_destroy(struct bsc_nat_ussd_con *con) +{ + if (con->nat->ussd_con == con) + con->nat->ussd_con = NULL; + close(con->queue.bfd.fd); + bsc_unregister_fd(&con->queue.bfd); + bsc_del_timer(&con->auth_timeout); + write_queue_clear(&con->queue); + talloc_free(con); +} + +static int ussd_read_cb(struct bsc_fd *bfd) +{ + int error; + struct bsc_nat_ussd_con *conn = bfd->data; + struct msgb *msg = ipaccess_read_msg(bfd, &error); + struct ipaccess_head *hh; + + if (!msg) { + LOGP(DNAT, LOGL_ERROR, "USSD Connection was lost.\n"); + bsc_nat_ussd_destroy(conn); + return -1; + } + + LOGP(DNAT, LOGL_NOTICE, "MSG from USSD: %s proto: %d\n", + hexdump(msg->data, msg->len), msg->l2h[0]); + hh = (struct ipaccess_head *) msg->data; + + if (hh->proto == IPAC_PROTO_IPACCESS) { + if (msg->l2h[0] == IPAC_MSGT_ID_RESP) { + struct tlv_parsed tvp; + ipaccess_idtag_parse(&tvp, + (unsigned char *) msg->l2h + 2, + msgb_l2len(msg) - 2); + if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME)) + ussd_auth_con(&tvp, conn); + } + + msgb_free(msg); + } else if (hh->proto == IPAC_PROTO_SCCP) { + LOGP(DNAT, LOGL_ERROR, "USSD SCCP is not handled\n"); + msgb_free(msg); + } else { + msgb_free(msg); + } + + return 0; +} + +static void ussd_auth_cb(void *_data) +{ + LOGP(DNAT, LOGL_ERROR, "USSD module didn't authenticate\n"); + bsc_nat_ussd_destroy((struct bsc_nat_ussd_con *) _data); +} + +static void ussd_auth_con(struct tlv_parsed *tvp, struct bsc_nat_ussd_con *conn) +{ + const char *token; + int len; + if (!conn->nat->ussd_token) { + LOGP(DNAT, LOGL_ERROR, "No USSD token set. Closing\n"); + bsc_nat_ussd_destroy(conn); + return; + } + + token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME); + len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME); + if (strncmp(conn->nat->ussd_token, token, len) != 0) { + LOGP(DNAT, LOGL_ERROR, "Wrong USSD token by client: %d\n", + conn->queue.bfd.fd); + bsc_nat_ussd_destroy(conn); + return; + } + /* it is authenticated now */ + if (conn->nat->ussd_con && conn->nat->ussd_con != conn) + bsc_nat_ussd_destroy(conn->nat->ussd_con); + + LOGP(DNAT, LOGL_ERROR, "USSD token specified. USSD provider is connected.\n"); + bsc_del_timer(&conn->auth_timeout); + conn->authorized = 1; + conn->nat->ussd_con = conn; +} + +static void ussd_start_auth(struct bsc_nat_ussd_con *conn) +{ + struct msgb *msg; + + conn->auth_timeout.data = conn; + conn->auth_timeout.cb = ussd_auth_cb; + bsc_schedule_timer(&conn->auth_timeout, conn->nat->auth_timeout, 0); + + msg = msgb_alloc_headroom(4096, 128, "auth message"); + if (!msg) { + LOGP(DNAT, LOGL_ERROR, "Failed to allocate auth msg\n"); + return; + } + + msgb_v_put(msg, IPAC_MSGT_ID_GET); + bsc_do_write(&conn->queue, msg, IPAC_PROTO_IPACCESS); +} + +static int ussd_listen_cb(struct bsc_fd *bfd, unsigned int what) +{ + struct bsc_nat_ussd_con *conn; + struct bsc_nat *nat; + struct sockaddr_in sa; + socklen_t sa_len = sizeof(sa); + int fd; + + if (!(what & BSC_FD_READ)) + return 0; + + fd = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len); + if (fd < 0) { + perror("accept"); + return fd; + } + + nat = (struct bsc_nat *) bfd->data; + counter_inc(nat->stats.ussd.reconn); + + conn = bsc_nat_ussd_alloc(nat); + if (!conn) { + LOGP(DNAT, LOGL_ERROR, "Failed to allocate USSD con struct.\n"); + close(fd); + return -1; + } + + write_queue_init(&conn->queue, 10); + conn->queue.bfd.data = conn; + conn->queue.bfd.fd = fd; + conn->queue.bfd.when = BSC_FD_READ; + conn->queue.read_cb = ussd_read_cb; + conn->queue.write_cb = bsc_write_cb; + + if (bsc_register_fd(&conn->queue.bfd) < 0) { + LOGP(DNAT, LOGL_ERROR, "Failed to register USSD fd.\n"); + bsc_nat_ussd_destroy(conn); + return -1; + } + + LOGP(DNAT, LOGL_NOTICE, "USSD Connection on %d with IP: %s\n", + fd, inet_ntoa(sa.sin_addr)); + + /* do authentication */ + ussd_start_auth(conn); + return 0; +} + +int bsc_ussd_init(struct bsc_nat *nat) +{ + struct in_addr addr; + + addr.s_addr = INADDR_ANY; + if (nat->ussd_local) + inet_aton(nat->ussd_local, &addr); + + nat->ussd_listen.data = nat; + return make_sock(&nat->ussd_listen, IPPROTO_TCP, + ntohl(addr.s_addr), 5001, ussd_listen_cb); +} int bsc_check_ussd(struct sccp_connections *con, struct bsc_nat_parsed *parsed, struct msgb *msg) -- cgit v1.2.3 From ec8a4e23d31ec84a041cbdbebea476258db87b0d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 14 Oct 2010 22:56:06 +0200 Subject: ipaccess: Add a structure for informing the USSD provider about the state This is used to inform the USSD provider about the state of the connection. --- openbsc/include/openbsc/ipaccess.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/openbsc/include/openbsc/ipaccess.h b/openbsc/include/openbsc/ipaccess.h index b36811ce3..b37022038 100644 --- a/openbsc/include/openbsc/ipaccess.h +++ b/openbsc/include/openbsc/ipaccess.h @@ -2,6 +2,7 @@ #define _IPACCESS_H #include "e1_input.h" +#include "gsm_subscriber.h" #include #define IPA_TCP_PORT_OML 3002 @@ -29,6 +30,9 @@ enum ipaccess_msgtype { IPAC_MSGT_ID_GET = 0x04, IPAC_MSGT_ID_RESP = 0x05, IPAC_MSGT_ID_ACK = 0x06, + + /* OpenBSC extension */ + IPAC_MSGT_SCCP_STATE = 0xff, }; enum ipaccess_id_tags { @@ -43,6 +47,14 @@ enum ipaccess_id_tags { IPAC_IDTAG_UNIT = 0x08, }; +struct ipac_msgt_sccp_state { + uint8_t src_ref[3]; + uint8_t dst_ref[3]; + uint8_t trans_id; + uint8_t invoke_id; + char imsi[GSM_IMSI_LENGTH]; +} __attribute__((packed)); + int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa); /* -- cgit v1.2.3 From 4c401e7a1a35d67256baaaa28f5f2965884f96c8 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Fri, 15 Oct 2010 10:09:31 +0200 Subject: nat: Forward extra state and the message to the USSD provider Forward the SCCP state and the data to the USSD provider, also mark the connection as local. --- openbsc/src/nat/bsc_nat.c | 6 ++---- openbsc/src/nat/bsc_ussd.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c index fb4c1507c..daabf0976 100644 --- a/openbsc/src/nat/bsc_nat.c +++ b/openbsc/src/nat/bsc_nat.c @@ -856,10 +856,8 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) } /* hand data to a side channel */ - if (bsc_check_ussd(con, parsed, msg) == 1) { - /* we are going to take over the connection */ - /* TODO: */ - } + if (bsc_check_ussd(con, parsed, msg) == 1) + con->con_local = 2; } con_bsc = con->bsc; diff --git a/openbsc/src/nat/bsc_ussd.c b/openbsc/src/nat/bsc_ussd.c index 6640635e8..cd40566eb 100644 --- a/openbsc/src/nat/bsc_ussd.c +++ b/openbsc/src/nat/bsc_ussd.c @@ -31,6 +31,8 @@ #include #include +#include + #include #include #include @@ -220,6 +222,39 @@ int bsc_ussd_init(struct bsc_nat *nat) ntohl(addr.s_addr), 5001, ussd_listen_cb); } +static int forward_ussd(struct sccp_connections *con, const struct ussd_request *req, + struct msgb *input) +{ + struct msgb *msg; + struct ipac_msgt_sccp_state *state; + struct bsc_nat_ussd_con *ussd; + + if (!con->bsc->nat->ussd_con) + return -1; + + msg = msgb_alloc_headroom(4096, 128, "forward ussd"); + if (!msg) { + LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n"); + return -1; + } + + msg->l2h = msgb_put(msg, 1); + msg->l2h[0] = IPAC_MSGT_SCCP_STATE; + + /* fill out the data */ + state = (struct ipac_msgt_sccp_state *) msgb_put(msg, sizeof(*state)); + state->trans_id = req->transaction_id; + state->invoke_id = req->invoke_id; + memcpy(&state->src_ref, &con->remote_ref, sizeof(con->remote_ref)); + memcpy(&state->dst_ref, &con->real_ref, sizeof(con->real_ref)); + memcpy(state->imsi, con->imsi, strlen(con->imsi)); + + ussd = con->bsc->nat->ussd_con; + bsc_do_write(&ussd->queue, msg, IPAC_PROTO_IPACCESS); + + return 0; +} + int bsc_check_ussd(struct sccp_connections *con, struct bsc_nat_parsed *parsed, struct msgb *msg) { @@ -279,5 +314,7 @@ int bsc_check_ussd(struct sccp_connections *con, struct bsc_nat_parsed *parsed, /* found a USSD query for our subscriber */ LOGP(DNAT, LOGL_NOTICE, "Found USSD query for %s\n", con->imsi); + if (forward_ussd(con, &req, msg) != 0) + return 0; return 1; } -- cgit v1.2.3 From 90bbccfca9f00094e89dd35b42052e80a8318404 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Sat, 16 Oct 2010 17:34:37 +0200 Subject: nat: Forward the data coming from the USSD module to the BSC. --- openbsc/src/nat/bsc_ussd.c | 47 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/openbsc/src/nat/bsc_ussd.c b/openbsc/src/nat/bsc_ussd.c index cd40566eb..3729d91f3 100644 --- a/openbsc/src/nat/bsc_ussd.c +++ b/openbsc/src/nat/bsc_ussd.c @@ -70,6 +70,37 @@ static void bsc_nat_ussd_destroy(struct bsc_nat_ussd_con *con) talloc_free(con); } +static int forward_sccp(struct bsc_nat *nat, struct msgb *msg) +{ + struct sccp_connections *con; + struct bsc_nat_parsed *parsed; + + + parsed = bsc_nat_parse(msg); + if (!parsed) { + LOGP(DNAT, LOGL_ERROR, "Can not parse msg from USSD.\n"); + msgb_free(msg); + return -1; + } + + if (!parsed->dest_local_ref) { + LOGP(DNAT, LOGL_ERROR, "No destination local reference.\n"); + msgb_free(msg); + return -1; + } + + con = bsc_nat_find_con_by_bsc(nat, parsed->dest_local_ref); + if (!con || !con->bsc) { + LOGP(DNAT, LOGL_ERROR, "No active connection found.\n"); + msgb_free(msg); + return -1; + } + + talloc_free(parsed); + bsc_write_msg(&con->bsc->write_queue, msg); + return 0; +} + static int ussd_read_cb(struct bsc_fd *bfd) { int error; @@ -99,8 +130,7 @@ static int ussd_read_cb(struct bsc_fd *bfd) msgb_free(msg); } else if (hh->proto == IPAC_PROTO_SCCP) { - LOGP(DNAT, LOGL_ERROR, "USSD SCCP is not handled\n"); - msgb_free(msg); + forward_sccp(conn->nat, msg); } else { msgb_free(msg); } @@ -225,7 +255,7 @@ int bsc_ussd_init(struct bsc_nat *nat) static int forward_ussd(struct sccp_connections *con, const struct ussd_request *req, struct msgb *input) { - struct msgb *msg; + struct msgb *msg, *copy; struct ipac_msgt_sccp_state *state; struct bsc_nat_ussd_con *ussd; @@ -238,6 +268,16 @@ static int forward_ussd(struct sccp_connections *con, const struct ussd_request return -1; } + copy = msgb_alloc_headroom(4096, 128, "forward bts"); + if (!copy) { + LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n"); + msgb_free(msg); + return -1; + } + + copy->l2h = msgb_put(copy, msgb_l2len(input)); + memcpy(copy->l2h, input->l2h, msgb_l2len(input)); + msg->l2h = msgb_put(msg, 1); msg->l2h[0] = IPAC_MSGT_SCCP_STATE; @@ -251,6 +291,7 @@ static int forward_ussd(struct sccp_connections *con, const struct ussd_request ussd = con->bsc->nat->ussd_con; bsc_do_write(&ussd->queue, msg, IPAC_PROTO_IPACCESS); + bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP); return 0; } -- cgit v1.2.3