cosmetics
[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-2006 Martin Willi
10 * Copyright (C) 2005 Jan Hutter
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include <arpa/inet.h>
25 #include <string.h>
26 #include <netdb.h>
27 #include <stdio.h>
28 #include <printf.h>
29
30 #include "traffic_selector.h"
31
32 #include <utils/linked_list.h>
33 #include <utils/identification.h>
34
35 ENUM(ts_type_name, TS_IPV4_ADDR_RANGE, TS_IPV6_ADDR_RANGE,
36 "TS_IPV4_ADDR_RANGE",
37 "TS_IPV6_ADDR_RANGE",
38 );
39
40 typedef struct private_traffic_selector_t private_traffic_selector_t;
41
42 /**
43 * Private data of an traffic_selector_t object
44 */
45 struct private_traffic_selector_t {
46
47 /**
48 * Public part
49 */
50 traffic_selector_t public;
51
52 /**
53 * Type of address
54 */
55 ts_type_t type;
56
57 /**
58 * IP protocol (UDP, TCP, ICMP, ...)
59 */
60 u_int8_t protocol;
61
62 /**
63 * begin of address range, network order
64 */
65 union {
66 /** dummy char for common address manipulation */
67 char from[0];
68 /** IPv4 address */
69 u_int32_t from4[1];
70 /** IPv6 address */
71 u_int32_t from6[4];
72 };
73
74 /**
75 * end of address range, network order
76 */
77 union {
78 /** dummy char for common address manipulation */
79 char to[0];
80 /** IPv4 address */
81 u_int32_t to4[1];
82 /** IPv6 address */
83 u_int32_t to6[4];
84 };
85
86 /**
87 * begin of port range
88 */
89 u_int16_t from_port;
90
91 /**
92 * end of port range
93 */
94 u_int16_t to_port;
95 };
96
97 /**
98 * calculate to "to"-address for the "from" address and a subnet size
99 */
100 static void calc_range(private_traffic_selector_t *this, u_int8_t netbits)
101 {
102 int byte;
103 size_t size = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
104
105 /* go through the from address, starting at the tail. While we
106 * have not processed the bits belonging to the host, set them to 1 on
107 * the to address. If we reach the bits for the net, copy them from "from". */
108 for (byte = size - 1; byte >=0; byte--)
109 {
110 u_char mask = 0x00;
111 int shift;
112
113 shift = (byte+1) * 8 - netbits;
114 if (shift > 0)
115 {
116 mask = 1 << shift;
117 if (mask != 0xFF)
118 {
119 mask--;
120 }
121 }
122 this->to[byte] = this->from[byte] | mask;
123 }
124 }
125
126 /**
127 * calculate to subnet size from "to"- and "from"-address
128 */
129 static u_int8_t calc_netbits(private_traffic_selector_t *this)
130 {
131 int byte, bit;
132 size_t size = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
133
134 /* go trough all bits of the addresses, begging in the front.
135 * As longer as they equal, the subnet gets larger */
136 for (byte = 0; byte < size; byte++)
137 {
138 for (bit = 7; bit >= 0; bit--)
139 {
140 if ((1<<bit & this->from[byte]) != (1<<bit & this->to[byte]))
141 {
142 return ((7 - bit) + (byte * 8));
143 }
144 }
145 }
146 /* single host, netmask is 32/128 */
147 return (size * 8);
148 }
149
150 /**
151 * internal generic constructor
152 */
153 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);
154
155 /**
156 * output handler in printf()
157 */
158 static int print(FILE *stream, const struct printf_info *info,
159 const void *const *args)
160 {
161 private_traffic_selector_t *this = *((private_traffic_selector_t**)(args[0]));
162 char addr_str[INET6_ADDRSTRLEN] = "";
163 u_int8_t mask;
164 struct protoent *proto;
165 struct servent *serv;
166 char *serv_proto = NULL;
167 bool has_proto = FALSE;
168 size_t written = 0;
169
170 if (this == NULL)
171 {
172 return fprintf(stream, "(null)");
173 }
174
175 if (this->type == TS_IPV4_ADDR_RANGE)
176 {
177 inet_ntop(AF_INET, &this->from4, addr_str, sizeof(addr_str));
178 }
179 else
180 {
181 inet_ntop(AF_INET6, &this->from6, addr_str, sizeof(addr_str));
182 }
183 mask = calc_netbits(this);
184
185 written += fprintf(stream, "%s/%d", addr_str, mask);
186
187 /* build protocol string */
188 if (this->protocol)
189 {
190 proto = getprotobynumber(this->protocol);
191 if (proto)
192 {
193 written += fprintf(stream, "[%s", proto->p_name);
194 serv_proto = proto->p_name;
195 }
196 else
197 {
198 written += fprintf(stream, "[%d", this->protocol);
199 }
200 has_proto = TRUE;
201 }
202
203 /* build port string */
204 if (this->from_port == this->to_port)
205 {
206 if (has_proto)
207 {
208 written += fprintf(stream, "/");
209 }
210 else
211 {
212 written += fprintf(stream, "[");
213 }
214 serv = getservbyport(htons(this->from_port), serv_proto);
215 if (serv)
216 {
217 written += fprintf(stream, "%s]", serv->s_name);
218 }
219 else
220 {
221 written += fprintf(stream, "%d]", this->from_port);
222 }
223 }
224 else if (!(this->from_port == 0 && this->to_port == 0xFFFF))
225 {
226 if (has_proto)
227 {
228 written += fprintf(stream, "/");
229 }
230 else
231 {
232 written += fprintf(stream, "[");
233 }
234 written += fprintf(stream, "%d-%d]", this->from_port, this->to_port);
235 }
236
237 return written;
238 }
239
240 /**
241 * register printf() handlers
242 */
243 static void __attribute__ ((constructor))print_register()
244 {
245 register_printf_function(PRINTF_TRAFFIC_SELECTOR, print, arginfo_ptr);
246 }
247
248 /**
249 * implements traffic_selector_t.get_subset
250 */
251 static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_traffic_selector_t *other)
252 {
253 if (this->type == other->type && (this->protocol == other->protocol ||
254 this->protocol == 0 || other->protocol == 0))
255 {
256 u_int16_t from_port, to_port;
257 u_char *from, *to;
258 u_int8_t protocol;
259 size_t size;
260 private_traffic_selector_t *new_ts;
261
262 /* calculate the maximum port range allowed for both */
263 from_port = max(this->from_port, other->from_port);
264 to_port = min(this->to_port, other->to_port);
265 if (from_port > to_port)
266 {
267 return NULL;
268 }
269 /* select protocol, which is not zero */
270 protocol = max(this->protocol, other->protocol);
271
272 switch (this->type)
273 {
274 case TS_IPV4_ADDR_RANGE:
275 size = sizeof(this->from4);
276 break;
277 case TS_IPV6_ADDR_RANGE:
278 size = sizeof(this->from6);
279 break;
280 default:
281 return NULL;
282 }
283
284 /* get higher from-address */
285 if (memcmp(this->from, other->from, size) > 0)
286 {
287 from = this->from;
288 }
289 else
290 {
291 from = other->from;
292 }
293 /* get lower to-address */
294 if (memcmp(this->to, other->to, size) > 0)
295 {
296 to = other->to;
297 }
298 else
299 {
300 to = this->to;
301 }
302 /* if "from" > "to", we don't have a match */
303 if (memcmp(from, to, size) > 0)
304 {
305 return NULL;
306 }
307
308 /* we have a match in protocol, port, and address: return it... */
309 new_ts = traffic_selector_create(protocol, this->type, from_port, to_port);
310 new_ts->type = this->type;
311 memcpy(new_ts->from, from, size);
312 memcpy(new_ts->to, to, size);
313
314 return &new_ts->public;
315 }
316 return NULL;
317 }
318
319 /**
320 * implements traffic_selector_t.equals
321 */
322 static bool equals(private_traffic_selector_t *this, private_traffic_selector_t *other)
323 {
324 if (this->type != other->type)
325 {
326 return FALSE;
327 }
328 if (!(this->from_port == other->from_port &&
329 this->to_port == other->to_port &&
330 this->protocol == other->protocol))
331 {
332 return FALSE;
333 }
334 switch (this->type)
335 {
336 case TS_IPV4_ADDR_RANGE:
337 if (memeq(this->from4, other->from4, sizeof(this->from4)))
338 {
339 return TRUE;
340 }
341 break;
342 case TS_IPV6_ADDR_RANGE:
343 if (memeq(this->from6, other->from6, sizeof(this->from6)))
344 {
345 return TRUE;
346 }
347 break;
348 default:
349 break;
350 }
351 return FALSE;
352 }
353
354 /**
355 * Implements traffic_selector_t.get_from_address.
356 */
357 static chunk_t get_from_address(private_traffic_selector_t *this)
358 {
359 chunk_t from = chunk_empty;
360
361 switch (this->type)
362 {
363 case TS_IPV4_ADDR_RANGE:
364 {
365 from.len = sizeof(this->from4);
366 from.ptr = malloc(from.len);
367 memcpy(from.ptr, this->from4, from.len);
368 break;
369 }
370 case TS_IPV6_ADDR_RANGE:
371 {
372 from.len = sizeof(this->from6);
373 from.ptr = malloc(from.len);
374 memcpy(from.ptr, this->from6, from.len);
375 break;
376 }
377 }
378 return from;
379 }
380
381 /**
382 * Implements traffic_selector_t.get_to_address.
383 */
384 static chunk_t get_to_address(private_traffic_selector_t *this)
385 {
386 chunk_t to = chunk_empty;
387
388 switch (this->type)
389 {
390 case TS_IPV4_ADDR_RANGE:
391 {
392 to.len = sizeof(this->to4);
393 to.ptr = malloc(to.len);
394 memcpy(to.ptr, this->to4, to.len);
395 break;
396 }
397 case TS_IPV6_ADDR_RANGE:
398 {
399 to.len = sizeof(this->to6);
400 to.ptr = malloc(to.len);
401 memcpy(to.ptr, this->to6, to.len);
402 break;
403 }
404 }
405 return to;
406 }
407
408 /**
409 * Implements traffic_selector_t.get_from_port.
410 */
411 static u_int16_t get_from_port(private_traffic_selector_t *this)
412 {
413 return this->from_port;
414 }
415
416 /**
417 * Implements traffic_selector_t.get_to_port.
418 */
419 static u_int16_t get_to_port(private_traffic_selector_t *this)
420 {
421 return this->to_port;
422 }
423
424 /**
425 * Implements traffic_selector_t.get_type.
426 */
427 static ts_type_t get_type(private_traffic_selector_t *this)
428 {
429 return this->type;
430 }
431
432 /**
433 * Implements traffic_selector_t.get_protocol.
434 */
435 static u_int8_t get_protocol(private_traffic_selector_t *this)
436 {
437 return this->protocol;
438 }
439
440 /**
441 * Implements traffic_selector_t.is_host.
442 */
443 static bool is_host(private_traffic_selector_t *this, host_t *host)
444 {
445 chunk_t addr;
446 int family = host->get_family(host);
447
448 if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
449 (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
450 {
451 addr = host->get_address(host);
452 if (memeq(addr.ptr, this->from, addr.len) &&
453 memeq(addr.ptr, this->to, addr.len))
454 {
455 return TRUE;
456 }
457 }
458 return FALSE;
459 }
460
461 /**
462 * Implements traffic_selector_t.update_address_range.
463 */
464 static void update_address_range(private_traffic_selector_t *this, host_t *host)
465 {
466 if ((this->type == TS_IPV4_ADDR_RANGE && this->from4[0] == 0) ||
467 (this->type == TS_IPV6_ADDR_RANGE && this->from6[0] == 0 &&
468 this->from6[1] == 0 && this->from6[2] == 0 && this->from6[3] == 0))
469 {
470 this->type = host->get_family(host) == AF_INET ?
471 TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE;
472
473 chunk_t from = host->get_address(host);
474 memcpy(this->from, from.ptr, from.len);
475 memcpy(this->to, from.ptr, from.len);
476 }
477 }
478
479 /**
480 * Implements traffic_selector_t.clone.
481 */
482 static traffic_selector_t *clone_(private_traffic_selector_t *this)
483 {
484 private_traffic_selector_t *clone;
485
486 clone = traffic_selector_create(this->protocol, this->type,
487 this->from_port, this->to_port);
488 switch (clone->type)
489 {
490 case TS_IPV4_ADDR_RANGE:
491 {
492 memcpy(clone->from4, this->from4, sizeof(this->from4));
493 memcpy(clone->to4, this->to4, sizeof(this->to4));
494 return &clone->public;
495 }
496 case TS_IPV6_ADDR_RANGE:
497 {
498 memcpy(clone->from6, this->from6, sizeof(this->from6));
499 memcpy(clone->to6, this->to6, sizeof(this->to6));
500 return &clone->public;
501 }
502 default:
503 {
504 /* unreachable */
505 return &clone->public;
506 }
507 }
508 }
509
510 /**
511 * Implements traffic_selector_t.destroy.
512 */
513 static void destroy(private_traffic_selector_t *this)
514 {
515 free(this);
516 }
517
518 /*
519 * see header
520 */
521 traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol, ts_type_t type, chunk_t from, u_int16_t from_port, chunk_t to, u_int16_t to_port)
522 {
523 private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
524
525 switch (type)
526 {
527 case TS_IPV4_ADDR_RANGE:
528 {
529 if (from.len != 4 || to.len != 4)
530 {
531 free(this);
532 return NULL;
533 }
534 memcpy(this->from4, from.ptr, from.len);
535 memcpy(this->to4, to.ptr, to.len);
536 break;
537 }
538 case TS_IPV6_ADDR_RANGE:
539 {
540 if (from.len != 16 || to.len != 16)
541 {
542 free(this);
543 return NULL;
544 }
545 memcpy(this->from6, from.ptr, from.len);
546 memcpy(this->to6, to.ptr, to.len);
547 break;
548 }
549 default:
550 {
551 free(this);
552 return NULL;
553 }
554 }
555 return (&this->public);
556 }
557
558 /*
559 * see header
560 */
561 traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, u_int8_t netbits, u_int8_t protocol, u_int16_t port)
562 {
563 private_traffic_selector_t *this = traffic_selector_create(protocol, 0, 0, 65535);
564
565 switch (net->get_family(net))
566 {
567 case AF_INET:
568 {
569 chunk_t from;
570
571 this->type = TS_IPV4_ADDR_RANGE;
572 from = net->get_address(net);
573 memcpy(this->from4, from.ptr, from.len);
574 if (this->from4[0] == 0)
575 {
576 /* use /0 for 0.0.0.0 */
577 this->to4[0] = ~0;
578 }
579 else
580 {
581 calc_range(this, netbits);
582 }
583 break;
584 }
585 case AF_INET6:
586 {
587 chunk_t from;
588
589 this->type = TS_IPV6_ADDR_RANGE;
590 from = net->get_address(net);
591 memcpy(this->from6, from.ptr, from.len);
592 if (this->from6[0] == 0 && this->from6[1] == 0 &&
593 this->from6[2] == 0 && this->from6[3] == 0)
594 {
595 /* use /0 for ::0 */
596 this->to6[0] = ~0;
597 this->to6[1] = ~0;
598 this->to6[2] = ~0;
599 this->to6[3] = ~0;
600 }
601 else
602 {
603 calc_range(this, netbits);
604 }
605 break;
606 }
607 default:
608 {
609 free(this);
610 return NULL;
611 }
612 }
613 if (port)
614 {
615 this->from_port = port;
616 this->to_port = port;
617 }
618 return (&this->public);
619 }
620
621 /*
622 * see header
623 */
624 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)
625 {
626 private_traffic_selector_t *this = traffic_selector_create(protocol, type, from_port, to_port);
627
628 /* public functions */
629 this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
630 this->public.destroy = (void(*)(traffic_selector_t*))destroy;
631
632 this->type = type;
633 switch (type)
634 {
635 case TS_IPV4_ADDR_RANGE:
636 {
637 if (inet_pton(AF_INET, from_addr, (struct in_addr*)this->from4) < 0)
638 {
639 free(this);
640 return NULL;
641 }
642 if (inet_pton(AF_INET, to_addr, (struct in_addr*)this->to4) < 0)
643 {
644 free(this);
645 return NULL;
646 }
647 break;
648 }
649 case TS_IPV6_ADDR_RANGE:
650 {
651 if (inet_pton(AF_INET6, from_addr, (struct in6_addr*)this->from6) < 0)
652 {
653 free(this);
654 return NULL;
655 }
656 if (inet_pton(AF_INET6, to_addr, (struct in6_addr*)this->to6) < 0)
657 {
658 free(this);
659 return NULL;
660 }
661 break;
662 }
663 }
664 return (&this->public);
665 }
666
667 /*
668 * see declaration
669 */
670 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)
671 {
672 private_traffic_selector_t *this = malloc_thing(private_traffic_selector_t);
673
674 /* public functions */
675 this->public.get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset;
676 this->public.equals = (bool(*)(traffic_selector_t*,traffic_selector_t*))equals;
677 this->public.get_from_address = (chunk_t(*)(traffic_selector_t*))get_from_address;
678 this->public.get_to_address = (chunk_t(*)(traffic_selector_t*))get_to_address;
679 this->public.get_from_port = (u_int16_t(*)(traffic_selector_t*))get_from_port;
680 this->public.get_to_port = (u_int16_t(*)(traffic_selector_t*))get_to_port;
681 this->public.get_type = (ts_type_t(*)(traffic_selector_t*))get_type;
682 this->public.get_protocol = (u_int8_t(*)(traffic_selector_t*))get_protocol;
683 this->public.is_host = (bool(*)(traffic_selector_t*,host_t*))is_host;
684 this->public.update_address_range = (void(*)(traffic_selector_t*,host_t*))update_address_range;
685 this->public.clone = (traffic_selector_t*(*)(traffic_selector_t*))clone_;
686 this->public.destroy = (void(*)(traffic_selector_t*))destroy;
687
688 this->from_port = from_port;
689 this->to_port = to_port;
690 this->protocol = protocol;
691 this->type = type;
692
693 return this;
694 }