Use a sync message cache to resynchronize IKE_SAs without rekeying
This commit is contained in:
@@ -17,6 +17,7 @@ libstrongswan_ha_la_SOURCES = \
|
|||||||
ha_tunnel.h ha_tunnel.c \
|
ha_tunnel.h ha_tunnel.c \
|
||||||
ha_dispatcher.h ha_dispatcher.c \
|
ha_dispatcher.h ha_dispatcher.c \
|
||||||
ha_segments.h ha_segments.c \
|
ha_segments.h ha_segments.c \
|
||||||
|
ha_cache.h ha_cache.c \
|
||||||
ha_kernel.h ha_kernel.c \
|
ha_kernel.h ha_kernel.c \
|
||||||
ha_ctl.h ha_ctl.c \
|
ha_ctl.h ha_ctl.c \
|
||||||
ha_ike.h ha_ike.c \
|
ha_ike.h ha_ike.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;
|
||||||
|
}
|
||||||
@@ -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_ @}*/
|
||||||
@@ -36,6 +36,11 @@ struct private_ha_child_t {
|
|||||||
* tunnel securing sync messages
|
* tunnel securing sync messages
|
||||||
*/
|
*/
|
||||||
ha_tunnel_t *tunnel;
|
ha_tunnel_t *tunnel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message cache
|
||||||
|
*/
|
||||||
|
ha_cache_t *cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
METHOD(listener_t, child_keys, bool,
|
METHOD(listener_t, child_keys, bool,
|
||||||
@@ -103,6 +108,7 @@ METHOD(listener_t, child_keys, bool,
|
|||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
this->socket->push(this->socket, m);
|
this->socket->push(this->socket, m);
|
||||||
|
m->destroy(m);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -133,6 +139,7 @@ METHOD(listener_t, child_state_change, bool,
|
|||||||
m->add_attribute(m, HA_INBOUND_SPI,
|
m->add_attribute(m, HA_INBOUND_SPI,
|
||||||
child_sa->get_spi(child_sa, TRUE));
|
child_sa->get_spi(child_sa, TRUE));
|
||||||
this->socket->push(this->socket, m);
|
this->socket->push(this->socket, m);
|
||||||
|
m->destroy(m);
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -146,7 +153,8 @@ METHOD(ha_child_t, destroy, void,
|
|||||||
/**
|
/**
|
||||||
* See header
|
* 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_cache_t *cache)
|
||||||
{
|
{
|
||||||
private_ha_child_t *this;
|
private_ha_child_t *this;
|
||||||
|
|
||||||
@@ -160,6 +168,7 @@ ha_child_t *ha_child_create(ha_socket_t *socket, ha_tunnel_t *tunnel)
|
|||||||
},
|
},
|
||||||
.socket = socket,
|
.socket = socket,
|
||||||
.tunnel = tunnel,
|
.tunnel = tunnel,
|
||||||
|
.cache = cache,
|
||||||
);
|
);
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
|
|||||||
@@ -21,14 +21,15 @@
|
|||||||
#ifndef HA_CHILD_H_
|
#ifndef HA_CHILD_H_
|
||||||
#define HA_CHILD_H_
|
#define HA_CHILD_H_
|
||||||
|
|
||||||
|
typedef struct ha_child_t ha_child_t;
|
||||||
|
|
||||||
#include "ha_socket.h"
|
#include "ha_socket.h"
|
||||||
#include "ha_tunnel.h"
|
#include "ha_tunnel.h"
|
||||||
#include "ha_segments.h"
|
#include "ha_segments.h"
|
||||||
|
#include "ha_cache.h"
|
||||||
|
|
||||||
#include <daemon.h>
|
#include <daemon.h>
|
||||||
|
|
||||||
typedef struct ha_child_t ha_child_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener to synchronize CHILD_SAs.
|
* Listener to synchronize CHILD_SAs.
|
||||||
*/
|
*/
|
||||||
@@ -50,8 +51,10 @@ struct ha_child_t {
|
|||||||
*
|
*
|
||||||
* @param socket socket to use for sending synchronization messages
|
* @param socket socket to use for sending synchronization messages
|
||||||
* @param tunnel tunnel securing sync messages, if any
|
* @param tunnel tunnel securing sync messages, if any
|
||||||
|
* @param cache message resync cache
|
||||||
* @return CHILD listener
|
* @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_cache_t *cache);
|
||||||
|
|
||||||
#endif /** HA_CHILD_ @}*/
|
#endif /** HA_CHILD_ @}*/
|
||||||
|
|||||||
@@ -44,6 +44,11 @@ struct private_ha_ctl_t {
|
|||||||
*/
|
*/
|
||||||
ha_segments_t *segments;
|
ha_segments_t *segments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resynchronization message cache
|
||||||
|
*/
|
||||||
|
ha_cache_t *cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FIFO reader thread
|
* FIFO reader thread
|
||||||
*/
|
*/
|
||||||
@@ -84,7 +89,7 @@ static job_requeue_t dispatch_fifo(private_ha_ctl_t *this)
|
|||||||
this->segments->deactivate(this->segments, segment, TRUE);
|
this->segments->deactivate(this->segments, segment, TRUE);
|
||||||
break;
|
break;
|
||||||
case '*':
|
case '*':
|
||||||
this->segments->resync(this->segments, segment);
|
this->cache->resync(this->cache, segment);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -106,7 +111,7 @@ METHOD(ha_ctl_t, destroy, void,
|
|||||||
/**
|
/**
|
||||||
* See header
|
* 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;
|
private_ha_ctl_t *this;
|
||||||
|
|
||||||
@@ -115,6 +120,7 @@ ha_ctl_t *ha_ctl_create(ha_segments_t *segments)
|
|||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
.segments = segments,
|
.segments = segments,
|
||||||
|
.cache = cache,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (access(HA_FIFO, R_OK|W_OK) != 0)
|
if (access(HA_FIFO, R_OK|W_OK) != 0)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#define HA_CTL_H_
|
#define HA_CTL_H_
|
||||||
|
|
||||||
#include "ha_segments.h"
|
#include "ha_segments.h"
|
||||||
|
#include "ha_cache.h"
|
||||||
|
|
||||||
typedef struct ha_ctl_t ha_ctl_t;
|
typedef struct ha_ctl_t ha_ctl_t;
|
||||||
|
|
||||||
@@ -40,8 +41,9 @@ struct ha_ctl_t {
|
|||||||
* Create a ha_ctl instance.
|
* Create a ha_ctl instance.
|
||||||
*
|
*
|
||||||
* @param segments segments to control
|
* @param segments segments to control
|
||||||
|
* @param cache message cache for resynchronization
|
||||||
* @return HA control interface
|
* @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_ @}*/
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ struct private_ha_dispatcher_t {
|
|||||||
*/
|
*/
|
||||||
ha_segments_t *segments;
|
ha_segments_t *segments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache for resync
|
||||||
|
*/
|
||||||
|
ha_cache_t *cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispatcher job
|
* Dispatcher job
|
||||||
*/
|
*/
|
||||||
@@ -153,6 +158,8 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
|
|||||||
old_sa = NULL;
|
old_sa = NULL;
|
||||||
}
|
}
|
||||||
ike_sa->set_state(ike_sa, IKE_CONNECTING);
|
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);
|
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -167,6 +174,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);
|
charon->ike_sa_manager->checkin(charon->ike_sa_manager, old_sa);
|
||||||
}
|
}
|
||||||
|
DESTROY_IF(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -276,10 +284,20 @@ static void process_ike_update(private_ha_dispatcher_t *this,
|
|||||||
if (ike_sa->get_state(ike_sa) == IKE_CONNECTING &&
|
if (ike_sa->get_state(ike_sa) == IKE_CONNECTING &&
|
||||||
ike_sa->get_peer_cfg(ike_sa))
|
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);
|
ike_sa->set_state(ike_sa, IKE_PASSIVE);
|
||||||
}
|
}
|
||||||
|
this->cache->cache(this->cache, ike_sa, message);
|
||||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -318,8 +336,13 @@ static void process_ike_mid(private_ha_dispatcher_t *this,
|
|||||||
{
|
{
|
||||||
ike_sa->set_message_id(ike_sa, initiator, 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);
|
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message->destroy(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -331,7 +354,7 @@ static void process_ike_delete(private_ha_dispatcher_t *this,
|
|||||||
ha_message_attribute_t attribute;
|
ha_message_attribute_t attribute;
|
||||||
ha_message_value_t value;
|
ha_message_value_t value;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
ike_sa_t *ike_sa;
|
ike_sa_t *ike_sa = NULL;
|
||||||
|
|
||||||
enumerator = message->create_attribute_enumerator(message);
|
enumerator = message->create_attribute_enumerator(message);
|
||||||
while (enumerator->enumerate(enumerator, &attribute, &value))
|
while (enumerator->enumerate(enumerator, &attribute, &value))
|
||||||
@@ -341,17 +364,22 @@ static void process_ike_delete(private_ha_dispatcher_t *this,
|
|||||||
case HA_IKE_ID:
|
case HA_IKE_ID:
|
||||||
ike_sa = charon->ike_sa_manager->checkout(
|
ike_sa = charon->ike_sa_manager->checkout(
|
||||||
charon->ike_sa_manager, value.ike_sa_id);
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -465,6 +493,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
|
|||||||
if (!ike_sa)
|
if (!ike_sa)
|
||||||
{
|
{
|
||||||
DBG1(DBG_CHD, "IKE_SA for HA CHILD_SA not found");
|
DBG1(DBG_CHD, "IKE_SA for HA CHILD_SA not found");
|
||||||
|
message->destroy(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
config = find_child_cfg(ike_sa, config_name);
|
config = find_child_cfg(ike_sa, config_name);
|
||||||
@@ -472,6 +501,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
|
|||||||
{
|
{
|
||||||
DBG1(DBG_CHD, "HA is missing nodes child configuration");
|
DBG1(DBG_CHD, "HA is missing nodes child configuration");
|
||||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||||
|
message->destroy(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,15 +588,19 @@ static void process_child_add(private_ha_dispatcher_t *this,
|
|||||||
local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
|
local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
|
||||||
remote_ts->destroy_offset(remote_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);
|
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||||
|
message->destroy(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DBG1(DBG_CFG, "installed HA CHILD_SA '%s' %#R=== %#R",
|
||||||
|
child_sa->get_name(child_sa), local_ts, remote_ts);
|
||||||
child_sa->add_policies(child_sa, local_ts, remote_ts);
|
child_sa->add_policies(child_sa, local_ts, remote_ts);
|
||||||
local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
|
local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
|
||||||
remote_ts->destroy_offset(remote_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);
|
child_sa->set_state(child_sa, CHILD_INSTALLED);
|
||||||
ike_sa->add_child_sa(ike_sa, child_sa);
|
ike_sa->add_child_sa(ike_sa, child_sa);
|
||||||
|
message->destroy(message);
|
||||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,6 +614,8 @@ static void process_child_delete(private_ha_dispatcher_t *this,
|
|||||||
ha_message_value_t value;
|
ha_message_value_t value;
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
ike_sa_t *ike_sa = NULL;
|
ike_sa_t *ike_sa = NULL;
|
||||||
|
child_sa_t *child_sa;
|
||||||
|
u_int32_t spi = 0;
|
||||||
|
|
||||||
enumerator = message->create_attribute_enumerator(message);
|
enumerator = message->create_attribute_enumerator(message);
|
||||||
while (enumerator->enumerate(enumerator, &attribute, &value))
|
while (enumerator->enumerate(enumerator, &attribute, &value))
|
||||||
@@ -591,20 +627,24 @@ static void process_child_delete(private_ha_dispatcher_t *this,
|
|||||||
value.ike_sa_id);
|
value.ike_sa_id);
|
||||||
break;
|
break;
|
||||||
case HA_INBOUND_SPI:
|
case HA_INBOUND_SPI:
|
||||||
if (ike_sa)
|
spi = value.u32;
|
||||||
{
|
|
||||||
ike_sa->destroy_child_sa(ike_sa, PROTO_ESP, value.u32);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
if (ike_sa)
|
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);
|
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
message->destroy(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -639,6 +679,7 @@ static void process_segment(private_ha_dispatcher_t *this,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
message->destroy(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -667,6 +708,7 @@ static void process_status(private_ha_dispatcher_t *this,
|
|||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
this->segments->handle_status(this->segments, mask);
|
this->segments->handle_status(this->segments, mask);
|
||||||
|
message->destroy(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -685,13 +727,14 @@ static void process_resync(private_ha_dispatcher_t *this,
|
|||||||
switch (attribute)
|
switch (attribute)
|
||||||
{
|
{
|
||||||
case HA_SEGMENT:
|
case HA_SEGMENT:
|
||||||
this->segments->resync(this->segments, value.u16);
|
this->cache->resync(this->cache, value.u16);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
message->destroy(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -746,10 +789,9 @@ static job_requeue_t dispatch(private_ha_dispatcher_t *this)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DBG1(DBG_CFG, "received unknown HA message type %d", type);
|
DBG1(DBG_CFG, "received unknown HA message type %d", type);
|
||||||
|
message->destroy(message);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
message->destroy(message);
|
|
||||||
|
|
||||||
return JOB_REQUEUE_DIRECT;
|
return JOB_REQUEUE_DIRECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,7 +806,7 @@ METHOD(ha_dispatcher_t, destroy, void,
|
|||||||
* See header
|
* See header
|
||||||
*/
|
*/
|
||||||
ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
|
ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
|
||||||
ha_segments_t *segments)
|
ha_segments_t *segments, ha_cache_t *cache)
|
||||||
{
|
{
|
||||||
private_ha_dispatcher_t *this;
|
private_ha_dispatcher_t *this;
|
||||||
|
|
||||||
@@ -775,6 +817,7 @@ ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
|
|||||||
},
|
},
|
||||||
.socket = socket,
|
.socket = socket,
|
||||||
.segments = segments,
|
.segments = segments,
|
||||||
|
.cache = cache,
|
||||||
);
|
);
|
||||||
this->job = callback_job_create((callback_job_cb_t)dispatch,
|
this->job = callback_job_create((callback_job_cb_t)dispatch,
|
||||||
this, NULL, NULL);
|
this, NULL, NULL);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "ha_socket.h"
|
#include "ha_socket.h"
|
||||||
#include "ha_segments.h"
|
#include "ha_segments.h"
|
||||||
|
#include "ha_cache.h"
|
||||||
|
|
||||||
typedef struct ha_dispatcher_t ha_dispatcher_t;
|
typedef struct ha_dispatcher_t ha_dispatcher_t;
|
||||||
|
|
||||||
@@ -42,9 +43,10 @@ struct ha_dispatcher_t {
|
|||||||
*
|
*
|
||||||
* @param socket socket to pull messages from
|
* @param socket socket to pull messages from
|
||||||
* @param segments segments to control based on received messages
|
* @param segments segments to control based on received messages
|
||||||
|
* @param cache message cache to use for resynchronization
|
||||||
* @return dispatcher object
|
* @return dispatcher object
|
||||||
*/
|
*/
|
||||||
ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
|
ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
|
||||||
ha_segments_t *segments);
|
ha_segments_t *segments, ha_cache_t *cache);
|
||||||
|
|
||||||
#endif /** HA_DISPATCHER_ @}*/
|
#endif /** HA_DISPATCHER_ @}*/
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ struct private_ha_ike_t {
|
|||||||
* tunnel securing sync messages
|
* tunnel securing sync messages
|
||||||
*/
|
*/
|
||||||
ha_tunnel_t *tunnel;
|
ha_tunnel_t *tunnel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message cache
|
||||||
|
*/
|
||||||
|
ha_cache_t *cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,6 +122,7 @@ METHOD(listener_t, ike_keys, bool,
|
|||||||
chunk_clear(&secret);
|
chunk_clear(&secret);
|
||||||
|
|
||||||
this->socket->push(this->socket, m);
|
this->socket->push(this->socket, m);
|
||||||
|
this->cache->cache(this->cache, ike_sa, m);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -181,6 +187,7 @@ METHOD(listener_t, ike_updown, bool,
|
|||||||
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
|
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
|
||||||
}
|
}
|
||||||
this->socket->push(this->socket, m);
|
this->socket->push(this->socket, m);
|
||||||
|
this->cache->cache(this->cache, ike_sa, m);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,6 +199,17 @@ METHOD(listener_t, ike_rekey, bool,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(listener_t, ike_state_change, bool,
|
||||||
|
private_ha_ike_t *this, ike_sa_t *ike_sa, ike_sa_state_t new)
|
||||||
|
{
|
||||||
|
/* clean up cache if a passive IKE_SA goes away */
|
||||||
|
if (ike_sa->get_state(ike_sa) == IKE_PASSIVE && new == IKE_DESTROYING)
|
||||||
|
{
|
||||||
|
this->cache->delete(this->cache, ike_sa);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(listener_t, message_hook, bool,
|
METHOD(listener_t, message_hook, bool,
|
||||||
private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message, bool incoming)
|
private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message, bool incoming)
|
||||||
{
|
{
|
||||||
@@ -216,6 +234,7 @@ METHOD(listener_t, message_hook, bool,
|
|||||||
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
|
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);
|
m->add_attribute(m, HA_MID, message->get_message_id(message) + 1);
|
||||||
this->socket->push(this->socket, m);
|
this->socket->push(this->socket, m);
|
||||||
|
this->cache->cache(this->cache, ike_sa, m);
|
||||||
}
|
}
|
||||||
if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
|
if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
|
||||||
message->get_exchange_type(message) == IKE_AUTH &&
|
message->get_exchange_type(message) == IKE_AUTH &&
|
||||||
@@ -233,6 +252,7 @@ METHOD(listener_t, message_hook, bool,
|
|||||||
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
|
m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa));
|
||||||
m->add_attribute(m, HA_REMOTE_VIP, vip);
|
m->add_attribute(m, HA_REMOTE_VIP, vip);
|
||||||
this->socket->push(this->socket, m);
|
this->socket->push(this->socket, m);
|
||||||
|
this->cache->cache(this->cache, ike_sa, m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -247,7 +267,8 @@ METHOD(ha_ike_t, destroy, void,
|
|||||||
/**
|
/**
|
||||||
* See header
|
* 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;
|
private_ha_ike_t *this;
|
||||||
|
|
||||||
@@ -257,12 +278,14 @@ ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel)
|
|||||||
.ike_keys = _ike_keys,
|
.ike_keys = _ike_keys,
|
||||||
.ike_updown = _ike_updown,
|
.ike_updown = _ike_updown,
|
||||||
.ike_rekey = _ike_rekey,
|
.ike_rekey = _ike_rekey,
|
||||||
|
.ike_state_change = _ike_state_change,
|
||||||
.message = _message_hook,
|
.message = _message_hook,
|
||||||
},
|
},
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
.socket = socket,
|
.socket = socket,
|
||||||
.tunnel = tunnel,
|
.tunnel = tunnel,
|
||||||
|
.cache = cache,
|
||||||
);
|
);
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
|
|||||||
@@ -21,14 +21,15 @@
|
|||||||
#ifndef HA_IKE_H_
|
#ifndef HA_IKE_H_
|
||||||
#define HA_IKE_H_
|
#define HA_IKE_H_
|
||||||
|
|
||||||
|
typedef struct ha_ike_t ha_ike_t;
|
||||||
|
|
||||||
#include "ha_socket.h"
|
#include "ha_socket.h"
|
||||||
#include "ha_tunnel.h"
|
#include "ha_tunnel.h"
|
||||||
#include "ha_segments.h"
|
#include "ha_segments.h"
|
||||||
|
#include "ha_cache.h"
|
||||||
|
|
||||||
#include <daemon.h>
|
#include <daemon.h>
|
||||||
|
|
||||||
typedef struct ha_ike_t ha_ike_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener to synchronize IKE_SAs.
|
* Listener to synchronize IKE_SAs.
|
||||||
*/
|
*/
|
||||||
@@ -50,8 +51,10 @@ struct ha_ike_t {
|
|||||||
*
|
*
|
||||||
* @param socket socket to use for sending synchronization messages
|
* @param socket socket to use for sending synchronization messages
|
||||||
* @param tunnel tunnel securing sync messages, if any
|
* @param tunnel tunnel securing sync messages, if any
|
||||||
|
* @param cache message cache
|
||||||
* @return IKE listener
|
* @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_ @}*/
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "ha_dispatcher.h"
|
#include "ha_dispatcher.h"
|
||||||
#include "ha_segments.h"
|
#include "ha_segments.h"
|
||||||
#include "ha_ctl.h"
|
#include "ha_ctl.h"
|
||||||
|
#include "ha_cache.h"
|
||||||
|
|
||||||
#include <daemon.h>
|
#include <daemon.h>
|
||||||
#include <config/child_cfg.h>
|
#include <config/child_cfg.h>
|
||||||
@@ -76,6 +77,11 @@ struct private_ha_plugin_t {
|
|||||||
* Segment control interface via FIFO
|
* Segment control interface via FIFO
|
||||||
*/
|
*/
|
||||||
ha_ctl_t *ctl;
|
ha_ctl_t *ctl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message cache for resynchronization
|
||||||
|
*/
|
||||||
|
ha_cache_t *cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
METHOD(plugin_t, destroy, void,
|
METHOD(plugin_t, destroy, void,
|
||||||
@@ -88,6 +94,7 @@ METHOD(plugin_t, destroy, void,
|
|||||||
this->ike->destroy(this->ike);
|
this->ike->destroy(this->ike);
|
||||||
this->child->destroy(this->child);
|
this->child->destroy(this->child);
|
||||||
this->dispatcher->destroy(this->dispatcher);
|
this->dispatcher->destroy(this->dispatcher);
|
||||||
|
this->cache->destroy(this->cache);
|
||||||
this->segments->destroy(this->segments);
|
this->segments->destroy(this->segments);
|
||||||
this->kernel->destroy(this->kernel);
|
this->kernel->destroy(this->kernel);
|
||||||
this->socket->destroy(this->socket);
|
this->socket->destroy(this->socket);
|
||||||
@@ -142,14 +149,16 @@ plugin_t *ha_plugin_create()
|
|||||||
}
|
}
|
||||||
this->kernel = ha_kernel_create(count);
|
this->kernel = ha_kernel_create(count);
|
||||||
this->segments = ha_segments_create(this->socket, this->kernel, this->tunnel,
|
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)
|
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->dispatcher = ha_dispatcher_create(this->socket, this->segments,
|
||||||
this->ike = ha_ike_create(this->socket, this->tunnel);
|
this->cache);
|
||||||
this->child = ha_child_create(this->socket, this->tunnel);
|
this->ike = ha_ike_create(this->socket, this->tunnel, this->cache);
|
||||||
|
this->child = ha_child_create(this->socket, this->tunnel, this->cache);
|
||||||
charon->bus->add_listener(charon->bus, &this->segments->listener);
|
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->ike->listener);
|
||||||
charon->bus->add_listener(charon->bus, &this->child->listener);
|
charon->bus->add_listener(charon->bus, &this->child->listener);
|
||||||
|
|||||||
@@ -183,6 +183,7 @@ static void enable_disable(private_ha_segments_t *this, u_int segment,
|
|||||||
message = ha_message_create(type);
|
message = ha_message_create(type);
|
||||||
message->add_attribute(message, HA_SEGMENT, segment);
|
message->add_attribute(message, HA_SEGMENT, segment);
|
||||||
this->socket->push(this->socket, message);
|
this->socket->push(this->socket, message);
|
||||||
|
message->destroy(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,115 +222,24 @@ METHOD(ha_segments_t, deactivate, void,
|
|||||||
enable_disable_all(this, segment, FALSE, 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)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
METHOD(ha_segments_t, resync, void,
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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 (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);
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list->destroy(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
METHOD(listener_t, alert_hook, bool,
|
METHOD(listener_t, alert_hook, bool,
|
||||||
private_ha_segments_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args)
|
private_ha_segments_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args)
|
||||||
{
|
{
|
||||||
if (alert == ALERT_SHUTDOWN_SIGNAL)
|
if (alert == ALERT_SHUTDOWN_SIGNAL)
|
||||||
{
|
{
|
||||||
deactivate(this, 0, TRUE);
|
if (this->job)
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, "HA heartbeat active, dropping all segments");
|
||||||
|
deactivate(this, 0, TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, "no HA heartbeat active, closing IKE_SAs");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 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;
|
|
||||||
|
|
||||||
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);
|
|
||||||
return JOB_REQUEUE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Monitor heartbeat activity of remote node
|
* Monitor heartbeat activity of remote node
|
||||||
*/
|
*/
|
||||||
@@ -422,6 +332,7 @@ static job_requeue_t send_status(private_ha_segments_t *this)
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->socket->push(this->socket, message);
|
this->socket->push(this->socket, message);
|
||||||
|
message->destroy(message);
|
||||||
|
|
||||||
/* schedule next invocation */
|
/* schedule next invocation */
|
||||||
charon->scheduler->schedule_job_ms(charon->scheduler, (job_t*)
|
charon->scheduler->schedule_job_ms(charon->scheduler, (job_t*)
|
||||||
@@ -449,7 +360,7 @@ METHOD(ha_segments_t, destroy, void,
|
|||||||
*/
|
*/
|
||||||
ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
|
ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
|
||||||
ha_tunnel_t *tunnel, u_int count, u_int node,
|
ha_tunnel_t *tunnel, u_int count, u_int node,
|
||||||
bool monitor, bool sync)
|
bool monitor)
|
||||||
{
|
{
|
||||||
private_ha_segments_t *this;
|
private_ha_segments_t *this;
|
||||||
|
|
||||||
@@ -458,7 +369,6 @@ ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
|
|||||||
.listener.alert = _alert_hook,
|
.listener.alert = _alert_hook,
|
||||||
.activate = _activate,
|
.activate = _activate,
|
||||||
.deactivate = _deactivate,
|
.deactivate = _deactivate,
|
||||||
.resync = _resync,
|
|
||||||
.handle_status = _handle_status,
|
.handle_status = _handle_status,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
@@ -477,14 +387,6 @@ ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
|
|||||||
start_watchdog(this);
|
start_watchdog(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
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), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,18 +67,6 @@ struct ha_segments_t {
|
|||||||
*/
|
*/
|
||||||
void (*deactivate)(ha_segments_t *this, u_int segment, bool notify);
|
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.
|
|
||||||
*
|
|
||||||
* @param segment segment to resync
|
|
||||||
*/
|
|
||||||
void (*resync)(ha_segments_t *this, u_int segment);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a status message from the remote node.
|
* Handle a status message from the remote node.
|
||||||
*
|
*
|
||||||
@@ -101,11 +89,10 @@ struct ha_segments_t {
|
|||||||
* @param count number of segments the cluster uses
|
* @param count number of segments the cluster uses
|
||||||
* @param node node, currently 1 or 0
|
* @param node node, currently 1 or 0
|
||||||
* @param monitor should we use monitoring functionality
|
* @param monitor should we use monitoring functionality
|
||||||
* @param resync request a complete resync on startup
|
|
||||||
* @return segment object
|
* @return segment object
|
||||||
*/
|
*/
|
||||||
ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
|
ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
|
||||||
ha_tunnel_t *tunnel, u_int count, u_int node,
|
ha_tunnel_t *tunnel, u_int count, u_int node,
|
||||||
bool monitor, bool resync);
|
bool monitor);
|
||||||
|
|
||||||
#endif /** HA_SEGMENTS_ @}*/
|
#endif /** HA_SEGMENTS_ @}*/
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ struct private_ha_socket_t {
|
|||||||
* Data to pass to the send_message() callback job
|
* Data to pass to the send_message() callback job
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ha_message_t *message;
|
chunk_t chunk;
|
||||||
private_ha_socket_t *this;
|
int fd;
|
||||||
} job_data_t;
|
} job_data_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,7 +67,7 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
static void job_data_destroy(job_data_t *this)
|
static void job_data_destroy(job_data_t *this)
|
||||||
{
|
{
|
||||||
this->message->destroy(this->message);
|
free(this->chunk.ptr);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,12 +76,7 @@ static void job_data_destroy(job_data_t *this)
|
|||||||
*/
|
*/
|
||||||
static job_requeue_t send_message(job_data_t *data)
|
static job_requeue_t send_message(job_data_t *data)
|
||||||
{
|
{
|
||||||
private_ha_socket_t *this;
|
if (send(data->fd, data->chunk.ptr, data->chunk.len, 0) < data->chunk.len)
|
||||||
chunk_t chunk;
|
|
||||||
|
|
||||||
this = data->this;
|
|
||||||
chunk = data->message->get_encoding(data->message);
|
|
||||||
if (send(this->fd, chunk.ptr, chunk.len, 0) < chunk.len)
|
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "pushing HA message failed: %s", strerror(errno));
|
DBG1(DBG_CFG, "pushing HA message failed: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
@@ -105,9 +100,10 @@ METHOD(ha_socket_t, push, void,
|
|||||||
/* Fallback to asynchronous transmission. This is required, as sendto()
|
/* Fallback to asynchronous transmission. This is required, as sendto()
|
||||||
* is a blocking call if it acquires a policy. We could end up in a
|
* is a blocking call if it acquires a policy. We could end up in a
|
||||||
* deadlock, as we own an IKE_SA. */
|
* deadlock, as we own an IKE_SA. */
|
||||||
data = malloc_thing(job_data_t);
|
INIT(data,
|
||||||
data->message = message;
|
.chunk = chunk_clone(chunk),
|
||||||
data->this = this;
|
.fd = this->fd,
|
||||||
|
);
|
||||||
|
|
||||||
job = callback_job_create((callback_job_cb_t)send_message,
|
job = callback_job_create((callback_job_cb_t)send_message,
|
||||||
data, (void*)job_data_destroy, NULL);
|
data, (void*)job_data_destroy, NULL);
|
||||||
@@ -116,7 +112,6 @@ METHOD(ha_socket_t, push, void,
|
|||||||
}
|
}
|
||||||
DBG1(DBG_CFG, "pushing HA message failed: %s", strerror(errno));
|
DBG1(DBG_CFG, "pushing HA message failed: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
message->destroy(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(ha_socket_t, pull, ha_message_t*,
|
METHOD(ha_socket_t, pull, ha_message_t*,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ struct ha_socket_t {
|
|||||||
/**
|
/**
|
||||||
* Push synchronization information to the responsible node.
|
* 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);
|
void (*push)(ha_socket_t *this, ha_message_t *message);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user