diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/charon/config/peer_cfg.c | 18 | ||||
-rw-r--r-- | src/charon/config/peer_cfg.h | 28 | ||||
-rw-r--r-- | src/charon/plugins/sql/sql_config.c | 10 | ||||
-rw-r--r-- | src/charon/plugins/stroke/stroke_config.c | 16 | ||||
-rw-r--r-- | src/charon/sa/ike_sa_manager.c | 39 | ||||
-rw-r--r-- | src/charon/sa/ike_sa_manager.h | 8 | ||||
-rw-r--r-- | src/charon/sa/tasks/ike_auth.c | 68 | ||||
-rw-r--r-- | src/starter/args.c | 10 | ||||
-rw-r--r-- | src/starter/ipsec.conf.5 | 7 | ||||
-rw-r--r-- | src/starter/starterstroke.c | 1 | ||||
-rw-r--r-- | src/stroke/stroke_msg.h | 1 |
11 files changed, 197 insertions, 9 deletions
diff --git a/src/charon/config/peer_cfg.c b/src/charon/config/peer_cfg.c index 85fa22a1a..ca9394797 100644 --- a/src/charon/config/peer_cfg.c +++ b/src/charon/config/peer_cfg.c @@ -89,6 +89,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 */ auth_method_t auth_method; @@ -295,6 +300,14 @@ static cert_policy_t get_cert_policy(private_peer_cfg_t *this) } /** + * 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) @@ -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; diff --git a/src/charon/config/peer_cfg.h b/src/charon/config/peer_cfg.h index 29de4afa8..5e12fbfd2 100644 --- a/src/charon/config/peer_cfg.h +++ b/src/charon/config/peer_cfg.h @@ -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> @@ -63,6 +64,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. * * The peer config defines a connection between two given IDs. It contains @@ -179,6 +197,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. * * @return authentication method @@ -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, diff --git a/src/charon/plugins/sql/sql_config.c b/src/charon/plugins/sql/sql_config.c index 920268a73..930fb2471 100644 --- a/src/charon/plugins/sql/sql_config.c +++ b/src/charon/plugins/sql/sql_config.c @@ -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; } diff --git a/src/charon/plugins/stroke/stroke_config.c b/src/charon/plugins/stroke/stroke_config.c index 57349f70f..5c2cb556e 100644 --- a/src/charon/plugins/stroke/stroke_config.c +++ b/src/charon/plugins/stroke/stroke_config.c @@ -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, diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c index e3db6a691..b20cb2879 100644 --- a/src/charon/sa/ike_sa_manager.c +++ b/src/charon/sa/ike_sa_manager.c @@ -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; diff --git a/src/charon/sa/ike_sa_manager.h b/src/charon/sa/ike_sa_manager.h index f0c14d007..a91c943ed 100644 --- a/src/charon/sa/ike_sa_manager.h +++ b/src/charon/sa/ike_sa_manager.h @@ -103,6 +103,14 @@ struct ike_sa_manager_t { 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. diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index 3984936db..c3a3f3bd4 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -89,6 +89,68 @@ struct private_ike_auth_t { }; /** + * 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) @@ -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) { diff --git a/src/starter/args.c b/src/starter/args.c index 075956df9..f9e307ed7 100644 --- a/src/starter/args.c +++ b/src/starter/args.c @@ -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 }, diff --git a/src/starter/ipsec.conf.5 b/src/starter/ipsec.conf.5 index b5534efc8..db0ab98a3 100644 --- a/src/starter/ipsec.conf.5 +++ b/src/starter/ipsec.conf.5 @@ -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 diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index 025cd66f4..ddac5560b 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -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; diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h index 4ba4b5da9..068f0639f 100644 --- a/src/stroke/stroke_msg.h +++ b/src/stroke/stroke_msg.h @@ -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; |