diff options
-rw-r--r-- | src/libcharon/plugins/ha/ha_cache.c | 17 | ||||
-rw-r--r-- | src/libcharon/plugins/ha/ha_dispatcher.c | 54 | ||||
-rw-r--r-- | src/libcharon/plugins/ha/ha_ike.c | 76 | ||||
-rw-r--r-- | src/libcharon/plugins/ha/ha_message.c | 5 | ||||
-rw-r--r-- | src/libcharon/plugins/ha/ha_message.h | 4 |
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, }; /** |