diff options
Diffstat (limited to 'src/libcharon/plugins/ha')
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_ @}*/ |