2 * Copyright (C) 2007 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
20 #include <arpa/inet.h>
26 #include "traffic_selector.h"
29 #include <utils/linked_list.h>
30 #include <utils/identification.h>
32 ENUM(ts_type_name
, TS_IPV4_ADDR_RANGE
, TS_IPV6_ADDR_RANGE
,
37 typedef struct private_traffic_selector_t private_traffic_selector_t
;
40 * Private data of an traffic_selector_t object
42 struct private_traffic_selector_t
{
47 traffic_selector_t
public;
55 * IP protocol (UDP, TCP, ICMP, ...)
60 * narrow this traffic selector to hosts external ip
61 * if set, from and to have no meaning until set_address() is called
66 * begin of address range, network order
69 /** dummy char for common address manipulation */
78 * end of address range, network order
81 /** dummy char for common address manipulation */
101 * calculate to "to"-address for the "from" address and a subnet size
103 static void calc_range(private_traffic_selector_t
*this, u_int8_t netbits
)
106 size_t size
= (this->type
== TS_IPV4_ADDR_RANGE
) ?
4 : 16;
108 /* go through the from address, starting at the tail. While we
109 * have not processed the bits belonging to the host, set them to 1 on
110 * the to address. If we reach the bits for the net, copy them from "from". */
111 for (byte
= size
- 1; byte
>=0; byte
--)
116 shift
= (byte
+1) * 8 - netbits
;
125 this->to
[byte
] = this->from
[byte
] | mask
;
130 * calculate to subnet size from "to"- and "from"-address
132 static u_int8_t
calc_netbits(private_traffic_selector_t
*this)
135 size_t size
= (this->type
== TS_IPV4_ADDR_RANGE
) ?
4 : 16;
137 /* go trough all bits of the addresses, beginning in the front.
138 * as long as they are equal, the subnet gets larger
140 for (byte
= 0; byte
< size
; byte
++)
142 for (bit
= 7; bit
>= 0; bit
--)
144 if ((1<<bit
& this->from
[byte
]) != (1<<bit
& this->to
[byte
]))
146 return ((7 - bit
) + (byte
* 8));
150 /* single host, netmask is 32/128 */
155 * internal generic constructor
157 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
);
160 * output handler in printf()
162 static int print(FILE *stream
, const struct printf_info
*info
,
163 const void *const *args
)
165 private_traffic_selector_t
*this = *((private_traffic_selector_t
**)(args
[0]));
166 linked_list_t
*list
= *((linked_list_t
**)(args
[0]));
167 iterator_t
*iterator
;
168 char addr_str
[INET6_ADDRSTRLEN
] = "";
169 char *serv_proto
= NULL
;
174 u_int32_t from
[4], to
[4];
178 return fprintf(stream
, "(null)");
183 iterator
= list
->create_iterator(list
, TRUE
);
184 while (iterator
->iterate(iterator
, (void**)&this))
186 /* call recursivly */
187 written
+= fprintf(stream
, "%R ", this);
189 iterator
->destroy(iterator
);
193 memset(from
, 0, sizeof(from
));
194 memset(to
, 0xFF, sizeof(to
));
196 memeq(this->from
, from
, this->type
== TS_IPV4_ADDR_RANGE ?
4 : 16) &&
197 memeq(this->to
, to
, this->type
== TS_IPV4_ADDR_RANGE ?
4 : 16))
199 written
+= fprintf(stream
, "dynamic");
203 if (this->type
== TS_IPV4_ADDR_RANGE
)
205 inet_ntop(AF_INET
, &this->from4
, addr_str
, sizeof(addr_str
));
209 inet_ntop(AF_INET6
, &this->from6
, addr_str
, sizeof(addr_str
));
211 mask
= calc_netbits(this);
212 written
+= fprintf(stream
, "%s/%d", addr_str
, mask
);
215 /* check if we have protocol and/or port selectors */
216 has_proto
= this->protocol
!= 0;
217 has_ports
= !(this->from_port
== 0 && this->to_port
== 0xFFFF);
219 if (!has_proto
&& !has_ports
)
224 written
+= fprintf(stream
, "[");
226 /* build protocol string */
229 struct protoent
*proto
= getprotobynumber(this->protocol
);
233 written
+= fprintf(stream
, "%s", proto
->p_name
);
234 serv_proto
= proto
->p_name
;
238 written
+= fprintf(stream
, "%d", this->protocol
);
242 if (has_proto
&& has_ports
)
244 written
+= fprintf(stream
, "/");
247 /* build port string */
250 if (this->from_port
== this->to_port
)
252 struct servent
*serv
= getservbyport(htons(this->from_port
), serv_proto
);
256 written
+= fprintf(stream
, "%s", serv
->s_name
);
260 written
+= fprintf(stream
, "%d", this->from_port
);
265 written
+= fprintf(stream
, "%d-%d", this->from_port
, this->to_port
);
269 written
+= fprintf(stream
, "]");
275 * arginfo handler for printf() traffic selector
277 static int arginfo(const struct printf_info
*info
, size_t n
, int *argtypes
)
281 argtypes
[0] = PA_POINTER
;
287 * return printf hook functions for a chunk
289 printf_hook_functions_t
traffic_selector_get_printf_hooks()
291 printf_hook_functions_t hooks
= {print
, arginfo
};
297 * implements traffic_selector_t.get_subset
299 static traffic_selector_t
*get_subset(private_traffic_selector_t
*this, private_traffic_selector_t
*other
)
301 if (this->type
== other
->type
&& (this->protocol
== other
->protocol
||
302 this->protocol
== 0 || other
->protocol
== 0))
304 u_int16_t from_port
, to_port
;
308 private_traffic_selector_t
*new_ts
;
310 /* calculate the maximum port range allowed for both */
311 from_port
= max(this->from_port
, other
->from_port
);
312 to_port
= min(this->to_port
, other
->to_port
);
313 if (from_port
> to_port
)
317 /* select protocol, which is not zero */
318 protocol
= max(this->protocol
, other
->protocol
);
322 case TS_IPV4_ADDR_RANGE
:
323 size
= sizeof(this->from4
);
325 case TS_IPV6_ADDR_RANGE
:
326 size
= sizeof(this->from6
);
332 /* get higher from-address */
333 if (memcmp(this->from
, other
->from
, size
) > 0)
341 /* get lower to-address */
342 if (memcmp(this->to
, other
->to
, size
) > 0)
350 /* if "from" > "to", we don't have a match */
351 if (memcmp(from
, to
, size
) > 0)
356 /* we have a match in protocol, port, and address: return it... */
357 new_ts
= traffic_selector_create(protocol
, this->type
, from_port
, to_port
);
358 new_ts
->type
= this->type
;
359 new_ts
->dynamic
= this->dynamic
|| other
->dynamic
;
360 memcpy(new_ts
->from
, from
, size
);
361 memcpy(new_ts
->to
, to
, size
);
363 return &new_ts
->public;
369 * implements traffic_selector_t.equals
371 static bool equals(private_traffic_selector_t
*this, private_traffic_selector_t
*other
)
373 if (this->type
!= other
->type
)
377 if (!(this->from_port
== other
->from_port
&&
378 this->to_port
== other
->to_port
&&
379 this->protocol
== other
->protocol
))
385 case TS_IPV4_ADDR_RANGE
:
386 if (memeq(this->from4
, other
->from4
, sizeof(this->from4
)))
391 case TS_IPV6_ADDR_RANGE
:
392 if (memeq(this->from6
, other
->from6
, sizeof(this->from6
)))
404 * Implements traffic_selector_t.get_from_address.
406 static chunk_t
get_from_address(private_traffic_selector_t
*this)
410 case TS_IPV4_ADDR_RANGE
:
411 return chunk_create(this->from
, sizeof(this->from4
));
412 case TS_IPV6_ADDR_RANGE
:
413 return chunk_create(this->from
, sizeof(this->from6
));
420 * Implements traffic_selector_t.get_to_address.
422 static chunk_t
get_to_address(private_traffic_selector_t
*this)
426 case TS_IPV4_ADDR_RANGE
:
427 return chunk_create(this->to
, sizeof(this->to4
));
428 case TS_IPV6_ADDR_RANGE
:
429 return chunk_create(this->to
, sizeof(this->to6
));
436 * Implements traffic_selector_t.get_from_port.
438 static u_int16_t
get_from_port(private_traffic_selector_t
*this)
440 return this->from_port
;
444 * Implements traffic_selector_t.get_to_port.
446 static u_int16_t
get_to_port(private_traffic_selector_t
*this)
448 return this->to_port
;
452 * Implements traffic_selector_t.get_type.
454 static ts_type_t
get_type(private_traffic_selector_t
*this)
460 * Implements traffic_selector_t.get_protocol.
462 static u_int8_t
get_protocol(private_traffic_selector_t
*this)
464 return this->protocol
;
468 * Implements traffic_selector_t.is_host.
470 static bool is_host(private_traffic_selector_t
*this, host_t
*host
)
475 int family
= host
->get_family(host
);
477 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
478 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
480 addr
= host
->get_address(host
);
481 if (memeq(addr
.ptr
, this->from
, addr
.len
) &&
482 memeq(addr
.ptr
, this->to
, addr
.len
))
490 size_t length
= (this->type
== TS_IPV4_ADDR_RANGE
) ?
4 : 16;
497 if (memeq(this->from
, this->to
, length
))
506 * Implementation of traffic_selector_t.is_dynamic
508 static bool is_dynamic(private_traffic_selector_t
*this)
510 return this->dynamic
;
514 * Implements traffic_selector_t.set_address.
516 static void set_address(private_traffic_selector_t
*this, host_t
*host
)
520 this->type
= host
->get_family(host
) == AF_INET ?
521 TS_IPV4_ADDR_RANGE
: TS_IPV6_ADDR_RANGE
;
523 if (host
->is_anyaddr(host
))
525 memset(this->from6
, 0x00, sizeof(this->from6
));
526 memset(this->to6
, 0xFF, sizeof(this->to6
));
530 chunk_t from
= host
->get_address(host
);
531 memcpy(this->from
, from
.ptr
, from
.len
);
532 memcpy(this->to
, from
.ptr
, from
.len
);
538 * Implements traffic_selector_t.is_contained_in.
540 static bool is_contained_in(private_traffic_selector_t
*this,
541 private_traffic_selector_t
*other
)
543 private_traffic_selector_t
*subset
;
544 bool contained_in
= FALSE
;
546 subset
= (private_traffic_selector_t
*)get_subset(this, other
);
550 if (equals(subset
, this))
560 * Implements traffic_selector_t.includes.
562 static bool includes(private_traffic_selector_t
*this, host_t
*host
)
565 int family
= host
->get_family(host
);
567 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
568 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
570 addr
= host
->get_address(host
);
572 return memcmp(this->from
, addr
.ptr
, addr
.len
) <= 0 &&
573 memcmp(this->to
, addr
.ptr
, addr
.len
) >= 0;
580 * Implements traffic_selector_t.to_subnet.
582 static void to_subnet(private_traffic_selector_t
*this, host_t
**net
, u_int8_t
*mask
)
584 /* there is no way to do this cleanly, as the address range may
585 * be anything else but a subnet. We use from_addr as subnet
586 * and try to calculate a usable subnet mask.
592 *mask
= calc_netbits(this);
596 case TS_IPV4_ADDR_RANGE
:
599 net_chunk
.len
= sizeof(this->from4
);
602 case TS_IPV6_ADDR_RANGE
:
605 net_chunk
.len
= sizeof(this->from6
);
615 net_chunk
.ptr
= malloc(net_chunk
.len
);
616 memcpy(net_chunk
.ptr
, this->from
, net_chunk
.len
);
618 for (byte
= net_chunk
.len
- 1; byte
>= (*mask
/ 8); --byte
)
620 int shift
= (byte
+ 1) * 8 - *mask
;
621 net_chunk
.ptr
[byte
] = net_chunk
.ptr
[byte
] & (0xFF << shift
);
624 if (this->to_port
== this->from_port
)
626 port
= this->to_port
;
629 *net
= host_create_from_chunk(family
, net_chunk
, port
);
630 chunk_free(&net_chunk
);
634 * Implements traffic_selector_t.clone.
636 static traffic_selector_t
*clone_(private_traffic_selector_t
*this)
638 private_traffic_selector_t
*clone
;
640 clone
= traffic_selector_create(this->protocol
, this->type
,
641 this->from_port
, this->to_port
);
643 clone
->dynamic
= this->dynamic
;
646 case TS_IPV4_ADDR_RANGE
:
648 memcpy(clone
->from4
, this->from4
, sizeof(this->from4
));
649 memcpy(clone
->to4
, this->to4
, sizeof(this->to4
));
650 return &clone
->public;
652 case TS_IPV6_ADDR_RANGE
:
654 memcpy(clone
->from6
, this->from6
, sizeof(this->from6
));
655 memcpy(clone
->to6
, this->to6
, sizeof(this->to6
));
656 return &clone
->public;
661 return &clone
->public;
667 * Implements traffic_selector_t.destroy.
669 static void destroy(private_traffic_selector_t
*this)
677 traffic_selector_t
*traffic_selector_create_from_bytes(u_int8_t protocol
,
679 chunk_t from
, u_int16_t from_port
,
680 chunk_t to
, u_int16_t to_port
)
682 private_traffic_selector_t
*this = traffic_selector_create(protocol
, type
,
687 case TS_IPV4_ADDR_RANGE
:
689 if (from
.len
!= 4 || to
.len
!= 4)
694 memcpy(this->from4
, from
.ptr
, from
.len
);
695 memcpy(this->to4
, to
.ptr
, to
.len
);
698 case TS_IPV6_ADDR_RANGE
:
700 if (from
.len
!= 16 || to
.len
!= 16)
705 memcpy(this->from6
, from
.ptr
, from
.len
);
706 memcpy(this->to6
, to
.ptr
, to
.len
);
715 return (&this->public);
721 traffic_selector_t
*traffic_selector_create_from_subnet(host_t
*net
,
722 u_int8_t netbits
, u_int8_t protocol
, u_int16_t port
)
724 private_traffic_selector_t
*this = traffic_selector_create(protocol
, 0, 0, 65535);
726 switch (net
->get_family(net
))
732 this->type
= TS_IPV4_ADDR_RANGE
;
733 from
= net
->get_address(net
);
734 memcpy(this->from4
, from
.ptr
, from
.len
);
735 if (this->from4
[0] == 0)
737 /* use /0 for 0.0.0.0 */
742 calc_range(this, netbits
);
750 this->type
= TS_IPV6_ADDR_RANGE
;
751 from
= net
->get_address(net
);
752 memcpy(this->from6
, from
.ptr
, from
.len
);
753 if (this->from6
[0] == 0 && this->from6
[1] == 0 &&
754 this->from6
[2] == 0 && this->from6
[3] == 0)
764 calc_range(this, netbits
);
777 this->from_port
= port
;
778 this->to_port
= port
;
781 return (&this->public);
787 traffic_selector_t
*traffic_selector_create_from_string(
788 u_int8_t protocol
, ts_type_t type
,
789 char *from_addr
, u_int16_t from_port
,
790 char *to_addr
, u_int16_t to_port
)
792 private_traffic_selector_t
*this = traffic_selector_create(protocol
, type
,
798 case TS_IPV4_ADDR_RANGE
:
800 if (inet_pton(AF_INET
, from_addr
, (struct in_addr
*)this->from4
) < 0)
805 if (inet_pton(AF_INET
, to_addr
, (struct in_addr
*)this->to4
) < 0)
812 case TS_IPV6_ADDR_RANGE
:
814 if (inet_pton(AF_INET6
, from_addr
, (struct in6_addr
*)this->from6
) < 0)
819 if (inet_pton(AF_INET6
, to_addr
, (struct in6_addr
*)this->to6
) < 0)
827 return (&this->public);
833 traffic_selector_t
*traffic_selector_create_dynamic(u_int8_t protocol
,
834 u_int16_t from_port
, u_int16_t to_port
)
836 private_traffic_selector_t
*this = traffic_selector_create(
837 protocol
, TS_IPV4_ADDR_RANGE
, from_port
, to_port
);
839 memset(this->from6
, 0, sizeof(this->from6
));
840 memset(this->to6
, 0xFF, sizeof(this->to6
));
842 this->dynamic
= TRUE
;
844 return &this->public;
850 static private_traffic_selector_t
*traffic_selector_create(u_int8_t protocol
,
851 ts_type_t type
, u_int16_t from_port
, u_int16_t to_port
)
853 private_traffic_selector_t
*this = malloc_thing(private_traffic_selector_t
);
855 /* public functions */
856 this->public.get_subset
= (traffic_selector_t
*(*)(traffic_selector_t
*,traffic_selector_t
*))get_subset
;
857 this->public.equals
= (bool(*)(traffic_selector_t
*,traffic_selector_t
*))equals
;
858 this->public.get_from_address
= (chunk_t(*)(traffic_selector_t
*))get_from_address
;
859 this->public.get_to_address
= (chunk_t(*)(traffic_selector_t
*))get_to_address
;
860 this->public.get_from_port
= (u_int16_t(*)(traffic_selector_t
*))get_from_port
;
861 this->public.get_to_port
= (u_int16_t(*)(traffic_selector_t
*))get_to_port
;
862 this->public.get_type
= (ts_type_t(*)(traffic_selector_t
*))get_type
;
863 this->public.get_protocol
= (u_int8_t(*)(traffic_selector_t
*))get_protocol
;
864 this->public.is_host
= (bool(*)(traffic_selector_t
*,host_t
*))is_host
;
865 this->public.is_dynamic
= (bool(*)(traffic_selector_t
*))is_dynamic
;
866 this->public.is_contained_in
= (bool(*)(traffic_selector_t
*,traffic_selector_t
*))is_contained_in
;
867 this->public.includes
= (bool(*)(traffic_selector_t
*,host_t
*))includes
;
868 this->public.set_address
= (void(*)(traffic_selector_t
*,host_t
*))set_address
;
869 this->public.to_subnet
= (void(*)(traffic_selector_t
*,host_t
**,u_int8_t
*))to_subnet
;
870 this->public.clone
= (traffic_selector_t
*(*)(traffic_selector_t
*))clone_
;
871 this->public.destroy
= (void(*)(traffic_selector_t
*))destroy
;
873 this->from_port
= from_port
;
874 this->to_port
= to_port
;
875 this->protocol
= protocol
;
877 this->dynamic
= FALSE
;