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 <collections/linked_list.h>
26 #include <utils/identification.h>
27 #include <utils/debug.h>
29 #define NON_SUBNET_ADDRESS_RANGE 255
31 ENUM(ts_type_name
, TS_IPV4_ADDR_RANGE
, TS_IPV6_ADDR_RANGE
,
36 typedef struct private_traffic_selector_t private_traffic_selector_t
;
39 * Private data of an traffic_selector_t object
41 struct private_traffic_selector_t
{
46 traffic_selector_t
public;
54 * IP protocol (UDP, TCP, ICMP, ...)
59 * narrow this traffic selector to hosts external ip
60 * if set, from and to have no meaning until set_address() is called
65 * subnet size in CIDR notation, 255 means a non-subnet address range
70 * begin of address range, network order
73 /** dummy char for common address manipulation */
82 * end of address range, network order
85 /** dummy char for common address manipulation */
105 * calculate the "to"-address for the "from" address and a subnet size
107 static void calc_range(private_traffic_selector_t
*this, u_int8_t netbits
)
113 this->netbits
= netbits
;
115 len
= (this->type
== TS_IPV4_ADDR_RANGE
) ? 4 : 16;
116 bytes
= (netbits
+ 7)/8;
117 bits
= (bytes
* 8) - netbits
;
118 mask
= bits
? (1 << bits
) - 1 : 0;
120 memcpy(this->to
, this->from
, bytes
);
121 memset(this->from
+ bytes
, 0x00, len
- bytes
);
122 memset(this->to
+ bytes
, 0xff, len
- bytes
);
123 this->from
[bytes
-1] &= ~mask
;
124 this->to
[bytes
-1] |= mask
;
128 * calculate the subnet size from the "to" and "from" addresses
130 static u_int8_t
calc_netbits(private_traffic_selector_t
*this)
134 size_t size
= (this->type
== TS_IPV4_ADDR_RANGE
) ? 4 : 16;
137 /* a perfect match results in a single address with a /32 or /128 netmask */
138 netbits
= (size
* 8);
139 this->netbits
= netbits
;
141 /* go through all bits of the addresses, beginning in the front.
142 * as long as they are equal, the subnet gets larger
144 for (byte
= 0; byte
< size
; byte
++)
146 for (bit
= 7; bit
>= 0; bit
--)
148 u_int8_t bitmask
= 1 << bit
;
152 if ((bitmask
& this->from
[byte
]) != (bitmask
& this->to
[byte
]))
154 /* store the common prefix which might be a true subnet */
155 netbits
= (7 - bit
) + (byte
* 8);
156 this->netbits
= netbits
;
162 if ((bitmask
& this->from
[byte
]) || !(bitmask
& this->to
[byte
]))
164 this->netbits
= NON_SUBNET_ADDRESS_RANGE
;
165 return netbits
; /* return a pseudo subnet */
171 return netbits
; /* return a true subnet */
175 * internal generic constructor
177 static private_traffic_selector_t
*traffic_selector_create(u_int8_t protocol
,
178 ts_type_t type
, u_int16_t from_port
, u_int16_t to_port
);
181 * Check if TS contains "opaque" ports
183 static bool is_opaque(private_traffic_selector_t
*this)
185 return this->from_port
== 0xffff && this->to_port
== 0;
189 * Check if TS contains "any" ports
191 static bool is_any(private_traffic_selector_t
*this)
193 return this->from_port
== 0 && this->to_port
== 0xffff;
197 * Described in header.
199 int traffic_selector_printf_hook(printf_hook_data_t
*data
,
200 printf_hook_spec_t
*spec
, const void *const *args
)
202 private_traffic_selector_t
*this = *((private_traffic_selector_t
**)(args
[0]));
203 linked_list_t
*list
= *((linked_list_t
**)(args
[0]));
204 enumerator_t
*enumerator
;
205 char from_str
[INET6_ADDRSTRLEN
] = "";
206 char to_str
[INET6_ADDRSTRLEN
] = "";
207 char *serv_proto
= NULL
;
211 u_int32_t from
[4], to
[4];
215 return print_in_hook(data
, "(null)");
220 enumerator
= list
->create_enumerator(list
);
221 while (enumerator
->enumerate(enumerator
, (void**)&this))
223 /* call recursivly */
224 written
+= print_in_hook(data
, "%R ", this);
226 enumerator
->destroy(enumerator
);
230 memset(from
, 0, sizeof(from
));
231 memset(to
, 0xFF, sizeof(to
));
233 memeq(this->from
, from
, this->type
== TS_IPV4_ADDR_RANGE
? 4 : 16) &&
234 memeq(this->to
, to
, this->type
== TS_IPV4_ADDR_RANGE
? 4 : 16))
236 written
+= print_in_hook(data
, "dynamic");
240 if (this->type
== TS_IPV4_ADDR_RANGE
)
242 inet_ntop(AF_INET
, &this->from4
, from_str
, sizeof(from_str
));
246 inet_ntop(AF_INET6
, &this->from6
, from_str
, sizeof(from_str
));
248 if (this->netbits
== NON_SUBNET_ADDRESS_RANGE
)
250 if (this->type
== TS_IPV4_ADDR_RANGE
)
252 inet_ntop(AF_INET
, &this->to4
, to_str
, sizeof(to_str
));
256 inet_ntop(AF_INET6
, &this->to6
, to_str
, sizeof(to_str
));
258 written
+= print_in_hook(data
, "%s..%s", from_str
, to_str
);
262 written
+= print_in_hook(data
, "%s/%d", from_str
, this->netbits
);
266 /* check if we have protocol and/or port selectors */
267 has_proto
= this->protocol
!= 0;
268 has_ports
= !is_any(this);
270 if (!has_proto
&& !has_ports
)
275 written
+= print_in_hook(data
, "[");
277 /* build protocol string */
280 struct protoent
*proto
= getprotobynumber(this->protocol
);
284 written
+= print_in_hook(data
, "%s", proto
->p_name
);
285 serv_proto
= proto
->p_name
;
289 written
+= print_in_hook(data
, "%d", this->protocol
);
293 if (has_proto
&& has_ports
)
295 written
+= print_in_hook(data
, "/");
298 /* build port string */
301 if (this->from_port
== this->to_port
)
303 struct servent
*serv
;
305 serv
= getservbyport(htons(this->from_port
), serv_proto
);
308 written
+= print_in_hook(data
, "%s", serv
->s_name
);
312 written
+= print_in_hook(data
, "%d", this->from_port
);
315 else if (is_opaque(this))
317 written
+= print_in_hook(data
, "OPAQUE");
321 written
+= print_in_hook(data
, "%d-%d",
322 this->from_port
, this->to_port
);
326 written
+= print_in_hook(data
, "]");
331 METHOD(traffic_selector_t
, get_subset
, traffic_selector_t
*,
332 private_traffic_selector_t
*this, traffic_selector_t
*other_public
)
334 private_traffic_selector_t
*other
, *subset
;
335 u_int16_t from_port
, to_port
;
340 other
= (private_traffic_selector_t
*)other_public
;
342 if (this->dynamic
|| other
->dynamic
)
343 { /* no set_address() applied, TS has no subset */
347 if (this->type
!= other
->type
)
353 case TS_IPV4_ADDR_RANGE
:
354 size
= sizeof(this->from4
);
356 case TS_IPV6_ADDR_RANGE
:
357 size
= sizeof(this->from6
);
363 if (this->protocol
!= other
->protocol
&&
364 this->protocol
!= 0 && other
->protocol
!= 0)
368 /* select protocol, which is not zero */
369 protocol
= max(this->protocol
, other
->protocol
);
371 if ((is_opaque(this) && is_opaque(other
)) ||
372 (is_opaque(this) && is_any(other
)) ||
373 (is_opaque(other
) && is_any(this)))
380 /* calculate the maximum port range allowed for both */
381 from_port
= max(this->from_port
, other
->from_port
);
382 to_port
= min(this->to_port
, other
->to_port
);
383 if (from_port
> to_port
)
388 /* get higher from-address */
389 if (memcmp(this->from
, other
->from
, size
) > 0)
397 /* get lower to-address */
398 if (memcmp(this->to
, other
->to
, size
) > 0)
406 /* if "from" > "to", we don't have a match */
407 if (memcmp(from
, to
, size
) > 0)
412 /* we have a match in protocol, port, and address: return it... */
413 subset
= traffic_selector_create(protocol
, this->type
, from_port
, to_port
);
414 memcpy(subset
->from
, from
, size
);
415 memcpy(subset
->to
, to
, size
);
416 calc_netbits(subset
);
418 return &subset
->public;
421 METHOD(traffic_selector_t
, equals
, bool,
422 private_traffic_selector_t
*this, traffic_selector_t
*other_public
)
424 private_traffic_selector_t
*other
;
426 other
= (private_traffic_selector_t
*)other_public
;
427 if (this->type
!= other
->type
)
431 if (!(this->from_port
== other
->from_port
&&
432 this->to_port
== other
->to_port
&&
433 this->protocol
== other
->protocol
))
439 case TS_IPV4_ADDR_RANGE
:
440 if (memeq(this->from4
, other
->from4
, sizeof(this->from4
)) &&
441 memeq(this->to4
, other
->to4
, sizeof(this->to4
)))
446 case TS_IPV6_ADDR_RANGE
:
447 if (memeq(this->from6
, other
->from6
, sizeof(this->from6
)) &&
448 memeq(this->to6
, other
->to6
, sizeof(this->to6
)))
459 METHOD(traffic_selector_t
, get_from_address
, chunk_t
,
460 private_traffic_selector_t
*this)
464 case TS_IPV4_ADDR_RANGE
:
465 return chunk_create(this->from
, sizeof(this->from4
));
466 case TS_IPV6_ADDR_RANGE
:
467 return chunk_create(this->from
, sizeof(this->from6
));
473 METHOD(traffic_selector_t
, get_to_address
, chunk_t
,
474 private_traffic_selector_t
*this)
478 case TS_IPV4_ADDR_RANGE
:
479 return chunk_create(this->to
, sizeof(this->to4
));
480 case TS_IPV6_ADDR_RANGE
:
481 return chunk_create(this->to
, sizeof(this->to6
));
487 METHOD(traffic_selector_t
, get_from_port
, u_int16_t
,
488 private_traffic_selector_t
*this)
490 return this->from_port
;
493 METHOD(traffic_selector_t
, get_to_port
, u_int16_t
,
494 private_traffic_selector_t
*this)
496 return this->to_port
;
499 METHOD(traffic_selector_t
, get_type
, ts_type_t
,
500 private_traffic_selector_t
*this)
505 METHOD(traffic_selector_t
, get_protocol
, u_int8_t
,
506 private_traffic_selector_t
*this)
508 return this->protocol
;
511 METHOD(traffic_selector_t
, is_host
, bool,
512 private_traffic_selector_t
*this, host_t
*host
)
517 int family
= host
->get_family(host
);
519 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
520 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
522 addr
= host
->get_address(host
);
523 if (memeq(addr
.ptr
, this->from
, addr
.len
) &&
524 memeq(addr
.ptr
, this->to
, addr
.len
))
532 size_t length
= (this->type
== TS_IPV4_ADDR_RANGE
) ? 4 : 16;
539 if (memeq(this->from
, this->to
, length
))
547 METHOD(traffic_selector_t
, is_dynamic
, bool,
548 private_traffic_selector_t
*this)
550 return this->dynamic
;
553 METHOD(traffic_selector_t
, set_address
, void,
554 private_traffic_selector_t
*this, host_t
*host
)
556 if (is_host(this, NULL
))
558 this->type
= host
->get_family(host
) == AF_INET
?
559 TS_IPV4_ADDR_RANGE
: TS_IPV6_ADDR_RANGE
;
561 if (host
->is_anyaddr(host
))
563 memset(this->from6
, 0x00, sizeof(this->from6
));
564 memset(this->to6
, 0xFF, sizeof(this->to6
));
569 chunk_t from
= host
->get_address(host
);
570 memcpy(this->from
, from
.ptr
, from
.len
);
571 memcpy(this->to
, from
.ptr
, from
.len
);
572 this->netbits
= from
.len
* 8;
574 this->dynamic
= FALSE
;
578 METHOD(traffic_selector_t
, is_contained_in
, bool,
579 private_traffic_selector_t
*this, traffic_selector_t
*other
)
581 private_traffic_selector_t
*subset
;
582 bool contained_in
= FALSE
;
584 subset
= (private_traffic_selector_t
*)get_subset(this, other
);
588 if (equals(subset
, &this->public))
597 METHOD(traffic_selector_t
, includes
, bool,
598 private_traffic_selector_t
*this, host_t
*host
)
601 int family
= host
->get_family(host
);
603 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
604 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
606 addr
= host
->get_address(host
);
608 return memcmp(this->from
, addr
.ptr
, addr
.len
) <= 0 &&
609 memcmp(this->to
, addr
.ptr
, addr
.len
) >= 0;
615 METHOD(traffic_selector_t
, to_subnet
, bool,
616 private_traffic_selector_t
*this, host_t
**net
, u_int8_t
*mask
)
618 /* there is no way to do this cleanly, as the address range may
619 * be anything else but a subnet. We use from_addr as subnet
620 * and try to calculate a usable subnet mask.
622 int family
, non_zero_bytes
;
626 *mask
= (this->netbits
== NON_SUBNET_ADDRESS_RANGE
) ? calc_netbits(this)
631 case TS_IPV4_ADDR_RANGE
:
633 net_chunk
.len
= sizeof(this->from4
);
635 case TS_IPV6_ADDR_RANGE
:
637 net_chunk
.len
= sizeof(this->from6
);
644 net_chunk
.ptr
= malloc(net_chunk
.len
);
645 memset(net_chunk
.ptr
, 0x00, net_chunk
.len
);
648 non_zero_bytes
= (*mask
+ 7) / 8;
649 memcpy(net_chunk
.ptr
, this->from
, non_zero_bytes
);
650 net_chunk
.ptr
[non_zero_bytes
-1] &= 0xFF << (8 * non_zero_bytes
- *mask
);
653 if (this->to_port
== this->from_port
)
655 port
= this->to_port
;
658 *net
= host_create_from_chunk(family
, net_chunk
, port
);
659 chunk_free(&net_chunk
);
661 return this->netbits
!= NON_SUBNET_ADDRESS_RANGE
;
664 METHOD(traffic_selector_t
, clone_
, traffic_selector_t
*,
665 private_traffic_selector_t
*this)
667 private_traffic_selector_t
*clone
;
669 clone
= traffic_selector_create(this->protocol
, this->type
,
670 this->from_port
, this->to_port
);
671 clone
->netbits
= this->netbits
;
672 clone
->dynamic
= this->dynamic
;
676 case TS_IPV4_ADDR_RANGE
:
677 memcpy(clone
->from4
, this->from4
, sizeof(this->from4
));
678 memcpy(clone
->to4
, this->to4
, sizeof(this->to4
));
679 return &clone
->public;
680 case TS_IPV6_ADDR_RANGE
:
681 memcpy(clone
->from6
, this->from6
, sizeof(this->from6
));
682 memcpy(clone
->to6
, this->to6
, sizeof(this->to6
));
683 return &clone
->public;
686 return &clone
->public;
690 METHOD(traffic_selector_t
, destroy
, void,
691 private_traffic_selector_t
*this)
699 traffic_selector_t
*traffic_selector_create_from_bytes(u_int8_t protocol
,
701 chunk_t from
, u_int16_t from_port
,
702 chunk_t to
, u_int16_t to_port
)
704 private_traffic_selector_t
*this = traffic_selector_create(protocol
, type
,
709 case TS_IPV4_ADDR_RANGE
:
710 if (from
.len
!= 4 || to
.len
!= 4)
715 memcpy(this->from4
, from
.ptr
, from
.len
);
716 memcpy(this->to4
, to
.ptr
, to
.len
);
718 case TS_IPV6_ADDR_RANGE
:
719 if (from
.len
!= 16 || to
.len
!= 16)
724 memcpy(this->from6
, from
.ptr
, from
.len
);
725 memcpy(this->to6
, to
.ptr
, to
.len
);
732 return (&this->public);
738 traffic_selector_t
*traffic_selector_create_from_rfc3779_format(ts_type_t type
,
739 chunk_t from
, chunk_t to
)
742 private_traffic_selector_t
*this = traffic_selector_create(0, type
, 0, 65535);
746 case TS_IPV4_ADDR_RANGE
:
749 case TS_IPV6_ADDR_RANGE
:
756 memset(this->from
, 0x00, len
);
757 memset(this->to
, 0xff, len
);
761 memcpy(this->from
, from
.ptr
+1, from
.len
-1);
765 u_int8_t mask
= to
.ptr
[0] ? (1 << to
.ptr
[0]) - 1 : 0;
767 memcpy(this->to
, to
.ptr
+1, to
.len
-1);
768 this->to
[to
.len
-2] |= mask
;
770 this->netbits
= chunk_equals(from
, to
) ? (from
.len
-1)*8 - from
.ptr
[0]
771 : NON_SUBNET_ADDRESS_RANGE
;
772 return (&this->public);
778 traffic_selector_t
*traffic_selector_create_from_subnet(host_t
*net
,
779 u_int8_t netbits
, u_int8_t protocol
,
780 u_int16_t from_port
, u_int16_t to_port
)
782 private_traffic_selector_t
*this;
785 this = traffic_selector_create(protocol
, 0, from_port
, to_port
);
787 switch (net
->get_family(net
))
790 this->type
= TS_IPV4_ADDR_RANGE
;
793 this->type
= TS_IPV6_ADDR_RANGE
;
800 from
= net
->get_address(net
);
801 memcpy(this->from
, from
.ptr
, from
.len
);
802 netbits
= min(netbits
, this->type
== TS_IPV4_ADDR_RANGE
? 32 : 128);
803 calc_range(this, netbits
);
806 return &this->public;
812 traffic_selector_t
*traffic_selector_create_from_string(
813 u_int8_t protocol
, ts_type_t type
,
814 char *from_addr
, u_int16_t from_port
,
815 char *to_addr
, u_int16_t to_port
)
817 private_traffic_selector_t
*this = traffic_selector_create(protocol
, type
,
822 case TS_IPV4_ADDR_RANGE
:
823 if (inet_pton(AF_INET
, from_addr
, (struct in_addr
*)this->from4
) < 0)
828 if (inet_pton(AF_INET
, to_addr
, (struct in_addr
*)this->to4
) < 0)
834 case TS_IPV6_ADDR_RANGE
:
835 if (inet_pton(AF_INET6
, from_addr
, (struct in6_addr
*)this->from6
) < 0)
840 if (inet_pton(AF_INET6
, to_addr
, (struct in6_addr
*)this->to6
) < 0)
848 return (&this->public);
854 traffic_selector_t
*traffic_selector_create_from_cidr(
855 char *string
, u_int8_t protocol
,
856 u_int16_t from_port
, u_int16_t to_port
)
861 net
= host_create_from_subnet(string
, &bits
);
864 return traffic_selector_create_from_subnet(net
, bits
, protocol
,
873 traffic_selector_t
*traffic_selector_create_dynamic(u_int8_t protocol
,
874 u_int16_t from_port
, u_int16_t to_port
)
876 private_traffic_selector_t
*this = traffic_selector_create(
877 protocol
, TS_IPV4_ADDR_RANGE
, from_port
, to_port
);
879 memset(this->from6
, 0, sizeof(this->from6
));
880 memset(this->to6
, 0xFF, sizeof(this->to6
));
882 this->dynamic
= TRUE
;
884 return &this->public;
890 static private_traffic_selector_t
*traffic_selector_create(u_int8_t protocol
,
891 ts_type_t type
, u_int16_t from_port
, u_int16_t to_port
)
893 private_traffic_selector_t
*this;
897 .get_subset
= _get_subset
,
899 .get_from_address
= _get_from_address
,
900 .get_to_address
= _get_to_address
,
901 .get_from_port
= _get_from_port
,
902 .get_to_port
= _get_to_port
,
903 .get_type
= _get_type
,
904 .get_protocol
= _get_protocol
,
906 .is_dynamic
= _is_dynamic
,
907 .is_contained_in
= _is_contained_in
,
908 .includes
= _includes
,
909 .set_address
= _set_address
,
910 .to_subnet
= _to_subnet
,
914 .from_port
= from_port
,
916 .protocol
= protocol
,