aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/plugins/ha/ha_cache.c17
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.c54
-rw-r--r--src/libcharon/plugins/ha/ha_ike.c76
-rw-r--r--src/libcharon/plugins/ha/ha_message.c5
-rw-r--r--src/libcharon/plugins/ha/ha_message.h4
5 files changed, 129 insertions, 27 deletions
diff --git a/src/libcharon/plugins/ha/ha_cache.c b/src/libcharon/plugins/ha/ha_cache.c
index 7b7a953e5..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)
@@ -309,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 e3080c449..197bb5e24 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -479,6 +479,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,
@@ -932,6 +983,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 b18cd6f11..97fc85600 100644
--- a/src/libcharon/plugins/ha/ha_ike.c
+++ b/src/libcharon/plugins/ha/ha_ike.c
@@ -16,6 +16,7 @@
#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;
@@ -245,39 +246,62 @@ METHOD(listener_t, message_hook, bool,
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;
- host_t *vip;
+ keymat_v1_t *keymat;
+ u_int32_t mid;
+ chunk_t iv;
- 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);
}
diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c
index 7df705a8a..c7c624d32 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;
@@ -267,6 +268,7 @@ METHOD(ha_message_t, add_attribute, void,
case HA_LOCAL_DH:
case HA_REMOTE_DH:
case HA_PSK:
+ case HA_IV:
case HA_OLD_SKD:
{
chunk_t chunk;
@@ -487,6 +489,7 @@ METHOD(enumerator_t, attribute_enumerate, bool,
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 b937d39b5..89f9fc391 100644
--- a/src/libcharon/plugins/ha/ha_message.h
+++ b/src/libcharon/plugins/ha/ha_message.h
@@ -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,
};
/**
@@ -150,6 +152,8 @@ enum ha_message_attribute_t {
HA_REMOTE_DH,
/** chunk_t, shared secret for IKEv1 key derivation */
HA_PSK,
+ /** chunk_t, IV for next IKEv1 message */
+ HA_IV,
};
/**