blob: 0727b33e6d47370662c83bbeeeb84d65a2282ba3 [file] [log] [blame]
Holger Hans Peter Freyther57adba52010-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 Freytherf75a6802010-06-15 18:45:38 +080025#include <openbsc/bssap.h>
Holger Hans Peter Freyther57adba52010-06-15 18:45:26 +080026#include <openbsc/ipaccess.h>
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +080027#include <openbsc/talloc.h>
28#include <openbsc/debug.h>
Holger Hans Peter Freyther57adba52010-06-15 18:45:26 +080029
Holger Hans Peter Freytherf75a6802010-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
42struct bsc_pkt_filter {
43 int ipa_proto;
44 int dest_ssn;
45 int bssap;
46 int gsm;
47 int filter_dir;
48};
49
50static struct bsc_pkt_filter black_list[] = {
51 /* filter reset messages to the MSC */
52 { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET, FILTER_TO_MSC },
53
54 /* filter reset ack messages to the BSC */
55 { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET_ACKNOWLEDGE, FILTER_TO_BSC },
56
57 /* filter ip access */
58 { IPAC_PROTO_IPACCESS, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_MSC },
59};
60
61static struct bsc_pkt_filter white_list[] = {
62 /* allow IPAC_PROTO_SCCP messages to both sides */
63 { IPAC_PROTO_SCCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_NONE },
64};
65
66struct bsc_nat_parsed* bsc_nat_parse(struct msgb *msg)
Holger Hans Peter Freyther57adba52010-06-15 18:45:26 +080067{
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +080068 struct sccp_parse_result result;
69 struct bsc_nat_parsed *parsed;
Holger Hans Peter Freyther57adba52010-06-15 18:45:26 +080070 struct ipaccess_head *hh;
71
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +080072 /* quick fail */
73 if (msg->len < 4)
74 return NULL;
75
76 parsed = talloc_zero(msg, struct bsc_nat_parsed);
77 if (!parsed)
78 return NULL;
79
80 /* more init */
81 parsed->ipa_proto = parsed->called_ssn = parsed->calling_ssn = -1;
82 parsed->sccp_type = parsed->bssap = parsed->gsm_type = -1;
83
84 /* start parsing */
Holger Hans Peter Freyther57adba52010-06-15 18:45:26 +080085 hh = (struct ipaccess_head *) msg->data;
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +080086 parsed->ipa_proto = hh->proto;
87
88 msg->l2h = &hh->data[0];
89
90 /* analyze sccp down here */
91 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
92 memset(&result, 0, sizeof(result));
93 if (sccp_parse_header(msg, &result) != 0) {
94 talloc_free(parsed);
95 return 0;
96 }
97
98 if (msg->l3h && msgb_l3len(msg) < 3) {
99 LOGP(DNAT, LOGL_ERROR, "Not enough space or GSM payload\n");
100 talloc_free(parsed);
101 return 0;
102 }
103
104 parsed->sccp_type = sccp_determine_msg_type(msg);
105 parsed->src_local_ref = result.source_local_reference;
106 parsed->dest_local_ref = result.destination_local_reference;
107 parsed->called_ssn = result.called.ssn;
108 parsed->calling_ssn = result.calling.ssn;
109
110 /* in case of connection confirm we have no payload */
111 if (msg->l3h) {
112 parsed->bssap = msg->l3h[0];
113 parsed->gsm_type = msg->l3h[2];
114 }
115 }
116
117 return parsed;
118}
119
120int bsc_nat_filter_ipa(struct msgb *msg, struct bsc_nat_parsed *parsed)
121{
122 int i;
123
124 /* go through the blacklist now */
125 for (i = 0; i < ARRAY_SIZE(black_list); ++i) {
126 /* the proto is not blacklisted */
127 if (black_list[i].ipa_proto != ALLOW_ANY
128 && black_list[i].ipa_proto != parsed->ipa_proto)
129 continue;
130
131 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
132 /* the SSN is not blacklisted */
133 if (black_list[i].dest_ssn != ALLOW_ANY
134 && black_list[i].dest_ssn != parsed->called_ssn)
135 continue;
136
137 /* bssap */
138 if (black_list[i].bssap != ALLOW_ANY
139 && black_list[i].bssap != parsed->bssap)
140 continue;
141
142 /* gsm */
143 if (black_list[i].gsm != ALLOW_ANY
144 && black_list[i].gsm != parsed->gsm_type)
145 continue;
146
147 /* blacklisted */
148 LOGP(DNAT, LOGL_NOTICE, "Blacklisted with rule %d\n", i);
149 return black_list[i].filter_dir;
150 } else {
151 /* blacklisted, we have no content sniffing yet */
152 LOGP(DNAT, LOGL_NOTICE, "Blacklisted with rule %d\n", i);
153 return black_list[i].filter_dir;
154 }
155 }
156
157 /* go through the whitelust now */
158 for (i = 0; i < ARRAY_SIZE(white_list); ++i) {
159 /* the proto is not whitelisted */
160 if (white_list[i].ipa_proto != ALLOW_ANY
161 && white_list[i].ipa_proto != parsed->ipa_proto)
162 continue;
163
164 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
165 /* the SSN is not whitelisted */
166 if (white_list[i].dest_ssn != ALLOW_ANY
167 && white_list[i].dest_ssn != parsed->called_ssn)
168 continue;
169
170 /* bssap */
171 if (white_list[i].bssap != ALLOW_ANY
172 && white_list[i].bssap != parsed->bssap)
173 continue;
174
175 /* gsm */
176 if (white_list[i].gsm != ALLOW_ANY
177 && white_list[i].gsm != parsed->gsm_type)
178 continue;
179
180 /* whitelisted */
181 LOGP(DNAT, LOGL_NOTICE, "Whitelisted with rule %d\n", i);
182 return FILTER_NONE;
183 } else {
184 /* whitelisted */
185 return FILTER_NONE;
186 }
187 }
188
189 return FILTER_TO_BOTH;
Holger Hans Peter Freyther57adba52010-06-15 18:45:26 +0800190}