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

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;

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,

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;
}

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,

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;

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.
*

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)
{

View File

@ -62,6 +62,14 @@ static const char *LST_sendcert[] = {
NULL
};
static const char *LST_unique[] = {
"no",
"yes",
"replace",
"keep",
NULL
};
static const char *LST_strict[] = {
"no",
"yes",
@ -163,7 +171,7 @@ static const token_info_t token_info[] =
{ ARG_STR, offsetof(starter_config_t, setup.charondebug), NULL },
{ ARG_STR, offsetof(starter_config_t, setup.prepluto), NULL },
{ ARG_STR, offsetof(starter_config_t, setup.postpluto), NULL },
{ ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_bool },
{ ARG_ENUM, offsetof(starter_config_t, setup.uniqueids), LST_unique },
{ ARG_UINT, offsetof(starter_config_t, setup.overridemtu), NULL },
{ ARG_TIME, offsetof(starter_config_t, setup.crlcheckinterval), NULL },
{ ARG_ENUM, offsetof(starter_config_t, setup.cachecrls), LST_bool },

View File

@ -1049,6 +1049,13 @@ and
Participant IDs normally \fIare\fR unique,
so a new (automatically-keyed) connection using the same ID is
almost invariably intended to replace an old one.
The IKEv2 daemon also accepts the value
.B replace
wich is identical to
.B yes
and the value
.B keep
to reject new IKE_SA setups and keep the duplicate established earlier.
.PP
The following
.B config section

View File

@ -257,6 +257,7 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn)
msg.add_conn.mobike = conn->policy & POLICY_MOBIKE;
msg.add_conn.force_encap = conn->policy & POLICY_FORCE_ENCAP;
msg.add_conn.crl_policy = cfg->setup.strictcrlpolicy;
msg.add_conn.unique = cfg->setup.uniqueids;
msg.add_conn.algorithms.ike = push_string(&msg, conn->ike);
msg.add_conn.algorithms.esp = push_string(&msg, conn->esp);
msg.add_conn.dpd.delay = conn->dpd_delay;

View File

@ -198,6 +198,7 @@ struct stroke_msg_t {
int mobike;
int force_encap;
crl_policy_t crl_policy;
int unique;
struct {
char *ike;
char *esp;