summaryrefslogtreecommitdiff
path: root/src/libcharon/config
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/config')
-rw-r--r--src/libcharon/config/backend_manager.c64
-rw-r--r--src/libcharon/config/ike_cfg.c252
-rw-r--r--src/libcharon/config/ike_cfg.h51
-rw-r--r--src/libcharon/config/peer_cfg.c18
-rw-r--r--src/libcharon/config/peer_cfg.h12
-rw-r--r--src/libcharon/config/proposal.c39
6 files changed, 339 insertions, 97 deletions
diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c
index f47d5715a..79f1d9fee 100644
--- a/src/libcharon/config/backend_manager.c
+++ b/src/libcharon/config/backend_manager.c
@@ -84,10 +84,8 @@ static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data)
static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other,
ike_version_t version)
{
- host_t *me_cand, *other_cand;
- char *my_addr, *other_addr;
- bool my_allow_any, other_allow_any;
ike_cfg_match_t match = MATCH_NONE;
+ int quality;
if (cand->get_version(cand) != IKE_ANY &&
version != cand->get_version(cand))
@@ -97,26 +95,12 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other,
if (me)
{
- my_addr = cand->get_my_addr(cand, &my_allow_any);
- me_cand = host_create_from_dns(my_addr, me->get_family(me), 0);
- if (!me_cand)
- {
- return MATCH_NONE;
- }
- if (me_cand->ip_equals(me_cand, me))
- {
- match += MATCH_ME;
- }
- else if (my_allow_any || me_cand->is_anyaddr(me_cand))
- {
- match += MATCH_ANY;
- }
- else
+ quality = cand->match_me(cand, me);
+ if (!quality)
{
- me_cand->destroy(me_cand);
return MATCH_NONE;
}
- me_cand->destroy(me_cand);
+ match += quality * MATCH_ME;
}
else
{
@@ -125,26 +109,12 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other,
if (other)
{
- other_addr = cand->get_other_addr(cand, &other_allow_any);
- other_cand = host_create_from_dns(other_addr, other->get_family(other), 0);
- if (!other_cand)
+ quality = cand->match_other(cand, other);
+ if (!quality)
{
return MATCH_NONE;
}
- if (other_cand->ip_equals(other_cand, other))
- {
- match += MATCH_OTHER;
- }
- else if (other_allow_any || other_cand->is_anyaddr(other_cand))
- {
- match += MATCH_ANY;
- }
- else
- {
- other_cand->destroy(other_cand);
- return MATCH_NONE;
- }
- other_cand->destroy(other_cand);
+ match += quality * MATCH_OTHER;
}
else
{
@@ -165,7 +135,6 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*,
{
ike_cfg_t *current, *found = NULL;
char *my_addr, *other_addr;
- bool my_allow_any, other_allow_any;
enumerator_t *enumerator;
ike_cfg_match_t match, best = MATCH_ANY;
ike_data_t *data;
@@ -189,11 +158,10 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*,
match, me, other, ike_version_names, version);
if (match)
{
- my_addr = current->get_my_addr(current, &my_allow_any);
- other_addr = current->get_other_addr(current, &other_allow_any);
- DBG2(DBG_CFG, " candidate: %s%s...%s%s, prio %d",
- my_allow_any ? "%":"", my_addr,
- other_allow_any ? "%":"", other_addr, match);
+ my_addr = current->get_my_addr(current);
+ other_addr = current->get_other_addr(current);
+ DBG2(DBG_CFG, " candidate: %s...%s, prio %d",
+ my_addr, other_addr, match);
if (match > best)
{
DESTROY_IF(found);
@@ -207,11 +175,10 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*,
this->lock->unlock(this->lock);
if (found)
{
- my_addr = found->get_my_addr(found, &my_allow_any);
- other_addr = found->get_other_addr(found, &other_allow_any);
- DBG2(DBG_CFG, "found matching ike config: %s%s...%s%s with prio %d",
- my_allow_any ? "%":"", my_addr,
- other_allow_any ? "%":"", other_addr, best);
+ my_addr = found->get_my_addr(found);
+ other_addr = found->get_other_addr(found);
+ DBG2(DBG_CFG, "found matching ike config: %s...%s with prio %d",
+ my_addr, other_addr, best);
}
return found;
}
@@ -481,4 +448,3 @@ backend_manager_t *backend_manager_create()
return &this->public;
}
-
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;
}
diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h
index 719ceb9dd..f9e4fbebc 100644
--- a/src/libcharon/config/ike_cfg.h
+++ b/src/libcharon/config/ike_cfg.h
@@ -78,20 +78,50 @@ struct ike_cfg_t {
ike_version_t (*get_version)(ike_cfg_t *this);
/**
+ * Resolve the local address to use for initiation.
+ *
+ * @param family address family to prefer, or AF_UNSPEC
+ * @return resolved host, NULL on error
+ */
+ host_t* (*resolve_me)(ike_cfg_t *this, int family);
+
+ /**
+ * Resolve the remote address to use for initiation.
+ *
+ * @param family address family to prefer, or AF_UNSPEC
+ * @return resolved host, NULL on error
+ */
+ host_t* (*resolve_other)(ike_cfg_t *this, int family);
+
+ /**
+ * Check how good a host matches to the configured local address.
+ *
+ * @param host host to check match quality
+ * @return quality of the match, 0 if not matching at all
+ */
+ u_int (*match_me)(ike_cfg_t *this, host_t *host);
+
+ /**
+ * Check how good a host matches to the configured remote address.
+ *
+ * @param host host to check match quality
+ * @return quality of the match, 0 if not matching at all
+ */
+ u_int (*match_other)(ike_cfg_t *this, host_t *host);
+
+ /**
* Get own address.
*
- * @param allow_any allow any address to match
* @return string of address/DNS name
*/
- char* (*get_my_addr) (ike_cfg_t *this, bool *allow_any);
+ char* (*get_my_addr) (ike_cfg_t *this);
/**
* Get peer's address.
*
- * @param allow_any allow any address to match
* @return string of address/DNS name
*/
- char* (*get_other_addr) (ike_cfg_t *this, bool *allow_any);
+ char* (*get_other_addr) (ike_cfg_t *this);
/**
* Get the port to use as our source port.
@@ -200,24 +230,27 @@ struct ike_cfg_t {
/**
* Creates a ike_cfg_t object.
*
- * Supplied hosts become owned by ike_cfg, the name gets cloned.
+ * Supplied hosts become owned by ike_cfg, strings get cloned.
+ *
+ * me and other are comma separated lists of IP addresses, DNS names, IP ranges
+ * or subnets. When initiating, the first non-range/subnet address is used
+ * as address. When responding, a match is performed against all items in the
+ * list.
*
* @param version IKE major version to use for this config
* @param certreq TRUE to send a certificate request
* @param force_encap enforce UDP encapsulation by faking NATD notify
* @param me address/DNS name of local peer
- * @param my_allow_any allow override of local address by any address
* @param my_port IKE port to use as source, 500 uses IKEv2 port floating
* @param other address/DNS name of remote peer
- * @param other_allow_any allow override of remote address by any address
* @param other_port IKE port to use as dest, 500 uses IKEv2 port floating
* @param fragmentation use IKEv1 fragmentation
* @param dscp DSCP value to send IKE packets with
* @return ike_cfg_t object.
*/
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);
#endif /** IKE_CFG_H_ @}*/
diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c
index eb983199b..d198503d0 100644
--- a/src/libcharon/config/peer_cfg.c
+++ b/src/libcharon/config/peer_cfg.c
@@ -100,6 +100,11 @@ struct private_peer_cfg_t {
bool aggressive;
/**
+ * Use pull or push in mode config?
+ */
+ bool pull_mode;
+
+ /**
* Time before starting rekeying
*/
u_int32_t rekey_time;
@@ -390,6 +395,12 @@ METHOD(peer_cfg_t, use_aggressive, bool,
return this->aggressive;
}
+METHOD(peer_cfg_t, use_pull_mode, bool,
+ private_peer_cfg_t *this)
+{
+ return this->pull_mode;
+}
+
METHOD(peer_cfg_t, get_dpd, u_int32_t,
private_peer_cfg_t *this)
{
@@ -588,6 +599,7 @@ METHOD(peer_cfg_t, equals, bool,
this->over_time == other->over_time &&
this->dpd == other->dpd &&
this->aggressive == other->aggressive &&
+ this->pull_mode == other->pull_mode &&
auth_cfg_equal(this, other)
#ifdef ME
&& this->mediation == other->mediation &&
@@ -638,8 +650,8 @@ peer_cfg_t *peer_cfg_create(char *name,
unique_policy_t unique, u_int32_t keyingtries,
u_int32_t rekey_time, u_int32_t reauth_time,
u_int32_t jitter_time, u_int32_t over_time,
- bool mobike, bool aggressive, u_int32_t dpd,
- u_int32_t dpd_timeout,
+ bool mobike, bool aggressive, bool pull_mode,
+ u_int32_t dpd, u_int32_t dpd_timeout,
bool mediation, peer_cfg_t *mediated_by,
identification_t *peer_id)
{
@@ -671,6 +683,7 @@ peer_cfg_t *peer_cfg_create(char *name,
.get_over_time = _get_over_time,
.use_mobike = _use_mobike,
.use_aggressive = _use_aggressive,
+ .use_pull_mode = _use_pull_mode,
.get_dpd = _get_dpd,
.get_dpd_timeout = _get_dpd_timeout,
.add_virtual_ip = _add_virtual_ip,
@@ -701,6 +714,7 @@ peer_cfg_t *peer_cfg_create(char *name,
.over_time = over_time,
.use_mobike = mobike,
.aggressive = aggressive,
+ .pull_mode = pull_mode,
.dpd = dpd,
.dpd_timeout = dpd_timeout,
.vips = linked_list_create(),
diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h
index e62e03ec5..3e780394a 100644
--- a/src/libcharon/config/peer_cfg.h
+++ b/src/libcharon/config/peer_cfg.h
@@ -248,6 +248,13 @@ struct peer_cfg_t {
bool (*use_aggressive)(peer_cfg_t *this);
/**
+ * Use pull or push mode for mode config?
+ *
+ * @return TRUE to use pull, FALSE to use push mode
+ */
+ bool (*use_pull_mode)(peer_cfg_t *this);
+
+ /**
* Get the DPD check interval.
*
* @return dpd_delay in seconds
@@ -366,6 +373,7 @@ struct peer_cfg_t {
* @param over_time maximum overtime before closing a rekeying/reauth SA
* @param mobike use MOBIKE (RFC4555) if peer supports it
* @param aggressive use/accept aggressive mode with IKEv1
+ * @param pull_mode TRUE to use modeconfig pull, FALSE for push
* @param dpd DPD check interval, 0 to disable
* @param dpd_timeout DPD timeout interval (IKEv1 only), if 0 default applies
* @param mediation TRUE if this is a mediation connection
@@ -378,8 +386,8 @@ peer_cfg_t *peer_cfg_create(char *name,
unique_policy_t unique, u_int32_t keyingtries,
u_int32_t rekey_time, u_int32_t reauth_time,
u_int32_t jitter_time, u_int32_t over_time,
- bool mobike, bool aggressive, u_int32_t dpd,
- u_int32_t dpd_timeout,
+ bool mobike, bool aggressive, bool pull_mode,
+ u_int32_t dpd, u_int32_t dpd_timeout,
bool mediation, peer_cfg_t *mediated_by,
identification_t *peer_id);
diff --git a/src/libcharon/config/proposal.c b/src/libcharon/config/proposal.c
index 0b702e014..1f3f2ba8b 100644
--- a/src/libcharon/config/proposal.c
+++ b/src/libcharon/config/proposal.c
@@ -429,30 +429,33 @@ static void check_proposal(private_proposal_t *this)
e->destroy(e);
}
- e = create_enumerator(this, ENCRYPTION_ALGORITHM);
- while (e->enumerate(e, &alg, &ks))
+ if (this->protocol == PROTO_ESP)
{
- if (!encryption_algorithm_is_aead(alg))
+ e = create_enumerator(this, ENCRYPTION_ALGORITHM);
+ while (e->enumerate(e, &alg, &ks))
{
- all_aead = FALSE;
- break;
+ if (!encryption_algorithm_is_aead(alg))
+ {
+ all_aead = FALSE;
+ break;
+ }
}
- }
- e->destroy(e);
+ e->destroy(e);
- if (all_aead)
- {
- /* if all encryption algorithms in the proposal are AEADs,
- * we MUST NOT propose any integrity algorithms */
- e = array_create_enumerator(this->transforms);
- while (e->enumerate(e, &entry))
+ if (all_aead)
{
- if (entry->type == INTEGRITY_ALGORITHM)
+ /* if all encryption algorithms in the proposal are AEADs,
+ * we MUST NOT propose any integrity algorithms */
+ e = array_create_enumerator(this->transforms);
+ while (e->enumerate(e, &entry))
{
- array_remove_at(this->transforms, e);
+ if (entry->type == INTEGRITY_ALGORITHM)
+ {
+ array_remove_at(this->transforms, e);
+ }
}
+ e->destroy(e);
}
- e->destroy(e);
}
if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
@@ -734,6 +737,10 @@ static void proposal_add_supported_ike(private_proposal_t *this)
case MODP_2048_256:
case ECP_192_BIT:
case ECP_224_BIT:
+ case ECP_224_BP:
+ case ECP_256_BP:
+ case ECP_384_BP:
+ case ECP_512_BP:
add_algorithm(this, DIFFIE_HELLMAN_GROUP, group, 0);
break;
default: