implemented IKE_SA uniqueness using ipsec.conf uniqueids paramater

additionally supports a "keep" value to keep the old IKE_SA
This commit is contained in:
Martin Willi
2008-04-14 13:23:24 +00:00
parent a593db5d35
commit 0644ebd3de
11 changed files with 197 additions and 9 deletions
+17 -1
View File
@@ -88,6 +88,11 @@ struct private_peer_cfg_t {
*/
cert_policy_t cert_policy;
/**
* uniqueness of an IKE_SA
*/
unique_policy_t unique;
/**
* Method to use for own authentication data
*/
@@ -294,6 +299,14 @@ static cert_policy_t get_cert_policy(private_peer_cfg_t *this)
return this->cert_policy;
}
/**
* Implementation of peer_cfg_t.get_unique_policy.
*/
static unique_policy_t get_unique_policy(private_peer_cfg_t *this)
{
return this->unique;
}
/**
* Implementation of connection_t.auth_method_t.
*/
@@ -444,6 +457,7 @@ static bool equals(private_peer_cfg_t *this, private_peer_cfg_t *other)
this->my_id->equals(this->my_id, other->my_id) &&
this->other_id->equals(this->other_id, other->other_id) &&
this->cert_policy == other->cert_policy &&
this->unique == other->unique &&
this->auth_method == other->auth_method &&
this->eap_type == other->eap_type &&
this->eap_vendor == other->eap_vendor &&
@@ -505,7 +519,7 @@ static void destroy(private_peer_cfg_t *this)
*/
peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
identification_t *my_id, identification_t *other_id,
cert_policy_t cert_policy,
cert_policy_t cert_policy, unique_policy_t unique,
auth_method_t auth_method, eap_type_t eap_type,
u_int32_t eap_vendor,
u_int32_t keyingtries, u_int32_t rekey_time,
@@ -528,6 +542,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
this->public.get_my_id = (identification_t* (*)(peer_cfg_t*))get_my_id;
this->public.get_other_id = (identification_t* (*)(peer_cfg_t *))get_other_id;
this->public.get_cert_policy = (cert_policy_t (*) (peer_cfg_t *))get_cert_policy;
this->public.get_unique_policy = (unique_policy_t (*) (peer_cfg_t *))get_unique_policy;
this->public.get_auth_method = (auth_method_t (*) (peer_cfg_t *))get_auth_method;
this->public.get_eap_type = (eap_type_t (*) (peer_cfg_t *,u_int32_t*))get_eap_type;
this->public.get_keyingtries = (u_int32_t (*) (peer_cfg_t *))get_keyingtries;
@@ -557,6 +572,7 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg,
this->my_id = my_id;
this->other_id = other_id;
this->cert_policy = cert_policy;
this->unique = unique;
this->auth_method = auth_method;
this->eap_type = eap_type;
this->eap_vendor = eap_vendor;
+27 -1
View File
@@ -26,6 +26,7 @@
#define PEER_CFG_H_
typedef enum cert_policy_t cert_policy_t;
typedef enum unique_policy_t unique_policy_t;
typedef struct peer_cfg_t peer_cfg_t;
#include <library.h>
@@ -62,6 +63,23 @@ enum cert_policy_t {
*/
extern enum_name_t *cert_policy_names;
/**
* Uniqueness of an IKE_SA, used to drop multiple connections with one peer.
*/
enum unique_policy_t {
/** do not check for client uniqueness */
UNIQUE_NO,
/** replace unique IKE_SAs if new ones get established */
UNIQUE_REPLACE,
/** keep existing IKE_SAs, close the new ones on connection attept */
UNIQUE_KEEP,
};
/**
* enum strings for unique_policy_t
*/
extern enum_name_t *unique_policy_names;
/**
* Configuration of a peer, specified by IDs.
*
@@ -178,6 +196,13 @@ struct peer_cfg_t {
*/
cert_policy_t (*get_cert_policy) (peer_cfg_t *this);
/**
* How to handle uniqueness of IKE_SAs?
*
* @return unique policy
*/
unique_policy_t (*get_unique_policy) (peer_cfg_t *this);
/**
* Get the authentication method to use to authenticate us.
*
@@ -332,6 +357,7 @@ struct peer_cfg_t {
* @param my_id identification_t for ourselves
* @param other_id identification_t for the remote guy
* @param cert_policy should we send a certificate payload?
* @param unique uniqueness of an IKE_SA
* @param auth_method auth method to use to authenticate us
* @param eap_type EAP type to use for peer authentication
* @param eap_vendor EAP vendor identifier, if vendor specific type is used
@@ -352,7 +378,7 @@ struct peer_cfg_t {
*/
peer_cfg_t *peer_cfg_create(char *name, u_int ikev_version, ike_cfg_t *ike_cfg,
identification_t *my_id, identification_t *other_id,
cert_policy_t cert_policy,
cert_policy_t cert_policy, unique_policy_t unique,
auth_method_t auth_method, eap_type_t eap_type,
u_int32_t eap_vendor,
u_int32_t keyingtries, u_int32_t rekey_time,
+5 -5
View File
@@ -309,11 +309,11 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e,
if (ike)
{
peer_cfg = peer_cfg_create(
name, 2, ike, local_id, remote_id, cert_policy,
auth_method, eap_type, eap_vendor, keyingtries,
rekeytime, reauthtime, jitter, overtime, mobike,
dpd_delay, NULL, NULL,
mediation, mediated_cfg, peer_id);
name, 2, ike, local_id, remote_id, cert_policy, UNIQUE_NO,
auth_method, eap_type, eap_vendor, keyingtries,
rekeytime, reauthtime, jitter, overtime, mobike,
dpd_delay, NULL, NULL,
mediation, mediated_cfg, peer_id);
add_child_cfgs(this, peer_cfg, id);
return peer_cfg;
}
+15 -1
View File
@@ -356,6 +356,7 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
peer_cfg_t *mediated_by = NULL;
host_t *vip = NULL;
certificate_t *cert;
unique_policy_t unique;
u_int32_t rekey = 0, reauth = 0, over, jitter;
me = identification_create_from_string(msg->add_conn.me.id ?
@@ -483,12 +484,25 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this,
}
}
}
switch (msg->add_conn.unique)
{
case 1: /* yes */
case 2: /* replace */
unique = UNIQUE_REPLACE;
break;
case 3: /* keep */
unique = UNIQUE_KEEP;
break;
default: /* no */
unique = UNIQUE_NO;
break;
}
/* other.sourceip is managed in stroke_attributes. If it is set, we define
* the pool name as the connection name, which the attribute provider
* uses to serve pool addresses. */
return peer_cfg_create(msg->add_conn.name,
msg->add_conn.ikev2 ? 2 : 1, ike_cfg, me, other,
msg->add_conn.me.sendcert, UNIQUE_NO, msg->add_conn.auth_method,
msg->add_conn.me.sendcert, unique, msg->add_conn.auth_method,
msg->add_conn.eap_type, msg->add_conn.eap_vendor,
msg->add_conn.rekey.tries, rekey, reauth, jitter, over,
msg->add_conn.mobike, msg->add_conn.dpd.delay,
+39
View File
@@ -686,6 +686,44 @@ static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
charon->bus->set_sa(charon->bus, ike_sa);
return ike_sa;
}
/**
* Implementation of ike_sa_manager_t.checkout_duplicate.
*/
static ike_sa_t* checkout_duplicate(private_ike_sa_manager_t *this,
ike_sa_t *ike_sa)
{
enumerator_t *enumerator;
entry_t *entry;
ike_sa_t *duplicate = NULL;
identification_t *me, *other;
me = ike_sa->get_my_id(ike_sa);
other = ike_sa->get_other_id(ike_sa);
pthread_mutex_lock(&this->mutex);
enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->ike_sa == ike_sa)
{ /* self is not a duplicate */
continue;
}
if (wait_for_entry(this, entry))
{
if (me->equals(me, entry->ike_sa->get_my_id(entry->ike_sa)) &&
other->equals(other, entry->ike_sa->get_other_id(entry->ike_sa)))
{
duplicate = entry->ike_sa;
entry->checked_out = TRUE;
break;
}
}
}
enumerator->destroy(enumerator);
pthread_mutex_unlock(&this->mutex);
return duplicate;
}
/**
* enumerator cleanup function
@@ -916,6 +954,7 @@ ike_sa_manager_t *ike_sa_manager_create()
this->public.checkout_by_config = (ike_sa_t*(*)(ike_sa_manager_t*,peer_cfg_t*))checkout_by_config;
this->public.checkout_by_id = (ike_sa_t*(*)(ike_sa_manager_t*,u_int32_t,bool))checkout_by_id;
this->public.checkout_by_name = (ike_sa_t*(*)(ike_sa_manager_t*,char*,bool))checkout_by_name;
this->public.checkout_duplicate = (ike_sa_t*(*)(ike_sa_manager_t*, ike_sa_t *ike_sa))checkout_duplicate;
this->public.create_enumerator = (enumerator_t*(*)(ike_sa_manager_t*))create_enumerator;
this->public.checkin = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin;
this->public.checkin_and_destroy = (status_t(*)(ike_sa_manager_t*,ike_sa_t*))checkin_and_destroy;
+8
View File
@@ -102,6 +102,14 @@ struct ike_sa_manager_t {
ike_sa_t* (*checkout_by_config) (ike_sa_manager_t* this,
peer_cfg_t *peer_cfg);
/**
* Check out a duplicate if ike_sa to do uniqueness tests.
*
* @param ike_sa ike_sa to get a duplicate from
* @return checked out duplicate
*/
ike_sa_t* (*checkout_duplicate)(ike_sa_manager_t *this, ike_sa_t *ike_sa);
/**
* Check out an IKE_SA a unique ID.
*
+68
View File
@@ -88,6 +88,68 @@ struct private_ike_auth_t {
bool peer_authenticated;
};
/**
* check uniqueness and delete duplicates
*/
static bool check_uniqueness(private_ike_auth_t *this)
{
ike_sa_t *duplicate;
unique_policy_t policy;
status_t status = SUCCESS;
peer_cfg_t *peer_cfg;
bool cancel = FALSE;
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
policy = peer_cfg->get_unique_policy(peer_cfg);
if (policy == UNIQUE_NO)
{
return FALSE;
}
duplicate = charon->ike_sa_manager->checkout_duplicate(
charon->ike_sa_manager, this->ike_sa);
if (duplicate)
{
peer_cfg = duplicate->get_peer_cfg(duplicate);
if (peer_cfg &&
peer_cfg->equals(peer_cfg, this->ike_sa->get_peer_cfg(this->ike_sa)))
{
switch (duplicate->get_state(duplicate))
{
case IKE_ESTABLISHED:
case IKE_REKEYING:
switch (policy)
{
case UNIQUE_REPLACE:
DBG1(DBG_IKE, "deleting duplicate IKE_SA due "
"uniqueness policy");
status = duplicate->delete(duplicate);
break;
case UNIQUE_KEEP:
DBG1(DBG_IKE, "cancelling IKE_SA setup due "
"uniqueness policy");
cancel = TRUE;
break;
default:
break;
}
break;
default:
break;
}
}
if (status == DESTROY_ME)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
duplicate);
}
else
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, duplicate);
}
}
return cancel;
}
/**
* build the AUTH payload
*/
@@ -576,6 +638,12 @@ static status_t build_r(private_ike_auth_t *this, message_t *message)
return FAILED;
}
if (check_uniqueness(this))
{
message->add_notify(message, TRUE, AUTHENTICATION_FAILED, chunk_empty);
return FAILED;
}
/* use "traditional" authentication if we could authenticate peer */
if (this->peer_authenticated)
{