2 * Copyright (C) 2007-2009 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
18 #include <arpa/inet.h>
23 #include "traffic_selector.h"
25 #include <utils/linked_list.h>
26 #include <utils/identification.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
, ts_type_t type
, u_int16_t from_port
, u_int16_t to_port
);
179 * Described in header.
181 int traffic_selector_printf_hook(char *dst
, size_t len
, printf_hook_spec_t
*spec
,
182 const void *const *args
)
184 private_traffic_selector_t
*this = *((private_traffic_selector_t
**)(args
[0]));
185 linked_list_t
*list
= *((linked_list_t
**)(args
[0]));
186 iterator_t
*iterator
;
187 char from_str
[INET6_ADDRSTRLEN
] = "";
188 char to_str
[INET6_ADDRSTRLEN
] = "";
189 char *serv_proto
= NULL
;
193 u_int32_t from
[4], to
[4];
197 return print_in_hook(dst
, len
, "(null)");
202 iterator
= list
->create_iterator(list
, TRUE
);
203 while (iterator
->iterate(iterator
, (void**)&this))
205 /* call recursivly */
206 written
+= print_in_hook(dst
, len
, "%R ", this);
208 iterator
->destroy(iterator
);
212 memset(from
, 0, sizeof(from
));
213 memset(to
, 0xFF, sizeof(to
));
215 memeq(this->from
, from
, this->type
== TS_IPV4_ADDR_RANGE
? 4 : 16) &&
216 memeq(this->to
, to
, this->type
== TS_IPV4_ADDR_RANGE
? 4 : 16))
218 written
+= print_in_hook(dst
, len
, "dynamic");
222 if (this->type
== TS_IPV4_ADDR_RANGE
)
224 inet_ntop(AF_INET
, &this->from4
, from_str
, sizeof(from_str
));
228 inet_ntop(AF_INET6
, &this->from6
, from_str
, sizeof(from_str
));
230 if (this->netbits
== NON_SUBNET_ADDRESS_RANGE
)
232 if (this->type
== TS_IPV4_ADDR_RANGE
)
234 inet_ntop(AF_INET
, &this->to4
, to_str
, sizeof(to_str
));
238 inet_ntop(AF_INET6
, &this->to6
, to_str
, sizeof(to_str
));
240 written
+= print_in_hook(dst
, len
, "%s..%s", from_str
, to_str
);
244 written
+= print_in_hook(dst
, len
, "%s/%d", from_str
, this->netbits
);
248 /* check if we have protocol and/or port selectors */
249 has_proto
= this->protocol
!= 0;
250 has_ports
= !(this->from_port
== 0 && this->to_port
== 0xFFFF);
252 if (!has_proto
&& !has_ports
)
257 written
+= print_in_hook(dst
, len
, "[");
259 /* build protocol string */
262 struct protoent
*proto
= getprotobynumber(this->protocol
);
266 written
+= print_in_hook(dst
, len
, "%s", proto
->p_name
);
267 serv_proto
= proto
->p_name
;
271 written
+= print_in_hook(dst
, len
, "%d", this->protocol
);
275 if (has_proto
&& has_ports
)
277 written
+= print_in_hook(dst
, len
, "/");
280 /* build port string */
283 if (this->from_port
== this->to_port
)
285 struct servent
*serv
= getservbyport(htons(this->from_port
), serv_proto
);
289 written
+= print_in_hook(dst
, len
, "%s", serv
->s_name
);
293 written
+= print_in_hook(dst
, len
, "%d", this->from_port
);
298 written
+= print_in_hook(dst
, len
, "%d-%d", this->from_port
, this->to_port
);
302 written
+= print_in_hook(dst
, len
, "]");
308 * implements traffic_selector_t.get_subset
310 static traffic_selector_t
*get_subset(private_traffic_selector_t
*this, private_traffic_selector_t
*other
)
312 if (this->type
== other
->type
&& (this->protocol
== other
->protocol
||
313 this->protocol
== 0 || other
->protocol
== 0))
315 u_int16_t from_port
, to_port
;
319 private_traffic_selector_t
*new_ts
;
321 /* calculate the maximum port range allowed for both */
322 from_port
= max(this->from_port
, other
->from_port
);
323 to_port
= min(this->to_port
, other
->to_port
);
324 if (from_port
> to_port
)
328 /* select protocol, which is not zero */
329 protocol
= max(this->protocol
, other
->protocol
);
333 case TS_IPV4_ADDR_RANGE
:
334 size
= sizeof(this->from4
);
336 case TS_IPV6_ADDR_RANGE
:
337 size
= sizeof(this->from6
);
343 /* get higher from-address */
344 if (memcmp(this->from
, other
->from
, size
) > 0)
352 /* get lower to-address */
353 if (memcmp(this->to
, other
->to
, size
) > 0)
361 /* if "from" > "to", we don't have a match */
362 if (memcmp(from
, to
, size
) > 0)
367 /* we have a match in protocol, port, and address: return it... */
368 new_ts
= traffic_selector_create(protocol
, this->type
, from_port
, to_port
);
369 new_ts
->dynamic
= this->dynamic
|| other
->dynamic
;
370 memcpy(new_ts
->from
, from
, size
);
371 memcpy(new_ts
->to
, to
, size
);
372 calc_netbits(new_ts
);
373 return &new_ts
->public;
379 * implements traffic_selector_t.equals
381 static bool equals(private_traffic_selector_t
*this, private_traffic_selector_t
*other
)
383 if (this->type
!= other
->type
)
387 if (!(this->from_port
== other
->from_port
&&
388 this->to_port
== other
->to_port
&&
389 this->protocol
== other
->protocol
))
395 case TS_IPV4_ADDR_RANGE
:
396 if (memeq(this->from4
, other
->from4
, sizeof(this->from4
)) &&
397 memeq(this->to4
, other
->to4
, sizeof(this->to4
)))
402 case TS_IPV6_ADDR_RANGE
:
403 if (memeq(this->from6
, other
->from6
, sizeof(this->from6
)) &&
404 memeq(this->to6
, other
->to6
, sizeof(this->to6
)))
416 * Implements traffic_selector_t.get_from_address.
418 static chunk_t
get_from_address(private_traffic_selector_t
*this)
422 case TS_IPV4_ADDR_RANGE
:
423 return chunk_create(this->from
, sizeof(this->from4
));
424 case TS_IPV6_ADDR_RANGE
:
425 return chunk_create(this->from
, sizeof(this->from6
));
432 * Implements traffic_selector_t.get_to_address.
434 static chunk_t
get_to_address(private_traffic_selector_t
*this)
438 case TS_IPV4_ADDR_RANGE
:
439 return chunk_create(this->to
, sizeof(this->to4
));
440 case TS_IPV6_ADDR_RANGE
:
441 return chunk_create(this->to
, sizeof(this->to6
));
448 * Implements traffic_selector_t.get_from_port.
450 static u_int16_t
get_from_port(private_traffic_selector_t
*this)
452 return this->from_port
;
456 * Implements traffic_selector_t.get_to_port.
458 static u_int16_t
get_to_port(private_traffic_selector_t
*this)
460 return this->to_port
;
464 * Implements traffic_selector_t.get_type.
466 static ts_type_t
get_type(private_traffic_selector_t
*this)
472 * Implements traffic_selector_t.get_protocol.
474 static u_int8_t
get_protocol(private_traffic_selector_t
*this)
476 return this->protocol
;
480 * Implements traffic_selector_t.is_host.
482 static bool is_host(private_traffic_selector_t
*this, host_t
*host
)
487 int family
= host
->get_family(host
);
489 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
490 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
492 addr
= host
->get_address(host
);
493 if (memeq(addr
.ptr
, this->from
, addr
.len
) &&
494 memeq(addr
.ptr
, this->to
, addr
.len
))
502 size_t length
= (this->type
== TS_IPV4_ADDR_RANGE
) ? 4 : 16;
509 if (memeq(this->from
, this->to
, length
))
518 * Implementation of traffic_selector_t.is_dynamic
520 static bool is_dynamic(private_traffic_selector_t
*this)
522 return this->dynamic
;
526 * Implements traffic_selector_t.set_address.
528 static void set_address(private_traffic_selector_t
*this, host_t
*host
)
532 this->type
= host
->get_family(host
) == AF_INET
?
533 TS_IPV4_ADDR_RANGE
: TS_IPV6_ADDR_RANGE
;
535 if (host
->is_anyaddr(host
))
537 memset(this->from6
, 0x00, sizeof(this->from6
));
538 memset(this->to6
, 0xFF, sizeof(this->to6
));
543 chunk_t from
= host
->get_address(host
);
544 memcpy(this->from
, from
.ptr
, from
.len
);
545 memcpy(this->to
, from
.ptr
, from
.len
);
546 this->netbits
= from
.len
* 8;
552 * Implements traffic_selector_t.is_contained_in.
554 static bool is_contained_in(private_traffic_selector_t
*this,
555 private_traffic_selector_t
*other
)
557 private_traffic_selector_t
*subset
;
558 bool contained_in
= FALSE
;
560 subset
= (private_traffic_selector_t
*)get_subset(this, other
);
564 if (equals(subset
, this))
574 * Implements traffic_selector_t.includes.
576 static bool includes(private_traffic_selector_t
*this, host_t
*host
)
579 int family
= host
->get_family(host
);
581 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
582 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
584 addr
= host
->get_address(host
);
586 return memcmp(this->from
, addr
.ptr
, addr
.len
) <= 0 &&
587 memcmp(this->to
, addr
.ptr
, addr
.len
) >= 0;
594 * Implements traffic_selector_t.to_subnet.
596 static void to_subnet(private_traffic_selector_t
*this, host_t
**net
, u_int8_t
*mask
)
598 /* there is no way to do this cleanly, as the address range may
599 * be anything else but a subnet. We use from_addr as subnet
600 * and try to calculate a usable subnet mask.
606 *mask
= (this->netbits
== NON_SUBNET_ADDRESS_RANGE
) ? calc_netbits(this)
611 case TS_IPV4_ADDR_RANGE
:
613 net_chunk
.len
= sizeof(this->from4
);
615 case TS_IPV6_ADDR_RANGE
:
617 net_chunk
.len
= sizeof(this->from6
);
624 net_chunk
.ptr
= malloc(net_chunk
.len
);
625 memcpy(net_chunk
.ptr
, this->from
, net_chunk
.len
);
627 for (byte
= net_chunk
.len
- 1; byte
>= (*mask
/ 8); --byte
)
629 int shift
= (byte
+ 1) * 8 - *mask
;
630 net_chunk
.ptr
[byte
] = net_chunk
.ptr
[byte
] & (0xFF << shift
);
633 if (this->to_port
== this->from_port
)
635 port
= this->to_port
;
638 *net
= host_create_from_chunk(family
, net_chunk
, port
);
639 chunk_free(&net_chunk
);
643 * Implements traffic_selector_t.clone.
645 static traffic_selector_t
*clone_(private_traffic_selector_t
*this)
647 private_traffic_selector_t
*clone
;
649 clone
= traffic_selector_create(this->protocol
, this->type
,
650 this->from_port
, this->to_port
);
651 clone
->netbits
= this->netbits
;
652 clone
->dynamic
= this->dynamic
;
656 case TS_IPV4_ADDR_RANGE
:
657 memcpy(clone
->from4
, this->from4
, sizeof(this->from4
));
658 memcpy(clone
->to4
, this->to4
, sizeof(this->to4
));
659 return &clone
->public;
660 case TS_IPV6_ADDR_RANGE
:
661 memcpy(clone
->from6
, this->from6
, sizeof(this->from6
));
662 memcpy(clone
->to6
, this->to6
, sizeof(this->to6
));
663 return &clone
->public;
666 return &clone
->public;
671 * Implements traffic_selector_t.destroy.
673 static void destroy(private_traffic_selector_t
*this)
681 traffic_selector_t
*traffic_selector_create_from_bytes(u_int8_t protocol
,
683 chunk_t from
, u_int16_t from_port
,
684 chunk_t to
, u_int16_t to_port
)
686 private_traffic_selector_t
*this = traffic_selector_create(protocol
, type
,
691 case TS_IPV4_ADDR_RANGE
:
692 if (from
.len
!= 4 || to
.len
!= 4)
697 memcpy(this->from4
, from
.ptr
, from
.len
);
698 memcpy(this->to4
, to
.ptr
, to
.len
);
700 case TS_IPV6_ADDR_RANGE
:
701 if (from
.len
!= 16 || to
.len
!= 16)
706 memcpy(this->from6
, from
.ptr
, from
.len
);
707 memcpy(this->to6
, to
.ptr
, to
.len
);
714 return (&this->public);
720 traffic_selector_t
*traffic_selector_create_from_rfc3779_format(ts_type_t type
,
721 chunk_t from
, chunk_t to
)
724 private_traffic_selector_t
*this = traffic_selector_create(0, type
, 0, 65535);
728 case TS_IPV4_ADDR_RANGE
:
731 case TS_IPV6_ADDR_RANGE
:
738 memset(this->from
, 0x00, len
);
739 memset(this->to
, 0xff, len
);
743 memcpy(this->from
, from
.ptr
+1, from
.len
-1);
747 u_int8_t mask
= to
.ptr
[0] ? (1 << to
.ptr
[0]) - 1 : 0;
749 memcpy(this->to
, to
.ptr
+1, to
.len
-1);
750 this->to
[to
.len
-2] |= mask
;
752 this->netbits
= chunk_equals(from
, to
) ? (from
.len
-1)*8 - from
.ptr
[0]
753 : NON_SUBNET_ADDRESS_RANGE
;
754 return (&this->public);
760 traffic_selector_t
*traffic_selector_create_from_subnet(host_t
*net
,
761 u_int8_t netbits
, u_int8_t protocol
, u_int16_t port
)
763 private_traffic_selector_t
*this = traffic_selector_create(protocol
, 0, 0, 65535);
765 switch (net
->get_family(net
))
771 this->type
= TS_IPV4_ADDR_RANGE
;
772 from
= net
->get_address(net
);
773 memcpy(this->from
, from
.ptr
, from
.len
);
774 if (this->from4
[0] == 0)
776 /* use /0 for 0.0.0.0 */
782 calc_range(this, netbits
);
790 this->type
= TS_IPV6_ADDR_RANGE
;
791 from
= net
->get_address(net
);
792 memcpy(this->from
, from
.ptr
, from
.len
);
793 if (this->from6
[0] == 0 && this->from6
[1] == 0 &&
794 this->from6
[2] == 0 && this->from6
[3] == 0)
805 calc_range(this, netbits
);
818 this->from_port
= port
;
819 this->to_port
= port
;
822 return (&this->public);
828 traffic_selector_t
*traffic_selector_create_from_string(
829 u_int8_t protocol
, ts_type_t type
,
830 char *from_addr
, u_int16_t from_port
,
831 char *to_addr
, u_int16_t to_port
)
833 private_traffic_selector_t
*this = traffic_selector_create(protocol
, type
,
838 case TS_IPV4_ADDR_RANGE
:
839 if (inet_pton(AF_INET
, from_addr
, (struct in_addr
*)this->from4
) < 0)
844 if (inet_pton(AF_INET
, to_addr
, (struct in_addr
*)this->to4
) < 0)
850 case TS_IPV6_ADDR_RANGE
:
851 if (inet_pton(AF_INET6
, from_addr
, (struct in6_addr
*)this->from6
) < 0)
856 if (inet_pton(AF_INET6
, to_addr
, (struct in6_addr
*)this->to6
) < 0)
864 return (&this->public);
870 traffic_selector_t
*traffic_selector_create_dynamic(u_int8_t protocol
,
871 u_int16_t from_port
, u_int16_t to_port
)
873 private_traffic_selector_t
*this = traffic_selector_create(
874 protocol
, TS_IPV4_ADDR_RANGE
, from_port
, to_port
);
876 memset(this->from6
, 0, sizeof(this->from6
));
877 memset(this->to6
, 0xFF, sizeof(this->to6
));
879 this->dynamic
= TRUE
;
881 return &this->public;
887 static private_traffic_selector_t
*traffic_selector_create(u_int8_t protocol
,
888 ts_type_t type
, u_int16_t from_port
, u_int16_t to_port
)
890 private_traffic_selector_t
*this = malloc_thing(private_traffic_selector_t
);
892 /* public functions */
893 this->public.get_subset
= (traffic_selector_t
*(*)(traffic_selector_t
*,traffic_selector_t
*))get_subset
;
894 this->public.equals
= (bool(*)(traffic_selector_t
*,traffic_selector_t
*))equals
;
895 this->public.get_from_address
= (chunk_t(*)(traffic_selector_t
*))get_from_address
;
896 this->public.get_to_address
= (chunk_t(*)(traffic_selector_t
*))get_to_address
;
897 this->public.get_from_port
= (u_int16_t(*)(traffic_selector_t
*))get_from_port
;
898 this->public.get_to_port
= (u_int16_t(*)(traffic_selector_t
*))get_to_port
;
899 this->public.get_type
= (ts_type_t(*)(traffic_selector_t
*))get_type
;
900 this->public.get_protocol
= (u_int8_t(*)(traffic_selector_t
*))get_protocol
;
901 this->public.is_host
= (bool(*)(traffic_selector_t
*,host_t
*))is_host
;
902 this->public.is_dynamic
= (bool(*)(traffic_selector_t
*))is_dynamic
;
903 this->public.is_contained_in
= (bool(*)(traffic_selector_t
*,traffic_selector_t
*))is_contained_in
;
904 this->public.includes
= (bool(*)(traffic_selector_t
*,host_t
*))includes
;
905 this->public.set_address
= (void(*)(traffic_selector_t
*,host_t
*))set_address
;
906 this->public.to_subnet
= (void(*)(traffic_selector_t
*,host_t
**,u_int8_t
*))to_subnet
;
907 this->public.clone
= (traffic_selector_t
*(*)(traffic_selector_t
*))clone_
;
908 this->public.destroy
= (void(*)(traffic_selector_t
*))destroy
;
910 this->from_port
= from_port
;
911 this->to_port
= to_port
;
912 this->protocol
= protocol
;
914 this->dynamic
= FALSE
;