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>
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
, ts_type_t type
, u_int16_t from_port
, u_int16_t to_port
);
180 * Described in header.
182 int traffic_selector_printf_hook(printf_hook_data_t
*data
,
183 printf_hook_spec_t
*spec
, const void *const *args
)
185 private_traffic_selector_t
*this = *((private_traffic_selector_t
**)(args
[0]));
186 linked_list_t
*list
= *((linked_list_t
**)(args
[0]));
187 enumerator_t
*enumerator
;
188 char from_str
[INET6_ADDRSTRLEN
] = "";
189 char to_str
[INET6_ADDRSTRLEN
] = "";
190 char *serv_proto
= NULL
;
194 u_int32_t from
[4], to
[4];
198 return print_in_hook(data
, "(null)");
203 enumerator
= list
->create_enumerator(list
);
204 while (enumerator
->enumerate(enumerator
, (void**)&this))
206 /* call recursivly */
207 written
+= print_in_hook(data
, "%R ", this);
209 enumerator
->destroy(enumerator
);
213 memset(from
, 0, sizeof(from
));
214 memset(to
, 0xFF, sizeof(to
));
216 memeq(this->from
, from
, this->type
== TS_IPV4_ADDR_RANGE ?
4 : 16) &&
217 memeq(this->to
, to
, this->type
== TS_IPV4_ADDR_RANGE ?
4 : 16))
219 written
+= print_in_hook(data
, "dynamic");
223 if (this->type
== TS_IPV4_ADDR_RANGE
)
225 inet_ntop(AF_INET
, &this->from4
, from_str
, sizeof(from_str
));
229 inet_ntop(AF_INET6
, &this->from6
, from_str
, sizeof(from_str
));
231 if (this->netbits
== NON_SUBNET_ADDRESS_RANGE
)
233 if (this->type
== TS_IPV4_ADDR_RANGE
)
235 inet_ntop(AF_INET
, &this->to4
, to_str
, sizeof(to_str
));
239 inet_ntop(AF_INET6
, &this->to6
, to_str
, sizeof(to_str
));
241 written
+= print_in_hook(data
, "%s..%s", from_str
, to_str
);
245 written
+= print_in_hook(data
, "%s/%d", from_str
, this->netbits
);
249 /* check if we have protocol and/or port selectors */
250 has_proto
= this->protocol
!= 0;
251 has_ports
= !(this->from_port
== 0 && this->to_port
== 0xFFFF);
253 if (!has_proto
&& !has_ports
)
258 written
+= print_in_hook(data
, "[");
260 /* build protocol string */
263 struct protoent
*proto
= getprotobynumber(this->protocol
);
267 written
+= print_in_hook(data
, "%s", proto
->p_name
);
268 serv_proto
= proto
->p_name
;
272 written
+= print_in_hook(data
, "%d", this->protocol
);
276 if (has_proto
&& has_ports
)
278 written
+= print_in_hook(data
, "/");
281 /* build port string */
284 if (this->from_port
== this->to_port
)
286 struct servent
*serv
= getservbyport(htons(this->from_port
), serv_proto
);
290 written
+= print_in_hook(data
, "%s", serv
->s_name
);
294 written
+= print_in_hook(data
, "%d", this->from_port
);
299 written
+= print_in_hook(data
, "%d-%d", this->from_port
, this->to_port
);
303 written
+= print_in_hook(data
, "]");
309 * Implements traffic_selector_t.get_subset
311 static traffic_selector_t
*get_subset(private_traffic_selector_t
*this, private_traffic_selector_t
*other
)
313 if (this->dynamic
|| other
->dynamic
)
314 { /* no set_address() applied, TS has no subset */
317 if (this->type
== other
->type
&& (this->protocol
== other
->protocol
||
318 this->protocol
== 0 || other
->protocol
== 0))
320 u_int16_t from_port
, to_port
;
324 private_traffic_selector_t
*new_ts
;
326 /* calculate the maximum port range allowed for both */
327 from_port
= max(this->from_port
, other
->from_port
);
328 to_port
= min(this->to_port
, other
->to_port
);
329 if (from_port
> to_port
)
333 /* select protocol, which is not zero */
334 protocol
= max(this->protocol
, other
->protocol
);
338 case TS_IPV4_ADDR_RANGE
:
339 size
= sizeof(this->from4
);
341 case TS_IPV6_ADDR_RANGE
:
342 size
= sizeof(this->from6
);
348 /* get higher from-address */
349 if (memcmp(this->from
, other
->from
, size
) > 0)
357 /* get lower to-address */
358 if (memcmp(this->to
, other
->to
, size
) > 0)
366 /* if "from" > "to", we don't have a match */
367 if (memcmp(from
, to
, size
) > 0)
372 /* we have a match in protocol, port, and address: return it... */
373 new_ts
= traffic_selector_create(protocol
, this->type
, from_port
, to_port
);
374 memcpy(new_ts
->from
, from
, size
);
375 memcpy(new_ts
->to
, to
, size
);
376 calc_netbits(new_ts
);
377 return &new_ts
->public;
383 * Implements traffic_selector_t.equals
385 static bool equals(private_traffic_selector_t
*this, private_traffic_selector_t
*other
)
387 if (this->type
!= other
->type
)
391 if (!(this->from_port
== other
->from_port
&&
392 this->to_port
== other
->to_port
&&
393 this->protocol
== other
->protocol
))
399 case TS_IPV4_ADDR_RANGE
:
400 if (memeq(this->from4
, other
->from4
, sizeof(this->from4
)) &&
401 memeq(this->to4
, other
->to4
, sizeof(this->to4
)))
406 case TS_IPV6_ADDR_RANGE
:
407 if (memeq(this->from6
, other
->from6
, sizeof(this->from6
)) &&
408 memeq(this->to6
, other
->to6
, sizeof(this->to6
)))
419 METHOD(traffic_selector_t
, get_from_address
, chunk_t
,
420 private_traffic_selector_t
*this)
424 case TS_IPV4_ADDR_RANGE
:
425 return chunk_create(this->from
, sizeof(this->from4
));
426 case TS_IPV6_ADDR_RANGE
:
427 return chunk_create(this->from
, sizeof(this->from6
));
433 METHOD(traffic_selector_t
, get_to_address
, chunk_t
,
434 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
));
447 METHOD(traffic_selector_t
, get_from_port
, u_int16_t
,
448 private_traffic_selector_t
*this)
450 return this->from_port
;
453 METHOD(traffic_selector_t
, get_to_port
, u_int16_t
,
454 private_traffic_selector_t
*this)
456 return this->to_port
;
459 METHOD(traffic_selector_t
, get_type
, ts_type_t
,
460 private_traffic_selector_t
*this)
465 METHOD(traffic_selector_t
, get_protocol
, u_int8_t
,
466 private_traffic_selector_t
*this)
468 return this->protocol
;
471 METHOD(traffic_selector_t
, is_host
, bool,
472 private_traffic_selector_t
*this, host_t
*host
)
477 int family
= host
->get_family(host
);
479 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
480 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
482 addr
= host
->get_address(host
);
483 if (memeq(addr
.ptr
, this->from
, addr
.len
) &&
484 memeq(addr
.ptr
, this->to
, addr
.len
))
492 size_t length
= (this->type
== TS_IPV4_ADDR_RANGE
) ?
4 : 16;
499 if (memeq(this->from
, this->to
, length
))
507 METHOD(traffic_selector_t
, is_dynamic
, bool,
508 private_traffic_selector_t
*this)
510 return this->dynamic
;
513 METHOD(traffic_selector_t
, set_address
, void,
514 private_traffic_selector_t
*this, host_t
*host
)
518 this->type
= host
->get_family(host
) == AF_INET ?
519 TS_IPV4_ADDR_RANGE
: TS_IPV6_ADDR_RANGE
;
521 if (host
->is_anyaddr(host
))
523 memset(this->from6
, 0x00, sizeof(this->from6
));
524 memset(this->to6
, 0xFF, sizeof(this->to6
));
529 chunk_t from
= host
->get_address(host
);
530 memcpy(this->from
, from
.ptr
, from
.len
);
531 memcpy(this->to
, from
.ptr
, from
.len
);
532 this->netbits
= from
.len
* 8;
534 this->dynamic
= FALSE
;
539 * Implements traffic_selector_t.is_contained_in.
541 static bool is_contained_in(private_traffic_selector_t
*this,
542 private_traffic_selector_t
*other
)
544 private_traffic_selector_t
*subset
;
545 bool contained_in
= FALSE
;
547 subset
= (private_traffic_selector_t
*)get_subset(this, other
);
551 if (equals(subset
, this))
560 METHOD(traffic_selector_t
, includes
, bool,
561 private_traffic_selector_t
*this, host_t
*host
)
564 int family
= host
->get_family(host
);
566 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
567 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
569 addr
= host
->get_address(host
);
571 return memcmp(this->from
, addr
.ptr
, addr
.len
) <= 0 &&
572 memcmp(this->to
, addr
.ptr
, addr
.len
) >= 0;
578 METHOD(traffic_selector_t
, to_subnet
, bool,
579 private_traffic_selector_t
*this, host_t
**net
, u_int8_t
*mask
)
581 /* there is no way to do this cleanly, as the address range may
582 * be anything else but a subnet. We use from_addr as subnet
583 * and try to calculate a usable subnet mask.
585 int family
, non_zero_bytes
;
589 *mask
= (this->netbits
== NON_SUBNET_ADDRESS_RANGE
) ?
calc_netbits(this)
594 case TS_IPV4_ADDR_RANGE
:
596 net_chunk
.len
= sizeof(this->from4
);
598 case TS_IPV6_ADDR_RANGE
:
600 net_chunk
.len
= sizeof(this->from6
);
607 net_chunk
.ptr
= malloc(net_chunk
.len
);
608 memset(net_chunk
.ptr
, 0x00, net_chunk
.len
);
611 non_zero_bytes
= (*mask
+ 7) / 8;
612 memcpy(net_chunk
.ptr
, this->from
, non_zero_bytes
);
613 net_chunk
.ptr
[non_zero_bytes
-1] &= 0xFF << (8 * non_zero_bytes
- *mask
);
616 if (this->to_port
== this->from_port
)
618 port
= this->to_port
;
621 *net
= host_create_from_chunk(family
, net_chunk
, port
);
622 chunk_free(&net_chunk
);
624 return this->netbits
!= NON_SUBNET_ADDRESS_RANGE
;
627 METHOD(traffic_selector_t
, clone_
, traffic_selector_t
*,
628 private_traffic_selector_t
*this)
630 private_traffic_selector_t
*clone
;
632 clone
= traffic_selector_create(this->protocol
, this->type
,
633 this->from_port
, this->to_port
);
634 clone
->netbits
= this->netbits
;
635 clone
->dynamic
= this->dynamic
;
639 case TS_IPV4_ADDR_RANGE
:
640 memcpy(clone
->from4
, this->from4
, sizeof(this->from4
));
641 memcpy(clone
->to4
, this->to4
, sizeof(this->to4
));
642 return &clone
->public;
643 case TS_IPV6_ADDR_RANGE
:
644 memcpy(clone
->from6
, this->from6
, sizeof(this->from6
));
645 memcpy(clone
->to6
, this->to6
, sizeof(this->to6
));
646 return &clone
->public;
649 return &clone
->public;
653 METHOD(traffic_selector_t
, destroy
, void,
654 private_traffic_selector_t
*this)
662 traffic_selector_t
*traffic_selector_create_from_bytes(u_int8_t protocol
,
664 chunk_t from
, u_int16_t from_port
,
665 chunk_t to
, u_int16_t to_port
)
667 private_traffic_selector_t
*this = traffic_selector_create(protocol
, type
,
672 case TS_IPV4_ADDR_RANGE
:
673 if (from
.len
!= 4 || to
.len
!= 4)
678 memcpy(this->from4
, from
.ptr
, from
.len
);
679 memcpy(this->to4
, to
.ptr
, to
.len
);
681 case TS_IPV6_ADDR_RANGE
:
682 if (from
.len
!= 16 || to
.len
!= 16)
687 memcpy(this->from6
, from
.ptr
, from
.len
);
688 memcpy(this->to6
, to
.ptr
, to
.len
);
695 return (&this->public);
701 traffic_selector_t
*traffic_selector_create_from_rfc3779_format(ts_type_t type
,
702 chunk_t from
, chunk_t to
)
705 private_traffic_selector_t
*this = traffic_selector_create(0, type
, 0, 65535);
709 case TS_IPV4_ADDR_RANGE
:
712 case TS_IPV6_ADDR_RANGE
:
719 memset(this->from
, 0x00, len
);
720 memset(this->to
, 0xff, len
);
724 memcpy(this->from
, from
.ptr
+1, from
.len
-1);
728 u_int8_t mask
= to
.ptr
[0] ?
(1 << to
.ptr
[0]) - 1 : 0;
730 memcpy(this->to
, to
.ptr
+1, to
.len
-1);
731 this->to
[to
.len
-2] |= mask
;
733 this->netbits
= chunk_equals(from
, to
) ?
(from
.len
-1)*8 - from
.ptr
[0]
734 : NON_SUBNET_ADDRESS_RANGE
;
735 return (&this->public);
741 traffic_selector_t
*traffic_selector_create_from_subnet(host_t
*net
,
742 u_int8_t netbits
, u_int8_t protocol
, u_int16_t port
)
744 private_traffic_selector_t
*this;
747 this = traffic_selector_create(protocol
, 0, 0, 65535);
749 switch (net
->get_family(net
))
752 this->type
= TS_IPV4_ADDR_RANGE
;
755 this->type
= TS_IPV6_ADDR_RANGE
;
762 from
= net
->get_address(net
);
763 memcpy(this->from
, from
.ptr
, from
.len
);
764 netbits
= min(netbits
, this->type
== TS_IPV4_ADDR_RANGE ?
32 : 128);
765 calc_range(this, netbits
);
768 this->from_port
= port
;
769 this->to_port
= port
;
773 return &this->public;
779 traffic_selector_t
*traffic_selector_create_from_string(
780 u_int8_t protocol
, ts_type_t type
,
781 char *from_addr
, u_int16_t from_port
,
782 char *to_addr
, u_int16_t to_port
)
784 private_traffic_selector_t
*this = traffic_selector_create(protocol
, type
,
789 case TS_IPV4_ADDR_RANGE
:
790 if (inet_pton(AF_INET
, from_addr
, (struct in_addr
*)this->from4
) < 0)
795 if (inet_pton(AF_INET
, to_addr
, (struct in_addr
*)this->to4
) < 0)
801 case TS_IPV6_ADDR_RANGE
:
802 if (inet_pton(AF_INET6
, from_addr
, (struct in6_addr
*)this->from6
) < 0)
807 if (inet_pton(AF_INET6
, to_addr
, (struct in6_addr
*)this->to6
) < 0)
815 return (&this->public);
821 traffic_selector_t
*traffic_selector_create_dynamic(u_int8_t protocol
,
822 u_int16_t from_port
, u_int16_t to_port
)
824 private_traffic_selector_t
*this = traffic_selector_create(
825 protocol
, TS_IPV4_ADDR_RANGE
, from_port
, to_port
);
827 memset(this->from6
, 0, sizeof(this->from6
));
828 memset(this->to6
, 0xFF, sizeof(this->to6
));
830 this->dynamic
= TRUE
;
832 return &this->public;
838 static private_traffic_selector_t
*traffic_selector_create(u_int8_t protocol
,
839 ts_type_t type
, u_int16_t from_port
, u_int16_t to_port
)
841 private_traffic_selector_t
*this;
845 .get_subset
= (traffic_selector_t
*(*)(traffic_selector_t
*,traffic_selector_t
*))get_subset
,
846 .equals
= (bool(*)(traffic_selector_t
*,traffic_selector_t
*))equals
,
847 .get_from_address
= _get_from_address
,
848 .get_to_address
= _get_to_address
,
849 .get_from_port
= _get_from_port
,
850 .get_to_port
= _get_to_port
,
851 .get_type
= _get_type
,
852 .get_protocol
= _get_protocol
,
854 .is_dynamic
= _is_dynamic
,
855 .is_contained_in
= (bool(*)(traffic_selector_t
*,traffic_selector_t
*))is_contained_in
,
856 .includes
= _includes
,
857 .set_address
= _set_address
,
858 .to_subnet
= _to_subnet
,
862 .from_port
= from_port
,
864 .protocol
= protocol
,