From c8e7dbcb563fddda26f85110e0b46cdd6173651f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 3 Nov 2014 16:00:13 +0100 Subject: [PATCH 01/10] ike-sa-manager: Use IKEv1 uniqueness reauthentication detection for IKEv2, too --- src/libcharon/sa/ike_sa_manager.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 7ca72f3c1..6d0a59800 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -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 From 349f7f24120cf00d499a34abe01fc7c19ec39ecf Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 3 Nov 2014 16:37:29 +0100 Subject: [PATCH 02/10] ikev2: Trigger make-before-break reauthentication instead of reauth task --- conf/options/charon.opt | 10 ++++ src/libcharon/sa/ike_sa.h | 5 +- src/libcharon/sa/ikev2/task_manager_v2.c | 76 ++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/conf/options/charon.opt b/conf/options/charon.opt index 02629a3f4..fc38a1451 100644 --- a/conf/options/charon.opt +++ b/conf/options/charon.opt @@ -196,6 +196,16 @@ charon.load_modular = no charon.max_packet = 10000 Maximum packet size accepted by charon. +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.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. diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index c72d87367..f65efd81f 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -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 */ diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index e9a677a65..b558f429d 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -171,6 +171,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; }; /** @@ -1505,9 +1510,78 @@ 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) + { + 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 +1847,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; From 52bd3b8ef9e1350b2a5abdf03245cc84cc227aa6 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 4 Nov 2014 13:54:29 +0100 Subject: [PATCH 03/10] ikev2: Allow task to skip exchange by setting undefined exchange type --- src/libcharon/sa/ikev2/task_manager_v2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index b558f429d..613c72996 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -609,6 +609,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)) { From 3676023e54c75bab3d2787c78f8024704d4bb4c3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 4 Nov 2014 13:41:48 +0100 Subject: [PATCH 04/10] ikev2: Schedule a make-before-break completion task to delete old IKE_SA --- src/libcharon/Android.mk | 1 + src/libcharon/Makefile.am | 1 + src/libcharon/sa/ikev2/task_manager_v2.c | 8 ++ src/libcharon/sa/ikev2/tasks/ike_reauth.h | 2 + .../sa/ikev2/tasks/ike_reauth_complete.c | 102 ++++++++++++++++++ .../sa/ikev2/tasks/ike_reauth_complete.h | 56 ++++++++++ src/libcharon/sa/task.c | 1 + src/libcharon/sa/task.h | 4 +- 8 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/libcharon/sa/ikev2/tasks/ike_reauth_complete.c create mode 100644 src/libcharon/sa/ikev2/tasks/ike_reauth_complete.h diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk index cf4ed3d49..77ce3f348 100644 --- a/src/libcharon/Android.mk +++ b/src/libcharon/Android.mk @@ -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 diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index e0457e493..e7b7c6854 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -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 diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index 613c72996..48266aa52 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -515,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)) { @@ -1569,6 +1575,8 @@ static void trigger_mbb_reauth(private_task_manager_t *this) 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); } diff --git a/src/libcharon/sa/ikev2/tasks/ike_reauth.h b/src/libcharon/sa/ikev2/tasks/ike_reauth.h index 781b463a7..e2e48f0d4 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_reauth.h +++ b/src/libcharon/sa/ikev2/tasks/ike_reauth.h @@ -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 { diff --git a/src/libcharon/sa/ikev2/tasks/ike_reauth_complete.c b/src/libcharon/sa/ikev2/tasks/ike_reauth_complete.c new file mode 100644 index 000000000..a01489c03 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_reauth_complete.c @@ -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 . + * + * 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 +#include + + +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; +} diff --git a/src/libcharon/sa/ikev2/tasks/ike_reauth_complete.h b/src/libcharon/sa/ikev2/tasks/ike_reauth_complete.h new file mode 100644 index 000000000..cc3d3b713 --- /dev/null +++ b/src/libcharon/sa/ikev2/tasks/ike_reauth_complete.h @@ -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 . + * + * 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 +#include +#include + +/** + * 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_ @}*/ diff --git a/src/libcharon/sa/task.c b/src/libcharon/sa/task.c index 4336b23ff..b35b58185 100644 --- a/src/libcharon/sa/task.c +++ b/src/libcharon/sa/task.c @@ -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", diff --git a/src/libcharon/sa/task.h b/src/libcharon/sa/task.h index 8e380851a..7bd3da1fe 100644 --- a/src/libcharon/sa/task.h +++ b/src/libcharon/sa/task.h @@ -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 */ From 22e6a06b8c2d12374156a9559bbc7edd183a9040 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 4 Nov 2014 16:32:33 +0100 Subject: [PATCH 05/10] mem-pool: Pass the remote IKE address, to re-acquire() an address during reauth With make-before-break IKEv2 re-authentication, virtual IP addresses must be assigned overlapping to the same peer. With the remote IKE address, the backend can detect re-authentication attempts by comparing the remote host address and port. This allows proper reassignment of the virtual IP if it is re-requested. This change removes the mem-pool.reassign_online option, as it is obsolete now. IPs get automatically reassigned if a peer re-requests the same address, and additionally connects from the same address and port. --- conf/options/charon.opt | 4 - src/libcharon/attributes/mem_pool.c | 96 ++++++++++++------- src/libcharon/attributes/mem_pool.h | 10 +- .../plugins/load_tester/load_tester_config.c | 2 +- .../plugins/stroke/stroke_attribute.c | 13 +-- src/libcharon/plugins/vici/vici_attribute.c | 15 +-- src/libcharon/tests/suites/test_mem_pool.c | 2 +- 7 files changed, 87 insertions(+), 55 deletions(-) diff --git a/conf/options/charon.opt b/conf/options/charon.opt index fc38a1451..f0969e6c6 100644 --- a/conf/options/charon.opt +++ b/conf/options/charon.opt @@ -206,10 +206,6 @@ charon.make_before_break = no gaps during reauthentication, but requires support for overlapping SAs by the peer. strongSwan can handle such overlapping SAs since version 5.3.0. -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.multiple_authentication = yes Enable multiple authentication exchanges (RFC 4739). diff --git a/src/libcharon/attributes/mem_pool.c b/src/libcharon/attributes/mem_pool.c index f35ffaa9c..759d94126 100644 --- a/src/libcharon/attributes/mem_pool.c +++ b/src/libcharon/attributes/mem_pool.c @@ -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, ¤t)) { - 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, ¤t)) + 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, ¤t)) { - 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, ¤t)) { - 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; diff --git a/src/libcharon/attributes/mem_pool.h b/src/libcharon/attributes/mem_pool.h index 7347bb547..3ee1dd37d 100644 --- a/src/libcharon/attributes/mem_pool.h +++ b/src/libcharon/attributes/mem_pool.h @@ -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. diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c index bc7c0ffbc..65575c6ac 100644 --- a/src/libcharon/plugins/load_tester/load_tester_config.c +++ b/src/libcharon/plugins/load_tester/load_tester_config.c @@ -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); diff --git a/src/libcharon/plugins/stroke/stroke_attribute.c b/src/libcharon/plugins/stroke/stroke_attribute.c index 131253c69..cd1b4d093 100644 --- a/src/libcharon/plugins/stroke/stroke_attribute.c +++ b/src/libcharon/plugins/stroke/stroke_attribute.c @@ -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); } } diff --git a/src/libcharon/plugins/vici/vici_attribute.c b/src/libcharon/plugins/vici/vici_attribute.c index 320fe5568..f04bae774 100644 --- a/src/libcharon/plugins/vici/vici_attribute.c +++ b/src/libcharon/plugins/vici/vici_attribute.c @@ -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); } } diff --git a/src/libcharon/tests/suites/test_mem_pool.c b/src/libcharon/tests/suites/test_mem_pool.c index c47a92f78..4204d4bab 100644 --- a/src/libcharon/tests/suites/test_mem_pool.c +++ b/src/libcharon/tests/suites/test_mem_pool.c @@ -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); From ae3fdf2603e85fad39b2e3695d4db24779652cdc Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 10 Nov 2014 15:36:08 +0100 Subject: [PATCH 06/10] testing: Add a test scenario for make-before-break reauth without a virtual IP --- .../tests/ikev2/reauth-mbb/description.txt | 7 +++++++ testing/tests/ikev2/reauth-mbb/evaltest.dat | 7 +++++++ .../reauth-mbb/hosts/carol/etc/ipsec.conf | 21 +++++++++++++++++++ .../hosts/carol/etc/strongswan.conf | 7 +++++++ .../reauth-mbb/hosts/moon/etc/ipsec.conf | 19 +++++++++++++++++ .../reauth-mbb/hosts/moon/etc/strongswan.conf | 5 +++++ testing/tests/ikev2/reauth-mbb/posttest.dat | 4 ++++ testing/tests/ikev2/reauth-mbb/pretest.dat | 6 ++++++ testing/tests/ikev2/reauth-mbb/test.conf | 21 +++++++++++++++++++ 9 files changed, 97 insertions(+) create mode 100644 testing/tests/ikev2/reauth-mbb/description.txt create mode 100644 testing/tests/ikev2/reauth-mbb/evaltest.dat create mode 100644 testing/tests/ikev2/reauth-mbb/hosts/carol/etc/ipsec.conf create mode 100644 testing/tests/ikev2/reauth-mbb/hosts/carol/etc/strongswan.conf create mode 100644 testing/tests/ikev2/reauth-mbb/hosts/moon/etc/ipsec.conf create mode 100644 testing/tests/ikev2/reauth-mbb/hosts/moon/etc/strongswan.conf create mode 100644 testing/tests/ikev2/reauth-mbb/posttest.dat create mode 100644 testing/tests/ikev2/reauth-mbb/pretest.dat create mode 100644 testing/tests/ikev2/reauth-mbb/test.conf diff --git a/testing/tests/ikev2/reauth-mbb/description.txt b/testing/tests/ikev2/reauth-mbb/description.txt new file mode 100644 index 000000000..ab92d7df8 --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb/description.txt @@ -0,0 +1,7 @@ +This scenario tests make-before-break reauthentication using overlapping +IKE_SAs by setting the make_before_break strongswan.conf option. The +initiator carol reauthenticates the IKE_SA with host moon using +ikelifetime=10s, but does not close the old IKE_SA before the replacement +CHILD_SA is in place. A constant ping from carol to client alice +hiding in the subnet behind moon tests if the CHILD_SA works during the +whole procedure. diff --git a/testing/tests/ikev2/reauth-mbb/evaltest.dat b/testing/tests/ikev2/reauth-mbb/evaltest.dat new file mode 100644 index 000000000..509457418 --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb/evaltest.dat @@ -0,0 +1,7 @@ +moon:: ipsec status 2> /dev/null::rw\[1]: ESTABLISHED.*moon.strongswan.org.*carol@strongswan.org::YES +carol::ipsec status 2> /dev/null::home\[1]: ESTABLISHED.*carol@strongswan.org.*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.*carol@strongswan.org::YES +carol::ipsec status 2> /dev/null::home\[2]: ESTABLISHED.*carol@strongswan.org.*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 diff --git a/testing/tests/ikev2/reauth-mbb/hosts/carol/etc/ipsec.conf b/testing/tests/ikev2/reauth-mbb/hosts/carol/etc/ipsec.conf new file mode 100644 index 000000000..f46405a47 --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb/hosts/carol/etc/ipsec.conf @@ -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 + leftid=carol@strongswan.org + leftfirewall=yes + right=PH_IP_MOON + rightid=@moon.strongswan.org + rightsubnet=10.1.0.0/16 + keyexchange=ikev2 + auto=add diff --git a/testing/tests/ikev2/reauth-mbb/hosts/carol/etc/strongswan.conf b/testing/tests/ikev2/reauth-mbb/hosts/carol/etc/strongswan.conf new file mode 100644 index 000000000..f89437e43 --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb/hosts/carol/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/reauth-mbb/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/reauth-mbb/hosts/moon/etc/ipsec.conf new file mode 100644 index 000000000..2f4557447 --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb/hosts/moon/etc/ipsec.conf @@ -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 + leftid=@moon.strongswan.org + leftsubnet=10.1.0.0/16 + leftfirewall=yes + right=%any + keyexchange=ikev2 + auto=add diff --git a/testing/tests/ikev2/reauth-mbb/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/reauth-mbb/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..f585edfca --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb/hosts/moon/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/reauth-mbb/posttest.dat b/testing/tests/ikev2/reauth-mbb/posttest.dat new file mode 100644 index 000000000..046d4cfdc --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb/posttest.dat @@ -0,0 +1,4 @@ +moon::ipsec stop +carol::ipsec stop +moon::iptables-restore < /etc/iptables.flush +carol::iptables-restore < /etc/iptables.flush diff --git a/testing/tests/ikev2/reauth-mbb/pretest.dat b/testing/tests/ikev2/reauth-mbb/pretest.dat new file mode 100644 index 000000000..baacc1605 --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb/pretest.dat @@ -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 diff --git a/testing/tests/ikev2/reauth-mbb/test.conf b/testing/tests/ikev2/reauth-mbb/test.conf new file mode 100644 index 000000000..4a5fc470f --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb/test.conf @@ -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" From b1ff437bbc4fca6d83bd42e18398475a0d544fa0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 10 Nov 2014 15:36:48 +0100 Subject: [PATCH 07/10] testing: Add a test scenario for make-before-break reauth using a virtual IP --- .../reauth-mbb-virtual-ip/description.txt | 8 +++++++ .../ikev2/reauth-mbb-virtual-ip/evaltest.dat | 7 ++++++ .../hosts/carol/etc/ipsec.conf | 22 +++++++++++++++++++ .../hosts/carol/etc/strongswan.conf | 7 ++++++ .../hosts/moon/etc/ipsec.conf | 20 +++++++++++++++++ .../hosts/moon/etc/strongswan.conf | 5 +++++ .../ikev2/reauth-mbb-virtual-ip/posttest.dat | 4 ++++ .../ikev2/reauth-mbb-virtual-ip/pretest.dat | 6 +++++ .../ikev2/reauth-mbb-virtual-ip/test.conf | 21 ++++++++++++++++++ 9 files changed, 100 insertions(+) create mode 100644 testing/tests/ikev2/reauth-mbb-virtual-ip/description.txt create mode 100644 testing/tests/ikev2/reauth-mbb-virtual-ip/evaltest.dat create mode 100644 testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/carol/etc/ipsec.conf create mode 100644 testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/carol/etc/strongswan.conf create mode 100644 testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/moon/etc/ipsec.conf create mode 100644 testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/moon/etc/strongswan.conf create mode 100644 testing/tests/ikev2/reauth-mbb-virtual-ip/posttest.dat create mode 100644 testing/tests/ikev2/reauth-mbb-virtual-ip/pretest.dat create mode 100644 testing/tests/ikev2/reauth-mbb-virtual-ip/test.conf diff --git a/testing/tests/ikev2/reauth-mbb-virtual-ip/description.txt b/testing/tests/ikev2/reauth-mbb-virtual-ip/description.txt new file mode 100644 index 000000000..dfec6a3b6 --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb-virtual-ip/description.txt @@ -0,0 +1,8 @@ +This scenario tests make-before-break reauthentication using overlapping +IKE_SAs by setting the make_before_break strongswan.conf option for +clients using an assigned virtual IP. The initiator carol reauthenticates +the IKE_SA with host moon using ikelifetime=10s, 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 carol to client alice +hiding in the subnet behind moon tests if the CHILD_SA works during the +whole procedure. diff --git a/testing/tests/ikev2/reauth-mbb-virtual-ip/evaltest.dat b/testing/tests/ikev2/reauth-mbb-virtual-ip/evaltest.dat new file mode 100644 index 000000000..509457418 --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb-virtual-ip/evaltest.dat @@ -0,0 +1,7 @@ +moon:: ipsec status 2> /dev/null::rw\[1]: ESTABLISHED.*moon.strongswan.org.*carol@strongswan.org::YES +carol::ipsec status 2> /dev/null::home\[1]: ESTABLISHED.*carol@strongswan.org.*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.*carol@strongswan.org::YES +carol::ipsec status 2> /dev/null::home\[2]: ESTABLISHED.*carol@strongswan.org.*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 diff --git a/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/carol/etc/ipsec.conf b/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/carol/etc/ipsec.conf new file mode 100644 index 000000000..6447b1cca --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/carol/etc/ipsec.conf @@ -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 + leftid=carol@strongswan.org + leftsourceip=%config + leftfirewall=yes + right=PH_IP_MOON + rightid=@moon.strongswan.org + rightsubnet=10.1.0.0/16 + keyexchange=ikev2 + auto=add diff --git a/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/carol/etc/strongswan.conf b/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/carol/etc/strongswan.conf new file mode 100644 index 000000000..f89437e43 --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/carol/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/moon/etc/ipsec.conf new file mode 100644 index 000000000..121ea7eab --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/moon/etc/ipsec.conf @@ -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 + leftid=@moon.strongswan.org + leftsubnet=10.1.0.0/16 + leftfirewall=yes + right=%any + rightsourceip=10.3.0.0/24 + keyexchange=ikev2 + auto=add diff --git a/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/moon/etc/strongswan.conf b/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/moon/etc/strongswan.conf new file mode 100644 index 000000000..f585edfca --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb-virtual-ip/hosts/moon/etc/strongswan.conf @@ -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 +} diff --git a/testing/tests/ikev2/reauth-mbb-virtual-ip/posttest.dat b/testing/tests/ikev2/reauth-mbb-virtual-ip/posttest.dat new file mode 100644 index 000000000..046d4cfdc --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb-virtual-ip/posttest.dat @@ -0,0 +1,4 @@ +moon::ipsec stop +carol::ipsec stop +moon::iptables-restore < /etc/iptables.flush +carol::iptables-restore < /etc/iptables.flush diff --git a/testing/tests/ikev2/reauth-mbb-virtual-ip/pretest.dat b/testing/tests/ikev2/reauth-mbb-virtual-ip/pretest.dat new file mode 100644 index 000000000..baacc1605 --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb-virtual-ip/pretest.dat @@ -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 diff --git a/testing/tests/ikev2/reauth-mbb-virtual-ip/test.conf b/testing/tests/ikev2/reauth-mbb-virtual-ip/test.conf new file mode 100644 index 000000000..4a5fc470f --- /dev/null +++ b/testing/tests/ikev2/reauth-mbb-virtual-ip/test.conf @@ -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" From 050556bf59e9089100c7820ef50758b8f7696e82 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 12 Nov 2014 12:09:04 +0100 Subject: [PATCH 08/10] testing: Be a little more flexible in testing for established CHILD_SA modes As we now print the reqid parameter in the CHILD_SA details, adapt the grep to still match the CHILD_SA mode and protocol. --- testing/tests/ikev1/double-nat-net/evaltest.dat | 4 ++-- testing/tests/ikev1/double-nat/evaltest.dat | 4 ++-- testing/tests/ikev1/nat-rw/evaltest.dat | 8 ++++---- testing/tests/ikev2/double-nat-net/evaltest.dat | 4 ++-- testing/tests/ikev2/double-nat/evaltest.dat | 4 ++-- testing/tests/ikev2/nat-rw-mark/evaltest.dat | 4 ++-- testing/tests/ikev2/nat-rw-psk/evaltest.dat | 6 +++--- testing/tests/ikev2/nat-rw/evaltest.dat | 8 ++++---- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/testing/tests/ikev1/double-nat-net/evaltest.dat b/testing/tests/ikev1/double-nat-net/evaltest.dat index 52c561964..8f5ffdb50 100644 --- a/testing/tests/ikev1/double-nat-net/evaltest.dat +++ b/testing/tests/ikev1/double-nat-net/evaltest.dat @@ -1,7 +1,7 @@ alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*alice@strongswan.org.*bob@strongswan.org::YES bob:: ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*bob@strongswan.org.*alice@strongswan.org::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 diff --git a/testing/tests/ikev1/double-nat/evaltest.dat b/testing/tests/ikev1/double-nat/evaltest.dat index 9ddad2de5..5f0622690 100644 --- a/testing/tests/ikev1/double-nat/evaltest.dat +++ b/testing/tests/ikev1/double-nat/evaltest.dat @@ -1,7 +1,7 @@ alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*alice@strongswan.org.*bob@strongswan.org::YES bob:: ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*bob@strongswan.org.*alice@strongswan.org::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 diff --git a/testing/tests/ikev1/nat-rw/evaltest.dat b/testing/tests/ikev1/nat-rw/evaltest.dat index 387dbae23..36d9f8456 100644 --- a/testing/tests/ikev1/nat-rw/evaltest.dat +++ b/testing/tests/ikev1/nat-rw/evaltest.dat @@ -2,10 +2,10 @@ alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*alice@strongswan.org.*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.*alice@strongswan.org::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 diff --git a/testing/tests/ikev2/double-nat-net/evaltest.dat b/testing/tests/ikev2/double-nat-net/evaltest.dat index 52c561964..8f5ffdb50 100644 --- a/testing/tests/ikev2/double-nat-net/evaltest.dat +++ b/testing/tests/ikev2/double-nat-net/evaltest.dat @@ -1,7 +1,7 @@ alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*alice@strongswan.org.*bob@strongswan.org::YES bob:: ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*bob@strongswan.org.*alice@strongswan.org::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 diff --git a/testing/tests/ikev2/double-nat/evaltest.dat b/testing/tests/ikev2/double-nat/evaltest.dat index 9ddad2de5..5f0622690 100644 --- a/testing/tests/ikev2/double-nat/evaltest.dat +++ b/testing/tests/ikev2/double-nat/evaltest.dat @@ -1,7 +1,7 @@ alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*alice@strongswan.org.*bob@strongswan.org::YES bob:: ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*bob@strongswan.org.*alice@strongswan.org::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 diff --git a/testing/tests/ikev2/nat-rw-mark/evaltest.dat b/testing/tests/ikev2/nat-rw-mark/evaltest.dat index bb8e856cc..c5390fbb6 100644 --- a/testing/tests/ikev2/nat-rw-mark/evaltest.dat +++ b/testing/tests/ikev2/nat-rw-mark/evaltest.dat @@ -1,7 +1,7 @@ alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*alice@strongswan.org.*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.*alice@strongswan.org::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 diff --git a/testing/tests/ikev2/nat-rw-psk/evaltest.dat b/testing/tests/ikev2/nat-rw-psk/evaltest.dat index 6ec29c779..86fc1975e 100644 --- a/testing/tests/ikev2/nat-rw-psk/evaltest.dat +++ b/testing/tests/ikev2/nat-rw-psk/evaltest.dat @@ -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 diff --git a/testing/tests/ikev2/nat-rw/evaltest.dat b/testing/tests/ikev2/nat-rw/evaltest.dat index 387dbae23..36d9f8456 100644 --- a/testing/tests/ikev2/nat-rw/evaltest.dat +++ b/testing/tests/ikev2/nat-rw/evaltest.dat @@ -2,10 +2,10 @@ alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*alice@strongswan.org.*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.*alice@strongswan.org::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 From f27fb58ae0ec833c4a11560b6d5a68e97eafaac5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 12 Nov 2014 16:52:52 +0100 Subject: [PATCH 09/10] testing: Update description and test evaluation of host2host-transport-nat As we now reuse the reqid for identical SAs, the behavior changes for transport connections to multiple peers behind the same NAT. Instead of rejecting the SA, we now have two valid SAs active. For the reverse path, however, sun sends traffic always over the newer SA, resembling the behavior before we introduced explicit SA conflicts for different reqids. --- .../ikev2/host2host-transport-nat/description.txt | 3 ++- .../ikev2/host2host-transport-nat/evaltest.dat | 13 +++++-------- .../tests/ikev2/host2host-transport-nat/pretest.dat | 1 + 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/testing/tests/ikev2/host2host-transport-nat/description.txt b/testing/tests/ikev2/host2host-transport-nat/description.txt index 6f18a88cd..fc7186c53 100644 --- a/testing/tests/ikev2/host2host-transport-nat/description.txt +++ b/testing/tests/ikev2/host2host-transport-nat/description.txt @@ -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 XfrmInTmplMismatch counter in /proc/net/xfrm_stat).
  • A similar issue arises when venus also establishes an IPsec transport-mode connection to -sun, due to the conflicting IPsec policies sun declines such a connection.
  • +sun. Due to the conflicting IPsec policies sun will use the newer SA from +venus to send traffic to the common transport mode address. diff --git a/testing/tests/ikev2/host2host-transport-nat/evaltest.dat b/testing/tests/ikev2/host2host-transport-nat/evaltest.dat index faa9fb265..0ec50bc92 100644 --- a/testing/tests/ikev2/host2host-transport-nat/evaltest.dat +++ b/testing/tests/ikev2/host2host-transport-nat/evaltest.dat @@ -1,12 +1,9 @@ alice::ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*alice@strongswan.org.*sun.strongswan.org::YES sun:: ipsec status 2> /dev/null::nat-t.*ESTABLISHED.*sun.strongswan.org.*alice@strongswan.org::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 diff --git a/testing/tests/ikev2/host2host-transport-nat/pretest.dat b/testing/tests/ikev2/host2host-transport-nat/pretest.dat index fe0f17d3d..2d2607078 100644 --- a/testing/tests/ikev2/host2host-transport-nat/pretest.dat +++ b/testing/tests/ikev2/host2host-transport-nat/pretest.dat @@ -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 From 4a00f912ed2b9643fb6e792c612dfde30407052a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 4 Feb 2015 11:47:56 +0100 Subject: [PATCH 10/10] NEWS: Introduce make-before-break reauthentication --- NEWS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/NEWS b/NEWS index 1bce48d69..976f34c18 100644 --- a/NEWS +++ b/NEWS @@ -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 ----------------