2 * Copyright (C) 2007-2017 Tobias Brunner
3 * Copyright (C) 2005-2007 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
6 * Copyright (C) secunet Security Networks AG
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 #include "traffic_selector.h"
24 #include <utils/debug.h>
25 #include <utils/utils.h>
26 #include <utils/identification.h>
27 #include <collections/linked_list.h>
31 #define TS_IP_LEN(this) ({ ((this)->type == TS_IPV4_ADDR_RANGE) ? IPV4_LEN : IPV6_LEN; })
33 #define NON_SUBNET_ADDRESS_RANGE 255
35 ENUM_BEGIN(ts_type_name
, TS_IPV4_ADDR_RANGE
, TS_IPV6_ADDR_RANGE
,
37 "TS_IPV6_ADDR_RANGE");
38 ENUM_NEXT(ts_type_name
, TS_SECLABEL
, TS_SECLABEL
, TS_IPV6_ADDR_RANGE
,
40 ENUM_END(ts_type_name
, TS_SECLABEL
);
42 typedef struct private_traffic_selector_t private_traffic_selector_t
;
45 * Private data of an traffic_selector_t object
47 struct private_traffic_selector_t
{
52 traffic_selector_t
public;
60 * IP protocol (UDP, TCP, ICMP, ...)
65 * narrow this traffic selector to hosts external ip
66 * if set, from and to have no meaning until set_address() is called
71 * subnet size in CIDR notation, 255 means a non-subnet address range
76 * begin of address range, network order
81 * end of address range, network order
97 * calculate the "to"-address for the "from" address and a subnet size
99 static void calc_range(private_traffic_selector_t
*this, uint8_t netbits
)
105 this->netbits
= netbits
;
107 len
= TS_IP_LEN(this);
108 bytes
= (netbits
+ 7)/8;
109 bits
= (bytes
* 8) - netbits
;
110 mask
= bits
? (1 << bits
) - 1 : 0;
112 memcpy(this->to
, this->from
, bytes
);
113 memset(this->from
+ bytes
, 0x00, len
- bytes
);
114 memset(this->to
+ bytes
, 0xff, len
- bytes
);
118 this->from
[bytes
-1] &= ~mask
;
119 this->to
[bytes
-1] |= mask
;
124 * calculate the subnet size from the "to" and "from" addresses
126 static uint8_t calc_netbits(private_traffic_selector_t
*this)
130 size_t size
= TS_IP_LEN(this);
133 /* a perfect match results in a single address with a /32 or /128 netmask */
134 netbits
= (size
* 8);
135 this->netbits
= netbits
;
137 /* go through 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 uint8_t bitmask
= 1 << bit
;
148 if ((bitmask
& this->from
[byte
]) != (bitmask
& this->to
[byte
]))
150 /* store the common prefix which might be a true subnet */
151 netbits
= (7 - bit
) + (byte
* 8);
152 this->netbits
= netbits
;
158 if ((bitmask
& this->from
[byte
]) || !(bitmask
& this->to
[byte
]))
160 this->netbits
= NON_SUBNET_ADDRESS_RANGE
;
161 return netbits
; /* return a pseudo subnet */
167 return netbits
; /* return a true subnet */
171 * internal generic constructor
173 static private_traffic_selector_t
*traffic_selector_create(uint8_t protocol
,
174 ts_type_t type
, uint16_t from_port
, uint16_t to_port
);
177 * Check if TS contains "opaque" ports
179 static bool is_opaque(private_traffic_selector_t
*this)
181 return this->from_port
== 0xffff && this->to_port
== 0;
185 * Check if TS contains "any" ports
187 static bool is_any(private_traffic_selector_t
*this)
189 return this->from_port
== 0 && this->to_port
== 0xffff;
193 * Print ICMP/ICMPv6 type and code
195 static int print_icmp(printf_hook_data_t
*data
, uint16_t port
)
199 type
= traffic_selector_icmp_type(port
);
200 code
= traffic_selector_icmp_code(port
);
203 return print_in_hook(data
, "%d(%d)", type
, code
);
205 return print_in_hook(data
, "%d", type
);
209 * Described in header.
211 int traffic_selector_printf_hook(printf_hook_data_t
*data
,
212 printf_hook_spec_t
*spec
, const void *const *args
)
214 private_traffic_selector_t
*this = *((private_traffic_selector_t
**)(args
[0]));
215 linked_list_t
*list
= *((linked_list_t
**)(args
[0]));
216 enumerator_t
*enumerator
;
217 char from_str
[INET6_ADDRSTRLEN
] = "";
218 char to_str
[INET6_ADDRSTRLEN
] = "";
219 char *serv_proto
= NULL
, *sep
= "";
220 bool has_proto
, has_ports
;
221 size_t written
= 0, len
;
222 char from
[IPV6_LEN
], to
[IPV6_LEN
];
226 return print_in_hook(data
, "(null)");
231 enumerator
= list
->create_enumerator(list
);
232 while (enumerator
->enumerate(enumerator
, (void**)&this))
234 written
+= print_in_hook(data
, "%s%R", sep
, this);
237 enumerator
->destroy(enumerator
);
241 len
= TS_IP_LEN(this);
242 memset(from
, 0, len
);
243 memset(to
, 0xFF, len
);
245 memeq(this->from
, from
, len
) && memeq(this->to
, to
, len
))
247 written
+= print_in_hook(data
, "dynamic");
251 if (this->type
== TS_IPV4_ADDR_RANGE
)
253 inet_ntop(AF_INET
, &this->from
, from_str
, sizeof(from_str
));
257 inet_ntop(AF_INET6
, &this->from
, from_str
, sizeof(from_str
));
259 if (this->netbits
== NON_SUBNET_ADDRESS_RANGE
)
261 if (this->type
== TS_IPV4_ADDR_RANGE
)
263 inet_ntop(AF_INET
, &this->to
, to_str
, sizeof(to_str
));
267 inet_ntop(AF_INET6
, &this->to
, to_str
, sizeof(to_str
));
269 written
+= print_in_hook(data
, "%s..%s", from_str
, to_str
);
273 written
+= print_in_hook(data
, "%s/%d", from_str
, this->netbits
);
277 /* check if we have protocol and/or port selectors */
278 has_proto
= this->protocol
!= 0;
279 has_ports
= !is_any(this);
281 if (!has_proto
&& !has_ports
)
286 written
+= print_in_hook(data
, "[");
288 /* build protocol string */
291 struct protoent
*proto
= getprotobynumber(this->protocol
);
295 written
+= print_in_hook(data
, "%s", proto
->p_name
);
296 serv_proto
= proto
->p_name
;
300 written
+= print_in_hook(data
, "%d", this->protocol
);
305 written
+= print_in_hook(data
, "0");
308 /* build port string */
311 written
+= print_in_hook(data
, "/");
313 if (this->from_port
== this->to_port
)
315 struct servent
*serv
;
317 if (this->protocol
== IPPROTO_ICMP
||
318 this->protocol
== IPPROTO_ICMPV6
)
320 written
+= print_icmp(data
, this->from_port
);
324 serv
= getservbyport(htons(this->from_port
), serv_proto
);
327 written
+= print_in_hook(data
, "%s", serv
->s_name
);
331 written
+= print_in_hook(data
, "%d", this->from_port
);
335 else if (is_opaque(this))
337 written
+= print_in_hook(data
, "OPAQUE");
339 else if (this->protocol
== IPPROTO_ICMP
||
340 this->protocol
== IPPROTO_ICMPV6
)
342 written
+= print_icmp(data
, this->from_port
);
343 written
+= print_in_hook(data
, "-");
344 written
+= print_icmp(data
, this->to_port
);
348 written
+= print_in_hook(data
, "%d-%d",
349 this->from_port
, this->to_port
);
353 written
+= print_in_hook(data
, "]");
358 METHOD(traffic_selector_t
, get_subset
, traffic_selector_t
*,
359 private_traffic_selector_t
*this, traffic_selector_t
*other_public
)
361 private_traffic_selector_t
*other
, *subset
;
362 uint16_t from_port
, to_port
;
367 other
= (private_traffic_selector_t
*)other_public
;
369 if (this->dynamic
|| other
->dynamic
)
370 { /* no set_address() applied, TS has no subset */
374 if (this->type
!= other
->type
)
379 if (this->protocol
!= other
->protocol
&&
380 this->protocol
!= 0 && other
->protocol
!= 0)
384 /* select protocol, which is not zero */
385 protocol
= max(this->protocol
, other
->protocol
);
387 if ((is_opaque(this) && is_opaque(other
)) ||
388 (is_opaque(this) && is_any(other
)) ||
389 (is_opaque(other
) && is_any(this)))
396 /* calculate the maximum port range allowed for both */
397 from_port
= max(this->from_port
, other
->from_port
);
398 to_port
= min(this->to_port
, other
->to_port
);
399 if (from_port
> to_port
)
404 size
= TS_IP_LEN(this);
405 /* get higher from-address */
406 if (memcmp(this->from
, other
->from
, size
) > 0)
414 /* get lower to-address */
415 if (memcmp(this->to
, other
->to
, size
) > 0)
423 /* if "from" > "to", we don't have a match */
424 if (memcmp(from
, to
, size
) > 0)
429 /* we have a match in protocol, port, and address: return it... */
430 subset
= traffic_selector_create(protocol
, this->type
, from_port
, to_port
);
431 memcpy(subset
->from
, from
, size
);
432 memcpy(subset
->to
, to
, size
);
433 calc_netbits(subset
);
435 return &subset
->public;
438 METHOD(traffic_selector_t
, equals
, bool,
439 private_traffic_selector_t
*this, traffic_selector_t
*other
)
441 return traffic_selector_cmp(&this->public, other
, NULL
) == 0;
444 METHOD(traffic_selector_t
, get_from_address
, chunk_t
,
445 private_traffic_selector_t
*this)
447 return chunk_create(this->from
, TS_IP_LEN(this));
450 METHOD(traffic_selector_t
, get_to_address
, chunk_t
,
451 private_traffic_selector_t
*this)
453 return chunk_create(this->to
, TS_IP_LEN(this));
456 METHOD(traffic_selector_t
, get_from_port
, uint16_t,
457 private_traffic_selector_t
*this)
459 return this->from_port
;
462 METHOD(traffic_selector_t
, get_to_port
, uint16_t,
463 private_traffic_selector_t
*this)
465 return this->to_port
;
468 METHOD(traffic_selector_t
, get_type
, ts_type_t
,
469 private_traffic_selector_t
*this)
474 METHOD(traffic_selector_t
, get_protocol
, uint8_t,
475 private_traffic_selector_t
*this)
477 return this->protocol
;
480 METHOD(traffic_selector_t
, is_host
, bool,
481 private_traffic_selector_t
*this, host_t
*host
)
486 int family
= host
->get_family(host
);
488 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
489 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
491 addr
= host
->get_address(host
);
492 if (memeq(addr
.ptr
, this->from
, addr
.len
) &&
493 memeq(addr
.ptr
, this->to
, addr
.len
))
501 size_t length
= TS_IP_LEN(this);
508 if (memeq(this->from
, this->to
, length
))
516 METHOD(traffic_selector_t
, is_dynamic
, bool,
517 private_traffic_selector_t
*this)
519 return this->dynamic
;
522 METHOD(traffic_selector_t
, set_address
, void,
523 private_traffic_selector_t
*this, host_t
*host
)
525 this->type
= host
->get_family(host
) == AF_INET
? TS_IPV4_ADDR_RANGE
526 : TS_IPV6_ADDR_RANGE
;
528 if (host
->is_anyaddr(host
))
530 memset(this->from
, 0x00, sizeof(this->from
));
531 memset(this->to
, 0xFF, sizeof(this->to
));
536 chunk_t from
= host
->get_address(host
);
537 memcpy(this->from
, from
.ptr
, from
.len
);
538 memcpy(this->to
, from
.ptr
, from
.len
);
539 this->netbits
= from
.len
* 8;
541 this->dynamic
= FALSE
;
544 METHOD(traffic_selector_t
, is_contained_in
, bool,
545 private_traffic_selector_t
*this, traffic_selector_t
*other
)
547 private_traffic_selector_t
*subset
;
548 bool contained_in
= FALSE
;
550 subset
= (private_traffic_selector_t
*)get_subset(this, other
);
554 if (equals(subset
, &this->public))
563 METHOD(traffic_selector_t
, includes
, bool,
564 private_traffic_selector_t
*this, host_t
*host
)
567 int family
= host
->get_family(host
);
569 if ((family
== AF_INET
&& this->type
== TS_IPV4_ADDR_RANGE
) ||
570 (family
== AF_INET6
&& this->type
== TS_IPV6_ADDR_RANGE
))
572 addr
= host
->get_address(host
);
574 return memcmp(this->from
, addr
.ptr
, addr
.len
) <= 0 &&
575 memcmp(this->to
, addr
.ptr
, addr
.len
) >= 0;
581 METHOD(traffic_selector_t
, to_subnet
, bool,
582 private_traffic_selector_t
*this, host_t
**net
, uint8_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.
588 int family
, non_zero_bytes
;
592 *mask
= (this->netbits
== NON_SUBNET_ADDRESS_RANGE
) ? calc_netbits(this)
597 case TS_IPV4_ADDR_RANGE
:
599 net_chunk
.len
= IPV4_LEN
;
601 case TS_IPV6_ADDR_RANGE
:
603 net_chunk
.len
= IPV6_LEN
;
610 net_chunk
.ptr
= malloc(net_chunk
.len
);
611 memset(net_chunk
.ptr
, 0x00, net_chunk
.len
);
614 non_zero_bytes
= (*mask
+ 7) / 8;
615 memcpy(net_chunk
.ptr
, this->from
, non_zero_bytes
);
616 net_chunk
.ptr
[non_zero_bytes
-1] &= 0xFF << (8 * non_zero_bytes
- *mask
);
619 if (this->to_port
== this->from_port
)
621 port
= this->to_port
;
624 *net
= host_create_from_chunk(family
, net_chunk
, port
);
625 chunk_free(&net_chunk
);
627 return this->netbits
!= NON_SUBNET_ADDRESS_RANGE
;
630 METHOD(traffic_selector_t
, clone_
, traffic_selector_t
*,
631 private_traffic_selector_t
*this)
633 private_traffic_selector_t
*clone
;
634 size_t len
= TS_IP_LEN(this);
636 clone
= traffic_selector_create(this->protocol
, this->type
,
637 this->from_port
, this->to_port
);
638 clone
->netbits
= this->netbits
;
639 clone
->dynamic
= this->dynamic
;
641 memcpy(clone
->from
, this->from
, len
);
642 memcpy(clone
->to
, this->to
, len
);
643 return &clone
->public;
646 METHOD(traffic_selector_t
, hash
, u_int
,
647 private_traffic_selector_t
*this, u_int hash
)
649 return chunk_hash_inc(get_from_address(this),
650 chunk_hash_inc(get_to_address(this),
651 chunk_hash_inc(chunk_from_thing(this->from_port
),
652 chunk_hash_inc(chunk_from_thing(this->to_port
),
653 chunk_hash_inc(chunk_from_thing(this->protocol
),
657 METHOD(traffic_selector_t
, destroy
, void,
658 private_traffic_selector_t
*this)
664 * Compare two integers
666 static int compare_int(int a
, int b
)
674 int traffic_selector_cmp(traffic_selector_t
*a_pub
, traffic_selector_t
*b_pub
,
677 private_traffic_selector_t
*a
, *b
;
681 a
= (private_traffic_selector_t
*)a_pub
;
682 b
= (private_traffic_selector_t
*)b_pub
;
684 /* IPv4 before IPv6 */
685 res
= compare_int(a
->type
, b
->type
);
691 /* lower starting subnets first */
692 res
= memcmp(a
->from
, b
->from
, len
);
697 /* larger subnets first */
698 res
= memcmp(b
->to
, a
->to
, len
);
703 /* lower protocols first */
704 res
= compare_int(a
->protocol
, b
->protocol
);
709 /* lower starting ports first */
710 res
= compare_int(a
->from_port
, b
->from_port
);
715 /* larger port ranges first */
716 return compare_int(b
->to_port
, a
->to_port
);
722 traffic_selector_t
*traffic_selector_create_from_bytes(uint8_t protocol
,
724 chunk_t from
, uint16_t from_port
,
725 chunk_t to
, uint16_t to_port
)
727 private_traffic_selector_t
*this = traffic_selector_create(protocol
, type
,
734 if (from
.len
!= to
.len
|| from
.len
!= TS_IP_LEN(this))
739 memcpy(this->from
, from
.ptr
, from
.len
);
740 memcpy(this->to
, to
.ptr
, to
.len
);
742 return &this->public;
748 traffic_selector_t
*traffic_selector_create_from_rfc3779_format(ts_type_t type
,
749 chunk_t from
, chunk_t to
)
751 private_traffic_selector_t
*this = traffic_selector_create(0, type
, 0, 65535);
758 len
= TS_IP_LEN(this);
760 memset(this->from
, 0x00, len
);
761 memset(this->to
, 0xff, len
);
765 memcpy(this->from
, from
.ptr
+1, from
.len
-1);
769 uint8_t mask
= to
.ptr
[0] ? (1 << to
.ptr
[0]) - 1 : 0;
771 memcpy(this->to
, to
.ptr
+1, to
.len
-1);
772 this->to
[to
.len
-2] |= mask
;
775 return &this->public;
781 traffic_selector_t
*traffic_selector_create_from_subnet(host_t
*net
,
782 uint8_t netbits
, uint8_t protocol
,
783 uint16_t from_port
, uint16_t to_port
)
785 private_traffic_selector_t
*this;
789 switch (net
->get_family(net
))
792 type
= TS_IPV4_ADDR_RANGE
;
795 type
= TS_IPV6_ADDR_RANGE
;
802 this = traffic_selector_create(protocol
, type
, from_port
, to_port
);
804 from
= net
->get_address(net
);
805 memcpy(this->from
, from
.ptr
, from
.len
);
806 netbits
= min(netbits
, TS_IP_LEN(this) * 8);
807 calc_range(this, netbits
);
809 return &this->public;
815 traffic_selector_t
*traffic_selector_create_from_string(
816 uint8_t protocol
, ts_type_t type
,
817 char *from_addr
, uint16_t from_port
,
818 char *to_addr
, uint16_t to_port
)
820 private_traffic_selector_t
*this;
825 case TS_IPV4_ADDR_RANGE
:
828 case TS_IPV6_ADDR_RANGE
:
835 this = traffic_selector_create(protocol
, type
, from_port
, to_port
);
837 if (inet_pton(family
, from_addr
, this->from
) != 1 ||
838 inet_pton(family
, to_addr
, this->to
) != 1)
844 return &this->public;
850 traffic_selector_t
*traffic_selector_create_from_cidr(
851 char *string
, uint8_t protocol
,
852 uint16_t from_port
, uint16_t to_port
)
857 net
= host_create_from_subnet(string
, &bits
);
860 return traffic_selector_create_from_subnet(net
, bits
, protocol
,
869 traffic_selector_t
*traffic_selector_create_dynamic(uint8_t protocol
,
870 uint16_t from_port
, uint16_t to_port
)
872 private_traffic_selector_t
*this = traffic_selector_create(
873 protocol
, TS_IPV4_ADDR_RANGE
, from_port
, to_port
);
875 memset(this->from
, 0, sizeof(this->from
));
876 memset(this->to
, 0xFF, sizeof(this->to
));
878 this->dynamic
= TRUE
;
880 return &this->public;
886 static private_traffic_selector_t
*traffic_selector_create(uint8_t protocol
,
887 ts_type_t type
, uint16_t from_port
, uint16_t to_port
)
889 private_traffic_selector_t
*this;
892 if (type
!= TS_IPV4_ADDR_RANGE
&& type
!= TS_IPV6_ADDR_RANGE
)
899 .get_subset
= _get_subset
,
901 .get_from_address
= _get_from_address
,
902 .get_to_address
= _get_to_address
,
903 .get_from_port
= _get_from_port
,
904 .get_to_port
= _get_to_port
,
905 .get_type
= _get_type
,
906 .get_protocol
= _get_protocol
,
908 .is_dynamic
= _is_dynamic
,
909 .is_contained_in
= _is_contained_in
,
910 .includes
= _includes
,
911 .set_address
= _set_address
,
912 .to_subnet
= _to_subnet
,
917 .from_port
= from_port
,
919 .protocol
= protocol
,
922 if (protocol
== IPPROTO_ICMP
|| protocol
== IPPROTO_ICMPV6
)
924 this->from_port
= from_port
< 256 ? from_port
<< 8 : from_port
;
925 this->to_port
= to_port
< 256 ? to_port
<< 8 : to_port
;