summaryrefslogtreecommitdiff
path: root/src/libstrongswan/selectors/traffic_selector.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/selectors/traffic_selector.c')
-rw-r--r--src/libstrongswan/selectors/traffic_selector.c347
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;
}
-