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:
parent
a593db5d35
commit
0644ebd3de
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -309,7 +309,7 @@ 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,
|
||||
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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -687,6 +687,44 @@ static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
|
|||
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;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue