diff options
Diffstat (limited to 'src/libstrongswan/selectors/traffic_selector.c')
-rw-r--r-- | src/libstrongswan/selectors/traffic_selector.c | 347 |
1 files changed, 184 insertions, 163 deletions
diff --git a/src/libstrongswan/selectors/traffic_selector.c b/src/libstrongswan/selectors/traffic_selector.c index b1bcf1b2d..75a8717dd 100644 --- a/src/libstrongswan/selectors/traffic_selector.c +++ b/src/libstrongswan/selectors/traffic_selector.c @@ -22,9 +22,9 @@ #include "traffic_selector.h" -#include <utils/linked_list.h> +#include <collections/linked_list.h> #include <utils/identification.h> -#include <debug.h> +#include <utils/debug.h> #define NON_SUBNET_ADDRESS_RANGE 255 @@ -174,13 +174,30 @@ static u_int8_t calc_netbits(private_traffic_selector_t *this) /** * internal generic constructor */ -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); +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); + +/** + * Check if TS contains "opaque" ports + */ +static bool is_opaque(private_traffic_selector_t *this) +{ + return this->from_port == 0xffff && this->to_port == 0; +} + +/** + * Check if TS contains "any" ports + */ +static bool is_any(private_traffic_selector_t *this) +{ + return this->from_port == 0 && this->to_port == 0xffff; +} /** * Described in header. */ -int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec, - const void *const *args) +int traffic_selector_printf_hook(printf_hook_data_t *data, + printf_hook_spec_t *spec, const void *const *args) { private_traffic_selector_t *this = *((private_traffic_selector_t**)(args[0])); linked_list_t *list = *((linked_list_t**)(args[0])); @@ -195,7 +212,7 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec if (this == NULL) { - return print_in_hook(dst, len, "(null)"); + return print_in_hook(data, "(null)"); } if (spec->hash) @@ -204,7 +221,7 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec while (enumerator->enumerate(enumerator, (void**)&this)) { /* call recursivly */ - written += print_in_hook(dst, len, "%R ", this); + written += print_in_hook(data, "%R ", this); } enumerator->destroy(enumerator); return written; @@ -216,7 +233,7 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec memeq(this->from, from, this->type == TS_IPV4_ADDR_RANGE ? 4 : 16) && memeq(this->to, to, this->type == TS_IPV4_ADDR_RANGE ? 4 : 16)) { - written += print_in_hook(dst, len, "dynamic"); + written += print_in_hook(data, "dynamic"); } else { @@ -238,24 +255,24 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec { inet_ntop(AF_INET6, &this->to6, to_str, sizeof(to_str)); } - written += print_in_hook(dst, len, "%s..%s", from_str, to_str); + written += print_in_hook(data, "%s..%s", from_str, to_str); } else { - written += print_in_hook(dst, len, "%s/%d", from_str, this->netbits); + written += print_in_hook(data, "%s/%d", from_str, this->netbits); } } /* check if we have protocol and/or port selectors */ has_proto = this->protocol != 0; - has_ports = !(this->from_port == 0 && this->to_port == 0xFFFF); + has_ports = !is_any(this); if (!has_proto && !has_ports) { return written; } - written += print_in_hook(dst, len, "["); + written += print_in_hook(data, "["); /* build protocol string */ if (has_proto) @@ -264,18 +281,18 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec if (proto) { - written += print_in_hook(dst, len, "%s", proto->p_name); + written += print_in_hook(data, "%s", proto->p_name); serv_proto = proto->p_name; } else { - written += print_in_hook(dst, len, "%d", this->protocol); + written += print_in_hook(data, "%d", this->protocol); } } if (has_proto && has_ports) { - written += print_in_hook(dst, len, "/"); + written += print_in_hook(data, "/"); } /* build port string */ @@ -283,42 +300,83 @@ int traffic_selector_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec { if (this->from_port == this->to_port) { - struct servent *serv = getservbyport(htons(this->from_port), serv_proto); + struct servent *serv; + serv = getservbyport(htons(this->from_port), serv_proto); if (serv) { - written += print_in_hook(dst, len, "%s", serv->s_name); + written += print_in_hook(data, "%s", serv->s_name); } else { - written += print_in_hook(dst, len, "%d", this->from_port); + written += print_in_hook(data, "%d", this->from_port); } } + else if (is_opaque(this)) + { + written += print_in_hook(data, "OPAQUE"); + } else { - written += print_in_hook(dst, len, "%d-%d", this->from_port, this->to_port); + written += print_in_hook(data, "%d-%d", + this->from_port, this->to_port); } } - written += print_in_hook(dst, len, "]"); + written += print_in_hook(data, "]"); return written; } -/** - * Implements traffic_selector_t.get_subset - */ -static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_traffic_selector_t *other) +METHOD(traffic_selector_t, get_subset, traffic_selector_t*, + private_traffic_selector_t *this, traffic_selector_t *other_public) { - if (this->type == other->type && (this->protocol == other->protocol || - this->protocol == 0 || other->protocol == 0)) + private_traffic_selector_t *other, *subset; + u_int16_t from_port, to_port; + u_char *from, *to; + u_int8_t protocol; + size_t size; + + other = (private_traffic_selector_t*)other_public; + + if (this->dynamic || other->dynamic) + { /* no set_address() applied, TS has no subset */ + return NULL; + } + + if (this->type != other->type) + { + return NULL; + } + switch (this->type) + { + case TS_IPV4_ADDR_RANGE: + size = sizeof(this->from4); + break; + case TS_IPV6_ADDR_RANGE: + size = sizeof(this->from6); + break; + default: + return NULL; + } + + if (this->protocol != other->protocol && + this->protocol != 0 && other->protocol != 0) { - u_int16_t from_port, to_port; - u_char *from, *to; - u_int8_t protocol; - size_t size; - private_traffic_selector_t *new_ts; + return NULL; + } + /* select protocol, which is not zero */ + protocol = max(this->protocol, other->protocol); + if ((is_opaque(this) && is_opaque(other)) || + (is_opaque(this) && is_any(other)) || + (is_opaque(other) && is_any(this))) + { + from_port = 0xffff; + to_port = 0; + } + else + { /* calculate the maximum port range allowed for both */ from_port = max(this->from_port, other->from_port); to_port = min(this->to_port, other->to_port); @@ -326,61 +384,46 @@ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_ { return NULL; } - /* select protocol, which is not zero */ - protocol = max(this->protocol, other->protocol); - - switch (this->type) - { - case TS_IPV4_ADDR_RANGE: - size = sizeof(this->from4); - break; - case TS_IPV6_ADDR_RANGE: - size = sizeof(this->from6); - break; - default: - return NULL; - } + } + /* get higher from-address */ + if (memcmp(this->from, other->from, size) > 0) + { + from = this->from; + } + else + { + from = other->from; + } + /* get lower to-address */ + if (memcmp(this->to, other->to, size) > 0) + { + to = other->to; + } + else + { + to = this->to; + } + /* if "from" > "to", we don't have a match */ + if (memcmp(from, to, size) > 0) + { + return NULL; + } - /* get higher from-address */ - if (memcmp(this->from, other->from, size) > 0) - { - from = this->from; - } - else - { - from = other->from; - } - /* get lower to-address */ - if (memcmp(this->to, other->to, size) > 0) - { - to = other->to; - } - else - { - to = this->to; - } - /* if "from" > "to", we don't have a match */ - if (memcmp(from, to, size) > 0) - { - return NULL; - } + /* we have a match in protocol, port, and address: return it... */ + subset = traffic_selector_create(protocol, this->type, from_port, to_port); + memcpy(subset->from, from, size); + memcpy(subset->to, to, size); + calc_netbits(subset); - /* we have a match in protocol, port, and address: return it... */ - new_ts = traffic_selector_create(protocol, this->type, from_port, to_port); - new_ts->dynamic = this->dynamic || other->dynamic; - memcpy(new_ts->from, from, size); - memcpy(new_ts->to, to, size); - calc_netbits(new_ts); - return &new_ts->public; - } - return NULL; + return &subset->public; } -/** - * Implements traffic_selector_t.equals - */ -static bool equals(private_traffic_selector_t *this, private_traffic_selector_t *other) +METHOD(traffic_selector_t, equals, bool, + private_traffic_selector_t *this, traffic_selector_t *other_public) { + private_traffic_selector_t *other; + + other = (private_traffic_selector_t*)other_public; if (this->type != other->type) { return FALSE; @@ -510,7 +553,7 @@ METHOD(traffic_selector_t, is_dynamic, bool, METHOD(traffic_selector_t, set_address, void, private_traffic_selector_t *this, host_t *host) { - if (this->dynamic) + if (is_host(this, NULL)) { this->type = host->get_family(host) == AF_INET ? TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE; @@ -528,14 +571,12 @@ METHOD(traffic_selector_t, set_address, void, memcpy(this->to, from.ptr, from.len); this->netbits = from.len * 8; } + this->dynamic = FALSE; } } -/** - * Implements traffic_selector_t.is_contained_in. - */ -static bool is_contained_in(private_traffic_selector_t *this, - private_traffic_selector_t *other) +METHOD(traffic_selector_t, is_contained_in, bool, + private_traffic_selector_t *this, traffic_selector_t *other) { private_traffic_selector_t *subset; bool contained_in = FALSE; @@ -544,7 +585,7 @@ static bool is_contained_in(private_traffic_selector_t *this, if (subset) { - if (equals(subset, this)) + if (equals(subset, &this->public)) { contained_in = TRUE; } @@ -571,7 +612,7 @@ METHOD(traffic_selector_t, includes, bool, return FALSE; } -METHOD(traffic_selector_t, to_subnet, void, +METHOD(traffic_selector_t, to_subnet, bool, private_traffic_selector_t *this, host_t **net, u_int8_t *mask) { /* there is no way to do this cleanly, as the address range may @@ -597,7 +638,7 @@ METHOD(traffic_selector_t, to_subnet, void, break; default: /* unreachable */ - return; + return FALSE; } net_chunk.ptr = malloc(net_chunk.len); @@ -616,6 +657,8 @@ METHOD(traffic_selector_t, to_subnet, void, *net = host_create_from_chunk(family, net_chunk, port); chunk_free(&net_chunk); + + return this->netbits != NON_SUBNET_ADDRESS_RANGE; } METHOD(traffic_selector_t, clone_, traffic_selector_t*, @@ -733,68 +776,34 @@ traffic_selector_t *traffic_selector_create_from_rfc3779_format(ts_type_t type, * see header */ traffic_selector_t *traffic_selector_create_from_subnet(host_t *net, - u_int8_t netbits, u_int8_t protocol, u_int16_t port) + u_int8_t netbits, u_int8_t protocol, + u_int16_t from_port, u_int16_t to_port) { - private_traffic_selector_t *this = traffic_selector_create(protocol, 0, 0, 65535); + private_traffic_selector_t *this; + chunk_t from; + + this = traffic_selector_create(protocol, 0, from_port, to_port); switch (net->get_family(net)) { case AF_INET: - { - chunk_t from; - this->type = TS_IPV4_ADDR_RANGE; - from = net->get_address(net); - memcpy(this->from, from.ptr, from.len); - if (this->from4[0] == 0) - { - /* use /0 for 0.0.0.0 */ - this->to4[0] = ~0; - this->netbits = 0; - } - else - { - calc_range(this, netbits); - } break; - } case AF_INET6: - { - chunk_t from; - this->type = TS_IPV6_ADDR_RANGE; - from = net->get_address(net); - memcpy(this->from, from.ptr, from.len); - if (this->from6[0] == 0 && this->from6[1] == 0 && - this->from6[2] == 0 && this->from6[3] == 0) - { - /* use /0 for ::0 */ - this->to6[0] = ~0; - this->to6[1] = ~0; - this->to6[2] = ~0; - this->to6[3] = ~0; - this->netbits = 0; - } - else - { - calc_range(this, netbits); - } break; - } default: - { net->destroy(net); free(this); return NULL; - } - } - if (port) - { - this->from_port = port; - this->to_port = port; } + from = net->get_address(net); + memcpy(this->from, from.ptr, from.len); + netbits = min(netbits, this->type == TS_IPV4_ADDR_RANGE ? 32 : 128); + calc_range(this, netbits); net->destroy(net); - return (&this->public); + + return &this->public; } /* @@ -805,38 +814,51 @@ traffic_selector_t *traffic_selector_create_from_string( char *from_addr, u_int16_t from_port, char *to_addr, u_int16_t to_port) { - private_traffic_selector_t *this = traffic_selector_create(protocol, type, - from_port, to_port); + private_traffic_selector_t *this; + int family; switch (type) { case TS_IPV4_ADDR_RANGE: - if (inet_pton(AF_INET, from_addr, (struct in_addr*)this->from4) < 0) - { - free(this); - return NULL; - } - if (inet_pton(AF_INET, to_addr, (struct in_addr*)this->to4) < 0) - { - free(this); - return NULL; - } + family = AF_INET; break; case TS_IPV6_ADDR_RANGE: - if (inet_pton(AF_INET6, from_addr, (struct in6_addr*)this->from6) < 0) - { - free(this); - return NULL; - } - if (inet_pton(AF_INET6, to_addr, (struct in6_addr*)this->to6) < 0) - { - free(this); - return NULL; - } + family = AF_INET6; break; + default: + return NULL; } + + this = traffic_selector_create(protocol, type, from_port, to_port); + + if (inet_pton(family, from_addr, this->from) != 1 || + inet_pton(family, to_addr, this->to) != 1) + { + free(this); + return NULL; + } + calc_netbits(this); - return (&this->public); + return &this->public; +} + +/* + * see header + */ +traffic_selector_t *traffic_selector_create_from_cidr( + char *string, u_int8_t protocol, + u_int16_t from_port, u_int16_t to_port) +{ + host_t *net; + int bits; + + net = host_create_from_subnet(string, &bits); + if (net) + { + return traffic_selector_create_from_subnet(net, bits, protocol, + from_port, to_port); + } + return NULL; } /* @@ -866,8 +888,8 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, INIT(this, .public = { - .get_subset = (traffic_selector_t*(*)(traffic_selector_t*,traffic_selector_t*))get_subset, - .equals = (bool(*)(traffic_selector_t*,traffic_selector_t*))equals, + .get_subset = _get_subset, + .equals = _equals, .get_from_address = _get_from_address, .get_to_address = _get_to_address, .get_from_port = _get_from_port, @@ -876,7 +898,7 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, .get_protocol = _get_protocol, .is_host = _is_host, .is_dynamic = _is_dynamic, - .is_contained_in = (bool(*)(traffic_selector_t*,traffic_selector_t*))is_contained_in, + .is_contained_in = _is_contained_in, .includes = _includes, .set_address = _set_address, .to_subnet = _to_subnet, @@ -891,4 +913,3 @@ static private_traffic_selector_t *traffic_selector_create(u_int8_t protocol, return this; } - |