daemon: Flush shunts before unloading plugins
[strongswan.git] / src / libstrongswan / selectors / traffic_selector.c
1 /*
2 * Copyright (C) 2007-2013 Tobias Brunner
3 * Copyright (C) 2005-2007 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include <string.h>
19 #include <stdio.h>
20
21 #include "traffic_selector.h"
22
23 #include <utils/debug.h>
24 #include <utils/utils.h>
25 #include <utils/identification.h>
26 #include <collections/linked_list.h>
27
28 #define NON_SUBNET_ADDRESS_RANGE 255
29
30 ENUM(ts_type_name, TS_IPV4_ADDR_RANGE, TS_IPV6_ADDR_RANGE,
31 "TS_IPV4_ADDR_RANGE",
32 "TS_IPV6_ADDR_RANGE",
33 );
34
35 typedef struct private_traffic_selector_t private_traffic_selector_t;
36
37 /**
38 * Private data of an traffic_selector_t object
39 */
40 struct private_traffic_selector_t {
41
42 /**
43 * Public part
44 */
45 traffic_selector_t public;
46
47 /**
48 * Type of address
49 */
50 ts_type_t type;
51
52 /**
53 * IP protocol (UDP, TCP, ICMP, ...)
54 */
55 u_int8_t protocol;
56
57 /**
58 * narrow this traffic selector to hosts external ip
59 * if set, from and to have no meaning until set_address() is called
60 */
61 bool dynamic;
62
63 /**
64 * subnet size in CIDR notation, 255 means a non-subnet address range
65 */
66 u_int8_t netbits;
67
68 /**
69 * begin of address range, network order
70 */
71 union {
72 /** dummy char for common address manipulation */
73 char from[0];
74 /** IPv4 address */
75 u_int32_t from4[1];
76 /** IPv6 address */
77 u_int32_t from6[4];
78 };
79
80 /**
81 * end of address range, network order
82 */
83 union {
84 /** dummy char for common address manipulation */
85 char to[0];
86 /** IPv4 address */
87 u_int32_t to4[1];
88 /** IPv6 address */
89 u_int32_t to6[4];
90 };
91
92 /**
93 * begin of port range
94 */
95 u_int16_t from_port;
96
97 /**
98 * end of port range
99 */
100 u_int16_t to_port;
101 };
102
103 /**
104 * calculate the "to"-address for the "from" address and a subnet size
105 */
106 static void calc_range(private_traffic_selector_t *this, u_int8_t netbits)
107 {
108 size_t len;
109 int bytes, bits;
110 u_int8_t mask;
111
112 this->netbits = netbits;
113
114 len = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
115 bytes = (netbits + 7)/8;
116 bits = (bytes * 8) - netbits;
117 mask = bits ? (1 << bits) - 1 : 0;
118
119 memcpy(this->to, this->from, bytes);
120 memset(this->from + bytes, 0x00, len - bytes);
121 memset(this->to + bytes, 0xff, len - bytes);
122 this->from[bytes-1] &= ~mask;
123 this->to[bytes-1] |= mask;
124 }
125
126 /**
127 * calculate the subnet size from the "to" and "from" addresses
128 */
129 static u_int8_t calc_netbits(private_traffic_selector_t *this)
130 {
131 int byte, bit;
132 u_int8_t netbits;
133 size_t size = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
134 bool prefix = TRUE;
135
136 /* a perfect match results in a single address with a /32 or /128 netmask */
137 netbits = (size * 8);
138 this->netbits = netbits;
139
140 /* go through all bits of the addresses, beginning in the front.
141 * as long as they are equal, the subnet gets larger
142 */
143 for (byte = 0; byte < size; byte++)
144 {
145 for (bit = 7; bit >= 0; bit--)
146 {
147 u_int8_t bitmask = 1 << bit;
148
149 if (prefix)
150 {
151 if ((bitmask & this->from[byte]) != (bitmask & this->to[byte]))
152 {
153 /* store the common prefix which might be a true subnet */
154 netbits = (7 - bit) + (byte * 8);
155 this->netbits = netbits;
156 prefix = FALSE;
157 }
158 }
159 else
160 {
161 if ((bitmask & this->from[byte]) || !(bitmask & this->to[byte]))
162 {
163 this->netbits = NON_SUBNET_ADDRESS_RANGE;
164 return netbits; /* return a pseudo subnet */
165
166 }
167 }
168 }
169 }
170 return netbits; /* return a true subnet */
171 }
172
173 /**
174 * internal generic constructor
175 */
176 static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol,
177 ts_type_t type, u_int16_t from_port, u_int16_t to_port);
178
179 /**
180 * Check if TS contains "opaque" ports
181 */
182 static bool is_opaque(private_traffic_selector_t *this)
183 {
184 return this->from_port == 0xffff && this->to_port == 0;
185 }
186
187 /**
188 * Check if TS contains "any" ports
189 */
190 static bool is_any(private_traffic_selector_t *this)
191 {
192 return this->from_port == 0 && this->to_port == 0xffff;
193 }
194
195 /**
196 * Print ICMP/ICMPv6 type and code
197 */
198 static int print_icmp(printf_hook_data_t *data, u_int16_t port)
199 {
200 u_int8_t type, code;
201
202 type = traffic_selector_icmp_type(port);
203 code = traffic_selector_icmp_code(port);
204 if (code)
205 {
206 return print_in_hook(data, "%d(%d)", type, code);
207 }
208 return print_in_hook(data, "%d", type);
209 }
210
211 /**
212 * Described in header.
213 */
214 int traffic_selector_printf_hook(printf_hook_data_t *data,
215 printf_hook_spec_t *spec, const void *const *args)
216 {
217 private_traffic_selector_t *this = *((private_traffic_selector_t**)(args[0]));
218 linked_list_t *list = *((linked_list_t**)(args[0]));
219 enumerator_t *enumerator;
220 char from_str[INET6_ADDRSTRLEN] = "";
221 char to_str[INET6_ADDRSTRLEN] = "";
222 char *serv_proto = NULL;
223 bool has_proto;
224 bool has_ports;
225 size_t written = 0;
226 u_int32_t from[4], to[4];
227
228 if (this == NULL)
229 {
230 return print_in_hook(data, "(null)");
231 }
232
233 if (spec->hash)
234 {
235 enumerator = list->create_enumerator(list);
236 while (enumerator->enumerate(enumerator, (void**)&this))
237 {
238 /* call recursivly */
239 written += print_in_hook(data, "%R ", this);
240 }
241 enumerator->destroy(enumerator);
242 return written;
243 }
244
245 memset(from, 0, sizeof(from));
246 memset(to, 0xFF, sizeof(to));
247 if (this->dynamic &&
248 memeq(this->from, from, this->type == TS_IPV4_ADDR_RANGE ? 4 : 16) &&
249 memeq(this->to, to, this->type == TS_IPV4_ADDR_RANGE ? 4 : 16))
250 {
251 written += print_in_hook(data, "dynamic");
252 }
253 else
254 {
255 if (this->type == TS_IPV4_ADDR_RANGE)
256 {
257 inet_ntop(AF_INET, &this->from4, from_str, sizeof(from_str));
258 }
259 else
260 {
261 inet_ntop(AF_INET6, &this->from6, from_str, sizeof(from_str));
262 }
263 if (this->netbits == NON_SUBNET_ADDRESS_RANGE)
264 {
265 if (this->type == TS_IPV4_ADDR_RANGE)
266 {
267 inet_ntop(AF_INET, &this->to4, to_str, sizeof(to_str));
268 }
269 else
270 {
271 inet_ntop(AF_INET6, &this->to6, to_str, sizeof(to_str));
272 }
273 written += print_in_hook(data, "%s..%s", from_str, to_str);
274 }
275 else
276 {
277 written += print_in_hook(data, "%s/%d", from_str, this->netbits);
278 }
279 }
280
281 /* check if we have protocol and/or port selectors */
282 has_proto = this->protocol != 0;
283 has_ports = !is_any(this);
284
285 if (!has_proto && !has_ports)
286 {
287 return written;
288 }
289
290 written += print_in_hook(data, "[");
291
292 /* build protocol string */
293 if (has_proto)
294 {
295 struct protoent *proto = getprotobynumber(this->protocol);
296
297 if (proto)
298 {
299 written += print_in_hook(data, "%s", proto->p_name);
300 serv_proto = proto->p_name;
301 }
302 else
303 {
304 written += print_in_hook(data, "%d", this->protocol);
305 }
306 }
307
308 if (has_proto && has_ports)
309 {
310 written += print_in_hook(data, "/");
311 }
312
313 /* build port string */
314 if (has_ports)
315 {
316 if (this->from_port == this->to_port)
317 {
318 struct servent *serv;
319
320 if (this->protocol == IPPROTO_ICMP ||
321 this->protocol == IPPROTO_ICMPV6)
322 {
323 written += print_icmp(data, this->from_port);
324 }
325 else
326 {
327 serv = getservbyport(htons(this->from_port), serv_proto);
328 if (serv)
329 {
330 written += print_in_hook(data, "%s", serv->s_name);
331 }
332 else
333 {
334 written += print_in_hook(data, "%d", this->from_port);
335 }
336 }
337 }
338 else if (is_opaque(this))
339 {
340 written += print_in_hook(data, "OPAQUE");
341 }
342 else if (this->protocol == IPPROTO_ICMP ||
343 this->protocol == IPPROTO_ICMPV6)
344 {
345 written += print_icmp(data, this->from_port);
346 written += print_in_hook(data, "-");
347 written += print_icmp(data, this->to_port);
348 }
349 else
350 {
351 written += print_in_hook(data, "%d-%d",
352 this->from_port, this->to_port);
353 }
354 }
355
356 written += print_in_hook(data, "]");
357
358 return written;
359 }
360
361 METHOD(traffic_selector_t, get_subset, traffic_selector_t*,
362 private_traffic_selector_t *this, traffic_selector_t *other_public)
363 {
364 private_traffic_selector_t *other, *subset;
365 u_int16_t from_port, to_port;
366 u_char *from, *to;
367 u_int8_t protocol;
368 size_t size;
369
370 other = (private_traffic_selector_t*)other_public;
371
372 if (this->dynamic || other->dynamic)
373 { /* no set_address() applied, TS has no subset */
374 return NULL;
375 }
376
377 if (this->type != other->type)
378 {
379 return NULL;
380 }
381 switch (this->type)
382 {
383 case TS_IPV4_ADDR_RANGE:
384 size = sizeof(this->from4);
385 break;
386 case TS_IPV6_ADDR_RANGE:
387 size = sizeof(this->from6);
388 break;
389 default:
390 return NULL;
391 }
392
393 if (this->protocol != other->protocol &&
394 this->protocol != 0 && other->protocol != 0)
395 {
396 return NULL;
397 }
398 /* select protocol, which is not zero */
399 protocol = max(this->protocol, other->protocol);
400
401 if ((is_opaque(this) && is_opaque(other)) ||
402 (is_opaque(this) && is_any(other)) ||
403 (is_opaque(other) && is_any(this)))
404 {
405 from_port = 0xffff;
406 to_port = 0;
407 }
408 else
409 {
410 /* calculate the maximum port range allowed for both */
411 from_port = max(this->from_port, other->from_port);
412 to_port = min(this->to_port, other->to_port);
413 if (from_port > to_port)
414 {
415 return NULL;
416 }
417 }
418 /* get higher from-address */
419 if (memcmp(this->from, other->from, size) > 0)
420 {
421 from = this->from;
422 }
423 else
424 {
425 from = other->from;
426 }
427 /* get lower to-address */
428 if (memcmp(this->to, other->to, size) > 0)
429 {
430 to = other->to;
431 }
432 else
433 {
434 to = this->to;
435 }
436 /* if "from" > "to", we don't have a match */
437 if (memcmp(from, to, size) > 0)
438 {
439 return NULL;
440 }
441
442 /* we have a match in protocol, port, and address: return it... */
443 subset = traffic_selector_create(protocol, this->type, from_port, to_port);
444 memcpy(subset->from, from, size);
445 memcpy(subset->to, to, size);
446 calc_netbits(subset);
447
448 return &subset->public;
449 }
450
451 METHOD(traffic_selector_t, equals, bool,
452 private_traffic_selector_t *this, traffic_selector_t *other)
453 {
454 return traffic_selector_cmp(&this->public, other, NULL) == 0;
455 }
456
457 METHOD(traffic_selector_t, get_from_address, chunk_t,
458 private_traffic_selector_t *this)
459 {
460 switch (this->type)
461 {
462 case TS_IPV4_ADDR_RANGE:
463 return chunk_create(this->from, sizeof(this->from4));
464 case TS_IPV6_ADDR_RANGE:
465 return chunk_create(this->from, sizeof(this->from6));
466 default:
467 return chunk_empty;
468 }
469 }
470
471 METHOD(traffic_selector_t, get_to_address, chunk_t,
472 private_traffic_selector_t *this)
473 {
474 switch (this->type)
475 {
476 case TS_IPV4_ADDR_RANGE:
477 return chunk_create(this->to, sizeof(this->to4));
478 case TS_IPV6_ADDR_RANGE:
479 return chunk_create(this->to, sizeof(this->to6));
480 default:
481 return chunk_empty;
482 }
483 }
484
485 METHOD(traffic_selector_t, get_from_port, u_int16_t,
486 private_traffic_selector_t *this)
487 {
488 return this->from_port;
489 }
490
491 METHOD(traffic_selector_t, get_to_port, u_int16_t,
492 private_traffic_selector_t *this)
493 {
494 return this->to_port;
495 }
496
497 METHOD(traffic_selector_t, get_type, ts_type_t,
498 private_traffic_selector_t *this)
499 {
500 return this->type;
501 }
502
503 METHOD(traffic_selector_t, get_protocol, u_int8_t,
504 private_traffic_selector_t *this)
505 {
506 return this->protocol;
507 }
508
509 METHOD(traffic_selector_t, is_host, bool,
510 private_traffic_selector_t *this, host_t *host)
511 {
512 if (host)
513 {
514 chunk_t addr;
515 int family = host->get_family(host);
516
517 if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
518 (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
519 {
520 addr = host->get_address(host);
521 if (memeq(addr.ptr, this->from, addr.len) &&
522 memeq(addr.ptr, this->to, addr.len))
523 {
524 return TRUE;
525 }
526 }
527 }
528 else
529 {
530 size_t length = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
531
532 if (this->dynamic)
533 {
534 return TRUE;
535 }
536
537 if (memeq(this->from, this->to, length))
538 {
539 return TRUE;
540 }
541 }
542 return FALSE;
543 }
544
545 METHOD(traffic_selector_t, is_dynamic, bool,
546 private_traffic_selector_t *this)
547 {
548 return this->dynamic;
549 }
550
551 METHOD(traffic_selector_t, set_address, void,
552 private_traffic_selector_t *this, host_t *host)
553 {
554 if (is_host(this, NULL))
555 {
556 this->type = host->get_family(host) == AF_INET ?
557 TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE;
558
559 if (host->is_anyaddr(host))
560 {
561 memset(this->from6, 0x00, sizeof(this->from6));
562 memset(this->to6, 0xFF, sizeof(this->to6));
563 this->netbits = 0;
564 }
565 else
566 {
567 chunk_t from = host->get_address(host);
568 memcpy(this->from, from.ptr, from.len);
569 memcpy(this->to, from.ptr, from.len);
570 this->netbits = from.len * 8;
571 }
572 this->dynamic = FALSE;
573 }
574 }
575
576 METHOD(traffic_selector_t, is_contained_in, bool,
577 private_traffic_selector_t *this, traffic_selector_t *other)
578 {
579 private_traffic_selector_t *subset;
580 bool contained_in = FALSE;
581
582 subset = (private_traffic_selector_t*)get_subset(this, other);
583
584 if (subset)
585 {
586 if (equals(subset, &this->public))
587 {
588 contained_in = TRUE;
589 }
590 free(subset);
591 }
592 return contained_in;
593 }
594
595 METHOD(traffic_selector_t, includes, bool,
596 private_traffic_selector_t *this, host_t *host)
597 {
598 chunk_t addr;
599 int family = host->get_family(host);
600
601 if ((family == AF_INET && this->type == TS_IPV4_ADDR_RANGE) ||
602 (family == AF_INET6 && this->type == TS_IPV6_ADDR_RANGE))
603 {
604 addr = host->get_address(host);
605
606 return memcmp(this->from, addr.ptr, addr.len) <= 0 &&
607 memcmp(this->to, addr.ptr, addr.len) >= 0;
608 }
609
610 return FALSE;
611 }
612
613 METHOD(traffic_selector_t, to_subnet, bool,
614 private_traffic_selector_t *this, host_t **net, u_int8_t *mask)
615 {
616 /* there is no way to do this cleanly, as the address range may
617 * be anything else but a subnet. We use from_addr as subnet
618 * and try to calculate a usable subnet mask.
619 */
620 int family, non_zero_bytes;
621 u_int16_t port = 0;
622 chunk_t net_chunk;
623
624 *mask = (this->netbits == NON_SUBNET_ADDRESS_RANGE) ? calc_netbits(this)
625 : this->netbits;
626
627 switch (this->type)
628 {
629 case TS_IPV4_ADDR_RANGE:
630 family = AF_INET;
631 net_chunk.len = sizeof(this->from4);
632 break;
633 case TS_IPV6_ADDR_RANGE:
634 family = AF_INET6;
635 net_chunk.len = sizeof(this->from6);
636 break;
637 default:
638 /* unreachable */
639 return FALSE;
640 }
641
642 net_chunk.ptr = malloc(net_chunk.len);
643 memset(net_chunk.ptr, 0x00, net_chunk.len);
644 if (*mask)
645 {
646 non_zero_bytes = (*mask + 7) / 8;
647 memcpy(net_chunk.ptr, this->from, non_zero_bytes);
648 net_chunk.ptr[non_zero_bytes-1] &= 0xFF << (8 * non_zero_bytes - *mask);
649 }
650
651 if (this->to_port == this->from_port)
652 {
653 port = this->to_port;
654 }
655
656 *net = host_create_from_chunk(family, net_chunk, port);
657 chunk_free(&net_chunk);
658
659 return this->netbits != NON_SUBNET_ADDRESS_RANGE;
660 }
661
662 METHOD(traffic_selector_t, clone_, traffic_selector_t*,
663 private_traffic_selector_t *this)
664 {
665 private_traffic_selector_t *clone;
666
667 clone = traffic_selector_create(this->protocol, this->type,
668 this->from_port, this->to_port);
669 clone->netbits = this->netbits;
670 clone->dynamic = this->dynamic;
671
672 switch (clone->type)
673 {
674 case TS_IPV4_ADDR_RANGE:
675 memcpy(clone->from4, this->from4, sizeof(this->from4));
676 memcpy(clone->to4, this->to4, sizeof(this->to4));
677 return &clone->public;
678 case TS_IPV6_ADDR_RANGE:
679 memcpy(clone->from6, this->from6, sizeof(this->from6));
680 memcpy(clone->to6, this->to6, sizeof(this->to6));
681 return &clone->public;
682 default:
683 /* unreachable */
684 return &clone->public;
685 }
686 }
687
688 METHOD(traffic_selector_t, hash, u_int,
689 private_traffic_selector_t *this, u_int hash)
690 {
691 return chunk_hash_inc(get_from_address(this),
692 chunk_hash_inc(get_to_address(this),
693 chunk_hash_inc(chunk_from_thing(this->from_port),
694 chunk_hash_inc(chunk_from_thing(this->to_port),
695 chunk_hash_inc(chunk_from_thing(this->protocol),
696 hash)))));
697 }
698
699 METHOD(traffic_selector_t, destroy, void,
700 private_traffic_selector_t *this)
701 {
702 free(this);
703 }
704
705 /**
706 * Compare two integers
707 */
708 static int compare_int(int a, int b)
709 {
710 return a - b;
711 }
712
713 /*
714 * See header
715 */
716 int traffic_selector_cmp(traffic_selector_t *a_pub, traffic_selector_t *b_pub,
717 void *opts)
718 {
719 private_traffic_selector_t *a, *b;
720 int res;
721
722 a = (private_traffic_selector_t*)a_pub;
723 b = (private_traffic_selector_t*)b_pub;
724
725 /* IPv4 before IPv6 */
726 res = compare_int(a->type, b->type);
727 if (res)
728 {
729 return res;
730 }
731 switch (a->type)
732 {
733 case TS_IPV4_ADDR_RANGE:
734 /* lower starting subnets first */
735 res = memcmp(a->from4, b->from4, sizeof(a->from4));
736 if (res)
737 {
738 return res;
739 }
740 /* larger subnets first */
741 res = memcmp(b->to4, a->to4, sizeof(a->to4));
742 if (res)
743 {
744 return res;
745 }
746 break;
747 case TS_IPV6_ADDR_RANGE:
748 res = memcmp(a->from6, b->from6, sizeof(a->from6));
749 if (res)
750 {
751 return res;
752 }
753 res = memcmp(b->to6, a->to6, sizeof(a->to6));
754 if (res)
755 {
756 return res;
757 }
758 break;
759 default:
760 return 1;
761 }
762 /* lower protocols first */
763 res = compare_int(a->protocol, b->protocol);
764 if (res)
765 {
766 return res;
767 }
768 /* lower starting ports first */
769 res = compare_int(a->from_port, b->from_port);
770 if (res)
771 {
772 return res;
773 }
774 /* larger port ranges first */
775 return compare_int(b->to_port, a->to_port);
776 }
777
778 /*
779 * see header
780 */
781 traffic_selector_t *traffic_selector_create_from_bytes(u_int8_t protocol,
782 ts_type_t type,
783 chunk_t from, u_int16_t from_port,
784 chunk_t to, u_int16_t to_port)
785 {
786 private_traffic_selector_t *this = traffic_selector_create(protocol, type,
787 from_port, to_port);
788
789 switch (type)
790 {
791 case TS_IPV4_ADDR_RANGE:
792 if (from.len != 4 || to.len != 4)
793 {
794 free(this);
795 return NULL;
796 }
797 memcpy(this->from4, from.ptr, from.len);
798 memcpy(this->to4, to.ptr, to.len);
799 break;
800 case TS_IPV6_ADDR_RANGE:
801 if (from.len != 16 || to.len != 16)
802 {
803 free(this);
804 return NULL;
805 }
806 memcpy(this->from6, from.ptr, from.len);
807 memcpy(this->to6, to.ptr, to.len);
808 break;
809 default:
810 free(this);
811 return NULL;
812 }
813 calc_netbits(this);
814 return (&this->public);
815 }
816
817 /*
818 * see header
819 */
820 traffic_selector_t *traffic_selector_create_from_rfc3779_format(ts_type_t type,
821 chunk_t from, chunk_t to)
822 {
823 size_t len;
824 private_traffic_selector_t *this = traffic_selector_create(0, type, 0, 65535);
825
826 switch (type)
827 {
828 case TS_IPV4_ADDR_RANGE:
829 len = 4;
830 break;
831 case TS_IPV6_ADDR_RANGE:
832 len = 16;
833 break;
834 default:
835 free(this);
836 return NULL;
837 }
838 memset(this->from, 0x00, len);
839 memset(this->to , 0xff, len);
840
841 if (from.len > 1)
842 {
843 memcpy(this->from, from.ptr+1, from.len-1);
844 }
845 if (to.len > 1)
846 {
847 u_int8_t mask = to.ptr[0] ? (1 << to.ptr[0]) - 1 : 0;
848
849 memcpy(this->to, to.ptr+1, to.len-1);
850 this->to[to.len-2] |= mask;
851 }
852 this->netbits = chunk_equals(from, to) ? (from.len-1)*8 - from.ptr[0]
853 : NON_SUBNET_ADDRESS_RANGE;
854 return (&this->public);
855 }
856
857 /*
858 * see header
859 */
860 traffic_selector_t *traffic_selector_create_from_subnet(host_t *net,
861 u_int8_t netbits, u_int8_t protocol,
862 u_int16_t from_port, u_int16_t to_port)
863 {
864 private_traffic_selector_t *this;
865 chunk_t from;
866
867 this = traffic_selector_create(protocol, 0, from_port, to_port);
868
869 switch (net->get_family(net))
870 {
871 case AF_INET:
872 this->type = TS_IPV4_ADDR_RANGE;
873 break;
874 case AF_INET6:
875 this->type = TS_IPV6_ADDR_RANGE;
876 break;
877 default:
878 net->destroy(net);
879 free(this);
880 return NULL;
881 }
882 from = net->get_address(net);
883 memcpy(this->from, from.ptr, from.len);
884 netbits = min(netbits, this->type == TS_IPV4_ADDR_RANGE ? 32 : 128);
885 calc_range(this, netbits);
886 net->destroy(net);
887
888 return &this->public;
889 }
890
891 /*
892 * see header
893 */
894 traffic_selector_t *traffic_selector_create_from_string(
895 u_int8_t protocol, ts_type_t type,
896 char *from_addr, u_int16_t from_port,
897 char *to_addr, u_int16_t to_port)
898 {
899 private_traffic_selector_t *this;
900 int family;
901
902 switch (type)
903 {
904 case TS_IPV4_ADDR_RANGE:
905 family = AF_INET;
906 break;
907 case TS_IPV6_ADDR_RANGE:
908 family = AF_INET6;
909 break;
910 default:
911 return NULL;
912 }
913
914 this = traffic_selector_create(protocol, type, from_port, to_port);
915
916 if (inet_pton(family, from_addr, this->from) != 1 ||
917 inet_pton(family, to_addr, this->to) != 1)
918 {
919 free(this);
920 return NULL;
921 }
922
923 calc_netbits(this);
924 return &this->public;
925 }
926
927 /*
928 * see header
929 */
930 traffic_selector_t *traffic_selector_create_from_cidr(
931 char *string, u_int8_t protocol,
932 u_int16_t from_port, u_int16_t to_port)
933 {
934 host_t *net;
935 int bits;
936
937 net = host_create_from_subnet(string, &bits);
938 if (net)
939 {
940 return traffic_selector_create_from_subnet(net, bits, protocol,
941 from_port, to_port);
942 }
943 return NULL;
944 }
945
946 /*
947 * see header
948 */
949 traffic_selector_t *traffic_selector_create_dynamic(u_int8_t protocol,
950 u_int16_t from_port, u_int16_t to_port)
951 {
952 private_traffic_selector_t *this = traffic_selector_create(
953 protocol, TS_IPV4_ADDR_RANGE, from_port, to_port);
954
955 memset(this->from6, 0, sizeof(this->from6));
956 memset(this->to6, 0xFF, sizeof(this->to6));
957 this->netbits = 0;
958 this->dynamic = TRUE;
959
960 return &this->public;
961 }
962
963 /*
964 * see declaration
965 */
966 static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol,
967 ts_type_t type, u_int16_t from_port, u_int16_t to_port)
968 {
969 private_traffic_selector_t *this;
970
971 INIT(this,
972 .public = {
973 .get_subset = _get_subset,
974 .equals = _equals,
975 .get_from_address = _get_from_address,
976 .get_to_address = _get_to_address,
977 .get_from_port = _get_from_port,
978 .get_to_port = _get_to_port,
979 .get_type = _get_type,
980 .get_protocol = _get_protocol,
981 .is_host = _is_host,
982 .is_dynamic = _is_dynamic,
983 .is_contained_in = _is_contained_in,
984 .includes = _includes,
985 .set_address = _set_address,
986 .to_subnet = _to_subnet,
987 .clone = _clone_,
988 .hash = _hash,
989 .destroy = _destroy,
990 },
991 .from_port = from_port,
992 .to_port = to_port,
993 .protocol = protocol,
994 .type = type,
995 );
996 if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6)
997 {
998 this->from_port = from_port < 256 ? from_port << 8 : from_port;
999 this->to_port = to_port < 256 ? to_port << 8 : to_port;
1000 }
1001 return this;
1002 }