blob: ad2f6138fdcc3cc8cc58c433db58c7d9c867df1d [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>
5 * (C) 2010 by on-waves.com
6 * 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 Freyther0b8f69d2010-06-15 18:45:38 +080025#include <openbsc/bssap.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/talloc.h>
28#include <openbsc/debug.h>
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080029
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080030#include <sccp/sccp.h>
31
32/*
33 * The idea is to have a simple struct describing a IPA packet with
34 * SCCP SSN and the GSM 08.08 payload and decide. We will both have
35 * a white and a blacklist of packets we want to handle.
36 *
37 * TODO: Implement a "NOT" in the filter language.
38 */
39
40#define ALLOW_ANY -1
41
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +010042#define FILTER_TO_BSC 1
43#define FILTER_TO_MSC 2
44#define FILTER_TO_BOTH 3
45
46
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080047struct bsc_pkt_filter {
48 int ipa_proto;
49 int dest_ssn;
50 int bssap;
51 int gsm;
52 int filter_dir;
53};
54
55static struct bsc_pkt_filter black_list[] = {
56 /* filter reset messages to the MSC */
57 { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET, FILTER_TO_MSC },
58
59 /* filter reset ack messages to the BSC */
60 { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET_ACKNOWLEDGE, FILTER_TO_BSC },
61
62 /* filter ip access */
63 { IPAC_PROTO_IPACCESS, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_MSC },
64};
65
66static struct bsc_pkt_filter white_list[] = {
67 /* allow IPAC_PROTO_SCCP messages to both sides */
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +010068 { IPAC_PROTO_SCCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH },
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080069};
70
71struct bsc_nat_parsed* bsc_nat_parse(struct msgb *msg)
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080072{
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080073 struct sccp_parse_result result;
74 struct bsc_nat_parsed *parsed;
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080075 struct ipaccess_head *hh;
76
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080077 /* quick fail */
78 if (msg->len < 4)
79 return NULL;
80
81 parsed = talloc_zero(msg, struct bsc_nat_parsed);
82 if (!parsed)
83 return NULL;
84
85 /* more init */
86 parsed->ipa_proto = parsed->called_ssn = parsed->calling_ssn = -1;
87 parsed->sccp_type = parsed->bssap = parsed->gsm_type = -1;
88
89 /* start parsing */
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080090 hh = (struct ipaccess_head *) msg->data;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +080091 parsed->ipa_proto = hh->proto;
92
93 msg->l2h = &hh->data[0];
94
95 /* analyze sccp down here */
96 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
97 memset(&result, 0, sizeof(result));
98 if (sccp_parse_header(msg, &result) != 0) {
99 talloc_free(parsed);
100 return 0;
101 }
102
103 if (msg->l3h && msgb_l3len(msg) < 3) {
104 LOGP(DNAT, LOGL_ERROR, "Not enough space or GSM payload\n");
105 talloc_free(parsed);
106 return 0;
107 }
108
109 parsed->sccp_type = sccp_determine_msg_type(msg);
110 parsed->src_local_ref = result.source_local_reference;
111 parsed->dest_local_ref = result.destination_local_reference;
112 parsed->called_ssn = result.called.ssn;
113 parsed->calling_ssn = result.calling.ssn;
114
115 /* in case of connection confirm we have no payload */
116 if (msg->l3h) {
117 parsed->bssap = msg->l3h[0];
118 parsed->gsm_type = msg->l3h[2];
119 }
120 }
121
122 return parsed;
123}
124
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100125int bsc_nat_filter_ipa(int dir, struct msgb *msg, struct bsc_nat_parsed *parsed)
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800126{
127 int i;
128
129 /* go through the blacklist now */
130 for (i = 0; i < ARRAY_SIZE(black_list); ++i) {
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100131 /* ignore the rule? */
132 if (black_list[i].filter_dir != FILTER_TO_BOTH
133 && black_list[i].filter_dir != dir)
134 continue;
135
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800136 /* the proto is not blacklisted */
137 if (black_list[i].ipa_proto != ALLOW_ANY
138 && black_list[i].ipa_proto != parsed->ipa_proto)
139 continue;
140
141 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
142 /* the SSN is not blacklisted */
143 if (black_list[i].dest_ssn != ALLOW_ANY
144 && black_list[i].dest_ssn != parsed->called_ssn)
145 continue;
146
147 /* bssap */
148 if (black_list[i].bssap != ALLOW_ANY
149 && black_list[i].bssap != parsed->bssap)
150 continue;
151
152 /* gsm */
153 if (black_list[i].gsm != ALLOW_ANY
154 && black_list[i].gsm != parsed->gsm_type)
155 continue;
156
157 /* blacklisted */
158 LOGP(DNAT, LOGL_NOTICE, "Blacklisted with rule %d\n", i);
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100159 return 1;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800160 } else {
161 /* blacklisted, we have no content sniffing yet */
162 LOGP(DNAT, LOGL_NOTICE, "Blacklisted with rule %d\n", i);
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100163 return 1;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800164 }
165 }
166
167 /* go through the whitelust now */
168 for (i = 0; i < ARRAY_SIZE(white_list); ++i) {
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100169 /* ignore the rule? */
170 if (white_list[i].filter_dir != FILTER_TO_BOTH
171 && white_list[i].filter_dir != dir)
172 continue;
173
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800174 /* the proto is not whitelisted */
175 if (white_list[i].ipa_proto != ALLOW_ANY
176 && white_list[i].ipa_proto != parsed->ipa_proto)
177 continue;
178
179 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
180 /* the SSN is not whitelisted */
181 if (white_list[i].dest_ssn != ALLOW_ANY
182 && white_list[i].dest_ssn != parsed->called_ssn)
183 continue;
184
185 /* bssap */
186 if (white_list[i].bssap != ALLOW_ANY
187 && white_list[i].bssap != parsed->bssap)
188 continue;
189
190 /* gsm */
191 if (white_list[i].gsm != ALLOW_ANY
192 && white_list[i].gsm != parsed->gsm_type)
193 continue;
194
195 /* whitelisted */
196 LOGP(DNAT, LOGL_NOTICE, "Whitelisted with rule %d\n", i);
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100197 return 0;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800198 } else {
199 /* whitelisted */
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100200 return 0;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800201 }
202 }
203
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100204 return 1;
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +0800205}