summaryrefslogtreecommitdiff
path: root/src/libcharon/config/ike_cfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/config/ike_cfg.c')
-rw-r--r--src/libcharon/config/ike_cfg.c252
1 files changed, 233 insertions, 19 deletions
diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c
index 54a054e40..cb6f6ca0e 100644
--- a/src/libcharon/config/ike_cfg.c
+++ b/src/libcharon/config/ike_cfg.c
@@ -50,24 +50,34 @@ struct private_ike_cfg_t {
ike_version_t version;
/**
- * Address of local host
+ * Address list string for local host
*/
char *me;
/**
- * Address of remote host
+ * Address list string for remote host
*/
char *other;
/**
- * Allow override of local address
+ * Local single host or DNS names, as allocated char*
*/
- bool my_allow_any;
+ linked_list_t *my_hosts;
/**
- * Allow override of remote address
+ * Remote single host or DNS names, as allocated char*
*/
- bool other_allow_any;
+ linked_list_t *other_hosts;
+
+ /**
+ * Local ranges/subnets this config matches to, as traffic_selector_t*
+ */
+ linked_list_t *my_ranges;
+
+ /**
+ * Remote ranges/subnets this config matches to, as traffic_selector_t*
+ */
+ linked_list_t *other_ranges;
/**
* our source port
@@ -129,23 +139,124 @@ METHOD(ike_cfg_t, fragmentation, fragmentation_t,
return this->fragmentation;
}
-METHOD(ike_cfg_t, get_my_addr, char*,
- private_ike_cfg_t *this, bool *allow_any)
+/**
+ * Common function for resolve_me/other
+ */
+static host_t* resolve(linked_list_t *hosts, int family, u_int16_t port)
{
- if (allow_any)
+ enumerator_t *enumerator;
+ host_t *host = NULL;
+ bool tried = FALSE;
+ char *str;
+
+ enumerator = hosts->create_enumerator(hosts);
+ while (enumerator->enumerate(enumerator, &str))
+ {
+ host = host_create_from_dns(str, family, port);
+ if (host)
+ {
+ break;
+ }
+ tried = TRUE;
+ }
+ enumerator->destroy(enumerator);
+
+ if (!host && !tried)
{
- *allow_any = this->my_allow_any;
+ /* we have no single host configured, return %any */
+ host = host_create_any(family ?: AF_INET);
+ host->set_port(host, port);
}
- return this->me;
+ return host;
}
-METHOD(ike_cfg_t, get_other_addr, char*,
- private_ike_cfg_t *this, bool *allow_any)
+METHOD(ike_cfg_t, resolve_me, host_t*,
+ private_ike_cfg_t *this, int family)
+{
+ return resolve(this->my_hosts, family, this->my_port);
+}
+
+METHOD(ike_cfg_t, resolve_other, host_t*,
+ private_ike_cfg_t *this, int family)
+{
+ return resolve(this->other_hosts, family, this->other_port);
+}
+
+/**
+ * Common function for match_me/other
+ */
+static u_int match(linked_list_t *hosts, linked_list_t *ranges, host_t *cand)
{
- if (allow_any)
+ enumerator_t *enumerator;
+ traffic_selector_t *ts;
+ char *str;
+ host_t *host;
+ u_int8_t mask;
+ u_int quality = 0;
+
+ /* try single hosts first */
+ enumerator = hosts->create_enumerator(hosts);
+ while (enumerator->enumerate(enumerator, &str))
+ {
+ host = host_create_from_dns(str, cand->get_family(cand), 0);
+ if (host)
+ {
+ if (host->ip_equals(host, cand))
+ {
+ quality = max(quality, 128 + 1);
+ }
+ if (host->is_anyaddr(host))
+ {
+ quality = max(quality, 1);
+ }
+ host->destroy(host);
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ /* then ranges/subnets */
+ enumerator = ranges->create_enumerator(ranges);
+ while (enumerator->enumerate(enumerator, &ts))
{
- *allow_any = this->other_allow_any;
+ if (ts->includes(ts, cand))
+ {
+ if (ts->to_subnet(ts, &host, &mask))
+ {
+ quality = max(quality, mask + 1);
+ host->destroy(host);
+ }
+ else
+ {
+ quality = max(quality, 1);
+ }
+ }
}
+ enumerator->destroy(enumerator);
+
+ return quality;
+}
+
+METHOD(ike_cfg_t, match_me, u_int,
+ private_ike_cfg_t *this, host_t *host)
+{
+ return match(this->my_hosts, this->my_ranges, host);
+}
+
+METHOD(ike_cfg_t, match_other, u_int,
+ private_ike_cfg_t *this, host_t *host)
+{
+ return match(this->other_hosts, this->other_ranges, host);
+}
+
+METHOD(ike_cfg_t, get_my_addr, char*,
+ private_ike_cfg_t *this)
+{
+ return this->me;
+}
+
+METHOD(ike_cfg_t, get_other_addr, char*,
+ private_ike_cfg_t *this)
+{
return this->other;
}
@@ -313,16 +424,110 @@ METHOD(ike_cfg_t, destroy, void,
offsetof(proposal_t, destroy));
free(this->me);
free(this->other);
+ this->my_hosts->destroy_function(this->my_hosts, free);
+ this->other_hosts->destroy_function(this->other_hosts, free);
+ this->my_ranges->destroy_offset(this->my_ranges,
+ offsetof(traffic_selector_t, destroy));
+ this->other_ranges->destroy_offset(this->other_ranges,
+ offsetof(traffic_selector_t, destroy));
free(this);
}
}
/**
+ * Try to parse a string as subnet
+ */
+static traffic_selector_t* make_subnet(char *str)
+{
+ char *pos;
+
+ pos = strchr(str, '/');
+ if (!pos)
+ {
+ return NULL;
+ }
+ return traffic_selector_create_from_cidr(str, 0, 0, 0);
+}
+
+/**
+ * Try to parse a string as an IP range
+ */
+static traffic_selector_t* make_range(char *str)
+{
+ traffic_selector_t *ts;
+ ts_type_t type;
+ char *pos;
+ host_t *from, *to;
+
+ pos = strchr(str, '-');
+ if (!pos)
+ {
+ return NULL;
+ }
+ to = host_create_from_string(pos + 1, 0);
+ if (!to)
+ {
+ return NULL;
+ }
+ str = strndup(str, pos - str);
+ from = host_create_from_string_and_family(str, to->get_family(to), 0);
+ free(str);
+ if (!from)
+ {
+ to->destroy(to);
+ return NULL;
+ }
+ if (to->get_family(to) == AF_INET)
+ {
+ type = TS_IPV4_ADDR_RANGE;
+ }
+ else
+ {
+ type = TS_IPV6_ADDR_RANGE;
+ }
+ ts = traffic_selector_create_from_bytes(0, type,
+ from->get_address(from), 0,
+ to->get_address(to), 0);
+ from->destroy(from);
+ to->destroy(to);
+ return ts;
+}
+
+/**
+ * Parse address string into lists of single hosts and ranges/subnets
+ */
+static void parse_addresses(char *str, linked_list_t *hosts,
+ linked_list_t *ranges)
+{
+ enumerator_t *enumerator;
+ traffic_selector_t *ts;
+
+ enumerator = enumerator_create_token(str, ",", " ");
+ while (enumerator->enumerate(enumerator, &str))
+ {
+ ts = make_subnet(str);
+ if (ts)
+ {
+ ranges->insert_last(ranges, ts);
+ continue;
+ }
+ ts = make_range(str);
+ if (ts)
+ {
+ ranges->insert_last(ranges, ts);
+ continue;
+ }
+ hosts->insert_last(hosts, strdup(str));
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
* Described in header.
*/
ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap,
- char *me, bool my_allow_any, u_int16_t my_port,
- char *other, bool other_allow_any, u_int16_t other_port,
+ char *me, u_int16_t my_port,
+ char *other, u_int16_t other_port,
fragmentation_t fragmentation, u_int8_t dscp)
{
private_ike_cfg_t *this;
@@ -333,6 +538,10 @@ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap,
.send_certreq = _send_certreq,
.force_encap = _force_encap_,
.fragmentation = _fragmentation,
+ .resolve_me = _resolve_me,
+ .resolve_other = _resolve_other,
+ .match_me = _match_me,
+ .match_other = _match_other,
.get_my_addr = _get_my_addr,
.get_other_addr = _get_other_addr,
.get_my_port = _get_my_port,
@@ -352,14 +561,19 @@ ike_cfg_t *ike_cfg_create(ike_version_t version, bool certreq, bool force_encap,
.force_encap = force_encap,
.fragmentation = fragmentation,
.me = strdup(me),
+ .my_ranges = linked_list_create(),
+ .my_hosts = linked_list_create(),
.other = strdup(other),
- .my_allow_any = my_allow_any,
- .other_allow_any = other_allow_any,
+ .other_ranges = linked_list_create(),
+ .other_hosts = linked_list_create(),
.my_port = my_port,
.other_port = other_port,
.dscp = dscp,
.proposals = linked_list_create(),
);
+ parse_addresses(me, this->my_hosts, this->my_ranges);
+ parse_addresses(other, this->other_hosts, this->other_ranges);
+
return &this->public;
}