cert_policy_t cert_policy;
/**
+ * uniqueness of an IKE_SA
+ */
+ unique_policy_t unique;
+
+ /**
* Method to use for own authentication data
*/
auth_method_t auth_method;
}
/**
+ * 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.
*/
static auth_method_t get_auth_method(private_peer_cfg_t *this)
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 &&
*/
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,
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;
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;
#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>
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.
*
* The peer config defines a connection between two given IDs. It contains
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.
*
* @return authentication method
* @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
*/
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,
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;
}
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 ?
}
}
}
+ 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,
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
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;
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.
*
* Every IKE_SA and every CHILD_SA is uniquely identified by an ID.
};
/**
+ * 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
*/
static status_t build_auth(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)
{
NULL
};
+static const char *LST_unique[] = {
+ "no",
+ "yes",
+ "replace",
+ "keep",
+ NULL
+};
+
static const char *LST_strict[] = {
"no",
"yes",
{ 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 },
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
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;
int mobike;
int force_encap;
crl_policy_t crl_policy;
+ int unique;
struct {
char *ike;
char *esp;