aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcharon/plugins/ha/Makefile.am3
-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_dispatcher.c27
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.h5
-rw-r--r--src/libcharon/plugins/ha/ha_plugin.c13
6 files changed, 468 insertions, 4 deletions
diff --git a/src/libcharon/plugins/ha/Makefile.am b/src/libcharon/plugins/ha/Makefile.am
index 165f8c9dc..0df1b8d91 100644
--- a/src/libcharon/plugins/ha/Makefile.am
+++ b/src/libcharon/plugins/ha/Makefile.am
@@ -21,6 +21,7 @@ libstrongswan_ha_la_SOURCES = \
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/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_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c
index ecae05fd5..3bc426ea0 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -51,6 +51,11 @@ struct private_ha_dispatcher_t {
ha_kernel_t *kernel;
/**
+ * HA enabled pool
+ */
+ ha_attribute_t *attr;
+
+ /**
* Dispatcher job
*/
callback_job_t *job;
@@ -215,6 +220,7 @@ static void process_ike_update(private_ha_dispatcher_t *this,
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))
@@ -252,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,
@@ -301,6 +308,22 @@ static void process_ike_update(private_ha_dispatcher_t *this,
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);
}
@@ -828,7 +851,8 @@ METHOD(ha_dispatcher_t, destroy, void,
* See header
*/
ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
- ha_segments_t *segments, ha_cache_t *cache, ha_kernel_t *kernel)
+ ha_segments_t *segments, ha_cache_t *cache,
+ ha_kernel_t *kernel, ha_attribute_t *attr)
{
private_ha_dispatcher_t *this;
@@ -841,6 +865,7 @@ ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
.segments = segments,
.cache = cache,
.kernel = kernel,
+ .attr = attr,
);
this->job = callback_job_create((callback_job_cb_t)dispatch,
this, NULL, NULL);
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.h b/src/libcharon/plugins/ha/ha_dispatcher.h
index 3a5ec7985..105a40473 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.h
+++ b/src/libcharon/plugins/ha/ha_dispatcher.h
@@ -25,6 +25,7 @@
#include "ha_segments.h"
#include "ha_cache.h"
#include "ha_kernel.h"
+#include "ha_attribute.h"
typedef struct ha_dispatcher_t ha_dispatcher_t;
@@ -46,9 +47,11 @@ struct ha_dispatcher_t {
* @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_cache_t *cache, ha_kernel_t *kernel);
+ ha_segments_t *segments, ha_cache_t *cache,
+ ha_kernel_t *kernel, ha_attribute_t *attr);
#endif /** HA_DISPATCHER_ @}*/
diff --git a/src/libcharon/plugins/ha/ha_plugin.c b/src/libcharon/plugins/ha/ha_plugin.c
index b20868b71..e722b4f3a 100644
--- a/src/libcharon/plugins/ha/ha_plugin.c
+++ b/src/libcharon/plugins/ha/ha_plugin.c
@@ -22,8 +22,10 @@
#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;
@@ -82,18 +84,25 @@ struct private_ha_plugin_t {
* Message cache for resynchronization
*/
ha_cache_t *cache;
+
+ /**
+ * Attribute provider
+ */
+ ha_attribute_t *attr;
};
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);
@@ -155,14 +164,16 @@ plugin_t *ha_plugin_create()
{
this->ctl = ha_ctl_create(this->segments, this->cache);
}
+ this->attr = ha_attribute_create(this->kernel, this->segments);
this->dispatcher = ha_dispatcher_create(this->socket, this->segments,
- this->cache, this->kernel);
+ 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;
}