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