- tested sa with traffic selectors
[strongswan.git] / Source / charon / config / traffic_selector.c
1 /**
2 * @file traffic_selector.c
3 *
4 * @brief Implementation of traffic_selector_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include "traffic_selector.h"
24
25 #include <utils/linked_list.h>
26 #include <utils/allocator.h>
27 #include <utils/identification.h>
28
29 typedef struct private_traffic_selector_t private_traffic_selector_t;
30
31 /**
32 * Private data of an traffic_selector_t object
33 */
34 struct private_traffic_selector_t {
35
36 /**
37 * Public part
38 */
39 traffic_selector_t public;
40
41 /**
42 * Type of address
43 */
44 ts_type_t type;
45
46 /**
47 * IP protocol (UDP, TCP, ICMP, ...)
48 */
49 u_int8_t protocol;
50
51 /**
52 * begin of address range
53 */
54 union {
55 struct {
56 u_int32_t from_addr_ipv4;
57 };
58 struct {
59 };
60 };
61
62 /**
63 * end of address range
64 */
65 union {
66 struct {
67 u_int32_t to_addr_ipv4;
68 };
69 struct {
70 };
71 };
72
73 /**
74 * begin of port range
75 */
76 u_int16_t from_port;
77
78 /**
79 * end of port range
80 */
81 u_int16_t to_port;
82 };
83
84 /**
85 * internal generic constructor
86 */
87 static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts_type_t type, u_int16_t from_port, u_int16_t to_port);
88
89 /**
90 * implements traffic_selector_t.get_subset
91 */
92 static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_traffic_selector_t *other)
93 {
94 if ((this->type == TS_IPV4_ADDR_RANGE) &&
95 (other->type == TS_IPV4_ADDR_RANGE) &&
96 (this->protocol == other->protocol))
97 {
98 u_int32_t from_addr, to_addr;
99 u_int16_t from_port, to_port;
100 private_traffic_selector_t *new_ts;
101
102 /* calculate the maximum address range allowed for both */
103 from_addr = max(this->from_addr_ipv4, other->from_addr_ipv4);
104 to_addr = min(this->to_addr_ipv4, other->to_addr_ipv4);
105 if (from_addr > to_addr)
106 {
107 /* no match */
108 return NULL;
109 }
110
111 /* calculate the maximum port range allowed for both */
112 from_port = max(this->from_port, other->from_port);
113 to_port = min(this->to_port, other->to_port);
114 if (from_port > to_port)
115 {
116 /* no match */
117 return NULL;
118 }
119
120 /* got a match, return it */
121 new_ts = traffic_selector_create(this->protocol, this->type, from_port, to_port);
122 new_ts->from_addr_ipv4 = from_addr;
123 new_ts->to_addr_ipv4 = to_addr;
124 new_ts->type = TS_IPV4_ADDR_RANGE;
125 return &(new_ts->public);
126 }
127 return NULL;
128 }
129
130 /**
131 * Implements traffic_selector_t.get_from_address.
132 */
133 static chunk_t get_from_address(private_traffic_selector_t *this)
134 {
135 chunk_t from_addr = CHUNK_INITIALIZER;
136
137 switch (this->type)
138 {
139 case TS_IPV4_ADDR_RANGE:
140 {
141 u_int32_t network;
142 from_addr.len = sizeof(network);
143 from_addr.ptr = allocator_alloc(from_addr.len);
144 /* chunk must contain network order, convert! */
145 network = htonl(this->from_addr_ipv4);
146 memcpy(from_addr.ptr, &network, from_addr.len);
147 break;
148 }
149 case TS_IPV6_ADDR_RANGE:
150 {
151 break;
152 }
153 }
154 return from_addr;
155 }
156
157 /**
158 * Implements traffic_selector_t.get_to_address.
159 */
160 static chunk_t get_to_address(private_traffic_selector_t *this)
161 {
162 chunk_t to_addr = CHUNK_INITIALIZER;
163
164 switch (this->type)
165 {
166 case TS_IPV4_ADDR_RANGE:
167 {
168 u_int32_t network;
169 to_addr.len = sizeof(network);
170 to_addr.ptr = allocator_alloc(to_addr.len);
171 /* chunk must contain network order, convert! */
172 network = htonl(this->to_addr_ipv4);
173 memcpy(to_addr.ptr, &network, to_addr.len);
174 break;
175 }
176 case TS_IPV6_ADDR_RANGE:
177 {
178 break;
179 }
180 }
181 return to_addr;
182 }
183
184 /**
185 * Implements traffic_selector_t.get_from_port.
186 */
187 static u_int16_t get_from_port(private_traffic_selector_t *this)
188 {
189 return this->from_port;
190 }
191
192 /**
193 * Implements traffic_selector_t.get_to_port.
194 */
195 static u_int16_t get_to_port(private_traffic_selector_t *this)
196 {
197 return this->to_port;
198 }
199
200 /**
201 * Implements traffic_selector_t.clone.
202 */
203 static traffic_selector_t *clone(private_traffic_selector_t *this)
204 {
205 private_traffic_selector_t *clone = traffic_selector_create(this->protocol, this->type, this->from_port, this->to_port);
206 clone->type = this->type;
207 switch (clone->type)
208 {
209 case TS_IPV4_ADDR_RANGE:
210 {
211 clone->from_addr_ipv4 = this->from_addr_ipv4;
212 clone->to_addr_ipv4 = this->to_addr_ipv4;
213 return &(clone->public);
214 }
215 case TS_IPV6_ADDR_RANGE:
216 default:
217 {
218 allocator_free(this);
219 return NULL;
220 }
221 }
222 }
223
224 /**
225 * Implements traffic_selector_t.destroy.
226 */
227 static void destroy(private_traffic_selector_t *this)
228 {
229 allocator_free(this);
230 }
231
232 /*
233 * see header
234 */
235 traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from_addr, int16_t from_port, chunk_t to_addr, u_int16_t to_port)
236 {
237 private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
238
239 this->type = type;
240 switch (type)
241 {
242 case TS_IPV4_ADDR_RANGE:
243 {
244 if (from_addr.len != 4 || to_addr.len != 4)
245 {
246 allocator_free(this);
247 return NULL;
248 }
249 /* chunk contains network order, convert! */
250 this->from_addr_ipv4 = ntohl(*((u_int32_t*)from_addr.ptr));
251 this->to_addr_ipv4 = ntohl(*((u_int32_t*)to_addr.ptr));
252 break;
253 }
254 case TS_IPV6_ADDR_RANGE:
255 default:
256 {
257 allocator_free(this);
258 return NULL;
259 }
260 }
261 return (&this->public);
262 }
263
264
265 /*
266 * Described in header-file
267 */
268 traffic_selector_t *traffic_selector_create_from_string(u_int8_t protocol, ts_type_t type, char *from_addr, u_int16_t from_port, char *to_addr, u_int16_t to_port)
269 {
270 private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
271
272 /* public functions */
273 this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
274 this->public.destroy = (void(*)(traffic_selector_t*))destroy;
275
276 this->type = type;
277 switch (type)
278 {
279 case TS_IPV4_ADDR_RANGE:
280 {
281 if (inet_aton(from_addr, (struct in_addr*)&(this->from_addr_ipv4)) == 0)
282 {
283 allocator_free(this);
284 return NULL;
285 }
286 if (inet_aton(to_addr, (struct in_addr*)&(this->to_addr_ipv4)) == 0)
287 {
288 allocator_free(this);
289 return NULL;
290 }
291 /* convert to host order, inet_aton has network order */
292 this->from_addr_ipv4 = ntohl(this->from_addr_ipv4);
293 this->to_addr_ipv4 = ntohl(this->to_addr_ipv4);
294 break;
295 }
296 case TS_IPV6_ADDR_RANGE:
297 {
298 allocator_free(this);
299 return NULL;
300 }
301 }
302
303 return (&this->public);
304 }
305
306 /*
307 * see declaration
308 */
309 static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, ts_type_t type, u_int16_t from_port, u_int16_t to_port)
310 {
311 private_traffic_selector_t *this = allocator_alloc_thing(private_traffic_selector_t);
312
313 /* public functions */
314 this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
315 this->public.get_from_address = (chunk_t(*)(traffic_selector_t*))get_from_address;
316 this->public.get_to_address = (chunk_t(*)(traffic_selector_t*))get_to_address;
317 this->public.get_from_port = (u_int16_t(*)(traffic_selector_t*))get_from_port;
318 this->public.get_to_port = (u_int16_t(*)(traffic_selector_t*))get_to_port;
319 this->public.clone = (traffic_selector_t*(*)(traffic_selector_t*))clone;
320 this->public.destroy = (void(*)(traffic_selector_t*))destroy;
321
322 this->from_port = from_port;
323 this->to_port = to_port;
324 this->protocol = protocol;
325 this->type = type;
326
327 return this;
328 }
329