From 6f5892f5c7c58b7124fda4a4c2abac81dbea6060 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 5 Jan 2011 16:44:01 +0100 Subject: [PATCH] Destroy existing IKE_SAs with same identities when receiving INITIAL_CONTACT --- src/libcharon/sa/ike_sa_manager.c | 11 +++++++++-- src/libcharon/sa/ike_sa_manager.h | 4 +++- src/libcharon/sa/tasks/ike_auth.c | 22 +++++++++++++++++++++- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index ec2d82dac..fb9cdbbea 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1394,7 +1394,7 @@ METHOD(ike_sa_manager_t, checkin_and_destroy, void, } METHOD(ike_sa_manager_t, check_uniqueness, bool, - private_ike_sa_manager_t *this, ike_sa_t *ike_sa) + private_ike_sa_manager_t *this, ike_sa_t *ike_sa, bool force_replace) { bool cancel = FALSE; peer_cfg_t *peer_cfg; @@ -1408,7 +1408,7 @@ METHOD(ike_sa_manager_t, check_uniqueness, bool, peer_cfg = ike_sa->get_peer_cfg(ike_sa); policy = peer_cfg->get_unique_policy(peer_cfg); - if (policy == UNIQUE_NO) + if (policy == UNIQUE_NO && !force_replace) { return FALSE; } @@ -1456,6 +1456,13 @@ METHOD(ike_sa_manager_t, check_uniqueness, bool, { continue; } + if (force_replace) + { + DBG1(DBG_IKE, "destroying duplicate IKE_SA for peer '%Y', " + "received INITIAL_CONTACT", other); + checkin_and_destroy(this, duplicate); + continue; + } peer_cfg = duplicate->get_peer_cfg(duplicate); if (peer_cfg && peer_cfg->equals(peer_cfg, ike_sa->get_peer_cfg(ike_sa))) { diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h index a9dbca6b0..ec157ab3a 100644 --- a/src/libcharon/sa/ike_sa_manager.h +++ b/src/libcharon/sa/ike_sa_manager.h @@ -106,10 +106,12 @@ struct ike_sa_manager_t { * deadlocks occur otherwise. * * @param ike_sa ike_sa to check + * @param force_replace replace existing SAs, regardless of unique policy * @return TRUE, if the given IKE_SA has duplicates and * should be deleted */ - bool (*check_uniqueness)(ike_sa_manager_t *this, ike_sa_t *ike_sa); + bool (*check_uniqueness)(ike_sa_manager_t *this, ike_sa_t *ike_sa, + bool force_replace); /** * Check if we already have a connected IKE_SA between two identities. diff --git a/src/libcharon/sa/tasks/ike_auth.c b/src/libcharon/sa/tasks/ike_auth.c index 6b024ccdc..178989a0a 100644 --- a/src/libcharon/sa/tasks/ike_auth.c +++ b/src/libcharon/sa/tasks/ike_auth.c @@ -106,6 +106,11 @@ struct private_ike_auth_t { * should we send a AUTHENTICATION_FAILED notify? */ bool authentication_failed; + + /** + * received an INITIAL_CONTACT? + */ + bool initial_contact; }; /** @@ -612,6 +617,14 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) return NEED_MORE; } + /* If authenticated (with non-EAP) and received INITIAL_CONTACT, + * delete any existing IKE_SAs with that peer. */ + if (message->get_message_id(message) == 1 && + message->get_notify(message, INITIAL_CONTACT)) + { + this->initial_contact = TRUE; + } + /* store authentication information */ cfg = auth_cfg_create(); cfg->merge(cfg, this->ike_sa->get_auth_cfg(this->ike_sa, FALSE), FALSE); @@ -705,6 +718,13 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) get_reserved_id_bytes(this, id_payload); message->add_payload(message, (payload_t*)id_payload); + if (this->initial_contact) + { + charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, + this->ike_sa, TRUE); + this->initial_contact = FALSE; + } + if ((uintptr_t)cfg->get(cfg, AUTH_RULE_AUTH_CLASS) == AUTH_CLASS_EAP) { /* EAP-only authentication */ if (!this->ike_sa->supports_extension(this->ike_sa, @@ -786,7 +806,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) if (!this->do_another_auth && !this->expect_another_auth) { if (charon->ike_sa_manager->check_uniqueness(charon->ike_sa_manager, - this->ike_sa)) + this->ike_sa, FALSE)) { DBG1(DBG_IKE, "cancelling IKE_SA setup due uniqueness policy"); message->add_notify(message, TRUE, AUTHENTICATION_FAILED,