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 ---------------- diff --git a/conf/options/charon.opt b/conf/options/charon.opt index 02629a3f4..f0969e6c6 100644 --- a/conf/options/charon.opt +++ b/conf/options/charon.opt @@ -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). 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/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/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/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 diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index e9a677a65..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 @@ -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; 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 */ 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); 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/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 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 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" 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"