- first attempt for connection loading and starting via "stroke"
[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 #include <arpa/inet.h>
29
30 typedef struct private_traffic_selector_t private_traffic_selector_t;
31
32 /**
33 * Private data of an traffic_selector_t object
34 */
35 struct private_traffic_selector_t {
36
37 /**
38 * Public part
39 */
40 traffic_selector_t public;
41
42 /**
43 * Type of address
44 */
45 ts_type_t type;
46
47 /**
48 * IP protocol (UDP, TCP, ICMP, ...)
49 */
50 u_int8_t protocol;
51
52 /**
53 * begin of address range, host order
54 */
55 union {
56 u_int32_t from_addr_ipv4;
57 };
58
59 /**
60 * end of address range, host order
61 */
62 union {
63 u_int32_t to_addr_ipv4;
64 };
65
66 /**
67 * begin of port range
68 */
69 u_int16_t from_port;
70
71 /**
72 * end of port range
73 */
74 u_int16_t to_port;
75 };
76
77 /**
78 * internal generic constructor
79 */
80 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);
81
82 /**
83 * implements traffic_selector_t.get_subset
84 */
85 static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_traffic_selector_t *other)
86 {
87 if ((this->type == TS_IPV4_ADDR_RANGE) &&
88 (other->type == TS_IPV4_ADDR_RANGE) &&
89 (this->protocol == other->protocol))
90 {
91 u_int32_t from_addr, to_addr;
92 u_int16_t from_port, to_port;
93 private_traffic_selector_t *new_ts;
94
95 /* calculate the maximum address range allowed for both */
96 from_addr = max(this->from_addr_ipv4, other->from_addr_ipv4);
97 to_addr = min(this->to_addr_ipv4, other->to_addr_ipv4);
98 if (from_addr > to_addr)
99 {
100 /* no match */
101 return NULL;
102 }
103
104 /* calculate the maximum port range allowed for both */
105 from_port = max(this->from_port, other->from_port);
106 to_port = min(this->to_port, other->to_port);
107 if (from_port > to_port)
108 {
109 /* no match */
110 return NULL;
111 }
112
113 /* got a match, return it */
114 new_ts = traffic_selector_create(this->protocol, this->type, from_port, to_port);
115 new_ts->from_addr_ipv4 = from_addr;
116 new_ts->to_addr_ipv4 = to_addr;
117 new_ts->type = TS_IPV4_ADDR_RANGE;
118 return &(new_ts->public);
119 }
120 return NULL;
121 }
122
123 /**
124 * Implements traffic_selector_t.get_from_address.
125 */
126 static chunk_t get_from_address(private_traffic_selector_t *this)
127 {
128 chunk_t from_addr = CHUNK_INITIALIZER;
129
130 switch (this->type)
131 {
132 case TS_IPV4_ADDR_RANGE:
133 {
134 u_int32_t network;
135 from_addr.len = sizeof(network);
136 from_addr.ptr = allocator_alloc(from_addr.len);
137 /* chunk must contain network order, convert! */
138 network = htonl(this->from_addr_ipv4);
139 memcpy(from_addr.ptr, &network, from_addr.len);
140 break;
141 }
142 case TS_IPV6_ADDR_RANGE:
143 {
144 break;
145 }
146 }
147 return from_addr;
148 }
149
150 /**
151 * Implements traffic_selector_t.get_to_address.
152 */
153 static chunk_t get_to_address(private_traffic_selector_t *this)
154 {
155 chunk_t to_addr = CHUNK_INITIALIZER;
156
157 switch (this->type)
158 {
159 case TS_IPV4_ADDR_RANGE:
160 {
161 u_int32_t network;
162 to_addr.len = sizeof(network);
163 to_addr.ptr = allocator_alloc(to_addr.len);
164 /* chunk must contain network order, convert! */
165 network = htonl(this->to_addr_ipv4);
166 memcpy(to_addr.ptr, &network, to_addr.len);
167 break;
168 }
169 case TS_IPV6_ADDR_RANGE:
170 {
171 break;
172 }
173 }
174 return to_addr;
175 }
176
177 /**
178 * Implements traffic_selector_t.get_from_port.
179 */
180 static u_int16_t get_from_port(private_traffic_selector_t *this)
181 {
182 return this->from_port;
183 }
184
185 /**
186 * Implements traffic_selector_t.get_to_port.
187 */
188 static u_int16_t get_to_port(private_traffic_selector_t *this)
189 {
190 return this->to_port;
191 }
192
193 /**
194 * Implements traffic_selector_t.get_type.
195 */
196 static ts_type_t get_type(private_traffic_selector_t *this)
197 {
198 return this->type;
199 }
200
201 /**
202 * Implements traffic_selector_t.get_protocol.
203 */
204 static u_int8_t get_protocol(private_traffic_selector_t *this)
205 {
206 return this->protocol;
207 }
208
209 /**
210 * Implements traffic_selector_t.get_netmask.
211 */
212 static u_int8_t get_netmask(private_traffic_selector_t *this)
213 {
214 switch (this->type)
215 {
216 case TS_IPV4_ADDR_RANGE:
217 {
218 u_int32_t from, to, bit;
219 from = htonl(this->from_addr_ipv4);
220 to = htonl(this->to_addr_ipv4);
221 printf("%x - %x\n", from, to);
222 for (bit = 0; bit < 32; bit++)
223 {
224 if ((1<<bit & from) != (1<<bit & to))
225 {
226 return bit;
227 }
228 }
229 return 0;
230 }
231 case TS_IPV6_ADDR_RANGE:
232 default:
233 {
234 return 0;
235 }
236 }
237 }
238
239 /**
240 * Implements traffic_selector_t.clone.
241 */
242 static traffic_selector_t *clone(private_traffic_selector_t *this)
243 {
244 private_traffic_selector_t *clone = traffic_selector_create(this->protocol, this->type, this->from_port, this->to_port);
245 clone->type = this->type;
246 switch (clone->type)
247 {
248 case TS_IPV4_ADDR_RANGE:
249 {
250 clone->from_addr_ipv4 = this->from_addr_ipv4;
251 clone->to_addr_ipv4 = this->to_addr_ipv4;
252 return &(clone->public);
253 }
254 case TS_IPV6_ADDR_RANGE:
255 default:
256 {
257 allocator_free(this);
258 return NULL;
259 }
260 }
261 }
262
263 /**
264 * Implements traffic_selector_t.destroy.
265 */
266 static void destroy(private_traffic_selector_t *this)
267 {
268 allocator_free(this);
269 }
270
271 /*
272 * see header
273 */
274 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)
275 {
276 private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
277
278 this->type = type;
279 switch (type)
280 {
281 case TS_IPV4_ADDR_RANGE:
282 {
283 if (from_addr.len != 4 || to_addr.len != 4)
284 {
285 allocator_free(this);
286 return NULL;
287 }
288 /* chunk contains network order, convert! */
289 this->from_addr_ipv4 = ntohl(*((u_int32_t*)from_addr.ptr));
290 this->to_addr_ipv4 = ntohl(*((u_int32_t*)to_addr.ptr));
291 break;
292 }
293 case TS_IPV6_ADDR_RANGE:
294 default:
295 {
296 allocator_free(this);
297 return NULL;
298 }
299 }
300 return (&this->public);
301 }
302
303 /*
304 * see header
305 */
306 traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t netbits)
307 {
308 private_traffic_selector_t *this = traffic_selector_create(0, 0, 0, 65535);
309
310 switch (net->get_family(net))
311 {
312 case AF_INET:
313 {
314 chunk_t from;
315
316 this->type = TS_IPV4_ADDR_RANGE;
317 from = net->get_address_as_chunk(net);
318 this->from_addr_ipv4 = ntohl(*((u_int32_t*)from.ptr));
319 this->to_addr_ipv4 = this->from_addr_ipv4 | ((1 << (32 - netbits)) - 1);
320 allocator_free_chunk(&from);
321 break;
322 }
323 case AF_INET6:
324 default:
325 {
326 allocator_free(this);
327 return NULL;
328 }
329 }
330 return (&this->public);
331 }
332
333 /*
334 * see header
335 */
336 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)
337 {
338 private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
339
340 /* public functions */
341 this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
342 this->public.destroy = (void(*)(traffic_selector_t*))destroy;
343
344 this->type = type;
345 switch (type)
346 {
347 case TS_IPV4_ADDR_RANGE:
348 {
349 if (inet_aton(from_addr, (struct in_addr*)&(this->from_addr_ipv4)) == 0)
350 {
351 allocator_free(this);
352 return NULL;
353 }
354 if (inet_aton(to_addr, (struct in_addr*)&(this->to_addr_ipv4)) == 0)
355 {
356 allocator_free(this);
357 return NULL;
358 }
359 /* convert to host order, inet_aton has network order */
360 this->from_addr_ipv4 = ntohl(this->from_addr_ipv4);
361 this->to_addr_ipv4 = ntohl(this->to_addr_ipv4);
362 break;
363 }
364 case TS_IPV6_ADDR_RANGE:
365 {
366 allocator_free(this);
367 return NULL;
368 }
369 }
370
371 return (&this->public);
372 }
373
374 /*
375 * see declaration
376 */
377 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)
378 {
379 private_traffic_selector_t *this = allocator_alloc_thing(private_traffic_selector_t);
380
381 /* public functions */
382 this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
383 this->public.get_from_address = (chunk_t(*)(traffic_selector_t*))get_from_address;
384 this->public.get_to_address = (chunk_t(*)(traffic_selector_t*))get_to_address;
385 this->public.get_from_port = (u_int16_t(*)(traffic_selector_t*))get_from_port;
386 this->public.get_to_port = (u_int16_t(*)(traffic_selector_t*))get_to_port;
387 this->public.get_type = (ts_type_t(*)(traffic_selector_t*))get_type;
388 this->public.get_protocol = (u_int8_t(*)(traffic_selector_t*))get_protocol;
389 this->public.get_netmask = (u_int8_t(*)(traffic_selector_t*))get_netmask;
390 this->public.clone = (traffic_selector_t*(*)(traffic_selector_t*))clone;
391 this->public.destroy = (void(*)(traffic_selector_t*))destroy;
392
393 this->from_port = from_port;
394 this->to_port = to_port;
395 this->protocol = protocol;
396 this->type = type;
397
398 return this;
399 }