summaryrefslogtreecommitdiff
path: root/src/libcharon/config
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/config')
-rw-r--r--src/libcharon/config/backend.h2
-rw-r--r--src/libcharon/config/backend_manager.c122
-rw-r--r--src/libcharon/config/backend_manager.h9
-rw-r--r--src/libcharon/config/child_cfg.c96
-rw-r--r--src/libcharon/config/child_cfg.h14
-rw-r--r--src/libcharon/config/ike_cfg.c79
-rw-r--r--src/libcharon/config/ike_cfg.h120
-rw-r--r--src/libcharon/config/peer_cfg.c172
-rw-r--r--src/libcharon/config/peer_cfg.h101
-rw-r--r--src/libcharon/config/proposal.c643
-rw-r--r--src/libcharon/config/proposal.h11
11 files changed, 775 insertions, 594 deletions
diff --git a/src/libcharon/config/backend.h b/src/libcharon/config/backend.h
index 458abc37f..aca3352ba 100644
--- a/src/libcharon/config/backend.h
+++ b/src/libcharon/config/backend.h
@@ -26,7 +26,7 @@ typedef struct backend_t backend_t;
#include <library.h>
#include <config/ike_cfg.h>
#include <config/peer_cfg.h>
-#include <utils/linked_list.h>
+#include <collections/linked_list.h>
/**
* The interface for a configuration backend.
diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c
index a93457ea4..f47d5715a 100644
--- a/src/libcharon/config/backend_manager.c
+++ b/src/libcharon/config/backend_manager.c
@@ -18,7 +18,7 @@
#include <sys/types.h>
#include <daemon.h>
-#include <utils/linked_list.h>
+#include <collections/linked_list.h>
#include <threading/rwlock.h>
@@ -49,10 +49,16 @@ struct private_backend_manager_t {
* match of an ike_cfg
*/
typedef enum ike_cfg_match_t {
- MATCH_NONE = 0x00,
- MATCH_ANY = 0x01,
- MATCH_ME = 0x04,
- MATCH_OTHER = 0x08,
+ /* doesn't match at all */
+ MATCH_NONE = 0x00,
+ /* match for a %any host. For both hosts, hence skip 0x02 */
+ MATCH_ANY = 0x01,
+ /* IKE version matches exactly (config is not for any version) */
+ MATCH_VERSION = 0x04,
+ /* local identity matches */
+ MATCH_ME = 0x08,
+ /* remote identity matches */
+ MATCH_OTHER = 0x10,
} ike_cfg_match_t;
/**
@@ -75,15 +81,24 @@ static enumerator_t *ike_enum_create(backend_t *backend, ike_data_t *data)
/**
* get a match of a candidate ike_cfg for two hosts
*/
-static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other)
+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;
+ if (cand->get_version(cand) != IKE_ANY &&
+ version != cand->get_version(cand))
+ {
+ return MATCH_NONE;
+ }
+
if (me)
{
- me_cand = host_create_from_dns(cand->get_my_addr(cand),
- me->get_family(me), 0);
+ 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;
@@ -92,7 +107,7 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other)
{
match += MATCH_ME;
}
- else if (me_cand->is_anyaddr(me_cand))
+ else if (my_allow_any || me_cand->is_anyaddr(me_cand))
{
match += MATCH_ANY;
}
@@ -110,8 +125,8 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other)
if (other)
{
- other_cand = host_create_from_dns(cand->get_other_addr(cand),
- other->get_family(other), 0);
+ 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)
{
return MATCH_NONE;
@@ -120,7 +135,7 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other)
{
match += MATCH_OTHER;
}
- else if (other_cand->is_anyaddr(other_cand))
+ else if (other_allow_any || other_cand->is_anyaddr(other_cand))
{
match += MATCH_ANY;
}
@@ -135,21 +150,31 @@ static ike_cfg_match_t get_ike_match(ike_cfg_t *cand, host_t *me, host_t *other)
{
match += MATCH_ANY;
}
+
+ if (match != MATCH_NONE &&
+ cand->get_version(cand) != IKE_ANY)
+ { /* if we have a match, improve it if candidate version specified */
+ match += MATCH_VERSION;
+ }
return match;
}
METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*,
- private_backend_manager_t *this, host_t *me, host_t *other)
+ private_backend_manager_t *this, host_t *me, host_t *other,
+ ike_version_t version)
{
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;
- data = malloc_thing(ike_data_t);
- data->this = this;
- data->me = me;
- data->other = other;
+ INIT(data,
+ .this = this,
+ .me = me,
+ .other = other,
+ );
DBG2(DBG_CFG, "looking for an ike config for %H...%H", me, other);
@@ -159,13 +184,16 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*,
(void*)ike_enum_create, data, (void*)free);
while (enumerator->enumerate(enumerator, (void**)&current))
{
- match = get_ike_match(current, me, other);
-
+ match = get_ike_match(current, me, other, version);
+ DBG3(DBG_CFG, "ike config match: %d (%H %H %N)",
+ match, me, other, ike_version_names, version);
if (match)
{
- DBG2(DBG_CFG, " candidate: %s...%s, prio %d",
- current->get_my_addr(current),
- current->get_other_addr(current), 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);
if (match > best)
{
DESTROY_IF(found);
@@ -179,8 +207,11 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*,
this->lock->unlock(this->lock);
if (found)
{
- DBG2(DBG_CFG, "found matching ike config: %s...%s with prio %d",
- found->get_my_addr(found), found->get_other_addr(found), best);
+ 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);
}
return found;
}
@@ -195,9 +226,13 @@ static id_match_t get_peer_match(identification_t *id,
auth_cfg_t *auth;
identification_t *candidate;
id_match_t match = ID_MATCH_NONE;
+ char *where = local ? "local" : "remote";
+ chunk_t data;
if (!id)
{
+ DBG3(DBG_CFG, "peer config match %s: %d (%N)",
+ where, ID_MATCH_ANY, id_type_names, ID_ANY);
return ID_MATCH_ANY;
}
@@ -221,6 +256,10 @@ static id_match_t get_peer_match(identification_t *id,
}
}
enumerator->destroy(enumerator);
+
+ data = id->get_encoding(id);
+ DBG3(DBG_CFG, "peer config match %s: %d (%N -> %#B)",
+ where, match, id_type_names, id->get_type(id), &data);
return match;
}
@@ -317,17 +356,18 @@ static void insert_sorted(match_entry_t *entry, linked_list_t *list,
METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*,
private_backend_manager_t *this, host_t *me, host_t *other,
- identification_t *my_id, identification_t *other_id)
+ identification_t *my_id, identification_t *other_id, ike_version_t version)
{
enumerator_t *enumerator;
peer_data_t *data;
peer_cfg_t *cfg;
linked_list_t *configs, *helper;
- data = malloc_thing(peer_data_t);
- data->lock = this->lock;
- data->me = my_id;
- data->other = other_id;
+ INIT(data,
+ .lock = this->lock,
+ .me = my_id,
+ .other = other_id,
+ );
/* create a sorted list with all matches */
this->lock->read_lock(this->lock);
@@ -340,9 +380,6 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*,
return enumerator;
}
- DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]",
- me, my_id, other, other_id);
-
configs = linked_list_create();
/* only once allocated helper list for sorting */
helper = linked_list_create();
@@ -351,28 +388,23 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*,
id_match_t match_peer_me, match_peer_other;
ike_cfg_match_t match_ike;
match_entry_t *entry;
- chunk_t data;
match_peer_me = get_peer_match(my_id, cfg, TRUE);
- data = my_id->get_encoding(my_id);
- DBG3(DBG_CFG, "match_peer_me: %d (%N -> %#B)", match_peer_me,
- id_type_names, my_id->get_type(my_id), &data);
match_peer_other = get_peer_match(other_id, cfg, FALSE);
- data = other_id->get_encoding(other_id);
- DBG3(DBG_CFG, "match_peer_other: %d (%N -> %#B)", match_peer_other,
- id_type_names, other_id->get_type(other_id), &data);
- match_ike = get_ike_match(cfg->get_ike_cfg(cfg), me, other);
- DBG3(DBG_CFG, "match_ike: %d (%H %H)", match_ike, me, other);
+ match_ike = get_ike_match(cfg->get_ike_cfg(cfg), me, other, version);
+ DBG3(DBG_CFG, "ike config match: %d (%H %H %N)",
+ match_ike, me, other, ike_version_names, version);
if (match_peer_me && match_peer_other && match_ike)
{
DBG2(DBG_CFG, " candidate \"%s\", match: %d/%d/%d (me/other/ike)",
cfg->get_name(cfg), match_peer_me, match_peer_other, match_ike);
- entry = malloc_thing(match_entry_t);
- entry->match_peer = match_peer_me + match_peer_other;
- entry->match_ike = match_ike;
- entry->cfg = cfg->get_ref(cfg);
+ INIT(entry,
+ .match_peer = match_peer_me + match_peer_other,
+ .match_ike = match_ike,
+ .cfg = cfg->get_ref(cfg),
+ );
insert_sorted(entry, configs, helper);
}
}
diff --git a/src/libcharon/config/backend_manager.h b/src/libcharon/config/backend_manager.h
index 5b394f791..cc8ef8785 100644
--- a/src/libcharon/config/backend_manager.h
+++ b/src/libcharon/config/backend_manager.h
@@ -24,7 +24,7 @@
typedef struct backend_manager_t backend_manager_t;
#include <library.h>
-#include <utils/host.h>
+#include <networking/host.h>
#include <utils/identification.h>
#include <config/ike_cfg.h>
#include <config/peer_cfg.h>
@@ -56,10 +56,12 @@ struct backend_manager_t {
*
* @param my_host address of own host
* @param other_host address of remote host
+ * @param version IKE version to get a config for
* @return matching ike_config, or NULL if none found
*/
ike_cfg_t* (*get_ike_cfg)(backend_manager_t *this,
- host_t *my_host, host_t *other_host);
+ host_t *my_host, host_t *other_host,
+ ike_version_t version);
/**
* Get a peer_config identified by it's name.
@@ -79,11 +81,12 @@ struct backend_manager_t {
* @param other remote address
* @param my_id IDr in first authentication round
* @param other_id IDi in first authentication round
+ * @param version IKE version to get a config for
* @return enumerator over peer_cfg_t
*/
enumerator_t* (*create_peer_cfg_enumerator)(backend_manager_t *this,
host_t *me, host_t *other, identification_t *my_id,
- identification_t *other_id);
+ identification_t *other_id, ike_version_t version);
/**
* Register a backend on the manager.
*
diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c
index 74949be3c..6fe7d44b8 100644
--- a/src/libcharon/config/child_cfg.c
+++ b/src/libcharon/config/child_cfg.c
@@ -165,12 +165,14 @@ METHOD(child_cfg_t, get_proposals, linked_list_t*,
current = current->clone(current);
if (strip_dh)
{
- current->strip_dh(current);
+ current->strip_dh(current, MODP_NONE);
}
proposals->insert_last(proposals, current);
}
enumerator->destroy(enumerator);
+ DBG2(DBG_CFG, "configured proposals: %#P", proposals);
+
return proposals;
}
@@ -192,7 +194,7 @@ METHOD(child_cfg_t, select_proposal, proposal_t*,
{
if (strip_dh)
{
- stored->strip_dh(stored);
+ stored->strip_dh(stored, MODP_NONE);
}
selected = stored->select(stored, supplied, private);
if (selected)
@@ -235,12 +237,16 @@ METHOD(child_cfg_t, add_traffic_selector, void,
}
METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*,
- private_child_cfg_t *this, bool local, linked_list_t *supplied, host_t *host)
+ private_child_cfg_t *this, bool local, linked_list_t *supplied,
+ linked_list_t *hosts)
{
enumerator_t *e1, *e2;
traffic_selector_t *ts1, *ts2, *selected;
- linked_list_t *result = linked_list_create();
+ linked_list_t *result, *derived;
+ host_t *host;
+ result = linked_list_create();
+ derived = linked_list_create();
if (local)
{
e1 = this->my_ts->create_enumerator(this->my_ts);
@@ -249,41 +255,47 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*,
{
e1 = this->other_ts->create_enumerator(this->other_ts);
}
-
- /* no list supplied, just fetch the stored traffic selectors */
- if (supplied == NULL)
+ /* In a first step, replace "dynamic" TS with the host list */
+ while (e1->enumerate(e1, &ts1))
{
- DBG2(DBG_CFG, "proposing traffic selectors for %s:",
- local ? "us" : "other");
- while (e1->enumerate(e1, &ts1))
+ if (hosts && hosts->get_count(hosts) &&
+ ts1->is_dynamic(ts1))
{
- /* we make a copy of the TS, this allows us to update dynamic TS' */
- selected = ts1->clone(ts1);
- if (host)
+ e2 = hosts->create_enumerator(hosts);
+ while (e2->enumerate(e2, &host))
{
- selected->set_address(selected, host);
+ ts2 = ts1->clone(ts1);
+ ts2->set_address(ts2, host);
+ derived->insert_last(derived, ts2);
}
- DBG2(DBG_CFG, " %R (derived from %R)", selected, ts1);
- result->insert_last(result, selected);
+ e2->destroy(e2);
}
- e1->destroy(e1);
+ else
+ {
+ derived->insert_last(derived, ts1->clone(ts1));
+ }
+ }
+ e1->destroy(e1);
+
+ DBG2(DBG_CFG, "%s traffic selectors for %s:",
+ supplied ? "selecting" : "proposing", local ? "us" : "other");
+ if (supplied == NULL)
+ {
+ while (derived->remove_first(derived, (void**)&ts1) == SUCCESS)
+ {
+ DBG2(DBG_CFG, " %R", ts1);
+ result->insert_last(result, ts1);
+ }
+ derived->destroy(derived);
}
else
{
- DBG2(DBG_CFG, "selecting traffic selectors for %s:",
- local ? "us" : "other");
+ e1 = derived->create_enumerator(derived);
e2 = supplied->create_enumerator(supplied);
- /* iterate over all stored selectors */
+ /* enumerate all configured/derived selectors */
while (e1->enumerate(e1, &ts1))
{
- /* we make a copy of the TS, as we have to update dynamic TS' */
- ts1 = ts1->clone(ts1);
- if (host)
- {
- ts1->set_address(ts1, host);
- }
-
- /* iterate over all supplied traffic selectors */
+ /* enumerate all supplied traffic selectors */
while (e2->enumerate(e2, &ts2))
{
selected = ts1->get_subset(ts1, ts2);
@@ -299,12 +311,27 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*,
ts1, ts2);
}
}
- e2->destroy(e2);
- e2 = supplied->create_enumerator(supplied);
- ts1->destroy(ts1);
+ supplied->reset_enumerator(supplied, e2);
}
e1->destroy(e1);
e2->destroy(e2);
+
+ /* check if we/peer did any narrowing, raise alert */
+ e1 = derived->create_enumerator(derived);
+ e2 = result->create_enumerator(result);
+ while (e1->enumerate(e1, &ts1))
+ {
+ if (!e2->enumerate(e2, &ts2) || !ts1->equals(ts1, ts2))
+ {
+ charon->bus->alert(charon->bus, ALERT_TS_NARROWED,
+ local, result, this);
+ break;
+ }
+ }
+ e1->destroy(e1);
+ e2->destroy(e2);
+
+ derived->destroy_offset(derived, offsetof(traffic_selector_t, destroy));
}
/* remove any redundant traffic selectors in the list */
@@ -320,16 +347,14 @@ METHOD(child_cfg_t, get_traffic_selectors, linked_list_t*,
{
result->remove_at(result, e2);
ts2->destroy(ts2);
- e1->destroy(e1);
- e1 = result->create_enumerator(result);
+ result->reset_enumerator(result, e1);
break;
}
if (ts1->is_contained_in(ts1, ts2))
{
result->remove_at(result, e1);
ts1->destroy(ts1);
- e2->destroy(e2);
- e2 = result->create_enumerator(result);
+ result->reset_enumerator(result, e2);
break;
}
}
@@ -566,4 +591,3 @@ child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t *lifetime,
return &this->public;
}
-
diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h
index 370ff9d58..20d1fa811 100644
--- a/src/libcharon/config/child_cfg.h
+++ b/src/libcharon/config/child_cfg.h
@@ -129,12 +129,12 @@ struct child_cfg_t {
*
* @param local TRUE for TS on local side, FALSE for remote
* @param supplied list with TS to select from, or NULL
- * @param host address to use for narrowing "dynamic" TS', or NULL
+ * @param hosts addresses to use for narrowing "dynamic" TS', host_t
* @return list containing the traffic selectors
*/
linked_list_t *(*get_traffic_selectors)(child_cfg_t *this, bool local,
linked_list_t *supplied,
- host_t *host);
+ linked_list_t *hosts);
/**
* Get the updown script to run for the CHILD_SA.
*
@@ -213,14 +213,14 @@ struct child_cfg_t {
u_int32_t (*get_inactivity)(child_cfg_t *this);
/**
- * Specific reqid to use for CHILD_SA
+ * Specific reqid to use for CHILD_SA.
*
* @return reqid
*/
u_int32_t (*get_reqid)(child_cfg_t *this);
/**
- * Optional mark for CHILD_SA
+ * Optional mark for CHILD_SA.
*
* @param inbound TRUE for inbound, FALSE for outbound
* @return mark
@@ -235,7 +235,7 @@ struct child_cfg_t {
u_int32_t (*get_tfc)(child_cfg_t *this);
/**
- * Sets two options needed for Mobile IPv6 interoperability
+ * Sets two options needed for Mobile IPv6 interoperability.
*
* @param proxy_mode use IPsec transport proxy mode (default FALSE)
* @param install_policy install IPsec kernel policies (default TRUE)
@@ -244,7 +244,7 @@ struct child_cfg_t {
bool install_policy);
/**
- * Check whether IPsec transport SA should be set up in proxy mode
+ * Check whether IPsec transport SA should be set up in proxy mode.
*
* @return TRUE, if proxy mode should be used
* FALSE, otherwise
@@ -252,7 +252,7 @@ struct child_cfg_t {
bool (*use_proxy_mode)(child_cfg_t *this);
/**
- * Check whether IPsec policies should be installed in the kernel
+ * Check whether IPsec policies should be installed in the kernel.
*
* @return TRUE, if IPsec kernel policies should be installed
* FALSE, otherwise
diff --git a/src/libcharon/config/ike_cfg.c b/src/libcharon/config/ike_cfg.c
index 342b9ddbe..54a054e40 100644
--- a/src/libcharon/config/ike_cfg.c
+++ b/src/libcharon/config/ike_cfg.c
@@ -21,6 +21,12 @@
#include <daemon.h>
+ENUM(ike_version_names, IKE_ANY, IKEV2,
+ "IKEv1/2",
+ "IKEv1",
+ "IKEv2",
+);
+
typedef struct private_ike_cfg_t private_ike_cfg_t;
/**
@@ -39,6 +45,11 @@ struct private_ike_cfg_t {
refcount_t refcount;
/**
+ * IKE version to use
+ */
+ ike_version_t version;
+
+ /**
* Address of local host
*/
char *me;
@@ -49,6 +60,16 @@ struct private_ike_cfg_t {
char *other;
/**
+ * Allow override of local address
+ */
+ bool my_allow_any;
+
+ /**
+ * Allow override of remote address
+ */
+ bool other_allow_any;
+
+ /**
* our source port
*/
u_int16_t my_port;
@@ -69,11 +90,27 @@ struct private_ike_cfg_t {
bool force_encap;
/**
+ * use IKEv1 fragmentation
+ */
+ fragmentation_t fragmentation;
+
+ /**
+ * DSCP value to use on sent IKE packets
+ */
+ u_int8_t dscp;
+
+ /**
* List of proposals to use
*/
linked_list_t *proposals;
};
+METHOD(ike_cfg_t, get_version, ike_version_t,
+ private_ike_cfg_t *this)
+{
+ return this->version;
+}
+
METHOD(ike_cfg_t, send_certreq, bool,
private_ike_cfg_t *this)
{
@@ -86,15 +123,29 @@ METHOD(ike_cfg_t, force_encap_, bool,
return this->force_encap;
}
-METHOD(ike_cfg_t, get_my_addr, char*,
+METHOD(ike_cfg_t, fragmentation, fragmentation_t,
private_ike_cfg_t *this)
{
+ return this->fragmentation;
+}
+
+METHOD(ike_cfg_t, get_my_addr, char*,
+ private_ike_cfg_t *this, bool *allow_any)
+{
+ if (allow_any)
+ {
+ *allow_any = this->my_allow_any;
+ }
return this->me;
}
METHOD(ike_cfg_t, get_other_addr, char*,
- private_ike_cfg_t *this)
+ private_ike_cfg_t *this, bool *allow_any)
{
+ if (allow_any)
+ {
+ *allow_any = this->other_allow_any;
+ }
return this->other;
}
@@ -110,6 +161,12 @@ METHOD(ike_cfg_t, get_other_port, u_int16_t,
return this->other_port;
}
+METHOD(ike_cfg_t, get_dscp, u_int8_t,
+ private_ike_cfg_t *this)
+{
+ return this->dscp;
+}
+
METHOD(ike_cfg_t, add_proposal, void,
private_ike_cfg_t *this, proposal_t *proposal)
{
@@ -132,6 +189,8 @@ METHOD(ike_cfg_t, get_proposals, linked_list_t*,
}
enumerator->destroy(enumerator);
+ DBG2(DBG_CFG, "configured proposals: %#P", proposals);
+
return proposals;
}
@@ -228,8 +287,10 @@ METHOD(ike_cfg_t, equals, bool,
e2->destroy(e2);
return (eq &&
+ this->version == other->version &&
this->certreq == other->certreq &&
this->force_encap == other->force_encap &&
+ this->fragmentation == other->fragmentation &&
streq(this->me, other->me) &&
streq(this->other, other->other) &&
this->my_port == other->my_port &&
@@ -259,19 +320,24 @@ METHOD(ike_cfg_t, destroy, void,
/**
* Described in header.
*/
-ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap,
- char *me, u_int16_t my_port, char *other, u_int16_t other_port)
+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,
+ fragmentation_t fragmentation, u_int8_t dscp)
{
private_ike_cfg_t *this;
INIT(this,
.public = {
+ .get_version = _get_version,
.send_certreq = _send_certreq,
.force_encap = _force_encap_,
+ .fragmentation = _fragmentation,
.get_my_addr = _get_my_addr,
.get_other_addr = _get_other_addr,
.get_my_port = _get_my_port,
.get_other_port = _get_other_port,
+ .get_dscp = _get_dscp,
.add_proposal = _add_proposal,
.get_proposals = _get_proposals,
.select_proposal = _select_proposal,
@@ -281,12 +347,17 @@ ike_cfg_t *ike_cfg_create(bool certreq, bool force_encap,
.destroy = _destroy,
},
.refcount = 1,
+ .version = version,
.certreq = certreq,
.force_encap = force_encap,
+ .fragmentation = fragmentation,
.me = strdup(me),
.other = strdup(other),
+ .my_allow_any = my_allow_any,
+ .other_allow_any = other_allow_any,
.my_port = my_port,
.other_port = other_port,
+ .dscp = dscp,
.proposals = linked_list_create(),
);
diff --git a/src/libcharon/config/ike_cfg.h b/src/libcharon/config/ike_cfg.h
index f1edde255..719ceb9dd 100644
--- a/src/libcharon/config/ike_cfg.h
+++ b/src/libcharon/config/ike_cfg.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -22,16 +23,47 @@
#ifndef IKE_CFG_H_
#define IKE_CFG_H_
+typedef enum ike_version_t ike_version_t;
+typedef enum fragmentation_t fragmentation_t;
typedef struct ike_cfg_t ike_cfg_t;
#include <library.h>
-#include <utils/host.h>
-#include <utils/linked_list.h>
+#include <networking/host.h>
+#include <collections/linked_list.h>
#include <utils/identification.h>
#include <config/proposal.h>
#include <crypto/diffie_hellman.h>
/**
+ * IKE version.
+ */
+enum ike_version_t {
+ /** any version */
+ IKE_ANY = 0,
+ /** IKE version 1 */
+ IKEV1 = 1,
+ /** IKE version 2 */
+ IKEV2 = 2,
+};
+
+/**
+ * Proprietary IKEv1 fragmentation
+ */
+enum fragmentation_t {
+ /** disable fragmentation */
+ FRAGMENTATION_NO,
+ /** enable fragmentation if supported by peer */
+ FRAGMENTATION_YES,
+ /** force use of fragmentation (even for the first message) */
+ FRAGMENTATION_FORCE,
+};
+
+/**
+ * enum strings fro ike_version_t
+ */
+extern enum_name_t *ike_version_names;
+
+/**
* An ike_cfg_t defines the rules to set up an IKE_SA.
*
* @see peer_cfg_t to get an overview over the configurations.
@@ -39,40 +71,56 @@ typedef struct ike_cfg_t ike_cfg_t;
struct ike_cfg_t {
/**
+ * Get the IKE version to use with this configuration.
+ *
+ * @return IKE major version
+ */
+ ike_version_t (*get_version)(ike_cfg_t *this);
+
+ /**
* Get own address.
*
- * @return string of address/DNS name
+ * @param allow_any allow any address to match
+ * @return string of address/DNS name
*/
- char* (*get_my_addr) (ike_cfg_t *this);
+ char* (*get_my_addr) (ike_cfg_t *this, bool *allow_any);
/**
- * Get peers address.
+ * Get peer's address.
*
- * @return string of address/DNS name
+ * @param allow_any allow any address to match
+ * @return string of address/DNS name
*/
- char* (*get_other_addr) (ike_cfg_t *this);
+ char* (*get_other_addr) (ike_cfg_t *this, bool *allow_any);
/**
* Get the port to use as our source port.
*
- * @return source address port, host order
+ * @return source address port, host order
*/
u_int16_t (*get_my_port)(ike_cfg_t *this);
/**
* Get the port to use as destination port.
*
- * @return destination address, host order
+ * @return destination address, host order
*/
u_int16_t (*get_other_port)(ike_cfg_t *this);
/**
+ * Get the DSCP value to use for IKE packets send from connections.
+ *
+ * @return DSCP value
+ */
+ u_int8_t (*get_dscp)(ike_cfg_t *this);
+
+ /**
* Adds a proposal to the list.
*
* The first added proposal has the highest priority, the last
* added the lowest.
*
- * @param proposal proposal to add
+ * @param proposal proposal to add
*/
void (*add_proposal) (ike_cfg_t *this, proposal_t *proposal);
@@ -81,7 +129,7 @@ struct ike_cfg_t {
*
* Returned list and its proposals must be destroyed after use.
*
- * @return list containing all the proposals
+ * @return list containing all the proposals
*/
linked_list_t* (*get_proposals) (ike_cfg_t *this);
@@ -90,9 +138,9 @@ struct ike_cfg_t {
*
* Returned proposal must be destroyed after use.
*
- * @param proposals list of proposals to select from
- * @param private accept algorithms from a private range
- * @return selected proposal, or NULL if none matches.
+ * @param proposals list of proposals to select from
+ * @param private accept algorithms from a private range
+ * @return selected proposal, or NULL if none matches.
*/
proposal_t *(*select_proposal) (ike_cfg_t *this, linked_list_t *proposals,
bool private);
@@ -100,36 +148,43 @@ struct ike_cfg_t {
/**
* Should we send a certificate request in IKE_SA_INIT?
*
- * @return certificate request sending policy
+ * @return certificate request sending policy
*/
bool (*send_certreq) (ike_cfg_t *this);
/**
* Enforce UDP encapsulation by faking NATD notifies?
*
- * @return TRUE to enfoce UDP encapsulation
+ * @return TRUE to enforce UDP encapsulation
*/
bool (*force_encap) (ike_cfg_t *this);
/**
+ * Use proprietary IKEv1 fragmentation
+ *
+ * @return TRUE to use fragmentation
+ */
+ fragmentation_t (*fragmentation) (ike_cfg_t *this);
+
+ /**
* Get the DH group to use for IKE_SA setup.
*
- * @return dh group to use for initialization
+ * @return dh group to use for initialization
*/
diffie_hellman_group_t (*get_dh_group)(ike_cfg_t *this);
/**
* Check if two IKE configs are equal.
*
- * @param other other to check for equality
- * @return TRUE if other equal to this
+ * @param other other to check for equality
+ * @return TRUE if other equal to this
*/
bool (*equals)(ike_cfg_t *this, ike_cfg_t *other);
/**
* Increase reference count.
*
- * @return reference to this
+ * @return reference to this
*/
ike_cfg_t* (*get_ref) (ike_cfg_t *this);
@@ -147,15 +202,22 @@ struct ike_cfg_t {
*
* Supplied hosts become owned by ike_cfg, the name gets cloned.
*
- * @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_port IKE port to use as source, 500 uses IKEv2 port floating
- * @param other address/DNS name of remote peer
- * @param other_port IKE port to use as dest, 500 uses IKEv2 port floating
- * @return ike_cfg_t object.
+ * @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(bool certreq, bool force_encap,
- char *me, u_int16_t my_port, char *other, u_int16_t other_port);
+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,
+ 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 c623cbc9b..eb983199b 100644
--- a/src/libcharon/config/peer_cfg.c
+++ b/src/libcharon/config/peer_cfg.c
@@ -22,7 +22,7 @@
#include <daemon.h>
#include <threading/mutex.h>
-#include <utils/linked_list.h>
+#include <collections/linked_list.h>
#include <utils/identification.h>
ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND,
@@ -60,11 +60,6 @@ struct private_peer_cfg_t {
char *name;
/**
- * IKE version to use for initiation
- */
- u_int ike_version;
-
- /**
* IKE config associated to this peer config
*/
ike_cfg_t *ike_cfg;
@@ -100,6 +95,11 @@ struct private_peer_cfg_t {
bool use_mobike;
/**
+ * Use aggressive mode?
+ */
+ bool aggressive;
+
+ /**
* Time before starting rekeying
*/
u_int32_t rekey_time;
@@ -125,14 +125,19 @@ struct private_peer_cfg_t {
u_int32_t dpd;
/**
- * virtual IP to use locally
+ * DPD timeout intervall (used for IKEv1 only)
*/
- host_t *virtual_ip;
+ u_int32_t dpd_timeout;
/**
- * pool to acquire configuration attributes from
+ * List of virtual IPs (host_t*) to request
*/
- char *pool;
+ linked_list_t *vips;
+
+ /**
+ * List of pool names to use for virtual IP lookup
+ */
+ linked_list_t *pools;
/**
* local authentication configs (rulesets)
@@ -169,10 +174,10 @@ METHOD(peer_cfg_t, get_name, char*,
return this->name;
}
-METHOD(peer_cfg_t, get_ike_version, u_int,
+METHOD(peer_cfg_t, get_ike_version, ike_version_t,
private_peer_cfg_t *this)
{
- return this->ike_version;
+ return this->ike_cfg->get_version(this->ike_cfg);
}
METHOD(peer_cfg_t, get_ike_cfg, ike_cfg_t*,
@@ -240,15 +245,15 @@ METHOD(peer_cfg_t, create_child_cfg_enumerator, enumerator_t*,
* Check how good a list of TS matches a given child config
*/
static int get_ts_match(child_cfg_t *cfg, bool local,
- linked_list_t *sup_list, host_t *host)
+ linked_list_t *sup_list, linked_list_t *hosts)
{
linked_list_t *cfg_list;
enumerator_t *sup_enum, *cfg_enum;
- traffic_selector_t *sup_ts, *cfg_ts;
+ traffic_selector_t *sup_ts, *cfg_ts, *subset;
int match = 0, round;
/* fetch configured TS list, narrowing dynamic TS */
- cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, host);
+ cfg_list = cfg->get_traffic_selectors(cfg, local, NULL, hosts);
/* use a round counter to rate leading TS with higher priority */
round = sup_list->get_count(sup_list);
@@ -263,10 +268,14 @@ static int get_ts_match(child_cfg_t *cfg, bool local,
{ /* equality is honored better than matches */
match += round * 5;
}
- else if (cfg_ts->is_contained_in(cfg_ts, sup_ts) ||
- sup_ts->is_contained_in(sup_ts, cfg_ts))
+ else
{
- match += round * 1;
+ subset = cfg_ts->get_subset(cfg_ts, sup_ts);
+ if (subset)
+ {
+ subset->destroy(subset);
+ match += round * 1;
+ }
}
}
cfg_enum->destroy(cfg_enum);
@@ -281,7 +290,7 @@ static int get_ts_match(child_cfg_t *cfg, bool local,
METHOD(peer_cfg_t, select_child_cfg, child_cfg_t*,
private_peer_cfg_t *this, linked_list_t *my_ts, linked_list_t *other_ts,
- host_t *my_host, host_t *other_host)
+ linked_list_t *my_hosts, linked_list_t *other_hosts)
{
child_cfg_t *current, *found = NULL;
enumerator_t *enumerator;
@@ -293,8 +302,8 @@ METHOD(peer_cfg_t, select_child_cfg, child_cfg_t*,
{
int my_prio, other_prio;
- my_prio = get_ts_match(current, TRUE, my_ts, my_host);
- other_prio = get_ts_match(current, FALSE, other_ts, other_host);
+ my_prio = get_ts_match(current, TRUE, my_ts, my_hosts);
+ other_prio = get_ts_match(current, FALSE, other_ts, other_hosts);
if (my_prio && other_prio)
{
@@ -336,13 +345,13 @@ METHOD(peer_cfg_t, get_keyingtries, u_int32_t,
}
METHOD(peer_cfg_t, get_rekey_time, u_int32_t,
- private_peer_cfg_t *this)
+ private_peer_cfg_t *this, bool jitter)
{
if (this->rekey_time == 0)
{
return 0;
}
- if (this->jitter_time == 0)
+ if (this->jitter_time == 0 || !jitter)
{
return this->rekey_time;
}
@@ -350,13 +359,13 @@ METHOD(peer_cfg_t, get_rekey_time, u_int32_t,
}
METHOD(peer_cfg_t, get_reauth_time, u_int32_t,
- private_peer_cfg_t *this)
+ private_peer_cfg_t *this, bool jitter)
{
if (this->reauth_time == 0)
{
return 0;
}
- if (this->jitter_time == 0)
+ if (this->jitter_time == 0 || !jitter)
{
return this->reauth_time;
}
@@ -375,22 +384,46 @@ METHOD(peer_cfg_t, use_mobike, bool,
return this->use_mobike;
}
+METHOD(peer_cfg_t, use_aggressive, bool,
+ private_peer_cfg_t *this)
+{
+ return this->aggressive;
+}
+
METHOD(peer_cfg_t, get_dpd, u_int32_t,
private_peer_cfg_t *this)
{
return this->dpd;
}
-METHOD(peer_cfg_t, get_virtual_ip, host_t*,
+METHOD(peer_cfg_t, get_dpd_timeout, u_int32_t,
private_peer_cfg_t *this)
{
- return this->virtual_ip;
+ return this->dpd_timeout;
+}
+
+METHOD(peer_cfg_t, add_virtual_ip, void,
+ private_peer_cfg_t *this, host_t *vip)
+{
+ this->vips->insert_last(this->vips, vip);
}
-METHOD(peer_cfg_t, get_pool, char*,
+METHOD(peer_cfg_t, create_virtual_ip_enumerator, enumerator_t*,
private_peer_cfg_t *this)
{
- return this->pool;
+ return this->vips->create_enumerator(this->vips);
+}
+
+METHOD(peer_cfg_t, add_pool, void,
+ private_peer_cfg_t *this, char *name)
+{
+ this->pools->insert_last(this->pools, strdup(name));
+}
+
+METHOD(peer_cfg_t, create_pool_enumerator, enumerator_t*,
+ private_peer_cfg_t *this)
+{
+ return this->pools->create_enumerator(this->pools);
}
METHOD(peer_cfg_t, add_auth_cfg, void,
@@ -493,6 +526,10 @@ static bool auth_cfg_equal(private_peer_cfg_t *this, private_peer_cfg_t *other)
METHOD(peer_cfg_t, equals, bool,
private_peer_cfg_t *this, private_peer_cfg_t *other)
{
+ enumerator_t *e1, *e2;
+ host_t *vip1, *vip2;
+ char *pool1, *pool2;
+
if (this == other)
{
return TRUE;
@@ -502,8 +539,45 @@ METHOD(peer_cfg_t, equals, bool,
return FALSE;
}
+ if (this->vips->get_count(this->vips) != other->vips->get_count(other->vips))
+ {
+ return FALSE;
+ }
+ e1 = create_virtual_ip_enumerator(this);
+ e2 = create_virtual_ip_enumerator(other);
+ if (e1->enumerate(e1, &vip1) && e2->enumerate(e2, &vip2))
+ {
+ if (!vip1->ip_equals(vip1, vip2))
+ {
+ e1->destroy(e1);
+ e2->destroy(e2);
+ return FALSE;
+ }
+ }
+ e1->destroy(e1);
+ e2->destroy(e2);
+
+ if (this->pools->get_count(this->pools) !=
+ other->pools->get_count(other->pools))
+ {
+ return FALSE;
+ }
+ e1 = create_pool_enumerator(this);
+ e2 = create_pool_enumerator(other);
+ if (e1->enumerate(e1, &pool1) && e2->enumerate(e2, &pool2))
+ {
+ if (!streq(pool1, pool2))
+ {
+ e1->destroy(e1);
+ e2->destroy(e2);
+ return FALSE;
+ }
+ }
+ e1->destroy(e1);
+ e2->destroy(e2);
+
return (
- this->ike_version == other->ike_version &&
+ get_ike_version(this) == get_ike_version(other) &&
this->cert_policy == other->cert_policy &&
this->unique == other->unique &&
this->keyingtries == other->keyingtries &&
@@ -513,11 +587,7 @@ METHOD(peer_cfg_t, equals, bool,
this->jitter_time == other->jitter_time &&
this->over_time == other->over_time &&
this->dpd == other->dpd &&
- (this->virtual_ip == other->virtual_ip ||
- (this->virtual_ip && other->virtual_ip &&
- this->virtual_ip->equals(this->virtual_ip, other->virtual_ip))) &&
- (this->pool == other->pool ||
- (this->pool && other->pool && streq(this->pool, other->pool))) &&
+ this->aggressive == other->aggressive &&
auth_cfg_equal(this, other)
#ifdef ME
&& this->mediation == other->mediation &&
@@ -544,18 +614,18 @@ METHOD(peer_cfg_t, destroy, void,
this->ike_cfg->destroy(this->ike_cfg);
this->child_cfgs->destroy_offset(this->child_cfgs,
offsetof(child_cfg_t, destroy));
- DESTROY_IF(this->virtual_ip);
this->local_auth->destroy_offset(this->local_auth,
offsetof(auth_cfg_t, destroy));
this->remote_auth->destroy_offset(this->remote_auth,
offsetof(auth_cfg_t, destroy));
+ this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
+ this->pools->destroy_function(this->pools, free);
#ifdef ME
DESTROY_IF(this->mediated_by);
DESTROY_IF(this->peer_id);
#endif /* ME */
this->mutex->destroy(this->mutex);
free(this->name);
- free(this->pool);
free(this);
}
}
@@ -563,12 +633,13 @@ METHOD(peer_cfg_t, destroy, void,
/*
* Described in header-file
*/
-peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
- cert_policy_t cert_policy, 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, u_int32_t dpd,
- host_t *virtual_ip, char *pool,
+peer_cfg_t *peer_cfg_create(char *name,
+ ike_cfg_t *ike_cfg, cert_policy_t cert_policy,
+ 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 mediation, peer_cfg_t *mediated_by,
identification_t *peer_id)
{
@@ -599,9 +670,13 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
.get_reauth_time = _get_reauth_time,
.get_over_time = _get_over_time,
.use_mobike = _use_mobike,
+ .use_aggressive = _use_aggressive,
.get_dpd = _get_dpd,
- .get_virtual_ip = _get_virtual_ip,
- .get_pool = _get_pool,
+ .get_dpd_timeout = _get_dpd_timeout,
+ .add_virtual_ip = _add_virtual_ip,
+ .create_virtual_ip_enumerator = _create_virtual_ip_enumerator,
+ .add_pool = _add_pool,
+ .create_pool_enumerator = _create_pool_enumerator,
.add_auth_cfg = _add_auth_cfg,
.create_auth_cfg_enumerator = _create_auth_cfg_enumerator,
.equals = (void*)_equals,
@@ -614,7 +689,6 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
#endif /* ME */
},
.name = strdup(name),
- .ike_version = ike_version,
.ike_cfg = ike_cfg,
.child_cfgs = linked_list_create(),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
@@ -626,9 +700,11 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
.jitter_time = jitter_time,
.over_time = over_time,
.use_mobike = mobike,
+ .aggressive = aggressive,
.dpd = dpd,
- .virtual_ip = virtual_ip,
- .pool = strdupnull(pool),
+ .dpd_timeout = dpd_timeout,
+ .vips = linked_list_create(),
+ .pools = linked_list_create(),
.local_auth = linked_list_create(),
.remote_auth = linked_list_create(),
.refcount = 1,
diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h
index f644fb547..e62e03ec5 100644
--- a/src/libcharon/config/peer_cfg.h
+++ b/src/libcharon/config/peer_cfg.h
@@ -29,13 +29,11 @@ typedef struct peer_cfg_t peer_cfg_t;
#include <library.h>
#include <utils/identification.h>
-#include <utils/enumerator.h>
+#include <collections/enumerator.h>
#include <selectors/traffic_selector.h>
#include <config/proposal.h>
#include <config/ike_cfg.h>
#include <config/child_cfg.h>
-#include <sa/authenticators/authenticator.h>
-#include <sa/authenticators/eap/eap_method.h>
#include <credentials/auth_cfg.h>
/**
@@ -65,11 +63,13 @@ extern enum_name_t *cert_policy_names;
* Uniqueness of an IKE_SA, used to drop multiple connections with one peer.
*/
enum unique_policy_t {
- /** do not check for client uniqueness */
+ /** never check for client uniqueness */
+ UNIQUE_NEVER,
+ /** only check for client uniqueness when receiving an INITIAL_CONTACT */
UNIQUE_NO,
- /** replace unique IKE_SAs if new ones get established */
+ /** replace existing IKE_SAs when new ones get established by a client */
UNIQUE_REPLACE,
- /** keep existing IKE_SAs, close the new ones on connection attept */
+ /** keep existing IKE_SAs, close the new ones on connection attempt */
UNIQUE_KEEP,
};
@@ -130,7 +130,7 @@ struct peer_cfg_t {
*
* @return IKE major version
*/
- u_int (*get_ike_version)(peer_cfg_t *this);
+ ike_version_t (*get_ike_version)(peer_cfg_t *this);
/**
* Get the IKE config to use for initiaton.
@@ -165,18 +165,18 @@ struct peer_cfg_t {
*
* @param my_ts TS for local side
* @param other_ts TS for remote side
- * @param my_host host to narrow down dynamic TS for local side
- * @param other_host host to narrow down dynamic TS for remote side
+ * @param my_hosts hosts to narrow down dynamic TS for local side
+ * @param other_hosts hosts to narrow down dynamic TS for remote side
* @return selected CHILD config, or NULL if no match found
*/
- child_cfg_t* (*select_child_cfg) (peer_cfg_t *this, linked_list_t *my_ts,
- linked_list_t *other_ts, host_t *my_host,
- host_t *other_host);
+ child_cfg_t* (*select_child_cfg) (peer_cfg_t *this,
+ linked_list_t *my_ts, linked_list_t *other_ts,
+ linked_list_t *my_hosts, linked_list_t *other_hosts);
/**
* Add an authentication config to the peer configuration.
*
- * @param config config to add
+ * @param cfg config to add
* @param local TRUE for local rules, FALSE for remote constraints
*/
void (*add_auth_cfg)(peer_cfg_t *this, auth_cfg_t *cfg, bool local);
@@ -190,7 +190,7 @@ struct peer_cfg_t {
enumerator_t* (*create_auth_cfg_enumerator)(peer_cfg_t *this, bool local);
/**
- * Should be sent a certificate for this connection?
+ * Should a certificate be sent for this connection?
*
* @return certificate sending policy
*/
@@ -211,18 +211,20 @@ struct peer_cfg_t {
u_int32_t (*get_keyingtries) (peer_cfg_t *this);
/**
- * Get a time to start rekeying (is randomized with jitter).
+ * Get a time to start rekeying.
*
+ * @param jitter remove a jitter value to randomize time
* @return time in s when to start rekeying, 0 disables rekeying
*/
- u_int32_t (*get_rekey_time)(peer_cfg_t *this);
+ u_int32_t (*get_rekey_time)(peer_cfg_t *this, bool jitter);
/**
- * Get a time to start reauthentication (is randomized with jitter).
+ * Get a time to start reauthentication.
*
+ * @param jitter remove a jitter value to randomize time
* @return time in s when to start reauthentication, 0 disables it
*/
- u_int32_t (*get_reauth_time)(peer_cfg_t *this);
+ u_int32_t (*get_reauth_time)(peer_cfg_t *this, bool jitter);
/**
* Get the timeout of a rekeying/reauthenticating SA.
@@ -239,6 +241,13 @@ struct peer_cfg_t {
bool (*use_mobike) (peer_cfg_t *this);
/**
+ * Use/Accept aggressive mode with IKEv1?.
+ *
+ * @return TRUE to use aggressive mode
+ */
+ bool (*use_aggressive)(peer_cfg_t *this);
+
+ /**
* Get the DPD check interval.
*
* @return dpd_delay in seconds
@@ -246,23 +255,41 @@ struct peer_cfg_t {
u_int32_t (*get_dpd) (peer_cfg_t *this);
/**
- * Get a virtual IP for the local peer.
+ * Get the DPD timeout interval (IKEv1 only)
+ *
+ * @return dpd_timeout in seconds
+ */
+ u_int32_t (*get_dpd_timeout) (peer_cfg_t *this);
+
+ /**
+ * Add a virtual IP to request as initiator.
*
- * If no virtual IP should be used, NULL is returned. %any means to request
- * a virtual IP using configuration payloads. A specific address is also
- * used for a request and may be changed by the server.
+ * @param vip virtual IP to request, may be %any or %any6
+ */
+ void (*add_virtual_ip)(peer_cfg_t *this, host_t *vip);
+
+ /**
+ * Create an enumerator over virtual IPs to request.
+ *
+ * The returned enumerator enumerates over IPs added with add_virtual_ip().
+ *
+ * @return enumerator over host_t*
+ */
+ enumerator_t* (*create_virtual_ip_enumerator)(peer_cfg_t *this);
+
+ /**
+ * Add a pool name this configuration uses to select virtual IPs.
*
- * @param suggestion NULL, %any or specific
- * @return virtual IP, %any or NULL
+ * @param name pool name to use for virtual IP lookup
*/
- host_t* (*get_virtual_ip) (peer_cfg_t *this);
+ void (*add_pool)(peer_cfg_t *this, char *name);
/**
- * Get the name of the pool to acquire configuration attributes from.
+ * Create an enumerator over pool names of this config.
*
- * @return pool name, NULL if none defined
+ * @return enumerator over char*
*/
- char* (*get_pool)(peer_cfg_t *this);
+ enumerator_t* (*create_pool_enumerator)(peer_cfg_t *this);
#ifdef ME
/**
@@ -329,7 +356,6 @@ struct peer_cfg_t {
* (rekeylifetime - random(0, jitter)).
*
* @param name name of the peer_cfg
- * @param ike_version which IKE version we should use for this peer
* @param ike_cfg IKE config to use when acting as initiator
* @param cert_policy should we send a certificate payload?
* @param unique uniqueness of an IKE_SA
@@ -339,20 +365,21 @@ struct peer_cfg_t {
* @param jitter_time timerange to randomly subtract from rekey/reauth time
* @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 dpd DPD check interval, 0 to disable
- * @param virtual_ip virtual IP for local host, or NULL
- * @param pool pool name to get configuration attributes from, or NULL
+ * @param dpd_timeout DPD timeout interval (IKEv1 only), if 0 default applies
* @param mediation TRUE if this is a mediation connection
* @param mediated_by peer_cfg_t of the mediation connection to mediate through
* @param peer_id ID that identifies our peer at the mediation server
* @return peer_cfg_t object
*/
-peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
- cert_policy_t cert_policy, 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, u_int32_t dpd,
- host_t *virtual_ip, char *pool,
+peer_cfg_t *peer_cfg_create(char *name,
+ ike_cfg_t *ike_cfg, cert_policy_t cert_policy,
+ 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 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 d3c60a469..0b702e014 100644
--- a/src/libcharon/config/proposal.c
+++ b/src/libcharon/config/proposal.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2009 Tobias Brunner
+ * Copyright (C) 2008-2012 Tobias Brunner
* Copyright (C) 2006-2010 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -19,24 +19,23 @@
#include "proposal.h"
#include <daemon.h>
-#include <utils/linked_list.h>
+#include <collections/array.h>
#include <utils/identification.h>
-#include <utils/lexparser.h>
+
#include <crypto/transform.h>
#include <crypto/prfs/prf.h>
#include <crypto/crypters/crypter.h>
#include <crypto/signers/signer.h>
-#include <crypto/proposal/proposal_keywords.h>
-ENUM(protocol_id_names, PROTO_NONE, PROTO_ESP,
+ENUM(protocol_id_names, PROTO_NONE, PROTO_IPCOMP,
"PROTO_NONE",
"IKE",
"AH",
"ESP",
+ "IPCOMP",
);
typedef struct private_proposal_t private_proposal_t;
-typedef struct algorithm_t algorithm_t;
/**
* Private data of an proposal_t object
@@ -54,29 +53,9 @@ struct private_proposal_t {
protocol_id_t protocol;
/**
- * priority ordered list of encryption algorithms
- */
- linked_list_t *encryption_algos;
-
- /**
- * priority ordered list of integrity algorithms
+ * Priority ordered list of transforms, as entry_t
*/
- linked_list_t *integrity_algos;
-
- /**
- * priority ordered list of pseudo random functions
- */
- linked_list_t *prf_algos;
-
- /**
- * priority ordered list of dh groups
- */
- linked_list_t *dh_groups;
-
- /**
- * priority ordered list of extended sequence number flags
- */
- linked_list_t *esns;
+ array_t *transforms;
/**
* senders SPI
@@ -92,68 +71,47 @@ struct private_proposal_t {
/**
* Struct used to store different kinds of algorithms.
*/
-struct algorithm_t {
- /**
- * Value from an encryption_algorithm_t/integrity_algorithm_t/...
- */
- u_int16_t algorithm;
-
- /**
- * the associated key size in bits, or zero if not needed
- */
+typedef struct {
+ /** Type of the transform */
+ transform_type_t type;
+ /** algorithm identifier */
+ u_int16_t alg;
+ /** key size in bits, or zero if not needed */
u_int16_t key_size;
-};
-
-/**
- * Add algorithm/keysize to a algorithm list
- */
-static void add_algo(linked_list_t *list, u_int16_t algo, u_int16_t key_size)
-{
- algorithm_t *algo_key;
-
- algo_key = malloc_thing(algorithm_t);
- algo_key->algorithm = algo;
- algo_key->key_size = key_size;
- list->insert_last(list, (void*)algo_key);
-}
+} entry_t;
METHOD(proposal_t, add_algorithm, void,
private_proposal_t *this, transform_type_t type,
- u_int16_t algo, u_int16_t key_size)
+ u_int16_t alg, u_int16_t key_size)
{
- switch (type)
- {
- case ENCRYPTION_ALGORITHM:
- add_algo(this->encryption_algos, algo, key_size);
- break;
- case INTEGRITY_ALGORITHM:
- add_algo(this->integrity_algos, algo, key_size);
- break;
- case PSEUDO_RANDOM_FUNCTION:
- add_algo(this->prf_algos, algo, key_size);
- break;
- case DIFFIE_HELLMAN_GROUP:
- add_algo(this->dh_groups, algo, 0);
- break;
- case EXTENDED_SEQUENCE_NUMBERS:
- add_algo(this->esns, algo, 0);
- break;
- default:
- break;
- }
+ entry_t entry = {
+ .type = type,
+ .alg = alg,
+ .key_size = key_size,
+ };
+
+ array_insert(this->transforms, ARRAY_TAIL, &entry);
}
/**
* filter function for peer configs
*/
-static bool alg_filter(void *null, algorithm_t **in, u_int16_t *alg,
+static bool alg_filter(uintptr_t type, entry_t **in, u_int16_t *alg,
void **unused, u_int16_t *key_size)
{
- algorithm_t *algo = *in;
- *alg = algo->algorithm;
+ entry_t *entry = *in;
+
+ if (entry->type != type)
+ {
+ return FALSE;
+ }
+ if (alg)
+ {
+ *alg = entry->alg;
+ }
if (key_size)
{
- *key_size = algo->key_size;
+ *key_size = entry->key_size;
}
return TRUE;
}
@@ -161,30 +119,9 @@ static bool alg_filter(void *null, algorithm_t **in, u_int16_t *alg,
METHOD(proposal_t, create_enumerator, enumerator_t*,
private_proposal_t *this, transform_type_t type)
{
- linked_list_t *list;
-
- switch (type)
- {
- case ENCRYPTION_ALGORITHM:
- list = this->encryption_algos;
- break;
- case INTEGRITY_ALGORITHM:
- list = this->integrity_algos;
- break;
- case PSEUDO_RANDOM_FUNCTION:
- list = this->prf_algos;
- break;
- case DIFFIE_HELLMAN_GROUP:
- list = this->dh_groups;
- break;
- case EXTENDED_SEQUENCE_NUMBERS:
- list = this->esns;
- break;
- default:
- return NULL;
- }
- return enumerator_create_filter(list->create_enumerator(list),
- (void*)alg_filter, NULL, NULL);
+ return enumerator_create_filter(
+ array_create_enumerator(this->transforms),
+ (void*)alg_filter, (void*)(uintptr_t)type, NULL);
}
METHOD(proposal_t, get_algorithm, bool,
@@ -200,77 +137,91 @@ METHOD(proposal_t, get_algorithm, bool,
found = TRUE;
}
enumerator->destroy(enumerator);
+
return found;
}
METHOD(proposal_t, has_dh_group, bool,
private_proposal_t *this, diffie_hellman_group_t group)
{
- bool result = FALSE;
+ bool found = FALSE, any = FALSE;
+ enumerator_t *enumerator;
+ u_int16_t current;
- if (this->dh_groups->get_count(this->dh_groups))
+ enumerator = create_enumerator(this, DIFFIE_HELLMAN_GROUP);
+ while (enumerator->enumerate(enumerator, &current, NULL))
{
- algorithm_t *current;
- enumerator_t *enumerator;
-
- enumerator = this->dh_groups->create_enumerator(this->dh_groups);
- while (enumerator->enumerate(enumerator, (void**)&current))
+ any = TRUE;
+ if (current == group)
{
- if (current->algorithm == group)
- {
- result = TRUE;
- break;
- }
+ found = TRUE;
+ break;
}
- enumerator->destroy(enumerator);
}
- else if (group == MODP_NONE)
+ enumerator->destroy(enumerator);
+
+ if (!any && group == MODP_NONE)
{
- result = TRUE;
+ found = TRUE;
}
- return result;
+ return found;
}
METHOD(proposal_t, strip_dh, void,
- private_proposal_t *this)
+ private_proposal_t *this, diffie_hellman_group_t keep)
{
- algorithm_t *alg;
+ enumerator_t *enumerator;
+ entry_t *entry;
- while (this->dh_groups->remove_last(this->dh_groups, (void**)&alg) == SUCCESS)
+ enumerator = array_create_enumerator(this->transforms);
+ while (enumerator->enumerate(enumerator, &entry))
{
- free(alg);
+ if (entry->type == DIFFIE_HELLMAN_GROUP &&
+ entry->alg != keep)
+ {
+ array_remove_at(this->transforms, enumerator);
+ }
}
+ enumerator->destroy(enumerator);
}
/**
- * Find a matching alg/keysize in two linked lists
+ * Select a matching proposal from this and other, insert into selected.
*/
-static bool select_algo(linked_list_t *first, linked_list_t *second, bool priv,
- bool *add, u_int16_t *alg, size_t *key_size)
+static bool select_algo(private_proposal_t *this, proposal_t *other,
+ proposal_t *selected, transform_type_t type, bool priv)
{
enumerator_t *e1, *e2;
- algorithm_t *alg1, *alg2;
+ u_int16_t alg1, alg2, ks1, ks2;
+ bool found = FALSE;
- /* if in both are zero algorithms specified, we HAVE a match */
- if (first->get_count(first) == 0 && second->get_count(second) == 0)
+ if (type == INTEGRITY_ALGORITHM &&
+ selected->get_algorithm(selected, ENCRYPTION_ALGORITHM, &alg1, NULL) &&
+ encryption_algorithm_is_aead(alg1))
{
- *add = FALSE;
+ /* no integrity algorithm required, we have an AEAD */
return TRUE;
}
- e1 = first->create_enumerator(first);
- e2 = second->create_enumerator(second);
+ e1 = create_enumerator(this, type);
+ e2 = other->create_enumerator(other, type);
+ if (!e1->enumerate(e1, NULL, NULL) && !e2->enumerate(e2, NULL, NULL))
+ {
+ found = TRUE;
+ }
+
+ e1->destroy(e1);
+ e1 = create_enumerator(this, type);
/* compare algs, order of algs in "first" is preferred */
- while (e1->enumerate(e1, &alg1))
+ while (!found && e1->enumerate(e1, &alg1, &ks1))
{
e2->destroy(e2);
- e2 = second->create_enumerator(second);
- while (e2->enumerate(e2, &alg2))
+ e2 = other->create_enumerator(other, type);
+ while (e2->enumerate(e2, &alg2, &ks2))
{
- if (alg1->algorithm == alg2->algorithm &&
- alg1->key_size == alg2->key_size)
+ if (alg1 == alg2 && ks1 == ks2)
{
- if (!priv && alg1->algorithm >= 1024)
+ if (!priv && alg1 >= 1024)
{
/* accept private use algorithms only if requested */
DBG1(DBG_CFG, "an algorithm from private space would match, "
@@ -278,132 +229,52 @@ static bool select_algo(linked_list_t *first, linked_list_t *second, bool priv,
continue;
}
/* ok, we have an algorithm */
- *alg = alg1->algorithm;
- *key_size = alg1->key_size;
- *add = TRUE;
- e1->destroy(e1);
- e2->destroy(e2);
- return TRUE;
+ selected->add_algorithm(selected, type, alg1, ks1);
+ found = TRUE;
+ break;
}
}
}
/* no match in all comparisons */
e1->destroy(e1);
e2->destroy(e2);
- return FALSE;
+
+ if (!found)
+ {
+ DBG2(DBG_CFG, " no acceptable %N found", transform_type_names, type);
+ }
+ return found;
}
METHOD(proposal_t, select_proposal, proposal_t*,
- private_proposal_t *this, proposal_t *other_pub, bool private)
+ private_proposal_t *this, proposal_t *other, bool private)
{
- private_proposal_t *other = (private_proposal_t*)other_pub;
proposal_t *selected;
- u_int16_t algo;
- size_t key_size;
- bool add;
DBG2(DBG_CFG, "selecting proposal:");
- /* check protocol */
- if (this->protocol != other->protocol)
+ if (this->protocol != other->get_protocol(other))
{
DBG2(DBG_CFG, " protocol mismatch, skipping");
return NULL;
}
- selected = proposal_create(this->protocol, other->number);
+ selected = proposal_create(this->protocol, other->get_number(other));
- /* select encryption algorithm */
- if (select_algo(this->encryption_algos, other->encryption_algos, private,
- &add, &algo, &key_size))
- {
- if (add)
- {
- selected->add_algorithm(selected, ENCRYPTION_ALGORITHM,
- algo, key_size);
- }
- }
- else
- {
- selected->destroy(selected);
- DBG2(DBG_CFG, " no acceptable %N found",
- transform_type_names, ENCRYPTION_ALGORITHM);
- return NULL;
- }
- /* select integrity algorithm */
- if (!encryption_algorithm_is_aead(algo))
- {
- if (select_algo(this->integrity_algos, other->integrity_algos, private,
- &add, &algo, &key_size))
- {
- if (add)
- {
- selected->add_algorithm(selected, INTEGRITY_ALGORITHM,
- algo, key_size);
- }
- }
- else
- {
- selected->destroy(selected);
- DBG2(DBG_CFG, " no acceptable %N found",
- transform_type_names, INTEGRITY_ALGORITHM);
- return NULL;
- }
- }
- /* select prf algorithm */
- if (select_algo(this->prf_algos, other->prf_algos, private,
- &add, &algo, &key_size))
- {
- if (add)
- {
- selected->add_algorithm(selected, PSEUDO_RANDOM_FUNCTION,
- algo, key_size);
- }
- }
- else
- {
- selected->destroy(selected);
- DBG2(DBG_CFG, " no acceptable %N found",
- transform_type_names, PSEUDO_RANDOM_FUNCTION);
- return NULL;
- }
- /* select a DH-group */
- if (select_algo(this->dh_groups, other->dh_groups, private,
- &add, &algo, &key_size))
- {
- if (add)
- {
- selected->add_algorithm(selected, DIFFIE_HELLMAN_GROUP, algo, 0);
- }
- }
- else
- {
- selected->destroy(selected);
- DBG2(DBG_CFG, " no acceptable %N found",
- transform_type_names, DIFFIE_HELLMAN_GROUP);
- return NULL;
- }
- /* select if we use ESNs (has no private use space) */
- if (select_algo(this->esns, other->esns, TRUE, &add, &algo, &key_size))
- {
- if (add)
- {
- selected->add_algorithm(selected, EXTENDED_SEQUENCE_NUMBERS, algo, 0);
- }
- }
- else
+ if (!select_algo(this, other, selected, ENCRYPTION_ALGORITHM, private) ||
+ !select_algo(this, other, selected, PSEUDO_RANDOM_FUNCTION, private) ||
+ !select_algo(this, other, selected, INTEGRITY_ALGORITHM, private) ||
+ !select_algo(this, other, selected, DIFFIE_HELLMAN_GROUP, private) ||
+ !select_algo(this, other, selected, EXTENDED_SEQUENCE_NUMBERS, private))
{
selected->destroy(selected);
- DBG2(DBG_CFG, " no acceptable %N found",
- transform_type_names, EXTENDED_SEQUENCE_NUMBERS);
return NULL;
}
+
DBG2(DBG_CFG, " proposal matches");
- /* apply SPI from "other" */
- selected->set_spi(selected, other->spi);
+ selected->set_spi(selected, other->get_spi(other));
- /* everything matched, return new proposal */
return selected;
}
@@ -426,50 +297,39 @@ METHOD(proposal_t, get_spi, u_int64_t,
}
/**
- * Clone a algorithm list
+ * Check if two proposals have the same algorithms for a given transform type
*/
-static void clone_algo_list(linked_list_t *list, linked_list_t *clone_list)
-{
- algorithm_t *algo, *clone_algo;
- enumerator_t *enumerator;
-
- enumerator = list->create_enumerator(list);
- while (enumerator->enumerate(enumerator, &algo))
- {
- clone_algo = malloc_thing(algorithm_t);
- memcpy(clone_algo, algo, sizeof(algorithm_t));
- clone_list->insert_last(clone_list, (void*)clone_algo);
- }
- enumerator->destroy(enumerator);
-}
-
-/**
- * check if an algorithm list equals
- */
-static bool algo_list_equals(linked_list_t *l1, linked_list_t *l2)
+static bool algo_list_equals(private_proposal_t *this, proposal_t *other,
+ transform_type_t type)
{
enumerator_t *e1, *e2;
- algorithm_t *alg1, *alg2;
+ u_int16_t alg1, alg2, ks1, ks2;
bool equals = TRUE;
- if (l1->get_count(l1) != l2->get_count(l2))
+ e1 = create_enumerator(this, type);
+ e2 = other->create_enumerator(other, type);
+ while (e1->enumerate(e1, &alg1, &ks1))
{
- return FALSE;
- }
-
- e1 = l1->create_enumerator(l1);
- e2 = l2->create_enumerator(l2);
- while (e1->enumerate(e1, &alg1) && e2->enumerate(e2, &alg2))
- {
- if (alg1->algorithm != alg2->algorithm ||
- alg1->key_size != alg2->key_size)
+ if (!e2->enumerate(e2, &alg2, &ks2))
{
+ /* this has more algs */
equals = FALSE;
break;
}
+ if (alg1 != alg2 || ks1 != ks2)
+ {
+ equals = FALSE;
+ break;
+ }
+ }
+ if (e2->enumerate(e2, &alg2, ks2))
+ {
+ /* other has more algs */
+ equals = FALSE;
}
e1->destroy(e1);
e2->destroy(e2);
+
return equals;
}
@@ -480,33 +340,35 @@ METHOD(proposal_t, get_number, u_int,
}
METHOD(proposal_t, equals, bool,
- private_proposal_t *this, proposal_t *other_pub)
+ private_proposal_t *this, proposal_t *other)
{
- private_proposal_t *other = (private_proposal_t*)other_pub;
-
- if (this == other)
+ if (&this->public == other)
{
return TRUE;
}
return (
- algo_list_equals(this->encryption_algos, other->encryption_algos) &&
- algo_list_equals(this->integrity_algos, other->integrity_algos) &&
- algo_list_equals(this->prf_algos, other->prf_algos) &&
- algo_list_equals(this->dh_groups, other->dh_groups) &&
- algo_list_equals(this->esns, other->esns));
+ algo_list_equals(this, other, ENCRYPTION_ALGORITHM) &&
+ algo_list_equals(this, other, INTEGRITY_ALGORITHM) &&
+ algo_list_equals(this, other, PSEUDO_RANDOM_FUNCTION) &&
+ algo_list_equals(this, other, DIFFIE_HELLMAN_GROUP) &&
+ algo_list_equals(this, other, EXTENDED_SEQUENCE_NUMBERS));
}
METHOD(proposal_t, clone_, proposal_t*,
private_proposal_t *this)
{
private_proposal_t *clone;
+ enumerator_t *enumerator;
+ entry_t *entry;
clone = (private_proposal_t*)proposal_create(this->protocol, 0);
- clone_algo_list(this->encryption_algos, clone->encryption_algos);
- clone_algo_list(this->integrity_algos, clone->integrity_algos);
- clone_algo_list(this->prf_algos, clone->prf_algos);
- clone_algo_list(this->dh_groups, clone->dh_groups);
- clone_algo_list(this->esns, clone->esns);
+
+ enumerator = array_create_enumerator(this->transforms);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ array_insert(clone->transforms, ARRAY_TAIL, entry);
+ }
+ enumerator->destroy(enumerator);
clone->spi = this->spi;
clone->number = this->number;
@@ -515,18 +377,62 @@ METHOD(proposal_t, clone_, proposal_t*,
}
/**
+ * Map integrity algorithms to the PRF functions using the same algorithm.
+ */
+static const struct {
+ integrity_algorithm_t integ;
+ pseudo_random_function_t prf;
+} integ_prf_map[] = {
+ {AUTH_HMAC_SHA1_96, PRF_HMAC_SHA1 },
+ {AUTH_HMAC_SHA2_256_128, PRF_HMAC_SHA2_256 },
+ {AUTH_HMAC_SHA2_384_192, PRF_HMAC_SHA2_384 },
+ {AUTH_HMAC_SHA2_512_256, PRF_HMAC_SHA2_512 },
+ {AUTH_HMAC_MD5_96, PRF_HMAC_MD5 },
+ {AUTH_AES_XCBC_96, PRF_AES128_XCBC },
+ {AUTH_CAMELLIA_XCBC_96, PRF_CAMELLIA128_XCBC },
+ {AUTH_AES_CMAC_96, PRF_AES128_CMAC },
+};
+
+/**
* Checks the proposal read from a string.
*/
static void check_proposal(private_proposal_t *this)
{
enumerator_t *e;
- algorithm_t *alg;
+ entry_t *entry;
+ u_int16_t alg, ks;
bool all_aead = TRUE;
+ int i;
+
+ if (this->protocol == PROTO_IKE)
+ {
+ e = create_enumerator(this, PSEUDO_RANDOM_FUNCTION);
+ if (!e->enumerate(e, &alg, &ks))
+ {
+ /* No explicit PRF found. We assume the same algorithm as used
+ * for integrity checking */
+ e->destroy(e);
+ e = create_enumerator(this, INTEGRITY_ALGORITHM);
+ while (e->enumerate(e, &alg, &ks))
+ {
+ for (i = 0; i < countof(integ_prf_map); i++)
+ {
+ if (alg == integ_prf_map[i].integ)
+ {
+ add_algorithm(this, PSEUDO_RANDOM_FUNCTION,
+ integ_prf_map[i].prf, 0);
+ break;
+ }
+ }
+ }
+ }
+ e->destroy(e);
+ }
- e = this->encryption_algos->create_enumerator(this->encryption_algos);
- while (e->enumerate(e, &alg))
+ e = create_enumerator(this, ENCRYPTION_ALGORITHM);
+ while (e->enumerate(e, &alg, &ks))
{
- if (!encryption_algorithm_is_aead(alg->algorithm))
+ if (!encryption_algorithm_is_aead(alg))
{
all_aead = FALSE;
break;
@@ -536,86 +442,55 @@ static void check_proposal(private_proposal_t *this)
if (all_aead)
{
- /* if all encryption algorithms in the proposal are authenticated encryption
- * algorithms we MUST NOT propose any integrity algorithms */
- while (this->integrity_algos->remove_last(this->integrity_algos,
- (void**)&alg) == SUCCESS)
+ /* 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))
{
- free(alg);
+ if (entry->type == INTEGRITY_ALGORITHM)
+ {
+ array_remove_at(this->transforms, e);
+ }
}
+ e->destroy(e);
}
if (this->protocol == PROTO_AH || this->protocol == PROTO_ESP)
{
- e = this->esns->create_enumerator(this->esns);
- if (!e->enumerate(e, &alg))
+ e = create_enumerator(this, EXTENDED_SEQUENCE_NUMBERS);
+ if (!e->enumerate(e, NULL, NULL))
{ /* ESN not specified, assume not supported */
add_algorithm(this, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0);
}
e->destroy(e);
}
+
+ array_compress(this->transforms);
}
/**
* add a algorithm identified by a string to the proposal.
*/
-static status_t add_string_algo(private_proposal_t *this, chunk_t alg)
+static bool add_string_algo(private_proposal_t *this, const char *alg)
{
- const proposal_token_t *token = proposal_get_token(alg.ptr, alg.len);
+ const proposal_token_t *token;
+ token = lib->proposal->get_token(lib->proposal, alg);
if (token == NULL)
{
- DBG1(DBG_CFG, "algorithm '%.*s' not recognized", alg.len, alg.ptr);
- return FAILED;
+ DBG1(DBG_CFG, "algorithm '%s' not recognized", alg);
+ return FALSE;
}
add_algorithm(this, token->type, token->algorithm, token->keysize);
- if (this->protocol == PROTO_IKE && token->type == INTEGRITY_ALGORITHM)
- {
- pseudo_random_function_t prf;
-
- switch (token->algorithm)
- {
- case AUTH_HMAC_SHA1_96:
- prf = PRF_HMAC_SHA1;
- break;
- case AUTH_HMAC_SHA2_256_128:
- prf = PRF_HMAC_SHA2_256;
- break;
- case AUTH_HMAC_SHA2_384_192:
- prf = PRF_HMAC_SHA2_384;
- break;
- case AUTH_HMAC_SHA2_512_256:
- prf = PRF_HMAC_SHA2_512;
- break;
- case AUTH_HMAC_MD5_96:
- prf = PRF_HMAC_MD5;
- break;
- case AUTH_AES_XCBC_96:
- prf = PRF_AES128_XCBC;
- break;
- case AUTH_CAMELLIA_XCBC_96:
- prf = PRF_CAMELLIA128_XCBC;
- break;
- case AUTH_AES_CMAC_96:
- prf = PRF_AES128_CMAC;
- break;
- default:
- prf = PRF_UNDEFINED;
- }
- if (prf != PRF_UNDEFINED)
- {
- add_algorithm(this, PSEUDO_RANDOM_FUNCTION, prf, 0);
- }
- }
- return SUCCESS;
+ return TRUE;
}
/**
* print all algorithms of a kind to buffer
*/
-static int print_alg(private_proposal_t *this, char **dst, size_t *len,
+static int print_alg(private_proposal_t *this, printf_hook_data_t *data,
u_int kind, void *names, bool *first)
{
enumerator_t *enumerator;
@@ -627,16 +502,16 @@ static int print_alg(private_proposal_t *this, char **dst, size_t *len,
{
if (*first)
{
- written += print_in_hook(*dst, *len, "%N", names, alg);
+ written += print_in_hook(data, "%N", names, alg);
*first = FALSE;
}
else
{
- written += print_in_hook(*dst, *len, "/%N", names, alg);
+ written += print_in_hook(data, "/%N", names, alg);
}
if (size)
{
- written += print_in_hook(*dst, *len, "_%u", size);
+ written += print_in_hook(data, "_%u", size);
}
}
enumerator->destroy(enumerator);
@@ -646,7 +521,7 @@ static int print_alg(private_proposal_t *this, char **dst, size_t *len,
/**
* Described in header.
*/
-int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
+int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
const void *const *args)
{
private_proposal_t *this = *((private_proposal_t**)(args[0]));
@@ -657,7 +532,7 @@ int proposal_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)
@@ -667,28 +542,28 @@ int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
{ /* call recursivly */
if (first)
{
- written += print_in_hook(dst, len, "%P", this);
+ written += print_in_hook(data, "%P", this);
first = FALSE;
}
else
{
- written += print_in_hook(dst, len, ", %P", this);
+ written += print_in_hook(data, ", %P", this);
}
}
enumerator->destroy(enumerator);
return written;
}
- written = print_in_hook(dst, len, "%N:", protocol_id_names, this->protocol);
- written += print_alg(this, &dst, &len, ENCRYPTION_ALGORITHM,
+ written = print_in_hook(data, "%N:", protocol_id_names, this->protocol);
+ written += print_alg(this, data, ENCRYPTION_ALGORITHM,
encryption_algorithm_names, &first);
- written += print_alg(this, &dst, &len, INTEGRITY_ALGORITHM,
+ written += print_alg(this, data, INTEGRITY_ALGORITHM,
integrity_algorithm_names, &first);
- written += print_alg(this, &dst, &len, PSEUDO_RANDOM_FUNCTION,
+ written += print_alg(this, data, PSEUDO_RANDOM_FUNCTION,
pseudo_random_function_names, &first);
- written += print_alg(this, &dst, &len, DIFFIE_HELLMAN_GROUP,
+ written += print_alg(this, data, DIFFIE_HELLMAN_GROUP,
diffie_hellman_group_names, &first);
- written += print_alg(this, &dst, &len, EXTENDED_SEQUENCE_NUMBERS,
+ written += print_alg(this, data, EXTENDED_SEQUENCE_NUMBERS,
extended_sequence_numbers_names, &first);
return written;
}
@@ -696,11 +571,7 @@ int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
METHOD(proposal_t, destroy, void,
private_proposal_t *this)
{
- this->encryption_algos->destroy_function(this->encryption_algos, free);
- this->integrity_algos->destroy_function(this->integrity_algos, free);
- this->prf_algos->destroy_function(this->prf_algos, free);
- this->dh_groups->destroy_function(this->dh_groups, free);
- this->esns->destroy_function(this->esns, free);
+ array_destroy(this->transforms);
free(this);
}
@@ -729,11 +600,7 @@ proposal_t *proposal_create(protocol_id_t protocol, u_int number)
},
.protocol = protocol,
.number = number,
- .encryption_algos = linked_list_create(),
- .integrity_algos = linked_list_create(),
- .prf_algos = linked_list_create(),
- .dh_groups = linked_list_create(),
- .esns = linked_list_create(),
+ .transforms = array_create(sizeof(entry_t), 0),
);
return &this->public;
@@ -760,6 +627,28 @@ static void proposal_add_supported_ike(private_proposal_t *this)
case ENCR_AES_CTR:
case ENCR_CAMELLIA_CBC:
case ENCR_CAMELLIA_CTR:
+ /* we assume that we support all AES/Camellia sizes */
+ add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 128);
+ add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
+ add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
+ break;
+ case ENCR_3DES:
+ add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
+ break;
+ case ENCR_DES:
+ /* no, thanks */
+ break;
+ default:
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = lib->crypto->create_aead_enumerator(lib->crypto);
+ while (enumerator->enumerate(enumerator, &encryption, &plugin_name))
+ {
+ switch (encryption)
+ {
case ENCR_AES_CCM_ICV8:
case ENCR_AES_CCM_ICV12:
case ENCR_AES_CCM_ICV16:
@@ -774,12 +663,6 @@ static void proposal_add_supported_ike(private_proposal_t *this)
add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 192);
add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 256);
break;
- case ENCR_3DES:
- add_algorithm(this, ENCRYPTION_ALGORITHM, encryption, 0);
- break;
- case ENCR_DES:
- /* no, thanks */
- break;
default:
break;
}
@@ -840,6 +723,7 @@ static void proposal_add_supported_ike(private_proposal_t *this)
case MODP_1024_BIT:
case MODP_1536_BIT:
case MODP_2048_BIT:
+ case MODP_3072_BIT:
case MODP_4096_BIT:
case MODP_8192_BIT:
case ECP_256_BIT:
@@ -899,28 +783,27 @@ proposal_t *proposal_create_default(protocol_id_t protocol)
*/
proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs)
{
- private_proposal_t *this = (private_proposal_t*)proposal_create(protocol, 0);
- chunk_t string = {(void*)algs, strlen(algs)};
- chunk_t alg;
- status_t status = SUCCESS;
+ private_proposal_t *this;
+ enumerator_t *enumerator;
+ bool failed = TRUE;
+ char *alg;
- eat_whitespace(&string);
- if (string.len < 1)
- {
- destroy(this);
- return NULL;
- }
+ this = (private_proposal_t*)proposal_create(protocol, 0);
/* get all tokens, separated by '-' */
- while (extract_token(&alg, '-', &string))
+ enumerator = enumerator_create_token(algs, "-", " ");
+ while (enumerator->enumerate(enumerator, &alg))
{
- status |= add_string_algo(this, alg);
- }
- if (string.len)
- {
- status |= add_string_algo(this, string);
+ if (!add_string_algo(this, alg))
+ {
+ failed = TRUE;
+ break;
+ }
+ failed = FALSE;
}
- if (status != SUCCESS)
+ enumerator->destroy(enumerator);
+
+ if (failed)
{
destroy(this);
return NULL;
diff --git a/src/libcharon/config/proposal.h b/src/libcharon/config/proposal.h
index 8f54d7e6e..7733143a8 100644
--- a/src/libcharon/config/proposal.h
+++ b/src/libcharon/config/proposal.h
@@ -27,8 +27,8 @@ typedef struct proposal_t proposal_t;
#include <library.h>
#include <utils/identification.h>
-#include <utils/linked_list.h>
-#include <utils/host.h>
+#include <collections/linked_list.h>
+#include <networking/host.h>
#include <crypto/transform.h>
#include <crypto/crypters/crypter.h>
#include <crypto/signers/signer.h>
@@ -43,6 +43,7 @@ enum protocol_id_t {
PROTO_IKE = 1,
PROTO_AH = 2,
PROTO_ESP = 3,
+ PROTO_IPCOMP = 4, /* IKEv1 only */
};
/**
@@ -110,8 +111,10 @@ struct proposal_t {
/**
* Strip DH groups from proposal to use it without PFS.
+ *
+ * @param keep group to keep (MODP_NONE to remove all)
*/
- void (*strip_dh)(proposal_t *this);
+ void (*strip_dh)(proposal_t *this, diffie_hellman_group_t keep);
/**
* Compare two proposal, and select a matching subset.
@@ -215,7 +218,7 @@ proposal_t *proposal_create_from_string(protocol_id_t protocol, const char *algs
* With the #-specifier, arguments are:
* linked_list_t *list containing proposal_t*
*/
-int proposal_printf_hook(char *dst, size_t len, printf_hook_spec_t *spec,
+int proposal_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
const void *const *args);
#endif /** PROPOSAL_H_ @}*/