Merge branch 'make-before-break'

Introduce an alternative make-before-break reauthentication scheme in addition
to the traditional break-before-make.
This commit is contained in:
Martin Willi
2015-02-20 13:34:58 +01:00
47 changed files with 597 additions and 99 deletions
+9
View File
@@ -1,3 +1,12 @@
- Added support for IKEv2 make-before-break reauthentication. By using a global
CHILD_SA reqid allocation mechanism, charon supports overlapping CHILD_SAs.
This allows the use of make-before-break instead of the previously supported
break-before-make reauthentication, avoiding connectivity gaps during that
procedure. As the new mechanism may fail with peers not supporting it (such
as any previous strongSwan release) it must be explicitly enabled using
the charon.make_before_break strongswan.conf option.
strongswan-5.2.2
----------------
+9 -3
View File
@@ -196,9 +196,15 @@ charon.load_modular = no
charon.max_packet = 10000
Maximum packet size accepted by charon.
charon.mem-pool.reassign_online = no
Reassign an online IP address lease from an in-memory address pool if a
client with the same identity requests it explicitly.
charon.make_before_break = no
Initiate IKEv2 reauthentication with a make-before-break scheme.
Initiate IKEv2 reauthentication with a make-before-break instead of a
break-before-make scheme. Make-before-break uses overlapping IKE and
CHILD_SA during reauthentication by first recreating all new SAs before
deleting the old ones. This behavior can be beneficial to avoid connectivity
gaps during reauthentication, but requires support for overlapping SAs by
the peer. strongSwan can handle such overlapping SAs since version 5.3.0.
charon.multiple_authentication = yes
Enable multiple authentication exchanges (RFC 4739).
+1
View File
@@ -102,6 +102,7 @@ sa/ikev2/tasks/ike_natd.c sa/ikev2/tasks/ike_natd.h \
sa/ikev2/tasks/ike_mobike.c sa/ikev2/tasks/ike_mobike.h \
sa/ikev2/tasks/ike_rekey.c sa/ikev2/tasks/ike_rekey.h \
sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \
sa/ikev2/tasks/ike_reauth_complete.c sa/ikev2/tasks/ike_reauth_complete.h \
sa/ikev2/tasks/ike_auth_lifetime.c sa/ikev2/tasks/ike_auth_lifetime.h \
sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h
+1
View File
@@ -101,6 +101,7 @@ sa/ikev2/tasks/ike_natd.c sa/ikev2/tasks/ike_natd.h \
sa/ikev2/tasks/ike_mobike.c sa/ikev2/tasks/ike_mobike.h \
sa/ikev2/tasks/ike_rekey.c sa/ikev2/tasks/ike_rekey.h \
sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \
sa/ikev2/tasks/ike_reauth_complete.c sa/ikev2/tasks/ike_reauth_complete.h \
sa/ikev2/tasks/ike_auth_lifetime.c sa/ikev2/tasks/ike_auth_lifetime.h \
sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h
endif
+60 -36
View File
@@ -70,20 +70,25 @@ struct private_mem_pool_t {
* lock to safely access the pool
*/
mutex_t *mutex;
/**
* Do we reassign online leases to the same identity, if requested?
*/
bool reassign_online;
};
/**
* A unique lease address offset, with a hash of the peer host address
*/
typedef struct {
/** lease, as offset */
u_int offset;
/** hash of remote address, to allow duplicates */
u_int hash;
} unique_lease_t;
/**
* Lease entry.
*/
typedef struct {
/* identitiy reference */
identification_t *id;
/* array of online leases, as u_int offset */
/* array of online leases, as unique_lease_t */
array_t *online;
/* array of offline leases, as u_int offset */
array_t *offline;
@@ -98,7 +103,7 @@ static entry_t* entry_create(identification_t *id)
INIT(entry,
.id = id->clone(id),
.online = array_create(sizeof(u_int), 0),
.online = array_create(sizeof(unique_lease_t), 0),
.offline = array_create(sizeof(u_int), 0),
);
return entry;
@@ -239,13 +244,26 @@ METHOD(mem_pool_t, get_offline, u_int,
return count;
}
/**
* Create a unique hash for a remote address
*/
static u_int hash_addr(host_t *addr)
{
if (addr)
{
return chunk_hash_inc(addr->get_address(addr), addr->get_port(addr));
}
return 0;
}
/**
* Get an existing lease for id
*/
static int get_existing(private_mem_pool_t *this, identification_t *id,
host_t *requested)
host_t *requested, host_t *peer)
{
enumerator_t *enumerator;
unique_lease_t *lease, reassign;
u_int *current;
entry_t *entry;
int offset = 0;
@@ -260,8 +278,9 @@ static int get_existing(private_mem_pool_t *this, identification_t *id,
enumerator = array_create_enumerator(entry->offline);
if (enumerator->enumerate(enumerator, &current))
{
offset = *current;
array_insert(entry->online, ARRAY_TAIL, current);
reassign.offset = offset = *current;
reassign.hash = hash_addr(peer);
array_insert(entry->online, ARRAY_TAIL, &reassign);
array_remove_at(entry->offline, enumerator);
}
enumerator->destroy(enumerator);
@@ -270,19 +289,20 @@ static int get_existing(private_mem_pool_t *this, identification_t *id,
DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id);
return offset;
}
if (!this->reassign_online)
if (!peer)
{
return 0;
}
/* check for a valid online lease to reassign */
enumerator = array_create_enumerator(entry->online);
while (enumerator->enumerate(enumerator, &current))
while (enumerator->enumerate(enumerator, &lease))
{
if (*current == host2offset(this, requested))
if (lease->offset == host2offset(this, requested) &&
lease->hash == hash_addr(peer))
{
offset = *current;
offset = lease->offset;
/* add an additional "online" entry */
array_insert(entry->online, ARRAY_TAIL, current);
array_insert(entry->online, ARRAY_TAIL, lease);
break;
}
}
@@ -297,10 +317,10 @@ static int get_existing(private_mem_pool_t *this, identification_t *id,
/**
* Get a new lease for id
*/
static int get_new(private_mem_pool_t *this, identification_t *id)
static int get_new(private_mem_pool_t *this, identification_t *id, host_t *peer)
{
entry_t *entry;
u_int offset = 0;
unique_lease_t lease = {};
if (this->unused < this->size)
{
@@ -311,28 +331,31 @@ static int get_new(private_mem_pool_t *this, identification_t *id)
this->leases->put(this->leases, entry->id, entry);
}
/* assigning offset, starting by 1 */
offset = ++this->unused + (this->base_is_network_id ? 1 : 0);
array_insert(entry->online, ARRAY_TAIL, &offset);
lease.offset = ++this->unused + (this->base_is_network_id ? 1 : 0);
lease.hash = hash_addr(peer);
array_insert(entry->online, ARRAY_TAIL, &lease);
DBG1(DBG_CFG, "assigning new lease to '%Y'", id);
}
return offset;
return lease.offset;
}
/**
* Get a reassigned lease for id in case the pool is full
*/
static int get_reassigned(private_mem_pool_t *this, identification_t *id)
static int get_reassigned(private_mem_pool_t *this, identification_t *id,
host_t *peer)
{
enumerator_t *enumerator;
entry_t *entry;
u_int current, offset = 0;
u_int current;
unique_lease_t lease = {};
enumerator = this->leases->create_enumerator(this->leases);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
if (array_remove(entry->offline, ARRAY_HEAD, &current))
{
offset = current;
lease.offset = current;
DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'"
" to '%Y'", entry->id, id);
break;
@@ -340,7 +363,7 @@ static int get_reassigned(private_mem_pool_t *this, identification_t *id)
}
enumerator->destroy(enumerator);
if (offset)
if (lease.offset)
{
entry = this->leases->get(this->leases, id);
if (!entry)
@@ -348,14 +371,15 @@ static int get_reassigned(private_mem_pool_t *this, identification_t *id)
entry = entry_create(id);
this->leases->put(this->leases, entry->id, entry);
}
array_insert(entry->online, ARRAY_TAIL, &offset);
lease.hash = hash_addr(peer);
array_insert(entry->online, ARRAY_TAIL, &lease);
}
return offset;
return lease.offset;
}
METHOD(mem_pool_t, acquire_address, host_t*,
private_mem_pool_t *this, identification_t *id, host_t *requested,
mem_pool_op_t operation)
mem_pool_op_t operation, host_t *peer)
{
int offset = 0;
@@ -376,13 +400,13 @@ METHOD(mem_pool_t, acquire_address, host_t*,
switch (operation)
{
case MEM_POOL_EXISTING:
offset = get_existing(this, id, requested);
offset = get_existing(this, id, requested, peer);
break;
case MEM_POOL_NEW:
offset = get_new(this, id);
offset = get_new(this, id, peer);
break;
case MEM_POOL_REASSIGN:
offset = get_reassigned(this, id);
offset = get_reassigned(this, id, peer);
if (!offset)
{
DBG1(DBG_CFG, "pool '%s' is full, unable to assign address",
@@ -407,7 +431,8 @@ METHOD(mem_pool_t, release_address, bool,
enumerator_t *enumerator;
bool found = FALSE, more = FALSE;
entry_t *entry;
u_int offset, *current;
u_int offset;
unique_lease_t *current;
if (this->size != 0)
{
@@ -420,7 +445,7 @@ METHOD(mem_pool_t, release_address, bool,
enumerator = array_create_enumerator(entry->online);
while (enumerator->enumerate(enumerator, &current))
{
if (*current == offset)
if (current->offset == offset)
{
if (!found)
{ /* remove the first entry only */
@@ -472,6 +497,7 @@ METHOD(enumerator_t, lease_enumerate, bool,
lease_enumerator_t *this, identification_t **id, host_t **addr, bool *online)
{
u_int *offset;
unique_lease_t *lease;
DESTROY_IF(this->addr);
this->addr = NULL;
@@ -480,10 +506,10 @@ METHOD(enumerator_t, lease_enumerate, bool,
{
if (this->entry)
{
if (this->online->enumerate(this->online, &offset))
if (this->online->enumerate(this->online, &lease))
{
*id = this->entry->id;
*addr = this->addr = offset2host(this->pool, *offset);
*addr = this->addr = offset2host(this->pool, lease->offset);
*online = TRUE;
return TRUE;
}
@@ -581,8 +607,6 @@ static private_mem_pool_t *create_generic(char *name)
.leases = hashtable_create((hashtable_hash_t)id_hash,
(hashtable_equals_t)id_equals, 16),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
.reassign_online = lib->settings->get_bool(lib->settings,
"%s.mem-pool.reassign_online", FALSE, lib->ns),
);
return this;
+9 -1
View File
@@ -87,13 +87,21 @@ struct mem_pool_t {
* acquire a new lease (MEM_POOL_NEW), and if the pool is full once again
* to assign an existing offline lease (MEM_POOL_REASSIGN).
*
* If the same identity requests a virtual IP that is already assigned to
* it, the peer address and port is used to check if it is the same client
* instance that is connecting. If this is true, the request is considered
* a request for a reauthentication attempt, and the same virtual IP gets
* assigned to the peer.
*
* @param id the id to acquire an address for
* @param requested acquire this address, if possible
* @param operation acquire operation to perform, see above
* @param peer optional remote IKE address and port
* @return the acquired address
*/
host_t* (*acquire_address)(mem_pool_t *this, identification_t *id,
host_t *requested, mem_pool_op_t operation);
host_t *requested, mem_pool_op_t operation,
host_t *peer);
/**
* Release a previously acquired address.
@@ -618,7 +618,7 @@ static host_t *allocate_addr(private_load_tester_config_t *this, uint num)
enumerator = this->pools->create_enumerator(this->pools);
while (enumerator->enumerate(enumerator, &pool))
{
found = pool->acquire_address(pool, id, requested, MEM_POOL_NEW);
found = pool->acquire_address(pool, id, requested, MEM_POOL_NEW, NULL);
if (found)
{
iface = (char*)pool->get_name(pool);
@@ -94,7 +94,7 @@ static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name)
*/
static host_t *find_addr(private_stroke_attribute_t *this, linked_list_t *pools,
identification_t *id, host_t *requested,
mem_pool_op_t operation)
mem_pool_op_t operation, host_t *peer)
{
host_t *addr = NULL;
enumerator_t *enumerator;
@@ -107,7 +107,7 @@ static host_t *find_addr(private_stroke_attribute_t *this, linked_list_t *pools,
pool = find_pool(this, name);
if (pool)
{
addr = pool->acquire_address(pool, id, requested, operation);
addr = pool->acquire_address(pool, id, requested, operation, peer);
if (addr)
{
break;
@@ -124,19 +124,20 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
host_t *requested)
{
identification_t *id;
host_t *addr;
host_t *addr, *peer;
id = ike_sa->get_other_eap_id(ike_sa);
peer = ike_sa->get_other_host(ike_sa);
this->lock->read_lock(this->lock);
addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING);
addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING, peer);
if (!addr)
{
addr = find_addr(this, pools, id, requested, MEM_POOL_NEW);
addr = find_addr(this, pools, id, requested, MEM_POOL_NEW, peer);
if (!addr)
{
addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN);
addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN, peer);
}
}
+9 -6
View File
@@ -96,7 +96,8 @@ static void pool_destroy(pool_t *pool)
* Find an existing or not yet existing lease
*/
static host_t *find_addr(private_vici_attribute_t *this, linked_list_t *pools,
identification_t *id, host_t *requested, mem_pool_op_t op)
identification_t *id, host_t *requested,
mem_pool_op_t op, host_t *peer)
{
enumerator_t *enumerator;
host_t *addr = NULL;
@@ -109,7 +110,8 @@ static host_t *find_addr(private_vici_attribute_t *this, linked_list_t *pools,
pool = this->pools->get(this->pools, name);
if (pool)
{
addr = pool->vips->acquire_address(pool->vips, id, requested, op);
addr = pool->vips->acquire_address(pool->vips, id, requested,
op, peer);
if (addr)
{
break;
@@ -126,19 +128,20 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
host_t *requested)
{
identification_t *id;
host_t *addr;
host_t *addr, *peer;
id = ike_sa->get_other_eap_id(ike_sa);
peer = ike_sa->get_other_host(ike_sa);
this->lock->read_lock(this->lock);
addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING);
addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING, peer);
if (!addr)
{
addr = find_addr(this, pools, id, requested, MEM_POOL_NEW);
addr = find_addr(this, pools, id, requested, MEM_POOL_NEW, peer);
if (!addr)
{
addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN);
addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN, peer);
}
}
+3 -2
View File
@@ -936,8 +936,9 @@ struct ike_sa_t {
/**
* Reauthenticate the IKE_SA.
*
* Create a completely new IKE_SA with authentication, recreates all children
* within the IKE_SA, closes this IKE_SA.
* Triggers a new IKE_SA that replaces this one. IKEv1 implicitly inherits
* all Quick Modes, while IKEv2 recreates all active and queued CHILD_SAs
* in the new IKE_SA.
*
* @return DESTROY_ME to destroy the IKE_SA
*/
+8 -12
View File
@@ -1743,15 +1743,6 @@ static void adopt_children(ike_sa_t *old, ike_sa_t *new)
enumerator->destroy(enumerator);
}
/**
* Check if the replaced IKE_SA might get reauthenticated from host
*/
static bool is_ikev1_reauth(ike_sa_t *duplicate, host_t *host)
{
return duplicate->get_version(duplicate) == IKEV1 &&
host->equals(host, duplicate->get_other_host(duplicate));
}
/**
* Delete an existing IKE_SA due to a unique replace policy
*/
@@ -1761,16 +1752,19 @@ static status_t enforce_replace(private_ike_sa_manager_t *this,
{
charon->bus->alert(charon->bus, ALERT_UNIQUE_REPLACE);
if (is_ikev1_reauth(duplicate, host))
if (host->equals(host, duplicate->get_other_host(duplicate)))
{
/* looks like a reauthentication attempt */
if (!new->has_condition(new, COND_INIT_CONTACT_SEEN))
{
/* IKEv1 implicitly takes over children, IKEv2 recreates them
* explicitly. */
adopt_children(duplicate, new);
}
/* For IKEv1 we have to delay the delete for the old IKE_SA. Some
* peers need to complete the new SA first, otherwise the quick modes
* might get lost. */
* might get lost. For IKEv2 we do the same, as we want overlapping
* CHILD_SAs to keep connectivity up. */
lib->scheduler->schedule_job(lib->scheduler, (job_t*)
delete_ike_sa_job_create(duplicate->get_id(duplicate), TRUE), 10);
return SUCCESS;
@@ -1835,7 +1829,9 @@ METHOD(ike_sa_manager_t, check_uniqueness, bool,
other, other_host);
break;
case UNIQUE_KEEP:
if (!is_ikev1_reauth(duplicate, other_host))
/* potential reauthentication? */
if (!other_host->equals(other_host,
duplicate->get_other_host(duplicate)))
{
cancel = TRUE;
/* we keep the first IKE_SA and delete all
+89
View File
@@ -29,6 +29,7 @@
#include <sa/ikev2/tasks/ike_cert_post.h>
#include <sa/ikev2/tasks/ike_rekey.h>
#include <sa/ikev2/tasks/ike_reauth.h>
#include <sa/ikev2/tasks/ike_reauth_complete.h>
#include <sa/ikev2/tasks/ike_delete.h>
#include <sa/ikev2/tasks/ike_config.h>
#include <sa/ikev2/tasks/ike_dpd.h>
@@ -171,6 +172,11 @@ struct private_task_manager_t {
* Base to calculate retransmission timeout
*/
double retransmit_base;
/**
* Use make-before-break instead of break-before-make reauth?
*/
bool make_before_break;
};
/**
@@ -510,6 +516,11 @@ METHOD(task_manager_t, initiate, status_t,
break;
}
#endif /* ME */
if (activate_task(this, TASK_IKE_REAUTH_COMPLETE))
{
exchange = INFORMATIONAL;
break;
}
case IKE_REKEYING:
if (activate_task(this, TASK_IKE_DELETE))
{
@@ -604,6 +615,11 @@ METHOD(task_manager_t, initiate, status_t,
/* update exchange type if a task changed it */
this->initiating.type = message->get_exchange_type(message);
if (this->initiating.type == EXCHANGE_TYPE_UNDEFINED)
{
message->destroy(message);
return SUCCESS;
}
if (!generate_message(this, message, &this->initiating.packets))
{
@@ -1505,9 +1521,80 @@ METHOD(task_manager_t, queue_ike_rekey, void,
queue_task(this, (task_t*)ike_rekey_create(this->ike_sa, TRUE));
}
/**
* Start reauthentication using make-before-break
*/
static void trigger_mbb_reauth(private_task_manager_t *this)
{
enumerator_t *enumerator;
child_sa_t *child_sa;
child_cfg_t *cfg;
ike_sa_t *new;
host_t *host;
task_t *task;
new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
this->ike_sa->get_version(this->ike_sa), TRUE);
if (!new)
{ /* shouldn't happen */
return;
}
new->set_peer_cfg(new, this->ike_sa->get_peer_cfg(this->ike_sa));
host = this->ike_sa->get_other_host(this->ike_sa);
new->set_other_host(new, host->clone(host));
host = this->ike_sa->get_my_host(this->ike_sa);
new->set_my_host(new, host->clone(host));
enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa, TRUE);
while (enumerator->enumerate(enumerator, &host))
{
new->add_virtual_ip(new, TRUE, host);
}
enumerator->destroy(enumerator);
enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
while (enumerator->enumerate(enumerator, &child_sa))
{
cfg = child_sa->get_config(child_sa);
new->queue_task(new, &child_create_create(new, cfg->get_ref(cfg),
FALSE, NULL, NULL)->task);
}
enumerator->destroy(enumerator);
enumerator = array_create_enumerator(this->queued_tasks);
while (enumerator->enumerate(enumerator, &task))
{
if (task->get_type(task) == TASK_CHILD_CREATE)
{
task->migrate(task, new);
new->queue_task(new, task);
array_remove_at(this->queued_tasks, enumerator);
}
}
enumerator->destroy(enumerator);
if (new->initiate(new, NULL, 0, NULL, NULL) != DESTROY_ME)
{
new->queue_task(new, (task_t*)ike_reauth_complete_create(new,
this->ike_sa->get_id(this->ike_sa)));
charon->ike_sa_manager->checkin(charon->ike_sa_manager, new);
this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
}
else
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new);
DBG1(DBG_IKE, "reauthenticating IKE_SA failed");
}
charon->bus->set_sa(charon->bus, this->ike_sa);
}
METHOD(task_manager_t, queue_ike_reauth, void,
private_task_manager_t *this)
{
if (this->make_before_break)
{
return trigger_mbb_reauth(this);
}
queue_task(this, (task_t*)ike_reauth_create(this->ike_sa));
}
@@ -1773,6 +1860,8 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
"%s.retransmit_timeout", RETRANSMIT_TIMEOUT, lib->ns),
.retransmit_base = lib->settings->get_double(lib->settings,
"%s.retransmit_base", RETRANSMIT_BASE, lib->ns),
.make_before_break = lib->settings->get_bool(lib->settings,
"%s.make_before_break", FALSE, lib->ns),
);
return &this->public;
@@ -29,6 +29,8 @@ typedef struct ike_reauth_t ike_reauth_t;
/**
* Task of type ike_reauth, reestablishes an IKE_SA.
*
* This task implements break-before-make reauthentication.
*/
struct ike_reauth_t {
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 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 "ike_reauth_complete.h"
#include <daemon.h>
#include <processing/jobs/delete_ike_sa_job.h>
typedef struct private_ike_reauth_complete_t private_ike_reauth_complete_t;
/**
* Private members of a ike_reauth_complete_t task.
*/
struct private_ike_reauth_complete_t {
/**
* Public methods and task_t interface.
*/
ike_reauth_complete_t public;
/**
* Assigned IKE_SA.
*/
ike_sa_t *ike_sa;
/**
* Reauthenticated IKE_SA identifier
*/
ike_sa_id_t *id;
};
METHOD(task_t, build_i, status_t,
private_ike_reauth_complete_t *this, message_t *message)
{
message->set_exchange_type(message, EXCHANGE_TYPE_UNDEFINED);
lib->processor->queue_job(lib->processor,
(job_t*)delete_ike_sa_job_create(this->id, TRUE));
return SUCCESS;
}
METHOD(task_t, process_i, status_t,
private_ike_reauth_complete_t *this, message_t *message)
{
return DESTROY_ME;
}
METHOD(task_t, get_type, task_type_t,
private_ike_reauth_complete_t *this)
{
return TASK_IKE_REAUTH_COMPLETE;
}
METHOD(task_t, migrate, void,
private_ike_reauth_complete_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
}
METHOD(task_t, destroy, void,
private_ike_reauth_complete_t *this)
{
this->id->destroy(this->id);
free(this);
}
/*
* Described in header.
*/
ike_reauth_complete_t *ike_reauth_complete_create(ike_sa_t *ike_sa,
ike_sa_id_t *id)
{
private_ike_reauth_complete_t *this;
INIT(this,
.public = {
.task = {
.get_type = _get_type,
.migrate = _migrate,
.build = _build_i,
.process = _process_i,
.destroy = _destroy,
},
},
.ike_sa = ike_sa,
.id = id->clone(id),
);
return &this->public;
}
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 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 ike_reauth_complete ike_reauth_complete
* @{ @ingroup tasks_v2
*/
#ifndef IKE_REAUTH_COMPLETE_H_
#define IKE_REAUTH_COMPLETE_H_
typedef struct ike_reauth_complete_t ike_reauth_complete_t;
#include <library.h>
#include <sa/ike_sa.h>
#include <sa/task.h>
/**
* Task of type IKE_REAUTH_COMPLETE, removes reauthenticated SA after reauth.
*
* This task completes make-before-break reauthentication by deleting the
* old, reauthenticated IKE_SA after the new one established.
*/
struct ike_reauth_complete_t {
/**
* Implements the task_t interface
*/
task_t task;
};
/**
* Create a new ike_reauth_complete task.
*
* This task is initiator only.
*
* @param ike_sa IKE_SA this task works for
* @param id old, reauthenticated IKE_SA
* @return ike_reauth_complete task to handle by the task_manager
*/
ike_reauth_complete_t *ike_reauth_complete_create(ike_sa_t *ike_sa,
ike_sa_id_t *id);
#endif /** IKE_REAUTH_COMPLETE_H_ @}*/
+1
View File
@@ -27,6 +27,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_ISAKMP_CERT_POST,
"IKE_CONFIG",
"IKE_REKEY",
"IKE_REAUTH",
"IKE_REAUTH_COMPLETE",
"IKE_DELETE",
"IKE_DPD",
"IKE_VENDOR",
+3 -1
View File
@@ -53,8 +53,10 @@ enum task_type_t {
TASK_IKE_CONFIG,
/** rekey an IKE_SA */
TASK_IKE_REKEY,
/** reestablish a complete IKE_SA */
/** reestablish a complete IKE_SA, break-before-make */
TASK_IKE_REAUTH,
/** completion task for make-before-break IKE_SA re-authentication */
TASK_IKE_REAUTH_COMPLETE,
/** delete an IKE_SA */
TASK_IKE_DELETE,
/** liveness check */
+1 -1
View File
@@ -43,7 +43,7 @@ static void assert_acquire(mem_pool_t *pool, char *requested, char *expected,
id = identification_create_from_string("tester");
req = host_create_from_string(requested, 0);
acquired = pool->acquire_address(pool, id, req, operation);
acquired = pool->acquire_address(pool, id, req, operation, NULL);
assert_host(expected, acquired);
DESTROY_IF(acquired);
@@ -1,7 +1,7 @@
alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*[email protected]::YES
bob:: ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*[email protected]::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
bob:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
bob:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
alice::ping -c 1 PH_IP_SUN1::64 bytes from PH_IP_SUN1: icmp_req=1::YES
moon::tcpdump::IP moon.strongswan.org.* > sun.strongswan.org.4500: UDP::YES
moon::tcpdump::IP sun.strongswan.org.4500 > moon.strongswan.org.*: UDP::YES
+2 -2
View File
@@ -1,7 +1,7 @@
alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*[email protected]::YES
bob:: ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*[email protected]::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
bob:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
bob:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_req=1::YES
moon::tcpdump::IP moon.strongswan.org.* > sun.strongswan.org.4500: UDP::YES
moon::tcpdump::IP sun.strongswan.org.4500 > moon.strongswan.org.*: UDP::YES
+4 -4
View File
@@ -2,10 +2,10 @@ alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*sun.
venus::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*venus.strongswan.org.*sun.strongswan.org::YES
sun:: ipsec status 2> /dev/null::nat-t\[1]: ESTABLISHED.*sun.strongswan.org.*[email protected]::YES
sun:: ipsec status 2> /dev/null::nat-t\[2]: ESTABLISHED.*sun.strongswan.org.*venus.strongswan.org::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
venus::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
sun:: ipsec status 2> /dev/null::nat-t[{]1}.*INSTALLED, TUNNEL, ESP in UDP::YES
sun:: ipsec status 2> /dev/null::nat-t[{]2}.*INSTALLED, TUNNEL, ESP in UDP::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
venus::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
sun:: ipsec status 2> /dev/null::nat-t[{]1}.*INSTALLED, TUNNEL.*ESP in UDP::YES
sun:: ipsec status 2> /dev/null::nat-t[{]2}.*INSTALLED, TUNNEL.*ESP in UDP::YES
alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_req=1::YES
venus::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_req=1::YES
moon:: sleep 6::no output expected::NO
@@ -1,7 +1,7 @@
alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*[email protected]::YES
bob:: ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*[email protected]::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
bob:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
bob:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
alice::ping -c 1 PH_IP_SUN1::64 bytes from PH_IP_SUN1: icmp_req=1::YES
moon::tcpdump::IP moon.strongswan.org.* > sun.strongswan.org.4500: UDP::YES
moon::tcpdump::IP sun.strongswan.org.4500 > moon.strongswan.org.*: UDP::YES
+2 -2
View File
@@ -1,7 +1,7 @@
alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*[email protected]::YES
bob:: ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*[email protected]::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
bob:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
bob:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_req=1::YES
moon::tcpdump::IP moon.strongswan.org.* > sun.strongswan.org.4500: UDP::YES
moon::tcpdump::IP sun.strongswan.org.4500 > moon.strongswan.org.*: UDP::YES
@@ -9,5 +9,6 @@ rules that let pass the decrypted IP packets. In order to test the host-to-host
dropped when the IPsec policies are consulted (increases the <em>XfrmInTmplMismatch</em> counter
in <em>/proc/net/xfrm_stat</em>).</li>
<li>A similar issue arises when <b>venus</b> also establishes an IPsec <b>transport-mode</b> connection to
<b>sun</b>, due to the conflicting IPsec policies <b>sun</b> declines such a connection.</li>
<b>sun</b>. Due to the conflicting IPsec policies <b>sun</b> will use the newer SA from
<b>venus</b> to send traffic to the common transport mode address.</li>
</ol>
@@ -1,12 +1,9 @@
alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*sun.strongswan.org::YES
sun:: ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*sun.strongswan.org.*[email protected]::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TRANSPORT::YES
sun:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TRANSPORT::YES
alice::ping -c 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_req=1::YES
venus::ping -c 1 -W 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_req=1::NO
venus::ipsec up nat-t::received TS_UNACCEPTABLE notify::YES
sun::cat /var/log/daemon.log::unable to install policy::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TRANSPORT, reqid 1::YES
venus::ipsec status 2> /dev/null::nat-t.*INSTALLED, TRANSPORT, reqid 1::YES
sun:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TRANSPORT, reqid 1::YES
alice::ping -c 1 -W 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_req=1::NO
venus::ping -c 1 -W 1 PH_IP_SUN::64 bytes from PH_IP_SUN: icmp_req=1::YES
sun::tcpdump::IP moon.strongswan.org.* > sun.strongswan.org.*: UDP::YES
sun::tcpdump::IP sun.strongswan.org.* > moon.strongswan.org.*: UDP::YES
sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ICMP echo request::YES
sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ICMP echo reply::NO
@@ -10,3 +10,4 @@ sun::ipsec start
alice::expect-connection nat-t
venus::expect-connection nat-t
alice::ipsec up nat-t
venus::ipsec up nat-t
+2 -2
View File
@@ -1,7 +1,7 @@
alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*sun.strongswan.org::YES
venus::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*venus.strongswan.org.*sun.strongswan.org::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
venus::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
venus::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
sun:: ipsec status 2> /dev/null::alice.*ESTABLISHED.*sun.strongswan.org.*[email protected]::YES
sun:: ipsec status 2> /dev/null::venus.*ESTABLISHED.*sun.strongswan.org.*venus.strongswan.org::YES
sun:: ipsec statusall 2> /dev/null::alice.*10.2.0.0/16 === 10.1.0.0/25::YES
+3 -3
View File
@@ -1,6 +1,6 @@
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
venus::ipsec status 2> /dev/null::nat-t.*INSTALLED. TUNNEL, ESP in UDP::YES
sun:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
venus::ipsec status 2> /dev/null::nat-t.*INSTALLED. TUNNEL.*ESP in UDP::YES
sun:: ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
sun:: ipsec status 2> /dev/null::nat-t.*\[PH_IP_ALICE\]::YES
sun:: ipsec status 2> /dev/null::nat-t.*\[PH_IP_VENUS\]::YES
alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_req=1::YES
+4 -4
View File
@@ -2,10 +2,10 @@ alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*[email protected].*sun.
venus::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*venus.strongswan.org.*sun.strongswan.org::YES
sun:: ipsec status 2> /dev/null::nat-t\[1]: ESTABLISHED.*sun.strongswan.org.*[email protected]::YES
sun:: ipsec status 2> /dev/null::nat-t\[2]: ESTABLISHED.*sun.strongswan.org.*venus.strongswan.org::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
venus::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL, ESP in UDP::YES
sun:: ipsec status 2> /dev/null::nat-t[{]1}.*INSTALLED, TUNNEL, ESP in UDP::YES
sun:: ipsec status 2> /dev/null::nat-t[{]2}.*INSTALLED, TUNNEL, ESP in UDP::YES
alice::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
venus::ipsec status 2> /dev/null::nat-t.*INSTALLED, TUNNEL.*ESP in UDP::YES
sun:: ipsec status 2> /dev/null::nat-t[{]1}.*INSTALLED, TUNNEL.*ESP in UDP::YES
sun:: ipsec status 2> /dev/null::nat-t[{]2}.*INSTALLED, TUNNEL.*ESP in UDP::YES
alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_req=1::YES
venus::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_req=1::YES
moon:: sleep 6::no output expected::NO
@@ -0,0 +1,8 @@
This scenario tests <b>make-before-break reauthentication</b> using overlapping
IKE_SAs by setting the <i>make_before_break</i> strongswan.conf option for
clients using an assigned virtual IP. The initiator <b>carol</b> reauthenticates
the IKE_SA with host <b>moon</b> using <b>ikelifetime=10s</b>, but does not
close the old IKE_SA before the replacement CHILD_SA using the same virtual IP
is in place. A constant ping from <b>carol</b> to client <b>alice</b>
hiding in the subnet behind <b>moon</b> tests if the CHILD_SA works during the
whole procedure.
@@ -0,0 +1,7 @@
moon:: ipsec status 2> /dev/null::rw\[1]: ESTABLISHED.*moon.strongswan.org.*[email protected]::YES
carol::ipsec status 2> /dev/null::home\[1]: ESTABLISHED.*[email protected].*moon.strongswan.org::YES
carol::ping -c 8 PH_IP_ALICE::64 bytes from PH_IP_ALICE::YES
moon:: ipsec status 2> /dev/null::rw\[2]: ESTABLISHED.*moon.strongswan.org.*[email protected]::YES
carol::ipsec status 2> /dev/null::home\[2]: ESTABLISHED.*[email protected].*moon.strongswan.org::YES
moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
@@ -0,0 +1,22 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
keylife=20m
ikelifetime=10s
rekeymargin=5s
rekeyfuzz=0%
keyingtries=1
conn home
left=PH_IP_CAROL
leftcert=carolCert.pem
[email protected]
leftsourceip=%config
leftfirewall=yes
right=PH_IP_MOON
[email protected]
rightsubnet=10.1.0.0/16
keyexchange=ikev2
auto=add
@@ -0,0 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc stroke kernel-netlink socket-default updown
make_before_break = yes
}
@@ -0,0 +1,20 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=30m
keylife=20m
rekeymargin=0s
keyingtries=1
conn rw
left=PH_IP_MOON
leftcert=moonCert.pem
[email protected]
leftsubnet=10.1.0.0/16
leftfirewall=yes
right=%any
rightsourceip=10.3.0.0/24
keyexchange=ikev2
auto=add
@@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc stroke kernel-netlink socket-default updown
}
@@ -0,0 +1,4 @@
moon::ipsec stop
carol::ipsec stop
moon::iptables-restore < /etc/iptables.flush
carol::iptables-restore < /etc/iptables.flush
@@ -0,0 +1,6 @@
moon::iptables-restore < /etc/iptables.rules
carol::iptables-restore < /etc/iptables.rules
moon::ipsec start
carol::ipsec start
carol::sleep 1
carol::ipsec up home
@@ -0,0 +1,21 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice moon carol winnetou"
# Corresponding block diagram
#
DIAGRAM="a-m-c-w.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="moon"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon carol"
@@ -0,0 +1,7 @@
This scenario tests <b>make-before-break reauthentication</b> using overlapping
IKE_SAs by setting the <i>make_before_break</i> strongswan.conf option. The
initiator <b>carol</b> reauthenticates the IKE_SA with host <b>moon</b> using
<b>ikelifetime=10s</b>, but does not close the old IKE_SA before the replacement
CHILD_SA is in place. A constant ping from <b>carol</b> to client <b>alice</b>
hiding in the subnet behind <b>moon</b> tests if the CHILD_SA works during the
whole procedure.
@@ -0,0 +1,7 @@
moon:: ipsec status 2> /dev/null::rw\[1]: ESTABLISHED.*moon.strongswan.org.*[email protected]::YES
carol::ipsec status 2> /dev/null::home\[1]: ESTABLISHED.*[email protected].*moon.strongswan.org::YES
carol::ping -c 8 PH_IP_ALICE::64 bytes from PH_IP_ALICE::YES
moon:: ipsec status 2> /dev/null::rw\[2]: ESTABLISHED.*moon.strongswan.org.*[email protected]::YES
carol::ipsec status 2> /dev/null::home\[2]: ESTABLISHED.*[email protected].*moon.strongswan.org::YES
moon::tcpdump::IP carol.strongswan.org > moon.strongswan.org: ESP::YES
moon::tcpdump::IP moon.strongswan.org > carol.strongswan.org: ESP::YES
@@ -0,0 +1,21 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
keylife=20m
ikelifetime=10s
rekeymargin=5s
rekeyfuzz=0%
keyingtries=1
conn home
left=PH_IP_CAROL
leftcert=carolCert.pem
[email protected]
leftfirewall=yes
right=PH_IP_MOON
[email protected]
rightsubnet=10.1.0.0/16
keyexchange=ikev2
auto=add
@@ -0,0 +1,7 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc stroke kernel-netlink socket-default updown
make_before_break = yes
}
@@ -0,0 +1,19 @@
# /etc/ipsec.conf - strongSwan IPsec configuration file
config setup
conn %default
ikelifetime=30m
keylife=20m
rekeymargin=0s
keyingtries=1
conn rw
left=PH_IP_MOON
leftcert=moonCert.pem
[email protected]
leftsubnet=10.1.0.0/16
leftfirewall=yes
right=%any
keyexchange=ikev2
auto=add
@@ -0,0 +1,5 @@
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = aes des sha1 sha2 md5 pem pkcs1 gmp random nonce x509 curl revocation hmac xcbc stroke kernel-netlink socket-default updown
}
@@ -0,0 +1,4 @@
moon::ipsec stop
carol::ipsec stop
moon::iptables-restore < /etc/iptables.flush
carol::iptables-restore < /etc/iptables.flush
@@ -0,0 +1,6 @@
moon::iptables-restore < /etc/iptables.rules
carol::iptables-restore < /etc/iptables.rules
moon::ipsec start
carol::ipsec start
carol::sleep 1
carol::ipsec up home
+21
View File
@@ -0,0 +1,21 @@
#!/bin/bash
#
# This configuration file provides information on the
# guest instances used for this test
# All guest instances that are required for this test
#
VIRTHOSTS="alice moon carol winnetou"
# Corresponding block diagram
#
DIAGRAM="a-m-c-w.png"
# Guest instances on which tcpdump is to be started
#
TCPDUMPHOSTS="moon"
# Guest instances on which IPsec is started
# Used for IPsec logging purposes
#
IPSECHOSTS="moon carol"