summaryrefslogtreecommitdiff
path: root/src/charon/sa
diff options
context:
space:
mode:
authorRene Mayrhofer <rene@mayrhofer.eu.org>2007-06-03 17:36:35 +0000
committerRene Mayrhofer <rene@mayrhofer.eu.org>2007-06-03 17:36:35 +0000
commit08ee5250bd9c43fda5f24d10b791ca2c4c17fcee (patch)
treed4e2fc7144e288d624555a38955593e1ee066531 /src/charon/sa
parentb0d8ed94fe9e74afb49fdf5f11e4add29879c65c (diff)
downloadvyos-strongswan-08ee5250bd9c43fda5f24d10b791ca2c4c17fcee.tar.gz
vyos-strongswan-08ee5250bd9c43fda5f24d10b791ca2c4c17fcee.zip
[svn-upgrade] Integrating new upstream version, strongswan (4.1.3)
Diffstat (limited to 'src/charon/sa')
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.c35
-rw-r--r--src/charon/sa/authenticators/eap/eap_sim.c104
-rw-r--r--src/charon/sa/authenticators/eap_authenticator.c58
-rw-r--r--src/charon/sa/authenticators/psk_authenticator.c10
-rw-r--r--src/charon/sa/authenticators/rsa_authenticator.c37
-rw-r--r--src/charon/sa/child_sa.c231
-rw-r--r--src/charon/sa/child_sa.h44
-rw-r--r--src/charon/sa/ike_sa.c713
-rw-r--r--src/charon/sa/ike_sa.h124
-rw-r--r--src/charon/sa/ike_sa_id.c28
-rw-r--r--src/charon/sa/ike_sa_manager.c24
-rw-r--r--src/charon/sa/task_manager.c22
-rw-r--r--src/charon/sa/task_manager.h40
-rw-r--r--src/charon/sa/tasks/child_create.c259
-rw-r--r--src/charon/sa/tasks/child_create.h6
-rw-r--r--src/charon/sa/tasks/child_delete.c22
-rw-r--r--src/charon/sa/tasks/child_rekey.c19
-rw-r--r--src/charon/sa/tasks/ike_auth.c66
-rw-r--r--src/charon/sa/tasks/ike_cert.c50
-rw-r--r--src/charon/sa/tasks/ike_config.c45
-rw-r--r--src/charon/sa/tasks/ike_config.h5
-rw-r--r--src/charon/sa/tasks/ike_delete.c3
-rw-r--r--src/charon/sa/tasks/ike_init.c137
-rw-r--r--src/charon/sa/tasks/ike_rekey.c77
24 files changed, 1174 insertions, 985 deletions
diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c
index a4d8abb58..e4a58f0a3 100644
--- a/src/charon/sa/authenticators/eap/eap_method.c
+++ b/src/charon/sa/authenticators/eap/eap_method.c
@@ -85,7 +85,7 @@ void eap_method_unload()
while (modules->remove_last(modules, (void**)&entry) == SUCCESS)
{
- DBG2(DBG_CFG, "unloaded module for %s", eap_type_names, entry->type);
+ DBG2(DBG_CFG, "unloaded module for %N", eap_type_names, entry->type);
dlclose(entry->handle);
free(entry);
}
@@ -100,27 +100,10 @@ void eap_method_unload()
void eap_method_load(char *directory)
{
struct dirent* entry;
- struct stat stb;
DIR* dir;
eap_method_unload();
modules = linked_list_create();
-
- if (stat(directory, &stb) == -1 || !(stb.st_mode & S_IFDIR))
- {
- DBG1(DBG_CFG, "error opening EAP modules directory %s", directory);
- return;
- }
- if (stb.st_uid != 0)
- {
- DBG1(DBG_CFG, "EAP modules directory %s not owned by root, skipped", directory);
- return;
- }
- if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP)
- {
- DBG1(DBG_CFG, "EAP modules directory %s writable by others, skipped", directory);
- return;
- }
dir = opendir(directory);
if (dir == NULL)
@@ -141,12 +124,6 @@ void eap_method_load(char *directory)
snprintf(file, sizeof(file), "%s/%s", directory, entry->d_name);
- if (stat(file, &stb) == -1 || !(stb.st_mode & S_IFREG))
- {
- DBG2(DBG_CFG, " skipping %s, doesn't look like a file",
- entry->d_name);
- continue;
- }
ending = entry->d_name + strlen(entry->d_name) - 3;
if (ending <= entry->d_name || !streq(ending, ".so"))
{
@@ -155,16 +132,6 @@ void eap_method_load(char *directory)
entry->d_name);
continue;
}
- if (stb.st_uid != 0)
- {
- DBG1(DBG_CFG, " skipping %s, file is not owned by root", entry->d_name);
- return;
- }
- if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP)
- {
- DBG1(DBG_CFG, " skipping %s, file is writeable by others", entry->d_name);
- continue;
- }
/* try to load the library */
module.handle = dlopen(file, RTLD_LAZY);
diff --git a/src/charon/sa/authenticators/eap/eap_sim.c b/src/charon/sa/authenticators/eap/eap_sim.c
index 3dc59fb6b..38d7f2534 100644
--- a/src/charon/sa/authenticators/eap/eap_sim.c
+++ b/src/charon/sa/authenticators/eap/eap_sim.c
@@ -398,6 +398,30 @@ static status_t process_start(private_eap_sim_t *this, eap_payload_t *in,
/* only include AT_IDENTITY if requested */
include_id = AT_IDENTITY;
break;
+ case AT_NOTIFICATION:
+ {
+ u_int16_t code = 0;
+ if (data.len == 2)
+ {
+ code = ntohs(*(u_int16_t*)data.ptr);
+ }
+ if (code <= 32767) /* no success bit */
+ {
+ DBG1(DBG_IKE, "received %N error %d",
+ sim_attribute_names, attribute, code);
+ *out = build_payload(this,
+ in->get_identifier(in), SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_general,
+ AT_END);
+ return NEED_MORE;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received %N code %d",
+ sim_attribute_names, attribute, code);
+ }
+ break;
+ }
default:
DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
sim_attribute_names, attribute);
@@ -456,6 +480,30 @@ static status_t process_challenge(private_eap_sim_t *this, eap_payload_t *in,
memset(data.ptr, 0, data.len);
break;
}
+ case AT_NOTIFICATION:
+ {
+ u_int16_t code = 0;
+ if (data.len == 2)
+ {
+ code = ntohs(*(u_int16_t*)data.ptr);
+ }
+ if (code <= 32767) /* no success bit */
+ {
+ DBG1(DBG_IKE, "received %N error %d",
+ sim_attribute_names, attribute, code);
+ *out = build_payload(this,
+ in->get_identifier(in), SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_general,
+ AT_END);
+ return NEED_MORE;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received %N code %d",
+ sim_attribute_names, attribute, code);
+ }
+ break;
+ }
default:
DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
sim_attribute_names, attribute);
@@ -472,7 +520,7 @@ static status_t process_challenge(private_eap_sim_t *this, eap_payload_t *in,
*out = build_payload(this, identifier, SIM_CLIENT_ERROR,
AT_CLIENT_ERROR_CODE, client_error_insufficient,
AT_END);
- return FAILED;
+ return NEED_MORE;
}
if (mac.len != MAC_LEN)
{
@@ -557,6 +605,58 @@ static status_t process_challenge(private_eap_sim_t *this, eap_payload_t *in,
}
/**
+ * process an EAP-SIM/Request/Notification message
+ */
+static status_t process_notification(private_eap_sim_t *this, eap_payload_t *in,
+ eap_payload_t **out)
+{
+ chunk_t message, data;
+ sim_attribute_t attribute;
+
+ message = in->get_data(in);
+ read_header(&message);
+
+ while ((attribute = read_attribute(&message, &data)) != AT_END)
+ {
+ switch (attribute)
+ {
+ case AT_NOTIFICATION:
+ {
+ u_int16_t code = 0;
+ if (data.len == 2)
+ {
+ code = ntohs(*(u_int16_t*)data.ptr);
+ }
+ if (code <= 32767) /* no success bit */
+ {
+ DBG1(DBG_IKE, "received %N error %d",
+ sim_attribute_names, attribute, code);
+ *out = build_payload(this,
+ in->get_identifier(in), SIM_CLIENT_ERROR,
+ AT_CLIENT_ERROR_CODE, client_error_general,
+ AT_END);
+ return NEED_MORE;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "received %N code %d",
+ sim_attribute_names, attribute, code);
+ }
+ break;
+ }
+ default:
+ DBG1(DBG_IKE, "ignoring EAP_SIM attribute %N",
+ sim_attribute_names, attribute);
+ break;
+ }
+ }
+ /* reply with empty notification */
+ *out = build_payload(this, in->get_identifier(in), SIM_NOTIFICATION, AT_END);
+ return NEED_MORE;
+}
+
+
+/**
* Implementation of eap_method_t.process for the peer
*/
static status_t process(private_eap_sim_t *this,
@@ -574,6 +674,8 @@ static status_t process(private_eap_sim_t *this,
return process_start(this, in, out);
case SIM_CHALLENGE:
return process_challenge(this, in, out);
+ case SIM_NOTIFICATION:
+ return process_notification(this, in, out);
default:
DBG1(DBG_IKE, "unable to process EAP_SIM subtype %N",
sim_subtype_names, type);
diff --git a/src/charon/sa/authenticators/eap_authenticator.c b/src/charon/sa/authenticators/eap_authenticator.c
index 6c8ca8d8f..6e2f73a43 100644
--- a/src/charon/sa/authenticators/eap_authenticator.c
+++ b/src/charon/sa/authenticators/eap_authenticator.c
@@ -25,7 +25,7 @@
#include "eap_authenticator.h"
#include <daemon.h>
-#include <config/policies/policy.h>
+#include <config/peer_cfg.h>
#include <sa/authenticators/eap/eap_method.h>
typedef struct private_eap_authenticator_t private_eap_authenticator_t;
@@ -61,21 +61,31 @@ struct private_eap_authenticator_t {
chunk_t msk;
};
+/**
+ * reuse shared key signature function from PSK authenticator
+ */
extern chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
- chunk_t secret, identification_t *id,
- prf_t *prf_skp, prf_t *prf);
-
+ chunk_t secret, identification_t *id,
+ chunk_t skp, prf_t *prf);
/**
* Implementation of authenticator_t.verify.
*/
static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init,
chunk_t my_nonce, auth_payload_t *auth_payload)
{
- chunk_t auth_data, recv_auth_data;
+ chunk_t auth_data, recv_auth_data, secret;
identification_t *other_id = this->ike_sa->get_other_id(this->ike_sa);
- auth_data = build_shared_key_signature(ike_sa_init, my_nonce, this->msk,
- other_id, this->ike_sa->get_auth_verify(this->ike_sa),
+ if (this->msk.len)
+ { /* use MSK if EAP method established one... */
+ secret = this->msk;
+ }
+ else
+ { /* ... or use SKp if not */
+ secret = this->ike_sa->get_skp_verify(this->ike_sa);
+ }
+ auth_data = build_shared_key_signature(ike_sa_init, my_nonce, secret,
+ other_id, this->ike_sa->get_skp_verify(this->ike_sa),
this->ike_sa->get_prf(this->ike_sa));
recv_auth_data = auth_payload->get_data(auth_payload);
@@ -98,14 +108,22 @@ static status_t verify(private_eap_authenticator_t *this, chunk_t ike_sa_init,
static status_t build(private_eap_authenticator_t *this, chunk_t ike_sa_init,
chunk_t other_nonce, auth_payload_t **auth_payload)
{
- chunk_t auth_data;
+ chunk_t auth_data, secret;
identification_t *my_id = this->ike_sa->get_my_id(this->ike_sa);
DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
my_id, auth_method_names, AUTH_EAP);
-
- auth_data = build_shared_key_signature(ike_sa_init, other_nonce, this->msk,
- my_id, this->ike_sa->get_auth_build(this->ike_sa),
+
+ if (this->msk.len)
+ { /* use MSK if EAP method established one... */
+ secret = this->msk;
+ }
+ else
+ { /* ... or use SKp if not */
+ secret = this->ike_sa->get_skp_build(this->ike_sa);
+ }
+ auth_data = build_shared_key_signature(ike_sa_init, other_nonce, secret,
+ my_id, this->ike_sa->get_skp_build(this->ike_sa),
this->ike_sa->get_prf(this->ike_sa));
*auth_payload = auth_payload_create();
@@ -233,13 +251,14 @@ static status_t process_server(private_eap_authenticator_t *this,
DBG1(DBG_IKE, "EAP method %N succeded, MSK established",
eap_type_names, this->method->get_type(this->method));
this->msk = chunk_clone(this->msk);
- *out = eap_payload_create_code(EAP_SUCCESS);
- return SUCCESS;
}
- DBG1(DBG_IKE, "EAP method %N succeded, but no MSK established",
- eap_type_names, this->method->get_type(this->method));
- *out = eap_payload_create_code(EAP_FAILURE);
- return FAILED;
+ else
+ {
+ DBG1(DBG_IKE, "EAP method %N succeded, no MSK established",
+ eap_type_names, this->method->get_type(this->method));
+ }
+ *out = eap_payload_create_code(EAP_SUCCESS);
+ return SUCCESS;
case FAILED:
default:
DBG1(DBG_IKE, "EAP method %N failed for peer %D",
@@ -290,11 +309,8 @@ static status_t process(private_eap_authenticator_t *this, eap_payload_t *in,
if (this->method->get_msk(this->method, &this->msk) == SUCCESS)
{
this->msk = chunk_clone(this->msk);
- return SUCCESS;
}
- DBG1(DBG_IKE, "EAP method %N has no MSK established",
- eap_type_names, this->method->get_type(this->method));
- return FAILED;
+ return SUCCESS;
}
case EAP_FAILURE:
default:
diff --git a/src/charon/sa/authenticators/psk_authenticator.c b/src/charon/sa/authenticators/psk_authenticator.c
index 43aec0971..37465d029 100644
--- a/src/charon/sa/authenticators/psk_authenticator.c
+++ b/src/charon/sa/authenticators/psk_authenticator.c
@@ -25,7 +25,6 @@
#include "psk_authenticator.h"
-#include <config/policies/policy.h>
#include <daemon.h>
/**
@@ -78,11 +77,12 @@ chunk_t build_tbs_octets(chunk_t ike_sa_init, chunk_t nonce,
*/
chunk_t build_shared_key_signature(chunk_t ike_sa_init, chunk_t nonce,
chunk_t secret, identification_t *id,
- prf_t *prf_skp, prf_t *prf)
+ chunk_t skp, prf_t *prf)
{
chunk_t key_pad, key, auth_data, octets;
- octets = build_tbs_octets(ike_sa_init, nonce, id, prf_skp);
+ prf->set_key(prf, skp);
+ octets = build_tbs_octets(ike_sa_init, nonce, id, prf);
/* AUTH = prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>) */
key_pad.ptr = IKEV2_KEY_PAD;
key_pad.len = IKEV2_KEY_PAD_LENGTH;
@@ -122,7 +122,7 @@ static status_t verify(private_psk_authenticator_t *this, chunk_t ike_sa_init,
}
auth_data = build_shared_key_signature(ike_sa_init, my_nonce, shared_key,
- other_id, this->ike_sa->get_auth_verify(this->ike_sa),
+ other_id, this->ike_sa->get_skp_verify(this->ike_sa),
this->ike_sa->get_prf(this->ike_sa));
chunk_free(&shared_key);
@@ -165,7 +165,7 @@ static status_t build(private_psk_authenticator_t *this, chunk_t ike_sa_init,
}
auth_data = build_shared_key_signature(ike_sa_init, other_nonce, shared_key,
- my_id, this->ike_sa->get_auth_build(this->ike_sa),
+ my_id, this->ike_sa->get_skp_build(this->ike_sa),
this->ike_sa->get_prf(this->ike_sa));
DBG2(DBG_IKE, "successfully created shared key MAC");
chunk_free(&shared_key);
diff --git a/src/charon/sa/authenticators/rsa_authenticator.c b/src/charon/sa/authenticators/rsa_authenticator.c
index dfa01e332..e5c5cd60e 100644
--- a/src/charon/sa/authenticators/rsa_authenticator.c
+++ b/src/charon/sa/authenticators/rsa_authenticator.c
@@ -25,7 +25,6 @@
#include "rsa_authenticator.h"
-#include <config/policies/policy.h>
#include <daemon.h>
@@ -61,8 +60,9 @@ static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
{
status_t status;
chunk_t auth_data, octets;
- rsa_public_key_t *public_key;
identification_t *other_id;
+ ca_info_t *issuer;
+ prf_t *prf;
other_id = this->ike_sa->get_other_id(this->ike_sa);
@@ -71,27 +71,20 @@ static status_t verify(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
return INVALID_ARG;
}
auth_data = auth_payload->get_data(auth_payload);
- public_key = charon->credentials->get_trusted_public_key(charon->credentials,
- other_id);
- if (public_key == NULL)
- {
- DBG1(DBG_IKE, "no RSA public key found for '%D'", other_id);
- return NOT_FOUND;
- }
- octets = build_tbs_octets(ike_sa_init, my_nonce, other_id,
- this->ike_sa->get_auth_verify(this->ike_sa));
- status = public_key->verify_emsa_pkcs1_signature(public_key, octets, auth_data);
+ prf = this->ike_sa->get_prf(this->ike_sa);
+ prf->set_key(prf, this->ike_sa->get_skp_verify(this->ike_sa));
+ octets = build_tbs_octets(ike_sa_init, my_nonce, other_id, prf);
+ status = charon->credentials->verify_signature(charon->credentials,
+ octets, auth_data, other_id, &issuer);
chunk_free(&octets);
- if (status != SUCCESS)
+ if (status == SUCCESS)
{
- DBG1(DBG_IKE, "RSA signature verification failed");
- return status;
+ this->ike_sa->set_other_ca(this->ike_sa, issuer);
+ DBG1(DBG_IKE, "authentication of '%D' with %N successful",
+ other_id, auth_method_names, AUTH_RSA);
}
-
- DBG1(DBG_IKE, "authentication of '%D' with %N successful",
- other_id, auth_method_names, AUTH_RSA);
- return SUCCESS;
+ return status;
}
/**
@@ -107,6 +100,7 @@ static status_t build(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
rsa_public_key_t *my_pubkey;
rsa_private_key_t *my_key;
identification_t *my_id;
+ prf_t *prf;
my_id = this->ike_sa->get_my_id(this->ike_sa);
DBG1(DBG_IKE, "authentication of '%D' (myself) with %N",
@@ -131,8 +125,9 @@ static status_t build(private_rsa_authenticator_t *this, chunk_t ike_sa_init,
}
DBG2(DBG_IKE, "matching RSA private key found");
- octets = build_tbs_octets(ike_sa_init, other_nonce, my_id,
- this->ike_sa->get_auth_build(this->ike_sa));
+ prf = this->ike_sa->get_prf(this->ike_sa);
+ prf->set_key(prf, this->ike_sa->get_skp_build(this->ike_sa));
+ octets = build_tbs_octets(ike_sa_init, other_nonce, my_id, prf);
status = my_key->build_emsa_pkcs1_signature(my_key, HASH_SHA1, octets, &auth_data);
chunk_free(&octets);
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c
index 19131389d..1e7b6cb2c 100644
--- a/src/charon/sa/child_sa.c
+++ b/src/charon/sa/child_sa.c
@@ -27,7 +27,6 @@
#include <stdio.h>
#include <string.h>
-#include <printf.h>
#include <daemon.h>
@@ -154,9 +153,9 @@ struct private_child_sa_t {
host_t *virtual_ip;
/**
- * policy used to create this child
+ * config used to create this child
*/
- policy_t *policy;
+ child_cfg_t *config;
};
/**
@@ -164,7 +163,7 @@ struct private_child_sa_t {
*/
static char *get_name(private_child_sa_t *this)
{
- return this->policy->get_name(this->policy);;
+ return this->config->get_name(this->config);
}
/**
@@ -204,11 +203,57 @@ static child_sa_state_t get_state(private_child_sa_t *this)
}
/**
- * Implements child_sa_t.get_policy
+ * Implements child_sa_t.get_config
*/
-static policy_t* get_policy(private_child_sa_t *this)
+static child_cfg_t* get_config(private_child_sa_t *this)
{
- return this->policy;
+ return this->config;
+}
+
+/**
+ * Implementation of child_sa_t.get_stats.
+ */
+static void get_stats(private_child_sa_t *this, mode_t *mode,
+ encryption_algorithm_t *encr_algo, size_t *encr_len,
+ integrity_algorithm_t *int_algo, size_t *int_len,
+ u_int32_t *rekey, u_int32_t *use_in, u_int32_t *use_out,
+ u_int32_t *use_fwd)
+{
+ sa_policy_t *policy;
+ iterator_t *iterator;
+ u_int32_t in = 0, out = 0, fwd = 0, time;
+
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->iterate(iterator, (void**)&policy))
+ {
+
+ if (charon->kernel_interface->query_policy(charon->kernel_interface,
+ policy->other_ts, policy->my_ts, POLICY_IN, &time) == SUCCESS)
+ {
+ in = max(in, time);
+ }
+ if (charon->kernel_interface->query_policy(charon->kernel_interface,
+ policy->my_ts, policy->other_ts, POLICY_OUT, &time) == SUCCESS)
+ {
+ out = max(out, time);
+ }
+ if (charon->kernel_interface->query_policy(charon->kernel_interface,
+ policy->other_ts, policy->my_ts, POLICY_FWD, &time) == SUCCESS)
+ {
+ fwd = max(fwd, time);
+ }
+ }
+ iterator->destroy(iterator);
+
+ *mode = this->mode;
+ *encr_algo = this->encryption.algorithm;
+ *encr_len = this->encryption.key_size;
+ *int_algo = this->integrity.algorithm;
+ *int_len = this->integrity.key_size;
+ *rekey = this->rekey_time;
+ *use_in = in;
+ *use_out = out;
+ *use_fwd = fwd;
}
/**
@@ -220,7 +265,7 @@ static void updown(private_child_sa_t *this, bool up)
iterator_t *iterator;
char *script;
- script = this->policy->get_updown(this->policy);
+ script = this->config->get_updown(this->config);
if (script == NULL)
{
@@ -300,7 +345,7 @@ static void updown(private_child_sa_t *this, bool up)
policy->my_ts->is_host(policy->my_ts,
this->me.addr) ? "-host" : "-client",
this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6",
- this->policy->get_name(this->policy),
+ this->config->get_name(this->config),
ifname ? ifname : "(unknown)",
this->reqid,
this->me.addr,
@@ -316,7 +361,7 @@ static void updown(private_child_sa_t *this, bool up)
policy->other_ts->get_from_port(policy->other_ts),
policy->other_ts->get_protocol(policy->other_ts),
virtual_ip,
- this->policy->get_hostaccess(this->policy) ?
+ this->config->get_hostaccess(this->config) ?
"PLUTO_HOST_ACCESS='1' " : "",
script);
free(ifname);
@@ -528,8 +573,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
natt = NULL;
}
- soft = this->policy->get_soft_lifetime(this->policy);
- hard = this->policy->get_hard_lifetime(this->policy);
+ soft = this->config->get_lifetime(this->config, TRUE);
+ hard = this->config->get_lifetime(this->config, FALSE);
/* send SA down to the kernel */
DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
@@ -542,7 +587,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
this->encryption = *enc_algo;
this->integrity = *int_algo;
this->install_time = time(NULL);
- this->rekey_time = soft;
+ this->rekey_time = this->install_time + soft;
return status;
}
@@ -628,7 +673,7 @@ static status_t add_policies(private_child_sa_t *this,
if (my_ts->get_type(my_ts) != other_ts->get_type(other_ts))
{
DBG2(DBG_CHD,
- "CHILD_SA policy uses two different IP families, ignored");
+ "CHILD_SA policy uses two different IP families - ignored");
continue;
}
@@ -637,7 +682,7 @@ static status_t add_policies(private_child_sa_t *this,
my_ts->get_protocol(my_ts) && other_ts->get_protocol(other_ts))
{
DBG2(DBG_CHD,
- "CHILD_SA policy uses two different protocols, ignored");
+ "CHILD_SA policy uses two different protocols - ignored");
continue;
}
@@ -665,10 +710,10 @@ static status_t add_policies(private_child_sa_t *this,
policy = malloc_thing(sa_policy_t);
policy->my_ts = my_ts->clone(my_ts);
policy->other_ts = other_ts->clone(other_ts);
- this->policies->insert_last(this->policies, (void*)policy);
+ this->policies->insert_last(this->policies, policy);
/* add to separate list to query them via get_*_traffic_selectors() */
- this->my_ts->insert_last(this->my_ts, (void*)policy->my_ts);
- this->other_ts->insert_last(this->other_ts, (void*)policy->other_ts);
+ this->my_ts->insert_last(this->my_ts, policy->my_ts);
+ this->other_ts->insert_last(this->other_ts, policy->other_ts);
}
}
my_iter->destroy(my_iter);
@@ -685,18 +730,14 @@ static status_t add_policies(private_child_sa_t *this,
}
/**
- * Implementation of child_sa_t.get_my_traffic_selectors.
+ * Implementation of child_sa_t.get_traffic_selectors.
*/
-static linked_list_t *get_my_traffic_selectors(private_child_sa_t *this)
-{
- return this->my_ts;
-}
-
-/**
- * Implementation of child_sa_t.get_my_traffic_selectors.
- */
-static linked_list_t *get_other_traffic_selectors(private_child_sa_t *this)
+static linked_list_t *get_traffic_selectors(private_child_sa_t *this, bool local)
{
+ if (local)
+ {
+ return this->my_ts;
+ }
return this->other_ts;
}
@@ -741,126 +782,6 @@ static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use
}
/**
- * output handler in printf()
- */
-static int print(FILE *stream, const struct printf_info *info,
- const void *const *args)
-{
- private_child_sa_t *this = *((private_child_sa_t**)(args[0]));
- iterator_t *iterator;
- sa_policy_t *policy;
- u_int32_t now, rekeying;
- u_int32_t use, use_in, use_fwd;
- status_t status;
- size_t written = 0;
-
- if (this == NULL)
- {
- return fprintf(stream, "(null)");
- }
-
- now = time(NULL);
-
- written += fprintf(stream, "%12s{%d}: %N, %N",
- this->policy->get_name(this->policy), this->reqid,
- child_sa_state_names, this->state,
- mode_names, this->mode);
-
- if (this->state == CHILD_INSTALLED)
- {
- written += fprintf(stream, ", %N SPIs: 0x%0x_i 0x%0x_o",
- protocol_id_names, this->protocol,
- htonl(this->me.spi), htonl(this->other.spi));
-
- if (info->alt)
- {
- written += fprintf(stream, "\n%12s{%d}: ",
- this->policy->get_name(this->policy),
- this->reqid);
-
- if (this->protocol == PROTO_ESP)
- {
- written += fprintf(stream, "%N", encryption_algorithm_names,
- this->encryption.algorithm);
-
- if (this->encryption.key_size)
- {
- written += fprintf(stream, "-%d", this->encryption.key_size);
- }
- written += fprintf(stream, "/");
- }
-
- written += fprintf(stream, "%N", integrity_algorithm_names,
- this->integrity.algorithm);
- if (this->integrity.key_size)
- {
- written += fprintf(stream, "-%d", this->integrity.key_size);
- }
- written += fprintf(stream, ", rekeying ");
-
- /* calculate rekey times */
- if (this->rekey_time)
- {
- rekeying = this->install_time + this->rekey_time - now;
- written += fprintf(stream, "in %ds", rekeying);
- }
- else
- {
- written += fprintf(stream, "disabled");
- }
- }
- }
- iterator = this->policies->create_iterator(this->policies, TRUE);
- while (iterator->iterate(iterator, (void**)&policy))
- {
- written += fprintf(stream, "\n%12s{%d}: %R===%R, last use: ",
- this->policy->get_name(this->policy), this->reqid,
- policy->my_ts, policy->other_ts);
-
- /* query time of last policy use */
-
- /* inbound: POLICY_IN or POLICY_FWD */
- status = charon->kernel_interface->query_policy(charon->kernel_interface,
- policy->other_ts, policy->my_ts, POLICY_IN, &use_in);
- use_in = (status == SUCCESS)? use_in : 0;
- status = charon->kernel_interface->query_policy(charon->kernel_interface,
- policy->other_ts, policy->my_ts, POLICY_FWD, &use_fwd);
- use_fwd = (status == SUCCESS)? use_fwd : 0;
- use = max(use_in, use_fwd);
- if (use)
- {
- written += fprintf(stream, "%ds_i ", now - use);
- }
- else
- {
- written += fprintf(stream, "no_i ");
- }
-
- /* outbound: POLICY_OUT */
- status = charon->kernel_interface->query_policy(charon->kernel_interface,
- policy->my_ts, policy->other_ts, POLICY_OUT, &use);
- if (status == SUCCESS && use)
- {
- written += fprintf(stream, "%ds_o ", now - use);
- }
- else
- {
- written += fprintf(stream, "no_o ");
- }
- }
- iterator->destroy(iterator);
- return written;
-}
-
-/**
- * register printf() handlers
- */
-static void __attribute__ ((constructor))print_register()
-{
- register_printf_function(PRINTF_CHILD_SA, print, arginfo_ptr);
-}
-
-/**
* Update the host adress/port of a SA
*/
static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other,
@@ -1066,7 +987,7 @@ static void destroy(private_child_sa_t *this)
this->other.addr->destroy(this->other.addr);
this->me.id->destroy(this->me.id);
this->other.id->destroy(this->other.id);
- this->policy->destroy(this->policy);
+ this->config->destroy(this->config);
DESTROY_IF(this->virtual_ip);
free(this);
}
@@ -1076,7 +997,7 @@ static void destroy(private_child_sa_t *this)
*/
child_sa_t * child_sa_create(host_t *me, host_t* other,
identification_t *my_id, identification_t *other_id,
- policy_t *policy, u_int32_t rekey, bool use_natt)
+ child_cfg_t *config, u_int32_t rekey, bool use_natt)
{
static u_int32_t reqid = 0;
private_child_sa_t *this = malloc_thing(private_child_sa_t);
@@ -1086,17 +1007,17 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->public.get_reqid = (u_int32_t(*)(child_sa_t*))get_reqid;
this->public.get_spi = (u_int32_t(*)(child_sa_t*, bool))get_spi;
this->public.get_protocol = (protocol_id_t(*)(child_sa_t*))get_protocol;
+ this->public.get_stats = (void(*)(child_sa_t*, mode_t*,encryption_algorithm_t*,size_t*,integrity_algorithm_t*,size_t*,u_int32_t*,u_int32_t*,u_int32_t*,u_int32_t*))get_stats;
this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
this->public.add = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))add;
this->public.update = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))update;
this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts;
this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies;
- this->public.get_my_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_my_traffic_selectors;
- this->public.get_other_traffic_selectors = (linked_list_t*(*)(child_sa_t*))get_other_traffic_selectors;
+ this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors;
this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
this->public.set_state = (void(*)(child_sa_t*,child_sa_state_t))set_state;
this->public.get_state = (child_sa_state_t(*)(child_sa_t*))get_state;
- this->public.get_policy = (policy_t*(*)(child_sa_t*))get_policy;
+ this->public.get_config = (child_cfg_t*(*)(child_sa_t*))get_config;
this->public.set_virtual_ip = (void(*)(child_sa_t*,host_t*))set_virtual_ip;
this->public.destroy = (void(*)(child_sa_t*))destroy;
@@ -1123,8 +1044,8 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->protocol = PROTO_NONE;
this->mode = MODE_TUNNEL;
this->virtual_ip = NULL;
- this->policy = policy;
- policy->get_ref(policy);
+ this->config = config;
+ config->get_ref(config);
return &this->public;
}
diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h
index 216e56659..cf5f3e7d7 100644
--- a/src/charon/sa/child_sa.h
+++ b/src/charon/sa/child_sa.h
@@ -32,7 +32,7 @@ typedef struct child_sa_t child_sa_t;
#include <crypto/prf_plus.h>
#include <encoding/payloads/proposal_substructure.h>
#include <config/proposal.h>
-#include <config/policies/policy.h>
+#include <config/child_cfg.h>
/**
* Where we should start with reqid enumeration
@@ -101,7 +101,7 @@ extern enum_name_t *child_sa_state_names;
struct child_sa_t {
/**
- * @brief Get the name of the policy this CHILD_SA uses.
+ * @brief Get the name of the config this CHILD_SA uses.
*
* @param this calling object
* @return name
@@ -141,6 +141,25 @@ struct child_sa_t {
protocol_id_t (*get_protocol) (child_sa_t *this);
/**
+ * @brief Get info and statistics about this CHILD_SA.
+ *
+ * @param mode mode this IKE_SA uses
+ * @param encr_algo encryption algorithm used by this CHILD_SA.
+ * @param encr_len key length of the algorithm, if any
+ * @param int_algo integrity algorithm used by this CHILD_SA
+ * @param int_len key length of the algorithm, if any
+ * @param rekey time when rekeying is scheduled
+ * @param use_in time when last traffic was seen coming in
+ * @param use_out time when last traffic was seen going out
+ * @param use_fwd time when last traffic was getting forwarded
+ */
+ void (*get_stats)(child_sa_t *this, mode_t *mode,
+ encryption_algorithm_t *encr, size_t *encr_len,
+ integrity_algorithm_t *int_algo, size_t *int_len,
+ u_int32_t *rekey, u_int32_t *use_in, u_int32_t *use_out,
+ u_int32_t *use_fwd);
+
+ /**
* @brief Allocate SPIs for given proposals.
*
* Since the kernel manages SPIs for us, we need
@@ -214,17 +233,10 @@ struct child_sa_t {
* @brief Get the traffic selectors of added policies of local host.
*
* @param this calling object
+ * @param local TRUE for own traffic selectors, FALSE for remote
* @return list of traffic selectors
*/
- linked_list_t* (*get_my_traffic_selectors) (child_sa_t *this);
-
- /**
- * @brief Get the traffic selectors of added policies of remote host.
- *
- * @param this calling object
- * @return list of traffic selectors
- */
- linked_list_t* (*get_other_traffic_selectors) (child_sa_t *this);
+ linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local);
/**
* @brief Get the time of this child_sa_t's last use (i.e. last use of any of its policies)
@@ -251,12 +263,12 @@ struct child_sa_t {
void (*set_state) (child_sa_t *this, child_sa_state_t state);
/**
- * @brief Get the policy used to set up this child sa.
+ * @brief Get the config used to set up this child sa.
*
* @param this calling object
- * @return policy
+ * @return child_cfg
*/
- policy_t* (*get_policy) (child_sa_t *this);
+ child_cfg_t* (*get_config) (child_sa_t *this);
/**
* @brief Set the virtual IP used received from IRAS.
@@ -284,7 +296,7 @@ struct child_sa_t {
* @param other remote address
* @param my_id id of own peer
* @param other_id id of remote peer
- * @param policy policy this CHILD_SA instantiates
+ * @param config config to use for this CHILD_SA
* @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise
* @param use_natt TRUE if NAT traversal is used
* @return child_sa_t object
@@ -293,6 +305,6 @@ struct child_sa_t {
*/
child_sa_t * child_sa_create(host_t *me, host_t *other,
identification_t *my_id, identification_t* other_id,
- policy_t *policy, u_int32_t reqid, bool use_natt);
+ child_cfg_t *config, u_int32_t reqid, bool use_natt);
#endif /*CHILD_SA_H_*/
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c
index 68aba3064..8b4b53e10 100644
--- a/src/charon/sa/ike_sa.c
+++ b/src/charon/sa/ike_sa.c
@@ -26,6 +26,7 @@
#include <string.h>
#include <printf.h>
#include <sys/stat.h>
+#include <errno.h>
#include "ike_sa.h"
@@ -56,13 +57,11 @@
#include <sa/tasks/child_create.h>
#include <sa/tasks/child_delete.h>
#include <sa/tasks/child_rekey.h>
-#include <queues/jobs/retransmit_job.h>
-#include <queues/jobs/delete_ike_sa_job.h>
-#include <queues/jobs/send_dpd_job.h>
-#include <queues/jobs/send_keepalive_job.h>
-#include <queues/jobs/rekey_ike_sa_job.h>
-#include <queues/jobs/route_job.h>
-#include <queues/jobs/initiate_job.h>
+#include <processing/jobs/retransmit_job.h>
+#include <processing/jobs/delete_ike_sa_job.h>
+#include <processing/jobs/send_dpd_job.h>
+#include <processing/jobs/send_keepalive_job.h>
+#include <processing/jobs/rekey_ike_sa_job.h>
#ifndef RESOLV_CONF
@@ -105,14 +104,14 @@ struct private_ike_sa_t {
ike_sa_state_t state;
/**
- * connection used to establish this IKE_SA.
+ * IKE configuration used to set up this IKE_SA
*/
- connection_t *connection;
+ ike_cfg_t *ike_cfg;
/**
* Peer and authentication information to establish IKE_SA.
*/
- policy_t *policy;
+ peer_cfg_t *peer_cfg;
/**
* Juggles tasks to process messages
@@ -140,6 +139,11 @@ struct private_ike_sa_t {
identification_t *other_id;
/**
+ * CA that issued the certificate of other
+ */
+ ca_info_t *other_ca;
+
+ /**
* Linked List containing the child sa's of the current IKE_SA.
*/
linked_list_t *child_sas;
@@ -175,14 +179,14 @@ struct private_ike_sa_t {
prf_t *child_prf;
/**
- * PRF to build outging authentication data
+ * Key to build outging authentication data (SKp)
*/
- prf_t *auth_build;
+ chunk_t skp_build;
/**
- * PRF to verify incoming authentication data
+ * Key to verify incoming authentication data (SKp)
*/
- prf_t *auth_verify;
+ chunk_t skp_verify;
/**
* NAT status of local host.
@@ -273,79 +277,126 @@ static u_int32_t get_unique_id(private_ike_sa_t *this)
*/
static char *get_name(private_ike_sa_t *this)
{
- if (this->connection)
+ if (this->peer_cfg)
{
- return this->connection->get_name(this->connection);
+ return this->peer_cfg->get_name(this->peer_cfg);
}
return "(unnamed)";
}
+
/**
- * Implementation of ike_sa_t.get_connection
+ * Implementation of ike_sa_t.get_stats.
*/
-static connection_t* get_connection(private_ike_sa_t *this)
+static void get_stats(private_ike_sa_t *this, u_int32_t *next_rekeying)
{
- return this->connection;
+ if (next_rekeying)
+ {
+ *next_rekeying = this->time.rekey;
+ }
}
/**
- * Implementation of ike_sa_t.set_connection
+ * Implementation of ike_sa_t.get_my_host.
*/
-static void set_connection(private_ike_sa_t *this, connection_t *connection)
+static host_t *get_my_host(private_ike_sa_t *this)
{
- this->connection = connection;
- connection->get_ref(connection);
+ return this->my_host;
}
/**
- * Implementation of ike_sa_t.get_policy
+ * Implementation of ike_sa_t.set_my_host.
*/
-static policy_t *get_policy(private_ike_sa_t *this)
+static void set_my_host(private_ike_sa_t *this, host_t *me)
{
- return this->policy;
+ DESTROY_IF(this->my_host);
+ this->my_host = me;
}
/**
- * Implementation of ike_sa_t.set_policy
+ * Implementation of ike_sa_t.get_other_host.
*/
-static void set_policy(private_ike_sa_t *this, policy_t *policy)
+static host_t *get_other_host(private_ike_sa_t *this)
{
- policy->get_ref(policy);
- this->policy = policy;
+ return this->other_host;
}
/**
- * Implementation of ike_sa_t.get_my_host.
+ * Implementation of ike_sa_t.set_other_host.
*/
-static host_t *get_my_host(private_ike_sa_t *this)
+static void set_other_host(private_ike_sa_t *this, host_t *other)
{
- return this->my_host;
+ DESTROY_IF(this->other_host);
+ this->other_host = other;
}
/**
- * Implementation of ike_sa_t.set_my_host.
+ * Implementation of ike_sa_t.get_peer_cfg
*/
-static void set_my_host(private_ike_sa_t *this, host_t *me)
+static peer_cfg_t* get_peer_cfg(private_ike_sa_t *this)
{
- DESTROY_IF(this->my_host);
- this->my_host = me;
+ return this->peer_cfg;
}
/**
- * Implementation of ike_sa_t.get_other_host.
+ * Implementation of ike_sa_t.set_peer_cfg
*/
-static host_t *get_other_host(private_ike_sa_t *this)
+static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg)
{
- return this->other_host;
+ peer_cfg->get_ref(peer_cfg);
+ this->peer_cfg = peer_cfg;
+
+ if (this->ike_cfg == NULL)
+ {
+ this->ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
+ this->ike_cfg->get_ref(this->ike_cfg);
+ }
+
+ /* apply values, so we are ready to initate/acquire */
+ if (this->my_host->is_anyaddr(this->my_host))
+ {
+ host_t *me = this->ike_cfg->get_my_host(this->ike_cfg);
+
+ set_my_host(this, me->clone(me));
+ }
+ if (this->other_host->is_anyaddr(this->other_host))
+ {
+ host_t *other = this->ike_cfg->get_other_host(this->ike_cfg);
+
+ set_other_host(this, other->clone(other));
+ }
+ /* apply IDs if they are not already set */
+ if (this->my_id->contains_wildcards(this->my_id))
+ {
+ identification_t *my_id = this->peer_cfg->get_my_id(this->peer_cfg);
+
+ DESTROY_IF(this->my_id);
+ this->my_id = my_id->clone(my_id);
+ }
+ if (this->other_id->contains_wildcards(this->other_id))
+ {
+ identification_t *other_id = this->peer_cfg->get_other_id(this->peer_cfg);
+
+ DESTROY_IF(this->other_id);
+ this->other_id = other_id->clone(other_id);
+ }
}
/**
- * Implementation of ike_sa_t.set_other_host.
+ * Implementation of ike_sa_t.get_ike_cfg
*/
-static void set_other_host(private_ike_sa_t *this, host_t *other)
+static ike_cfg_t *get_ike_cfg(private_ike_sa_t *this)
{
- DESTROY_IF(this->other_host);
- this->other_host = other;
+ return this->ike_cfg;
+}
+
+/**
+ * Implementation of ike_sa_t.set_ike_cfg
+ */
+static void set_ike_cfg(private_ike_sa_t *this, ike_cfg_t *ike_cfg)
+{
+ ike_cfg->get_ref(ike_cfg);
+ this->ike_cfg = ike_cfg;
}
/**
@@ -356,7 +407,7 @@ static status_t send_dpd(private_ike_sa_t *this)
send_dpd_job_t *job;
time_t diff, delay;
- delay = this->connection->get_dpd_delay(this->connection);
+ delay = this->peer_cfg->get_dpd_delay(this->peer_cfg);
if (delay == 0)
{
@@ -402,15 +453,14 @@ static status_t send_dpd(private_ike_sa_t *this)
static void send_keepalive(private_ike_sa_t *this)
{
send_keepalive_job_t *job;
- time_t last_out, now, diff, interval;
+ time_t last_out, now, diff;
last_out = get_use_time(this, FALSE);
now = time(NULL);
diff = now - last_out;
- interval = charon->configuration->get_keepalive_interval(charon->configuration);
- if (diff >= interval)
+ if (diff >= KEEPALIVE_INTERVAL)
{
packet_t *packet;
chunk_t data;
@@ -428,7 +478,7 @@ static void send_keepalive(private_ike_sa_t *this)
}
job = send_keepalive_job_create(this->ike_sa_id);
charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
- (interval - diff) * 1000);
+ (KEEPALIVE_INTERVAL - diff) * 1000);
}
/**
@@ -464,9 +514,9 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
send_dpd(this);
/* schedule rekeying/reauthentication */
- soft = this->connection->get_soft_lifetime(this->connection);
- hard = this->connection->get_hard_lifetime(this->connection);
- reauth = this->connection->get_reauth(this->connection);
+ soft = this->peer_cfg->get_lifetime(this->peer_cfg, TRUE);
+ hard = this->peer_cfg->get_lifetime(this->peer_cfg, FALSE);
+ reauth = this->peer_cfg->use_reauth(this->peer_cfg);
DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds",
reauth ? "reauthentication": "rekeying", soft, hard);
@@ -492,9 +542,8 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
{
/* delete may fail if a packet gets lost, so set a timeout */
job_t *job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
- charon->event_queue->add_relative(charon->event_queue, job,
- charon->configuration->get_half_open_ike_sa_timeout(
- charon->configuration));
+ charon->event_queue->add_relative(charon->event_queue, job,
+ HALF_OPEN_IKE_SA_TIMEOUT);
break;
}
default:
@@ -521,7 +570,7 @@ static void reset(private_ike_sa_t *this)
}
/**
- * Update connection host, as addresses may change (NAT)
+ * Update hosts, as addresses may change (NAT)
*/
static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
{
@@ -696,16 +745,16 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
me = message->get_destination(message);
other = message->get_source(message);
- /* if this IKE_SA is virgin, we check for a connection */
- if (this->connection == NULL)
+ /* if this IKE_SA is virgin, we check for a config */
+ if (this->ike_cfg == NULL)
{
job_t *job;
- this->connection = charon->connections->get_connection_by_hosts(
- charon->connections, me, other);
- if (this->connection == NULL)
+ this->ike_cfg = charon->backends->get_ike_cfg(charon->backends,
+ me, other);
+ if (this->ike_cfg == NULL)
{
- /* no connection found for these hosts, destroy */
- DBG1(DBG_IKE, "no connection found for %H...%H, sending %N",
+ /* no config found for these hosts, destroy */
+ DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N",
me, other, notify_type_names, NO_PROPOSAL_CHOSEN);
send_notify_response(this, message, NO_PROPOSAL_CHOSEN);
return DESTROY_ME;
@@ -713,11 +762,10 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
/* add a timeout if peer does not establish it completely */
job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE);
charon->event_queue->add_relative(charon->event_queue, job,
- charon->configuration->get_half_open_ike_sa_timeout(
- charon->configuration));
+ HALF_OPEN_IKE_SA_TIMEOUT);
}
-
- /* check if message is trustworthy, and update connection information */
+
+ /* check if message is trustworthy, and update host information */
if (this->state == IKE_CREATED ||
message->get_exchange_type(message) != IKE_SA_INIT)
{
@@ -729,46 +777,14 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
}
/**
- * apply the connection/policy information to this IKE_SA
- */
-static void apply_config(private_ike_sa_t *this,
- connection_t *connection, policy_t *policy)
-{
- host_t *me, *other;
- identification_t *my_id, *other_id;
-
- if (this->connection == NULL && this->policy == NULL)
- {
- this->connection = connection;
- connection->get_ref(connection);
- this->policy = policy;
- policy->get_ref(policy);
-
- me = connection->get_my_host(connection);
- other = connection->get_other_host(connection);
- my_id = policy->get_my_id(policy);
- other_id = policy->get_other_id(policy);
- set_my_host(this, me->clone(me));
- set_other_host(this, other->clone(other));
- DESTROY_IF(this->my_id);
- DESTROY_IF(this->other_id);
- this->my_id = my_id->clone(my_id);
- this->other_id = other_id->clone(other_id);
- }
-}
-
-/**
* Implementation of ike_sa_t.initiate.
*/
-static status_t initiate(private_ike_sa_t *this,
- connection_t *connection, policy_t *policy)
+static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
{
task_t *task;
if (this->state == IKE_CREATED)
{
- /* if we aren't established/establishing, do so */
- apply_config(this, connection, policy);
if (this->other_host->is_anyaddr(this->other_host))
{
@@ -785,11 +801,12 @@ static status_t initiate(private_ike_sa_t *this,
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_auth_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
- task = (task_t*)ike_config_create(&this->public, policy);
+ task = (task_t*)ike_config_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
}
- task = (task_t*)child_create_create(&this->public, policy);
+ task = (task_t*)child_create_create(&this->public, child_cfg);
+ child_cfg->destroy(child_cfg);
this->task_manager->queue_task(this->task_manager, task);
return this->task_manager->initiate(this->task_manager);
@@ -800,7 +817,7 @@ static status_t initiate(private_ike_sa_t *this,
*/
static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
{
- policy_t *policy;
+ child_cfg_t *child_cfg;
iterator_t *iterator;
child_sa_t *current, *child_sa = NULL;
task_t *task;
@@ -833,7 +850,6 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
return FAILED;
}
- policy = child_sa->get_policy(child_sa);
if (this->state == IKE_CREATED)
{
@@ -845,11 +861,12 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_auth_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
- task = (task_t*)ike_config_create(&this->public, policy);
+ task = (task_t*)ike_config_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
}
- child_create = child_create_create(&this->public, policy);
+ child_cfg = child_sa->get_config(child_sa);
+ child_create = child_create_create(&this->public, child_cfg);
child_create->use_reqid(child_create, reqid);
this->task_manager->queue_task(this->task_manager, (task_t*)child_create);
@@ -857,40 +874,11 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
}
/**
- * compare two lists of traffic selectors for equality
- */
-static bool ts_list_equals(linked_list_t *l1, linked_list_t *l2)
-{
- bool equals = TRUE;
- iterator_t *i1, *i2;
- traffic_selector_t *t1, *t2;
-
- if (l1->get_count(l1) != l2->get_count(l2))
- {
- return FALSE;
- }
-
- i1 = l1->create_iterator(l1, TRUE);
- i2 = l2->create_iterator(l2, TRUE);
- while (i1->iterate(i1, (void**)&t1) && i2->iterate(i2, (void**)&t2))
- {
- if (!t1->equals(t1, t2))
- {
- equals = FALSE;
- break;
- }
- }
- i1->destroy(i1);
- i2->destroy(i2);
- return equals;
-}
-
-/**
* Implementation of ike_sa_t.route.
*/
-static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t *policy)
+static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg)
{
- child_sa_t *child_sa = NULL;
+ child_sa_t *child_sa;
iterator_t *iterator;
linked_list_t *my_ts, *other_ts;
status_t status;
@@ -901,27 +889,12 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
- if (child_sa->get_state(child_sa) == CHILD_ROUTED)
+ if (child_sa->get_state(child_sa) == CHILD_ROUTED &&
+ streq(child_sa->get_name(child_sa), child_cfg->get_name(child_cfg)))
{
- linked_list_t *my_ts_conf, *other_ts_conf;
-
- my_ts = child_sa->get_my_traffic_selectors(child_sa);
- other_ts = child_sa->get_other_traffic_selectors(child_sa);
-
- my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
- other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
-
- if (ts_list_equals(my_ts, my_ts_conf) &&
- ts_list_equals(other_ts, other_ts_conf))
- {
- iterator->destroy(iterator);
- my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
- other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
- SIG(CHILD_ROUTE_FAILED, "CHILD_SA with such a policy already routed");
- return FAILED;
- }
- my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
- other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
+ iterator->destroy(iterator);
+ SIG(CHILD_ROUTE_FAILED, "CHILD_SA with such a config already routed");
+ return FAILED;
}
}
iterator->destroy(iterator);
@@ -934,9 +907,6 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t
"unable to route CHILD_SA, as its IKE_SA gets deleted");
return FAILED;
case IKE_CREATED:
- /* apply connection information, we need it to acquire */
- apply_config(this, connection, policy);
- break;
case IKE_CONNECTING:
case IKE_ESTABLISHED:
default:
@@ -944,29 +914,37 @@ static status_t route(private_ike_sa_t *this, connection_t *connection, policy_t
}
/* install kernel policies */
- child_sa = child_sa_create(this->my_host, this->other_host,
- this->my_id, this->other_id, policy, FALSE, 0);
+ child_sa = child_sa_create(this->my_host, this->other_host, this->my_id,
+ this->other_id, child_cfg, FALSE, 0);
- my_ts = policy->get_my_traffic_selectors(policy, this->my_host);
- other_ts = policy->get_other_traffic_selectors(policy, this->other_host);
+ my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL,
+ this->my_host);
+ other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL,
+ this->other_host);
status = child_sa->add_policies(child_sa, my_ts, other_ts,
- policy->get_mode(policy));
+ child_cfg->get_mode(child_cfg));
my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
- this->child_sas->insert_last(this->child_sas, child_sa);
- SIG(CHILD_ROUTE_SUCCESS, "CHILD_SA routed");
+ if (status == SUCCESS)
+ {
+ this->child_sas->insert_last(this->child_sas, child_sa);
+ SIG(CHILD_ROUTE_SUCCESS, "CHILD_SA routed");
+ }
+ else
+ {
+ SIG(CHILD_ROUTE_FAILED, "routing CHILD_SA failed");
+ }
return status;
}
/**
* Implementation of ike_sa_t.unroute.
*/
-static status_t unroute(private_ike_sa_t *this, policy_t *policy)
+static status_t unroute(private_ike_sa_t *this, u_int32_t reqid)
{
iterator_t *iterator;
- child_sa_t *child_sa = NULL;
+ child_sa_t *child_sa;
bool found = FALSE;
- linked_list_t *my_ts, *other_ts, *my_ts_conf, *other_ts_conf;
SIG(CHILD_UNROUTE_START, "unrouting CHILD_SA");
@@ -974,27 +952,14 @@ static status_t unroute(private_ike_sa_t *this, policy_t *policy)
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
- if (child_sa->get_state(child_sa) == CHILD_ROUTED)
+ if (child_sa->get_state(child_sa) == CHILD_ROUTED &&
+ child_sa->get_reqid(child_sa) == reqid)
{
- my_ts = child_sa->get_my_traffic_selectors(child_sa);
- other_ts = child_sa->get_other_traffic_selectors(child_sa);
-
- my_ts_conf = policy->get_my_traffic_selectors(policy, this->my_host);
- other_ts_conf = policy->get_other_traffic_selectors(policy, this->other_host);
-
- if (ts_list_equals(my_ts, my_ts_conf) &&
- ts_list_equals(other_ts, other_ts_conf))
- {
- iterator->remove(iterator);
- SIG(CHILD_UNROUTE_SUCCESS, "CHILD_SA unrouted");
- child_sa->destroy(child_sa);
- my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
- other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
- found = TRUE;
- break;
- }
- my_ts_conf->destroy_offset(my_ts_conf, offsetof(traffic_selector_t, destroy));
- other_ts_conf->destroy_offset(other_ts_conf, offsetof(traffic_selector_t, destroy));
+ iterator->remove(iterator);
+ SIG(CHILD_UNROUTE_SUCCESS, "CHILD_SA unrouted");
+ child_sa->destroy(child_sa);
+ found = TRUE;
+ break;
}
}
iterator->destroy(iterator);
@@ -1021,7 +986,7 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
this->time.outbound = time(NULL);
if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
{
- policy_t *policy;
+ child_cfg_t *child_cfg;
child_sa_t* child_sa;
linked_list_t *to_route, *to_restart;
iterator_t *iterator;
@@ -1032,7 +997,7 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
case IKE_CONNECTING:
{
/* retry IKE_SA_INIT if we have multiple keyingtries */
- u_int32_t tries = this->connection->get_keyingtries(this->connection);
+ u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg);
this->keyingtry++;
if (tries == 0 || tries > this->keyingtry)
{
@@ -1060,23 +1025,23 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
- policy = child_sa->get_policy(child_sa);
+ child_cfg = child_sa->get_config(child_sa);
if (child_sa->get_state(child_sa) == CHILD_ROUTED)
{
/* reroute routed CHILD_SAs */
- to_route->insert_last(to_route, policy);
+ to_route->insert_last(to_route, child_cfg);
}
else
{
/* use DPD action for established CHILD_SAs */
- switch (policy->get_dpd_action(policy))
+ switch (this->peer_cfg->get_dpd_action(this->peer_cfg))
{
case DPD_ROUTE:
- to_route->insert_last(to_route, policy);
+ to_route->insert_last(to_route, child_cfg);
break;
case DPD_RESTART:
- to_restart->insert_last(to_restart, policy);
+ to_restart->insert_last(to_restart, child_cfg);
break;
default:
break;
@@ -1094,15 +1059,15 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
new = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new(
charon->ike_sa_manager, TRUE);
- apply_config(new, this->connection, this->policy);
- /* use actual used host, not the wildcarded one in connection */
+ set_peer_cfg(new, this->peer_cfg);
+ /* use actual used host, not the wildcarded one in config */
new->other_host->destroy(new->other_host);
new->other_host = this->other_host->clone(this->other_host);
/* install routes */
- while (to_route->remove_last(to_route, (void**)&policy) == SUCCESS)
+ while (to_route->remove_last(to_route, (void**)&child_cfg) == SUCCESS)
{
- route(new, new->connection, policy);
+ route(new, child_cfg);
}
/* restart children */
@@ -1114,14 +1079,14 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
new->task_manager->queue_task(new->task_manager, task);
task = (task_t*)ike_cert_create(&new->public, TRUE);
new->task_manager->queue_task(new->task_manager, task);
- task = (task_t*)ike_config_create(&new->public, new->policy);
+ task = (task_t*)ike_config_create(&new->public, TRUE);
new->task_manager->queue_task(new->task_manager, task);
task = (task_t*)ike_auth_create(&new->public, TRUE);
new->task_manager->queue_task(new->task_manager, task);
- while (to_restart->remove_last(to_restart, (void**)&policy) == SUCCESS)
+ while (to_restart->remove_last(to_restart, (void**)&child_cfg) == SUCCESS)
{
- task = (task_t*)child_create_create(&new->public, policy);
+ task = (task_t*)child_create_create(&new->public, child_cfg);
new->task_manager->queue_task(new->task_manager, task);
}
new->task_manager->initiate(new->task_manager);
@@ -1152,19 +1117,19 @@ static prf_t *get_child_prf(private_ike_sa_t *this)
}
/**
- * Implementation of ike_sa_t.get_auth_bild
+ * Implementation of ike_sa_t.get_skp_bild
*/
-static prf_t *get_auth_build(private_ike_sa_t *this)
+static chunk_t get_skp_build(private_ike_sa_t *this)
{
- return this->auth_build;
+ return this->skp_build;
}
/**
- * Implementation of ike_sa_t.get_auth_verify
+ * Implementation of ike_sa_t.get_skp_verify
*/
-static prf_t *get_auth_verify(private_ike_sa_t *this)
+static chunk_t get_skp_verify(private_ike_sa_t *this)
{
- return this->auth_verify;
+ return this->skp_verify;
}
/**
@@ -1210,6 +1175,71 @@ static void set_other_id(private_ike_sa_t *this, identification_t *other)
}
/**
+ * Implementation of ike_sa_t.get_other_ca.
+ */
+static ca_info_t* get_other_ca(private_ike_sa_t *this)
+{
+ return this->other_ca;
+}
+
+/**
+ * Implementation of ike_sa_t.set_other_ca.
+ */
+static void set_other_ca(private_ike_sa_t *this, ca_info_t *other_ca)
+{
+ this->other_ca = other_ca;
+}
+
+/**
+ * Implementation of ike_sa_t.set_virtual_ip
+ */
+static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip)
+{
+ if (local)
+ {
+ DBG1(DBG_IKE, "installing new virtual IP %H", ip);
+ if (this->my_virtual_ip)
+ {
+ DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip);
+ charon->kernel_interface->del_ip(charon->kernel_interface,
+ this->my_virtual_ip,
+ this->my_host);
+ this->my_virtual_ip->destroy(this->my_virtual_ip);
+ }
+ if (charon->kernel_interface->add_ip(charon->kernel_interface, ip,
+ this->my_host) == SUCCESS)
+ {
+ this->my_virtual_ip = ip->clone(ip);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "installing virtual IP %H failed", ip);
+ this->my_virtual_ip = NULL;
+ }
+ }
+ else
+ {
+ DESTROY_IF(this->other_virtual_ip);
+ this->other_virtual_ip = ip->clone(ip);
+ }
+}
+
+/**
+ * Implementation of ike_sa_t.get_virtual_ip
+ */
+static host_t* get_virtual_ip(private_ike_sa_t *this, bool local)
+{
+ if (local)
+ {
+ return this->my_virtual_ip;
+ }
+ else
+ {
+ return this->other_virtual_ip;
+ }
+}
+
+/**
* Implementation of ike_sa_t.derive_keys.
*/
static status_t derive_keys(private_ike_sa_t *this,
@@ -1223,7 +1253,6 @@ static status_t derive_keys(private_ike_sa_t *this,
size_t key_size;
crypter_t *crypter_i, *crypter_r;
signer_t *signer_i, *signer_r;
- prf_t *prf_i, *prf_r;
u_int8_t spi_i_buf[sizeof(u_int64_t)], spi_r_buf[sizeof(u_int64_t)];
chunk_t spi_i = chunk_from_buf(spi_i_buf);
chunk_t spi_r = chunk_from_buf(spi_r_buf);
@@ -1364,31 +1393,27 @@ static status_t derive_keys(private_ike_sa_t *this,
this->crypter_out = crypter_r;
}
- /* SK_pi/SK_pr used for authentication => prf_auth_i, prf_auth_r */
- proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &algo);
- prf_i = prf_create(algo->algorithm);
- prf_r = prf_create(algo->algorithm);
-
- key_size = prf_i->get_key_size(prf_i);
+ /* SK_pi/SK_pr used for authentication => stored for later */
+ key_size = this->prf->get_key_size(this->prf);
prf_plus->allocate_bytes(prf_plus, key_size, &key);
DBG4(DBG_IKE, "Sk_pi secret %B", &key);
- prf_i->set_key(prf_i, key);
- chunk_free(&key);
-
+ if (initiator)
+ {
+ this->skp_build = key;
+ }
+ else
+ {
+ this->skp_verify = key;
+ }
prf_plus->allocate_bytes(prf_plus, key_size, &key);
DBG4(DBG_IKE, "Sk_pr secret %B", &key);
- prf_r->set_key(prf_r, key);
- chunk_free(&key);
-
if (initiator)
{
- this->auth_verify = prf_r;
- this->auth_build = prf_i;
+ this->skp_verify = key;
}
else
{
- this->auth_verify = prf_i;
- this->auth_build = prf_r;
+ this->skp_build = key;
}
/* all done, prf_plus not needed anymore */
@@ -1507,8 +1532,6 @@ static status_t delete_(private_ike_sa_t *this)
switch (this->state)
{
case IKE_ESTABLISHED:
- DBG1(DBG_IKE, "deleting IKE_SA");
- /* do not log when rekeyed */
case IKE_REKEYING:
ike_delete = ike_delete_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, &ike_delete->task);
@@ -1542,16 +1565,21 @@ static void reestablish(private_ike_sa_t *this)
private_ike_sa_t *other;
iterator_t *iterator;
child_sa_t *child_sa;
- policy_t *policy;
+ child_cfg_t *child_cfg;
task_t *task;
job_t *job;
other = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new(
charon->ike_sa_manager, TRUE);
- apply_config(other, this->connection, this->policy);
+ set_peer_cfg(other, this->peer_cfg);
other->other_host->destroy(other->other_host);
other->other_host = this->other_host->clone(this->other_host);
+ if (this->my_virtual_ip)
+ {
+ /* if we already have a virtual IP, we reuse it */
+ set_virtual_ip(other, TRUE, this->my_virtual_ip);
+ }
if (this->state == IKE_ESTABLISHED)
{
@@ -1561,7 +1589,7 @@ static void reestablish(private_ike_sa_t *this)
other->task_manager->queue_task(other->task_manager, task);
task = (task_t*)ike_cert_create(&other->public, TRUE);
other->task_manager->queue_task(other->task_manager, task);
- task = (task_t*)ike_config_create(&other->public, other->policy);
+ task = (task_t*)ike_config_create(&other->public, TRUE);
other->task_manager->queue_task(other->task_manager, task);
task = (task_t*)ike_auth_create(&other->public, TRUE);
other->task_manager->queue_task(other->task_manager, task);
@@ -1583,8 +1611,8 @@ static void reestablish(private_ike_sa_t *this)
}
default:
{
- policy = child_sa->get_policy(child_sa);
- task = (task_t*)child_create_create(&other->public, policy);
+ child_cfg = child_sa->get_config(child_sa);
+ task = (task_t*)child_create_create(&other->public, child_cfg);
other->task_manager->queue_task(other->task_manager, task);
break;
}
@@ -1678,55 +1706,6 @@ static void enable_natt(private_ike_sa_t *this, bool local)
}
/**
- * Implementation of ike_sa_t.set_virtual_ip
- */
-static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip)
-{
- if (local)
- {
- DBG1(DBG_IKE, "installing new virtual IP %H", ip);
- if (this->my_virtual_ip)
- {
- DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip);
- charon->kernel_interface->del_ip(charon->kernel_interface,
- this->my_virtual_ip,
- this->my_host);
- this->my_virtual_ip->destroy(this->my_virtual_ip);
- }
- if (charon->kernel_interface->add_ip(charon->kernel_interface, ip,
- this->my_host) == SUCCESS)
- {
- this->my_virtual_ip = ip->clone(ip);
- }
- else
- {
- DBG1(DBG_IKE, "installing virtual IP %H failed", ip);
- this->my_virtual_ip = NULL;
- }
- }
- else
- {
- DESTROY_IF(this->other_virtual_ip);
- this->other_virtual_ip = ip->clone(ip);
- }
-}
-
-/**
- * Implementation of ike_sa_t.get_virtual_ip
- */
-static host_t* get_virtual_ip(private_ike_sa_t *this, bool local)
-{
- if (local)
- {
- return this->my_virtual_ip;
- }
- else
- {
- return this->other_virtual_ip;
- }
-}
-
-/**
* Implementation of ike_sa_t.remove_dns_server
*/
static void remove_dns_servers(private_ike_sa_t *this)
@@ -1747,7 +1726,8 @@ static void remove_dns_servers(private_ike_sa_t *this)
file = fopen(RESOLV_CONF, "r");
if (file == NULL || stat(RESOLV_CONF, &stats) != 0)
{
- DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+ DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s",
+ RESOLV_CONF, strerror(errno));
return;
}
@@ -1755,7 +1735,7 @@ static void remove_dns_servers(private_ike_sa_t *this)
if (fread(contents.ptr, 1, contents.len, file) != contents.len)
{
- DBG1(DBG_IKE, "unable to read DNS configuration file: %m");
+ DBG1(DBG_IKE, "unable to read DNS configuration file: %s", strerror(errno));
fclose(file);
return;
}
@@ -1764,7 +1744,8 @@ static void remove_dns_servers(private_ike_sa_t *this)
file = fopen(RESOLV_CONF, "w");
if (file == NULL)
{
- DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+ DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s",
+ RESOLV_CONF, strerror(errno));
return;
}
@@ -1820,7 +1801,8 @@ static void add_dns_server(private_ike_sa_t *this, host_t *dns)
file = fopen(RESOLV_CONF, "a+");
if (file == NULL || stat(RESOLV_CONF, &stats) != 0)
{
- DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+ DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s",
+ RESOLV_CONF, strerror(errno));
return;
}
@@ -1828,7 +1810,7 @@ static void add_dns_server(private_ike_sa_t *this, host_t *dns)
if (fread(contents.ptr, 1, contents.len, file) != contents.len)
{
- DBG1(DBG_IKE, "unable to read DNS configuration file: %m");
+ DBG1(DBG_IKE, "unable to read DNS configuration file: %s", strerror(errno));
fclose(file);
return;
}
@@ -1837,14 +1819,15 @@ static void add_dns_server(private_ike_sa_t *this, host_t *dns)
file = fopen(RESOLV_CONF, "w");
if (file == NULL)
{
- DBG1(DBG_IKE, "unable to open DNS configuration file %s: %m", RESOLV_CONF);
+ DBG1(DBG_IKE, "unable to open DNS configuration file %s: %s",
+ RESOLV_CONF, strerror(errno));
return;
}
if (fprintf(file, "nameserver %H # added by strongSwan, assigned by %D\n",
dns, this->other_id) < 0)
{
- DBG1(DBG_IKE, "unable to write DNS configuration: %m");
+ DBG1(DBG_IKE, "unable to write DNS configuration: %s", strerror(errno));
}
else
{
@@ -1856,50 +1839,6 @@ static void add_dns_server(private_ike_sa_t *this, host_t *dns)
}
/**
- * output handler in printf()
- */
-static int print(FILE *stream, const struct printf_info *info,
- const void *const *args)
-{
- int written = 0;
- bool reauth = FALSE;
- private_ike_sa_t *this = *((private_ike_sa_t**)(args[0]));
-
- if (this->connection)
- {
- reauth = this->connection->get_reauth(this->connection);
- }
-
- if (this == NULL)
- {
- return fprintf(stream, "(null)");
- }
-
- written = fprintf(stream, "%12s[%d]: %N, %H[%D]...%H[%D]", get_name(this),
- this->unique_id, ike_sa_state_names, this->state,
- this->my_host, this->my_id, this->other_host,
- this->other_id);
- written += fprintf(stream, "\n%12s[%d]: IKE SPIs: %J, %s in %ds",
- get_name(this), this->unique_id, this->ike_sa_id,
- this->connection && reauth? "reauthentication":"rekeying",
- this->time.rekey - time(NULL));
-
- if (info->alt)
- {
-
- }
- return written;
-}
-
-/**
- * register printf() handlers
- */
-static void __attribute__ ((constructor))print_register()
-{
- register_printf_function(PRINTF_IKE_SA, print, arginfo_ptr);
-}
-
-/**
* Implementation of ike_sa_t.destroy.
*/
static void destroy(private_ike_sa_t *this)
@@ -1912,8 +1851,8 @@ static void destroy(private_ike_sa_t *this)
DESTROY_IF(this->signer_out);
DESTROY_IF(this->prf);
DESTROY_IF(this->child_prf);
- DESTROY_IF(this->auth_verify);
- DESTROY_IF(this->auth_build);
+ chunk_free(&this->skp_verify);
+ chunk_free(&this->skp_build);
if (this->my_virtual_ip)
{
@@ -1931,8 +1870,8 @@ static void destroy(private_ike_sa_t *this)
DESTROY_IF(this->my_id);
DESTROY_IF(this->other_id);
- DESTROY_IF(this->connection);
- DESTROY_IF(this->policy);
+ DESTROY_IF(this->ike_cfg);
+ DESTROY_IF(this->peer_cfg);
this->ike_sa_id->destroy(this->ike_sa_id);
this->task_manager->destroy(this->task_manager);
@@ -1948,54 +1887,57 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
static u_int32_t unique_id = 0;
/* Public functions */
- this->public.get_state = (ike_sa_state_t(*)(ike_sa_t*)) get_state;
- this->public.set_state = (void(*)(ike_sa_t*,ike_sa_state_t)) set_state;
- this->public.get_name = (char*(*)(ike_sa_t*))get_name;
- this->public.process_message = (status_t(*)(ike_sa_t*, message_t*)) process_message;
- this->public.initiate = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) initiate;
- this->public.route = (status_t(*)(ike_sa_t*,connection_t*,policy_t*)) route;
- this->public.unroute = (status_t(*)(ike_sa_t*,policy_t*)) unroute;
- this->public.acquire = (status_t(*)(ike_sa_t*,u_int32_t)) acquire;
- this->public.get_connection = (connection_t*(*)(ike_sa_t*))get_connection;
- this->public.set_connection = (void(*)(ike_sa_t*,connection_t*))set_connection;
- this->public.get_policy = (policy_t*(*)(ike_sa_t*))get_policy;
- this->public.set_policy = (void(*)(ike_sa_t*,policy_t*))set_policy;
- this->public.get_id = (ike_sa_id_t*(*)(ike_sa_t*)) get_id;
- this->public.get_my_host = (host_t*(*)(ike_sa_t*)) get_my_host;
- this->public.set_my_host = (void(*)(ike_sa_t*,host_t*)) set_my_host;
- this->public.get_other_host = (host_t*(*)(ike_sa_t*)) get_other_host;
- this->public.set_other_host = (void(*)(ike_sa_t*,host_t*)) set_other_host;
- this->public.get_my_id = (identification_t*(*)(ike_sa_t*)) get_my_id;
- this->public.set_my_id = (void(*)(ike_sa_t*,identification_t*)) set_my_id;
- this->public.get_other_id = (identification_t*(*)(ike_sa_t*)) get_other_id;
- this->public.set_other_id = (void(*)(ike_sa_t*,identification_t*)) set_other_id;
- this->public.retransmit = (status_t (*) (ike_sa_t *, u_int32_t)) retransmit;
- this->public.delete = (status_t(*)(ike_sa_t*))delete_;
- this->public.destroy = (void(*)(ike_sa_t*))destroy;
+ this->public.get_state = (ike_sa_state_t (*)(ike_sa_t*)) get_state;
+ this->public.set_state = (void (*)(ike_sa_t*,ike_sa_state_t)) set_state;
+ this->public.get_stats = (void (*)(ike_sa_t*,u_int32_t*))get_stats;
+ this->public.get_name = (char* (*)(ike_sa_t*))get_name;
+ this->public.process_message = (status_t (*)(ike_sa_t*, message_t*)) process_message;
+ this->public.initiate = (status_t (*)(ike_sa_t*,child_cfg_t*)) initiate;
+ this->public.route = (status_t (*)(ike_sa_t*,child_cfg_t*)) route;
+ this->public.unroute = (status_t (*)(ike_sa_t*,u_int32_t)) unroute;
+ this->public.acquire = (status_t (*)(ike_sa_t*,u_int32_t)) acquire;
+ this->public.get_ike_cfg = (ike_cfg_t* (*)(ike_sa_t*))get_ike_cfg;
+ this->public.set_ike_cfg = (void (*)(ike_sa_t*,ike_cfg_t*))set_ike_cfg;
+ this->public.get_peer_cfg = (peer_cfg_t* (*)(ike_sa_t*))get_peer_cfg;
+ this->public.set_peer_cfg = (void (*)(ike_sa_t*,peer_cfg_t*))set_peer_cfg;
+ this->public.get_id = (ike_sa_id_t* (*)(ike_sa_t*)) get_id;
+ this->public.get_my_host = (host_t* (*)(ike_sa_t*)) get_my_host;
+ this->public.set_my_host = (void (*)(ike_sa_t*,host_t*)) set_my_host;
+ this->public.get_other_host = (host_t* (*)(ike_sa_t*)) get_other_host;
+ this->public.set_other_host = (void (*)(ike_sa_t*,host_t*)) set_other_host;
+ this->public.get_my_id = (identification_t* (*)(ike_sa_t*)) get_my_id;
+ this->public.set_my_id = (void (*)(ike_sa_t*,identification_t*)) set_my_id;
+ this->public.get_other_id = (identification_t* (*)(ike_sa_t*)) get_other_id;
+ this->public.set_other_id = (void (*)(ike_sa_t*,identification_t*)) set_other_id;
+ this->public.get_other_ca = (ca_info_t* (*)(ike_sa_t*)) get_other_ca;
+ this->public.set_other_ca = (void (*)(ike_sa_t*,ca_info_t*)) set_other_ca;
+ this->public.retransmit = (status_t (*)(ike_sa_t *, u_int32_t)) retransmit;
+ this->public.delete = (status_t (*)(ike_sa_t*))delete_;
+ this->public.destroy = (void (*)(ike_sa_t*))destroy;
this->public.send_dpd = (status_t (*)(ike_sa_t*)) send_dpd;
this->public.send_keepalive = (void (*)(ike_sa_t*)) send_keepalive;
- this->public.get_prf = (prf_t *(*) (ike_sa_t *)) get_prf;
- this->public.get_child_prf = (prf_t *(*) (ike_sa_t *)) get_child_prf;
- this->public.get_auth_verify = (prf_t *(*) (ike_sa_t *)) get_auth_verify;
- this->public.get_auth_build = (prf_t *(*) (ike_sa_t *)) get_auth_build;
- this->public.derive_keys = (status_t (*) (ike_sa_t *,proposal_t*,chunk_t,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys;
- this->public.add_child_sa = (void (*) (ike_sa_t*,child_sa_t*)) add_child_sa;
+ this->public.get_prf = (prf_t* (*)(ike_sa_t*)) get_prf;
+ this->public.get_child_prf = (prf_t* (*)(ike_sa_t *)) get_child_prf;
+ this->public.get_skp_verify = (chunk_t (*)(ike_sa_t *)) get_skp_verify;
+ this->public.get_skp_build = (chunk_t (*)(ike_sa_t *)) get_skp_build;
+ this->public.derive_keys = (status_t (*)(ike_sa_t *,proposal_t*,chunk_t,chunk_t,chunk_t,bool,prf_t*,prf_t*)) derive_keys;
+ this->public.add_child_sa = (void (*)(ike_sa_t*,child_sa_t*)) add_child_sa;
this->public.get_child_sa = (child_sa_t* (*)(ike_sa_t*,protocol_id_t,u_int32_t,bool)) get_child_sa;
this->public.create_child_sa_iterator = (iterator_t* (*)(ike_sa_t*)) create_child_sa_iterator;
- this->public.rekey_child_sa = (status_t(*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa;
- this->public.delete_child_sa = (status_t(*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa;
+ this->public.rekey_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa;
+ this->public.delete_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa;
this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa;
- this->public.enable_natt = (void(*)(ike_sa_t*, bool)) enable_natt;
- this->public.is_natt_enabled = (bool(*)(ike_sa_t*)) is_natt_enabled;
- this->public.rekey = (status_t(*)(ike_sa_t*))rekey;
- this->public.reestablish = (void(*)(ike_sa_t*))reestablish;
- this->public.inherit = (status_t(*)(ike_sa_t*,ike_sa_t*))inherit;
- this->public.generate_message = (status_t(*)(ike_sa_t*,message_t*,packet_t**))generate_message;
- this->public.reset = (void(*)(ike_sa_t*))reset;
- this->public.get_unique_id = (u_int32_t(*)(ike_sa_t*))get_unique_id;
- this->public.set_virtual_ip = (void(*)(ike_sa_t*,bool,host_t*))set_virtual_ip;
- this->public.get_virtual_ip = (host_t*(*)(ike_sa_t*,bool))get_virtual_ip;
- this->public.add_dns_server = (void(*)(ike_sa_t*,host_t*))add_dns_server;
+ this->public.enable_natt = (void (*)(ike_sa_t*, bool)) enable_natt;
+ this->public.is_natt_enabled = (bool (*)(ike_sa_t*)) is_natt_enabled;
+ this->public.rekey = (status_t (*)(ike_sa_t*))rekey;
+ this->public.reestablish = (void (*)(ike_sa_t*))reestablish;
+ this->public.inherit = (status_t (*)(ike_sa_t*,ike_sa_t*))inherit;
+ this->public.generate_message = (status_t (*)(ike_sa_t*,message_t*,packet_t**))generate_message;
+ this->public.reset = (void (*)(ike_sa_t*))reset;
+ this->public.get_unique_id = (u_int32_t (*)(ike_sa_t*))get_unique_id;
+ this->public.set_virtual_ip = (void (*)(ike_sa_t*,bool,host_t*))set_virtual_ip;
+ this->public.get_virtual_ip = (host_t* (*)(ike_sa_t*,bool))get_virtual_ip;
+ this->public.add_dns_server = (void (*)(ike_sa_t*,host_t*))add_dns_server;
/* initialize private fields */
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
@@ -2004,13 +1946,14 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->other_host = host_create_any(AF_INET);
this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty);
this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty);
+ this->other_ca = NULL;
this->crypter_in = NULL;
this->crypter_out = NULL;
this->signer_in = NULL;
this->signer_out = NULL;
this->prf = NULL;
- this->auth_verify = NULL;
- this->auth_build = NULL;
+ this->skp_verify = chunk_empty;
+ this->skp_build = chunk_empty;
this->child_prf = NULL;
this->nat_here = FALSE;
this->nat_there = FALSE;
@@ -2019,8 +1962,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->time.established = 0;
this->time.rekey = 0;
this->time.delete = 0;
- this->connection = NULL;
- this->policy = NULL;
+ this->ike_cfg = NULL;
+ this->peer_cfg = NULL;
this->task_manager = task_manager_create(&this->public);
this->unique_id = ++unique_id;
this->my_virtual_ip = NULL;
diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h
index 604ec94a9..76942b208 100644
--- a/src/charon/sa/ike_sa.h
+++ b/src/charon/sa/ike_sa.h
@@ -34,14 +34,42 @@ typedef struct ike_sa_t ike_sa_t;
#include <sa/ike_sa_id.h>
#include <sa/child_sa.h>
#include <sa/tasks/task.h>
-#include <config/configuration.h>
#include <utils/randomizer.h>
#include <crypto/prfs/prf.h>
#include <crypto/crypters/crypter.h>
#include <crypto/signers/signer.h>
-#include <config/connections/connection.h>
-#include <config/policies/policy.h>
-#include <config/proposal.h>
+#include <crypto/ca.h>
+#include <config/peer_cfg.h>
+#include <config/ike_cfg.h>
+
+/**
+ * Timeout in milliseconds after that a half open IKE_SA gets deleted.
+ *
+ * @ingroup sa
+ */
+#define HALF_OPEN_IKE_SA_TIMEOUT 30000
+
+/**
+ * Interval to send keepalives when NATed, in seconds.
+ *
+ * @ingroup sa
+ */
+#define KEEPALIVE_INTERVAL 20
+
+/**
+ * After which time rekeying should be retried if it failed, in seconds.
+ *
+ * @ingroup sa
+ */
+#define RETRY_INTERVAL 30
+
+/**
+ * Jitter to subtract from RETRY_INTERVAL to randomize rekey retry.
+ *
+ * @ingroup sa
+ */
+#define RETRY_JITTER 20
+
/**
* @brief State of an IKE_SA.
@@ -157,6 +185,13 @@ struct ike_sa_t {
ike_sa_state_t (*get_state) (ike_sa_t *this);
/**
+ * @brief Get some statistics about this IKE_SA.
+ *
+ * @param next_rekeying when the next rekeying is scheduled
+ */
+ void (*get_stats)(ike_sa_t *this, u_int32_t *next_rekeying);
+
+ /**
* @brief Set the state of the IKE_SA.
*
* @param this calling object
@@ -221,7 +256,7 @@ struct ike_sa_t {
void (*set_my_id) (ike_sa_t *this, identification_t *me);
/**
- * @brief Get the other peers identification.
+ * @brief Get the other peer's identification.
*
* @param this calling object
* @return identification
@@ -229,7 +264,7 @@ struct ike_sa_t {
identification_t* (*get_other_id) (ike_sa_t *this);
/**
- * @brief Set the other peers identification.
+ * @brief Set the other peer's identification.
*
* @param this calling object
* @param other identification
@@ -237,51 +272,65 @@ struct ike_sa_t {
void (*set_other_id) (ike_sa_t *this, identification_t *other);
/**
- * @brief Get the connection used by this IKE_SA.
+ * @brief Get the other peer's certification authority
+ *
+ * @param this calling object
+ * @return ca_info_t record of other ca
+ */
+ ca_info_t* (*get_other_ca) (ike_sa_t *this);
+
+ /**
+ * @brief Set the other peer's certification authority
+ *
+ * @param this calling object
+ * @param other_ca ca_info_t record of other ca
+ */
+ void (*set_other_ca) (ike_sa_t *this, ca_info_t *other_ca);
+
+ /**
+ * @brief Get the config used to setup this IKE_SA.
*
* @param this calling object
- * @return connection
+ * @return ike_config
*/
- connection_t* (*get_connection) (ike_sa_t *this);
+ ike_cfg_t* (*get_ike_cfg) (ike_sa_t *this);
/**
- * @brief Set the connection to use with this IKE_SA.
+ * @brief Set the config to setup this IKE_SA.
*
* @param this calling object
- * @param connection connection to use
+ * @param config ike_config to use
*/
- void (*set_connection) (ike_sa_t *this, connection_t* connection);
+ void (*set_ike_cfg) (ike_sa_t *this, ike_cfg_t* config);
/**
- * @brief Get the policy used by this IKE_SA.
+ * @brief Get the peer config used by this IKE_SA.
*
* @param this calling object
- * @return policy
+ * @return peer_config
*/
- policy_t* (*get_policy) (ike_sa_t *this);
+ peer_cfg_t* (*get_peer_cfg) (ike_sa_t *this);
/**
- * @brief Set the policy to use with this IKE_SA.
+ * @brief Set the peer config to use with this IKE_SA.
*
* @param this calling object
- * @param policy policy to use
+ * @param config peer_config to use
*/
- void (*set_policy) (ike_sa_t *this, policy_t *policy);
+ void (*set_peer_cfg) (ike_sa_t *this, peer_cfg_t *config);
/**
* @brief Initiate a new connection.
*
- * The policy/connection is owned by the IKE_SA after the call, so
- * do not modify or destroy it.
+ * The configs are owned by the IKE_SA after the call.
*
* @param this calling object
- * @param connection connection to initiate
- * @param policy policy to set up
+ * @param child_cfg child config to create CHILD from
* @return
* - SUCCESS if initialization started
- * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted
+ * - DESTROY_ME if initialization failed
*/
- status_t (*initiate) (ike_sa_t *this, connection_t *connection, policy_t *policy);
+ status_t (*initiate) (ike_sa_t *this, child_cfg_t *child_cfg);
/**
* @brief Route a policy in the kernel.
@@ -290,28 +339,27 @@ struct ike_sa_t {
* the kernel requests connection setup from the IKE_SA via acquire().
*
* @param this calling object
- * @param connection connection definition used for routing
- * @param policy policy to route
+ * @param child_cfg child config to route
* @return
* - SUCCESS if routed successfully
* - FAILED if routing failed
*/
- status_t (*route) (ike_sa_t *this, connection_t *connection, policy_t *policy);
+ status_t (*route) (ike_sa_t *this, child_cfg_t *child_cfg);
/**
* @brief Unroute a policy in the kernel previously routed.
*
* @param this calling object
- * @param policy policy to route
+ * @param reqid reqid of CHILD_SA to unroute
* @return
* - SUCCESS if route removed
- * - DESTROY_ME if last route was removed from
- * an IKE_SA which was not established
+ * - NOT_FOUND if CHILD_SA not found
+ * - DESTROY_ME if last CHILD_SA was unrouted
*/
- status_t (*unroute) (ike_sa_t *this, policy_t *policy);
+ status_t (*unroute) (ike_sa_t *this, u_int32_t reqid);
/**
- * @brief Acquire connection setup for a policy.
+ * @brief Acquire connection setup for an installed kernel policy.
*
* If an installed policy raises an acquire, the kernel calls
* this function to establish the CHILD_SA (and maybe the IKE_SA).
@@ -320,7 +368,7 @@ struct ike_sa_t {
* @param reqid reqid of the CHILD_SA the policy belongs to.
* @return
* - SUCCESS if initialization started
- * - DESTROY_ME if initialization failed and IKE_SA MUST be deleted
+ * - DESTROY_ME if initialization failed
*/
status_t (*acquire) (ike_sa_t *this, u_int32_t reqid);
@@ -456,7 +504,7 @@ struct ike_sa_t {
bool initiator, prf_t *child_prf, prf_t *old_prf);
/**
- * @brief Get the multi purpose prf.
+ * @brief Get a multi purpose prf for the negotiated PRF function.
*
* @param this calling object
* @return pointer to prf_t object
@@ -472,20 +520,20 @@ struct ike_sa_t {
prf_t *(*get_child_prf) (ike_sa_t *this);
/**
- * @brief Get the prf to build outgoing authentication data.
+ * @brief Get the key to build outgoing authentication data.
*
* @param this calling object
* @return pointer to prf_t object
*/
- prf_t *(*get_auth_build) (ike_sa_t *this);
+ chunk_t (*get_skp_build) (ike_sa_t *this);
/**
- * @brief Get the prf to verify incoming authentication data.
+ * @brief Get the key to verify incoming authentication data.
*
* @param this calling object
* @return pointer to prf_t object
*/
- prf_t *(*get_auth_verify) (ike_sa_t *this);
+ chunk_t (*get_skp_verify) (ike_sa_t *this);
/**
* @brief Associates a child SA to this IKE SA
diff --git a/src/charon/sa/ike_sa_id.c b/src/charon/sa/ike_sa_id.c
index c143fc0ba..a838c0b8a 100644
--- a/src/charon/sa/ike_sa_id.c
+++ b/src/charon/sa/ike_sa_id.c
@@ -24,7 +24,6 @@
#include "ike_sa_id.h"
-#include <printf.h>
#include <stdio.h>
@@ -153,33 +152,6 @@ static ike_sa_id_t* clone_(private_ike_sa_id_t *this)
}
/**
- * output handler in printf()
- */
-static int print(FILE *stream, const struct printf_info *info,
- const void *const *args)
-{
- private_ike_sa_id_t *this = *((private_ike_sa_id_t**)(args[0]));
-
- if (this == NULL)
- {
- return fprintf(stream, "(null)");
- }
- return fprintf(stream, "0x%0llx_i%s 0x%0llx_r%s",
- this->initiator_spi,
- this->is_initiator_flag ? "*" : "",
- this->responder_spi,
- this->is_initiator_flag ? "" : "*");
-}
-
-/**
- * register printf() handlers
- */
-static void __attribute__ ((constructor))print_register()
-{
- register_printf_function(PRINTF_IKE_SA_ID, print, arginfo_ptr);
-}
-
-/**
* Implementation of ike_sa_id_t.destroy.
*/
static void destroy(private_ike_sa_id_t *this)
diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c
index 791ef805e..a62ec5e3c 100644
--- a/src/charon/sa/ike_sa_manager.c
+++ b/src/charon/sa/ike_sa_manager.c
@@ -322,8 +322,8 @@ static ike_sa_t* checkout(private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id
ike_sa_t *ike_sa = NULL;
entry_t *entry;
- DBG2(DBG_MGR, "checkout IKE_SA: %J, %d IKE_SAs in manager",
- ike_sa_id, this->ike_sa_list->get_count(this->ike_sa_list));
+ DBG2(DBG_MGR, "checkout IKE_SA, %d IKE_SAs in manager",
+ this->ike_sa_list->get_count(this->ike_sa_list));
pthread_mutex_lock(&(this->mutex));
if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS)
@@ -356,13 +356,14 @@ static ike_sa_t *checkout_new(private_ike_sa_manager_t* this, bool initiator)
{
id = ike_sa_id_create(0, get_next_spi(this), FALSE);
}
- entry = entry_create(id);
+ entry = entry_create(id);
+ id->destroy(id);
pthread_mutex_lock(&this->mutex);
this->ike_sa_list->insert_last(this->ike_sa_list, entry);
entry->checked_out = TRUE;
pthread_mutex_unlock(&this->mutex);
- DBG2(DBG_MGR, "created IKE_SA: %J, %d IKE_SAs in manager",
- id, this->ike_sa_list->get_count(this->ike_sa_list));
+ DBG2(DBG_MGR, "created IKE_SA, %d IKE_SAs in manager",
+ this->ike_sa_list->get_count(this->ike_sa_list));
return entry->ike_sa;
}
@@ -378,8 +379,8 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
id = id->clone(id);
id->switch_initiator(id);
- DBG2(DBG_MGR, "checkout IKE_SA: %J by message, %d IKE_SAs in manager",
- id, this->ike_sa_list->get_count(this->ike_sa_list));
+ DBG2(DBG_MGR, "checkout IKE_SA by message, %d IKE_SAs in manager",
+ this->ike_sa_list->get_count(this->ike_sa_list));
if (message->get_request(message) &&
message->get_exchange_type(message) == IKE_SA_INIT)
@@ -439,7 +440,8 @@ static ike_sa_t* checkout_by_message(private_ike_sa_manager_t* this,
}
else
{
- DBG1(DBG_MGR, "ignoring message for %J, no such IKE_SA", id);
+ chunk_free(&hash);
+ DBG1(DBG_MGR, "ignoring message, no such IKE_SA");
}
}
else
@@ -554,7 +556,7 @@ static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this,
/* create entry */
new_entry = entry_create(new_ike_sa_id);
- DBG2(DBG_MGR, "created IKE_SA: %J", new_ike_sa_id);
+ DBG2(DBG_MGR, "created IKE_SA");
new_ike_sa_id->destroy(new_ike_sa_id);
this->ike_sa_list->insert_last(this->ike_sa_list, new_entry);
@@ -720,7 +722,7 @@ static status_t checkin(private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
ike_sa_id = ike_sa->get_id(ike_sa);
- DBG2(DBG_MGR, "checkin IKE_SA: %J", ike_sa_id);
+ DBG2(DBG_MGR, "checkin IKE_SA");
pthread_mutex_lock(&(this->mutex));
@@ -767,7 +769,7 @@ static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ik
ike_sa_id_t *ike_sa_id;
ike_sa_id = ike_sa->get_id(ike_sa);
- DBG2(DBG_MGR, "checkin and destroy IKE_SA: %J", ike_sa_id);
+ DBG2(DBG_MGR, "checkin and destroy IKE_SA");
pthread_mutex_lock(&(this->mutex));
diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c
index 844300735..e67508ed1 100644
--- a/src/charon/sa/task_manager.c
+++ b/src/charon/sa/task_manager.c
@@ -22,6 +22,8 @@
#include "task_manager.h"
+#include <math.h>
+
#include <daemon.h>
#include <sa/tasks/ike_init.h>
#include <sa/tasks/ike_natd.h>
@@ -35,7 +37,7 @@
#include <sa/tasks/child_rekey.h>
#include <sa/tasks/child_delete.h>
#include <encoding/payloads/delete_payload.h>
-#include <queues/jobs/retransmit_job.h>
+#include <processing/jobs/retransmit_job.h>
typedef struct exchange_t exchange_t;
@@ -210,9 +212,12 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
u_int32_t timeout;
job_t *job;
- timeout = charon->configuration->get_retransmit_timeout(
- charon->configuration, this->initiating.retransmitted);
- if (timeout == 0)
+ if (this->initiating.retransmitted <= RETRANSMIT_TRIES)
+ {
+ timeout = (u_int32_t)(RETRANSMIT_TIMEOUT *
+ pow(RETRANSMIT_BASE, this->initiating.retransmitted));
+ }
+ else
{
DBG1(DBG_IKE, "giving up after %d retransmits",
this->initiating.retransmitted - 1);
@@ -262,6 +267,7 @@ static status_t build_request(private_task_manager_t *this)
case IKE_CREATED:
if (activate_task(this, IKE_INIT))
{
+ this->initiating.mid = 0;
exchange = IKE_SA_INIT;
activate_task(this, IKE_NATD);
activate_task(this, IKE_CERT);
@@ -274,7 +280,6 @@ static status_t build_request(private_task_manager_t *this)
if (activate_task(this, CHILD_CREATE))
{
exchange = CREATE_CHILD_SA;
- activate_task(this, IKE_CONFIG);
break;
}
if (activate_task(this, CHILD_DELETE))
@@ -328,6 +333,11 @@ static status_t build_request(private_task_manager_t *this)
case IKE_AUTHENTICATE:
exchange = IKE_AUTH;
break;
+ case CHILD_CREATE:
+ case CHILD_REKEY:
+ case IKE_REKEY:
+ exchange = CREATE_CHILD_SA;
+ break;
default:
continue;
}
@@ -577,7 +587,7 @@ static status_t process_request(private_task_manager_t *this,
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)ike_auth_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
- task = (task_t*)ike_config_create(this->ike_sa, NULL);
+ task = (task_t*)ike_config_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)child_create_create(this->ike_sa, NULL);
this->passive_tasks->insert_last(this->passive_tasks, task);
diff --git a/src/charon/sa/task_manager.h b/src/charon/sa/task_manager.h
index c766d4a65..fb34aab6a 100644
--- a/src/charon/sa/task_manager.h
+++ b/src/charon/sa/task_manager.h
@@ -31,6 +31,28 @@ typedef struct task_manager_t task_manager_t;
#include <sa/tasks/task.h>
/**
+ * First retransmit timeout in milliseconds.
+ *
+ * @ingroup sa
+ */
+#define RETRANSMIT_TIMEOUT 4000
+
+/**
+ * Base which is raised to the power of the retransmission try.
+ *
+ * @ingroup sa
+ */
+#define RETRANSMIT_BASE 1.8
+
+/**
+ * Number of retransmits done before giving up.
+ *
+ * @ingroup sa
+ */
+#define RETRANSMIT_TRIES 5
+
+
+/**
* @brief The task manager, juggles task and handles message exchanges.
*
* On incoming requests, the task manager creates new tasks on demand and
@@ -43,6 +65,24 @@ typedef struct task_manager_t task_manager_t;
* For the initial IKE_SA setup, several tasks are queued: One for the
* unauthenticated IKE_SA setup, one for authentication, one for CHILD_SA setup
* and maybe one for virtual IP assignement.
+ * The task manager is also responsible for retransmission. It uses a backoff
+ * algorithm. The timeout is calculated using
+ * RETRANSMIT_TIMEOUT * (RETRANSMIT_BASE ** try).
+ * When try reaches RETRANSMIT_TRIES, retransmission is given up.
+ *
+ * Using an initial TIMEOUT of 4s, a BASE of 1.8, and 5 TRIES gives us:
+ * @verbatim
+ | relative | absolute
+ ---------------------------------------------------------
+ 4s * (1.8 ** 0) = 4s 4s
+ 4s * (1.8 ** 1) = 7s 11s
+ 4s * (1.8 ** 2) = 13s 24s
+ 4s * (1.8 ** 3) = 23s 47s
+ 4s * (1.8 ** 4) = 42s 89s
+ 4s * (1.8 ** 5) = 76s 165s
+
+ @endberbatim
+ * The peer is considered dead after 2min 45s when no reply comes in.
*
* @b Constructors:
* - task_manager_create()
diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c
index 781d679f2..f70730b05 100644
--- a/src/charon/sa/tasks/child_create.c
+++ b/src/charon/sa/tasks/child_create.c
@@ -26,6 +26,7 @@
#include <daemon.h>
#include <crypto/diffie_hellman.h>
#include <encoding/payloads/sa_payload.h>
+#include <encoding/payloads/ke_payload.h>
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/notify_payload.h>
@@ -64,9 +65,9 @@ struct private_child_create_t {
chunk_t other_nonce;
/**
- * policy to create the CHILD_SA from
+ * config to create the CHILD_SA from
*/
- policy_t *policy;
+ child_cfg_t *config;
/**
* list of proposal candidates
@@ -89,6 +90,16 @@ struct private_child_create_t {
linked_list_t *tsr;
/**
+ * optional diffie hellman exchange
+ */
+ diffie_hellman_t *dh;
+
+ /**
+ * group used for DH exchange
+ */
+ diffie_hellman_group_t dh_group;
+
+ /**
* mode the new CHILD_SA uses (transport/tunnel/beet)
*/
mode_t mode;
@@ -162,21 +173,29 @@ static bool ts_list_is_host(linked_list_t *list, host_t *host)
}
/**
- * Install a CHILD_SA for usage
+ * Install a CHILD_SA for usage, return value:
+ * - FAILED: no acceptable proposal
+ * - INVALID_ARG: diffie hellman group inacceptable
+ * - NOT_FOUND: TS inacceptable
*/
-static status_t select_and_install(private_child_create_t *this)
+static status_t select_and_install(private_child_create_t *this, bool no_dh)
{
prf_plus_t *prf_plus;
status_t status;
- chunk_t nonce_i, nonce_r, seed;
+ chunk_t nonce_i, nonce_r, secret, seed;
linked_list_t *my_ts, *other_ts;
host_t *me, *other, *other_vip, *my_vip;
- if (this->proposals == NULL || this->tsi == NULL || this->tsr == NULL)
+ if (this->proposals == NULL)
{
- SIG(CHILD_UP_FAILED, "SA/TS payloads missing in message");
+ SIG(CHILD_UP_FAILED, "SA payload missing in message");
return FAILED;
}
+ if (this->tsi == NULL || this->tsr == NULL)
+ {
+ SIG(CHILD_UP_FAILED, "TS payloads missing in message");
+ return NOT_FOUND;
+ }
if (this->initiator)
{
@@ -198,36 +217,61 @@ static status_t select_and_install(private_child_create_t *this)
my_vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
other_vip = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
- this->proposal = this->policy->select_proposal(this->policy, this->proposals);
-
+ this->proposal = this->config->select_proposal(this->config, this->proposals,
+ no_dh);
if (this->proposal == NULL)
{
SIG(CHILD_UP_FAILED, "no acceptable proposal found");
return FAILED;
}
- if (this->initiator && my_vip)
- { /* if we have a virtual IP, shorten our TS to the minimum */
- my_ts = this->policy->select_my_traffic_selectors(this->policy, my_ts,
- my_vip);
+ if (!this->proposal->has_dh_group(this->proposal, this->dh_group))
+ {
+ algorithm_t *algo;
+ if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
+ &algo))
+ {
+ u_int16_t group = algo->algorithm;
+ SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N",
+ diffie_hellman_group_names, this->dh_group,
+ diffie_hellman_group_names, group);
+ this->dh_group = group;
+ return INVALID_ARG;
+ }
+ else
+ {
+ SIG(CHILD_UP_FAILED, "no acceptable proposal found");
+ return FAILED;
+ }
+ }
+
+ if (my_vip == NULL)
+ {
+ my_vip = me;
+ }
+ else if (this->initiator)
+ {
/* to setup firewall rules correctly, CHILD_SA needs the virtual IP */
this->child_sa->set_virtual_ip(this->child_sa, my_vip);
}
- else
- { /* shorten in the host2host case only */
- my_ts = this->policy->select_my_traffic_selectors(this->policy,
- my_ts, me);
- }
- if (other_vip)
- { /* if other has a virtual IP, shorten it's traffic selectors to it */
- other_ts = this->policy->select_other_traffic_selectors(this->policy,
- other_ts, other_vip);
+ if (other_vip == NULL)
+ {
+ other_vip = other;
}
- else
- { /* use his host for the host2host case */
- other_ts = this->policy->select_other_traffic_selectors(this->policy,
- other_ts, other);
+
+ my_ts = this->config->get_traffic_selectors(this->config, TRUE, my_ts,
+ my_vip);
+ other_ts = this->config->get_traffic_selectors(this->config, FALSE, other_ts,
+ other_vip);
+
+ if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0)
+ {
+ my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
+ other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
+ SIG(CHILD_UP_FAILED, "no acceptable traffic selectors found");
+ return NOT_FOUND;
}
+
this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
if (this->initiator)
@@ -241,13 +285,6 @@ static status_t select_and_install(private_child_create_t *this)
this->tsi = other_ts;
}
- if (this->tsi->get_count(this->tsi) == 0 ||
- this->tsr->get_count(this->tsr) == 0)
- {
- SIG(CHILD_UP_FAILED, "no acceptable traffic selectors found");
- return FAILED;
- }
-
if (!this->initiator)
{
/* check if requested mode is acceptable, downgrade if required */
@@ -279,7 +316,20 @@ static status_t select_and_install(private_child_create_t *this)
}
}
- seed = chunk_cata("cc", nonce_i, nonce_r);
+ if (this->dh)
+ {
+ if (this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
+ {
+ SIG(CHILD_UP_FAILED, "DH exchange incomplete");
+ return FAILED;
+ }
+ DBG3(DBG_IKE, "DH secret %B", &secret);
+ seed = chunk_cata("mcc", secret, nonce_i, nonce_r);
+ }
+ else
+ {
+ seed = chunk_cata("cc", nonce_i, nonce_r);
+ }
prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed);
if (this->initiator)
@@ -297,7 +347,7 @@ static status_t select_and_install(private_child_create_t *this)
if (status != SUCCESS)
{
SIG(CHILD_UP_FAILED, "unable to install IPsec SA (SAD) in kernel");
- return status;
+ return FAILED;
}
status = this->child_sa->add_policies(this->child_sa, my_ts, other_ts,
@@ -306,7 +356,7 @@ static status_t select_and_install(private_child_create_t *this)
if (status != SUCCESS)
{
SIG(CHILD_UP_FAILED, "unable to install IPsec policies (SPD) in kernel");
- return status;
+ return NOT_FOUND;
}
/* add to IKE_SA, and remove from task */
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
@@ -321,8 +371,9 @@ static status_t select_and_install(private_child_create_t *this)
static void build_payloads(private_child_create_t *this, message_t *message)
{
sa_payload_t *sa_payload;
- ts_payload_t *ts_payload;
nonce_payload_t *nonce_payload;
+ ke_payload_t *ke_payload;
+ ts_payload_t *ts_payload;
/* add SA payload */
if (this->initiator)
@@ -343,6 +394,13 @@ static void build_payloads(private_child_create_t *this, message_t *message)
message->add_payload(message, (payload_t*)nonce_payload);
}
+ /* diffie hellman exchange, if PFS enabled */
+ if (this->dh)
+ {
+ ke_payload = ke_payload_create_from_diffie_hellman(this->dh);
+ message->add_payload(message, (payload_t*)ke_payload);
+ }
+
/* add TSi/TSr payloads */
ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
message->add_payload(message, (payload_t*)ts_payload);
@@ -371,6 +429,7 @@ static void process_payloads(private_child_create_t *this, message_t *message)
iterator_t *iterator;
payload_t *payload;
sa_payload_t *sa_payload;
+ ke_payload_t *ke_payload;
ts_payload_t *ts_payload;
notify_payload_t *notify_payload;
@@ -386,6 +445,19 @@ static void process_payloads(private_child_create_t *this, message_t *message)
sa_payload = (sa_payload_t*)payload;
this->proposals = sa_payload->get_proposals(sa_payload);
break;
+ case KEY_EXCHANGE:
+ ke_payload = (ke_payload_t*)payload;
+ if (!this->initiator)
+ {
+ this->dh_group = ke_payload->get_dh_group_number(ke_payload);
+ this->dh = diffie_hellman_create(this->dh_group);
+ }
+ if (this->dh)
+ {
+ this->dh->set_other_public_value(this->dh,
+ ke_payload->get_key_exchange_data(ke_payload));
+ }
+ break;
case TRAFFIC_SELECTOR_INITIATOR:
ts_payload = (ts_payload_t*)payload;
this->tsi = ts_payload->get_traffic_selectors(ts_payload);
@@ -421,6 +493,7 @@ static void process_payloads(private_child_create_t *this, message_t *message)
static status_t build_i(private_child_create_t *this, message_t *message)
{
host_t *me, *other, *vip;
+ peer_cfg_t *peer_cfg;
switch (message->get_exchange_type(message))
{
@@ -432,6 +505,10 @@ static status_t build_i(private_child_create_t *this, message_t *message)
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
+ if (this->dh_group == MODP_NONE)
+ {
+ this->dh_group = this->config->get_dh_group(this->config);
+ }
break;
case IKE_AUTH:
if (!message->get_payload(message, ID_INITIATOR))
@@ -448,25 +525,30 @@ static status_t build_i(private_child_create_t *this, message_t *message)
me = this->ike_sa->get_my_host(this->ike_sa);
other = this->ike_sa->get_other_host(this->ike_sa);
- vip = this->policy->get_virtual_ip(this->policy, NULL);
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ vip = peer_cfg->get_my_virtual_ip(peer_cfg);
if (vip)
{ /* propose a 0.0.0.0/0 subnet when we use virtual ip */
- this->tsi = this->policy->get_my_traffic_selectors(this->policy, NULL);
+ this->tsi = this->config->get_traffic_selectors(this->config, TRUE,
+ NULL, NULL);
vip->destroy(vip);
}
else
{ /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */
- this->tsi = this->policy->get_my_traffic_selectors(this->policy, me);
+ this->tsi = this->config->get_traffic_selectors(this->config, TRUE,
+ NULL, me);
}
- this->tsr = this->policy->get_other_traffic_selectors(this->policy, other);
- this->proposals = this->policy->get_proposals(this->policy);
- this->mode = this->policy->get_mode(this->policy);
+ this->tsr = this->config->get_traffic_selectors(this->config, FALSE,
+ NULL, other);
+ this->proposals = this->config->get_proposals(this->config,
+ this->dh_group == MODP_NONE);
+ this->mode = this->config->get_mode(this->config);
this->child_sa = child_sa_create(me, other,
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa),
- this->policy, this->reqid,
+ this->config, this->reqid,
this->ike_sa->is_natt_enabled(this->ike_sa));
if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
@@ -475,6 +557,11 @@ static status_t build_i(private_child_create_t *this, message_t *message)
return FAILED;
}
+ if (this->dh_group != MODP_NONE)
+ {
+ this->dh = diffie_hellman_create(this->dh_group);
+ }
+
build_payloads(this, message);
this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
@@ -492,6 +579,8 @@ static status_t build_i(private_child_create_t *this, message_t *message)
*/
static status_t process_r(private_child_create_t *this, message_t *message)
{
+ peer_cfg_t *peer_cfg;
+
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
@@ -517,18 +606,13 @@ static status_t process_r(private_child_create_t *this, message_t *message)
return NEED_MORE;
}
- this->policy = charon->policies->get_policy(charon->policies,
- this->ike_sa->get_my_id(this->ike_sa),
- this->ike_sa->get_other_id(this->ike_sa),
- this->tsr, this->tsi,
- this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa));
-
- if (this->policy && this->ike_sa->get_policy(this->ike_sa) == NULL)
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (peer_cfg)
{
- this->ike_sa->set_policy(this->ike_sa, this->policy);
+ this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, this->tsi,
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa));
}
-
return NEED_MORE;
}
@@ -537,6 +621,8 @@ static status_t process_r(private_child_create_t *this, message_t *message)
*/
static status_t build_r(private_child_create_t *this, message_t *message)
{
+ bool no_dh = TRUE;
+
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
@@ -547,6 +633,7 @@ static status_t build_r(private_child_create_t *this, message_t *message)
message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
return SUCCESS;
}
+ no_dh = FALSE;
break;
case IKE_AUTH:
if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
@@ -565,10 +652,11 @@ static status_t build_r(private_child_create_t *this, message_t *message)
return SUCCESS;
}
- if (this->policy == NULL)
+ if (this->config == NULL)
{
- SIG(CHILD_UP_FAILED, "no acceptable policy found");
- message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ SIG(CHILD_UP_FAILED, "traffic selectors %#R=== %#R inacceptable",
+ this->tsr, this->tsi);
+ message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
return SUCCESS;
}
@@ -576,13 +664,27 @@ static status_t build_r(private_child_create_t *this, message_t *message)
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa),
- this->policy, this->reqid,
+ this->config, this->reqid,
this->ike_sa->is_natt_enabled(this->ike_sa));
- if (select_and_install(this) != SUCCESS)
+ switch (select_and_install(this, no_dh))
{
- message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
- return SUCCESS;
+ case SUCCESS:
+ break;
+ case NOT_FOUND:
+ message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
+ return SUCCESS;
+ case INVALID_ARG:
+ {
+ u_int16_t group = htons(this->dh_group);
+ message->add_notify(message, FALSE, INVALID_KE_PAYLOAD,
+ chunk_from_thing(group));
+ return SUCCESS;
+ }
+ case FAILED:
+ default:
+ message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
+ return SUCCESS;
}
build_payloads(this, message);
@@ -599,6 +701,7 @@ static status_t process_i(private_child_create_t *this, message_t *message)
{
iterator_t *iterator;
payload_t *payload;
+ bool no_dh = TRUE;
switch (message->get_exchange_type(message))
{
@@ -606,6 +709,7 @@ static status_t process_i(private_child_create_t *this, message_t *message)
return get_nonce(message, &this->other_nonce);
case CREATE_CHILD_SA:
get_nonce(message, &this->other_nonce);
+ no_dh = FALSE;
break;
case IKE_AUTH:
if (message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
@@ -643,6 +747,22 @@ static status_t process_i(private_child_create_t *this, message_t *message)
/* an error in CHILD_SA creation is not critical */
return SUCCESS;
}
+ case INVALID_KE_PAYLOAD:
+ {
+ chunk_t data;
+ diffie_hellman_group_t bad_group;
+
+ bad_group = this->dh_group;
+ data = notify->get_notification_data(notify);
+ this->dh_group = ntohs(*((u_int16_t*)data.ptr));
+ DBG1(DBG_IKE, "peer didn't accept DH group %N, "
+ "it requested %N", diffie_hellman_group_names,
+ bad_group, diffie_hellman_group_names, this->dh_group);
+
+ this->public.task.migrate(&this->public.task, this->ike_sa);
+ iterator->destroy(iterator);
+ return NEED_MORE;
+ }
default:
break;
}
@@ -652,7 +772,7 @@ static status_t process_i(private_child_create_t *this, message_t *message)
process_payloads(this, message);
- if (select_and_install(this) == SUCCESS)
+ if (select_and_install(this, no_dh) == SUCCESS)
{
SIG(CHILD_UP_SUCCESS, "established CHILD_SA successfully");
}
@@ -716,6 +836,7 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa)
}
DESTROY_IF(this->child_sa);
DESTROY_IF(this->proposal);
+ DESTROY_IF(this->dh);
if (this->proposals)
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
@@ -725,6 +846,7 @@ static void migrate(private_child_create_t *this, ike_sa_t *ike_sa)
this->proposals = NULL;
this->tsi = NULL;
this->tsr = NULL;
+ this->dh = NULL;
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
this->reqid = 0;
@@ -751,19 +873,20 @@ static void destroy(private_child_create_t *this)
DESTROY_IF(this->child_sa);
}
DESTROY_IF(this->proposal);
+ DESTROY_IF(this->dh);
if (this->proposals)
{
this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
}
- DESTROY_IF(this->policy);
+ DESTROY_IF(this->config);
free(this);
}
/*
* Described in header.
*/
-child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy)
+child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config)
{
private_child_create_t *this = malloc_thing(private_child_create_t);
@@ -773,12 +896,12 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy)
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
- if (policy)
+ if (config)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
- policy->get_ref(policy);
+ config->get_ref(config);
}
else
{
@@ -788,13 +911,15 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy)
}
this->ike_sa = ike_sa;
- this->policy = policy;
+ this->config = config;
this->my_nonce = chunk_empty;
this->other_nonce = chunk_empty;
this->proposals = NULL;
this->proposal = NULL;
this->tsi = NULL;
this->tsr = NULL;
+ this->dh = NULL;
+ this->dh_group = MODP_NONE;
this->child_sa = NULL;
this->mode = MODE_TUNNEL;
this->reqid = 0;
diff --git a/src/charon/sa/tasks/child_create.h b/src/charon/sa/tasks/child_create.h
index 200d37457..9f4815215 100644
--- a/src/charon/sa/tasks/child_create.h
+++ b/src/charon/sa/tasks/child_create.h
@@ -28,7 +28,7 @@ typedef struct child_create_t child_create_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
-#include <config/policies/policy.h>
+#include <config/child_cfg.h>
/**
* @brief Task of type CHILD_CREATE, established a new CHILD_SA.
@@ -80,9 +80,9 @@ struct child_create_t {
* @brief Create a new child_create task.
*
* @param ike_sa IKE_SA this task works for
- * @param policy policy if task initiator, NULL if responder
+ * @param config child_cfg if task initiator, NULL if responder
* @return child_create task to handle by the task_manager
*/
-child_create_t *child_create_create(ike_sa_t *ike_sa, policy_t *policy);
+child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config);
#endif /* CHILD_CREATE_H_ */
diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c
index 23d509de5..d0b34a276 100644
--- a/src/charon/sa/tasks/child_delete.c
+++ b/src/charon/sa/tasks/child_delete.c
@@ -177,10 +177,29 @@ static void destroy_children(private_child_delete_t *this)
}
/**
+ * send closing signals for all CHILD_SAs over the bus
+ */
+static void log_children(private_child_delete_t *this)
+{
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ SIG(CHILD_DOWN_START, "closing CHILD_SA %#R=== %#R",
+ child_sa->get_traffic_selectors(child_sa, TRUE),
+ child_sa->get_traffic_selectors(child_sa, FALSE));
+ }
+ iterator->destroy(iterator);
+}
+
+/**
* Implementation of task_t.build for initiator
*/
static status_t build_i(private_child_delete_t *this, message_t *message)
{
+ log_children(this);
build_payloads(this, message);
return NEED_MORE;
}
@@ -196,6 +215,7 @@ static status_t process_i(private_child_delete_t *this, message_t *message)
process_payloads(this, message);
destroy_children(this);
+ SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed");
return SUCCESS;
}
@@ -205,6 +225,7 @@ static status_t process_i(private_child_delete_t *this, message_t *message)
static status_t process_r(private_child_delete_t *this, message_t *message)
{
process_payloads(this, message);
+ log_children(this);
return NEED_MORE;
}
@@ -219,6 +240,7 @@ static status_t build_r(private_child_delete_t *this, message_t *message)
build_payloads(this, message);
}
destroy_children(this);
+ SIG(CHILD_DOWN_SUCCESS, "CHILD_SA closed");
return SUCCESS;
}
diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c
index 745895dbb..4f3c69034 100644
--- a/src/charon/sa/tasks/child_rekey.c
+++ b/src/charon/sa/tasks/child_rekey.c
@@ -27,7 +27,7 @@
#include <encoding/payloads/notify_payload.h>
#include <sa/tasks/child_create.h>
#include <sa/tasks/child_delete.h>
-#include <queues/jobs/rekey_child_sa_job.h>
+#include <processing/jobs/rekey_child_sa_job.h>
typedef struct private_child_rekey_t private_child_rekey_t;
@@ -183,7 +183,12 @@ static status_t process_i(private_child_rekey_t *this, message_t *message)
u_int32_t spi;
child_sa_t *to_delete;
- this->child_create->task.process(&this->child_create->task, message);
+ if (this->child_create->task.process(&this->child_create->task, message) == NEED_MORE)
+ {
+ /* bad DH group while rekeying, try again */
+ this->child_create->task.migrate(&this->child_create->task, this->ike_sa);
+ return NEED_MORE;
+ }
if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
{
/* establishing new child failed, reuse old. but not when we
@@ -192,8 +197,8 @@ static status_t process_i(private_child_rekey_t *this, message_t *message)
this->collision->get_type(this->collision) == CHILD_DELETE))
{
job_t *job;
- u_int32_t retry = charon->configuration->get_retry_interval(
- charon->configuration);
+ u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
+
job = (job_t*)rekey_child_sa_job_create(
this->child_sa->get_reqid(this->child_sa),
this->child_sa->get_protocol(this->child_sa),
@@ -315,8 +320,8 @@ static void destroy(private_child_rekey_t *this)
*/
child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
{
+ child_cfg_t *config;
private_child_rekey_t *this = malloc_thing(private_child_rekey_t);
- policy_t *policy;
this->public.collide = (void (*)(child_rekey_t*,task_t*))collide;
this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
@@ -327,8 +332,8 @@ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, child_sa_t *child_sa)
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
this->initiator = TRUE;
- policy = child_sa->get_policy(child_sa);
- this->child_create = child_create_create(ike_sa, policy);
+ config = child_sa->get_config(child_sa);
+ this->child_create = child_create_create(ike_sa, config);
}
else
{
diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c
index 541e1bb37..d0dd49aee 100644
--- a/src/charon/sa/tasks/ike_auth.c
+++ b/src/charon/sa/tasks/ike_auth.c
@@ -100,18 +100,18 @@ static status_t build_auth(private_ike_auth_t *this, message_t *message)
{
authenticator_t *auth;
auth_payload_t *auth_payload;
- policy_t *policy;
+ peer_cfg_t *config;
auth_method_t method;
status_t status;
/* create own authenticator and add auth payload */
- policy = this->ike_sa->get_policy(this->ike_sa);
- if (!policy)
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (!config)
{
- SIG(IKE_UP_FAILED, "unable to authenticate, no policy found");
+ SIG(IKE_UP_FAILED, "unable to authenticate, no peer config found");
return FAILED;
}
- method = policy->get_auth_method(policy);
+ method = config->get_auth_method(config);
auth = authenticator_create(this->ike_sa, method);
if (auth == NULL)
@@ -140,15 +140,15 @@ static status_t build_id(private_ike_auth_t *this, message_t *message)
{
identification_t *me, *other;
id_payload_t *id;
- policy_t *policy;
+ peer_cfg_t *config;
me = this->ike_sa->get_my_id(this->ike_sa);
other = this->ike_sa->get_other_id(this->ike_sa);
- policy = this->ike_sa->get_policy(this->ike_sa);
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
if (me->contains_wildcards(me))
{
- me = policy->get_my_id(policy);
+ me = config->get_my_id(config);
if (me->contains_wildcards(me))
{
SIG(IKE_UP_FAILED, "negotiation of own ID failed");
@@ -202,7 +202,7 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message)
auth->destroy(auth);
if (status != SUCCESS)
{
- SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
+ SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed",
this->ike_sa->get_other_id(this->ike_sa),
auth_method_names, auth_method);
return FAILED;
@@ -215,7 +215,7 @@ static status_t process_auth(private_ike_auth_t *this, message_t *message)
*/
static status_t process_id(private_ike_auth_t *this, message_t *message)
{
- identification_t *id;
+ identification_t *id, *req;
id_payload_t *idr, *idi;
idi = (id_payload_t*)message->get_payload(message, ID_INITIATOR);
@@ -230,6 +230,13 @@ static status_t process_id(private_ike_auth_t *this, message_t *message)
if (this->initiator)
{
id = idr->get_identification(idr);
+ req = this->ike_sa->get_other_id(this->ike_sa);
+ if (!id->matches(id, req, NULL))
+ {
+ SIG(IKE_UP_FAILED, "peer ID %D unacceptable, %D required", id, req);
+ id->destroy(id);
+ return FAILED;
+ }
this->ike_sa->set_other_id(this->ike_sa, id);
}
else
@@ -346,7 +353,7 @@ static status_t process_auth_eap(private_ike_auth_t *this, message_t *message)
if (!this->peer_authenticated)
{
- SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
+ SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed",
this->ike_sa->get_other_id(this->ike_sa),
auth_method_names, AUTH_EAP);
if (this->initiator)
@@ -444,7 +451,7 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message)
this->public.task.process = (status_t(*)(task_t*,message_t*))process_auth_eap;
break;
default:
- SIG(IKE_UP_FAILED, "authentication of %D using %N failed",
+ SIG(IKE_UP_FAILED, "authentication of '%D' with %N failed",
this->ike_sa->get_other_id(this->ike_sa),
auth_method_names, AUTH_EAP);
status = FAILED;
@@ -459,7 +466,7 @@ static status_t build_eap_r(private_ike_auth_t *this, message_t *message)
*/
static status_t build_i(private_ike_auth_t *this, message_t *message)
{
- policy_t *policy;
+ peer_cfg_t *config;
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
@@ -471,8 +478,8 @@ static status_t build_i(private_ike_auth_t *this, message_t *message)
return FAILED;
}
- policy = this->ike_sa->get_policy(this->ike_sa);
- if (policy->get_auth_method(policy) == AUTH_EAP)
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (config->get_auth_method(config) == AUTH_EAP)
{
this->eap_auth = eap_authenticator_create(this->ike_sa);
}
@@ -488,10 +495,12 @@ static status_t build_i(private_ike_auth_t *this, message_t *message)
}
/**
- * Implementation of task_t.process for initiator
+ * Implementation of task_t.process for responder
*/
static status_t process_r(private_ike_auth_t *this, message_t *message)
-{
+{
+ peer_cfg_t *config;
+
if (message->get_exchange_type(message) == IKE_SA_INIT)
{
return collect_other_init_data(this, message);
@@ -514,6 +523,17 @@ static status_t process_r(private_ike_auth_t *this, message_t *message)
default:
break;
}
+
+ config = charon->backends->get_peer_cfg(charon->backends,
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa),
+ this->ike_sa->get_other_ca(this->ike_sa));
+ if (config)
+ {
+ this->ike_sa->set_peer_cfg(this->ike_sa, config);
+ config->destroy(config);
+ }
+
return NEED_MORE;
}
@@ -522,7 +542,7 @@ static status_t process_r(private_ike_auth_t *this, message_t *message)
*/
static status_t build_r(private_ike_auth_t *this, message_t *message)
{
- policy_t *policy;
+ peer_cfg_t *config;
eap_type_t eap_type;
eap_payload_t *eap_payload;
status_t status;
@@ -532,10 +552,12 @@ static status_t build_r(private_ike_auth_t *this, message_t *message)
return collect_my_init_data(this, message);
}
- policy = this->ike_sa->get_policy(this->ike_sa);
- if (policy == NULL)
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (config == NULL)
{
- SIG(IKE_UP_FAILED, "no acceptable policy found");
+ SIG(IKE_UP_FAILED, "no matching config found for %D...%D",
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa));
message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
return FAILED;
}
@@ -567,7 +589,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message)
}
/* initiate EAP authenitcation */
- eap_type = policy->get_eap_type(policy);
+ eap_type = config->get_eap_type(config);
status = this->eap_auth->initiate(this->eap_auth, eap_type, &eap_payload);
message->add_payload(message, (payload_t*)eap_payload);
if (status != NEED_MORE)
diff --git a/src/charon/sa/tasks/ike_cert.c b/src/charon/sa/tasks/ike_cert.c
index 160600742..880ed9c42 100644
--- a/src/charon/sa/tasks/ike_cert.c
+++ b/src/charon/sa/tasks/ike_cert.c
@@ -84,7 +84,7 @@ static void process_certreqs(private_ike_cert_t *this, message_t *message)
encoding = certreq->get_cert_encoding(certreq);
if (encoding != CERT_X509_SIGNATURE)
{
- DBG1(DBG_IKE, "certreq payload %N not supported, ignored",
+ DBG1(DBG_IKE, "certreq payload %N not supported - ignored",
cert_encoding_names, encoding);
continue;
}
@@ -125,7 +125,7 @@ static void process_certs(private_ike_cert_t *this, message_t *message)
encoding = cert_payload->get_cert_encoding(cert_payload);
if (encoding != CERT_X509_SIGNATURE)
{
- DBG1(DBG_IKE, "certificate payload %N not supported, ignored",
+ DBG1(DBG_IKE, "certificate payload %N not supported - ignored",
cert_encoding_names, encoding);
continue;
}
@@ -134,31 +134,29 @@ static void process_certs(private_ike_cert_t *this, message_t *message)
cert = x509_create_from_chunk(cert_data, 0);
if (cert)
{
- if (charon->credentials->verify(charon->credentials,
- cert, &found))
+ if (charon->credentials->verify(charon->credentials, cert, &found))
{
- DBG2(DBG_IKE, "received end entity certificate is trusted, "
- "added to store");
- if (!found)
+ DBG2(DBG_IKE, "received end entity certificate is trusted - "
+ "added to store");
+ if (found)
{
- charon->credentials->add_end_certificate(
- charon->credentials, cert);
+ cert->destroy(cert);
}
else
{
- cert->destroy(cert);
+ charon->credentials->add_end_certificate(charon->credentials, cert);
}
}
else
{
- DBG1(DBG_IKE, "received end entity certificate is not "
- "trusted, discarded");
+ DBG1(DBG_IKE, "received end entity certificate is not trusted - "
+ "discarded");
cert->destroy(cert);
}
}
else
{
- DBG1(DBG_IKE, "parsing of received certificate failed, discarded");
+ DBG1(DBG_IKE, "parsing of received certificate failed - discarded");
chunk_free(&cert_data);
}
}
@@ -171,20 +169,20 @@ static void process_certs(private_ike_cert_t *this, message_t *message)
*/
static void build_certreqs(private_ike_cert_t *this, message_t *message)
{
- connection_t *connection;
- policy_t *policy;
+ ike_cfg_t *ike_cfg;
+ peer_cfg_t *peer_cfg;
identification_t *ca;
certreq_payload_t *certreq;
- connection = this->ike_sa->get_connection(this->ike_sa);
+ ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
- if (connection->get_certreq_policy(connection) != CERT_NEVER_SEND)
+ if (ike_cfg->send_certreq(ike_cfg) != CERT_NEVER_SEND)
{
- policy = this->ike_sa->get_policy(this->ike_sa);
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (policy)
+ if (peer_cfg)
{
- ca = policy->get_other_ca(policy);
+ ca = peer_cfg->get_other_ca(peer_cfg);
if (ca && ca->get_type(ca) != ID_ANY)
{
@@ -212,17 +210,15 @@ static void build_certreqs(private_ike_cert_t *this, message_t *message)
*/
static void build_certs(private_ike_cert_t *this, message_t *message)
{
- policy_t *policy;
- connection_t *connection;
+ peer_cfg_t *peer_cfg;
x509_t *cert;
cert_payload_t *payload;
- policy = this->ike_sa->get_policy(this->ike_sa);
- connection = this->ike_sa->get_connection(this->ike_sa);
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (policy && policy->get_auth_method(policy) == AUTH_RSA)
+ if (peer_cfg && peer_cfg->get_auth_method(peer_cfg) == AUTH_RSA)
{
- switch (connection->get_cert_policy(connection))
+ switch (peer_cfg->get_cert_policy(peer_cfg))
{
case CERT_NEVER_SEND:
break;
@@ -236,7 +232,7 @@ static void build_certs(private_ike_cert_t *this, message_t *message)
{
/* TODO: respect CA cert request */
cert = charon->credentials->get_certificate(charon->credentials,
- policy->get_my_id(policy));
+ peer_cfg->get_my_id(peer_cfg));
if (cert)
{
payload = cert_payload_create_from_x509(cert);
diff --git a/src/charon/sa/tasks/ike_config.c b/src/charon/sa/tasks/ike_config.c
index ce29b9220..3c73395a5 100644
--- a/src/charon/sa/tasks/ike_config.c
+++ b/src/charon/sa/tasks/ike_config.c
@@ -49,11 +49,6 @@ struct private_ike_config_t {
bool initiator;
/**
- * associated policy with virtual IP configuration
- */
- policy_t *policy;
-
- /**
* virtual ip
*/
host_t *virtual_ip;
@@ -266,7 +261,20 @@ static status_t build_i(private_ike_config_t *this, message_t *message)
if (message->get_exchange_type(message) == IKE_AUTH &&
message->get_payload(message, ID_INITIATOR))
{
- this->virtual_ip = this->policy->get_virtual_ip(this->policy, NULL);
+ peer_cfg_t *config;
+ host_t *vip;
+
+ /* reuse virtual IP if we already have one */
+ vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
+ if (vip)
+ {
+ this->virtual_ip = vip->clone(vip);
+ }
+ else
+ {
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ this->virtual_ip = config->get_my_virtual_ip(config);
+ }
build_payloads(this, message, CFG_REQUEST);
}
@@ -295,17 +303,18 @@ static status_t build_r(private_ike_config_t *this, message_t *message)
if (message->get_exchange_type(message) == IKE_AUTH &&
message->get_payload(message, EXTENSIBLE_AUTHENTICATION) == NULL)
{
- this->policy = this->ike_sa->get_policy(this->ike_sa);
+ peer_cfg_t *config = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (this->policy && this->virtual_ip)
+ if (config && this->virtual_ip)
{
host_t *ip;
DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip);
- ip = this->policy->get_virtual_ip(this->policy, this->virtual_ip);
+ ip = config->get_other_virtual_ip(config, this->virtual_ip);
if (ip == NULL || ip->is_anyaddr(ip))
{
DBG1(DBG_IKE, "not assigning a virtual IP to peer");
+ DESTROY_IF(ip);
return SUCCESS;
}
DBG1(DBG_IKE, "assigning virtual IP %H to peer", ip);
@@ -340,13 +349,20 @@ static status_t process_i(private_ike_config_t *this, message_t *message)
!message->get_payload(message, EXTENSIBLE_AUTHENTICATION))
{
host_t *ip;
+ peer_cfg_t *config;
DESTROY_IF(this->virtual_ip);
this->virtual_ip = NULL;
process_payloads(this, message);
+
+ if (this->virtual_ip == NULL)
+ { /* force a configured virtual IP, even server didn't return one */
+ config = this->ike_sa->get_peer_cfg(this->ike_sa);
+ this->virtual_ip = config->get_my_virtual_ip(config);
+ }
- if (this->virtual_ip)
+ if (this->virtual_ip && !this->virtual_ip->is_anyaddr(this->virtual_ip))
{
this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip);
@@ -398,7 +414,7 @@ static void destroy(private_ike_config_t *this)
/*
* Described in header.
*/
-ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy)
+ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
{
private_ike_config_t *this = malloc_thing(private_ike_config_t);
@@ -406,21 +422,18 @@ ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy)
this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
this->public.task.destroy = (void(*)(task_t*))destroy;
- if (policy)
+ if (initiator)
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
- this->initiator = TRUE;
}
else
{
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
- this->initiator = FALSE;
}
-
+ this->initiator = initiator;
this->ike_sa = ike_sa;
- this->policy = policy;
this->virtual_ip = NULL;
this->dns = linked_list_create();
diff --git a/src/charon/sa/tasks/ike_config.h b/src/charon/sa/tasks/ike_config.h
index 0c9b961b4..a7cfddff0 100644
--- a/src/charon/sa/tasks/ike_config.h
+++ b/src/charon/sa/tasks/ike_config.h
@@ -28,7 +28,6 @@ typedef struct ike_config_t ike_config_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/tasks/task.h>
-#include <config/policies/policy.h>
/**
* @brief Task of type IKE_CONFIG, sets up a virtual IP and other
@@ -51,9 +50,9 @@ struct ike_config_t {
* @brief Create a new ike_config task.
*
* @param ike_sa IKE_SA this task works for
- * @param policy policy for the initiator, NULL for the responder
+ * @param initiator TRUE for initiator
* @return ike_config task to handle by the task_manager
*/
-ike_config_t *ike_config_create(ike_sa_t *ike_sa, policy_t *policy);
+ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator);
#endif /* IKE_CONFIG_H_ */
diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c
index 9c4fdac0e..1a3656ca6 100644
--- a/src/charon/sa/tasks/ike_delete.c
+++ b/src/charon/sa/tasks/ike_delete.c
@@ -28,7 +28,7 @@
typedef struct private_ike_delete_t private_ike_delete_t;
-/**
+/**file
* Private members of a ike_delete_t task.
*/
struct private_ike_delete_t {
@@ -94,7 +94,6 @@ static status_t process_r(private_ike_delete_t *this, message_t *message)
DBG1(DBG_IKE, "deleting IKE_SA on request");
break;
case IKE_REKEYING:
- DBG1(DBG_IKE, "initiated rekeying, but received delete for IKE_SA");
break;
default:
break;
diff --git a/src/charon/sa/tasks/ike_init.c b/src/charon/sa/tasks/ike_init.c
index 0b493666a..f78b5dd66 100644
--- a/src/charon/sa/tasks/ike_init.c
+++ b/src/charon/sa/tasks/ike_init.c
@@ -57,9 +57,9 @@ struct private_ike_init_t {
bool initiator;
/**
- * Connection established by this IKE_SA
+ * IKE config to establish
*/
- connection_t *connection;
+ ike_cfg_t *config;
/**
* diffie hellman group to use
@@ -69,7 +69,7 @@ struct private_ike_init_t {
/**
* Diffie hellman object used to generate public DH value.
*/
- diffie_hellman_t *diffie_hellman;
+ diffie_hellman_t *dh;
/**
* nonce chosen by us
@@ -117,11 +117,11 @@ static void build_payloads(private_ike_init_t *this, message_t *message)
id = this->ike_sa->get_id(this->ike_sa);
- this->connection = this->ike_sa->get_connection(this->ike_sa);
+ this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
if (this->initiator)
{
- proposal_list = this->connection->get_proposals(this->connection);
+ proposal_list = this->config->get_proposals(this->config);
if (this->old_sa)
{
/* include SPI of new IKE_SA when we are rekeying */
@@ -151,7 +151,7 @@ static void build_payloads(private_ike_init_t *this, message_t *message)
nonce_payload->set_nonce(nonce_payload, this->my_nonce);
message->add_payload(message, (payload_t*)nonce_payload);
- ke_payload = ke_payload_create_from_diffie_hellman(this->diffie_hellman);
+ ke_payload = ke_payload_create_from_diffie_hellman(this->dh);
message->add_payload(message, (payload_t*)ke_payload);
}
@@ -174,8 +174,8 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
linked_list_t *proposal_list;
proposal_list = sa_payload->get_proposals(sa_payload);
- this->proposal = this->connection->select_proposal(
- this->connection, proposal_list);
+ this->proposal = this->config->select_proposal(this->config,
+ proposal_list);
proposal_list->destroy_offset(proposal_list,
offsetof(proposal_t, destroy));
break;
@@ -183,34 +183,16 @@ static void process_payloads(private_ike_init_t *this, message_t *message)
case KEY_EXCHANGE:
{
ke_payload_t *ke_payload = (ke_payload_t*)payload;
- diffie_hellman_group_t dh_group;
- chunk_t key_data;
- dh_group = ke_payload->get_dh_group_number(ke_payload);
-
- if (this->initiator)
+ this->dh_group = ke_payload->get_dh_group_number(ke_payload);
+ if (!this->initiator)
{
- if (dh_group != this->dh_group)
- {
- DBG1(DBG_IKE, "received a DH group not requested (%N)",
- diffie_hellman_group_names, dh_group);
- break;
- }
+ this->dh = diffie_hellman_create(this->dh_group);
}
- else
+ if (this->dh)
{
- this->dh_group = dh_group;
- if (!this->connection->check_dh_group(this->connection,
- dh_group))
- {
- break;
- }
- this->diffie_hellman = diffie_hellman_create(dh_group);
- }
- if (this->diffie_hellman)
- {
- key_data = ke_payload->get_key_exchange_data(ke_payload);
- this->diffie_hellman->set_other_public_value(this->diffie_hellman, key_data);
+ this->dh->set_other_public_value(this->dh,
+ ke_payload->get_key_exchange_data(ke_payload));
}
break;
}
@@ -235,9 +217,9 @@ static status_t build_i(private_ike_init_t *this, message_t *message)
randomizer_t *randomizer;
status_t status;
- this->connection = this->ike_sa->get_connection(this->ike_sa);
+ this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
SIG(IKE_UP_START, "initiating IKE_SA to %H",
- this->connection->get_other_host(this->connection));
+ this->config->get_other_host(this->config));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
if (this->retry++ >= MAX_RETRIES)
@@ -247,11 +229,11 @@ static status_t build_i(private_ike_init_t *this, message_t *message)
}
/* if the DH group is set via use_dh_group(), we already have a DH object */
- if (!this->diffie_hellman)
+ if (!this->dh)
{
- this->dh_group = this->connection->get_dh_group(this->connection);
- this->diffie_hellman = diffie_hellman_create(this->dh_group);
- if (this->diffie_hellman == NULL)
+ this->dh_group = this->config->get_dh_group(this->config);
+ this->dh = diffie_hellman_create(this->dh_group);
+ if (this->dh == NULL)
{
SIG(IKE_UP_FAILED, "configured DH group %N not supported",
diffie_hellman_group_names, this->dh_group);
@@ -291,7 +273,7 @@ static status_t process_r(private_ike_init_t *this, message_t *message)
{
randomizer_t *randomizer;
- this->connection = this->ike_sa->get_connection(this->ike_sa);
+ this->config = this->ike_sa->get_ike_cfg(this->ike_sa);
SIG(IKE_UP_FAILED, "%H is initiating an IKE_SA",
message->get_source(message));
this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING);
@@ -326,25 +308,29 @@ static status_t build_r(private_ike_init_t *this, message_t *message)
return FAILED;
}
- if (this->diffie_hellman == NULL ||
- this->diffie_hellman->get_shared_secret(this->diffie_hellman,
- &secret) != SUCCESS)
+ if (this->dh == NULL ||
+ !this->proposal->has_dh_group(this->proposal, this->dh_group) ||
+ this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
{
- chunk_t chunk;
- u_int16_t dh_enc;
-
- SIG(IKE_UP_FAILED, "received inacceptable DH group (%N)",
- diffie_hellman_group_names, this->dh_group);
- this->dh_group = this->connection->get_dh_group(this->connection);
- dh_enc = htons(this->dh_group);
- chunk.ptr = (u_int8_t*)&dh_enc;
- chunk.len = sizeof(dh_enc);
- message->add_notify(message, TRUE, INVALID_KE_PAYLOAD, chunk);
- DBG1(DBG_IKE, "requesting DH group %N",
- diffie_hellman_group_names, this->dh_group);
+ algorithm_t *algo;
+ if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
+ &algo))
+ {
+ u_int16_t group = algo->algorithm;
+ SIG(CHILD_UP_FAILED, "DH group %N inacceptable, requesting %N",
+ diffie_hellman_group_names, this->dh_group,
+ diffie_hellman_group_names, group);
+ this->dh_group = group;
+ group = htons(group);
+ message->add_notify(message, FALSE, INVALID_KE_PAYLOAD,
+ chunk_from_thing(group));
+ }
+ else
+ {
+ SIG(IKE_UP_FAILED, "no acceptable proposal found");
+ }
return FAILED;
}
-
if (this->old_sa)
{
@@ -405,27 +391,20 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
case INVALID_KE_PAYLOAD:
{
chunk_t data;
- diffie_hellman_group_t old_dh_group;
+ diffie_hellman_group_t bad_group;
- old_dh_group = this->dh_group;
+ bad_group = this->dh_group;
data = notify->get_notification_data(notify);
this->dh_group = ntohs(*((u_int16_t*)data.ptr));
-
- DBG1(DBG_IKE, "peer didn't accept DH group %N, it requested"
- " %N", diffie_hellman_group_names, old_dh_group,
- diffie_hellman_group_names, this->dh_group);
- if (!this->connection->check_dh_group(this->connection,
- this->dh_group))
- {
- DBG1(DBG_IKE, "requested DH group %N not acceptable, "
- "giving up", diffie_hellman_group_names,
- this->dh_group);
- iterator->destroy(iterator);
- return FAILED;
+ DBG1(DBG_IKE, "peer didn't accept DH group %N, "
+ "it requested %N", diffie_hellman_group_names,
+ bad_group, diffie_hellman_group_names, this->dh_group);
+
+ if (this->old_sa == NULL)
+ { /* reset the IKE_SA if we are not rekeying */
+ this->ike_sa->reset(this->ike_sa);
}
- this->ike_sa->reset(this->ike_sa);
-
iterator->destroy(iterator);
return NEED_MORE;
}
@@ -470,9 +449,9 @@ static status_t process_i(private_ike_init_t *this, message_t *message)
return FAILED;
}
- if (this->diffie_hellman == NULL ||
- this->diffie_hellman->get_shared_secret(this->diffie_hellman,
- &secret) != SUCCESS)
+ if (this->dh == NULL ||
+ !this->proposal->has_dh_group(this->proposal, this->dh_group) ||
+ this->dh->get_shared_secret(this->dh, &secret) != SUCCESS)
{
SIG(IKE_UP_FAILED, "peers DH group selection invalid");
return FAILED;
@@ -539,12 +518,12 @@ static chunk_t get_lower_nonce(private_ike_init_t *this)
static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
{
DESTROY_IF(this->proposal);
- DESTROY_IF(this->diffie_hellman);
+ DESTROY_IF(this->dh);
chunk_free(&this->other_nonce);
this->ike_sa = ike_sa;
this->proposal = NULL;
- this->diffie_hellman = diffie_hellman_create(this->dh_group);
+ this->dh = diffie_hellman_create(this->dh_group);
}
/**
@@ -553,7 +532,7 @@ static void migrate(private_ike_init_t *this, ike_sa_t *ike_sa)
static void destroy(private_ike_init_t *this)
{
DESTROY_IF(this->proposal);
- DESTROY_IF(this->diffie_hellman);
+ DESTROY_IF(this->dh);
chunk_free(&this->my_nonce);
chunk_free(&this->other_nonce);
chunk_free(&this->cookie);
@@ -585,12 +564,12 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa)
this->ike_sa = ike_sa;
this->initiator = initiator;
this->dh_group = MODP_NONE;
- this->diffie_hellman = NULL;
+ this->dh = NULL;
this->my_nonce = chunk_empty;
this->other_nonce = chunk_empty;
this->cookie = chunk_empty;
this->proposal = NULL;
- this->connection = NULL;
+ this->config = NULL;
this->old_sa = old_sa;
this->retry = 0;
diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c
index a33e7ee34..d54fc3524 100644
--- a/src/charon/sa/tasks/ike_rekey.c
+++ b/src/charon/sa/tasks/ike_rekey.c
@@ -26,8 +26,8 @@
#include <daemon.h>
#include <encoding/payloads/notify_payload.h>
#include <sa/tasks/ike_init.h>
-#include <queues/jobs/delete_ike_sa_job.h>
-#include <queues/jobs/rekey_ike_sa_job.h>
+#include <processing/jobs/delete_ike_sa_job.h>
+#include <processing/jobs/rekey_ike_sa_job.h>
typedef struct private_ike_rekey_t private_ike_rekey_t;
@@ -73,21 +73,20 @@ struct private_ike_rekey_t {
*/
static status_t build_i(private_ike_rekey_t *this, message_t *message)
{
- connection_t *connection;
- policy_t *policy;
+ peer_cfg_t *peer_cfg;
- this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
- TRUE);
-
- connection = this->ike_sa->get_connection(this->ike_sa);
- policy = this->ike_sa->get_policy(this->ike_sa);
- this->new_sa->set_connection(this->new_sa, connection);
- this->new_sa->set_policy(this->new_sa, policy);
-
- this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa);
+ /* create new SA only on first try */
+ if (this->new_sa == NULL)
+ {
+ this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
+ TRUE);
+
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ this->new_sa->set_peer_cfg(this->new_sa, peer_cfg);
+ this->ike_init = ike_init_create(this->new_sa, TRUE, this->ike_sa);
+ this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
+ }
this->ike_init->task.build(&this->ike_init->task, message);
-
- this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
return NEED_MORE;
}
@@ -97,8 +96,7 @@ static status_t build_i(private_ike_rekey_t *this, message_t *message)
*/
static status_t process_r(private_ike_rekey_t *this, message_t *message)
{
- connection_t *connection;
- policy_t *policy;
+ peer_cfg_t *peer_cfg;
iterator_t *iterator;
child_sa_t *child_sa;
@@ -129,11 +127,8 @@ static status_t process_r(private_ike_rekey_t *this, message_t *message)
this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
FALSE);
- connection = this->ike_sa->get_connection(this->ike_sa);
- policy = this->ike_sa->get_policy(this->ike_sa);
- this->new_sa->set_connection(this->new_sa, connection);
- this->new_sa->set_policy(this->new_sa, policy);
-
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ this->new_sa->set_peer_cfg(this->new_sa, peer_cfg);
this->ike_init = ike_init_create(this->new_sa, FALSE, this->ike_sa);
this->ike_init->task.process(&this->ike_init->task, message);
@@ -171,23 +166,29 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message)
job_t *job;
ike_sa_id_t *to_delete;
- if (this->ike_init->task.process(&this->ike_init->task, message) == FAILED)
+ switch (this->ike_init->task.process(&this->ike_init->task, message))
{
- /* rekeying failed, fallback to old SA */
- if (!(this->collision &&
- this->collision->get_type(this->collision) == IKE_DELETE))
- {
- job_t *job;
- u_int32_t retry = charon->configuration->get_retry_interval(
- charon->configuration);
- job = (job_t*)rekey_ike_sa_job_create(
- this->ike_sa->get_id(this->ike_sa), FALSE);
- DBG1(DBG_IKE, "IKE_SA rekeying failed, "
- "trying again in %d seconds", retry);
- this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
- charon->event_queue->add_relative(charon->event_queue, job, retry * 1000);
- }
- return SUCCESS;
+ case FAILED:
+ /* rekeying failed, fallback to old SA */
+ if (!(this->collision &&
+ this->collision->get_type(this->collision) == IKE_DELETE))
+ {
+ job_t *job;
+ u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
+ job = (job_t*)rekey_ike_sa_job_create(
+ this->ike_sa->get_id(this->ike_sa), FALSE);
+ DBG1(DBG_IKE, "IKE_SA rekeying failed, "
+ "trying again in %d seconds", retry);
+ this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+ charon->event_queue->add_relative(charon->event_queue, job, retry * 1000);
+ }
+ return SUCCESS;
+ case NEED_MORE:
+ /* bad dh group, try again */
+ this->ike_init->task.migrate(&this->ike_init->task, this->new_sa);
+ return NEED_MORE;
+ default:
+ break;
}
this->new_sa->set_state(this->new_sa, IKE_ESTABLISHED);