]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
Added support for Phase1 IV synchronization to HA plugin
authorMartin Willi <martin@revosec.ch>
Thu, 19 Jan 2012 15:34:59 +0000 (16:34 +0100)
committerMartin Willi <martin@revosec.ch>
Tue, 20 Mar 2012 16:31:37 +0000 (17:31 +0100)
src/libcharon/plugins/ha/ha_cache.c
src/libcharon/plugins/ha/ha_dispatcher.c
src/libcharon/plugins/ha/ha_ike.c
src/libcharon/plugins/ha/ha_message.c
src/libcharon/plugins/ha/ha_message.h

index 7b7a953e5c6680e13db67821171be756ef95ab94..e21b461a74b98753aead53c9c604d77aad014e51 100644 (file)
@@ -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);
index e3080c449034ad4709d11b76027cb884d25853e9..197bb5e24a0d1b9eef418be54404c14bb7ebd1e4 100644 (file)
@@ -478,6 +478,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
  */
@@ -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;
index b18cd6f11a2fe30dc7b71c2c2cf78034b6e2efb6..97fc8560021f09ad86e907ffb275f9593affbaf5 100644 (file)
@@ -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);
                }
index 7df705a8a5a9d99f5b04fe37d9d553f88ce5a8b2..c7c624d3221968c41fb15dbaf432703f49735aa4 100644 (file)
@@ -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;
index b937d39b506c5111426f3ff6382d37d15ecd9e9c..89f9fc391d63bf7203778359f005fad69c72824b 100644 (file)
@@ -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,
 };
 
 /**