basic syncing of IKE_SAs
authorMartin Willi <martin@strongswan.org>
Mon, 17 Nov 2008 15:58:39 +0000 (15:58 +0000)
committerMartin Willi <martin@revosec.ch>
Wed, 7 Apr 2010 11:55:11 +0000 (13:55 +0200)
recreating SAs with keymat derivation

src/charon/plugins/ha_sync/Makefile.am
src/charon/plugins/ha_sync/ha_sync_cache.c [new file with mode: 0644]
src/charon/plugins/ha_sync/ha_sync_cache.h [new file with mode: 0644]
src/charon/plugins/ha_sync/ha_sync_dispatcher.c
src/charon/plugins/ha_sync/ha_sync_dispatcher.h
src/charon/plugins/ha_sync/ha_sync_ike.c
src/charon/plugins/ha_sync/ha_sync_message.c
src/charon/plugins/ha_sync/ha_sync_message.h
src/charon/plugins/ha_sync/ha_sync_plugin.c

index fd15a6e..b48a6cf 100644 (file)
@@ -9,6 +9,7 @@ libstrongswan_ha_sync_la_SOURCES = \
   ha_sync_message.h ha_sync_message.c \
   ha_sync_socket.h ha_sync_socket.c \
   ha_sync_dispatcher.h ha_sync_dispatcher.c \
+  ha_sync_dispatcher.h ha_sync_cache.c \
   ha_sync_ike.h ha_sync_ike.c \
   ha_sync_child.h ha_sync_child.c
 libstrongswan_ha_sync_la_LDFLAGS = -module
