From: Martin Willi Date: Wed, 5 Jan 2011 14:58:38 +0000 (+0100) Subject: Send INITIAL_CONTACT for the first IKE_SA if it has a unique policy X-Git-Tag: 4.5.1~142 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a4a1e24d37e33cf86ea2edba97fbeeaa465d2ffd;p=thirdparty%2Fstrongswan.git Send INITIAL_CONTACT for the first IKE_SA if it has a unique policy --- diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index c8fbbde619..ec2d82dac5 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1320,9 +1320,8 @@ METHOD(ike_sa_manager_t, checkin, void, segment = put_entry(this, entry); } - /* apply identities for duplicate test (only as responder) */ - if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) && - ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && + /* apply identities for duplicate test */ + if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && entry->my_id == NULL && entry->other_id == NULL) { entry->my_id = my_id->clone(my_id); @@ -1377,8 +1376,7 @@ METHOD(ike_sa_manager_t, checkin_and_destroy, void, { remove_half_open(this, entry); } - if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) && - entry->my_id && entry->other_id) + if (entry->my_id && entry->other_id) { remove_connected_peers(this, entry); } @@ -1502,6 +1500,34 @@ METHOD(ike_sa_manager_t, check_uniqueness, bool, return cancel; } +METHOD(ike_sa_manager_t, has_contact, bool, + private_ike_sa_manager_t *this, identification_t *me, + identification_t *other, int family) +{ + linked_list_t *list; + u_int row, segment; + rwlock_t *lock; + bool found = FALSE; + + row = chunk_hash_inc(other->get_encoding(other), + chunk_hash(me->get_encoding(me))) & this->table_mask; + segment = row & this->segment_mask; + lock = this->connected_peers_segments[segment & this->segment_mask].lock; + lock->read_lock(lock); + list = this->connected_peers_table[row]; + if (list) + { + if (list->find_first(list, (linked_list_match_t)connected_peers_match, + NULL, me, other, family) == SUCCESS) + { + found = TRUE; + } + } + lock->unlock(lock); + + return found; +} + METHOD(ike_sa_manager_t, get_half_open_count, int, private_ike_sa_manager_t *this, host_t *ip) { @@ -1608,8 +1634,7 @@ METHOD(ike_sa_manager_t, flush, void, { remove_half_open(this, entry); } - if (!entry->ike_sa_id->is_initiator(entry->ike_sa_id) && - entry->my_id && entry->other_id) + if (entry->my_id && entry->other_id) { remove_connected_peers(this, entry); } @@ -1686,6 +1711,7 @@ ike_sa_manager_t *ike_sa_manager_create() .checkout_by_id = _checkout_by_id, .checkout_by_name = _checkout_by_name, .check_uniqueness = _check_uniqueness, + .has_contact = _has_contact, .create_enumerator = _create_enumerator, .checkin = _checkin, .checkin_and_destroy = _checkin_and_destroy, diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h index 115e8d3377..a9dbca6b07 100644 --- a/src/libcharon/sa/ike_sa_manager.h +++ b/src/libcharon/sa/ike_sa_manager.h @@ -111,6 +111,17 @@ struct ike_sa_manager_t { */ bool (*check_uniqueness)(ike_sa_manager_t *this, ike_sa_t *ike_sa); + /** + * Check if we already have a connected IKE_SA between two identities. + * + * @param me own identity + * @param other remote identity + * @param family address family to include in uniqueness check + * @return TRUE if we have a connected IKE_SA + */ + bool (*has_contact)(ike_sa_manager_t *this, identification_t *me, + identification_t *other, int family); + /** * Check out an IKE_SA a unique ID. * diff --git a/src/libcharon/sa/tasks/ike_auth.c b/src/libcharon/sa/tasks/ike_auth.c index 48174e2c22..6b024ccdcb 100644 --- a/src/libcharon/sa/tasks/ike_auth.c +++ b/src/libcharon/sa/tasks/ike_auth.c @@ -390,7 +390,7 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) /* check if an authenticator is in progress */ if (this->my_auth == NULL) { - identification_t *id; + identification_t *idi, *idr = NULL; id_payload_t *id_payload; /* clean up authentication config from a previous round */ @@ -401,29 +401,42 @@ static status_t build_i(private_ike_auth_t *this, message_t *message) cfg = get_auth_cfg(this, FALSE); if (cfg) { - id = cfg->get(cfg, AUTH_RULE_IDENTITY); - if (id && !id->contains_wildcards(id)) + idr = cfg->get(cfg, AUTH_RULE_IDENTITY); + if (idr && !idr->contains_wildcards(idr)) { - this->ike_sa->set_other_id(this->ike_sa, id->clone(id)); + this->ike_sa->set_other_id(this->ike_sa, idr->clone(idr)); id_payload = id_payload_create_from_identification( - ID_RESPONDER, id); + ID_RESPONDER, idr); message->add_payload(message, (payload_t*)id_payload); } } /* add IDi */ cfg = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); cfg->merge(cfg, get_auth_cfg(this, TRUE), TRUE); - id = cfg->get(cfg, AUTH_RULE_IDENTITY); - if (!id) + idi = cfg->get(cfg, AUTH_RULE_IDENTITY); + if (!idi) { DBG1(DBG_CFG, "configuration misses IDi"); return FAILED; } - this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); - id_payload = id_payload_create_from_identification(ID_INITIATOR, id); + this->ike_sa->set_my_id(this->ike_sa, idi->clone(idi)); + id_payload = id_payload_create_from_identification(ID_INITIATOR, idi); get_reserved_id_bytes(this, id_payload); message->add_payload(message, (payload_t*)id_payload); + if (idr && message->get_message_id(message) == 1 && + this->peer_cfg->get_unique_policy(this->peer_cfg) != UNIQUE_NO) + { + host_t *host; + + host = this->ike_sa->get_other_host(this->ike_sa); + if (!charon->ike_sa_manager->has_contact(charon->ike_sa_manager, + idi, idr, host->get_family(host))) + { + message->add_notify(message, FALSE, INITIAL_CONTACT, chunk_empty); + } + } + /* build authentication data */ this->my_auth = authenticator_create_builder(this->ike_sa, cfg, this->other_nonce, this->my_nonce,