From 03fd8d014f9871896a86534432c8757d65a576fe Mon Sep 17 00:00:00 2001 From: Jonathan Santos Date: Wed, 25 May 2011 13:54:02 -0400 Subject: Import upstream version 0.9.13 --- src/osmo-bsc_nat/bsc_filter.c | 216 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 src/osmo-bsc_nat/bsc_filter.c (limited to 'src/osmo-bsc_nat/bsc_filter.c') diff --git a/src/osmo-bsc_nat/bsc_filter.c b/src/osmo-bsc_nat/bsc_filter.c new file mode 100644 index 000000000..73e987893 --- /dev/null +++ b/src/osmo-bsc_nat/bsc_filter.c @@ -0,0 +1,216 @@ +/* BSC Multiplexer/NAT */ + +/* + * (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 Affero General Public License as published by + * the Free Software Foundation; either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include + +#include +#include + +#include + +/* + * The idea is to have a simple struct describing a IPA packet with + * SCCP SSN and the GSM 08.08 payload and decide. We will both have + * a white and a blacklist of packets we want to handle. + * + * TODO: Implement a "NOT" in the filter language. + */ + +#define ALLOW_ANY -1 + +#define FILTER_TO_BSC 1 +#define FILTER_TO_MSC 2 +#define FILTER_TO_BOTH 3 + + +struct bsc_pkt_filter { + int ipa_proto; + int dest_ssn; + int bssap; + int gsm; + int filter_dir; +}; + +static struct bsc_pkt_filter black_list[] = { + /* filter reset messages to the MSC */ + { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET, FILTER_TO_MSC }, + + /* filter reset ack messages to the BSC */ + { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET_ACKNOWLEDGE, FILTER_TO_BSC }, + + /* filter ip access */ + { IPAC_PROTO_IPACCESS, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_MSC }, +}; + +static struct bsc_pkt_filter white_list[] = { + /* allow IPAC_PROTO_SCCP messages to both sides */ + { IPAC_PROTO_SCCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH }, + + /* allow MGCP messages to both sides */ + { IPAC_PROTO_MGCP_OLD, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH }, +}; + +struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg) +{ + struct sccp_parse_result result; + struct bsc_nat_parsed *parsed; + struct ipaccess_head *hh; + + /* quick fail */ + if (msg->len < 4) + return NULL; + + parsed = talloc_zero(msg, struct bsc_nat_parsed); + if (!parsed) + return NULL; + + /* more init */ + parsed->ipa_proto = parsed->called_ssn = parsed->calling_ssn = -1; + parsed->sccp_type = parsed->bssap = parsed->gsm_type = -1; + + /* start parsing */ + hh = (struct ipaccess_head *) msg->data; + parsed->ipa_proto = hh->proto; + + msg->l2h = &hh->data[0]; + + /* do a size check on the input */ + if (ntohs(hh->len) != msgb_l2len(msg)) { + LOGP(DINP, LOGL_ERROR, "Wrong input length?\n"); + talloc_free(parsed); + return NULL; + } + + /* analyze sccp down here */ + if (parsed->ipa_proto == IPAC_PROTO_SCCP) { + memset(&result, 0, sizeof(result)); + if (sccp_parse_header(msg, &result) != 0) { + talloc_free(parsed); + return 0; + } + + if (msg->l3h && msgb_l3len(msg) < 3) { + LOGP(DNAT, LOGL_ERROR, "Not enough space or GSM payload\n"); + talloc_free(parsed); + return 0; + } + + parsed->sccp_type = sccp_determine_msg_type(msg); + parsed->src_local_ref = result.source_local_reference; + parsed->dest_local_ref = result.destination_local_reference; + parsed->called_ssn = result.called.ssn; + parsed->calling_ssn = result.calling.ssn; + + /* in case of connection confirm we have no payload */ + if (msg->l3h) { + parsed->bssap = msg->l3h[0]; + parsed->gsm_type = msg->l3h[2]; + } + } + + return parsed; +} + +int bsc_nat_filter_ipa(int dir, struct msgb *msg, struct bsc_nat_parsed *parsed) +{ + int i; + + /* go through the blacklist now */ + for (i = 0; i < ARRAY_SIZE(black_list); ++i) { + /* ignore the rule? */ + if (black_list[i].filter_dir != FILTER_TO_BOTH + && black_list[i].filter_dir != dir) + continue; + + /* the proto is not blacklisted */ + if (black_list[i].ipa_proto != ALLOW_ANY + && black_list[i].ipa_proto != parsed->ipa_proto) + continue; + + if (parsed->ipa_proto == IPAC_PROTO_SCCP) { + /* the SSN is not blacklisted */ + if (black_list[i].dest_ssn != ALLOW_ANY + && black_list[i].dest_ssn != parsed->called_ssn) + continue; + + /* bssap */ + if (black_list[i].bssap != ALLOW_ANY + && black_list[i].bssap != parsed->bssap) + continue; + + /* gsm */ + if (black_list[i].gsm != ALLOW_ANY + && black_list[i].gsm != parsed->gsm_type) + continue; + + /* blacklisted */ + LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i); + return 1; + } else { + /* blacklisted, we have no content sniffing yet */ + LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i); + return 1; + } + } + + /* go through the whitelust now */ + for (i = 0; i < ARRAY_SIZE(white_list); ++i) { + /* ignore the rule? */ + if (white_list[i].filter_dir != FILTER_TO_BOTH + && white_list[i].filter_dir != dir) + continue; + + /* the proto is not whitelisted */ + if (white_list[i].ipa_proto != ALLOW_ANY + && white_list[i].ipa_proto != parsed->ipa_proto) + continue; + + if (parsed->ipa_proto == IPAC_PROTO_SCCP) { + /* the SSN is not whitelisted */ + if (white_list[i].dest_ssn != ALLOW_ANY + && white_list[i].dest_ssn != parsed->called_ssn) + continue; + + /* bssap */ + if (white_list[i].bssap != ALLOW_ANY + && white_list[i].bssap != parsed->bssap) + continue; + + /* gsm */ + if (white_list[i].gsm != ALLOW_ANY + && white_list[i].gsm != parsed->gsm_type) + continue; + + /* whitelisted */ + LOGP(DNAT, LOGL_INFO, "Whitelisted with rule %d\n", i); + return 0; + } else { + /* whitelisted */ + return 0; + } + } + + return 1; +} -- cgit v1.2.3