aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon/plugins/ha
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/ha')
-rw-r--r--src/libcharon/plugins/ha/ha_cache.c20
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.c213
-rw-r--r--src/libcharon/plugins/ha/ha_ike.c151
-rw-r--r--src/libcharon/plugins/ha/ha_message.c20
-rw-r--r--src/libcharon/plugins/ha/ha_message.h16
-rw-r--r--src/libcharon/plugins/ha/ha_tunnel.c4
6 files changed, 365 insertions, 59 deletions
diff --git a/src/libcharon/plugins/ha/ha_cache.c b/src/libcharon/plugins/ha/ha_cache.c
index 970a8a2b9..e21b461a7 100644
--- a/src/libcharon/plugins/ha/ha_cache.c
+++ b/src/libcharon/plugins/ha/ha_cache.c
@@ -88,6 +88,8 @@ typedef struct {
ha_message_t *midi;
/* last responder mid */
ha_message_t *midr;
+ /* last IV update */
+ ha_message_t *iv;
} entry_t;
/**
@@ -114,6 +116,7 @@ static void entry_destroy(entry_t *entry)
entry->add->destroy(entry->add);
DESTROY_IF(entry->midi);
DESTROY_IF(entry->midr);
+ DESTROY_IF(entry->iv);
free(entry);
}
@@ -164,6 +167,16 @@ METHOD(ha_cache_t, cache, void,
}
message->destroy(message);
break;
+ case HA_IKE_IV:
+ entry = this->cache->get(this->cache, ike_sa);
+ if (entry)
+ {
+ DESTROY_IF(entry->iv);
+ entry->iv = message;
+ break;
+ }
+ message->destroy(message);
+ break;
case HA_IKE_DELETE:
entry = this->cache->remove(this->cache, ike_sa);
if (entry)
@@ -212,7 +225,8 @@ static status_t rekey_children(ike_sa_t *ike_sa)
DBG1(DBG_CFG, "resyncing CHILD_SA using a delete");
status = ike_sa->delete_child_sa(ike_sa,
child_sa->get_protocol(child_sa),
- child_sa->get_spi(child_sa, TRUE));
+ child_sa->get_spi(child_sa, TRUE),
+ FALSE);
}
else
{
@@ -308,6 +322,10 @@ METHOD(ha_cache_t, resync, void,
{
this->socket->push(this->socket, entry->midr);
}
+ if (entry->iv)
+ {
+ this->socket->push(this->socket, entry->iv);
+ }
}
}
enumerator->destroy(enumerator);
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c
index 994f91d20..de5253b37 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -16,9 +16,13 @@
#include "ha_dispatcher.h"
#include <daemon.h>
+#include <sa/ikev2/keymat_v2.h>
+#include <sa/ikev1/keymat_v1.h>
#include <processing/jobs/callback_job.h>
+#include <processing/jobs/adopt_children_job.h>
typedef struct private_ha_dispatcher_t private_ha_dispatcher_t;
+typedef struct ha_diffie_hellman_t ha_diffie_hellman_t;
/**
* Private data of an ha_dispatcher_t object.
@@ -62,14 +66,65 @@ struct private_ha_dispatcher_t {
};
/**
- * Quick and dirty hack implementation of diffie_hellman_t.get_shared_secret
+ * DH implementation for HA synced DH values
*/
-static status_t get_shared_secret(diffie_hellman_t *this, chunk_t *secret)
+struct ha_diffie_hellman_t {
+
+ /**
+ * Implements diffie_hellman_t
+ */
+ diffie_hellman_t dh;
+
+ /**
+ * Shared secret
+ */
+ chunk_t secret;
+
+ /**
+ * Own public value
+ */
+ chunk_t pub;
+};
+
+METHOD(diffie_hellman_t, dh_get_shared_secret, status_t,
+ ha_diffie_hellman_t *this, chunk_t *secret)
{
- *secret = chunk_clone((*(chunk_t*)this->destroy));
+ *secret = chunk_clone(this->secret);
return SUCCESS;
}
+METHOD(diffie_hellman_t, dh_get_my_public_value, void,
+ ha_diffie_hellman_t *this, chunk_t *value)
+{
+ *value = chunk_clone(this->pub);
+}
+
+METHOD(diffie_hellman_t, dh_destroy, void,
+ ha_diffie_hellman_t *this)
+{
+ free(this);
+}
+
+/**
+ * Create a HA synced DH implementation
+ */
+static diffie_hellman_t *ha_diffie_hellman_create(chunk_t secret, chunk_t pub)
+{
+ ha_diffie_hellman_t *this;
+
+ INIT(this,
+ .dh = {
+ .get_shared_secret = _dh_get_shared_secret,
+ .get_my_public_value = _dh_get_my_public_value,
+ .destroy = _dh_destroy,
+ },
+ .secret = secret,
+ .pub = pub,
+ );
+
+ return &this->dh;
+}
+
/**
* Process messages of type IKE_ADD
*/
@@ -79,9 +134,12 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
ha_message_value_t value;
enumerator_t *enumerator;
ike_sa_t *ike_sa = NULL, *old_sa = NULL;
+ ike_version_t version = IKEV2;
u_int16_t encr = 0, len = 0, integ = 0, prf = 0, old_prf = PRF_UNDEFINED;
chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty;
chunk_t secret = chunk_empty, old_skd = chunk_empty;
+ chunk_t dh_local = chunk_empty, dh_remote = chunk_empty, psk = chunk_empty;
+ bool ok = FALSE;
enumerator = message->create_attribute_enumerator(message);
while (enumerator->enumerate(enumerator, &attribute, &value))
@@ -89,12 +147,16 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
switch (attribute)
{
case HA_IKE_ID:
- ike_sa = ike_sa_create(value.ike_sa_id);
+ ike_sa = ike_sa_create(value.ike_sa_id,
+ value.ike_sa_id->is_initiator(value.ike_sa_id), version);
break;
case HA_IKE_REKEY_ID:
old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
value.ike_sa_id);
break;
+ case HA_IKE_VERSION:
+ version = value.u8;
+ break;
case HA_NONCE_I:
nonce_i = value.chunk;
break;
@@ -104,6 +166,15 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
case HA_SECRET:
secret = value.chunk;
break;
+ case HA_LOCAL_DH:
+ dh_local = value.chunk;
+ break;
+ case HA_REMOTE_DH:
+ dh_remote = value.chunk;
+ break;
+ case HA_PSK:
+ psk = value.chunk;
+ break;
case HA_OLD_SKD:
old_skd = value.chunk;
break;
@@ -131,13 +202,9 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
if (ike_sa)
{
proposal_t *proposal;
- keymat_t *keymat;
- /* quick and dirty hack of a DH implementation ;-) */
- diffie_hellman_t dh = { .get_shared_secret = get_shared_secret,
- .destroy = (void*)&secret };
+ diffie_hellman_t *dh;
proposal = proposal_create(PROTO_IKE, 0);
- keymat = ike_sa->get_keymat(ike_sa);
if (integ)
{
proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
@@ -151,8 +218,35 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0);
}
charon->bus->set_sa(charon->bus, ike_sa);
- if (keymat->derive_ike_keys(keymat, proposal, &dh, nonce_i, nonce_r,
- ike_sa->get_id(ike_sa), old_prf, old_skd))
+ dh = ha_diffie_hellman_create(secret, dh_local);
+ if (ike_sa->get_version(ike_sa) == IKEV2)
+ {
+ keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
+
+ ok = keymat_v2->derive_ike_keys(keymat_v2, proposal, dh, nonce_i,
+ nonce_r, ike_sa->get_id(ike_sa), old_prf, old_skd);
+ }
+ if (ike_sa->get_version(ike_sa) == IKEV1)
+ {
+ keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
+ shared_key_t *shared = NULL;
+ auth_method_t method = AUTH_RSA;
+
+ if (psk.len)
+ {
+ method = AUTH_PSK;
+ shared = shared_key_create(SHARED_IKE, chunk_clone(psk));
+ }
+ if (keymat_v1->create_hasher(keymat_v1, proposal))
+ {
+ ok = keymat_v1->derive_ike_keys(keymat_v1, proposal,
+ dh, dh_remote, nonce_i, nonce_r,
+ ike_sa->get_id(ike_sa), method, shared);
+ }
+ DESTROY_IF(shared);
+ }
+ dh->destroy(dh);
+ if (ok)
{
if (old_sa)
{
@@ -168,6 +262,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
old_sa = NULL;
}
ike_sa->set_state(ike_sa, IKE_CONNECTING);
+ ike_sa->set_proposal(ike_sa, proposal);
this->cache->cache(this->cache, ike_sa, message);
message = NULL;
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
@@ -289,6 +384,8 @@ static void process_ike_update(private_ha_dispatcher_t *this,
set_extension(ike_sa, value.u32, EXT_STRONGSWAN);
set_extension(ike_sa, value.u32, EXT_EAP_ONLY_AUTHENTICATION);
set_extension(ike_sa, value.u32, EXT_MS_WINDOWS);
+ set_extension(ike_sa, value.u32, EXT_XAUTH);
+ set_extension(ike_sa, value.u32, EXT_DPD);
break;
case HA_CONDITIONS:
set_condition(ike_sa, value.u32, COND_NAT_ANY);
@@ -299,6 +396,8 @@ static void process_ike_update(private_ha_dispatcher_t *this,
set_condition(ike_sa, value.u32, COND_CERTREQ_SEEN);
set_condition(ike_sa, value.u32, COND_ORIGINAL_INITIATOR);
set_condition(ike_sa, value.u32, COND_STALE);
+ set_condition(ike_sa, value.u32, COND_INIT_CONTACT_SEEN);
+ set_condition(ike_sa, value.u32, COND_XAUTH_AUTHENTICATED);
break;
default:
break;
@@ -333,6 +432,11 @@ static void process_ike_update(private_ha_dispatcher_t *this,
}
}
}
+ if (ike_sa->get_version(ike_sa) == IKEV1)
+ {
+ lib->processor->queue_job(lib->processor, (job_t*)
+ adopt_children_job_create(ike_sa->get_id(ike_sa)));
+ }
this->cache->cache(this->cache, ike_sa, message);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
@@ -389,6 +493,57 @@ static void process_ike_mid(private_ha_dispatcher_t *this,
}
/**
+ * Process messages of type IKE_IV
+ */
+static void process_ike_iv(private_ha_dispatcher_t *this, ha_message_t *message)
+{
+ ha_message_attribute_t attribute;
+ ha_message_value_t value;
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa = NULL;
+ chunk_t iv = chunk_empty;
+
+ enumerator = message->create_attribute_enumerator(message);
+ while (enumerator->enumerate(enumerator, &attribute, &value))
+ {
+ switch (attribute)
+ {
+ case HA_IKE_ID:
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+ value.ike_sa_id);
+ break;
+ case HA_IV:
+ iv = value.chunk;
+ break;
+ default:
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (ike_sa)
+ {
+ if (ike_sa->get_version(ike_sa) == IKEV1)
+ {
+ if (iv.len)
+ {
+ keymat_v1_t *keymat;
+
+ keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
+ keymat->update_iv(keymat, 0, iv);
+ keymat->confirm_iv(keymat, 0);
+ }
+ }
+ this->cache->cache(this->cache, ike_sa, message);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ message->destroy(message);
+ }
+}
+
+/**
* Process messages of type IKE_DELETE
*/
static void process_ike_delete(private_ha_dispatcher_t *this,
@@ -465,8 +620,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
child_cfg_t *config = NULL;
child_sa_t *child_sa;
proposal_t *proposal;
- keymat_t *keymat;
- bool initiator = FALSE, failed = FALSE;
+ bool initiator = FALSE, failed = FALSE, ok = FALSE;
u_int32_t inbound_spi = 0, outbound_spi = 0;
u_int16_t inbound_cpi = 0, outbound_cpi = 0;
u_int8_t mode = MODE_TUNNEL, ipcomp = 0;
@@ -476,9 +630,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty;
chunk_t encr_i, integ_i, encr_r, integ_r;
linked_list_t *local_ts, *remote_ts;
- /* quick and dirty hack of a DH implementation */
- diffie_hellman_t dh = { .get_shared_secret = get_shared_secret,
- .destroy = (void*)&secret };
+ diffie_hellman_t *dh = NULL;
enumerator = message->create_attribute_enumerator(message);
while (enumerator->enumerate(enumerator, &attribute, &value))
@@ -572,10 +724,30 @@ static void process_child_add(private_ha_dispatcher_t *this,
proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
}
proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0);
- keymat = ike_sa->get_keymat(ike_sa);
+ if (secret.len)
+ {
+ dh = ha_diffie_hellman_create(secret, chunk_empty);
+ }
+ if (ike_sa->get_version(ike_sa) == IKEV2)
+ {
+ keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
- if (!keymat->derive_child_keys(keymat, proposal, secret.ptr ? &dh : NULL,
- nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r))
+ ok = keymat_v2->derive_child_keys(keymat_v2, proposal, dh,
+ nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
+ }
+ if (ike_sa->get_version(ike_sa) == IKEV1)
+ {
+ keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
+ u_int32_t spi_i, spi_r;
+
+ spi_i = initiator ? inbound_spi : outbound_spi;
+ spi_r = initiator ? outbound_spi : inbound_spi;
+
+ ok = keymat_v1->derive_child_keys(keymat_v1, proposal, dh, spi_i, spi_r,
+ nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
+ }
+ DESTROY_IF(dh);
+ if (!ok)
{
DBG1(DBG_CHD, "HA CHILD_SA key derivation failed");
child_sa->destroy(child_sa);
@@ -825,6 +997,9 @@ static job_requeue_t dispatch(private_ha_dispatcher_t *this)
case HA_IKE_MID_RESPONDER:
process_ike_mid(this, message, FALSE);
break;
+ case HA_IKE_IV:
+ process_ike_iv(this, message);
+ break;
case HA_IKE_DELETE:
process_ike_delete(this, message);
break;
diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c
index e818aec9c..2819b9dd5 100644
--- a/src/libcharon/plugins/ha/ha_ike.c
+++ b/src/libcharon/plugins/ha/ha_ike.c
@@ -15,6 +15,9 @@
#include "ha_ike.h"
+#include <sa/ikev2/keymat_v2.h>
+#include <sa/ikev1/keymat_v1.h>
+
typedef struct private_ha_ike_t private_ha_ike_t;
/**
@@ -69,7 +72,8 @@ static ike_extension_t copy_extension(ike_sa_t *ike_sa, ike_extension_t ext)
METHOD(listener_t, ike_keys, bool,
private_ha_ike_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
- chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey)
+ chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey,
+ shared_key_t *shared)
{
ha_message_t *m;
chunk_t secret;
@@ -86,14 +90,15 @@ METHOD(listener_t, ike_keys, bool,
}
m = ha_message_create(HA_IKE_ADD);
+ m->add_attribute(m, HA_IKE_VERSION, ike_sa->get_version(ike_sa));
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
- if (rekey)
+ if (rekey && rekey->get_version(rekey) == IKEV2)
{
chunk_t skd;
- keymat_t *keymat;
+ keymat_v2_t *keymat;
- keymat = rekey->get_keymat(rekey);
+ keymat = (keymat_v2_t*)rekey->get_keymat(rekey);
m->add_attribute(m, HA_IKE_REKEY_ID, rekey->get_id(rekey));
m->add_attribute(m, HA_ALG_OLD_PRF, keymat->get_skd(keymat, &skd));
m->add_attribute(m, HA_OLD_SKD, skd);
@@ -120,6 +125,17 @@ METHOD(listener_t, ike_keys, bool,
m->add_attribute(m, HA_NONCE_R, nonce_r);
m->add_attribute(m, HA_SECRET, secret);
chunk_clear(&secret);
+ if (ike_sa->get_version(ike_sa) == IKEV1)
+ {
+ dh->get_my_public_value(dh, &secret);
+ m->add_attribute(m, HA_LOCAL_DH, secret);
+ chunk_free(&secret);
+ m->add_attribute(m, HA_REMOTE_DH, dh_other);
+ if (shared)
+ {
+ m->add_attribute(m, HA_PSK, shared->get_key(shared));
+ }
+ }
this->socket->push(this->socket, m);
this->cache->cache(this->cache, ike_sa, m);
@@ -159,7 +175,9 @@ METHOD(listener_t, ike_updown, bool,
| copy_condition(ike_sa, COND_EAP_AUTHENTICATED)
| copy_condition(ike_sa, COND_CERTREQ_SEEN)
| copy_condition(ike_sa, COND_ORIGINAL_INITIATOR)
- | copy_condition(ike_sa, COND_STALE);
+ | copy_condition(ike_sa, COND_STALE)
+ | copy_condition(ike_sa, COND_INIT_CONTACT_SEEN)
+ | copy_condition(ike_sa, COND_XAUTH_AUTHENTICATED);
extension = copy_extension(ike_sa, EXT_NATT)
| copy_extension(ike_sa, EXT_MOBIKE)
@@ -167,7 +185,9 @@ METHOD(listener_t, ike_updown, bool,
| copy_extension(ike_sa, EXT_MULTIPLE_AUTH)
| copy_extension(ike_sa, EXT_STRONGSWAN)
| copy_extension(ike_sa, EXT_EAP_ONLY_AUTHENTICATION)
- | copy_extension(ike_sa, EXT_MS_WINDOWS);
+ | copy_extension(ike_sa, EXT_MS_WINDOWS)
+ | copy_extension(ike_sa, EXT_XAUTH)
+ | copy_extension(ike_sa, EXT_DPD);
id = ike_sa->get_id(ike_sa);
@@ -222,49 +242,116 @@ METHOD(listener_t, ike_state_change, bool,
}
METHOD(listener_t, message_hook, bool,
- private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message, bool incoming)
+ private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message,
+ bool incoming, bool plain)
{
if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
{ /* do not sync SA between nodes */
return TRUE;
}
- if (message->get_exchange_type(message) != IKE_SA_INIT &&
- message->get_request(message))
- { /* we sync on requests, but skip it on IKE_SA_INIT */
- ha_message_t *m;
-
- if (incoming)
- {
- m = ha_message_create(HA_IKE_MID_RESPONDER);
+ if (plain && ike_sa->get_version(ike_sa) == IKEV2)
+ {
+ if (message->get_exchange_type(message) != IKE_SA_INIT &&
+ message->get_request(message))
+ { /* we sync on requests, but skip it on IKE_SA_INIT */
+ ha_message_t *m;
+
+ if (incoming)
+ {
+ m = ha_message_create(HA_IKE_MID_RESPONDER);
+ }
+ else
+ {
+ m = ha_message_create(HA_IKE_MID_INITIATOR);
+ }
+ m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
+ m->add_attribute(m, HA_MID, message->get_message_id(message) + 1);
+ this->socket->push(this->socket, m);
+ this->cache->cache(this->cache, ike_sa, m);
}
- else
- {
- m = ha_message_create(HA_IKE_MID_INITIATOR);
+ if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
+ message->get_exchange_type(message) == IKE_AUTH &&
+ !message->get_request(message))
+ { /* After IKE_SA has been established, sync peers virtual IP.
+ * We cannot sync it in the state_change hook, it is installed later.
+ * TODO: where to sync local VIP? */
+ ha_message_t *m;
+ host_t *vip;
+
+ vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
+ if (vip)
+ {
+ m = ha_message_create(HA_IKE_UPDATE);
+ m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
+ m->add_attribute(m, HA_REMOTE_VIP, vip);
+ this->socket->push(this->socket, m);
+ this->cache->cache(this->cache, ike_sa, m);
+ }
}
- m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
- m->add_attribute(m, HA_MID, message->get_message_id(message) + 1);
- this->socket->push(this->socket, m);
- this->cache->cache(this->cache, ike_sa, m);
}
- if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
- message->get_exchange_type(message) == IKE_AUTH &&
- !message->get_request(message))
- { /* After IKE_SA has been established, sync peers virtual IP.
- * We cannot sync it in the state_change hook, it is installed later.
- * TODO: where to sync local VIP? */
+ if (!plain && ike_sa->get_version(ike_sa) == IKEV1)
+ {
ha_message_t *m;
+ keymat_v1_t *keymat;
+ u_int32_t mid;
+ chunk_t iv;
host_t *vip;
- vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
- if (vip)
+ mid = message->get_message_id(message);
+ if (mid == 0)
{
- m = ha_message_create(HA_IKE_UPDATE);
+ keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
+ iv = keymat->get_iv(keymat, mid);
+ m = ha_message_create(HA_IKE_IV);
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
- m->add_attribute(m, HA_REMOTE_VIP, vip);
+ m->add_attribute(m, HA_IV, iv);
+ free(iv.ptr);
this->socket->push(this->socket, m);
this->cache->cache(this->cache, ike_sa, m);
}
+ if (!incoming && message->get_exchange_type(message) == TRANSACTION)
+ {
+ vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
+ if (vip)
+ {
+ m = ha_message_create(HA_IKE_UPDATE);
+ m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
+ m->add_attribute(m, HA_REMOTE_VIP, vip);
+ this->socket->push(this->socket, m);
+ this->cache->cache(this->cache, ike_sa, m);
+ }
+ }
+ }
+ if (plain && ike_sa->get_version(ike_sa) == IKEV1 &&
+ message->get_exchange_type(message) == INFORMATIONAL_V1)
+ {
+ ha_message_t *m;
+ notify_payload_t *notify;
+ chunk_t data;
+ u_int32_t seq;
+
+ notify = message->get_notify(message, DPD_R_U_THERE);
+ if (notify)
+ {
+ data = notify->get_notification_data(notify);
+ if (data.len == 4)
+ {
+ seq = untoh32(data.ptr);
+ if (incoming)
+ {
+ m = ha_message_create(HA_IKE_MID_RESPONDER);
+ }
+ else
+ {
+ m = ha_message_create(HA_IKE_MID_INITIATOR);
+ }
+ m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
+ m->add_attribute(m, HA_MID, seq + 1);
+ this->socket->push(this->socket, m);
+ this->cache->cache(this->cache, ike_sa, m);
+ }
+ }
}
return TRUE;
}
diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c
index 810109a5d..6b00ed83f 100644
--- a/src/libcharon/plugins/ha/ha_message.c
+++ b/src/libcharon/plugins/ha/ha_message.c
@@ -46,7 +46,7 @@ struct private_ha_message_t {
chunk_t buf;
};
-ENUM(ha_message_type_names, HA_IKE_ADD, HA_RESYNC,
+ENUM(ha_message_type_names, HA_IKE_ADD, HA_IKE_IV,
"IKE_ADD",
"IKE_UPDATE",
"IKE_MID_INITIATOR",
@@ -58,6 +58,7 @@ ENUM(ha_message_type_names, HA_IKE_ADD, HA_RESYNC,
"SEGMENT_TAKE",
"STATUS",
"RESYNC",
+ "IKE_IV",
);
typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t;
@@ -66,6 +67,7 @@ typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t;
* Encoding if an ike_sa_id_t
*/
struct ike_sa_id_encoding_t {
+ u_int8_t ike_version;
u_int64_t initiator_spi;
u_int64_t responder_spi;
u_int8_t initiator;
@@ -156,6 +158,7 @@ METHOD(ha_message_t, add_attribute, void,
enc = (ike_sa_id_encoding_t*)(this->buf.ptr + this->buf.len);
this->buf.len += sizeof(ike_sa_id_encoding_t);
enc->initiator = id->is_initiator(id);
+ enc->ike_version = id->get_ike_version(id);
enc->initiator_spi = id->get_initiator_spi(id);
enc->responder_spi = id->get_responder_spi(id);
break;
@@ -213,6 +216,7 @@ METHOD(ha_message_t, add_attribute, void,
break;
}
/* u_int8_t */
+ case HA_IKE_VERSION:
case HA_INITIATOR:
case HA_IPSEC_MODE:
case HA_IPCOMP:
@@ -263,6 +267,10 @@ METHOD(ha_message_t, add_attribute, void,
case HA_NONCE_I:
case HA_NONCE_R:
case HA_SECRET:
+ case HA_LOCAL_DH:
+ case HA_REMOTE_DH:
+ case HA_PSK:
+ case HA_IV:
case HA_OLD_SKD:
{
chunk_t chunk;
@@ -351,8 +359,9 @@ METHOD(enumerator_t, attribute_enumerate, bool,
return FALSE;
}
enc = (ike_sa_id_encoding_t*)(this->buf.ptr);
- value->ike_sa_id = ike_sa_id_create(enc->initiator_spi,
- enc->responder_spi, enc->initiator);
+ value->ike_sa_id = ike_sa_id_create(enc->ike_version,
+ enc->initiator_spi, enc->responder_spi,
+ enc->initiator);
*attr_out = attr;
this->cleanup = (void*)value->ike_sa_id->destroy;
this->cleanup_data = value->ike_sa_id;
@@ -426,6 +435,7 @@ METHOD(enumerator_t, attribute_enumerate, bool,
return TRUE;
}
/* u_int8_t */
+ case HA_IKE_VERSION:
case HA_INITIATOR:
case HA_IPSEC_MODE:
case HA_IPCOMP:
@@ -479,6 +489,10 @@ METHOD(enumerator_t, attribute_enumerate, bool,
case HA_NONCE_I:
case HA_NONCE_R:
case HA_SECRET:
+ case HA_LOCAL_DH:
+ case HA_REMOTE_DH:
+ case HA_PSK:
+ case HA_IV:
case HA_OLD_SKD:
{
size_t len;
diff --git a/src/libcharon/plugins/ha/ha_message.h b/src/libcharon/plugins/ha/ha_message.h
index d0323d7a0..8cd30f711 100644
--- a/src/libcharon/plugins/ha/ha_message.h
+++ b/src/libcharon/plugins/ha/ha_message.h
@@ -30,7 +30,7 @@
/**
* Protocol version of this implementation
*/
-#define HA_MESSAGE_VERSION 2
+#define HA_MESSAGE_VERSION 3
typedef struct ha_message_t ha_message_t;
typedef enum ha_message_type_t ha_message_type_t;
@@ -63,6 +63,8 @@ enum ha_message_type_t {
HA_STATUS,
/** segments the receiving node is requested to resync */
HA_RESYNC,
+ /** IV synchronization for IKEv1 Main/Aggressive mode */
+ HA_IKE_IV,
};
/**
@@ -76,7 +78,7 @@ extern enum_name_t *ha_message_type_names;
enum ha_message_attribute_t {
/** ike_sa_id_t*, to identify IKE_SA */
HA_IKE_ID = 1,
- /** ike_Sa_id_t*, identifies IKE_SA which gets rekeyed */
+ /** ike_sa_id_t*, identifies IKE_SA which gets rekeyed */
HA_IKE_REKEY_ID,
/** identification_t*, local identity */
HA_LOCAL_ID,
@@ -142,6 +144,16 @@ enum ha_message_attribute_t {
HA_SEGMENT,
/** u_int16_t, Extended Sequence numbers */
HA_ESN,
+ /** u_int8_t, IKE version */
+ HA_IKE_VERSION,
+ /** chunk_t, own DH public value */
+ HA_LOCAL_DH,
+ /** chunk_t, remote DH public value */
+ HA_REMOTE_DH,
+ /** chunk_t, shared secret for IKEv1 key derivation */
+ HA_PSK,
+ /** chunk_t, IV for next IKEv1 message */
+ HA_IV,
};
/**
diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c
index 299053ec1..6f20620f2 100644
--- a/src/libcharon/plugins/ha/ha_tunnel.c
+++ b/src/libcharon/plugins/ha/ha_tunnel.c
@@ -206,8 +206,8 @@ static void setup_tunnel(private_ha_tunnel_t *this,
ike_cfg = ike_cfg_create(FALSE, FALSE, local, IKEV2_UDP_PORT,
remote, IKEV2_UDP_PORT);
ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE));
- peer_cfg = peer_cfg_create("ha", 2, ike_cfg, CERT_NEVER_SEND,
- UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, 30,
+ peer_cfg = peer_cfg_create("ha", IKEV2, ike_cfg, CERT_NEVER_SEND,
+ UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, 30,
NULL, NULL, FALSE, NULL, NULL);
auth_cfg = auth_cfg_create();