diff --git a/src/charon/plugins/ha_sync/ha_sync_cache.c b/src/charon/plugins/ha_sync/ha_sync_cache.c
new file mode 100644 (file)
index 0000000..9924b08
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * $Id$
+ */
+
+#include "ha_sync_cache.h"
+
+#include <utils/linked_list.h>
+
+typedef struct private_ha_sync_cache_t private_ha_sync_cache_t;
+
+/**
+ * Private data of an ha_sync_cache_t object.
+ */
+struct private_ha_sync_cache_t {
+
+       /**
+        * Public ha_sync_cache_t interface.
+        */
+       ha_sync_cache_t public;
+
+       /**
+        * Linked list of IKE_SAs, ike_sa_t
+        */
+       linked_list_t *list;
+};
+
+/**
+ * Implementation of ha_sync_cache_t.get_ike_sa
+ */
+static ike_sa_t* get_ike_sa(private_ha_sync_cache_t *this, ike_sa_id_t *id)
+{
+       enumerator_t *enumerator;
+       ike_sa_t *current, *found = NULL;
+
+       enumerator = this->list->create_enumerator(this->list);
+       while (enumerator->enumerate(enumerator, &current))
+       {
+               if (id->equals(id, current->get_id(current)))
+               {
+                       found = current;
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (!found)
+       {
+               found = ike_sa_create(id);
+               this->list->insert_first(this->list, found);
+       }
+       return found;
+}
+
+/**
+ * Implementation of ha_sync_cache_t.delete_ike_sa
+ */
+static void delete_ike_sa(private_ha_sync_cache_t *this, ike_sa_id_t *id)
+{
+       enumerator_t *enumerator;
+       ike_sa_t *ike_sa;
+
+       enumerator = this->list->create_enumerator(this->list);
+       while (enumerator->enumerate(enumerator, &ike_sa))
+       {
+               if (id->equals(id, ike_sa->get_id(ike_sa)))
+               {
+                       this->list->remove_at(this->list, enumerator);
+                       ike_sa->destroy(ike_sa);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+}
+
+/**
+ * Implementation of ha_sync_cache_t.activate_segment
+ */
+static void activate_segment(private_ha_sync_cache_t *this, u_int segment)
+{
+       ike_sa_t *ike_sa;
+
+       /* TODO: activate only segment, not all */
+       while (this->list->remove_last(this->list, (void**)&ike_sa) == SUCCESS)
+       {
+               /* TODO: fix checkin of inexisting IKE_SA in manager */
+               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+       }
+}
+
+/**
+ * Implementation of ha_sync_cache_t.destroy.
+ */
+static void destroy(private_ha_sync_cache_t *this)
+{
+       this->list->destroy_offset(this->list, offsetof(ike_sa_t, destroy));
+       free(this);
+}
+
+/**
+ * See header
+ */
+ha_sync_cache_t *ha_sync_cache_create()
+{
+       private_ha_sync_cache_t *this = malloc_thing(private_ha_sync_cache_t);
+
+       this->public.get_ike_sa = (ike_sa_t*(*)(ha_sync_cache_t*, ike_sa_id_t *id))get_ike_sa;
+       this->public.delete_ike_sa = (void(*)(ha_sync_cache_t*, ike_sa_id_t *id))delete_ike_sa;
+       this->public.activate_segment = (void(*)(ha_sync_cache_t*, u_int segment))activate_segment;
+       this->public.destroy = (void(*)(ha_sync_cache_t*))destroy;
+
+       this->list = linked_list_create();
+
+       return &this->public;
+}
+
diff --git a/src/charon/plugins/ha_sync/ha_sync_cache.h b/src/charon/plugins/ha_sync/ha_sync_cache.h
new file mode 100644 (file)
index 0000000..2088011
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * $Id$
+ */
+
+/**
+ * @defgroup ha_sync_cache ha_sync_cache
+ * @{ @ingroup ha_sync
+ */
+
+#ifndef HA_SYNC_CACHE_H_
+#define HA_SYNC_CACHE_H_
+
+#include <daemon.h>
+
+typedef struct ha_sync_cache_t ha_sync_cache_t;
+
+/**
+ * Locally cached HA state synced from other nodes.
+ */
+struct ha_sync_cache_t {
+
+       /**
+        * Get a synced and cached IKE_SA entry.
+        *
+        * If no cached IKE_SA with such an id exists, it gets created.
+        *
+        * @param id            IKE_SA identifier of cached SA.
+        * @return                      cached IKE_SA
+        */
+       ike_sa_t* (*get_ike_sa)(ha_sync_cache_t *this, ike_sa_id_t *id);
+
+       /**
+        * Delete a synced and cached IKE_SA entry.
+        *
+        * @param id            IKE_SA identifier of cached SA to delete.
+        */
+       void (*delete_ike_sa)(ha_sync_cache_t *this, ike_sa_id_t *id);
+
+       /**
+        * Activate a set of IKE_SAs identified by a segment.
+        *
+        * Activating means do a takeover of SAs as the responsible node has failed.
+        * This involves moving all SAs to the daemons IKE_SA manager and handle
+        * them actively now.
+        *
+        * @param segment       numerical segment to takeover
+        */
+       void (*activate_segment)(ha_sync_cache_t *this, u_int segment);
+
+       /**
+        * Destroy a ha_sync_cache_t.
+        */
+       void (*destroy)(ha_sync_cache_t *this);
+};
+
+/**
+ * Create a ha_sync_cache instance.
+ */
+ha_sync_cache_t *ha_sync_cache_create();
+
+#endif /* HA_SYNC_CACHE_ @}*/
index d5279da..b42ca51 100644 (file)
@@ -38,12 +38,26 @@ struct private_ha_sync_dispatcher_t {
        ha_sync_socket_t *socket;
 
        /**
+        * Synced SA state cache
+        */
+       ha_sync_cache_t *cache;
+
+       /**
         * Dispatcher job
         */
        callback_job_t *job;
 };
 
 /**
+ * Quick and dirty hack implementation of diffie_hellman_t.get_shared_secret
+ */
+static status_t get_shared_secret(diffie_hellman_t *this, chunk_t *secret)
+{
+       *secret = chunk_clone((*(chunk_t*)this->destroy));
+       return SUCCESS;
+}
+
+/**
  * Process messages of type IKE_ADD
  */
 static void process_ike_add(private_ha_sync_dispatcher_t *this,
@@ -52,49 +66,204 @@ static void process_ike_add(private_ha_sync_dispatcher_t *this,
        ha_sync_message_attribute_t attribute;
        ha_sync_message_value_t value;
        enumerator_t *enumerator;
+       ike_sa_t *ike_sa = NULL;
+       u_int16_t encr = 0, len = 0, integ = 0, prf = 0;
+       chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty;
 
        enumerator = message->create_attribute_enumerator(message);
        while (enumerator->enumerate(enumerator, &attribute, &value))
        {
                switch (attribute)
                {
-                       /* ike_sa_id_t* */
                        case HA_SYNC_IKE_ID:
+                               ike_sa = this->cache->get_ike_sa(this->cache, value.ike_sa_id);
+                               break;
                        case HA_SYNC_IKE_REKEY_ID:
-                               DBG1(DBG_IKE, " %d -> %llu:%llu %s", attribute,
-                                        value.ike_sa_id->get_initiator_spi(value.ike_sa_id),
-                                        value.ike_sa_id->get_responder_spi(value.ike_sa_id),
-                                        value.ike_sa_id->is_initiator(value.ike_sa_id) ?
-                                               "initiator" : "responder");
+                               DBG1(DBG_IKE, "TODO: rekey HA sync");
+                               break;
+                       case HA_SYNC_NONCE_I:
+                               nonce_i = value.chunk;
+                               break;
+                       case HA_SYNC_NONCE_R:
+                               nonce_r = value.chunk;
+                               break;
+                       case HA_SYNC_SECRET:
+                               secret = value.chunk;
+                               break;
+                       case HA_SYNC_ALG_ENCR:
+                               encr = value.u16;
+                               break;
+                       case HA_SYNC_ALG_ENCR_LEN:
+                               len = value.u16;
+                               break;
+                       case HA_SYNC_ALG_INTEG:
+                               integ = value.u16;
+                               break;
+                       case HA_SYNC_ALG_PRF:
+                               prf = value.u16;
+                               break;
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+
+       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 };
+
+               proposal = proposal_create(PROTO_IKE);
+               keymat = ike_sa->get_keymat(ike_sa);
+               if (integ)
+               {
+                       proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
+               }
+               if (encr)
+               {
+                       proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
+               }
+               if (prf)
+               {
+                       proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0);
+               }
+               if (!keymat->derive_ike_keys(keymat, proposal, &dh, nonce_i, nonce_r,
+                                                                       ike_sa->get_id(ike_sa), NULL))
+               {
+                       DBG1(DBG_IKE, "HA sync keymat derivation failed");
+               }
+               proposal->destroy(proposal);
+       }
+}
+
+/**
+ * Apply a condition flag to the IKE_SA if it is in set
+ */
+static void set_condition(ike_sa_t *ike_sa, ike_condition_t set,
+                                                 ike_condition_t flag)
+{
+       ike_sa->set_condition(ike_sa, flag, flag & set);
+}
+
+/**
+ * Apply a extension flag to the IKE_SA if it is in set
+ */
+static void set_extension(ike_sa_t *ike_sa, ike_extension_t set,
+                                                 ike_extension_t flag)
+{
+       if (flag & set)
+       {
+               ike_sa->enable_extension(ike_sa, flag);
+       }
+}
+
+/**
+ * Process messages of type IKE_UPDATE
+ */
+static void process_ike_update(private_ha_sync_dispatcher_t *this,
+                                                          ha_sync_message_t *message)
+{
+       ha_sync_message_attribute_t attribute;
+       ha_sync_message_value_t value;
+       enumerator_t *enumerator;
+       ike_sa_t *ike_sa = NULL;
+       peer_cfg_t *peer_cfg = NULL;
+
+       enumerator = message->create_attribute_enumerator(message);
+       while (enumerator->enumerate(enumerator, &attribute, &value))
+       {
+               if (attribute != HA_SYNC_IKE_ID && ike_sa == NULL)
+               {
+                       DBG1(DBG_IKE, "HA_SYNC_IKE_ID must be first attribute");
+                       break;
+               }
+               switch (attribute)
+               {
+                       case HA_SYNC_IKE_ID:
+                               ike_sa = this->cache->get_ike_sa(this->cache, value.ike_sa_id);
                                break;
-                       /* identification_t* */
                        case HA_SYNC_LOCAL_ID:
+                               ike_sa->set_my_id(ike_sa, value.id->clone(value.id));
+                               break;
                        case HA_SYNC_REMOTE_ID:
+                               ike_sa->set_other_id(ike_sa, value.id->clone(value.id));
+                               break;
                        case HA_SYNC_EAP_ID:
-                               DBG1(DBG_IKE, " %d -> %D", attribute, value.id);
+                               ike_sa->set_eap_identity(ike_sa, value.id->clone(value.id));
                                break;
-                       /* host_t* */
                        case HA_SYNC_LOCAL_ADDR:
+                               ike_sa->set_my_host(ike_sa, value.host->clone(value.host));
+                               break;
                        case HA_SYNC_REMOTE_ADDR:
+                               ike_sa->set_other_host(ike_sa, value.host->clone(value.host));
+                               break;
                        case HA_SYNC_LOCAL_VIP:
                        case HA_SYNC_REMOTE_VIP:
+                               ike_sa->set_virtual_ip(ike_sa, attribute == HA_SYNC_LOCAL_VIP,
+                                                                          value.host->clone(value.host));
+                               break;
                        case HA_SYNC_ADDITIONAL_ADDR:
-                               DBG1(DBG_IKE, " %d -> %H", attribute, value.host);
+                               ike_sa->add_additional_address(ike_sa,
+                                                                                          value.host->clone(value.host));
                                break;
-                       /* char* */
                        case HA_SYNC_CONFIG_NAME:
-                               DBG1(DBG_IKE, " %d -> %s", attribute, value.str);
+                               peer_cfg = charon->backends->get_peer_cfg_by_name(
+                                                                                               charon->backends, value.str);
                                break;
-                       /** u_int32_t */
                        case HA_SYNC_CONDITIONS:
+                               set_condition(ike_sa, value.u32, EXT_NATT);
+                               set_condition(ike_sa, value.u32, EXT_MOBIKE);
+                               set_condition(ike_sa, value.u32, EXT_HASH_AND_URL);
+                               break;
                        case HA_SYNC_EXTENSIONS:
-                               DBG1(DBG_IKE, " %d -> %lu", attribute, value.u32);
+                               set_extension(ike_sa, value.u32, COND_NAT_ANY);
+                               set_extension(ike_sa, value.u32, COND_NAT_HERE);
+                               set_extension(ike_sa, value.u32, COND_NAT_THERE);
+                               set_extension(ike_sa, value.u32, COND_NAT_FAKE);
+                               set_extension(ike_sa, value.u32, COND_EAP_AUTHENTICATED);
+                               set_extension(ike_sa, value.u32, COND_CERTREQ_SEEN);
+                               set_extension(ike_sa, value.u32, COND_ORIGINAL_INITIATOR);
                                break;
-                       /** chunk_t */
-                       case HA_SYNC_NONCE_I:
-                       case HA_SYNC_NONCE_R:
-                       case HA_SYNC_SECRET:
-                               DBG1(DBG_IKE, " %d -> %B", attribute, &value.chunk);
+                       default:
+                               break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (peer_cfg)
+       {
+               ike_sa->set_peer_cfg(ike_sa, peer_cfg);
+               peer_cfg->destroy(peer_cfg);
+       }
+       else
+       {
+               DBG1(DBG_IKE, "HA sync is missing nodes configuration");
+       }
+}
+
+/**
+ * Process messages of type IKE_DELETE
+ */
+static void process_ike_delete(private_ha_sync_dispatcher_t *this,
+                                                          ha_sync_message_t *message)
+{
+       ha_sync_message_attribute_t attribute;
+       ha_sync_message_value_t value;
+       enumerator_t *enumerator;
+
+       enumerator = message->create_attribute_enumerator(message);
+       while (enumerator->enumerate(enumerator, &attribute, &value))
+       {
+               switch (attribute)
+               {
+                       case HA_SYNC_IKE_ID:
+                               this->cache->delete_ike_sa(this->cache, value.ike_sa_id);
+                               break;
+                       default:
                                break;
                }
        }
@@ -115,8 +284,10 @@ static job_requeue_t dispatch(private_ha_sync_dispatcher_t *this)
                        process_ike_add(this, message);
                        break;
                case HA_SYNC_IKE_UPDATE:
+                       process_ike_update(this, message);
                        break;
                case HA_SYNC_IKE_DELETE:
+                       process_ike_delete(this, message);
                        break;
                case HA_SYNC_IKE_REKEY:
                        break;
@@ -146,13 +317,15 @@ static void destroy(private_ha_sync_dispatcher_t *this)
 /**
  * See header
  */
-ha_sync_dispatcher_t *ha_sync_dispatcher_create(ha_sync_socket_t *socket)
+ha_sync_dispatcher_t *ha_sync_dispatcher_create(ha_sync_socket_t *socket,
+                                                                                               ha_sync_cache_t *cache)
 {
        private_ha_sync_dispatcher_t *this = malloc_thing(private_ha_sync_dispatcher_t);
 
        this->public.destroy = (void(*)(ha_sync_dispatcher_t*))destroy;
 
        this->socket = socket;
+       this->cache = cache;
        this->job = callback_job_create((callback_job_cb_t)dispatch,
                                                                        this, NULL, NULL);
        charon->processor->queue_job(charon->processor, (job_t*)this->job);
index eb2817e..eda4c4d 100644 (file)
@@ -24,6 +24,7 @@
 #define HA_SYNC_DISPATCHER_H_
 
 #include "ha_sync_socket.h"
+#include "ha_sync_cache.h"
 
 typedef struct ha_sync_dispatcher_t ha_sync_dispatcher_t;
 
@@ -42,8 +43,10 @@ struct ha_sync_dispatcher_t {
  * Create a ha_sync_dispatcher instance pulling from socket.
  *
  * @param socket               socket to pull messages from
+ * @param cache                        cache to push synced SAs to
  * @return                             dispatcher object
  */
-ha_sync_dispatcher_t *ha_sync_dispatcher_create(ha_sync_socket_t *socket);
+ha_sync_dispatcher_t *ha_sync_dispatcher_create(ha_sync_socket_t *socket,
+                                                                                               ha_sync_cache_t *cache);
 
 #endif /* HA_SYNC_DISPATCHER_ @}*/
index 083b6a0..2984f57 100644 (file)
@@ -66,31 +66,10 @@ static bool ike_keys(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
                                         diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r,
                                         ike_sa_t *rekey)
 {
-       iterator_t *iterator;
        ha_sync_message_t *m;
-       peer_cfg_t *peer_cfg;
-       u_int32_t extension, condition;
-       host_t *local_vip, *remote_vip, *addr;
-       identification_t *eap_id;
        chunk_t secret;
-
-       peer_cfg = ike_sa->get_peer_cfg(ike_sa);
-
-       condition = copy_condition(ike_sa, COND_NAT_ANY)
-                         | copy_condition(ike_sa, COND_NAT_HERE)
-                         | copy_condition(ike_sa, COND_NAT_THERE)
-                         | copy_condition(ike_sa, COND_NAT_FAKE)
-                         | copy_condition(ike_sa, COND_EAP_AUTHENTICATED)
-                         | copy_condition(ike_sa, COND_CERTREQ_SEEN)
-                         | copy_condition(ike_sa, COND_ORIGINAL_INITIATOR);
-
-       extension = copy_extension(ike_sa, EXT_NATT)
-                         | copy_extension(ike_sa, EXT_MOBIKE)
-                         | copy_extension(ike_sa, EXT_HASH_AND_URL);
-
-       local_vip = ike_sa->get_virtual_ip(ike_sa, TRUE);
-       remote_vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
-       eap_id = ike_sa->get_eap_identity(ike_sa);
+       proposal_t *proposal;
+       u_int16_t alg, len;
 
        if (dh->get_shared_secret(dh, &secret) != SUCCESS)
        {
@@ -102,30 +81,6 @@ static bool ike_keys(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
                m = ha_sync_message_create(HA_SYNC_IKE_ADD);
 
                m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
-               m->add_attribute(m, HA_SYNC_LOCAL_ID, ike_sa->get_my_id(ike_sa));
-               m->add_attribute(m, HA_SYNC_REMOTE_ID, ike_sa->get_other_id(ike_sa));
-               m->add_attribute(m, HA_SYNC_LOCAL_ADDR, ike_sa->get_my_host(ike_sa));
-               m->add_attribute(m, HA_SYNC_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
-               m->add_attribute(m, HA_SYNC_CONDITIONS, condition);
-               m->add_attribute(m, HA_SYNC_EXTENSIONS, extension);
-               if (local_vip)
-               {
-                       m->add_attribute(m, HA_SYNC_LOCAL_VIP, local_vip);
-               }
-               if (remote_vip)
-               {
-                       m->add_attribute(m, HA_SYNC_REMOTE_VIP, remote_vip);
-               }
-               if (eap_id)
-               {
-                       m->add_attribute(m, HA_SYNC_EAP_ID, eap_id);
-               }
-               iterator = ike_sa->create_additional_address_iterator(ike_sa);
-               while (iterator->iterate(iterator, (void**)&addr))
-               {
-                       m->add_attribute(m, HA_SYNC_ADDITIONAL_ADDR, addr);
-               }
-               iterator->destroy(iterator);
        }
        else
        {
@@ -135,6 +90,23 @@ static bool ike_keys(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
                m->add_attribute(m, HA_SYNC_IKE_REKEY_ID, rekey->get_id(rekey));
        }
 
+       proposal = ike_sa->get_proposal(ike_sa);
+       if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &len))
+       {
+               m->add_attribute(m, HA_SYNC_ALG_ENCR, alg);
+               if (len)
+               {
+                       m->add_attribute(m, HA_SYNC_ALG_ENCR_LEN, len);
+               }
+       }
+       if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL))
+       {
+               m->add_attribute(m, HA_SYNC_ALG_INTEG, alg);
+       }
+       if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL))
+       {
+               m->add_attribute(m, HA_SYNC_ALG_PRF, alg);
+       }
        m->add_attribute(m, HA_SYNC_NONCE_I, nonce_i);
        m->add_attribute(m, HA_SYNC_NONCE_R, nonce_r);
        m->add_attribute(m, HA_SYNC_SECRET, secret);
@@ -147,6 +119,85 @@ static bool ike_keys(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
 }
 
 /**
+ * Implementation of listener_t.ike_state_change
+ */
+static bool ike_state_change(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
+                                                        ike_sa_state_t state)
+{
+       ha_sync_message_t *m;
+
+       switch (state)
+       {
+               case IKE_ESTABLISHED:
+               {
+                       iterator_t *iterator;
+                       peer_cfg_t *peer_cfg;
+                       u_int32_t extension, condition;
+                       host_t *local_vip, *remote_vip, *addr;
+                       identification_t *eap_id;
+
+                       peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+
+                       condition = copy_condition(ike_sa, COND_NAT_ANY)
+                                         | copy_condition(ike_sa, COND_NAT_HERE)
+                                         | copy_condition(ike_sa, COND_NAT_THERE)
+                                         | copy_condition(ike_sa, COND_NAT_FAKE)
+                                         | copy_condition(ike_sa, COND_EAP_AUTHENTICATED)
+                                         | copy_condition(ike_sa, COND_CERTREQ_SEEN)
+                                         | copy_condition(ike_sa, COND_ORIGINAL_INITIATOR);
+
+                       extension = copy_extension(ike_sa, EXT_NATT)
+                                         | copy_extension(ike_sa, EXT_MOBIKE)
+                                         | copy_extension(ike_sa, EXT_HASH_AND_URL);
+
+                       local_vip = ike_sa->get_virtual_ip(ike_sa, TRUE);
+                       remote_vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
+                       eap_id = ike_sa->get_eap_identity(ike_sa);
+
+                       m = ha_sync_message_create(HA_SYNC_IKE_UPDATE);
+                       m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
+                       m->add_attribute(m, HA_SYNC_LOCAL_ID, ike_sa->get_my_id(ike_sa));
+                       m->add_attribute(m, HA_SYNC_REMOTE_ID, ike_sa->get_other_id(ike_sa));
+                       m->add_attribute(m, HA_SYNC_LOCAL_ADDR, ike_sa->get_my_host(ike_sa));
+                       m->add_attribute(m, HA_SYNC_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
+                       m->add_attribute(m, HA_SYNC_CONDITIONS, condition);
+                       m->add_attribute(m, HA_SYNC_EXTENSIONS, extension);
+                       m->add_attribute(m, HA_SYNC_CONFIG_NAME, peer_cfg->get_name(peer_cfg));
+                       if (local_vip)
+                       {
+                               m->add_attribute(m, HA_SYNC_LOCAL_VIP, local_vip);
+                       }
+                       if (remote_vip)
+                       {
+                               m->add_attribute(m, HA_SYNC_REMOTE_VIP, remote_vip);
+                       }
+                       if (eap_id)
+                       {
+                               m->add_attribute(m, HA_SYNC_EAP_ID, eap_id);
+                       }
+                       iterator = ike_sa->create_additional_address_iterator(ike_sa);
+                       while (iterator->iterate(iterator, (void**)&addr))
+                       {
+                               m->add_attribute(m, HA_SYNC_ADDITIONAL_ADDR, addr);
+                       }
+                       iterator->destroy(iterator);
+                       break;
+               }
+               case IKE_DESTROYING:
+               {
+                       m = ha_sync_message_create(HA_SYNC_IKE_DELETE);
+                       m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
+                       break;
+               }
+               default:
+                       return TRUE;
+       }
+       this->socket->push(this->socket, m);
+       m->destroy(m);
+       return TRUE;
+}
+
+/**
  * Implementation of ha_sync_ike_t.destroy.
  */
 static void destroy(private_ha_sync_ike_t *this)
@@ -163,6 +214,7 @@ ha_sync_ike_t *ha_sync_ike_create(ha_sync_socket_t *socket)
 
        memset(&this->public.listener, 0, sizeof(listener_t));
        this->public.listener.ike_keys = (bool(*)(listener_t*, ike_sa_t *ike_sa, diffie_hellman_t *dh,chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey))ike_keys;
+       this->public.listener.ike_state_change = (bool(*)(listener_t*,ike_sa_t *ike_sa, ike_sa_state_t state))ike_state_change;
        this->public.destroy = (void(*)(ha_sync_ike_t*))destroy;
 
        this->socket = socket;
index f8a81dc..7a1fc71 100644 (file)
@@ -191,6 +191,20 @@ static void add_attribute(private_ha_sync_message_t *this,
                        this->buf.len += len;
                        break;
                }
+               /* u_int16_t */
+               case HA_SYNC_ALG_PRF:
+               case HA_SYNC_ALG_ENCR:
+               case HA_SYNC_ALG_ENCR_LEN:
+               case HA_SYNC_ALG_INTEG:
+               {
+                       u_int16_t val;
+
+                       val = (u_int16_t)va_arg(args, u_int32_t);
+                       check_buf(this, sizeof(val));
+                       *(u_int16_t*)(this->buf.ptr + this->buf.len) = htons(val);
+                       this->buf.len += sizeof(val);
+                       break;
+               }
                /** u_int32_t */
                case HA_SYNC_CONDITIONS:
                case HA_SYNC_EXTENSIONS:
@@ -199,7 +213,7 @@ static void add_attribute(private_ha_sync_message_t *this,
 
                        val = va_arg(args, u_int32_t);
                        check_buf(this, sizeof(val));
-                       this->buf.ptr[this->buf.len] = htonl(val);
+                       *(u_int32_t*)(this->buf.ptr + this->buf.len) = htonl(val);
                        this->buf.len += sizeof(val);
                        break;
                }
@@ -349,6 +363,21 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
                        this->buf = chunk_skip(this->buf, len + 1);
                        return TRUE;
                }
+               /** u_int16_t */
+               case HA_SYNC_ALG_PRF:
+               case HA_SYNC_ALG_ENCR:
+               case HA_SYNC_ALG_ENCR_LEN:
+               case HA_SYNC_ALG_INTEG:
+               {
+                       if (this->buf.len < sizeof(u_int16_t))
+                       {
+                               return FALSE;
+                       }
+                       value->u16 = ntohs(*(u_int16_t*)this->buf.ptr);
+                       *attr_out = attr;
+                       this->buf = chunk_skip(this->buf, sizeof(u_int16_t));
+                       return TRUE;
+               }
                /** u_int32_t */
                case HA_SYNC_CONDITIONS:
                case HA_SYNC_EXTENSIONS:
index 53701e1..e7d358c 100644 (file)
@@ -92,6 +92,14 @@ enum ha_sync_message_attribute_t {
        HA_SYNC_NONCE_R,
        /** chunk_t, diffie hellman shared secret */
        HA_SYNC_SECRET,
+       /** u_int16_t, pseudo random function */
+       HA_SYNC_ALG_PRF,
+       /** u_int16_t, encryption algorithm */
+       HA_SYNC_ALG_ENCR,
+       /** u_int16_t, encryption key size in bytes */
+       HA_SYNC_ALG_ENCR_LEN,
+       /** u_int16_t, integrity protection algorithm */
+       HA_SYNC_ALG_INTEG,
 };
 
 /**
@@ -99,6 +107,7 @@ enum ha_sync_message_attribute_t {
  */
 union ha_sync_message_value_t {
        u_int32_t u32;
+       u_int16_t u16;
        char *str;
        chunk_t chunk;
        ike_sa_id_t *ike_sa_id;
index 8a73512..aae51aa 100644 (file)
@@ -20,6 +20,7 @@
 #include "ha_sync_child.h"
 #include "ha_sync_socket.h"
 #include "ha_sync_dispatcher.h"
+#include "ha_sync_cache.h"
 
 #include <daemon.h>
 #include <config/child_cfg.h>
@@ -55,6 +56,11 @@ struct private_ha_sync_plugin_t {
         * Dispatcher to process incoming messages
         */
        ha_sync_dispatcher_t *dispatcher;
+
+       /**
+        * Local cache of a nodes synced SAs
+        */
+       ha_sync_cache_t *cache;
 };
 
 /**
@@ -67,6 +73,7 @@ static void destroy(private_ha_sync_plugin_t *this)
        this->ike->destroy(this->ike);
        this->child->destroy(this->child);
        this->dispatcher->destroy(this->dispatcher);
+       this->cache->destroy(this->cache);
        this->socket->destroy(this->socket);
        free(this);
 }
@@ -86,7 +93,8 @@ plugin_t *plugin_create()
                free(this);
                return NULL;
        }
-       this->dispatcher = ha_sync_dispatcher_create(this->socket);
+       this->cache = ha_sync_cache_create();
+       this->dispatcher = ha_sync_dispatcher_create(this->socket, this->cache);
        this->ike = ha_sync_ike_create(this->socket);
        this->child = ha_sync_child_create(this->socket);
        charon->bus->add_listener(charon->bus, &this->ike->listener);