aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon/tests/utils/mock_ipsec.c
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2017-05-23 18:49:13 +0200
committerTobias Brunner <tobias@strongswan.org>2017-05-23 18:49:13 +0200
commitf8eb636e701cc66198bfab9e601842273b038219 (patch)
tree4e4d7b800c93c1c479f153784a996a434f192d7c /src/libcharon/tests/utils/mock_ipsec.c
parent4cc77142e0292d5d00f20e62849139f4401895c8 (diff)
parent10c7a668067b2657e8dffef70812d81b6408f12c (diff)
downloadstrongswan-f8eb636e701cc66198bfab9e601842273b038219.tar.bz2
strongswan-f8eb636e701cc66198bfab9e601842273b038219.tar.xz
Merge branch 'avoid-rekey-loss'
This changes the behavior during IKEv2 CHILD_SA rekeyings to avoid traffic loss. When responding to a CREATE_CHILD_SA request to rekey a CHILD_SA the responder already has everything available to install and use the new CHILD_SA. However, this could lead to lost traffic as the initiator won't be able to process inbound packets until it processed the CREATE_CHILD_SA response and updated the inbound SA. To avoid this the responder now only installs the new inbound SA and delays installing the outbound SA until it receives the DELETE for the replaced CHILD_SA. The messages transporting these DELETEs could reach the peer before packets sent with the deleted outbound SAs reach the respective peer. To reduce the chance of traffic loss due to this the inbound SA of the replaced CHILD_SA is not removed for a configurable amount of seconds after the DELETE has been processed. Fixes #1291.
Diffstat (limited to 'src/libcharon/tests/utils/mock_ipsec.c')
-rw-r--r--src/libcharon/tests/utils/mock_ipsec.c171
1 files changed, 169 insertions, 2 deletions
diff --git a/src/libcharon/tests/utils/mock_ipsec.c b/src/libcharon/tests/utils/mock_ipsec.c
index d57a26a87..68daaac32 100644
--- a/src/libcharon/tests/utils/mock_ipsec.c
+++ b/src/libcharon/tests/utils/mock_ipsec.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Tobias Brunner
+ * Copyright (C) 2016-2017 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* HSR Hochschule fuer Technik Rapperswil
*
@@ -16,6 +16,12 @@
#include "mock_ipsec.h"
+#include <daemon.h>
+#include <collections/hashtable.h>
+#include <collections/array.h>
+
+#include <assert.h>
+
typedef struct private_kernel_ipsec_t private_kernel_ipsec_t;
/**
@@ -29,16 +35,80 @@ struct private_kernel_ipsec_t {
kernel_ipsec_t public;
/**
+ * Rekey listener
+ */
+ listener_t listener;
+
+ /**
* Allocated SPI
*/
refcount_t spi;
+
+ /**
+ * Installed SAs
+ */
+ hashtable_t *sas;
};
+/**
+ * Global instance
+ */
+static private_kernel_ipsec_t *instance;
+
+/**
+ * Data about installed IPsec SAs
+ */
+typedef struct {
+ /**
+ * SPI of the SA
+ */
+ uint32_t spi;
+
+ /**
+ * Associated IKE_SA
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * TRUE if this was an allocated SPI
+ */
+ bool alloc;
+
+} entry_t;
+
+/**
+ * Hash an IPsec SA entry
+ */
+static u_int entry_hash(const void *key)
+{
+ entry_t *entry = (entry_t*)key;
+ return chunk_hash_inc(chunk_from_thing(entry->spi),
+ chunk_hash(chunk_from_thing(entry->ike_sa)));
+}
+
+/**
+ * Compare an IPsec SA entry
+ */
+static bool entry_equals(const void *key, const void *other_key)
+{
+ entry_t *a = (entry_t*)key, *b = (entry_t*)other_key;
+ return a->spi == b->spi && a->ike_sa == b->ike_sa;
+}
+
METHOD(kernel_ipsec_t, get_spi, status_t,
private_kernel_ipsec_t *this, host_t *src, host_t *dst, uint8_t protocol,
uint32_t *spi)
{
+ entry_t *entry;
+
*spi = (uint32_t)ref_get(&this->spi);
+ INIT(entry,
+ .spi = *spi,
+ .ike_sa = charon->bus->get_sa(charon->bus),
+ .alloc = TRUE,
+ );
+ entry = this->sas->put(this->sas, entry, entry);
+ assert(!entry);
return SUCCESS;
}
@@ -52,6 +122,23 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
private_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
kernel_ipsec_add_sa_t *data)
{
+ entry_t *entry;
+
+ INIT(entry,
+ .spi = id->spi,
+ .ike_sa = charon->bus->get_sa(charon->bus),
+ );
+ if (data->inbound)
+ {
+ entry = this->sas->put(this->sas, entry, entry);
+ assert(entry && entry->alloc);
+ free(entry);
+ }
+ else
+ {
+ entry = this->sas->put(this->sas, entry, entry);
+ assert(!entry);
+ }
return SUCCESS;
}
@@ -74,9 +161,47 @@ METHOD(kernel_ipsec_t, del_sa, status_t,
private_kernel_ipsec_t *this, kernel_ipsec_sa_id_t *id,
kernel_ipsec_del_sa_t *data)
{
+ entry_t *entry, lookup = {
+ .spi = id->spi,
+ .ike_sa = charon->bus->get_sa(charon->bus),
+ };
+
+ entry = this->sas->remove(this->sas, &lookup);
+ assert(entry);
+ free(entry);
return SUCCESS;
}
+METHOD(listener_t, ike_rekey, bool,
+ listener_t *listener, ike_sa_t *old, ike_sa_t *new)
+{
+ enumerator_t *enumerator;
+ array_t *sas = NULL;
+ entry_t *entry;
+
+ enumerator = instance->sas->create_enumerator(instance->sas);
+ while (enumerator->enumerate(enumerator, &entry, NULL))
+ {
+ if (entry->ike_sa == old)
+ {
+ instance->sas->remove_at(instance->sas, enumerator);
+ array_insert_create(&sas, ARRAY_TAIL, entry);
+ }
+ }
+ enumerator->destroy(enumerator);
+ enumerator = array_create_enumerator(sas);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ array_remove_at(sas, enumerator);
+ entry->ike_sa = new;
+ entry = instance->sas->put(instance->sas, entry, entry);
+ assert(!entry);
+ }
+ enumerator->destroy(enumerator);
+ array_destroy(sas);
+ return TRUE;
+}
+
METHOD(kernel_ipsec_t, add_policy, status_t,
private_kernel_ipsec_t *this, kernel_ipsec_policy_id_t *id,
kernel_ipsec_manage_policy_t *data)
@@ -99,6 +224,14 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
return SUCCESS;
}
+METHOD(kernel_ipsec_t, destroy, void,
+ private_kernel_ipsec_t *this)
+{
+ charon->bus->remove_listener(charon->bus, &this->listener);
+ this->sas->destroy(this->sas);
+ free(this);
+}
+
/*
* Described in header
*/
@@ -121,8 +254,42 @@ kernel_ipsec_t *mock_ipsec_create()
.flush_policies = (void*)return_failed,
.bypass_socket = (void*)return_true,
.enable_udp_decap = (void*)return_true,
- .destroy = (void*)free,
+ .destroy = _destroy,
},
+ .listener = {
+ .ike_rekey = _ike_rekey,
+ },
+ .sas = hashtable_create(entry_hash, entry_equals, 8),
);
+
+ instance = this;
+
+ charon->bus->add_listener(charon->bus, &this->listener);
+
return &this->public;
}
+
+/**
+ * Filter SAs
+ */
+static bool filter_sas(void *data, entry_t **entry, ike_sa_t **ike_sa,
+ void *unused, uint32_t *spi)
+{
+ if ((*entry)->alloc)
+ {
+ return FALSE;
+ }
+ *ike_sa = (*entry)->ike_sa;
+ *spi = (*entry)->spi;
+ return TRUE;
+}
+
+/*
+ * Described in header
+ */
+enumerator_t *mock_ipsec_create_sa_enumerator()
+{
+ return enumerator_create_filter(
+ instance->sas->create_enumerator(instance->sas),
+ (void*)filter_sas, NULL, NULL);
+}