blob: e968fa22bd67517f816057a6c3b4f7a78094b3d6 [file] [log] [blame]
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +08001/* BSC Multiplexer/NAT */
2
3/*
4 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
Holger Hans Peter Freytherdf6143a2010-06-15 18:46:56 +08005 * (C) 2010 by On-Waves
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +08006 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 */
23
24#include <openbsc/bsc_nat.h>
Holger Hans Peter Freytherc2b31ed2010-07-31 05:17:17 +080025#include <openbsc/bsc_nat_sccp.h>
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080026#include <openbsc/ipaccess.h>
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080027#include <openbsc/debug.h>
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080028
Holger Hans Peter Freyther6c45f2e2010-06-15 19:06:18 +080029#include <osmocore/talloc.h>
Holger Hans Peter Freyther69d801e2010-06-15 20:13:33 +080030#include <osmocore/protocol/gsm_08_08.h>
Holger Hans Peter Freyther6c45f2e2010-06-15 19:06:18 +080031
Harald Welted5db12c2010-08-03 15:11:51 +020032#include <osmocom/sccp/sccp.h>
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080033
34/*
35 * The idea is to have a simple struct describing a IPA packet with
36 * SCCP SSN and the GSM 08.08 payload and decide. We will both have
37 * a white and a blacklist of packets we want to handle.
38 *
39 * TODO: Implement a "NOT" in the filter language.
40 */
41
42#define ALLOW_ANY -1
43
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +010044#define FILTER_TO_BSC 1
45#define FILTER_TO_MSC 2
46#define FILTER_TO_BOTH 3
47
48
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080049struct bsc_pkt_filter {
50 int ipa_proto;
51 int dest_ssn;
52 int bssap;
53 int gsm;
54 int filter_dir;
55};
56
57static struct bsc_pkt_filter black_list[] = {
58 /* filter reset messages to the MSC */
59 { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET, FILTER_TO_MSC },
60
61 /* filter reset ack messages to the BSC */
62 { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET_ACKNOWLEDGE, FILTER_TO_BSC },
63
64 /* filter ip access */
65 { IPAC_PROTO_IPACCESS, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_MSC },
66};
67
68static struct bsc_pkt_filter white_list[] = {
69 /* allow IPAC_PROTO_SCCP messages to both sides */
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +010070 { IPAC_PROTO_SCCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH },
Holger Hans Peter Freythera128d912010-04-01 08:47:12 +020071
72 /* allow MGCP messages to both sides */
73 { NAT_IPAC_PROTO_MGCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH },
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080074};
75
Holger Hans Peter Freytheradb6e1c2010-09-18 06:44:24 +080076struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg)
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080077{
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080078 struct sccp_parse_result result;
79 struct bsc_nat_parsed *parsed;
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080080 struct ipaccess_head *hh;
81
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080082 /* quick fail */
83 if (msg->len < 4)
84 return NULL;
85
86 parsed = talloc_zero(msg, struct bsc_nat_parsed);
87 if (!parsed)
88 return NULL;
89
90 /* more init */
91 parsed->ipa_proto = parsed->called_ssn = parsed->calling_ssn = -1;
92 parsed->sccp_type = parsed->bssap = parsed->gsm_type = -1;
93
94 /* start parsing */
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080095 hh = (struct ipaccess_head *) msg->data;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080096 parsed->ipa_proto = hh->proto;
97
98 msg->l2h = &hh->data[0];
99
Holger Hans Peter Freytherea8cbd52010-03-29 14:58:43 +0200100 /* do a size check on the input */
101 if (ntohs(hh->len) != msgb_l2len(msg)) {
102 LOGP(DINP, LOGL_ERROR, "Wrong input length?\n");
103 talloc_free(parsed);
104 return NULL;
105 }
106
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800107 /* analyze sccp down here */
108 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
109 memset(&result, 0, sizeof(result));
110 if (sccp_parse_header(msg, &result) != 0) {
111 talloc_free(parsed);
112 return 0;
113 }
114
115 if (msg->l3h && msgb_l3len(msg) < 3) {
116 LOGP(DNAT, LOGL_ERROR, "Not enough space or GSM payload\n");
117 talloc_free(parsed);
118 return 0;
119 }
120
121 parsed->sccp_type = sccp_determine_msg_type(msg);
122 parsed->src_local_ref = result.source_local_reference;
123 parsed->dest_local_ref = result.destination_local_reference;
124 parsed->called_ssn = result.called.ssn;
125 parsed->calling_ssn = result.calling.ssn;
126
127 /* in case of connection confirm we have no payload */
128 if (msg->l3h) {
129 parsed->bssap = msg->l3h[0];
130 parsed->gsm_type = msg->l3h[2];
131 }
132 }
133
134 return parsed;
135}
136
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100137int bsc_nat_filter_ipa(int dir, struct msgb *msg, struct bsc_nat_parsed *parsed)
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800138{
139 int i;
140
141 /* go through the blacklist now */
142 for (i = 0; i < ARRAY_SIZE(black_list); ++i) {
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100143 /* ignore the rule? */
144 if (black_list[i].filter_dir != FILTER_TO_BOTH
145 && black_list[i].filter_dir != dir)
146 continue;
147
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800148 /* the proto is not blacklisted */
149 if (black_list[i].ipa_proto != ALLOW_ANY
150 && black_list[i].ipa_proto != parsed->ipa_proto)
151 continue;
152
153 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
154 /* the SSN is not blacklisted */
155 if (black_list[i].dest_ssn != ALLOW_ANY
156 && black_list[i].dest_ssn != parsed->called_ssn)
157 continue;
158
159 /* bssap */
160 if (black_list[i].bssap != ALLOW_ANY
161 && black_list[i].bssap != parsed->bssap)
162 continue;
163
164 /* gsm */
165 if (black_list[i].gsm != ALLOW_ANY
166 && black_list[i].gsm != parsed->gsm_type)
167 continue;
168
169 /* blacklisted */
Holger Hans Peter Freyther0dc569a2010-03-29 14:59:59 +0200170 LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i);
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100171 return 1;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800172 } else {
173 /* blacklisted, we have no content sniffing yet */
Holger Hans Peter Freyther0dc569a2010-03-29 14:59:59 +0200174 LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i);
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100175 return 1;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800176 }
177 }
178
179 /* go through the whitelust now */
180 for (i = 0; i < ARRAY_SIZE(white_list); ++i) {
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100181 /* ignore the rule? */
182 if (white_list[i].filter_dir != FILTER_TO_BOTH
183 && white_list[i].filter_dir != dir)
184 continue;
185
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800186 /* the proto is not whitelisted */
187 if (white_list[i].ipa_proto != ALLOW_ANY
188 && white_list[i].ipa_proto != parsed->ipa_proto)
189 continue;
190
191 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
192 /* the SSN is not whitelisted */
193 if (white_list[i].dest_ssn != ALLOW_ANY
194 && white_list[i].dest_ssn != parsed->called_ssn)
195 continue;
196
197 /* bssap */
198 if (white_list[i].bssap != ALLOW_ANY
199 && white_list[i].bssap != parsed->bssap)
200 continue;
201
202 /* gsm */
203 if (white_list[i].gsm != ALLOW_ANY
204 && white_list[i].gsm != parsed->gsm_type)
205 continue;
206
207 /* whitelisted */
Holger Hans Peter Freyther0dc569a2010-03-29 14:59:59 +0200208 LOGP(DNAT, LOGL_INFO, "Whitelisted with rule %d\n", i);
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100209 return 0;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800210 } else {
211 /* whitelisted */
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100212 return 0;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800213 }
214 }
215
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100216 return 1;
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +0800217}