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
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>.
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
21 #include "traffic_selector.h"
23 #include <utils/debug.h>
24 #include <utils/utils.h>
25 #include <utils/identification.h>
26 #include <collections/linked_list.h>
28 #define NON_SUBNET_ADDRESS_RANGE 255
30 ENUM(ts_type_name
, TS_IPV4_ADDR_RANGE
, TS_IPV6_ADDR_RANGE
,
35 typedef struct private_traffic_selector_t private_traffic_selector_t
;
38 * Private data of an traffic_selector_t object
40 struct private_traffic_selector_t
{
45 traffic_selector_t
public;
53 * IP protocol (UDP, TCP, ICMP, ...)
58 * narrow this traffic selector to hosts external ip
59 * if set, from and to have no meaning until set_address() is called
64 * subnet size in CIDR notation, 255 means a non-subnet address range
69 * begin of address range, network order
72 /** dummy char for common address manipulation */
81 * end of address range, network order
84 /** dummy char for common address manipulation */
104 * calculate the "to"-address for the "from" address and a subnet size
106 static void calc_range(private_traffic_selector_t
*this, u_int8_t netbits
)
112 this->netbits
= netbits
;
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;
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
;
127 * calculate the subnet size from the "to" and "from" addresses
129 static u_int8_t
calc_netbits(private_traffic_selector_t
*this)
133 size_t size
= (this->type
== TS_IPV4_ADDR_RANGE
) ? 4 : 16;
136 /* a perfect match results in a single address with a /32 or /128 netmask */
137 netbits
= (size
* 8);
138 this->netbits
= netbits
;
140 /* go through all bits of the addresses, beginning in the front.
141 * as long as they are equal, the subnet gets larger
143 for (byte
= 0; byte
< size
; byte
++)
145 for (bit
= 7; bit
>= 0; bit
--)
147 u_int8_t bitmask
= 1 << bit
;
151 if ((bitmask
& this->from
[byte
]) != (bitmask
& this->to
[byte
]))
153 /* store the common prefix which might be a true subnet */
154 netbits
= (7 - bit
) + (byte
* 8);
155 this->netbits
= netbits
;
161 if ((bitmask
& this->from
[byte
]) || !(bitmask
& this->to
[byte
]))
163 this->netbits
= NON_SUBNET_ADDRESS_RANGE
;
164 return netbits
; /* return a pseudo subnet */
170 return netbits
; /* return a true subnet */
174 * internal generic constructor
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
);
180 * Check if TS contains "opaque" ports
182 static bool is_opaque(private_traffic_selector_t
*this)
184 return this->from_port
== 0xffff && this->to_port
== 0;
188 * Check if TS contains "any" ports
190 static bool is_any(private_traffic_selector_t
*this)
192 return this->from_port
== 0 && this->to_port
== 0xffff;
196 * Print ICMP/ICMPv6 type and code
198 static int print_icmp(printf_hook_data_t
*data
, u_int16_t port
)
202 type
= traffic_selector_icmp_type(port
);
203 code
= traffic_selector_icmp_code(port
);
206 return print_in_hook(data
, "%d(%d)", type
, code
);
208 return print_in_hook(data
, "%d", type
);
212 * Described in header.
214 int traffic_selector_printf_hook(printf_hook_data_t
*data
,
215 printf_hook_spec_t
*spec
, const void *const *args
)
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
;
226 u_int32_t from
[4], to
[4];
230 return print_in_hook(data
, "(null)");
235 enumerator
= list
->create_enumerator(list
);
236 while (enumerator
->enumerate(enumerator
, (void**)&this))
238 /* call recursivly */
239 written
+= print_in_hook(data
, "%R ", this);
241 enumerator
->destroy(enumerator
);
245 memset(from
, 0, sizeof(from
));
246 memset(to
, 0xFF, sizeof(to
));
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))
251 written
+= print_in_hook(data
, "dynamic");
255 if (this->type
== TS_IPV4_ADDR_RANGE
)
257 inet_ntop(AF_INET
, &this->from4
, from_str
, sizeof(from_str
));
261 inet_ntop(AF_INET6
, &this->from6
, from_str
, sizeof(from_str
));
263 if (this->netbits
== NON_SUBNET_ADDRESS_RANGE
)
265 if (this->type
== TS_IPV4_ADDR_RANGE
)
267 inet_ntop(AF_INET
, &this->to4
, to_str
, sizeof(to_str
));
271 inet_ntop(AF_INET6
, &this->to6
, to_str
, sizeof(to_str
));
273 written
+= print_in_hook(data
, "%s..%s", from_str
, to_str
);
277 written
+= print_in_hook(data
, "%s/%d", from_str
, this->netbits
);
281 /* check if we have protocol and/or port selectors */
282 has_proto
= this->protocol
!= 0;
283 has_ports
= !is_any(this);
285 if (!has_proto
&& !has_ports
)
290 written
+= print_in_hook(data
, "[");
292 /* build protocol string */
295 struct protoent
*proto
= getprotobynumber(this->protocol
);
299 written
+= print_in_hook(data
, "%s", proto
->p_name
);
300 serv_proto
= proto
->p_name
;
304 written
+= print_in_hook(data
, "%d", this->protocol
);
308 if (has_proto
&& has_ports
)
310 written
+= print_in_hook(data
, "/");
313 /* build port string */
316 if (this->from_port
== this->to_port
)
318 struct servent
*serv
;
320 if (this->protocol
== IPPROTO_ICMP
||
321 this->protocol
== IPPROTO_ICMPV6
)
323 written
+= print_icmp(data
, this->from_port
);
327 serv
= getservbyport(htons(this->from_port
), serv_proto
);
330 written
+= print_in_hook(data
, "%s", serv
->s_name
);
334 written
+= print_in_hook(data
, "%d", this->from_port
);
338 else if (is_opaque(this))
340 written
+= print_in_hook(data
, "OPAQUE");
342 else if (this->protocol
== IPPROTO_ICMP
||
343 this->protocol
== IPPROTO_ICMPV6
)
345 written
+= print_icmp(data
, this->from_port
);
346 written
+= print_in_hook(data
, "-");
347 written
+= print_icmp(data
, this->to_port
);
351 written
+= print_in_hook(data
, "%d-%d",
352 this->from_port
, this->to_port
);
356 written
+= print_in_hook(data
, "]");
361 METHOD(traffic_selector_t
, get_subset
, traffic_selector_t
*,
362 private_traffic_selector_t
*this, traffic_selector_t
*other_public
)
364 private_traffic_selector_t
*other
, *subset
;
365 u_int16_t from_port
, to_port
;
370 other
= (private_traffic_selector_t
*)other_public
;
372 if (this->dynamic
|| other
->dynamic
)
373 { /* no set_address() applied, TS has no subset */
377 if (this->type
!= other
->type
)
383 case TS_IPV4_ADDR_RANGE
:
384 size
= sizeof(this->from4
);
386 case TS_IPV6_ADDR_RANGE
:
387 size
= sizeof(this->from6
);
393 if (this->protocol
!= other
->protocol
&&
394 this->protocol
!= 0 && other
->protocol
!= 0)
398 /* select protocol, which is not zero */
399 protocol
= max(this->protocol
, other
->protocol
);
401 if ((is_opaque(this) && is_opaque(other
)) ||
402 (is_opaque(this) && is_any(other
)) ||
403 (is_opaque(other
) && is_any(this)))
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
)
418 /* get higher from-address */
419 if (memcmp(this->from
, other
->from
, size
) > 0)
427 /* get lower to-address */
428 if (memcmp(this->to
, other
->to
, size
) > 0)
436 /* if "from" > "to", we don't have a match */
437 if (memcmp(from
, to
, size
) > 0)
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
);
448 return &subset
->public;
451 METHOD(traffic_selector_t
, equals
, bool,
452 private_traffic_selector_t
*this, traffic_selector_t
*other
)
454 return traffic_selector_cmp(&this->public, other
, NULL
) == 0;
457 METHOD(traffic_selector_t
, get_from_address
, chunk_t
,
458 private_traffic_selector_t
*this)
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
));
471 METHOD(traffic_selector_t
, get_to_address
, chunk_t
,
472 private_traffic_selector_t
*this)
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
));
485 METHOD(traffic_selector_t
, get_from_port
, u_int16_t
,
486 private_traffic_selector_t
*this)
488 return this->from_port
;
491 METHOD(traffic_selector_t
, get_to_port
, u_int16_t
,
492 private_traffic_selector_t
*this)
494 return this->to_port
;
497 METHOD(traffic_selector_t
, get_type
, ts_type_t
,
498 private_traffic_selector_t
*this)
503 METHOD(traffic_selector_t
, get_protocol
, u_int8_t
,
504 private_traffic_selector_t
*this)
506 return this->protocol
;
509 METHOD(traffic_selector_t
, is_host
, bool,
510 private_traffic_selector_t
*this, host_t
*host
)
515 int family
= host
->get_family(host
);
517 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
518 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
520 addr
= host
->get_address(host
);
521 if (memeq(addr
.ptr
, this->from
, addr
.len
) &&
522 memeq(addr
.ptr
, this->to
, addr
.len
))
530 size_t length
= (this->type
== TS_IPV4_ADDR_RANGE
) ? 4 : 16;
537 if (memeq(this->from
, this->to
, length
))
545 METHOD(traffic_selector_t
, is_dynamic
, bool,
546 private_traffic_selector_t
*this)
548 return this->dynamic
;
551 METHOD(traffic_selector_t
, set_address
, void,
552 private_traffic_selector_t
*this, host_t
*host
)
554 if (is_host(this, NULL
))
556 this->type
= host
->get_family(host
) == AF_INET
?
557 TS_IPV4_ADDR_RANGE
: TS_IPV6_ADDR_RANGE
;
559 if (host
->is_anyaddr(host
))
561 memset(this->from6
, 0x00, sizeof(this->from6
));
562 memset(this->to6
, 0xFF, sizeof(this->to6
));
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;
572 this->dynamic
= FALSE
;
576 METHOD(traffic_selector_t
, is_contained_in
, bool,
577 private_traffic_selector_t
*this, traffic_selector_t
*other
)
579 private_traffic_selector_t
*subset
;
580 bool contained_in
= FALSE
;
582 subset
= (private_traffic_selector_t
*)get_subset(this, other
);
586 if (equals(subset
, &this->public))
595 METHOD(traffic_selector_t
, includes
, bool,
596 private_traffic_selector_t
*this, host_t
*host
)
599 int family
= host
->get_family(host
);
601 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
602 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
604 addr
= host
->get_address(host
);
606 return memcmp(this->from
, addr
.ptr
, addr
.len
) <= 0 &&
607 memcmp(this->to
, addr
.ptr
, addr
.len
) >= 0;
613 METHOD(traffic_selector_t
, to_subnet
, bool,
614 private_traffic_selector_t
*this, host_t
**net
, u_int8_t
*mask
)
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.
620 int family
, non_zero_bytes
;
624 *mask
= (this->netbits
== NON_SUBNET_ADDRESS_RANGE
) ? calc_netbits(this)
629 case TS_IPV4_ADDR_RANGE
:
631 net_chunk
.len
= sizeof(this->from4
);
633 case TS_IPV6_ADDR_RANGE
:
635 net_chunk
.len
= sizeof(this->from6
);
642 net_chunk
.ptr
= malloc(net_chunk
.len
);
643 memset(net_chunk
.ptr
, 0x00, net_chunk
.len
);
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
);
651 if (this->to_port
== this->from_port
)
653 port
= this->to_port
;
656 *net
= host_create_from_chunk(family
, net_chunk
, port
);
657 chunk_free(&net_chunk
);
659 return this->netbits
!= NON_SUBNET_ADDRESS_RANGE
;
662 METHOD(traffic_selector_t
, clone_
, traffic_selector_t
*,
663 private_traffic_selector_t
*this)
665 private_traffic_selector_t
*clone
;
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
;
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;
684 return &clone
->public;
688 METHOD(traffic_selector_t
, hash
, u_int
,
689 private_traffic_selector_t
*this, u_int hash
)
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
),
699 METHOD(traffic_selector_t
, destroy
, void,
700 private_traffic_selector_t
*this)
706 * Compare two integers
708 static int compare_int(int a
, int b
)
716 int traffic_selector_cmp(traffic_selector_t
*a_pub
, traffic_selector_t
*b_pub
,
719 private_traffic_selector_t
*a
, *b
;
722 a
= (private_traffic_selector_t
*)a_pub
;
723 b
= (private_traffic_selector_t
*)b_pub
;
725 /* IPv4 before IPv6 */
726 res
= compare_int(a
->type
, b
->type
);
733 case TS_IPV4_ADDR_RANGE
:
734 /* lower starting subnets first */
735 res
= memcmp(a
->from4
, b
->from4
, sizeof(a
->from4
));
740 /* larger subnets first */
741 res
= memcmp(b
->to4
, a
->to4
, sizeof(a
->to4
));
747 case TS_IPV6_ADDR_RANGE
:
748 res
= memcmp(a
->from6
, b
->from6
, sizeof(a
->from6
));
753 res
= memcmp(b
->to6
, a
->to6
, sizeof(a
->to6
));
762 /* lower protocols first */
763 res
= compare_int(a
->protocol
, b
->protocol
);
768 /* lower starting ports first */
769 res
= compare_int(a
->from_port
, b
->from_port
);
774 /* larger port ranges first */
775 return compare_int(b
->to_port
, a
->to_port
);
781 traffic_selector_t
*traffic_selector_create_from_bytes(u_int8_t protocol
,
783 chunk_t from
, u_int16_t from_port
,
784 chunk_t to
, u_int16_t to_port
)
786 private_traffic_selector_t
*this = traffic_selector_create(protocol
, type
,
791 case TS_IPV4_ADDR_RANGE
:
792 if (from
.len
!= 4 || to
.len
!= 4)
797 memcpy(this->from4
, from
.ptr
, from
.len
);
798 memcpy(this->to4
, to
.ptr
, to
.len
);
800 case TS_IPV6_ADDR_RANGE
:
801 if (from
.len
!= 16 || to
.len
!= 16)
806 memcpy(this->from6
, from
.ptr
, from
.len
);
807 memcpy(this->to6
, to
.ptr
, to
.len
);
814 return (&this->public);
820 traffic_selector_t
*traffic_selector_create_from_rfc3779_format(ts_type_t type
,
821 chunk_t from
, chunk_t to
)
824 private_traffic_selector_t
*this = traffic_selector_create(0, type
, 0, 65535);
828 case TS_IPV4_ADDR_RANGE
:
831 case TS_IPV6_ADDR_RANGE
:
838 memset(this->from
, 0x00, len
);
839 memset(this->to
, 0xff, len
);
843 memcpy(this->from
, from
.ptr
+1, from
.len
-1);
847 u_int8_t mask
= to
.ptr
[0] ? (1 << to
.ptr
[0]) - 1 : 0;
849 memcpy(this->to
, to
.ptr
+1, to
.len
-1);
850 this->to
[to
.len
-2] |= mask
;
852 this->netbits
= chunk_equals(from
, to
) ? (from
.len
-1)*8 - from
.ptr
[0]
853 : NON_SUBNET_ADDRESS_RANGE
;
854 return (&this->public);
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
)
864 private_traffic_selector_t
*this;
867 this = traffic_selector_create(protocol
, 0, from_port
, to_port
);
869 switch (net
->get_family(net
))
872 this->type
= TS_IPV4_ADDR_RANGE
;
875 this->type
= TS_IPV6_ADDR_RANGE
;
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
);
888 return &this->public;
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
)
899 private_traffic_selector_t
*this;
904 case TS_IPV4_ADDR_RANGE
:
907 case TS_IPV6_ADDR_RANGE
:
914 this = traffic_selector_create(protocol
, type
, from_port
, to_port
);
916 if (inet_pton(family
, from_addr
, this->from
) != 1 ||
917 inet_pton(family
, to_addr
, this->to
) != 1)
924 return &this->public;
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
)
937 net
= host_create_from_subnet(string
, &bits
);
940 return traffic_selector_create_from_subnet(net
, bits
, protocol
,
949 traffic_selector_t
*traffic_selector_create_dynamic(u_int8_t protocol
,
950 u_int16_t from_port
, u_int16_t to_port
)
952 private_traffic_selector_t
*this = traffic_selector_create(
953 protocol
, TS_IPV4_ADDR_RANGE
, from_port
, to_port
);
955 memset(this->from6
, 0, sizeof(this->from6
));
956 memset(this->to6
, 0xFF, sizeof(this->to6
));
958 this->dynamic
= TRUE
;
960 return &this->public;
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
)
969 private_traffic_selector_t
*this;
973 .get_subset
= _get_subset
,
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
,
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
,
991 .from_port
= from_port
,
993 .protocol
= protocol
,
996 if (protocol
== IPPROTO_ICMP
|| protocol
== IPPROTO_ICMPV6
)
998 this->from_port
= from_port
< 256 ? from_port
<< 8 : from_port
;
999 this->to_port
= to_port
< 256 ? to_port
<< 8 : to_port
;