summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/ha
diff options
context:
space:
mode:
authorRene Mayrhofer <rene@mayrhofer.eu.org>2010-08-09 08:09:54 +0000
committerRene Mayrhofer <rene@mayrhofer.eu.org>2010-08-09 08:09:54 +0000
commitb8064f4099997a9e2179f3ad4ace605f5ccac3a1 (patch)
tree81778e976b476374c48b4fe83d084b986b890421 /src/libcharon/plugins/ha
parent1ac70afcc1f7d6d2738a34308810719b0976d29f (diff)
downloadvyos-strongswan-b8064f4099997a9e2179f3ad4ace605f5ccac3a1.tar.gz
vyos-strongswan-b8064f4099997a9e2179f3ad4ace605f5ccac3a1.zip
[svn-upgrade] new version strongswan (4.4.1)
Diffstat (limited to 'src/libcharon/plugins/ha')
-rw-r--r--src/libcharon/plugins/ha/Makefile.am4
-rw-r--r--src/libcharon/plugins/ha/Makefile.in11
-rw-r--r--src/libcharon/plugins/ha/ha_attribute.c364
-rw-r--r--src/libcharon/plugins/ha/ha_attribute.h60
-rw-r--r--src/libcharon/plugins/ha/ha_cache.c362
-rw-r--r--src/libcharon/plugins/ha/ha_cache.h78
-rw-r--r--src/libcharon/plugins/ha/ha_child.c84
-rw-r--r--src/libcharon/plugins/ha/ha_child.h12
-rw-r--r--src/libcharon/plugins/ha/ha_ctl.c26
-rw-r--r--src/libcharon/plugins/ha/ha_ctl.h6
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.c209
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.h11
-rw-r--r--src/libcharon/plugins/ha/ha_ike.c101
-rw-r--r--src/libcharon/plugins/ha/ha_ike.h11
-rw-r--r--src/libcharon/plugins/ha/ha_kernel.c96
-rw-r--r--src/libcharon/plugins/ha/ha_kernel.h28
-rw-r--r--src/libcharon/plugins/ha/ha_message.c102
-rw-r--r--src/libcharon/plugins/ha/ha_message.h26
-rw-r--r--src/libcharon/plugins/ha/ha_plugin.c45
-rw-r--r--src/libcharon/plugins/ha/ha_plugin.h2
-rw-r--r--src/libcharon/plugins/ha/ha_segments.c220
-rw-r--r--src/libcharon/plugins/ha/ha_segments.h23
-rw-r--r--src/libcharon/plugins/ha/ha_socket.c58
-rw-r--r--src/libcharon/plugins/ha/ha_socket.h4
-rw-r--r--src/libcharon/plugins/ha/ha_tunnel.c78
-rw-r--r--src/libcharon/plugins/ha/ha_tunnel.h2
26 files changed, 1534 insertions, 489 deletions
diff --git a/src/libcharon/plugins/ha/Makefile.am b/src/libcharon/plugins/ha/Makefile.am
index 74fe1f4c7..0df1b8d91 100644
--- a/src/libcharon/plugins/ha/Makefile.am
+++ b/src/libcharon/plugins/ha/Makefile.am
@@ -17,9 +17,11 @@ libstrongswan_ha_la_SOURCES = \
ha_tunnel.h ha_tunnel.c \
ha_dispatcher.h ha_dispatcher.c \
ha_segments.h ha_segments.c \
+ ha_cache.h ha_cache.c \
ha_kernel.h ha_kernel.c \
ha_ctl.h ha_ctl.c \
ha_ike.h ha_ike.c \
- ha_child.h ha_child.c
+ ha_child.h ha_child.c \
+ ha_attribute.h ha_attribute.c
libstrongswan_ha_la_LDFLAGS = -module -avoid-version
diff --git a/src/libcharon/plugins/ha/Makefile.in b/src/libcharon/plugins/ha/Makefile.in
index c60d3bf56..5ca9b464b 100644
--- a/src/libcharon/plugins/ha/Makefile.in
+++ b/src/libcharon/plugins/ha/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11 from Makefile.am.
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -76,7 +76,8 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
libstrongswan_ha_la_LIBADD =
am_libstrongswan_ha_la_OBJECTS = ha_plugin.lo ha_message.lo \
ha_socket.lo ha_tunnel.lo ha_dispatcher.lo ha_segments.lo \
- ha_kernel.lo ha_ctl.lo ha_ike.lo ha_child.lo
+ ha_cache.lo ha_kernel.lo ha_ctl.lo ha_ike.lo ha_child.lo \
+ ha_attribute.lo
libstrongswan_ha_la_OBJECTS = $(am_libstrongswan_ha_la_OBJECTS)
libstrongswan_ha_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
@@ -269,10 +270,12 @@ libstrongswan_ha_la_SOURCES = \
ha_tunnel.h ha_tunnel.c \
ha_dispatcher.h ha_dispatcher.c \
ha_segments.h ha_segments.c \
+ ha_cache.h ha_cache.c \
ha_kernel.h ha_kernel.c \
ha_ctl.h ha_ctl.c \
ha_ike.h ha_ike.c \
- ha_child.h ha_child.c
+ ha_child.h ha_child.c \
+ ha_attribute.h ha_attribute.c
libstrongswan_ha_la_LDFLAGS = -module -avoid-version
all: all-am
@@ -358,6 +361,8 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_attribute.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_cache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_child.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_ctl.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ha_dispatcher.Plo@am__quote@
diff --git a/src/libcharon/plugins/ha/ha_attribute.c b/src/libcharon/plugins/ha/ha_attribute.c
new file mode 100644
index 000000000..b08abe1a9
--- /dev/null
+++ b/src/libcharon/plugins/ha/ha_attribute.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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.
+ */
+
+#include "ha_attribute.h"
+
+#include <utils/linked_list.h>
+#include <threading/mutex.h>
+
+typedef struct private_ha_attribute_t private_ha_attribute_t;
+
+/**
+ * Private data of an ha_attribute_t object.
+ */
+struct private_ha_attribute_t {
+
+ /**
+ * Public ha_attribute_t interface.
+ */
+ ha_attribute_t public;
+
+ /**
+ * List of pools, pool_t
+ */
+ linked_list_t *pools;
+
+ /**
+ * Mutex to lock mask
+ */
+ mutex_t *mutex;
+
+ /**
+ * Kernel helper
+ */
+ ha_kernel_t *kernel;
+
+ /**
+ * Segment responsibility
+ */
+ ha_segments_t *segments;
+};
+
+/**
+ * In-memory pool.
+ */
+typedef struct {
+ /** name of the pool */
+ char *name;
+ /** base address of pool */
+ host_t *base;
+ /** total number of addresses in this pool */
+ int size;
+ /** bitmask for address usage */
+ u_char *mask;
+} pool_t;
+
+/**
+ * Clean up a pool entry
+ */
+static void pool_destroy(pool_t *pool)
+{
+ pool->base->destroy(pool->base);
+ free(pool->name);
+ free(pool->mask);
+ free(pool);
+}
+
+/**
+ * convert a pool offset to an address
+ */
+static host_t* offset2host(pool_t *pool, int offset)
+{
+ chunk_t addr;
+ host_t *host;
+ u_int32_t *pos;
+
+ if (offset > pool->size)
+ {
+ return NULL;
+ }
+
+ addr = chunk_clone(pool->base->get_address(pool->base));
+ if (pool->base->get_family(pool->base) == AF_INET6)
+ {
+ pos = (u_int32_t*)(addr.ptr + 12);
+ }
+ else
+ {
+ pos = (u_int32_t*)addr.ptr;
+ }
+ *pos = htonl(offset + ntohl(*pos));
+ host = host_create_from_chunk(pool->base->get_family(pool->base), addr, 0);
+ free(addr.ptr);
+ return host;
+}
+
+/**
+ * convert a host to a pool offset
+ */
+static int host2offset(pool_t *pool, host_t *addr)
+{
+ chunk_t host, base;
+ u_int32_t hosti, basei;
+
+ if (addr->get_family(addr) != pool->base->get_family(pool->base))
+ {
+ return -1;
+ }
+ host = addr->get_address(addr);
+ base = pool->base->get_address(pool->base);
+ if (addr->get_family(addr) == AF_INET6)
+ {
+ /* only look at last /32 block */
+ if (!memeq(host.ptr, base.ptr, 12))
+ {
+ return -1;
+ }
+ host = chunk_skip(host, 12);
+ base = chunk_skip(base, 12);
+ }
+ hosti = ntohl(*(u_int32_t*)(host.ptr));
+ basei = ntohl(*(u_int32_t*)(base.ptr));
+ if (hosti > basei + pool->size)
+ {
+ return -1;
+ }
+ return hosti - basei;
+}
+
+/**
+ * Find a pool by its name
+ */
+static pool_t* get_pool(private_ha_attribute_t *this, char *name)
+{
+ enumerator_t *enumerator;
+ pool_t *pool, *found = NULL;
+
+ enumerator = this->pools->create_enumerator(this->pools);
+ while (enumerator->enumerate(enumerator, &pool))
+ {
+ if (streq(name, pool->name))
+ {
+ found = pool;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found;
+}
+
+/**
+ * Check if we are responsible for a bit in our bitmask
+ */
+static bool responsible_for(private_ha_attribute_t *this, int bit)
+{
+ u_int segment;
+
+ segment = this->kernel->get_segment_int(this->kernel, bit);
+ return this->segments->is_active(this->segments, segment);
+}
+
+METHOD(attribute_provider_t, acquire_address, host_t*,
+ private_ha_attribute_t *this, char *name, identification_t *id,
+ host_t *requested)
+{
+ pool_t *pool;
+ int offset = -1, byte, bit;
+ host_t *address;
+
+ this->mutex->lock(this->mutex);
+ pool = get_pool(this, name);
+ if (pool)
+ {
+ for (byte = 0; byte < pool->size / 8; byte++)
+ {
+ if (pool->mask[byte] != 0xFF)
+ {
+ for (bit = 0; bit < 8; bit++)
+ {
+ if (!(pool->mask[byte] & 1 << bit) &&
+ responsible_for(this, bit))
+ {
+ offset = byte * 8 + bit;
+ pool->mask[byte] |= 1 << bit;
+ break;
+ }
+ }
+ }
+ if (offset != -1)
+ {
+ break;
+ }
+ }
+ if (offset == -1)
+ {
+ DBG1(DBG_CFG, "no address left in HA pool '%s' belonging to"
+ "a responsible segment", name);
+ }
+ }
+ this->mutex->unlock(this->mutex);
+ if (offset != -1)
+ {
+ address = offset2host(pool, offset);
+ DBG1(DBG_CFG, "acquired address %H from HA pool '%s'", address, name);
+ return address;
+ }
+ return NULL;
+}
+
+METHOD(attribute_provider_t, release_address, bool,
+ private_ha_attribute_t *this, char *name, host_t *address,
+ identification_t *id)
+{
+ pool_t *pool;
+ int offset;
+ bool found = FALSE;
+
+ this->mutex->lock(this->mutex);
+ pool = get_pool(this, name);
+ if (pool)
+ {
+ offset = host2offset(pool, address);
+ if (offset > 0 && offset < pool->size)
+ {
+ pool->mask[offset / 8] &= ~(1 << (offset % 8));
+ DBG1(DBG_CFG, "released address %H to HA pool '%s'", address, name);
+ found = TRUE;
+ }
+ }
+ this->mutex->unlock(this->mutex);
+ return found;
+}
+
+METHOD(ha_attribute_t, reserve, void,
+ private_ha_attribute_t *this, char *name, host_t *address)
+{
+ pool_t *pool;
+ int offset;
+
+ this->mutex->lock(this->mutex);
+ pool = get_pool(this, name);
+ if (pool)
+ {
+ offset = host2offset(pool, address);
+ if (offset > 0 && offset < pool->size)
+ {
+ pool->mask[offset / 8] |= 1 << (offset % 8);
+ DBG1(DBG_CFG, "reserved address %H in HA pool '%s'", address, name);
+ }
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(ha_attribute_t, destroy, void,
+ private_ha_attribute_t *this)
+{
+ this->pools->destroy_function(this->pools, (void*)pool_destroy);
+ this->mutex->destroy(this->mutex);
+ free(this);
+}
+
+/**
+ * Load the configured pools.
+ */
+static void load_pools(private_ha_attribute_t *this)
+{
+ enumerator_t *enumerator;
+ char *name, *net, *bits;
+ host_t *base;
+ int mask, maxbits;
+ pool_t *pool;
+
+ enumerator = lib->settings->create_key_value_enumerator(lib->settings,
+ "charon.plugins.ha.pools");
+ while (enumerator->enumerate(enumerator, &name, &net))
+ {
+ net = strdup(net);
+ bits = strchr(net, '/');
+ if (!bits)
+ {
+ DBG1(DBG_CFG, "invalid HA pool '%s' subnet, skipped", name);
+ free(net);
+ continue;
+ }
+ *bits++ = '\0';
+
+ base = host_create_from_string(net, 0);
+ mask = atoi(bits);
+ free(net);
+ if (!base || !mask)
+ {
+ DESTROY_IF(base);
+ DBG1(DBG_CFG, "invalid HA pool '%s', skipped", name);
+ continue;
+ }
+ maxbits = base->get_family(base) == AF_INET ? 32 : 128;
+ mask = maxbits - mask;
+ if (mask > 24)
+ {
+ mask = 24;
+ DBG1(DBG_CFG, "size of HA pool '%s' limited to /%d",
+ name, maxbits - mask);
+ }
+ if (mask < 3)
+ {
+ DBG1(DBG_CFG, "HA pool '%s' too small, skipped", name);
+ base->destroy(base);
+ continue;
+ }
+
+ INIT(pool,
+ .name = strdup(name),
+ .base = base,
+ .size = (1 << mask),
+ );
+ pool->mask = calloc(pool->size / 8, 1);
+ /* do not use first/last address of pool */
+ pool->mask[0] |= 0x01;
+ pool->mask[pool->size / 8 - 1] |= 0x80;
+
+ DBG1(DBG_CFG, "loaded HA pool '%s' %H/%d (%d addresses)",
+ pool->name, pool->base, maxbits - mask, pool->size - 2);
+ this->pools->insert_last(this->pools, pool);
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
+ * See header
+ */
+ha_attribute_t *ha_attribute_create(ha_kernel_t *kernel, ha_segments_t *segments)
+{
+ private_ha_attribute_t *this;
+
+ INIT(this,
+ .public = {
+ .provider = {
+ .acquire_address = _acquire_address,
+ .release_address = _release_address,
+ .create_attribute_enumerator = enumerator_create_empty,
+ },
+ .reserve = _reserve,
+ .destroy = _destroy,
+ },
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .pools = linked_list_create(),
+ .kernel = kernel,
+ .segments = segments,
+ );
+
+ load_pools(this);
+
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/ha/ha_attribute.h b/src/libcharon/plugins/ha/ha_attribute.h
new file mode 100644
index 000000000..d1e4f5e89
--- /dev/null
+++ b/src/libcharon/plugins/ha/ha_attribute.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup ha_attribute ha_attribute
+ * @{ @ingroup ha
+ */
+
+#ifndef HA_ATTRIBUTE_H_
+#define HA_ATTRIBUTE_H_
+
+#include "ha_kernel.h"
+#include "ha_segments.h"
+
+#include <attributes/attribute_provider.h>
+
+typedef struct ha_attribute_t ha_attribute_t;
+
+/**
+ * A HA enabled in memory address pool attribute provider.
+ */
+struct ha_attribute_t {
+
+ /**
+ * Implements attribute provider interface.
+ */
+ attribute_provider_t provider;
+
+ /**
+ * Reserve an address for a passive IKE_SA.
+ *
+ * @param name pool name to reserve address in
+ * @param address address to reserve
+ */
+ void (*reserve)(ha_attribute_t *this, char *name, host_t *address);
+
+ /**
+ * Destroy a ha_attribute_t.
+ */
+ void (*destroy)(ha_attribute_t *this);
+};
+
+/**
+ * Create a ha_attribute instance.
+ */
+ha_attribute_t *ha_attribute_create(ha_kernel_t *kernel, ha_segments_t *segments);
+
+#endif /** HA_ATTRIBUTE_H_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_cache.c b/src/libcharon/plugins/ha/ha_cache.c
new file mode 100644
index 000000000..1ebc33ca4
--- /dev/null
+++ b/src/libcharon/plugins/ha/ha_cache.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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.
+ */
+
+#include "ha_cache.h"
+
+#include <utils/hashtable.h>
+#include <utils/linked_list.h>
+#include <threading/mutex.h>
+#include <processing/jobs/callback_job.h>
+
+typedef struct private_ha_cache_t private_ha_cache_t;
+
+/**
+ * Private data of an ha_cache_t object.
+ */
+struct private_ha_cache_t {
+
+ /**
+ * Public ha_cache_t interface.
+ */
+ ha_cache_t public;
+
+ /**
+ * Kernel helper functions
+ */
+ ha_kernel_t *kernel;
+
+ /**
+ * Socket to send sync messages over
+ */
+ ha_socket_t *socket;
+
+ /**
+ * Total number of segments
+ */
+ u_int count;
+
+ /**
+ * cached entries (ike_sa_t, entry_t)
+ */
+ hashtable_t *cache;
+
+ /**
+ * Mutex to lock cache
+ */
+ mutex_t *mutex;
+};
+
+/**
+ * Hashtable hash function
+ */
+static u_int hash(void *key)
+{
+ return (uintptr_t)key;
+}
+
+/**
+ * Hashtable equals function
+ */
+static bool equals(void *a, void *b)
+{
+ return a == b;
+}
+
+/**
+ * Cache entry for an IKE_SA
+ */
+typedef struct {
+ /* segment this entry is associate to */
+ u_int segment;
+ /* ADD message */
+ ha_message_t *add;
+ /* list of updates UPDATE message */
+ linked_list_t *updates;
+ /* last initiator mid */
+ ha_message_t *midi;
+ /* last responder mid */
+ ha_message_t *midr;
+} entry_t;
+
+/**
+ * Create a entry with an add message
+ */
+static entry_t *entry_create(ha_message_t *add)
+{
+ entry_t *entry;
+
+ INIT(entry,
+ .add = add,
+ .updates = linked_list_create(),
+ );
+ return entry;
+}
+
+/**
+ * clean up a entry
+ */
+static void entry_destroy(entry_t *entry)
+{
+ entry->updates->destroy_offset(entry->updates,
+ offsetof(ha_message_t, destroy));
+ entry->add->destroy(entry->add);
+ DESTROY_IF(entry->midi);
+ DESTROY_IF(entry->midr);
+ free(entry);
+}
+
+METHOD(ha_cache_t, cache, void,
+ private_ha_cache_t *this, ike_sa_t *ike_sa, ha_message_t *message)
+{
+ entry_t *entry;
+
+ this->mutex->lock(this->mutex);
+ switch (message->get_type(message))
+ {
+ case HA_IKE_ADD:
+ entry = entry_create(message);
+ entry = this->cache->put(this->cache, ike_sa, entry);
+ if (entry)
+ {
+ entry_destroy(entry);
+ }
+ break;
+ case HA_IKE_UPDATE:
+ entry = this->cache->get(this->cache, ike_sa);
+ if (entry)
+ {
+ entry->segment = this->kernel->get_segment(this->kernel,
+ ike_sa->get_other_host(ike_sa));
+ entry->updates->insert_last(entry->updates, message);
+ break;
+ }
+ message->destroy(message);
+ break;
+ case HA_IKE_MID_INITIATOR:
+ entry = this->cache->get(this->cache, ike_sa);
+ if (entry)
+ {
+ DESTROY_IF(entry->midi);
+ entry->midi = message;
+ break;
+ }
+ message->destroy(message);
+ break;
+ case HA_IKE_MID_RESPONDER:
+ entry = this->cache->get(this->cache, ike_sa);
+ if (entry)
+ {
+ DESTROY_IF(entry->midr);
+ entry->midr = message;
+ break;
+ }
+ message->destroy(message);
+ break;
+ case HA_IKE_DELETE:
+ entry = this->cache->remove(this->cache, ike_sa);
+ if (entry)
+ {
+ entry_destroy(entry);
+ }
+ message->destroy(message);
+ break;
+ default:
+ message->destroy(message);
+ break;
+ }
+ this->mutex->unlock(this->mutex);
+}
+
+METHOD(ha_cache_t, delete_, void,
+ private_ha_cache_t *this, ike_sa_t *ike_sa)
+{
+ entry_t *entry;
+
+ entry = this->cache->remove(this->cache, ike_sa);
+ if (entry)
+ {
+ entry_destroy(entry);
+ }
+}
+
+/**
+ * Rekey all children of an IKE_SA
+ */
+static status_t rekey_children(ike_sa_t *ike_sa)
+{
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+ status_t status = SUCCESS;
+
+ iterator = ike_sa->create_child_sa_iterator(ike_sa);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ DBG1(DBG_CFG, "resyncing CHILD_SA");
+ status = ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa),
+ child_sa->get_spi(child_sa, TRUE));
+ if (status == DESTROY_ME)
+ {
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return status;
+}
+
+/**
+ * Trigger rekeying of CHILD_SA in segment
+ */
+static void rekey_segment(private_ha_cache_t *this, u_int segment)
+{
+ ike_sa_t *ike_sa;
+ enumerator_t *enumerator;
+ linked_list_t *list;
+ ike_sa_id_t *id;
+
+ list = linked_list_create();
+
+ enumerator = charon->ike_sa_manager->create_enumerator(
+ charon->ike_sa_manager);
+ while (enumerator->enumerate(enumerator, &ike_sa))
+ {
+ if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
+ this->kernel->get_segment(this->kernel,
+ ike_sa->get_other_host(ike_sa)) == segment)
+ {
+ id = ike_sa->get_id(ike_sa);
+ list->insert_last(list, id->clone(id));
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ while (list->remove_last(list, (void**)&id) == SUCCESS)
+ {
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
+ if (ike_sa)
+ {
+ if (rekey_children(ike_sa) != DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin(
+ charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
+ }
+ }
+ id->destroy(id);
+ }
+ list->destroy(list);
+}
+
+METHOD(ha_cache_t, resync, void,
+ private_ha_cache_t *this, u_int segment)
+{
+ enumerator_t *enumerator, *updates;
+ ike_sa_t *ike_sa;
+ entry_t *entry;
+ ha_message_t *message;
+
+ DBG1(DBG_CFG, "resyncing HA segment %d", segment);
+
+ this->mutex->lock(this->mutex);
+ enumerator = this->cache->create_enumerator(this->cache);
+ while (enumerator->enumerate(enumerator, &ike_sa, &entry))
+ {
+ if (entry->segment == segment)
+ {
+ this->socket->push(this->socket, entry->add);
+ updates = entry->updates->create_enumerator(entry->updates);
+ while (updates->enumerate(updates, &message))
+ {
+ this->socket->push(this->socket, message);
+ }
+ updates->destroy(updates);
+ if (entry->midi)
+ {
+ this->socket->push(this->socket, entry->midi);
+ }
+ if (entry->midr)
+ {
+ this->socket->push(this->socket, entry->midr);
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->mutex->unlock(this->mutex);
+
+ rekey_segment(this, segment);
+}
+
+/**
+ * Request a resync of all segments
+ */
+static job_requeue_t request_resync(private_ha_cache_t *this)
+{
+ ha_message_t *message;
+ int i;
+
+ DBG1(DBG_CFG, "requesting HA resynchronization");
+
+ message = ha_message_create(HA_RESYNC);
+ for (i = 1; i <= this->count; i++)
+ {
+ message->add_attribute(message, HA_SEGMENT, i);
+ }
+ this->socket->push(this->socket, message);
+ message->destroy(message);
+ return JOB_REQUEUE_NONE;
+}
+
+METHOD(ha_cache_t, destroy, void,
+ private_ha_cache_t *this)
+{
+ this->cache->destroy(this->cache);
+ this->mutex->destroy(this->mutex);
+ free(this);
+}
+
+/**
+ * See header
+ */
+ha_cache_t *ha_cache_create(ha_kernel_t *kernel, ha_socket_t *socket,
+ bool sync, u_int count)
+{
+ private_ha_cache_t *this;
+
+ INIT(this,
+ .public = {
+ .cache = _cache,
+ .delete = _delete_,
+ .resync = _resync,
+ .destroy = _destroy,
+ },
+ .count = count,
+ .kernel = kernel,
+ .socket = socket,
+ .cache = hashtable_create(hash, equals, 8),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
+
+ if (sync)
+ {
+ /* request a resync as soon as we are up */
+ charon->scheduler->schedule_job(charon->scheduler, (job_t*)
+ callback_job_create((callback_job_cb_t)request_resync,
+ this, NULL, NULL), 1);
+ }
+ return &this->public;
+}
diff --git a/src/libcharon/plugins/ha/ha_cache.h b/src/libcharon/plugins/ha/ha_cache.h
new file mode 100644
index 000000000..39f1947a8
--- /dev/null
+++ b/src/libcharon/plugins/ha/ha_cache.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 Martin Willi
+ * Copyright (C) 2010 revosec AG
+ *
+ * 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.
+ */
+
+/**
+ * @defgroup ha_cache ha_cache
+ * @{ @ingroup ha
+ */
+
+#ifndef HA_CACHE_H_
+#define HA_CACHE_H_
+
+typedef struct ha_cache_t ha_cache_t;
+
+#include "ha_message.h"
+#include "ha_kernel.h"
+#include "ha_socket.h"
+
+#include <utils/enumerator.h>
+
+#include <sa/ike_sa.h>
+
+/**
+ * HA message caching facility, allows reintegration of new nodes.
+ */
+struct ha_cache_t {
+
+ /**
+ * Cache an IKE specific message.
+ *
+ * @param ike_sa associated IKE_SA
+ * @param message message to cache
+ */
+ void (*cache)(ha_cache_t *this, ike_sa_t *ike_sa, ha_message_t *message);
+
+ /**
+ * Delete a cache entry for an IKE_SA.
+ *
+ * @param ike_sa cache entry to delete
+ */
+ void (*delete)(ha_cache_t *this, ike_sa_t *ike_sa);
+
+ /**
+ * Resync a segment to the node using the cached messages.
+ *
+ * @param segment segment to resync
+ */
+ void (*resync)(ha_cache_t *this, u_int segment);
+
+ /**
+ * Destroy a ha_cache_t.
+ */
+ void (*destroy)(ha_cache_t *this);
+};
+
+/**
+ * Create a ha_cache instance.
+ *
+ * @param kernel kernel helper
+ * @param socket socket to send resync messages
+ * @param resync request a resync during startup?
+ * @param count total number of segments
+ */
+ha_cache_t *ha_cache_create(ha_kernel_t *kernel, ha_socket_t *socket,
+ bool resync, u_int count);
+
+#endif /** HA_CACHE_H_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_child.c b/src/libcharon/plugins/ha/ha_child.c
index 2eb8e27f6..1a9425423 100644
--- a/src/libcharon/plugins/ha/ha_child.c
+++ b/src/libcharon/plugins/ha/ha_child.c
@@ -36,22 +36,30 @@ struct private_ha_child_t {
* tunnel securing sync messages
*/
ha_tunnel_t *tunnel;
+
+ /**
+ * Segment handling
+ */
+ ha_segments_t *segments;
+
+ /**
+ * Kernel helper
+ */
+ ha_kernel_t *kernel;
};
-/**
- * Implementation of listener_t.child_keys
- */
-static bool child_keys(private_ha_child_t *this, ike_sa_t *ike_sa,
- child_sa_t *child_sa, diffie_hellman_t *dh,
- chunk_t nonce_i, chunk_t nonce_r)
+METHOD(listener_t, child_keys, bool,
+ private_ha_child_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+ bool initiator, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r)
{
ha_message_t *m;
chunk_t secret;
proposal_t *proposal;
u_int16_t alg, len;
- linked_list_t *list;
+ linked_list_t *local_ts, *remote_ts;
enumerator_t *enumerator;
traffic_selector_t *ts;
+ u_int seg_i, seg_o;
if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
{ /* do not sync SA between nodes */
@@ -61,6 +69,7 @@ static bool child_keys(private_ha_child_t *this, ike_sa_t *ike_sa,
m = ha_message_create(HA_CHILD_ADD);
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
+ m->add_attribute(m, HA_INITIATOR, (u_int8_t)initiator);
m->add_attribute(m, HA_INBOUND_SPI, child_sa->get_spi(child_sa, TRUE));
m->add_attribute(m, HA_OUTBOUND_SPI, child_sa->get_spi(child_sa, FALSE));
m->add_attribute(m, HA_INBOUND_CPI, child_sa->get_cpi(child_sa, TRUE));
@@ -90,31 +99,40 @@ static bool child_keys(private_ha_child_t *this, ike_sa_t *ike_sa,
chunk_clear(&secret);
}
- list = child_sa->get_traffic_selectors(child_sa, TRUE);
- enumerator = list->create_enumerator(list);
+ local_ts = child_sa->get_traffic_selectors(child_sa, TRUE);
+ enumerator = local_ts->create_enumerator(local_ts);
while (enumerator->enumerate(enumerator, &ts))
{
m->add_attribute(m, HA_LOCAL_TS, ts);
}
enumerator->destroy(enumerator);
- list = child_sa->get_traffic_selectors(child_sa, FALSE);
- enumerator = list->create_enumerator(list);
+ remote_ts = child_sa->get_traffic_selectors(child_sa, FALSE);
+ enumerator = remote_ts->create_enumerator(remote_ts);
while (enumerator->enumerate(enumerator, &ts))
{
m->add_attribute(m, HA_REMOTE_TS, ts);
}
enumerator->destroy(enumerator);
+ seg_i = this->kernel->get_segment_spi(this->kernel,
+ ike_sa->get_my_host(ike_sa), child_sa->get_spi(child_sa, TRUE));
+ seg_o = this->kernel->get_segment_spi(this->kernel,
+ ike_sa->get_other_host(ike_sa), child_sa->get_spi(child_sa, FALSE));
+ DBG1(DBG_CFG, "handling HA CHILD_SA %s{%d} %#R=== %#R "
+ "(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
+ child_sa->get_reqid(child_sa), local_ts, remote_ts,
+ seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
+ seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
+
this->socket->push(this->socket, m);
+ m->destroy(m);
return TRUE;
}
-/**
- * Implementation of listener_t.child_state_change
- */
-static bool child_state_change(private_ha_child_t *this, ike_sa_t *ike_sa,
- child_sa_t *child_sa, child_sa_state_t state)
+METHOD(listener_t, child_state_change, bool,
+ private_ha_child_t *this, ike_sa_t *ike_sa,
+ child_sa_t *child_sa, child_sa_state_t state)
{
if (!ike_sa ||
ike_sa->get_state(ike_sa) == IKE_PASSIVE ||
@@ -138,14 +156,13 @@ static bool child_state_change(private_ha_child_t *this, ike_sa_t *ike_sa,
m->add_attribute(m, HA_INBOUND_SPI,
child_sa->get_spi(child_sa, TRUE));
this->socket->push(this->socket, m);
+ m->destroy(m);
}
return TRUE;
}
-/**
- * Implementation of ha_child_t.destroy.
- */
-static void destroy(private_ha_child_t *this)
+METHOD(ha_child_t, destroy, void,
+ private_ha_child_t *this)
{
free(this);
}
@@ -153,17 +170,24 @@ static void destroy(private_ha_child_t *this)
/**
* See header
*/
-ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel)
+ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
+ ha_segments_t *segments, ha_kernel_t *kernel)
{
- private_ha_child_t *this = malloc_thing(private_ha_child_t);
-
- memset(&this->public.listener, 0, sizeof(listener_t));
- this->public.listener.child_keys = (bool(*)(listener_t*, ike_sa_t *ike_sa, child_sa_t *child_sa, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r))child_keys;
- this->public.listener.child_state_change = (bool(*)(listener_t*,ike_sa_t *ike_sa, child_sa_t *child_sa, child_sa_state_t state))child_state_change;
- this->public.destroy = (void(*)(ha_child_t*))destroy;
-
- this->socket = socket;
- this->tunnel = tunnel;
+ private_ha_child_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .child_keys = _child_keys,
+ .child_state_change = _child_state_change,
+ },
+ .destroy = _destroy,
+ },
+ .socket = socket,
+ .tunnel = tunnel,
+ .segments = segments,
+ .kernel = kernel,
+ );
return &this->public;
}
diff --git a/src/libcharon/plugins/ha/ha_child.h b/src/libcharon/plugins/ha/ha_child.h
index ea83495f7..56cd769ba 100644
--- a/src/libcharon/plugins/ha/ha_child.h
+++ b/src/libcharon/plugins/ha/ha_child.h
@@ -21,14 +21,15 @@
#ifndef HA_CHILD_H_
#define HA_CHILD_H_
+typedef struct ha_child_t ha_child_t;
+
#include "ha_socket.h"
#include "ha_tunnel.h"
#include "ha_segments.h"
+#include "ha_kernel.h"
#include <daemon.h>
-typedef struct ha_child_t ha_child_t;
-
/**
* Listener to synchronize CHILD_SAs.
*/
@@ -50,8 +51,11 @@ struct ha_child_t {
*
* @param socket socket to use for sending synchronization messages
* @param tunnel tunnel securing sync messages, if any
+ * @param segments segment handling
+ * @param kernel kernel helper
* @return CHILD listener
*/
-ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel);
+ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
+ ha_segments_t *segments, ha_kernel_t *kernel);
-#endif /* HA_CHILD_ @}*/
+#endif /** HA_CHILD_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_ctl.c b/src/libcharon/plugins/ha/ha_ctl.c
index 441d26d9e..e188a8484 100644
--- a/src/libcharon/plugins/ha/ha_ctl.c
+++ b/src/libcharon/plugins/ha/ha_ctl.c
@@ -45,6 +45,11 @@ struct private_ha_ctl_t {
ha_segments_t *segments;
/**
+ * Resynchronization message cache
+ */
+ ha_cache_t *cache;
+
+ /**
* FIFO reader thread
*/
callback_job_t *job;
@@ -84,7 +89,7 @@ static job_requeue_t dispatch_fifo(private_ha_ctl_t *this)
this->segments->deactivate(this->segments, segment, TRUE);
break;
case '*':
- this->segments->resync(this->segments, segment);
+ this->cache->resync(this->cache, segment);
break;
default:
break;
@@ -96,10 +101,8 @@ static job_requeue_t dispatch_fifo(private_ha_ctl_t *this)
return JOB_REQUEUE_DIRECT;
}
-/**
- * Implementation of ha_ctl_t.destroy.
- */
-static void destroy(private_ha_ctl_t *this)
+METHOD(ha_ctl_t, destroy, void,
+ private_ha_ctl_t *this)
{
this->job->cancel(this->job);
free(this);
@@ -108,11 +111,17 @@ static void destroy(private_ha_ctl_t *this)
/**
* See header
*/
-ha_ctl_t *ha_ctl_create(ha_segments_t *segments)
+ha_ctl_t *ha_ctl_create(ha_segments_t *segments, ha_cache_t *cache)
{
- private_ha_ctl_t *this = malloc_thing(private_ha_ctl_t);
+ private_ha_ctl_t *this;
- this->public.destroy = (void(*)(ha_ctl_t*))destroy;
+ INIT(this,
+ .public = {
+ .destroy = _destroy,
+ },
+ .segments = segments,
+ .cache = cache,
+ );
if (access(HA_FIFO, R_OK|W_OK) != 0)
{
@@ -123,7 +132,6 @@ ha_ctl_t *ha_ctl_create(ha_segments_t *segments)
}
}
- this->segments = segments;
this->job = callback_job_create((callback_job_cb_t)dispatch_fifo,
this, NULL, NULL);
charon->processor->queue_job(charon->processor, (job_t*)this->job);
diff --git a/src/libcharon/plugins/ha/ha_ctl.h b/src/libcharon/plugins/ha/ha_ctl.h
index f33a809be..1e717832a 100644
--- a/src/libcharon/plugins/ha/ha_ctl.h
+++ b/src/libcharon/plugins/ha/ha_ctl.h
@@ -22,6 +22,7 @@
#define HA_CTL_H_
#include "ha_segments.h"
+#include "ha_cache.h"
typedef struct ha_ctl_t ha_ctl_t;
@@ -40,8 +41,9 @@ struct ha_ctl_t {
* Create a ha_ctl instance.
*
* @param segments segments to control
+ * @param cache message cache for resynchronization
* @return HA control interface
*/
-ha_ctl_t *ha_ctl_create(ha_segments_t *segments);
+ha_ctl_t *ha_ctl_create(ha_segments_t *segments, ha_cache_t *cache);
-#endif /* HA_CTL_ @}*/
+#endif /** HA_CTL_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c
index 7df2f1fa8..3bc426ea0 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -41,6 +41,21 @@ struct private_ha_dispatcher_t {
ha_segments_t *segments;
/**
+ * Cache for resync
+ */
+ ha_cache_t *cache;
+
+ /**
+ * Kernel helper
+ */
+ ha_kernel_t *kernel;
+
+ /**
+ * HA enabled pool
+ */
+ ha_attribute_t *attr;
+
+ /**
* Dispatcher job
*/
callback_job_t *job;
@@ -153,6 +168,8 @@ 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);
+ this->cache->cache(this->cache, ike_sa, message);
+ message = NULL;
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
else
@@ -167,6 +184,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, old_sa);
}
+ DESTROY_IF(message);
}
/**
@@ -201,6 +219,8 @@ static void process_ike_update(private_ha_dispatcher_t *this,
enumerator_t *enumerator;
ike_sa_t *ike_sa = NULL;
peer_cfg_t *peer_cfg = NULL;
+ auth_cfg_t *auth;
+ bool received_vip = FALSE;
enumerator = message->create_attribute_enumerator(message);
while (enumerator->enumerate(enumerator, &attribute, &value))
@@ -222,6 +242,11 @@ static void process_ike_update(private_ha_dispatcher_t *this,
case HA_REMOTE_ID:
ike_sa->set_other_id(ike_sa, value.id->clone(value.id));
break;
+ case HA_REMOTE_EAP_ID:
+ auth = auth_cfg_create();
+ auth->add(auth, AUTH_RULE_EAP_IDENTITY, value.id->clone(value.id));
+ ike_sa->add_auth_cfg(ike_sa, FALSE, auth);
+ break;
case HA_LOCAL_ADDR:
ike_sa->set_my_host(ike_sa, value.host->clone(value.host));
break;
@@ -233,6 +258,7 @@ static void process_ike_update(private_ha_dispatcher_t *this,
break;
case HA_REMOTE_VIP:
ike_sa->set_virtual_ip(ike_sa, FALSE, value.host);
+ received_vip = TRUE;
break;
case HA_ADDITIONAL_ADDR:
ike_sa->add_additional_address(ike_sa,
@@ -265,12 +291,6 @@ 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);
break;
- case HA_INITIATE_MID:
- ike_sa->set_message_id(ike_sa, TRUE, value.u32);
- break;
- case HA_RESPOND_MID:
- ike_sa->set_message_id(ike_sa, FALSE, value.u32);
- break;
default:
break;
}
@@ -282,10 +302,81 @@ static void process_ike_update(private_ha_dispatcher_t *this,
if (ike_sa->get_state(ike_sa) == IKE_CONNECTING &&
ike_sa->get_peer_cfg(ike_sa))
{
+ DBG1(DBG_CFG, "installed HA passive IKE_SA '%s' %H[%Y]...%H[%Y]",
+ ike_sa->get_name(ike_sa),
+ ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
+ ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
ike_sa->set_state(ike_sa, IKE_PASSIVE);
}
+ if (received_vip)
+ {
+ host_t *vip;
+ char *pool;
+
+ peer_cfg = ike_sa->get_peer_cfg(ike_sa);
+ vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
+ if (peer_cfg && vip)
+ {
+ pool = peer_cfg->get_pool(peer_cfg);
+ if (pool)
+ {
+ this->attr->reserve(this->attr, pool, vip);
+ }
+ }
+ }
+ this->cache->cache(this->cache, ike_sa, message);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
+ else
+ {
+ DBG1(DBG_CFG, "passive HA IKE_SA to update not found");
+ message->destroy(message);
+ }
+}
+
+/**
+ * Process messages of type IKE_MID_INITIATOR/RESPONDER
+ */
+static void process_ike_mid(private_ha_dispatcher_t *this,
+ ha_message_t *message, bool initiator)
+{
+ ha_message_attribute_t attribute;
+ ha_message_value_t value;
+ enumerator_t *enumerator;
+ ike_sa_t *ike_sa = NULL;
+ u_int32_t mid = 0;
+
+ 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_MID:
+ mid = value.u32;
+ break;
+ default:
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (ike_sa)
+ {
+ if (mid)
+ {
+ ike_sa->set_message_id(ike_sa, initiator, mid);
+ }
+ this->cache->cache(this->cache, ike_sa, message);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ message->destroy(message);
+ }
}
/**
@@ -297,7 +388,7 @@ static void process_ike_delete(private_ha_dispatcher_t *this,
ha_message_attribute_t attribute;
ha_message_value_t value;
enumerator_t *enumerator;
- ike_sa_t *ike_sa;
+ ike_sa_t *ike_sa = NULL;
enumerator = message->create_attribute_enumerator(message);
while (enumerator->enumerate(enumerator, &attribute, &value))
@@ -307,17 +398,22 @@ static void process_ike_delete(private_ha_dispatcher_t *this,
case HA_IKE_ID:
ike_sa = charon->ike_sa_manager->checkout(
charon->ike_sa_manager, value.ike_sa_id);
- if (ike_sa)
- {
- charon->ike_sa_manager->checkin_and_destroy(
- charon->ike_sa_manager, ike_sa);
- }
break;
default:
break;
}
}
enumerator->destroy(enumerator);
+ if (ike_sa)
+ {
+ this->cache->cache(this->cache, ike_sa, message);
+ charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ message->destroy(message);
+ }
}
/**
@@ -366,6 +462,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
u_int16_t inbound_cpi = 0, outbound_cpi = 0;
u_int8_t mode = MODE_TUNNEL, ipcomp = 0;
u_int16_t encr = ENCR_UNDEFINED, integ = AUTH_UNDEFINED, len = 0;
+ u_int seg_i, seg_o;
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;
@@ -381,11 +478,13 @@ static void process_child_add(private_ha_dispatcher_t *this,
case HA_IKE_ID:
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
value.ike_sa_id);
- initiator = value.ike_sa_id->is_initiator(value.ike_sa_id);
break;
case HA_CONFIG_NAME:
config_name = value.str;
break;
+ case HA_INITIATOR:
+ initiator = value.u8;
+ break;
case HA_INBOUND_SPI:
inbound_spi = value.u32;
break;
@@ -431,6 +530,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
if (!ike_sa)
{
DBG1(DBG_CHD, "IKE_SA for HA CHILD_SA not found");
+ message->destroy(message);
return;
}
config = find_child_cfg(ike_sa, config_name);
@@ -438,6 +538,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
{
DBG1(DBG_CHD, "HA is missing nodes child configuration");
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ message->destroy(message);
return;
}
@@ -524,15 +625,27 @@ static void process_child_add(private_ha_dispatcher_t *this,
local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ message->destroy(message);
return;
}
+ seg_i = this->kernel->get_segment_spi(this->kernel,
+ ike_sa->get_my_host(ike_sa), inbound_spi);
+ seg_o = this->kernel->get_segment_spi(this->kernel,
+ ike_sa->get_other_host(ike_sa), outbound_spi);
+
+ DBG1(DBG_CFG, "installed HA CHILD_SA %s{%d} %#R=== %#R "
+ "(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
+ child_sa->get_reqid(child_sa), local_ts, remote_ts,
+ seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
+ seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
child_sa->add_policies(child_sa, local_ts, remote_ts);
local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
child_sa->set_state(child_sa, CHILD_INSTALLED);
ike_sa->add_child_sa(ike_sa, child_sa);
+ message->destroy(message);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
@@ -546,6 +659,8 @@ static void process_child_delete(private_ha_dispatcher_t *this,
ha_message_value_t value;
enumerator_t *enumerator;
ike_sa_t *ike_sa = NULL;
+ child_sa_t *child_sa;
+ u_int32_t spi = 0;
enumerator = message->create_attribute_enumerator(message);
while (enumerator->enumerate(enumerator, &attribute, &value))
@@ -557,20 +672,24 @@ static void process_child_delete(private_ha_dispatcher_t *this,
value.ike_sa_id);
break;
case HA_INBOUND_SPI:
- if (ike_sa)
- {
- ike_sa->destroy_child_sa(ike_sa, PROTO_ESP, value.u32);
- }
+ spi = value.u32;
break;
default:
break;
}
}
+ enumerator->destroy(enumerator);
+
if (ike_sa)
{
+ child_sa = ike_sa->get_child_sa(ike_sa, PROTO_ESP, spi, TRUE);
+ if (child_sa)
+ {
+ ike_sa->destroy_child_sa(ike_sa, PROTO_ESP, spi);
+ }
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
- enumerator->destroy(enumerator);
+ message->destroy(message);
}
/**
@@ -605,6 +724,7 @@ static void process_segment(private_ha_dispatcher_t *this,
}
}
enumerator->destroy(enumerator);
+ message->destroy(message);
}
/**
@@ -633,6 +753,7 @@ static void process_status(private_ha_dispatcher_t *this,
enumerator->destroy(enumerator);
this->segments->handle_status(this->segments, mask);
+ message->destroy(message);
}
/**
@@ -651,13 +772,14 @@ static void process_resync(private_ha_dispatcher_t *this,
switch (attribute)
{
case HA_SEGMENT:
- this->segments->resync(this->segments, value.u16);
+ this->cache->resync(this->cache, value.u16);
break;
default:
break;
}
}
enumerator->destroy(enumerator);
+ message->destroy(message);
}
/**
@@ -666,9 +788,16 @@ static void process_resync(private_ha_dispatcher_t *this,
static job_requeue_t dispatch(private_ha_dispatcher_t *this)
{
ha_message_t *message;
+ ha_message_type_t type;
message = this->socket->pull(this->socket);
- switch (message->get_type(message))
+ type = message->get_type(message);
+ if (type != HA_STATUS)
+ {
+ DBG2(DBG_CFG, "received HA %N message", ha_message_type_names,
+ message->get_type(message));
+ }
+ switch (type)
{
case HA_IKE_ADD:
process_ike_add(this, message);
@@ -676,6 +805,12 @@ static job_requeue_t dispatch(private_ha_dispatcher_t *this)
case HA_IKE_UPDATE:
process_ike_update(this, message);
break;
+ case HA_IKE_MID_INITIATOR:
+ process_ike_mid(this, message, TRUE);
+ break;
+ case HA_IKE_MID_RESPONDER:
+ process_ike_mid(this, message, FALSE);
+ break;
case HA_IKE_DELETE:
process_ike_delete(this, message);
break;
@@ -698,19 +833,15 @@ static job_requeue_t dispatch(private_ha_dispatcher_t *this)
process_resync(this, message);
break;
default:
- DBG1(DBG_CFG, "received unknown HA message type %d",
- message->get_type(message));
+ DBG1(DBG_CFG, "received unknown HA message type %d", type);
+ message->destroy(message);
break;
}
- message->destroy(message);
-
return JOB_REQUEUE_DIRECT;
}
-/**
- * Implementation of ha_dispatcher_t.destroy.
- */
-static void destroy(private_ha_dispatcher_t *this)
+METHOD(ha_dispatcher_t, destroy, void,
+ private_ha_dispatcher_t *this)
{
this->job->cancel(this->job);
free(this);
@@ -720,14 +851,22 @@ static void destroy(private_ha_dispatcher_t *this)
* See header
*/
ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
- ha_segments_t *segments)
+ ha_segments_t *segments, ha_cache_t *cache,
+ ha_kernel_t *kernel, ha_attribute_t *attr)
{
- private_ha_dispatcher_t *this = malloc_thing(private_ha_dispatcher_t);
-
- this->public.destroy = (void(*)(ha_dispatcher_t*))destroy;
-
- this->socket = socket;
- this->segments = segments;
+ private_ha_dispatcher_t *this;
+
+
+ INIT(this,
+ .public = {
+ .destroy = _destroy,
+ },
+ .socket = socket,
+ .segments = segments,
+ .cache = cache,
+ .kernel = kernel,
+ .attr = attr,
+ );
this->job = callback_job_create((callback_job_cb_t)dispatch,
this, NULL, NULL);
charon->processor->queue_job(charon->processor, (job_t*)this->job);
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.h b/src/libcharon/plugins/ha/ha_dispatcher.h
index d2baace3f..105a40473 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.h
+++ b/src/libcharon/plugins/ha/ha_dispatcher.h
@@ -23,6 +23,9 @@
#include "ha_socket.h"
#include "ha_segments.h"
+#include "ha_cache.h"
+#include "ha_kernel.h"
+#include "ha_attribute.h"
typedef struct ha_dispatcher_t ha_dispatcher_t;
@@ -42,9 +45,13 @@ struct ha_dispatcher_t {
*
* @param socket socket to pull messages from
* @param segments segments to control based on received messages
+ * @param cache message cache to use for resynchronization
+ * @param kernel kernel helper
+ * @param attr HA enabled pool
* @return dispatcher object
*/
ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
- ha_segments_t *segments);
+ ha_segments_t *segments, ha_cache_t *cache,
+ ha_kernel_t *kernel, ha_attribute_t *attr);
-#endif /* HA_DISPATCHER_ @}*/
+#endif /** HA_DISPATCHER_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c
index 1f025d0e5..1efba4e8f 100644
--- a/src/libcharon/plugins/ha/ha_ike.c
+++ b/src/libcharon/plugins/ha/ha_ike.c
@@ -36,6 +36,11 @@ struct private_ha_ike_t {
* tunnel securing sync messages
*/
ha_tunnel_t *tunnel;
+
+ /**
+ * message cache
+ */
+ ha_cache_t *cache;
};
/**
@@ -62,12 +67,9 @@ static ike_extension_t copy_extension(ike_sa_t *ike_sa, ike_extension_t ext)
return 0;
}
-/**
- * Implementation of listener_t.ike_keys
- */
-static bool ike_keys(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)
+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)
{
ha_message_t *m;
chunk_t secret;
@@ -120,14 +122,13 @@ static bool ike_keys(private_ha_ike_t *this, ike_sa_t *ike_sa,
chunk_clear(&secret);
this->socket->push(this->socket, m);
+ this->cache->cache(this->cache, ike_sa, m);
return TRUE;
}
-/**
- * Implementation of listener_t.ike_updown
- */
-static bool ike_updown(private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
+METHOD(listener_t, ike_updown, bool,
+ private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
{
ha_message_t *m;
@@ -147,6 +148,7 @@ static bool ike_updown(private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
u_int32_t extension, condition;
host_t *addr;
ike_sa_id_t *id;
+ identification_t *eap_id;
peer_cfg = ike_sa->get_peer_cfg(ike_sa);
@@ -168,6 +170,11 @@ static bool ike_updown(private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
m->add_attribute(m, HA_IKE_ID, id);
m->add_attribute(m, HA_LOCAL_ID, ike_sa->get_my_id(ike_sa));
m->add_attribute(m, HA_REMOTE_ID, ike_sa->get_other_id(ike_sa));
+ eap_id = ike_sa->get_other_eap_id(ike_sa);
+ if (!eap_id->equals(eap_id, ike_sa->get_other_id(ike_sa)))
+ {
+ m->add_attribute(m, HA_REMOTE_EAP_ID, eap_id);
+ }
m->add_attribute(m, HA_LOCAL_ADDR, ike_sa->get_my_host(ike_sa));
m->add_attribute(m, HA_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
m->add_attribute(m, HA_CONDITIONS, condition);
@@ -186,24 +193,31 @@ static bool ike_updown(private_ha_ike_t *this, ike_sa_t *ike_sa, bool up)
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
}
this->socket->push(this->socket, m);
+ this->cache->cache(this->cache, ike_sa, m);
return TRUE;
}
-/**
- * Implementation of listener_t.ike_rekey
- */
-static bool ike_rekey(private_ha_ike_t *this, ike_sa_t *old, ike_sa_t *new)
+METHOD(listener_t, ike_rekey, bool,
+ private_ha_ike_t *this, ike_sa_t *old, ike_sa_t *new)
{
ike_updown(this, old, FALSE);
ike_updown(this, new, TRUE);
return TRUE;
}
-/**
- * Implementation of listener_t.message
- */
-static bool message_hook(private_ha_ike_t *this, ike_sa_t *ike_sa,
- message_t *message, bool incoming)
+METHOD(listener_t, ike_state_change, bool,
+ private_ha_ike_t *this, ike_sa_t *ike_sa, ike_sa_state_t new)
+{
+ /* delete any remaining cache entry if IKE_SA gets destroyed */
+ if (new == IKE_DESTROYING)
+ {
+ this->cache->delete(this->cache, ike_sa);
+ }
+ return TRUE;
+}
+
+METHOD(listener_t, message_hook, bool,
+ private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message, bool incoming)
{
if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
{ /* do not sync SA between nodes */
@@ -214,20 +228,19 @@ static bool message_hook(private_ha_ike_t *this, ike_sa_t *ike_sa,
message->get_request(message))
{ /* we sync on requests, but skip it on IKE_SA_INIT */
ha_message_t *m;
- u_int32_t mid;
- m = ha_message_create(HA_IKE_UPDATE);
- m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
- mid = message->get_message_id(message) + 1;
if (incoming)
{
- m->add_attribute(m, HA_RESPOND_MID, mid);
+ m = ha_message_create(HA_IKE_MID_RESPONDER);
}
else
{
- m->add_attribute(m, HA_INITIATE_MID, mid);
+ 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);
}
if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
message->get_exchange_type(message) == IKE_AUTH &&
@@ -245,15 +258,14 @@ static bool message_hook(private_ha_ike_t *this, ike_sa_t *ike_sa,
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);
}
}
return TRUE;
}
-/**
- * Implementation of ha_ike_t.destroy.
- */
-static void destroy(private_ha_ike_t *this)
+METHOD(ha_ike_t, destroy, void,
+ private_ha_ike_t *this)
{
free(this);
}
@@ -261,19 +273,26 @@ static void destroy(private_ha_ike_t *this)
/**
* See header
*/
-ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel)
+ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
+ ha_cache_t *cache)
{
- private_ha_ike_t *this = malloc_thing(private_ha_ike_t);
-
- 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_updown = (bool(*)(listener_t*,ike_sa_t *ike_sa, bool up))ike_updown;
- this->public.listener.ike_rekey = (bool(*)(listener_t*,ike_sa_t *old, ike_sa_t *new))ike_rekey;
- this->public.listener.message = (bool(*)(listener_t*, ike_sa_t *, message_t *,bool))message_hook;
- this->public.destroy = (void(*)(ha_ike_t*))destroy;
-
- this->socket = socket;
- this->tunnel = tunnel;
+ private_ha_ike_t *this;
+
+ INIT(this,
+ .public = {
+ .listener = {
+ .ike_keys = _ike_keys,
+ .ike_updown = _ike_updown,
+ .ike_rekey = _ike_rekey,
+ .ike_state_change = _ike_state_change,
+ .message = _message_hook,
+ },
+ .destroy = _destroy,
+ },
+ .socket = socket,
+ .tunnel = tunnel,
+ .cache = cache,
+ );
return &this->public;
}
diff --git a/src/libcharon/plugins/ha/ha_ike.h b/src/libcharon/plugins/ha/ha_ike.h
index 9de210e67..b22cd6250 100644
--- a/src/libcharon/plugins/ha/ha_ike.h
+++ b/src/libcharon/plugins/ha/ha_ike.h
@@ -21,14 +21,15 @@
#ifndef HA_IKE_H_
#define HA_IKE_H_
+typedef struct ha_ike_t ha_ike_t;
+
#include "ha_socket.h"
#include "ha_tunnel.h"
#include "ha_segments.h"
+#include "ha_cache.h"
#include <daemon.h>
-typedef struct ha_ike_t ha_ike_t;
-
/**
* Listener to synchronize IKE_SAs.
*/
@@ -50,8 +51,10 @@ struct ha_ike_t {
*
* @param socket socket to use for sending synchronization messages
* @param tunnel tunnel securing sync messages, if any
+ * @param cache message cache
* @return IKE listener
*/
-ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel);
+ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel,
+ ha_cache_t *cache);
-#endif /* HA_IKE_ @}*/
+#endif /** HA_IKE_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_kernel.c b/src/libcharon/plugins/ha/ha_kernel.c
index 0ad9c22c3..10a63453a 100644
--- a/src/libcharon/plugins/ha/ha_kernel.c
+++ b/src/libcharon/plugins/ha/ha_kernel.c
@@ -52,24 +52,57 @@ struct private_ha_kernel_t {
};
/**
- * Implementation of ha_kernel_t.in_segment
+ * Segmentate a calculated hash
*/
-static bool in_segment(private_ha_kernel_t *this, host_t *host, u_int segment)
+static u_int hash2segment(private_ha_kernel_t *this, u_int64_t hash)
+{
+ return ((hash * this->count) >> 32) + 1;
+}
+
+/**
+ * Get a host as an integer for hashing
+ */
+static u_int32_t host2int(host_t *host)
{
if (host->get_family(host) == AF_INET)
{
- unsigned long hash;
- u_int32_t addr;
+ return *(u_int32_t*)host->get_address(host).ptr;
+ }
+ return 0;
+}
- addr = *(u_int32_t*)host->get_address(host).ptr;
- hash = jhash_1word(ntohl(addr), this->initval);
+METHOD(ha_kernel_t, get_segment, u_int,
+ private_ha_kernel_t *this, host_t *host)
+{
+ unsigned long hash;
+ u_int32_t addr;
- if ((((u_int64_t)hash * this->count) >> 32) + 1 == segment)
- {
- return TRUE;
- }
- }
- return FALSE;
+ addr = host2int(host);
+ hash = jhash_1word(ntohl(addr), this->initval);
+
+ return hash2segment(this, hash);
+}
+
+METHOD(ha_kernel_t, get_segment_spi, u_int,
+ private_ha_kernel_t *this, host_t *host, u_int32_t spi)
+{
+ unsigned long hash;
+ u_int32_t addr;
+
+ addr = host2int(host);
+ hash = jhash_2words(ntohl(addr), ntohl(spi), this->initval);
+
+ return hash2segment(this, hash);
+}
+
+METHOD(ha_kernel_t, get_segment_int, u_int,
+ private_ha_kernel_t *this, int n)
+{
+ unsigned long hash;
+
+ hash = jhash_1word(ntohl(n), this->initval);
+
+ return hash2segment(this, hash);
}
/**
@@ -142,10 +175,8 @@ static segment_mask_t get_active(private_ha_kernel_t *this, char *file)
return mask;
}
-/**
- * Implementation of ha_kernel_t.activate
- */
-static void activate(private_ha_kernel_t *this, u_int segment)
+METHOD(ha_kernel_t, activate, void,
+ private_ha_kernel_t *this, u_int segment)
{
enumerator_t *enumerator;
char *file;
@@ -158,10 +189,8 @@ static void activate(private_ha_kernel_t *this, u_int segment)
enumerator->destroy(enumerator);
}
-/**
- * Implementation of ha_kernel_t.deactivate
- */
-static void deactivate(private_ha_kernel_t *this, u_int segment)
+METHOD(ha_kernel_t, deactivate, void,
+ private_ha_kernel_t *this, u_int segment)
{
enumerator_t *enumerator;
char *file;
@@ -199,10 +228,8 @@ static void disable_all(private_ha_kernel_t *this)
enumerator->destroy(enumerator);
}
-/**
- * Implementation of ha_kernel_t.destroy.
- */
-static void destroy(private_ha_kernel_t *this)
+METHOD(ha_kernel_t, destroy, void,
+ private_ha_kernel_t *this)
{
free(this);
}
@@ -212,15 +239,20 @@ static void destroy(private_ha_kernel_t *this)
*/
ha_kernel_t *ha_kernel_create(u_int count)
{
- private_ha_kernel_t *this = malloc_thing(private_ha_kernel_t);
-
- this->public.in_segment = (bool(*)(ha_kernel_t*, host_t *host, u_int segment))in_segment;
- this->public.activate = (void(*)(ha_kernel_t*, u_int segment))activate;
- this->public.deactivate = (void(*)(ha_kernel_t*, u_int segment))deactivate;
- this->public.destroy = (void(*)(ha_kernel_t*))destroy;
+ private_ha_kernel_t *this;
- this->initval = 0;
- this->count = count;
+ INIT(this,
+ .public = {
+ .get_segment = _get_segment,
+ .get_segment_spi = _get_segment_spi,
+ .get_segment_int = _get_segment_int,
+ .activate = _activate,
+ .deactivate = _deactivate,
+ .destroy = _destroy,
+ },
+ .initval = 0,
+ .count = count,
+ );
disable_all(this);
diff --git a/src/libcharon/plugins/ha/ha_kernel.h b/src/libcharon/plugins/ha/ha_kernel.h
index b37cc7667..7b56f1e3a 100644
--- a/src/libcharon/plugins/ha/ha_kernel.h
+++ b/src/libcharon/plugins/ha/ha_kernel.h
@@ -31,13 +31,28 @@ typedef struct ha_kernel_t ha_kernel_t;
struct ha_kernel_t {
/**
- * Check if a host is in a segment.
+ * Get the segment a host is in.
*
- * @param host host to check
- * @param segment segment
- * @return TRUE if host belongs to segment
+ * @param host host to get segment for
+ * @return segment number
*/
- bool (*in_segment)(ha_kernel_t *this, host_t *host, u_int segment);
+ u_int (*get_segment)(ha_kernel_t *this, host_t *host);
+
+ /**
+ * Get the segment a host/SPI is in, as used for CHILD_SA segmentation.
+ *
+ * @param host host to get segment for
+ * @param spi SPI to include in hash
+ * @return segment number
+ */
+ u_int (*get_segment_spi)(ha_kernel_t *this, host_t *host, u_int32_t spi);
+
+ /**
+ * Get the segment an arbitrary integer is in.
+ *
+ * @param n integer to segmentate
+ */
+ u_int (*get_segment_int)(ha_kernel_t *this, int n);
/**
* Activate a segment at kernel level for all cluster addresses.
@@ -63,8 +78,7 @@ struct ha_kernel_t {
* Create a ha_kernel instance.
*
* @param count total number of segments to use
- * @param active bitmask of initially active segments
*/
ha_kernel_t *ha_kernel_create(u_int count);
-#endif /* HA_KERNEL_ @}*/
+#endif /** HA_KERNEL_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c
index 54b10f05d..7ce9cbe09 100644
--- a/src/libcharon/plugins/ha/ha_message.c
+++ b/src/libcharon/plugins/ha/ha_message.c
@@ -46,6 +46,20 @@ struct private_ha_message_t {
chunk_t buf;
};
+ENUM(ha_message_type_names, HA_IKE_ADD, HA_RESYNC,
+ "IKE_ADD",
+ "IKE_UPDATE",
+ "IKE_MID_INITIATOR",
+ "IKE_MID_RESPONDER",
+ "IKE_DELETE",
+ "CHILD_ADD",
+ "CHILD_DELETE",
+ "SEGMENT_DROP",
+ "SEGMENT_TAKE",
+ "STATUS",
+ "RESYNC",
+);
+
typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t;
/**
@@ -93,10 +107,8 @@ struct ts_encoding_t {
char encoding[];
} __attribute__((packed));
-/**
- * Implementation of ha_message_t.get_type
- */
-static ha_message_type_t get_type(private_ha_message_t *this)
+METHOD(ha_message_t, get_type, ha_message_type_t,
+ private_ha_message_t *this)
{
return this->buf.ptr[1];
}
@@ -119,11 +131,8 @@ static void check_buf(private_ha_message_t *this, size_t len)
}
}
-/**
- * Implementation of ha_message_t.add_attribute
- */
-static void add_attribute(private_ha_message_t *this,
- ha_message_attribute_t attribute, ...)
+METHOD(ha_message_t, add_attribute, void,
+ private_ha_message_t *this, ha_message_attribute_t attribute, ...)
{
size_t len;
va_list args;
@@ -154,6 +163,7 @@ static void add_attribute(private_ha_message_t *this,
/* identification_t* */
case HA_LOCAL_ID:
case HA_REMOTE_ID:
+ case HA_REMOTE_EAP_ID:
{
identification_encoding_t *enc;
identification_t *id;
@@ -203,6 +213,7 @@ static void add_attribute(private_ha_message_t *this,
break;
}
/* u_int8_t */
+ case HA_INITIATOR:
case HA_IPSEC_MODE:
case HA_IPCOMP:
{
@@ -237,8 +248,7 @@ static void add_attribute(private_ha_message_t *this,
case HA_EXTENSIONS:
case HA_INBOUND_SPI:
case HA_OUTBOUND_SPI:
- case HA_INITIATE_MID:
- case HA_RESPOND_MID:
+ case HA_MID:
{
u_int32_t val;
@@ -310,12 +320,9 @@ typedef struct {
void *cleanup_data;
} attribute_enumerator_t;
-/**
- * Implementation of create_attribute_enumerator().enumerate
- */
-static bool attribute_enumerate(attribute_enumerator_t *this,
- ha_message_attribute_t *attr_out,
- ha_message_value_t *value)
+METHOD(enumerator_t, attribute_enumerate, bool,
+ attribute_enumerator_t *this, ha_message_attribute_t *attr_out,
+ ha_message_value_t *value)
{
ha_message_attribute_t attr;
@@ -354,6 +361,7 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
/* identification_t* */
case HA_LOCAL_ID:
case HA_REMOTE_ID:
+ case HA_REMOTE_EAP_ID:
{
identification_encoding_t *enc;
@@ -417,6 +425,7 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
return TRUE;
}
/* u_int8_t */
+ case HA_INITIATOR:
case HA_IPSEC_MODE:
case HA_IPCOMP:
{
@@ -453,8 +462,7 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
case HA_EXTENSIONS:
case HA_INBOUND_SPI:
case HA_OUTBOUND_SPI:
- case HA_INITIATE_MID:
- case HA_RESPOND_MID:
+ case HA_MID:
{
if (this->buf.len < sizeof(u_int32_t))
{
@@ -559,10 +567,8 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
}
}
-/**
- * Implementation of create_attribute_enumerator().destroy
- */
-static void enum_destroy(attribute_enumerator_t *this)
+METHOD(enumerator_t, enum_destroy, void,
+ attribute_enumerator_t *this)
{
if (this->cleanup)
{
@@ -571,35 +577,30 @@ static void enum_destroy(attribute_enumerator_t *this)
free(this);
}
-/**
- * Implementation of ha_message_t.create_attribute_enumerator
- */
-static enumerator_t* create_attribute_enumerator(private_ha_message_t *this)
+METHOD(ha_message_t, create_attribute_enumerator, enumerator_t*,
+ private_ha_message_t *this)
{
- attribute_enumerator_t *e = malloc_thing(attribute_enumerator_t);
-
- e->public.enumerate = (void*)attribute_enumerate;
- e->public.destroy = (void*)enum_destroy;
+ attribute_enumerator_t *e;
- e->buf = chunk_skip(this->buf, 2);
- e->cleanup = NULL;
- e->cleanup_data = NULL;
+ INIT(e,
+ .public = {
+ .enumerate = (void*)_attribute_enumerate,
+ .destroy = _enum_destroy,
+ },
+ .buf = chunk_skip(this->buf, 2),
+ );
return &e->public;
}
-/**
- * Implementation of ha_message_t.get_encoding
- */
-static chunk_t get_encoding(private_ha_message_t *this)
+METHOD(ha_message_t, get_encoding, chunk_t,
+ private_ha_message_t *this)
{
return this->buf;
}
-/**
- * Implementation of ha_message_t.destroy.
- */
-static void destroy(private_ha_message_t *this)
+METHOD(ha_message_t, destroy, void,
+ private_ha_message_t *this)
{
free(this->buf.ptr);
free(this);
@@ -608,14 +609,17 @@ static void destroy(private_ha_message_t *this)
static private_ha_message_t *ha_message_create_generic()
{
- private_ha_message_t *this = malloc_thing(private_ha_message_t);
-
- this->public.get_type = (ha_message_type_t(*)(ha_message_t*))get_type;
- this->public.add_attribute = (void(*)(ha_message_t*, ha_message_attribute_t attribute, ...))add_attribute;
- this->public.create_attribute_enumerator = (enumerator_t*(*)(ha_message_t*))create_attribute_enumerator;
- this->public.get_encoding = (chunk_t(*)(ha_message_t*))get_encoding;
- this->public.destroy = (void(*)(ha_message_t*))destroy;
+ private_ha_message_t *this;
+ INIT(this,
+ .public = {
+ .get_type = _get_type,
+ .add_attribute = _add_attribute,
+ .create_attribute_enumerator = _create_attribute_enumerator,
+ .get_encoding = _get_encoding,
+ .destroy = _destroy,
+ },
+ );
return this;
}
diff --git a/src/libcharon/plugins/ha/ha_message.h b/src/libcharon/plugins/ha/ha_message.h
index b2bc23724..50e11830f 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 1
+#define HA_MESSAGE_VERSION 2
typedef struct ha_message_t ha_message_t;
typedef enum ha_message_type_t ha_message_type_t;
@@ -43,8 +43,12 @@ typedef union ha_message_value_t ha_message_value_t;
enum ha_message_type_t {
/** add a completely new IKE_SA */
HA_IKE_ADD = 1,
- /** update an existing IKE_SA (message IDs, address update, ...) */
+ /** update an existing IKE_SA (identities, address update, ...) */
HA_IKE_UPDATE,
+ /** update initiator message id */
+ HA_IKE_MID_INITIATOR,
+ /** update responder message id */
+ HA_IKE_MID_RESPONDER,
/** delete an existing IKE_SA */
HA_IKE_DELETE,
/** add a new CHILD_SA */
@@ -62,6 +66,11 @@ enum ha_message_type_t {
};
/**
+ * Enum names for message types
+ */
+extern enum_name_t *ha_message_type_names;
+
+/**
* Type of attributes contained in a message
*/
enum ha_message_attribute_t {
@@ -73,6 +82,8 @@ enum ha_message_attribute_t {
HA_LOCAL_ID,
/** identification_t*, remote identity */
HA_REMOTE_ID,
+ /** identification_t*, remote EAP identity */
+ HA_REMOTE_EAP_ID,
/** host_t*, local address */
HA_LOCAL_ADDR,
/** host_t*, remote address */
@@ -89,6 +100,8 @@ enum ha_message_attribute_t {
HA_REMOTE_VIP,
/** host_t*, additional MOBIKE peer address */
HA_ADDITIONAL_ADDR,
+ /** u_int8_t, initiator of an exchange, TRUE for local */
+ HA_INITIATOR,
/** chunk_t, initiators nonce */
HA_NONCE_I,
/** chunk_t, responders nonce */
@@ -123,10 +136,8 @@ enum ha_message_attribute_t {
HA_LOCAL_TS,
/** traffic_selector_t*, remote traffic selector */
HA_REMOTE_TS,
- /** u_int32_t, initiating message ID */
- HA_INITIATE_MID,
- /** u_int32_t, responding message ID */
- HA_RESPOND_MID,
+ /** u_int32_t, message ID */
+ HA_MID,
/** u_int16_t, HA segment */
HA_SEGMENT,
};
@@ -190,7 +201,6 @@ struct ha_message_t {
/**
* Create a new ha_message instance, ready for adding attributes
*
- * @param version protocol version to create a message from
* @param type type of the message
*/
ha_message_t *ha_message_create(ha_message_type_t type);
@@ -202,4 +212,4 @@ ha_message_t *ha_message_create(ha_message_type_t type);
*/
ha_message_t *ha_message_parse(chunk_t data);
-#endif /* HA_MESSAGE_ @}*/
+#endif /** HA_MESSAGE_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_plugin.c b/src/libcharon/plugins/ha/ha_plugin.c
index ea255c8ab..e722b4f3a 100644
--- a/src/libcharon/plugins/ha/ha_plugin.c
+++ b/src/libcharon/plugins/ha/ha_plugin.c
@@ -21,8 +21,11 @@
#include "ha_dispatcher.h"
#include "ha_segments.h"
#include "ha_ctl.h"
+#include "ha_cache.h"
+#include "ha_attribute.h"
#include <daemon.h>
+#include <hydra.h>
#include <config/child_cfg.h>
typedef struct private_ha_plugin_t private_ha_plugin_t;
@@ -76,20 +79,31 @@ struct private_ha_plugin_t {
* Segment control interface via FIFO
*/
ha_ctl_t *ctl;
+
+ /**
+ * Message cache for resynchronization
+ */
+ ha_cache_t *cache;
+
+ /**
+ * Attribute provider
+ */
+ ha_attribute_t *attr;
};
-/**
- * Implementation of plugin_t.destroy
- */
-static void destroy(private_ha_plugin_t *this)
+METHOD(plugin_t, destroy, void,
+ private_ha_plugin_t *this)
{
DESTROY_IF(this->ctl);
+ hydra->attributes->remove_provider(hydra->attributes, &this->attr->provider);
charon->bus->remove_listener(charon->bus, &this->segments->listener);
charon->bus->remove_listener(charon->bus, &this->ike->listener);
charon->bus->remove_listener(charon->bus, &this->child->listener);
this->ike->destroy(this->ike);
this->child->destroy(this->child);
this->dispatcher->destroy(this->dispatcher);
+ this->attr->destroy(this->attr);
+ this->cache->destroy(this->cache);
this->segments->destroy(this->segments);
this->kernel->destroy(this->kernel);
this->socket->destroy(this->socket);
@@ -127,11 +141,9 @@ plugin_t *ha_plugin_create()
return NULL;
}
- this = malloc_thing(private_ha_plugin_t);
-
- this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
- this->tunnel = NULL;
- this->ctl = NULL;
+ INIT(this,
+ .public.plugin.destroy = _destroy,
+ );
if (secret)
{
@@ -146,17 +158,22 @@ plugin_t *ha_plugin_create()
}
this->kernel = ha_kernel_create(count);
this->segments = ha_segments_create(this->socket, this->kernel, this->tunnel,
- count, strcmp(local, remote) > 0, monitor, resync);
+ count, strcmp(local, remote) > 0, monitor);
+ this->cache = ha_cache_create(this->kernel, this->socket, resync, count);
if (fifo)
{
- this->ctl = ha_ctl_create(this->segments);
+ this->ctl = ha_ctl_create(this->segments, this->cache);
}
- this->dispatcher = ha_dispatcher_create(this->socket, this->segments);
- this->ike = ha_ike_create(this->socket, this->tunnel);
- this->child = ha_child_create(this->socket, this->tunnel);
+ this->attr = ha_attribute_create(this->kernel, this->segments);
+ this->dispatcher = ha_dispatcher_create(this->socket, this->segments,
+ this->cache, this->kernel, this->attr);
+ this->ike = ha_ike_create(this->socket, this->tunnel, this->cache);
+ this->child = ha_child_create(this->socket, this->tunnel, this->segments,
+ this->kernel);
charon->bus->add_listener(charon->bus, &this->segments->listener);
charon->bus->add_listener(charon->bus, &this->ike->listener);
charon->bus->add_listener(charon->bus, &this->child->listener);
+ hydra->attributes->add_provider(hydra->attributes, &this->attr->provider);
return &this->public.plugin;
}
diff --git a/src/libcharon/plugins/ha/ha_plugin.h b/src/libcharon/plugins/ha/ha_plugin.h
index 1ae2fe6dd..d4d746f91 100644
--- a/src/libcharon/plugins/ha/ha_plugin.h
+++ b/src/libcharon/plugins/ha/ha_plugin.h
@@ -44,4 +44,4 @@ struct ha_plugin_t {
plugin_t plugin;
};
-#endif /* HA_PLUGIN_H_ @}*/
+#endif /** HA_PLUGIN_H_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_segments.c b/src/libcharon/plugins/ha/ha_segments.c
index 2199671fc..be2d7e428 100644
--- a/src/libcharon/plugins/ha/ha_segments.c
+++ b/src/libcharon/plugins/ha/ha_segments.c
@@ -22,8 +22,8 @@
#include <utils/linked_list.h>
#include <processing/jobs/callback_job.h>
-#define HEARTBEAT_DELAY 1000
-#define HEARTBEAT_TIMEOUT 2100
+#define DEFAULT_HEARTBEAT_DELAY 1000
+#define DEFAULT_HEARTBEAT_TIMEOUT 2100
typedef struct private_ha_segments_t private_ha_segments_t;
@@ -81,6 +81,16 @@ struct private_ha_segments_t {
* Node number
*/
u_int node;
+
+ /**
+ * Interval we send hearbeats
+ */
+ int heartbeat_delay;
+
+ /**
+ * Timeout for heartbeats received from other node
+ */
+ int heartbeat_timeout;
};
/**
@@ -168,8 +178,8 @@ static void enable_disable(private_ha_segments_t *this, u_int segment,
{
continue;
}
- if (this->kernel->in_segment(this->kernel,
- ike_sa->get_other_host(ike_sa), segment))
+ if (this->kernel->get_segment(this->kernel,
+ ike_sa->get_other_host(ike_sa)) == segment)
{
ike_sa->set_state(ike_sa, new);
}
@@ -183,6 +193,7 @@ static void enable_disable(private_ha_segments_t *this, u_int segment,
message = ha_message_create(type);
message->add_attribute(message, HA_SEGMENT, segment);
this->socket->push(this->socket, message);
+ message->destroy(message);
}
}
@@ -209,135 +220,37 @@ static void enable_disable_all(private_ha_segments_t *this, u_int segment,
this->mutex->unlock(this->mutex);
}
-/**
- * Implementation of ha_segments_t.activate
- */
-static void activate(private_ha_segments_t *this, u_int segment, bool notify)
+METHOD(ha_segments_t, activate, void,
+ private_ha_segments_t *this, u_int segment, bool notify)
{
enable_disable_all(this, segment, TRUE, notify);
}
-/**
- * Implementation of ha_segments_t.deactivate
- */
-static void deactivate(private_ha_segments_t *this, u_int segment, bool notify)
+METHOD(ha_segments_t, deactivate, void,
+ private_ha_segments_t *this, u_int segment, bool notify)
{
enable_disable_all(this, segment, FALSE, notify);
}
-/**
- * Rekey all children of an IKE_SA
- */
-static status_t rekey_children(ike_sa_t *ike_sa)
+METHOD(listener_t, alert_hook, bool,
+ private_ha_segments_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args)
{
- iterator_t *iterator;
- child_sa_t *child_sa;
- status_t status = SUCCESS;
-
- iterator = ike_sa->create_child_sa_iterator(ike_sa);
- while (iterator->iterate(iterator, (void**)&child_sa))
- {
- DBG1(DBG_CFG, "resyncing CHILD_SA");
- status = ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa),
- child_sa->get_spi(child_sa, TRUE));
- if (status == DESTROY_ME)
- {
- break;
- }
- }
- iterator->destroy(iterator);
- return status;
-}
-
-/**
- * Implementation of ha_segments_t.resync
- */
-static void resync(private_ha_segments_t *this, u_int segment)
-{
- ike_sa_t *ike_sa;
- enumerator_t *enumerator;
- linked_list_t *list;
- ike_sa_id_t *id;
-
- list = linked_list_create();
- this->mutex->lock(this->mutex);
-
- if (segment > 0 && segment <= this->count)
+ if (alert == ALERT_SHUTDOWN_SIGNAL)
{
- DBG1(DBG_CFG, "resyncing HA segment %d", segment);
-
- /* we do the actual rekeying in a seperate loop to avoid rekeying
- * an SA twice. */
- enumerator = charon->ike_sa_manager->create_enumerator(
- charon->ike_sa_manager);
- while (enumerator->enumerate(enumerator, &ike_sa))
+ if (this->job)
{
- if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
- this->kernel->in_segment(this->kernel,
- ike_sa->get_other_host(ike_sa), segment))
- {
- id = ike_sa->get_id(ike_sa);
- list->insert_last(list, id->clone(id));
- }
+ DBG1(DBG_CFG, "HA heartbeat active, dropping all segments");
+ deactivate(this, 0, TRUE);
}
- enumerator->destroy(enumerator);
- }
- this->mutex->unlock(this->mutex);
-
- while (list->remove_last(list, (void**)&id) == SUCCESS)
- {
- ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
- id->destroy(id);
- if (ike_sa)
+ else
{
- DBG1(DBG_CFG, "resyncing IKE_SA");
- if (ike_sa->rekey(ike_sa) != DESTROY_ME)
- {
- if (rekey_children(ike_sa) != DESTROY_ME)
- {
- charon->ike_sa_manager->checkin(
- charon->ike_sa_manager, ike_sa);
- continue;
- }
- }
- charon->ike_sa_manager->checkin_and_destroy(
- charon->ike_sa_manager, ike_sa);
+ DBG1(DBG_CFG, "no HA heartbeat active, closing IKE_SAs");
}
}
- list->destroy(list);
-}
-
-/**
- * Implementation of listener_t.alert
- */
-static bool alert_hook(private_ha_segments_t *this, ike_sa_t *ike_sa,
- alert_t alert, va_list args)
-{
- if (alert == ALERT_SHUTDOWN_SIGNAL)
- {
- deactivate(this, 0, TRUE);
- }
return TRUE;
}
/**
- * Request a resync of all segments
- */
-static job_requeue_t request_resync(private_ha_segments_t *this)
-{
- ha_message_t *message;
- int i;
-
- message = ha_message_create(HA_RESYNC);
- for (i = 1; i <= this->count; i++)
- {
- message->add_attribute(message, HA_SEGMENT, i);
- }
- this->socket->push(this->socket, message);
- return JOB_REQUEUE_NONE;
-}
-
-/**
* Monitor heartbeat activity of remote node
*/
static job_requeue_t watchdog(private_ha_segments_t *this)
@@ -349,7 +262,7 @@ static job_requeue_t watchdog(private_ha_segments_t *this)
pthread_cleanup_push((void*)this->mutex->unlock, this->mutex);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
timeout = this->condvar->timed_wait(this->condvar, this->mutex,
- HEARTBEAT_TIMEOUT);
+ this->heartbeat_timeout);
pthread_setcancelstate(oldstate, NULL);
pthread_cleanup_pop(TRUE);
if (timeout)
@@ -373,10 +286,8 @@ static void start_watchdog(private_ha_segments_t *this)
charon->processor->queue_job(charon->processor, (job_t*)this->job);
}
-/**
- * Implementation of ha_segments_t.handle_status
- */
-static void handle_status(private_ha_segments_t *this, segment_mask_t mask)
+METHOD(ha_segments_t, handle_status, void,
+ private_ha_segments_t *this, segment_mask_t mask)
{
segment_mask_t missing;
int i;
@@ -431,20 +342,25 @@ static job_requeue_t send_status(private_ha_segments_t *this)
}
this->socket->push(this->socket, message);
+ message->destroy(message);
/* schedule next invocation */
charon->scheduler->schedule_job_ms(charon->scheduler, (job_t*)
callback_job_create((callback_job_cb_t)
send_status, this, NULL, NULL),
- HEARTBEAT_DELAY);
+ this->heartbeat_delay);
return JOB_REQUEUE_NONE;
}
-/**
- * Implementation of ha_segments_t.destroy.
- */
-static void destroy(private_ha_segments_t *this)
+METHOD(ha_segments_t, is_active, bool,
+ private_ha_segments_t *this, u_int segment)
+{
+ return (this->active & SEGMENTS_BIT(segment)) != 0;
+}
+
+METHOD(ha_segments_t, destroy, void,
+ private_ha_segments_t *this)
{
if (this->job)
{
@@ -460,44 +376,40 @@ static void destroy(private_ha_segments_t *this)
*/
ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
ha_tunnel_t *tunnel, u_int count, u_int node,
- bool monitor, bool sync)
+ bool monitor)
{
- private_ha_segments_t *this = malloc_thing(private_ha_segments_t);
-
- memset(&this->public.listener, 0, sizeof(listener_t));
- this->public.listener.alert = (bool(*)(listener_t*, ike_sa_t *, alert_t, va_list))alert_hook;
- this->public.activate = (void(*)(ha_segments_t*, u_int segment,bool))activate;
- this->public.deactivate = (void(*)(ha_segments_t*, u_int segment,bool))deactivate;
- this->public.resync = (void(*)(ha_segments_t*, u_int segment))resync;
- this->public.handle_status = (void(*)(ha_segments_t*, segment_mask_t mask))handle_status;
- this->public.destroy = (void(*)(ha_segments_t*))destroy;
-
- this->socket = socket;
- this->tunnel = tunnel;
- this->kernel = kernel;
- this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
- this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
- this->count = count;
- this->node = node;
- this->job = NULL;
-
- /* initially all segments are deactivated */
- this->active = 0;
+ private_ha_segments_t *this;
+
+ INIT(this,
+ .public = {
+ .listener.alert = _alert_hook,
+ .activate = _activate,
+ .deactivate = _deactivate,
+ .handle_status = _handle_status,
+ .is_active = _is_active,
+ .destroy = _destroy,
+ },
+ .socket = socket,
+ .tunnel = tunnel,
+ .kernel = kernel,
+ .count = count,
+ .node = node,
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
+ .heartbeat_delay = lib->settings->get_int(lib->settings,
+ "charon.plugins.ha.heartbeat_delay", DEFAULT_HEARTBEAT_DELAY),
+ .heartbeat_timeout = lib->settings->get_int(lib->settings,
+ "charon.plugins.ha.heartbeat_timeout", DEFAULT_HEARTBEAT_TIMEOUT),
+ );
if (monitor)
{
+ DBG1(DBG_CFG, "starting HA heartbeat, delay %dms, timeout %dms",
+ this->heartbeat_delay, this->heartbeat_timeout);
send_status(this);
start_watchdog(this);
}
- if (sync)
- {
- /* request a resync as soon as we are up */
- charon->processor->queue_job(charon->processor, (job_t*)
- callback_job_create((callback_job_cb_t)request_resync,
- this, NULL, NULL));
- }
-
return &this->public;
}
diff --git a/src/libcharon/plugins/ha/ha_segments.h b/src/libcharon/plugins/ha/ha_segments.h
index 6d1cd5441..eb9e5c1d5 100644
--- a/src/libcharon/plugins/ha/ha_segments.h
+++ b/src/libcharon/plugins/ha/ha_segments.h
@@ -68,23 +68,19 @@ struct ha_segments_t {
void (*deactivate)(ha_segments_t *this, u_int segment, bool notify);
/**
- * Resync an active segment.
- *
- * To reintegrade a node into the cluster, resynchronization is reqired.
- * IKE_SAs and CHILD_SAs are synced automatically during rekeying. A call
- * to this method enforces a rekeying immediately sync all state of a
- * segment.
+ * Handle a status message from the remote node.
*
- * @param segment segment to resync
+ * @param mask segments the remote node is serving actively
*/
- void (*resync)(ha_segments_t *this, u_int segment);
+ void (*handle_status)(ha_segments_t *this, segment_mask_t mask);
/**
- * Handle a status message from the remote node.
+ * Check if a given segment is currently active.
*
- * @param mask segments the remote node is serving actively
+ * @param segment segment to check
+ * @return TRUE if segment active
*/
- void (*handle_status)(ha_segments_t *this, segment_mask_t mask);
+ bool (*is_active)(ha_segments_t *this, u_int segment);
/**
* Destroy a ha_segments_t.
@@ -101,11 +97,10 @@ struct ha_segments_t {
* @param count number of segments the cluster uses
* @param node node, currently 1 or 0
* @param monitor should we use monitoring functionality
- * @param resync request a complete resync on startup
* @return segment object
*/
ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
ha_tunnel_t *tunnel, u_int count, u_int node,
- bool monitor, bool resync);
+ bool monitor);
-#endif /* HA_SEGMENTS_ @}*/
+#endif /** HA_SEGMENTS_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_socket.c b/src/libcharon/plugins/ha/ha_socket.c
index b84b02868..21e6eb6d5 100644
--- a/src/libcharon/plugins/ha/ha_socket.c
+++ b/src/libcharon/plugins/ha/ha_socket.c
@@ -58,8 +58,8 @@ struct private_ha_socket_t {
* Data to pass to the send_message() callback job
*/
typedef struct {
- ha_message_t *message;
- private_ha_socket_t *this;
+ chunk_t chunk;
+ int fd;
} job_data_t;
/**
@@ -67,7 +67,7 @@ typedef struct {
*/
static void job_data_destroy(job_data_t *this)
{
- this->message->destroy(this->message);
+ free(this->chunk.ptr);
free(this);
}
@@ -76,22 +76,15 @@ static void job_data_destroy(job_data_t *this)
*/
static job_requeue_t send_message(job_data_t *data)
{
- private_ha_socket_t *this;
- chunk_t chunk;
-
- this = data->this;
- chunk = data->message->get_encoding(data->message);
- if (send(this->fd, chunk.ptr, chunk.len, 0) < chunk.len)
+ if (send(data->fd, data->chunk.ptr, data->chunk.len, 0) < data->chunk.len)
{
DBG1(DBG_CFG, "pushing HA message failed: %s", strerror(errno));
}
return JOB_REQUEUE_NONE;
}
-/**
- * Implementation of ha_socket_t.push
- */
-static void push(private_ha_socket_t *this, ha_message_t *message)
+METHOD(ha_socket_t, push, void,
+ private_ha_socket_t *this, ha_message_t *message)
{
chunk_t chunk;
@@ -107,9 +100,10 @@ static void push(private_ha_socket_t *this, ha_message_t *message)
/* Fallback to asynchronous transmission. This is required, as sendto()
* is a blocking call if it acquires a policy. We could end up in a
* deadlock, as we own an IKE_SA. */
- data = malloc_thing(job_data_t);
- data->message = message;
- data->this = this;
+ INIT(data,
+ .chunk = chunk_clone(chunk),
+ .fd = this->fd,
+ );
job = callback_job_create((callback_job_cb_t)send_message,
data, (void*)job_data_destroy, NULL);
@@ -118,13 +112,10 @@ static void push(private_ha_socket_t *this, ha_message_t *message)
}
DBG1(DBG_CFG, "pushing HA message failed: %s", strerror(errno));
}
- message->destroy(message);
}
-/**
- * Implementation of ha_socket_t.pull
- */
-static ha_message_t *pull(private_ha_socket_t *this)
+METHOD(ha_socket_t, pull, ha_message_t*,
+ private_ha_socket_t *this)
{
while (TRUE)
{
@@ -189,10 +180,8 @@ static bool open_socket(private_ha_socket_t *this)
return TRUE;
}
-/**
- * Implementation of ha_socket_t.destroy.
- */
-static void destroy(private_ha_socket_t *this)
+METHOD(ha_socket_t, destroy, void,
+ private_ha_socket_t *this)
{
if (this->fd != -1)
{
@@ -208,15 +197,18 @@ static void destroy(private_ha_socket_t *this)
*/
ha_socket_t *ha_socket_create(char *local, char *remote)
{
- private_ha_socket_t *this = malloc_thing(private_ha_socket_t);
-
- this->public.push = (void(*)(ha_socket_t*, ha_message_t*))push;
- this->public.pull = (ha_message_t*(*)(ha_socket_t*))pull;
- this->public.destroy = (void(*)(ha_socket_t*))destroy;
+ private_ha_socket_t *this;
- this->local = host_create_from_dns(local, 0, HA_PORT);
- this->remote = host_create_from_dns(remote, 0, HA_PORT);
- this->fd = -1;
+ INIT(this,
+ .public = {
+ .push = _push,
+ .pull = _pull,
+ .destroy = _destroy,
+ },
+ .local = host_create_from_dns(local, 0, HA_PORT),
+ .remote = host_create_from_dns(remote, 0, HA_PORT),
+ .fd = -1,
+ );
if (!this->local || !this->remote)
{
diff --git a/src/libcharon/plugins/ha/ha_socket.h b/src/libcharon/plugins/ha/ha_socket.h
index 8d398e22b..a4789a51d 100644
--- a/src/libcharon/plugins/ha/ha_socket.h
+++ b/src/libcharon/plugins/ha/ha_socket.h
@@ -35,7 +35,7 @@ struct ha_socket_t {
/**
* Push synchronization information to the responsible node.
*
- * @param message message to send, gets destroyed by push()
+ * @param message message to send
*/
void (*push)(ha_socket_t *this, ha_message_t *message);
@@ -57,4 +57,4 @@ struct ha_socket_t {
*/
ha_socket_t *ha_socket_create(char *local, char *remote);
-#endif /* HA_SOCKET_ @}*/
+#endif /** HA_SOCKET_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c
index b3511e5f0..fef84a430 100644
--- a/src/libcharon/plugins/ha/ha_tunnel.c
+++ b/src/libcharon/plugins/ha/ha_tunnel.c
@@ -92,10 +92,8 @@ struct private_ha_tunnel_t {
ha_creds_t creds;
};
-/**
- * Implementation of ha_tunnel_t.is_sa
- */
-static bool is_sa(private_ha_tunnel_t *this, ike_sa_t *ike_sa)
+METHOD(ha_tunnel_t, is_sa, bool,
+ private_ha_tunnel_t *this, ike_sa_t *ike_sa)
{
peer_cfg_t *cfg = this->backend.cfg;
@@ -112,11 +110,8 @@ typedef struct {
shared_key_t *key;
} shared_enum_t;
-/**
- * Implementation of shared_enum_t.enumerate
- */
-static bool shared_enumerate(shared_enum_t *this, shared_key_t **key,
- id_match_t *me, id_match_t *other)
+METHOD(enumerator_t, shared_enumerate, bool,
+ shared_enum_t *this, shared_key_t **key, id_match_t *me, id_match_t *other)
{
if (this->key)
{
@@ -135,12 +130,9 @@ static bool shared_enumerate(shared_enum_t *this, shared_key_t **key,
return FALSE;
}
-/**
- * Implements ha_creds_t.create_shared_enumerator
- */
-static enumerator_t* create_shared_enumerator(ha_creds_t *this,
- shared_key_type_t type, identification_t *me,
- identification_t *other)
+METHOD(ha_creds_t, create_shared_enumerator, enumerator_t*,
+ ha_creds_t *this, shared_key_type_t type,
+ identification_t *me, identification_t *other)
{
shared_enum_t *enumerator;
@@ -157,28 +149,25 @@ static enumerator_t* create_shared_enumerator(ha_creds_t *this,
return NULL;
}
- enumerator = malloc_thing(shared_enum_t);
- enumerator->public.enumerate = (void*)shared_enumerate;
- enumerator->public.destroy = (void*)free;
- enumerator->key = this->key;
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_shared_enumerate,
+ .destroy = (void*)free,
+ },
+ .key = this->key,
+ );
return &enumerator->public;
}
-/**
- * Implementation of backend_t.create_peer_cfg_enumerator.
- */
-static enumerator_t* create_peer_cfg_enumerator(ha_backend_t *this,
- identification_t *me, identification_t *other)
+METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*,
+ ha_backend_t *this, identification_t *me, identification_t *other)
{
return enumerator_create_single(this->cfg, NULL);
}
-/**
- * Implementation of backend_t.create_ike_cfg_enumerator.
- */
-static enumerator_t* create_ike_cfg_enumerator(ha_backend_t *this,
- host_t *me, host_t *other)
+METHOD(backend_t, create_ike_cfg_enumerator, enumerator_t*,
+ ha_backend_t *this, host_t *me, host_t *other)
{
return enumerator_create_single(this->cfg->get_ike_cfg(this->cfg), NULL);
}
@@ -207,11 +196,11 @@ static void setup_tunnel(private_ha_tunnel_t *this,
chunk_clone(chunk_create(secret, strlen(secret))));
this->creds.public.create_private_enumerator = (void*)return_null;
this->creds.public.create_cert_enumerator = (void*)return_null;
- this->creds.public.create_shared_enumerator = (void*)create_shared_enumerator;
+ this->creds.public.create_shared_enumerator = (void*)_create_shared_enumerator;
this->creds.public.create_cdp_enumerator = (void*)return_null;
this->creds.public.cache_cert = (void*)nop;
- charon->credentials->add_set(charon->credentials, &this->creds.public);
+ lib->credmgr->add_set(lib->credmgr, &this->creds.public);
/* create config and backend */
ike_cfg = ike_cfg_create(FALSE, FALSE, local, IKEV2_UDP_PORT,
@@ -233,8 +222,9 @@ static void setup_tunnel(private_ha_tunnel_t *this,
identification_create_from_string(remote));
peer_cfg->add_auth_cfg(peer_cfg, auth_cfg, FALSE);
- child_cfg = child_cfg_create("ha", &lifetime, NULL, TRUE,
- MODE_TRANSPORT, ACTION_NONE, ACTION_NONE, FALSE, 0);
+ child_cfg = child_cfg_create("ha", &lifetime, NULL, TRUE, MODE_TRANSPORT,
+ ACTION_NONE, ACTION_NONE, FALSE, 0, 0,
+ NULL, NULL);
ts = traffic_selector_create_dynamic(IPPROTO_UDP, HA_PORT, HA_PORT);
child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
ts = traffic_selector_create_dynamic(IPPROTO_ICMP, 0, 65535);
@@ -247,8 +237,8 @@ static void setup_tunnel(private_ha_tunnel_t *this,
peer_cfg->add_child_cfg(peer_cfg, child_cfg);
this->backend.cfg = peer_cfg;
- this->backend.public.create_peer_cfg_enumerator = (void*)create_peer_cfg_enumerator;
- this->backend.public.create_ike_cfg_enumerator = (void*)create_ike_cfg_enumerator;
+ this->backend.public.create_peer_cfg_enumerator = (void*)_create_peer_cfg_enumerator;
+ this->backend.public.create_ike_cfg_enumerator = (void*)_create_ike_cfg_enumerator;
this->backend.public.get_peer_cfg_by_name = (void*)return_null;
charon->backends->add_backend(charon->backends, &this->backend.public);
@@ -257,10 +247,8 @@ static void setup_tunnel(private_ha_tunnel_t *this,
this->trap = charon->traps->install(charon->traps, peer_cfg, child_cfg);
}
-/**
- * Implementation of ha_tunnel_t.destroy.
- */
-static void destroy(private_ha_tunnel_t *this)
+METHOD(ha_tunnel_t, destroy, void,
+ private_ha_tunnel_t *this)
{
if (this->backend.cfg)
{
@@ -269,7 +257,7 @@ static void destroy(private_ha_tunnel_t *this)
}
if (this->creds.key)
{
- charon->credentials->remove_set(charon->credentials, &this->creds.public);
+ lib->credmgr->remove_set(lib->credmgr, &this->creds.public);
this->creds.key->destroy(this->creds.key);
}
this->creds.local->destroy(this->creds.local);
@@ -286,10 +274,14 @@ static void destroy(private_ha_tunnel_t *this)
*/
ha_tunnel_t *ha_tunnel_create(char *local, char *remote, char *secret)
{
- private_ha_tunnel_t *this = malloc_thing(private_ha_tunnel_t);
+ private_ha_tunnel_t *this;
- this->public.is_sa = (bool(*)(ha_tunnel_t*, ike_sa_t *ike_sa))is_sa;
- this->public.destroy = (void(*)(ha_tunnel_t*))destroy;
+ INIT(this,
+ .public = {
+ .is_sa = _is_sa,
+ .destroy = _destroy,
+ },
+ );
setup_tunnel(this, local, remote, secret);
diff --git a/src/libcharon/plugins/ha/ha_tunnel.h b/src/libcharon/plugins/ha/ha_tunnel.h
index 085fb6122..549e33055 100644
--- a/src/libcharon/plugins/ha/ha_tunnel.h
+++ b/src/libcharon/plugins/ha/ha_tunnel.h
@@ -54,4 +54,4 @@ struct ha_tunnel_t {
*/
ha_tunnel_t *ha_tunnel_create(char *local, char *remote, char *secret);
-#endif /* HA_TUNNEL_H_ @}*/
+#endif /** HA_TUNNEL_H_ @}*/