summaryrefslogtreecommitdiff
path: root/src/libcharon/sa
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa')
-rw-r--r--src/libcharon/sa/child_sa.c221
-rw-r--r--src/libcharon/sa/child_sa.h21
-rw-r--r--src/libcharon/sa/ike_sa.c305
-rw-r--r--src/libcharon/sa/ike_sa.h12
-rw-r--r--src/libcharon/sa/ike_sa_id.h2
-rw-r--r--src/libcharon/sa/ikev1/task_manager_v1.c70
-rw-r--r--src/libcharon/sa/ikev1/tasks/isakmp_delete.c5
-rw-r--r--src/libcharon/sa/ikev1/tasks/isakmp_natd.c18
-rw-r--r--src/libcharon/sa/ikev1/tasks/isakmp_vendor.c83
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_delete.c70
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.c100
-rw-r--r--src/libcharon/sa/ikev2/task_manager_v2.c210
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c301
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_delete.c32
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_rekey.c17
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_auth.c30
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_cert_pre.h2
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_delete.c8
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_init.c20
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_natd.c19
-rw-r--r--src/libcharon/sa/keymat.h2
-rw-r--r--src/libcharon/sa/task.h2
-rw-r--r--src/libcharon/sa/task_manager.h9
-rw-r--r--src/libcharon/sa/trap_manager.c40
-rw-r--r--src/libcharon/sa/trap_manager.h11
25 files changed, 1078 insertions, 532 deletions
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 463ad2e22..46e4b6f7b 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -25,6 +25,7 @@
#include <hydra.h>
#include <daemon.h>
+#include <collections/array.h>
ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
"CREATED",
@@ -79,14 +80,14 @@ struct private_child_sa_t {
u_int16_t other_cpi;
/**
- * List for local traffic selectors
+ * Array for local traffic selectors
*/
- linked_list_t *my_ts;
+ array_t *my_ts;
/**
- * List for remote traffic selectors
+ * Array for remote traffic selectors
*/
- linked_list_t *other_ts;
+ array_t *other_ts;
/**
* Protocol used to protect this SA, ESP|AH
@@ -331,10 +332,14 @@ METHOD(child_sa_t, set_proposal, void,
this->proposal = proposal->clone(proposal);
}
-METHOD(child_sa_t, get_traffic_selectors, linked_list_t*,
- private_child_sa_t *this, bool local)
+METHOD(child_sa_t, create_ts_enumerator, enumerator_t*,
+ private_child_sa_t *this, bool local)
{
- return local ? this->my_ts : this->other_ts;
+ if (local)
+ {
+ return array_create_enumerator(this->my_ts);
+ }
+ return array_create_enumerator(this->other_ts);
}
typedef struct policy_enumerator_t policy_enumerator_t;
@@ -349,8 +354,8 @@ struct policy_enumerator_t {
enumerator_t *mine;
/** enumerator over others TS */
enumerator_t *other;
- /** list of others TS, to recreate enumerator */
- linked_list_t *list;
+ /** array of others TS, to recreate enumerator */
+ array_t *array;
/** currently enumerating TS for "me" side */
traffic_selector_t *ts;
};
@@ -366,7 +371,7 @@ METHOD(enumerator_t, policy_enumerate, bool,
if (!this->other->enumerate(this->other, &other_ts))
{ /* end of others list, restart with new of mine */
this->other->destroy(this->other);
- this->other = this->list->create_enumerator(this->list);
+ this->other = array_create_enumerator(this->array);
this->ts = NULL;
continue;
}
@@ -405,9 +410,9 @@ METHOD(child_sa_t, create_policy_enumerator, enumerator_t*,
.enumerate = (void*)_policy_enumerate,
.destroy = _policy_destroy,
},
- .mine = this->my_ts->create_enumerator(this->my_ts),
- .other = this->other_ts->create_enumerator(this->other_ts),
- .list = this->other_ts,
+ .mine = array_create_enumerator(this->my_ts),
+ .other = array_create_enumerator(this->other_ts),
+ .array = this->other_ts,
.ts = NULL,
);
@@ -424,6 +429,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
{
status_t status = FAILED;
u_int64_t bytes, packets;
+ u_int32_t time;
if (inbound)
{
@@ -432,13 +438,17 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
status = hydra->kernel_interface->query_sa(hydra->kernel_interface,
this->other_addr, this->my_addr, this->my_spi,
proto_ike2ip(this->protocol), this->mark_in,
- &bytes, &packets);
+ &bytes, &packets, &time);
if (status == SUCCESS)
{
if (bytes > this->my_usebytes)
{
this->my_usebytes = bytes;
this->my_usepackets = packets;
+ if (time)
+ {
+ this->my_usetime = time;
+ }
return SUCCESS;
}
return FAILED;
@@ -452,13 +462,17 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
status = hydra->kernel_interface->query_sa(hydra->kernel_interface,
this->my_addr, this->other_addr, this->other_spi,
proto_ike2ip(this->protocol), this->mark_out,
- &bytes, &packets);
+ &bytes, &packets, &time);
if (status == SUCCESS)
{
if (bytes > this->other_usebytes)
{
this->other_usebytes = bytes;
this->other_usepackets = packets;
+ if (time)
+ {
+ this->other_usetime = time;
+ }
return SUCCESS;
}
return FAILED;
@@ -471,7 +485,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
/**
* updates the cached usetime
*/
-static void update_usetime(private_child_sa_t *this, bool inbound)
+static bool update_usetime(private_child_sa_t *this, bool inbound)
{
enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts;
@@ -511,7 +525,7 @@ static void update_usetime(private_child_sa_t *this, bool inbound)
if (last_use == 0)
{
- return;
+ return FALSE;
}
if (inbound)
{
@@ -521,18 +535,26 @@ static void update_usetime(private_child_sa_t *this, bool inbound)
{
this->other_usetime = last_use;
}
+ return TRUE;
}
METHOD(child_sa_t, get_usestats, void,
private_child_sa_t *this, bool inbound,
time_t *time, u_int64_t *bytes, u_int64_t *packets)
{
- if (update_usebytes(this, inbound) != FAILED)
+ if ((!bytes && !packets) || update_usebytes(this, inbound) != FAILED)
{
/* there was traffic since last update or the kernel interface
* does not support querying the number of usebytes.
*/
- update_usetime(this, inbound);
+ if (time)
+ {
+ if (!update_usetime(this, inbound) && !bytes && !packets)
+ {
+ /* if policy query did not yield a usetime, query SAs instead */
+ update_usebytes(this, inbound);
+ }
+ }
}
if (time)
{
@@ -590,9 +612,9 @@ METHOD(child_sa_t, alloc_cpi, u_int16_t,
}
METHOD(child_sa_t, install, status_t,
- private_child_sa_t *this, chunk_t encr, chunk_t integ, u_int32_t spi,
- u_int16_t cpi, bool inbound, bool tfcv3, linked_list_t *my_ts,
- linked_list_t *other_ts)
+ private_child_sa_t *this, chunk_t encr, chunk_t integ, u_int32_t spi,
+ u_int16_t cpi, bool initiator, bool inbound, bool tfcv3,
+ linked_list_t *my_ts, linked_list_t *other_ts)
{
u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
u_int16_t esn = NO_EXT_SEQ_NUMBERS;
@@ -668,28 +690,26 @@ METHOD(child_sa_t, install, status_t,
lifetime->time.rekey = 0;
}
- if (this->mode == MODE_BEET || this->mode == MODE_TRANSPORT)
+ /* BEET requires the bound address from the traffic selectors.
+ * TODO: We add just the first traffic selector for now, as the
+ * kernel accepts a single TS per SA only */
+ if (inbound)
{
- /* BEET requires the bound address from the traffic selectors.
- * TODO: We add just the first traffic selector for now, as the
- * kernel accepts a single TS per SA only */
- if (inbound)
- {
- my_ts->get_first(my_ts, (void**)&dst_ts);
- other_ts->get_first(other_ts, (void**)&src_ts);
- }
- else
- {
- my_ts->get_first(my_ts, (void**)&src_ts);
- other_ts->get_first(other_ts, (void**)&dst_ts);
- }
+ my_ts->get_first(my_ts, (void**)&dst_ts);
+ other_ts->get_first(other_ts, (void**)&src_ts);
+ }
+ else
+ {
+ my_ts->get_first(my_ts, (void**)&src_ts);
+ other_ts->get_first(other_ts, (void**)&dst_ts);
}
status = hydra->kernel_interface->add_sa(hydra->kernel_interface,
src, dst, spi, proto_ike2ip(this->protocol), this->reqid,
inbound ? this->mark_in : this->mark_out, tfc,
lifetime, enc_alg, encr, int_alg, integ, this->mode,
- this->ipcomp, cpi, this->encap, esn, update, src_ts, dst_ts);
+ this->ipcomp, cpi, initiator, this->encap, esn, update,
+ src_ts, dst_ts);
free(lifetime);
@@ -757,13 +777,13 @@ METHOD(child_sa_t, add_policies, status_t,
enumerator = my_ts_list->create_enumerator(my_ts_list);
while (enumerator->enumerate(enumerator, &my_ts))
{
- this->my_ts->insert_last(this->my_ts, my_ts->clone(my_ts));
+ array_insert(this->my_ts, ARRAY_TAIL, my_ts->clone(my_ts));
}
enumerator->destroy(enumerator);
enumerator = other_ts_list->create_enumerator(other_ts_list);
while (enumerator->enumerate(enumerator, &other_ts))
{
- this->other_ts->insert_last(this->other_ts, other_ts->clone(other_ts));
+ array_insert(this->other_ts, ARRAY_TAIL, other_ts->clone(other_ts));
}
enumerator->destroy(enumerator);
@@ -1054,8 +1074,8 @@ METHOD(child_sa_t, destroy, void,
enumerator->destroy(enumerator);
}
- this->my_ts->destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
- this->other_ts->destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
+ array_destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
+ array_destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
this->my_addr->destroy(this->my_addr);
this->other_addr->destroy(this->other_addr);
DESTROY_IF(this->proposal);
@@ -1064,12 +1084,47 @@ METHOD(child_sa_t, destroy, void,
}
/**
+ * Get proxy address for one side, if any
+ */
+static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local)
+{
+ host_t *host = NULL;
+ u_int8_t mask;
+ enumerator_t *enumerator;
+ linked_list_t *ts_list, *list;
+ traffic_selector_t *ts;
+
+ list = linked_list_create_with_items(ike, NULL);
+ ts_list = config->get_traffic_selectors(config, local, NULL, list);
+ list->destroy(list);
+
+ enumerator = ts_list->create_enumerator(ts_list);
+ while (enumerator->enumerate(enumerator, &ts))
+ {
+ if (ts->is_host(ts, NULL) && ts->to_subnet(ts, &host, &mask))
+ {
+ DBG1(DBG_CHD, "%s address: %H is a transport mode proxy for %H",
+ local ? "my" : "other", ike, host);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy));
+
+ if (!host)
+ {
+ host = ike->clone(ike);
+ }
+ return host;
+}
+
+/**
* Described in header.
*/
child_sa_t * child_sa_create(host_t *me, host_t* other,
child_cfg_t *config, u_int32_t rekey, bool encap)
{
- static u_int32_t reqid = 0;
+ static refcount_t reqid = 0;
private_child_sa_t *this;
INIT(this,
@@ -1102,17 +1157,15 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
.install = _install,
.update = _update,
.add_policies = _add_policies,
- .get_traffic_selectors = _get_traffic_selectors,
+ .create_ts_enumerator = _create_ts_enumerator,
.create_policy_enumerator = _create_policy_enumerator,
.destroy = _destroy,
},
- .my_addr = me->clone(me),
- .other_addr = other->clone(other),
.encap = encap,
.ipcomp = IPCOMP_NONE,
.state = CHILD_CREATED,
- .my_ts = linked_list_create(),
- .other_ts = linked_list_create(),
+ .my_ts = array_create(0, 0),
+ .other_ts = array_create(0, 0),
.protocol = PROTO_NONE,
.mode = MODE_TUNNEL,
.close_action = config->get_close_action(config),
@@ -1128,7 +1181,18 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
if (!this->reqid)
{
/* reuse old reqid if we are rekeying an existing CHILD_SA */
- this->reqid = rekey ? rekey : ++reqid;
+ if (rekey)
+ {
+ this->reqid = rekey;
+ }
+ else
+ {
+ this->reqid = charon->traps->find_reqid(charon->traps, config);
+ if (!this->reqid)
+ {
+ this->reqid = ref_get(&reqid);
+ }
+ }
}
if (this->mark_in.value == MARK_REQID)
@@ -1144,62 +1208,15 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
if (config->get_mode(config) == MODE_TRANSPORT &&
config->use_proxy_mode(config))
{
- ts_type_t type;
- int family;
- chunk_t addr;
- host_t *host;
- enumerator_t *enumerator;
- linked_list_t *my_ts_list, *other_ts_list, *list;
- traffic_selector_t *my_ts, *other_ts;
-
this->mode = MODE_TRANSPORT;
- list = linked_list_create_with_items(me, NULL);
- my_ts_list = config->get_traffic_selectors(config, TRUE, NULL, list);
- list->destroy(list);
- enumerator = my_ts_list->create_enumerator(my_ts_list);
- if (enumerator->enumerate(enumerator, &my_ts))
- {
- if (my_ts->is_host(my_ts, NULL) &&
- !my_ts->is_host(my_ts, this->my_addr))
- {
- type = my_ts->get_type(my_ts);
- family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
- addr = my_ts->get_from_address(my_ts);
- host = host_create_from_chunk(family, addr, 0);
- free(addr.ptr);
- DBG1(DBG_CHD, "my address: %H is a transport mode proxy for %H",
- this->my_addr, host);
- this->my_addr->destroy(this->my_addr);
- this->my_addr = host;
- }
- }
- enumerator->destroy(enumerator);
- my_ts_list->destroy_offset(my_ts_list, offsetof(traffic_selector_t, destroy));
-
- list = linked_list_create_with_items(other, NULL);
- other_ts_list = config->get_traffic_selectors(config, FALSE, NULL, list);
- list->destroy(list);
- enumerator = other_ts_list->create_enumerator(other_ts_list);
- if (enumerator->enumerate(enumerator, &other_ts))
- {
- if (other_ts->is_host(other_ts, NULL) &&
- !other_ts->is_host(other_ts, this->other_addr))
- {
- type = other_ts->get_type(other_ts);
- family = (type == TS_IPV4_ADDR_RANGE) ? AF_INET : AF_INET6;
- addr = other_ts->get_from_address(other_ts);
- host = host_create_from_chunk(family, addr, 0);
- free(addr.ptr);
- DBG1(DBG_CHD, "other address: %H is a transport mode proxy for %H",
- this->other_addr, host);
- this->other_addr->destroy(this->other_addr);
- this->other_addr = host;
- }
- }
- enumerator->destroy(enumerator);
- other_ts_list->destroy_offset(other_ts_list, offsetof(traffic_selector_t, destroy));
+ this->my_addr = get_proxy_addr(config, me, TRUE);
+ this->other_addr = get_proxy_addr(config, other, FALSE);
+ }
+ else
+ {
+ this->my_addr = me->clone(me);
+ this->other_addr = other->clone(other);
}
-
return &this->public;
}
diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h
index 44511edf8..ed52d60b1 100644
--- a/src/libcharon/sa/child_sa.h
+++ b/src/libcharon/sa/child_sa.h
@@ -231,7 +231,7 @@ struct child_sa_t {
/**
* Override the DPD action specified by the CHILD_SA config.
*
- * @param close action to enforce
+ * @param dpd action to enforce
*/
void (*set_dpd_action)(child_sa_t *this, action_t action);
@@ -284,17 +284,20 @@ struct child_sa_t {
mark_t (*get_mark)(child_sa_t *this, bool inbound);
/**
- * Get the traffic selectors list added for one side.
+ * Create an enumerator over traffic selectors of one side.
*
- * @param local TRUE for own traffic selectors, FALSE for remote
- * @return list of traffic selectors
+ * @param local TRUE for own traffic selectors, FALSE for remote.
+ * @return enumerator over traffic_selector_t*
*/
- linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local);
+ enumerator_t* (*create_ts_enumerator)(child_sa_t *this, bool local);
/**
* Create an enumerator over installed policies.
*
- * @return enumerator over pairs of traffic selectors.
+ * The enumerated traffic selectors is a full mesh of compatible local
+ * and remote traffic selectors.
+ *
+ * @return enumerator over a pair of traffic_selector_t*
*/
enumerator_t* (*create_policy_enumerator)(child_sa_t *this);
@@ -321,6 +324,7 @@ struct child_sa_t {
* @param integ integrity key
* @param spi SPI to use, allocated for inbound
* @param cpi CPI to use, allocated for outbound
+ * @param initiator TRUE if initiator of exchange resulting in this SA
* @param inbound TRUE to install an inbound SA, FALSE for outbound
* @param tfcv3 TRUE if peer supports ESPv3 TFC
* @param my_ts negotiated local traffic selector list
@@ -328,7 +332,8 @@ struct child_sa_t {
* @return SUCCESS or FAILED
*/
status_t (*install)(child_sa_t *this, chunk_t encr, chunk_t integ,
- u_int32_t spi, u_int16_t cpi, bool inbound, bool tfcv3,
+ u_int32_t spi, u_int16_t cpi,
+ bool initiator, bool inbound, bool tfcv3,
linked_list_t *my_ts, linked_list_t *other_ts);
/**
* Install the policies using some traffic selectors.
@@ -348,7 +353,7 @@ struct child_sa_t {
* @param me the new local host
* @param other the new remote host
* @param vips list of local virtual IPs
- * @param TRUE to use UDP encapsulation for NAT traversal
+ * @param encap TRUE to use UDP encapsulation for NAT traversal
* @return SUCCESS or FAILED
*/
status_t (*update)(child_sa_t *this, host_t *me, host_t *other,
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index 63c04d9c0..2f4e1123c 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2012 Tobias Brunner
+ * Copyright (C) 2006-2013 Tobias Brunner
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
@@ -26,7 +26,7 @@
#include <library.h>
#include <hydra.h>
#include <daemon.h>
-#include <collections/linked_list.h>
+#include <collections/array.h>
#include <utils/lexparser.h>
#include <processing/jobs/retransmit_job.h>
#include <processing/jobs/delete_ike_sa_job.h>
@@ -95,24 +95,24 @@ struct private_ike_sa_t {
peer_cfg_t *peer_cfg;
/**
- * currently used authentication ruleset, local (as auth_cfg_t)
+ * currently used authentication ruleset, local
*/
auth_cfg_t *my_auth;
/**
- * list of completed local authentication rounds
+ * currently used authentication constraints, remote
*/
- linked_list_t *my_auths;
+ auth_cfg_t *other_auth;
/**
- * list of completed remote authentication rounds
+ * Array of completed local authentication rounds (as auth_cfg_t)
*/
- linked_list_t *other_auths;
+ array_t *my_auths;
/**
- * currently used authentication constraints, remote (as auth_cfg_t)
+ * Array of completed remote authentication rounds (as auth_cfg_t)
*/
- auth_cfg_t *other_auth;
+ array_t *other_auths;
/**
* Selected IKE proposal
@@ -172,9 +172,9 @@ struct private_ike_sa_t {
ike_condition_t conditions;
/**
- * Linked List containing the child sa's of the current IKE_SA.
+ * Array containing the child sa's of the current IKE_SA.
*/
- linked_list_t *child_sas;
+ array_t *child_sas;
/**
* keymat of this IKE_SA
@@ -184,22 +184,22 @@ struct private_ike_sa_t {
/**
* Virtual IPs on local host
*/
- linked_list_t *my_vips;
+ array_t *my_vips;
/**
* Virtual IPs on remote host
*/
- linked_list_t *other_vips;
+ array_t *other_vips;
/**
* List of configuration attributes (attribute_entry_t)
*/
- linked_list_t *attributes;
+ array_t *attributes;
/**
* list of peer's addresses, additional ones transmitted via MOBIKE
*/
- linked_list_t *peer_addresses;
+ array_t *peer_addresses;
/**
* previously value of received DESTINATION_IP hash
@@ -282,7 +282,8 @@ static time_t get_use_time(private_ike_sa_t* this, bool inbound)
{
use_time = this->stats[STAT_OUTBOUND];
}
- enumerator = this->child_sas->create_enumerator(this->child_sas);
+
+ enumerator = array_create_enumerator(this->child_sas);
while (enumerator->enumerate(enumerator, &child_sa))
{
child_sa->get_usestats(child_sa, inbound, &current, NULL, NULL);
@@ -389,11 +390,11 @@ METHOD(ike_sa_t, add_auth_cfg, void,
{
if (local)
{
- this->my_auths->insert_last(this->my_auths, cfg);
+ array_insert(this->my_auths, ARRAY_TAIL, cfg);
}
else
{
- this->other_auths->insert_last(this->other_auths, cfg);
+ array_insert(this->other_auths, ARRAY_TAIL, cfg);
}
}
@@ -402,9 +403,9 @@ METHOD(ike_sa_t, create_auth_cfg_enumerator, enumerator_t*,
{
if (local)
{
- return this->my_auths->create_enumerator(this->my_auths);
+ return array_create_enumerator(this->my_auths);
}
- return this->other_auths->create_enumerator(this->other_auths);
+ return array_create_enumerator(this->other_auths);
}
/**
@@ -417,13 +418,11 @@ static void flush_auth_cfgs(private_ike_sa_t *this)
this->my_auth->purge(this->my_auth, FALSE);
this->other_auth->purge(this->other_auth, FALSE);
- while (this->my_auths->remove_last(this->my_auths,
- (void**)&cfg) == SUCCESS)
+ while (array_remove(this->my_auths, ARRAY_TAIL, &cfg))
{
cfg->destroy(cfg);
}
- while (this->other_auths->remove_last(this->other_auths,
- (void**)&cfg) == SUCCESS)
+ while (array_remove(this->other_auths, ARRAY_TAIL, &cfg))
{
cfg->destroy(cfg);
}
@@ -750,7 +749,7 @@ METHOD(ike_sa_t, add_virtual_ip, void,
if (hydra->kernel_interface->add_ip(hydra->kernel_interface,
ip, -1, iface) == SUCCESS)
{
- this->my_vips->insert_last(this->my_vips, ip->clone(ip));
+ array_insert_create(&this->my_vips, ARRAY_TAIL, ip->clone(ip));
}
else
{
@@ -765,7 +764,7 @@ METHOD(ike_sa_t, add_virtual_ip, void,
}
else
{
- this->other_vips->insert_last(this->other_vips, ip->clone(ip));
+ array_insert_create(&this->other_vips, ARRAY_TAIL, ip->clone(ip));
}
}
@@ -773,14 +772,15 @@ METHOD(ike_sa_t, add_virtual_ip, void,
METHOD(ike_sa_t, clear_virtual_ips, void,
private_ike_sa_t *this, bool local)
{
- linked_list_t *vips = local ? this->my_vips : this->other_vips;
+ array_t *vips;
host_t *vip;
- if (!local && vips->get_count(vips))
+ vips = local ? this->my_vips : this->other_vips;
+ if (!local && array_count(vips))
{
charon->bus->assign_vips(charon->bus, &this->public, FALSE);
}
- while (vips->remove_first(vips, (void**)&vip) == SUCCESS)
+ while (array_remove(vips, ARRAY_HEAD, &vip))
{
if (local)
{
@@ -796,23 +796,23 @@ METHOD(ike_sa_t, create_virtual_ip_enumerator, enumerator_t*,
{
if (local)
{
- return this->my_vips->create_enumerator(this->my_vips);
+ return array_create_enumerator(this->my_vips);
}
- return this->other_vips->create_enumerator(this->other_vips);
+ return array_create_enumerator(this->other_vips);
}
METHOD(ike_sa_t, add_peer_address, void,
private_ike_sa_t *this, host_t *host)
{
- this->peer_addresses->insert_last(this->peer_addresses, host);
+ array_insert_create(&this->peer_addresses, ARRAY_TAIL, host);
}
METHOD(ike_sa_t, create_peer_address_enumerator, enumerator_t*,
private_ike_sa_t *this)
{
- if (this->peer_addresses->get_count(this->peer_addresses))
+ if (this->peer_addresses)
{
- return this->peer_addresses->create_enumerator(this->peer_addresses);
+ return array_create_enumerator(this->peer_addresses);
}
/* in case we don't have MOBIKE */
return enumerator_create_single(this->other_host, NULL);
@@ -821,17 +821,8 @@ METHOD(ike_sa_t, create_peer_address_enumerator, enumerator_t*,
METHOD(ike_sa_t, clear_peer_addresses, void,
private_ike_sa_t *this)
{
- enumerator_t *enumerator;
- host_t *host;
-
- enumerator = this->peer_addresses->create_enumerator(this->peer_addresses);
- while (enumerator->enumerate(enumerator, (void**)&host))
- {
- this->peer_addresses->remove_at(this->peer_addresses,
- enumerator);
- host->destroy(host);
- }
- enumerator->destroy(enumerator);
+ array_destroy_offset(this->peer_addresses, offsetof(host_t, destroy));
+ this->peer_addresses = NULL;
}
METHOD(ike_sa_t, has_mapping_changed, bool,
@@ -927,13 +918,16 @@ METHOD(ike_sa_t, update_hosts, void,
{
enumerator_t *enumerator;
child_sa_t *child_sa;
+ linked_list_t *vips;
- enumerator = this->child_sas->create_enumerator(this->child_sas);
- while (enumerator->enumerate(enumerator, (void**)&child_sa))
+ vips = linked_list_create_from_enumerator(
+ array_create_enumerator(this->my_vips));
+
+ enumerator = array_create_enumerator(this->child_sas);
+ while (enumerator->enumerate(enumerator, &child_sa))
{
- if (child_sa->update(child_sa, this->my_host,
- this->other_host, this->my_vips,
- has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED)
+ if (child_sa->update(child_sa, this->my_host, this->other_host,
+ vips, has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED)
{
this->public.rekey_child_sa(&this->public,
child_sa->get_protocol(child_sa),
@@ -941,6 +935,8 @@ METHOD(ike_sa_t, update_hosts, void,
}
}
enumerator->destroy(enumerator);
+
+ vips->destroy(vips);
}
}
@@ -1081,6 +1077,20 @@ METHOD(ike_sa_t, initiate_mediated, status_t,
static void resolve_hosts(private_ike_sa_t *this)
{
host_t *host;
+ int family = 0;
+
+ switch (charon->socket->supported_families(charon->socket))
+ {
+ case SOCKET_FAMILY_IPV4:
+ family = AF_INET;
+ break;
+ case SOCKET_FAMILY_IPV6:
+ family = AF_INET6;
+ break;
+ case SOCKET_FAMILY_BOTH:
+ case SOCKET_FAMILY_NONE:
+ break;
+ }
if (this->remote_host)
{
@@ -1094,7 +1104,7 @@ static void resolve_hosts(private_ike_sa_t *this)
other_addr = this->ike_cfg->get_other_addr(this->ike_cfg, NULL);
other_port = this->ike_cfg->get_other_port(this->ike_cfg);
- host = host_create_from_dns(other_addr, 0, other_port);
+ host = host_create_from_dns(other_addr, family, other_port);
}
if (host)
{
@@ -1110,7 +1120,6 @@ static void resolve_hosts(private_ike_sa_t *this)
{
char *my_addr;
u_int16_t my_port;
- int family = 0;
/* use same address family as for other */
if (!this->other_host->is_anyaddr(this->other_host))
@@ -1133,7 +1142,7 @@ static void resolve_hosts(private_ike_sa_t *this)
}
else
{ /* fallback to address family specific %any(6), if configured */
- host = host_create_from_dns(my_addr, 0, my_port);
+ host = host_create_from_dns(my_addr, family, my_port);
}
}
}
@@ -1313,7 +1322,7 @@ METHOD(ike_sa_t, get_other_eap_id, identification_t*,
enumerator_t *enumerator;
auth_cfg_t *cfg;
- enumerator = this->other_auths->create_enumerator(this->other_auths);
+ enumerator = array_create_enumerator(this->other_auths);
while (enumerator->enumerate(enumerator, &cfg))
{
/* prefer EAP-Identity of last round */
@@ -1350,7 +1359,7 @@ METHOD(ike_sa_t, set_other_id, void,
METHOD(ike_sa_t, add_child_sa, void,
private_ike_sa_t *this, child_sa_t *child_sa)
{
- this->child_sas->insert_last(this->child_sas, child_sa);
+ array_insert_create(&this->child_sas, ARRAY_TAIL, child_sa);
}
METHOD(ike_sa_t, get_child_sa, child_sa_t*,
@@ -1359,7 +1368,7 @@ METHOD(ike_sa_t, get_child_sa, child_sa_t*,
enumerator_t *enumerator;
child_sa_t *current, *found = NULL;
- enumerator = this->child_sas->create_enumerator(this->child_sas);
+ enumerator = array_create_enumerator(this->child_sas);
while (enumerator->enumerate(enumerator, (void**)&current))
{
if (current->get_spi(current, inbound) == spi &&
@@ -1375,19 +1384,19 @@ METHOD(ike_sa_t, get_child_sa, child_sa_t*,
METHOD(ike_sa_t, get_child_count, int,
private_ike_sa_t *this)
{
- return this->child_sas->get_count(this->child_sas);
+ return array_count(this->child_sas);
}
METHOD(ike_sa_t, create_child_sa_enumerator, enumerator_t*,
private_ike_sa_t *this)
{
- return this->child_sas->create_enumerator(this->child_sas);
+ return array_create_enumerator(this->child_sas);
}
METHOD(ike_sa_t, remove_child_sa, void,
private_ike_sa_t *this, enumerator_t *enumerator)
{
- this->child_sas->remove_at(this->child_sas, enumerator);
+ array_remove_at(this->child_sas, enumerator);
}
METHOD(ike_sa_t, rekey_child_sa, status_t,
@@ -1420,13 +1429,13 @@ METHOD(ike_sa_t, destroy_child_sa, status_t,
child_sa_t *child_sa;
status_t status = NOT_FOUND;
- enumerator = this->child_sas->create_enumerator(this->child_sas);
+ enumerator = array_create_enumerator(this->child_sas);
while (enumerator->enumerate(enumerator, (void**)&child_sa))
{
if (child_sa->get_protocol(child_sa) == protocol &&
child_sa->get_spi(child_sa, TRUE) == spi)
{
- this->child_sas->remove_at(this->child_sas, enumerator);
+ array_remove_at(this->child_sas, enumerator);
child_sa->destroy(child_sa);
status = SUCCESS;
break;
@@ -1493,7 +1502,7 @@ METHOD(ike_sa_t, reauth, status_t,
if (!has_condition(this, COND_ORIGINAL_INITIATOR))
{
DBG1(DBG_IKE, "initiator did not reauthenticate as requested");
- if (this->other_vips->get_count(this->other_vips) != 0 ||
+ if (array_count(this->other_vips) != 0 ||
has_condition(this, COND_XAUTH_AUTHENTICATED) ||
has_condition(this, COND_EAP_AUTHENTICATED)
#ifdef ME
@@ -1526,6 +1535,30 @@ METHOD(ike_sa_t, reauth, status_t,
return this->task_manager->initiate(this->task_manager);
}
+/**
+ * Check if tasks to create CHILD_SAs are queued in the given queue
+ */
+static bool is_child_queued(private_ike_sa_t *this, task_queue_t queue)
+{
+ enumerator_t *enumerator;
+ task_t *task;
+ bool found = FALSE;
+
+ enumerator = this->task_manager->create_task_enumerator(this->task_manager,
+ queue);
+ while (enumerator->enumerate(enumerator, &task))
+ {
+ if (task->get_type(task) == TASK_CHILD_CREATE ||
+ task->get_type(task) == TASK_QUICK_MODE)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return found;
+}
+
METHOD(ike_sa_t, reestablish, status_t,
private_ike_sa_t *this)
{
@@ -1540,7 +1573,7 @@ METHOD(ike_sa_t, reestablish, status_t,
if (has_condition(this, COND_REAUTHENTICATING))
{ /* only reauthenticate if we have children */
- if (this->child_sas->get_count(this->child_sas) == 0
+ if (array_count(this->child_sas) == 0
#ifdef ME
/* allow reauth of mediation connections without CHILD_SAs */
&& !this->peer_cfg->is_mediation(this->peer_cfg)
@@ -1557,7 +1590,7 @@ METHOD(ike_sa_t, reestablish, status_t,
}
else
{ /* check if we have children to keep up at all */
- enumerator = this->child_sas->create_enumerator(this->child_sas);
+ enumerator = array_create_enumerator(this->child_sas);
while (enumerator->enumerate(enumerator, (void**)&child_sa))
{
if (this->state == IKE_DELETING)
@@ -1575,13 +1608,20 @@ METHOD(ike_sa_t, reestablish, status_t,
break;
case ACTION_ROUTE:
charon->traps->install(charon->traps, this->peer_cfg,
- child_sa->get_config(child_sa));
+ child_sa->get_config(child_sa),
+ child_sa->get_reqid(child_sa));
break;
default:
break;
}
}
enumerator->destroy(enumerator);
+ /* check if we have tasks that recreate children */
+ if (!restart)
+ {
+ restart = is_child_queued(this, TASK_QUEUE_ACTIVE) ||
+ is_child_queued(this, TASK_QUEUE_QUEUED);
+ }
#ifdef ME
/* mediation connections have no children, keep them up anyway */
if (this->peer_cfg->is_mediation(this->peer_cfg))
@@ -1597,7 +1637,7 @@ METHOD(ike_sa_t, reestablish, status_t,
/* check if we are able to reestablish this IKE_SA */
if (!has_condition(this, COND_ORIGINAL_INITIATOR) &&
- (this->other_vips->get_count(this->other_vips) != 0 ||
+ (array_count(this->other_vips) != 0 ||
has_condition(this, COND_EAP_AUTHENTICATED)
#ifdef ME
|| this->is_mediation_server
@@ -1620,7 +1660,7 @@ METHOD(ike_sa_t, reestablish, status_t,
host = this->my_host;
new->set_my_host(new, host->clone(host));
/* if we already have a virtual IP, we reuse it */
- enumerator = this->my_vips->create_enumerator(this->my_vips);
+ enumerator = array_create_enumerator(this->my_vips);
while (enumerator->enumerate(enumerator, &host))
{
new->add_virtual_ip(new, TRUE, host);
@@ -1635,7 +1675,8 @@ METHOD(ike_sa_t, reestablish, status_t,
else
#endif /* ME */
{
- enumerator = this->child_sas->create_enumerator(this->child_sas);
+ /* handle existing CHILD_SAs */
+ enumerator = array_create_enumerator(this->child_sas);
while (enumerator->enumerate(enumerator, (void**)&child_sa))
{
if (has_condition(this, COND_REAUTHENTICATING))
@@ -1644,7 +1685,7 @@ METHOD(ike_sa_t, reestablish, status_t,
{
case CHILD_ROUTED:
{ /* move routed child directly */
- this->child_sas->remove_at(this->child_sas, enumerator);
+ array_remove_at(this->child_sas, enumerator);
new->add_child_sa(new, child_sa);
action = ACTION_NONE;
break;
@@ -1674,7 +1715,8 @@ METHOD(ike_sa_t, reestablish, status_t,
DBG1(DBG_IKE, "restarting CHILD_SA %s",
child_cfg->get_name(child_cfg));
child_cfg->get_ref(child_cfg);
- status = new->initiate(new, child_cfg, 0, NULL, NULL);
+ status = new->initiate(new, child_cfg,
+ child_sa->get_reqid(child_sa), NULL, NULL);
break;
default:
continue;
@@ -1685,6 +1727,16 @@ METHOD(ike_sa_t, reestablish, status_t,
}
}
enumerator->destroy(enumerator);
+ /* adopt any active or queued CHILD-creating tasks */
+ if (status != DESTROY_ME)
+ {
+ task_manager_t *other_tasks = ((private_ike_sa_t*)new)->task_manager;
+ other_tasks->adopt_child_tasks(other_tasks, this->task_manager);
+ if (new->get_state(new) == IKE_CREATED)
+ {
+ status = new->initiate(new, NULL, 0, NULL, NULL);
+ }
+ }
}
if (status == DESTROY_ME)
@@ -1774,7 +1826,7 @@ METHOD(ike_sa_t, set_auth_lifetime, status_t,
* We send the notify in IKE_AUTH if not yet ESTABLISHED. */
send_update = this->state == IKE_ESTABLISHED && this->version == IKEV2 &&
!has_condition(this, COND_ORIGINAL_INITIATOR) &&
- (this->other_vips->get_count(this->other_vips) != 0 ||
+ (array_count(this->other_vips) != 0 ||
has_condition(this, COND_EAP_AUTHENTICATED));
if (lifetime < diff)
@@ -1948,13 +2000,12 @@ METHOD(ike_sa_t, add_configuration_attribute, void,
private_ike_sa_t *this, attribute_handler_t *handler,
configuration_attribute_type_t type, chunk_t data)
{
- attribute_entry_t *entry = malloc_thing(attribute_entry_t);
-
- entry->handler = handler;
- entry->type = type;
- entry->data = chunk_clone(data);
-
- this->attributes->insert_last(this->attributes, entry);
+ attribute_entry_t entry = {
+ .handler = handler,
+ .type = type,
+ .data = chunk_clone(data),
+ };
+ array_insert(this->attributes, ARRAY_TAIL, &entry);
}
METHOD(ike_sa_t, create_task_enumerator, enumerator_t*,
@@ -1980,8 +2031,8 @@ METHOD(ike_sa_t, inherit, void,
{
private_ike_sa_t *other = (private_ike_sa_t*)other_public;
child_sa_t *child_sa;
- attribute_entry_t *entry;
enumerator_t *enumerator;
+ attribute_entry_t entry;
auth_cfg_t *cfg;
host_t *vip;
@@ -1996,35 +2047,33 @@ METHOD(ike_sa_t, inherit, void,
this->other_id = other->other_id->clone(other->other_id);
/* apply assigned virtual IPs... */
- while (other->my_vips->remove_last(other->my_vips, (void**)&vip) == SUCCESS)
+ while (array_remove(other->my_vips, ARRAY_HEAD, &vip))
{
- this->my_vips->insert_first(this->my_vips, vip);
+ array_insert_create(&this->my_vips, ARRAY_TAIL, vip);
}
- while (other->other_vips->remove_last(other->other_vips,
- (void**)&vip) == SUCCESS)
+ while (array_remove(other->other_vips, ARRAY_HEAD, &vip))
{
- this->other_vips->insert_first(this->other_vips, vip);
+ array_insert_create(&this->other_vips, ARRAY_TAIL, vip);
}
/* authentication information */
- enumerator = other->my_auths->create_enumerator(other->my_auths);
+ enumerator = array_create_enumerator(other->my_auths);
while (enumerator->enumerate(enumerator, &cfg))
{
- this->my_auths->insert_last(this->my_auths, cfg->clone(cfg));
+ array_insert(this->my_auths, ARRAY_TAIL, cfg->clone(cfg));
}
enumerator->destroy(enumerator);
- enumerator = other->other_auths->create_enumerator(other->other_auths);
+ enumerator = array_create_enumerator(other->other_auths);
while (enumerator->enumerate(enumerator, &cfg))
{
- this->other_auths->insert_last(this->other_auths, cfg->clone(cfg));
+ array_insert(this->other_auths, ARRAY_TAIL, cfg->clone(cfg));
}
enumerator->destroy(enumerator);
/* ... and configuration attributes */
- while (other->attributes->remove_last(other->attributes,
- (void**)&entry) == SUCCESS)
+ while (array_remove(other->attributes, ARRAY_HEAD, &entry))
{
- this->attributes->insert_first(this->attributes, entry);
+ array_insert(this->attributes, ARRAY_TAIL, &entry);
}
/* inherit all conditions */
@@ -2047,10 +2096,9 @@ METHOD(ike_sa_t, inherit, void,
#endif /* ME */
/* adopt all children */
- while (other->child_sas->remove_last(other->child_sas,
- (void**)&child_sa) == SUCCESS)
+ while (array_remove(other->child_sas, ARRAY_HEAD, &child_sa))
{
- this->child_sas->insert_first(this->child_sas, (void*)child_sa);
+ array_insert_create(&this->child_sas, ARRAY_TAIL, child_sa);
}
/* move pending tasks to the new IKE_SA */
@@ -2077,7 +2125,8 @@ METHOD(ike_sa_t, inherit, void,
METHOD(ike_sa_t, destroy, void,
private_ike_sa_t *this)
{
- attribute_entry_t *entry;
+ attribute_entry_t entry;
+ child_sa_t *child_sa;
host_t *vip;
charon->bus->set_sa(charon->bus, &this->public);
@@ -2086,35 +2135,28 @@ METHOD(ike_sa_t, destroy, void,
DESTROY_IF(this->task_manager);
/* remove attributes first, as we pass the IKE_SA to the handler */
- while (this->attributes->remove_last(this->attributes,
- (void**)&entry) == SUCCESS)
+ while (array_remove(this->attributes, ARRAY_TAIL, &entry))
{
- hydra->attributes->release(hydra->attributes, entry->handler,
- this->other_id, entry->type, entry->data);
- free(entry->data.ptr);
- free(entry);
+ hydra->attributes->release(hydra->attributes, entry.handler,
+ this->other_id, entry.type, entry.data);
+ free(entry.data.ptr);
}
- this->attributes->destroy(this->attributes);
-
- this->child_sas->destroy_offset(this->child_sas, offsetof(child_sa_t, destroy));
-
- /* unset SA after here to avoid usage by the listeners */
- charon->bus->set_sa(charon->bus, NULL);
-
- DESTROY_IF(this->keymat);
-
- while (this->my_vips->remove_last(this->my_vips, (void**)&vip) == SUCCESS)
+ /* uninstall CHILD_SAs before virtual IPs, otherwise we might kill
+ * routes that the CHILD_SA tries to uninstall. */
+ while (array_remove(this->child_sas, ARRAY_TAIL, &child_sa))
+ {
+ child_sa->destroy(child_sa);
+ }
+ while (array_remove(this->my_vips, ARRAY_TAIL, &vip))
{
hydra->kernel_interface->del_ip(hydra->kernel_interface, vip, -1, TRUE);
vip->destroy(vip);
}
- this->my_vips->destroy(this->my_vips);
- if (this->other_vips->get_count(this->other_vips))
+ if (array_count(this->other_vips))
{
charon->bus->assign_vips(charon->bus, &this->public, FALSE);
}
- while (this->other_vips->remove_last(this->other_vips,
- (void**)&vip) == SUCCESS)
+ while (array_remove(this->other_vips, ARRAY_TAIL, &vip))
{
if (this->peer_cfg)
{
@@ -2129,9 +2171,16 @@ METHOD(ike_sa_t, destroy, void,
}
vip->destroy(vip);
}
- this->other_vips->destroy(this->other_vips);
- this->peer_addresses->destroy_offset(this->peer_addresses,
- offsetof(host_t, destroy));
+
+ /* unset SA after here to avoid usage by the listeners */
+ charon->bus->set_sa(charon->bus, NULL);
+
+ array_destroy(this->child_sas);
+ DESTROY_IF(this->keymat);
+ array_destroy(this->attributes);
+ array_destroy(this->my_vips);
+ array_destroy(this->other_vips);
+ array_destroy_offset(this->peer_addresses, offsetof(host_t, destroy));
#ifdef ME
if (this->is_mediation_server)
{
@@ -2155,10 +2204,8 @@ METHOD(ike_sa_t, destroy, void,
DESTROY_IF(this->proposal);
this->my_auth->destroy(this->my_auth);
this->other_auth->destroy(this->other_auth);
- this->my_auths->destroy_offset(this->my_auths,
- offsetof(auth_cfg_t, destroy));
- this->other_auths->destroy_offset(this->other_auths,
- offsetof(auth_cfg_t, destroy));
+ array_destroy_offset(this->my_auths, offsetof(auth_cfg_t, destroy));
+ array_destroy_offset(this->other_auths, offsetof(auth_cfg_t, destroy));
this->ike_sa_id->destroy(this->ike_sa_id);
free(this);
@@ -2171,7 +2218,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
ike_version_t version)
{
private_ike_sa_t *this;
- static u_int32_t unique_id = 0;
+ static refcount_t unique_id = 0;
if (version == IKE_ANY)
{ /* prefer IKEv2 if protocol not specified */
@@ -2270,7 +2317,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
},
.ike_sa_id = ike_sa_id->clone(ike_sa_id),
.version = version,
- .child_sas = linked_list_create(),
.my_host = host_create_any(AF_INET),
.other_host = host_create_any(AF_INET),
.my_id = identification_create_from_encoding(ID_ANY, chunk_empty),
@@ -2281,13 +2327,10 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
.stats[STAT_OUTBOUND] = time_monotonic(NULL),
.my_auth = auth_cfg_create(),
.other_auth = auth_cfg_create(),
- .my_auths = linked_list_create(),
- .other_auths = linked_list_create(),
- .unique_id = ++unique_id,
- .peer_addresses = linked_list_create(),
- .my_vips = linked_list_create(),
- .other_vips = linked_list_create(),
- .attributes = linked_list_create(),
+ .my_auths = array_create(0, 0),
+ .other_auths = array_create(0, 0),
+ .attributes = array_create(sizeof(attribute_entry_t), 0),
+ .unique_id = ref_get(&unique_id),
.keepalive_interval = lib->settings->get_time(lib->settings,
"%s.keep_alive", KEEPALIVE_INTERVAL, charon->name),
.retry_initiate_interval = lib->settings->get_time(lib->settings,
diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h
index 625859a3f..00c16c05e 100644
--- a/src/libcharon/sa/ike_sa.h
+++ b/src/libcharon/sa/ike_sa.h
@@ -200,11 +200,11 @@ enum ike_condition_t {
enum statistic_t {
/** Timestamp of SA establishement */
STAT_ESTABLISHED = 0,
- /** Timestamp of scheudled rekeying */
+ /** Timestamp of scheduled rekeying */
STAT_REKEY,
- /** Timestamp of scheudled reauthentication */
+ /** Timestamp of scheduled reauthentication */
STAT_REAUTH,
- /** Timestamp of scheudled delete */
+ /** Timestamp of scheduled delete */
STAT_DELETE,
/** Timestamp of last inbound IKE packet */
STAT_INBOUND,
@@ -812,10 +812,8 @@ struct ike_sa_t {
/**
* Sends a keep alive packet.
*
- * To refresh NAT tables in a NAT router
- * between the peers, periodic empty
- * UDP packets are sent if no other traffic
- * was sent.
+ * To refresh NAT tables in a NAT router between the peers, periodic empty
+ * UDP packets are sent if no other traffic was sent.
*/
void (*send_keepalive) (ike_sa_t *this);
diff --git a/src/libcharon/sa/ike_sa_id.h b/src/libcharon/sa/ike_sa_id.h
index 227683d1c..5eb754e95 100644
--- a/src/libcharon/sa/ike_sa_id.h
+++ b/src/libcharon/sa/ike_sa_id.h
@@ -86,7 +86,7 @@ struct ike_sa_id_t {
bool (*equals) (ike_sa_id_t *this, ike_sa_id_t *other);
/**
- * Replace all values of a given ike_sa_id_t object with values.
+ * Replace all values of a given ike_sa_id_t object with values
* from another ike_sa_id_t object.
*
* After calling this function, both objects are equal.
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index 709033cb5..857cb027e 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -1753,21 +1753,22 @@ METHOD(task_manager_t, queue_child, void,
/**
* Check if two CHILD_SAs have the same traffic selector
*/
-static bool have_equal_ts(child_sa_t *a, child_sa_t *b, bool local)
+static bool have_equal_ts(child_sa_t *child1, child_sa_t *child2, bool local)
{
- linked_list_t *list;
- traffic_selector_t *ts_a, *ts_b;
+ enumerator_t *e1, *e2;
+ traffic_selector_t *ts1, *ts2;
+ bool equal = FALSE;
- list = a->get_traffic_selectors(a, local);
- if (list->get_first(list, (void**)&ts_a) == SUCCESS)
+ e1 = child1->create_ts_enumerator(child1, local);
+ e2 = child2->create_ts_enumerator(child2, local);
+ if (e1->enumerate(e1, &ts1) && e2->enumerate(e2, &ts2))
{
- list = b->get_traffic_selectors(b, local);
- if (list->get_first(list, (void**)&ts_b) == SUCCESS)
- {
- return ts_a->equals(ts_a, ts_b);
- }
+ equal = ts1->equals(ts1, ts2);
}
- return FALSE;
+ e1->destroy(e1);
+ e1->destroy(e1);
+
+ return equal;
}
/**
@@ -1806,14 +1807,13 @@ static bool is_redundant(private_task_manager_t *this, child_sa_t *child_sa)
static traffic_selector_t* get_first_ts(child_sa_t *child_sa, bool local)
{
traffic_selector_t *ts = NULL;
- linked_list_t *list;
+ enumerator_t *enumerator;
- list = child_sa->get_traffic_selectors(child_sa, local);
- if (list->get_first(list, (void**)&ts) == SUCCESS)
- {
- return ts;
- }
- return NULL;
+ enumerator = child_sa->create_ts_enumerator(child_sa, local);
+ enumerator->enumerate(enumerator, &ts);
+ enumerator->destroy(enumerator);
+
+ return ts;
}
METHOD(task_manager_t, queue_child_rekey, void,
@@ -1900,6 +1900,39 @@ METHOD(task_manager_t, adopt_tasks, void,
}
}
+/**
+ * Migrates child-creating tasks from src to dst
+ */
+static void migrate_child_tasks(private_task_manager_t *this,
+ linked_list_t *src, linked_list_t *dst)
+{
+ enumerator_t *enumerator;
+ task_t *task;
+
+ enumerator = src->create_enumerator(src);
+ while (enumerator->enumerate(enumerator, &task))
+ {
+ if (task->get_type(task) == TASK_QUICK_MODE)
+ {
+ src->remove_at(src, enumerator);
+ task->migrate(task, this->ike_sa);
+ dst->insert_last(dst, task);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+METHOD(task_manager_t, adopt_child_tasks, void,
+ private_task_manager_t *this, task_manager_t *other_public)
+{
+ private_task_manager_t *other = (private_task_manager_t*)other_public;
+
+ /* move active child tasks from other to this */
+ migrate_child_tasks(this, other->active_tasks, this->queued_tasks);
+ /* do the same for queued tasks */
+ migrate_child_tasks(this, other->queued_tasks, this->queued_tasks);
+}
+
METHOD(task_manager_t, busy, bool,
private_task_manager_t *this)
{
@@ -2014,6 +2047,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
.incr_mid = _incr_mid,
.reset = _reset,
.adopt_tasks = _adopt_tasks,
+ .adopt_child_tasks = _adopt_child_tasks,
.busy = _busy,
.create_task_enumerator = _create_task_enumerator,
.flush_queue = _flush_queue,
diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_delete.c b/src/libcharon/sa/ikev1/tasks/isakmp_delete.c
index 0640d13b1..a44f3c4a9 100644
--- a/src/libcharon/sa/ikev1/tasks/isakmp_delete.c
+++ b/src/libcharon/sa/ikev1/tasks/isakmp_delete.c
@@ -85,6 +85,11 @@ METHOD(task_t, process_r, status_t,
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
+ if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
+ {
+ this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
+ this->ike_sa->reestablish(this->ike_sa);
+ }
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
return DESTROY_ME;
diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_natd.c b/src/libcharon/sa/ikev1/tasks/isakmp_natd.c
index 5a779ff62..fc6ac0771 100644
--- a/src/libcharon/sa/ikev1/tasks/isakmp_natd.c
+++ b/src/libcharon/sa/ikev1/tasks/isakmp_natd.c
@@ -97,6 +97,20 @@ struct private_isakmp_natd_t {
};
/**
+ * Check if UDP encapsulation has to be forced either by config or required
+ * by the kernel interface
+ */
+static bool force_encap(ike_cfg_t *ike_cfg)
+{
+ if (!ike_cfg->force_encap(ike_cfg))
+ {
+ return hydra->kernel_interface->get_features(hydra->kernel_interface) &
+ KERNEL_REQUIRE_UDP_ENCAPSULATION;
+ }
+ return TRUE;
+}
+
+/**
* Get NAT-D payload type (RFC 3947 or RFC 3947 drafts).
*/
static payload_type_t get_nat_d_payload_type(ike_sa_t *ike_sa)
@@ -183,7 +197,7 @@ static hash_payload_t *build_natd_payload(private_isakmp_natd_t *this, bool src,
chunk_t hash;
config = this->ike_sa->get_ike_cfg(this->ike_sa);
- if (src && config->force_encap(config))
+ if (src && force_encap(config))
{
hash = generate_natd_hash_faked(this);
}
@@ -297,7 +311,7 @@ static void process_payloads(private_isakmp_natd_t *this, message_t *message)
!this->src_matched);
config = this->ike_sa->get_ike_cfg(this->ike_sa);
if (this->dst_matched && this->src_matched &&
- config->force_encap(config))
+ force_encap(config))
{
this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE);
}
diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
index 2ff2b55e9..11155b287 100644
--- a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
+++ b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c
@@ -67,6 +67,11 @@ struct private_isakmp_vendor_t {
* Index of best nat traversal VID found
*/
int best_natt_ext;
+
+ /**
+ * Number of times we have been invoked
+ */
+ int count;
};
/**
@@ -175,8 +180,10 @@ static bool fragmentation_supported(chunk_t data, int i)
return FALSE;
}
-METHOD(task_t, build, status_t,
- private_isakmp_vendor_t *this, message_t *message)
+/**
+ * Add supported vendor ID payloads
+ */
+static void build(private_isakmp_vendor_t *this, message_t *message)
{
vendor_id_payload_t *vid_payload;
bool strongswan, cisco_unity, fragmentation;
@@ -219,11 +226,12 @@ METHOD(task_t, build, status_t,
message->add_payload(message, &vid_payload->payload_interface);
}
}
- return this->initiator ? NEED_MORE : SUCCESS;
}
-METHOD(task_t, process, status_t,
- private_isakmp_vendor_t *this, message_t *message)
+/**
+ * Process vendor ID payloads
+ */
+static void process(private_isakmp_vendor_t *this, message_t *message)
{
enumerator_t *enumerator;
payload_t *payload;
@@ -289,14 +297,64 @@ METHOD(task_t, process, status_t,
this->ike_sa->enable_extension(this->ike_sa,
vendor_natt_ids[this->best_natt_ext].extension);
}
+}
- return this->initiator ? SUCCESS : NEED_MORE;
+METHOD(task_t, build_i, status_t,
+ private_isakmp_vendor_t *this, message_t *message)
+{
+ if (this->count++ == 0)
+ {
+ build(this, message);
+ }
+ if (message->get_exchange_type(message) == AGGRESSIVE && this->count > 1)
+ {
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+METHOD(task_t, process_r, status_t,
+ private_isakmp_vendor_t *this, message_t *message)
+{
+ this->count++;
+ process(this, message);
+ if (message->get_exchange_type(message) == AGGRESSIVE && this->count > 1)
+ {
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+METHOD(task_t, build_r, status_t,
+ private_isakmp_vendor_t *this, message_t *message)
+{
+ if (this->count == 1)
+ {
+ build(this, message);
+ }
+ if (message->get_exchange_type(message) == ID_PROT && this->count > 2)
+ {
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+METHOD(task_t, process_i, status_t,
+ private_isakmp_vendor_t *this, message_t *message)
+{
+ process(this, message);
+ if (message->get_exchange_type(message) == ID_PROT && this->count > 2)
+ {
+ return SUCCESS;
+ }
+ return NEED_MORE;
}
METHOD(task_t, migrate, void,
private_isakmp_vendor_t *this, ike_sa_t *ike_sa)
{
this->ike_sa = ike_sa;
+ this->count = 0;
}
METHOD(task_t, get_type, task_type_t,
@@ -321,8 +379,6 @@ isakmp_vendor_t *isakmp_vendor_create(ike_sa_t *ike_sa, bool initiator)
INIT(this,
.public = {
.task = {
- .build = _build,
- .process = _process,
.migrate = _migrate,
.get_type = _get_type,
.destroy = _destroy,
@@ -333,5 +389,16 @@ isakmp_vendor_t *isakmp_vendor_create(ike_sa_t *ike_sa, bool initiator)
.best_natt_ext = -1,
);
+ if (initiator)
+ {
+ this->public.task.build = _build_i;
+ this->public.task.process = _process_i;
+ }
+ else
+ {
+ this->public.task.build = _build_r;
+ this->public.task.process = _process_r;
+ }
+
return &this->public;
}
diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c
index e9f06cbe3..1a2cdb777 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_delete.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c
@@ -12,6 +12,27 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
+/*
+ * Copyright (C) 2013 Oliver Smith
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
#include "quick_delete.h"
@@ -64,11 +85,13 @@ struct private_quick_delete_t {
/**
* Delete the specified CHILD_SA, if found
*/
-static bool delete_child(private_quick_delete_t *this,
- protocol_id_t protocol, u_int32_t spi)
+static bool delete_child(private_quick_delete_t *this, protocol_id_t protocol,
+ u_int32_t spi, bool remote_close)
{
u_int64_t bytes_in, bytes_out;
child_sa_t *child_sa;
+ linked_list_t *my_ts, *other_ts;
+ child_cfg_t *child_cfg;
bool rekeyed;
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, TRUE);
@@ -85,15 +108,17 @@ static bool delete_child(private_quick_delete_t *this,
rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYING;
child_sa->set_state(child_sa, CHILD_DELETING);
+ my_ts = linked_list_create_from_enumerator(
+ child_sa->create_ts_enumerator(child_sa, TRUE));
+ other_ts = linked_list_create_from_enumerator(
+ child_sa->create_ts_enumerator(child_sa, FALSE));
if (this->expired)
{
DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)),
- ntohl(child_sa->get_spi(child_sa, FALSE)),
- child_sa->get_traffic_selectors(child_sa, TRUE),
- child_sa->get_traffic_selectors(child_sa, FALSE));
+ ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
}
else
{
@@ -105,18 +130,39 @@ static bool delete_child(private_quick_delete_t *this,
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
- child_sa->get_traffic_selectors(child_sa, TRUE),
- child_sa->get_traffic_selectors(child_sa, FALSE));
+ my_ts, other_ts);
}
+ my_ts->destroy(my_ts);
+ other_ts->destroy(other_ts);
if (!rekeyed)
{
charon->bus->child_updown(charon->bus, child_sa, FALSE);
- }
- this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
+ if (remote_close)
+ {
+ child_cfg = child_sa->get_config(child_sa);
+ child_cfg->get_ref(child_cfg);
- /* TODO-IKEv1: handle close action? */
+ switch (child_sa->get_close_action(child_sa))
+ {
+ case ACTION_RESTART:
+ child_cfg->get_ref(child_cfg);
+ this->ike_sa->initiate(this->ike_sa, child_cfg,
+ child_sa->get_reqid(child_sa), NULL, NULL);
+ break;
+ case ACTION_ROUTE:
+ charon->traps->install(charon->traps,
+ this->ike_sa->get_peer_cfg(this->ike_sa),
+ child_cfg, child_sa->get_reqid(child_sa));
+ break;
+ default:
+ break;
+ }
+ child_cfg->destroy(child_cfg);
+ }
+ }
+ this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
return TRUE;
}
@@ -124,7 +170,7 @@ static bool delete_child(private_quick_delete_t *this,
METHOD(task_t, build_i, status_t,
private_quick_delete_t *this, message_t *message)
{
- if (delete_child(this, this->protocol, this->spi) || this->force)
+ if (delete_child(this, this->protocol, this->spi, FALSE) || this->force)
{
delete_payload_t *delete_payload;
@@ -172,7 +218,7 @@ METHOD(task_t, process_r, status_t,
{
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x",
protocol_id_names, protocol, ntohl(spi));
- if (!delete_child(this, protocol, spi))
+ if (!delete_child(this, protocol, spi, TRUE))
{
DBG1(DBG_IKE, "CHILD_SA not found, ignored");
continue;
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 7a0fb5788..6271e5b05 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -259,7 +259,7 @@ static bool install(private_quick_mode_t *this)
{
status_t status, status_i, status_o;
chunk_t encr_i, encr_r, integ_i, integ_r;
- linked_list_t *tsi, *tsr;
+ linked_list_t *tsi, *tsr, *my_ts, *other_ts;
child_sa_t *old = NULL;
this->child_sa->set_proposal(this->child_sa, this->proposal);
@@ -306,17 +306,21 @@ static bool install(private_quick_mode_t *this)
{
if (this->initiator)
{
- status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
- this->spi_i, this->cpi_i, TRUE, FALSE, tsi, tsr);
- status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
- this->spi_r, this->cpi_r, FALSE, FALSE, tsi, tsr);
+ status_i = this->child_sa->install(this->child_sa,
+ encr_r, integ_r, this->spi_i, this->cpi_i,
+ this->initiator, TRUE, FALSE, tsi, tsr);
+ status_o = this->child_sa->install(this->child_sa,
+ encr_i, integ_i, this->spi_r, this->cpi_r,
+ this->initiator, FALSE, FALSE, tsi, tsr);
}
else
{
- status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
- this->spi_r, this->cpi_r, TRUE, FALSE, tsr, tsi);
- status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
- this->spi_i, this->cpi_i, FALSE, FALSE, tsr, tsi);
+ status_i = this->child_sa->install(this->child_sa,
+ encr_i, integ_i, this->spi_r, this->cpi_r,
+ this->initiator, TRUE, FALSE, tsr, tsi);
+ status_o = this->child_sa->install(this->child_sa,
+ encr_r, integ_r, this->spi_i, this->cpi_i,
+ this->initiator, FALSE, FALSE, tsr, tsi);
}
}
chunk_clear(&integ_i);
@@ -358,14 +362,20 @@ static bool install(private_quick_mode_t *this)
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
+ my_ts = linked_list_create_from_enumerator(
+ this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
+ other_ts = linked_list_create_from_enumerator(
+ this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
+
DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
this->child_sa->get_name(this->child_sa),
this->child_sa->get_reqid(this->child_sa),
ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
- ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
- this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
- this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
+ ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts);
+
+ my_ts->destroy(my_ts);
+ other_ts->destroy(other_ts);
if (this->rekey)
{
@@ -500,33 +510,11 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local,
static void add_ts(private_quick_mode_t *this, message_t *message)
{
id_payload_t *id_payload;
- host_t *hsi, *hsr;
- if (this->initiator)
- {
- hsi = this->ike_sa->get_my_host(this->ike_sa);
- hsr = this->ike_sa->get_other_host(this->ike_sa);
- }
- else
- {
- hsr = this->ike_sa->get_my_host(this->ike_sa);
- hsi = this->ike_sa->get_other_host(this->ike_sa);
- }
- /* add ID payload only if negotiating non host2host tunnels */
- if (!this->tsi->is_host(this->tsi, hsi) ||
- !this->tsr->is_host(this->tsr, hsr) ||
- this->tsi->get_protocol(this->tsi) ||
- this->tsr->get_protocol(this->tsr) ||
- this->tsi->get_from_port(this->tsi) ||
- this->tsr->get_from_port(this->tsr) ||
- this->tsi->get_to_port(this->tsi) != 65535 ||
- this->tsr->get_to_port(this->tsr) != 65535)
- {
- id_payload = id_payload_create_from_ts(this->tsi);
- message->add_payload(message, &id_payload->payload_interface);
- id_payload = id_payload_create_from_ts(this->tsr);
- message->add_payload(message, &id_payload->payload_interface);
- }
+ id_payload = id_payload_create_from_ts(this->tsi);
+ message->add_payload(message, &id_payload->payload_interface);
+ id_payload = id_payload_create_from_ts(this->tsr);
+ message->add_payload(message, &id_payload->payload_interface);
}
/**
@@ -774,19 +762,11 @@ METHOD(task_t, build_i, status_t,
if (this->config->use_ipcomp(this->config))
{
- if (this->udp)
- {
- DBG1(DBG_IKE, "IPComp is not supported if either peer is "
- "natted, IPComp disabled");
- }
- else
+ this->cpi_i = this->child_sa->alloc_cpi(this->child_sa);
+ if (!this->cpi_i)
{
- this->cpi_i = this->child_sa->alloc_cpi(this->child_sa);
- if (!this->cpi_i)
- {
- DBG1(DBG_IKE, "unable to allocate a CPI from kernel, "
- "IPComp disabled");
- }
+ DBG1(DBG_IKE, "unable to allocate a CPI from kernel, "
+ "IPComp disabled");
}
}
@@ -1009,21 +989,13 @@ METHOD(task_t, process_r, status_t,
if (this->config->use_ipcomp(this->config))
{
- if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
- {
- DBG1(DBG_IKE, "IPComp is not supported if either peer is "
- "natted, IPComp disabled");
- }
- else
+ list = sa_payload->get_ipcomp_proposals(sa_payload,
+ &this->cpi_i);
+ if (!list->get_count(list))
{
- list = sa_payload->get_ipcomp_proposals(sa_payload,
- &this->cpi_i);
- if (!list->get_count(list))
- {
- DBG1(DBG_IKE, "expected IPComp proposal but peer did "
- "not send one, IPComp disabled");
- this->cpi_i = 0;
- }
+ DBG1(DBG_IKE, "expected IPComp proposal but peer did "
+ "not send one, IPComp disabled");
+ this->cpi_i = 0;
}
}
if (!list || !list->get_count(list))
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index 5298abf79..a6af744fc 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -18,6 +18,7 @@
#include <math.h>
+#include <collections/array.h>
#include <daemon.h>
#include <sa/ikev2/tasks/ike_init.h>
#include <sa/ikev2/tasks/ike_natd.h>
@@ -122,19 +123,19 @@ struct private_task_manager_t {
} initiating;
/**
- * List of queued tasks not yet in action
+ * Array of queued tasks not yet in action
*/
- linked_list_t *queued_tasks;
+ array_t *queued_tasks;
/**
- * List of active tasks, initiated by ourselve
+ * Array of active tasks, initiated by ourselve
*/
- linked_list_t *active_tasks;
+ array_t *active_tasks;
/**
- * List of tasks initiated by peer
+ * Array of tasks initiated by peer
*/
- linked_list_t *passive_tasks;
+ array_t *passive_tasks;
/**
* the task manager has been reset
@@ -160,24 +161,24 @@ struct private_task_manager_t {
METHOD(task_manager_t, flush_queue, void,
private_task_manager_t *this, task_queue_t queue)
{
- linked_list_t *list;
+ array_t *array;
task_t *task;
switch (queue)
{
case TASK_QUEUE_ACTIVE:
- list = this->active_tasks;
+ array = this->active_tasks;
break;
case TASK_QUEUE_PASSIVE:
- list = this->passive_tasks;
+ array = this->passive_tasks;
break;
case TASK_QUEUE_QUEUED:
- list = this->queued_tasks;
+ array = this->queued_tasks;
break;
default:
return;
}
- while (list->remove_last(list, (void**)&task) == SUCCESS)
+ while (array_remove(array, ARRAY_TAIL, &task))
{
task->destroy(task);
}
@@ -202,14 +203,14 @@ static bool activate_task(private_task_manager_t *this, task_type_t type)
task_t *task;
bool found = FALSE;
- enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
+ enumerator = array_create_enumerator(this->queued_tasks);
while (enumerator->enumerate(enumerator, (void**)&task))
{
if (task->get_type(task) == type)
{
DBG2(DBG_IKE, " activating %N task", task_type_names, type);
- this->queued_tasks->remove_at(this->queued_tasks, enumerator);
- this->active_tasks->insert_last(this->active_tasks, task);
+ array_remove_at(this->queued_tasks, enumerator);
+ array_insert(this->active_tasks, ARRAY_TAIL, task);
found = TRUE;
break;
}
@@ -231,7 +232,7 @@ METHOD(task_manager_t, retransmit, status_t,
ike_mobike_t *mobike = NULL;
/* check if we are retransmitting a MOBIKE routability check */
- enumerator = this->active_tasks->create_enumerator(this->active_tasks);
+ enumerator = array_create_enumerator(this->active_tasks);
while (enumerator->enumerate(enumerator, (void*)&task))
{
if (task->get_type(task) == TASK_IKE_MOBIKE)
@@ -319,7 +320,7 @@ METHOD(task_manager_t, initiate, status_t,
return SUCCESS;
}
- if (this->active_tasks->get_count(this->active_tasks) == 0)
+ if (array_count(this->active_tasks) == 0)
{
DBG2(DBG_IKE, "activating new tasks");
switch (this->ike_sa->get_state(this->ike_sa))
@@ -414,8 +415,8 @@ METHOD(task_manager_t, initiate, status_t,
else
{
DBG2(DBG_IKE, "reinitiating already active tasks");
- enumerator = this->active_tasks->create_enumerator(this->active_tasks);
- while (enumerator->enumerate(enumerator, (void**)&task))
+ enumerator = array_create_enumerator(this->active_tasks);
+ while (enumerator->enumerate(enumerator, &task))
{
DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task));
switch (task->get_type(task))
@@ -460,14 +461,14 @@ METHOD(task_manager_t, initiate, status_t,
this->initiating.type = exchange;
this->initiating.retransmitted = 0;
- enumerator = this->active_tasks->create_enumerator(this->active_tasks);
- while (enumerator->enumerate(enumerator, (void*)&task))
+ enumerator = array_create_enumerator(this->active_tasks);
+ while (enumerator->enumerate(enumerator, &task))
{
switch (task->build(task, message))
{
case SUCCESS:
/* task completed, remove it */
- this->active_tasks->remove_at(this->active_tasks, enumerator);
+ array_remove_at(this->active_tasks, enumerator);
task->destroy(task);
break;
case NEED_MORE:
@@ -507,6 +508,9 @@ METHOD(task_manager_t, initiate, status_t,
}
message->destroy(message);
+ array_compress(this->active_tasks);
+ array_compress(this->queued_tasks);
+
return retransmit(this, this->initiating.mid);
}
@@ -530,14 +534,14 @@ static status_t process_response(private_task_manager_t *this,
/* catch if we get resetted while processing */
this->reset = FALSE;
- enumerator = this->active_tasks->create_enumerator(this->active_tasks);
- while (enumerator->enumerate(enumerator, (void*)&task))
+ enumerator = array_create_enumerator(this->active_tasks);
+ while (enumerator->enumerate(enumerator, &task))
{
switch (task->process(task, message))
{
case SUCCESS:
/* task completed, remove it */
- this->active_tasks->remove_at(this->active_tasks, enumerator);
+ array_remove_at(this->active_tasks, enumerator);
task->destroy(task);
break;
case NEED_MORE:
@@ -549,7 +553,7 @@ static status_t process_response(private_task_manager_t *this,
/* FALL */
case DESTROY_ME:
/* critical failure, destroy IKE_SA */
- this->active_tasks->remove_at(this->active_tasks, enumerator);
+ array_remove_at(this->active_tasks, enumerator);
enumerator->destroy(enumerator);
task->destroy(task);
return DESTROY_ME;
@@ -568,6 +572,8 @@ static status_t process_response(private_task_manager_t *this,
this->initiating.packet->destroy(this->initiating.packet);
this->initiating.packet = NULL;
+ array_compress(this->active_tasks);
+
return initiate(this);
}
@@ -588,8 +594,8 @@ static bool handle_collisions(private_task_manager_t *this, task_t *task)
type == TASK_IKE_REAUTH)
{
/* find an exchange collision, and notify these tasks */
- enumerator = this->active_tasks->create_enumerator(this->active_tasks);
- while (enumerator->enumerate(enumerator, (void**)&active))
+ enumerator = array_create_enumerator(this->active_tasks);
+ while (enumerator->enumerate(enumerator, &active))
{
switch (active->get_type(active))
{
@@ -646,14 +652,14 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
message->set_message_id(message, this->responding.mid);
message->set_request(message, FALSE);
- enumerator = this->passive_tasks->create_enumerator(this->passive_tasks);
+ enumerator = array_create_enumerator(this->passive_tasks);
while (enumerator->enumerate(enumerator, (void*)&task))
{
switch (task->build(task, message))
{
case SUCCESS:
/* task completed, remove it */
- this->passive_tasks->remove_at(this->passive_tasks, enumerator);
+ array_remove_at(this->passive_tasks, enumerator);
if (!handle_collisions(this, task))
{
task->destroy(task);
@@ -663,8 +669,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
/* processed, but task needs another exchange */
if (handle_collisions(this, task))
{
- this->passive_tasks->remove_at(this->passive_tasks,
- enumerator);
+ array_remove_at(this->passive_tasks, enumerator);
}
break;
case FAILED:
@@ -721,6 +726,9 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
}
return DESTROY_ME;
}
+
+ array_compress(this->passive_tasks);
+
return SUCCESS;
}
@@ -736,37 +744,37 @@ static status_t process_request(private_task_manager_t *this,
notify_payload_t *notify;
delete_payload_t *delete;
- if (this->passive_tasks->get_count(this->passive_tasks) == 0)
+ if (array_count(this->passive_tasks) == 0)
{ /* create tasks depending on request type, if not already some queued */
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
{
task = (task_t*)ike_vendor_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
task = (task_t*)ike_init_create(this->ike_sa, FALSE, NULL);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
task = (task_t*)ike_natd_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
#ifdef ME
task = (task_t*)ike_me_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
#endif /* ME */
task = (task_t*)ike_auth_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
task = (task_t*)ike_cert_post_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
task = (task_t*)ike_config_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
task = (task_t*)child_create_create(this->ike_sa, NULL, FALSE,
NULL, NULL);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
task = (task_t*)ike_mobike_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
break;
}
case CREATE_CHILD_SA:
@@ -817,7 +825,7 @@ static status_t process_request(private_task_manager_t *this,
{
task = (task_t*)ike_rekey_create(this->ike_sa, FALSE);
}
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
break;
}
case INFORMATIONAL:
@@ -849,6 +857,12 @@ static status_t process_request(private_task_manager_t *this,
task = (task_t*)ike_auth_lifetime_create(
this->ike_sa, FALSE);
break;
+ case AUTHENTICATION_FAILED:
+ /* initiator failed to authenticate us.
+ * We use ike_delete to handle this, which
+ * invokes all the required hooks. */
+ task = (task_t*)ike_delete_create(
+ this->ike_sa, FALSE);
default:
break;
}
@@ -883,14 +897,14 @@ static status_t process_request(private_task_manager_t *this,
{
task = (task_t*)ike_dpd_create(FALSE);
}
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
break;
}
#ifdef ME
case ME_CONNECT:
{
task = (task_t*)ike_me_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ array_insert(this->passive_tasks, ARRAY_TAIL, task);
}
#endif /* ME */
default:
@@ -899,14 +913,14 @@ static status_t process_request(private_task_manager_t *this,
}
/* let the tasks process the message */
- enumerator = this->passive_tasks->create_enumerator(this->passive_tasks);
+ enumerator = array_create_enumerator(this->passive_tasks);
while (enumerator->enumerate(enumerator, (void*)&task))
{
switch (task->process(task, message))
{
case SUCCESS:
/* task completed, remove it */
- this->passive_tasks->remove_at(this->passive_tasks, enumerator);
+ array_remove_at(this->passive_tasks, enumerator);
task->destroy(task);
break;
case NEED_MORE:
@@ -918,7 +932,7 @@ static status_t process_request(private_task_manager_t *this,
/* FALL */
case DESTROY_ME:
/* critical failure, destroy IKE_SA */
- this->passive_tasks->remove_at(this->passive_tasks, enumerator);
+ array_remove_at(this->passive_tasks, enumerator);
enumerator->destroy(enumerator);
task->destroy(task);
return DESTROY_ME;
@@ -1078,6 +1092,7 @@ METHOD(task_manager_t, process_message, status_t,
host_t *me, *other;
status_t status;
u_int32_t mid;
+ bool schedule_delete_job = FALSE;
charon->bus->message(charon->bus, msg, TRUE, FALSE);
status = parse_message(this, msg);
@@ -1092,9 +1107,8 @@ METHOD(task_manager_t, process_message, status_t,
/* if this IKE_SA is virgin, we check for a config */
if (this->ike_sa->get_ike_cfg(this->ike_sa) == NULL)
{
- ike_sa_id_t *ike_sa_id;
ike_cfg_t *ike_cfg;
- job_t *job;
+
ike_cfg = charon->backends->get_ike_cfg(charon->backends,
me, other, IKEV2);
if (ike_cfg == NULL)
@@ -1109,12 +1123,7 @@ METHOD(task_manager_t, process_message, status_t,
this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg);
ike_cfg->destroy(ike_cfg);
/* add a timeout if peer does not establish it completely */
- ike_sa_id = this->ike_sa->get_id(this->ike_sa);
- job = (job_t*)delete_ike_sa_job_create(ike_sa_id, FALSE);
- lib->scheduler->schedule_job(lib->scheduler, job,
- lib->settings->get_int(lib->settings,
- "%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT,
- charon->name));
+ schedule_delete_job = TRUE;
}
this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
time_monotonic(NULL));
@@ -1213,6 +1222,19 @@ METHOD(task_manager_t, process_message, status_t,
return SUCCESS;
}
}
+
+ if (schedule_delete_job)
+ {
+ ike_sa_id_t *ike_sa_id;
+ job_t *job;
+
+ ike_sa_id = this->ike_sa->get_id(this->ike_sa);
+ job = (job_t*)delete_ike_sa_job_create(ike_sa_id, FALSE);
+ lib->scheduler->schedule_job(lib->scheduler, job,
+ lib->settings->get_int(lib->settings,
+ "%s.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT,
+ charon->name));
+ }
return SUCCESS;
}
@@ -1224,8 +1246,8 @@ METHOD(task_manager_t, queue_task, void,
enumerator_t *enumerator;
task_t *current;
- enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
- while (enumerator->enumerate(enumerator, (void**)&current))
+ enumerator = array_create_enumerator(this->queued_tasks);
+ while (enumerator->enumerate(enumerator, &current))
{
if (current->get_type(current) == TASK_IKE_MOBIKE)
{
@@ -1237,7 +1259,7 @@ METHOD(task_manager_t, queue_task, void,
enumerator->destroy(enumerator);
}
DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task));
- this->queued_tasks->insert_last(this->queued_tasks, task);
+ array_insert(this->queued_tasks, ARRAY_TAIL, task);
}
/**
@@ -1249,7 +1271,7 @@ static bool has_queued(private_task_manager_t *this, task_type_t type)
bool found = FALSE;
task_t *task;
- enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
+ enumerator = array_create_enumerator(this->queued_tasks);
while (enumerator->enumerate(enumerator, &task))
{
if (task->get_type(task) == type)
@@ -1404,19 +1426,51 @@ METHOD(task_manager_t, adopt_tasks, void,
task_t *task;
/* move queued tasks from other to this */
- while (other->queued_tasks->remove_last(other->queued_tasks,
- (void**)&task) == SUCCESS)
+ while (array_remove(other->queued_tasks, ARRAY_TAIL, &task))
{
DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task));
task->migrate(task, this->ike_sa);
- this->queued_tasks->insert_first(this->queued_tasks, task);
+ array_insert(this->queued_tasks, ARRAY_HEAD, task);
+ }
+}
+
+/**
+ * Migrates child-creating tasks from src to dst
+ */
+static void migrate_child_tasks(private_task_manager_t *this,
+ array_t *src, array_t *dst)
+{
+ enumerator_t *enumerator;
+ task_t *task;
+
+ enumerator = array_create_enumerator(src);
+ while (enumerator->enumerate(enumerator, &task))
+ {
+ if (task->get_type(task) == TASK_CHILD_CREATE)
+ {
+ array_remove_at(src, enumerator);
+ task->migrate(task, this->ike_sa);
+ array_insert(dst, ARRAY_TAIL, task);
+ }
}
+ enumerator->destroy(enumerator);
+}
+
+METHOD(task_manager_t, adopt_child_tasks, void,
+ private_task_manager_t *this, task_manager_t *other_public)
+{
+ private_task_manager_t *other = (private_task_manager_t*)other_public;
+
+ /* move active child tasks from other to this */
+ migrate_child_tasks(this, other->active_tasks, this->queued_tasks);
+ /* do the same for queued tasks */
+ migrate_child_tasks(this, other->queued_tasks, this->queued_tasks);
}
METHOD(task_manager_t, busy, bool,
private_task_manager_t *this)
{
- return (this->active_tasks->get_count(this->active_tasks) > 0);
+ return array_count(this->active_tasks) > 0;
}
METHOD(task_manager_t, reset, void,
@@ -1441,7 +1495,7 @@ METHOD(task_manager_t, reset, void,
this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
/* reset queued tasks */
- enumerator = this->queued_tasks->create_enumerator(this->queued_tasks);
+ enumerator = array_create_enumerator(this->queued_tasks);
while (enumerator->enumerate(enumerator, &task))
{
task->migrate(task, this->ike_sa);
@@ -1449,11 +1503,10 @@ METHOD(task_manager_t, reset, void,
enumerator->destroy(enumerator);
/* reset active tasks */
- while (this->active_tasks->remove_last(this->active_tasks,
- (void**)&task) == SUCCESS)
+ while (array_remove(this->active_tasks, ARRAY_TAIL, &task))
{
task->migrate(task, this->ike_sa);
- this->queued_tasks->insert_first(this->queued_tasks, task);
+ array_insert(this->queued_tasks, ARRAY_HEAD, task);
}
this->reset = TRUE;
@@ -1465,11 +1518,11 @@ METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
switch (queue)
{
case TASK_QUEUE_ACTIVE:
- return this->active_tasks->create_enumerator(this->active_tasks);
+ return array_create_enumerator(this->active_tasks);
case TASK_QUEUE_PASSIVE:
- return this->passive_tasks->create_enumerator(this->passive_tasks);
+ return array_create_enumerator(this->passive_tasks);
case TASK_QUEUE_QUEUED:
- return this->queued_tasks->create_enumerator(this->queued_tasks);
+ return array_create_enumerator(this->queued_tasks);
default:
return enumerator_create_empty();
}
@@ -1480,9 +1533,9 @@ METHOD(task_manager_t, destroy, void,
{
flush(this);
- this->active_tasks->destroy(this->active_tasks);
- this->queued_tasks->destroy(this->queued_tasks);
- this->passive_tasks->destroy(this->passive_tasks);
+ array_destroy(this->active_tasks);
+ array_destroy(this->queued_tasks);
+ array_destroy(this->passive_tasks);
DESTROY_IF(this->responding.packet);
DESTROY_IF(this->initiating.packet);
@@ -1515,6 +1568,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
.incr_mid = _incr_mid,
.reset = _reset,
.adopt_tasks = _adopt_tasks,
+ .adopt_child_tasks = _adopt_child_tasks,
.busy = _busy,
.create_task_enumerator = _create_task_enumerator,
.flush_queue = _flush_queue,
@@ -1523,9 +1577,9 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
},
.ike_sa = ike_sa,
.initiating.type = EXCHANGE_TYPE_UNDEFINED,
- .queued_tasks = linked_list_create(),
- .active_tasks = linked_list_create(),
- .passive_tasks = linked_list_create(),
+ .queued_tasks = array_create(0, 0),
+ .active_tasks = array_create(0, 0),
+ .passive_tasks = array_create(0, 0),
.retransmit_tries = lib->settings->get_int(lib->settings,
"%s.retransmit_tries", RETRANSMIT_TRIES, charon->name),
.retransmit_timeout = lib->settings->get_double(lib->settings,
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index 32c0e8c4a..8ae36af84 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -27,6 +27,7 @@
#include <encoding/payloads/ts_payload.h>
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/notify_payload.h>
+#include <encoding/payloads/delete_payload.h>
#include <processing/jobs/delete_ike_sa_job.h>
#include <processing/jobs/inactivity_job.h>
@@ -342,6 +343,79 @@ static linked_list_t *get_dynamic_hosts(ike_sa_t *ike_sa, bool local)
}
/**
+ * Substitude any host address with NATed address in traffic selector
+ */
+static linked_list_t* get_transport_nat_ts(private_child_create_t *this,
+ bool local, linked_list_t *in)
+{
+ enumerator_t *enumerator;
+ linked_list_t *out;
+ traffic_selector_t *ts;
+ host_t *ike, *first = NULL;
+ u_int8_t mask;
+
+ if (local)
+ {
+ ike = this->ike_sa->get_my_host(this->ike_sa);
+ }
+ else
+ {
+ ike = this->ike_sa->get_other_host(this->ike_sa);
+ }
+
+ out = linked_list_create();
+
+ enumerator = in->create_enumerator(in);
+ while (enumerator->enumerate(enumerator, &ts))
+ {
+ /* require that all selectors match the first "host" selector */
+ if (ts->is_host(ts, first))
+ {
+ if (!first)
+ {
+ ts->to_subnet(ts, &first, &mask);
+ }
+ ts = ts->clone(ts);
+ ts->set_address(ts, ike);
+ out->insert_last(out, ts);
+ }
+ }
+ enumerator->destroy(enumerator);
+ DESTROY_IF(first);
+
+ return out;
+}
+
+/**
+ * Narrow received traffic selectors with configuration
+ */
+static linked_list_t* narrow_ts(private_child_create_t *this, bool local,
+ linked_list_t *in)
+{
+ linked_list_t *hosts, *nat, *ts;
+ ike_condition_t cond;
+
+ cond = local ? COND_NAT_HERE : COND_NAT_THERE;
+ hosts = get_dynamic_hosts(this->ike_sa, local);
+
+ if (this->mode == MODE_TRANSPORT &&
+ this->ike_sa->has_condition(this->ike_sa, cond))
+ {
+ nat = get_transport_nat_ts(this, local, in);
+ ts = this->config->get_traffic_selectors(this->config, local, nat, hosts);
+ nat->destroy_offset(nat, offsetof(traffic_selector_t, destroy));
+ }
+ else
+ {
+ ts = this->config->get_traffic_selectors(this->config, local, in, hosts);
+ }
+
+ hosts->destroy(hosts);
+
+ return ts;
+}
+
+/**
* Install a CHILD_SA for usage, return value:
* - FAILED: no acceptable proposal
* - INVALID_ARG: diffie hellman group inacceptable
@@ -354,7 +428,7 @@ static status_t select_and_install(private_child_create_t *this,
chunk_t nonce_i, nonce_r;
chunk_t encr_i = chunk_empty, encr_r = chunk_empty;
chunk_t integ_i = chunk_empty, integ_r = chunk_empty;
- linked_list_t *my_ts, *other_ts, *list;
+ linked_list_t *my_ts, *other_ts;
host_t *me, *other;
bool private;
@@ -415,24 +489,16 @@ static status_t select_and_install(private_child_create_t *this,
{
nonce_i = this->my_nonce;
nonce_r = this->other_nonce;
- my_ts = this->tsi;
- other_ts = this->tsr;
+ my_ts = narrow_ts(this, TRUE, this->tsi);
+ other_ts = narrow_ts(this, FALSE, this->tsr);
}
else
{
nonce_r = this->my_nonce;
nonce_i = this->other_nonce;
- my_ts = this->tsr;
- other_ts = this->tsi;
+ my_ts = narrow_ts(this, TRUE, this->tsr);
+ other_ts = narrow_ts(this, FALSE, this->tsi);
}
- list = get_dynamic_hosts(this->ike_sa, TRUE);
- my_ts = this->config->get_traffic_selectors(this->config,
- TRUE, my_ts, list);
- list->destroy(list);
- list = get_dynamic_hosts(this->ike_sa, FALSE);
- other_ts = this->config->get_traffic_selectors(this->config,
- FALSE, other_ts, list);
- list->destroy(list);
if (this->initiator)
{
@@ -489,10 +555,9 @@ static status_t select_and_install(private_child_create_t *this,
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using transport mode, not host-to-host");
}
- else if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
+ if (this->config->get_mode(this->config) != MODE_TRANSPORT)
{
this->mode = MODE_TUNNEL;
- DBG1(DBG_IKE, "not using transport mode, connection NATed");
}
break;
case MODE_BEET:
@@ -502,6 +567,10 @@ static status_t select_and_install(private_child_create_t *this,
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
}
+ if (this->config->get_mode(this->config) != MODE_BEET)
+ {
+ this->mode = MODE_TUNNEL;
+ }
break;
default:
break;
@@ -525,20 +594,20 @@ static status_t select_and_install(private_child_create_t *this,
{
if (this->initiator)
{
- status_i = this->child_sa->install(this->child_sa,
- encr_r, integ_r, this->my_spi, this->my_cpi,
+ status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
+ this->my_spi, this->my_cpi, this->initiator,
TRUE, this->tfcv3, my_ts, other_ts);
- status_o = this->child_sa->install(this->child_sa,
- encr_i, integ_i, this->other_spi, this->other_cpi,
+ status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
+ this->other_spi, this->other_cpi, this->initiator,
FALSE, this->tfcv3, my_ts, other_ts);
}
else
{
- status_i = this->child_sa->install(this->child_sa,
- encr_i, integ_i, this->my_spi, this->my_cpi,
+ status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
+ this->my_spi, this->my_cpi, this->initiator,
TRUE, this->tfcv3, my_ts, other_ts);
- status_o = this->child_sa->install(this->child_sa,
- encr_r, integ_r, this->other_spi, this->other_cpi,
+ status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
+ this->other_spi, this->other_cpi, this->initiator,
FALSE, this->tfcv3, my_ts, other_ts);
}
}
@@ -604,6 +673,22 @@ static status_t select_and_install(private_child_create_t *this,
{ /* a rekeyed SA uses the same reqid, no need for a new job */
schedule_inactivity_timeout(this);
}
+
+ my_ts = linked_list_create_from_enumerator(
+ this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
+ other_ts = linked_list_create_from_enumerator(
+ this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
+
+ DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
+ "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
+ this->child_sa->get_name(this->child_sa),
+ this->child_sa->get_reqid(this->child_sa),
+ ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
+ ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts);
+
+ my_ts->destroy(my_ts);
+ other_ts->destroy(other_ts);
+
return SUCCESS;
}
@@ -678,13 +763,6 @@ static void build_payloads(private_child_create_t *this, message_t *message)
static void add_ipcomp_notify(private_child_create_t *this,
message_t *message, u_int8_t ipcomp)
{
- if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
- {
- DBG1(DBG_IKE, "IPComp is not supported if either peer is natted, "
- "IPComp disabled");
- return;
- }
-
this->my_cpi = this->child_sa->alloc_cpi(this->child_sa);
if (this->my_cpi)
{
@@ -901,12 +979,6 @@ METHOD(task_t, build_i, status_t,
this->proposals = this->config->get_proposals(this->config,
this->dh_group == MODP_NONE);
this->mode = this->config->get_mode(this->config);
- if (this->mode == MODE_TRANSPORT &&
- this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
- {
- this->mode = MODE_TUNNEL;
- DBG1(DBG_IKE, "not using transport mode, connection NATed");
- }
this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid,
@@ -1002,10 +1074,77 @@ static void handle_child_sa_failure(private_child_create_t *this,
}
}
+/**
+ * Substitute transport mode NAT selectors, if applicable
+ */
+static linked_list_t* get_ts_if_nat_transport(private_child_create_t *this,
+ bool local, linked_list_t *in)
+{
+ linked_list_t *out = NULL;
+ ike_condition_t cond;
+
+ if (this->mode == MODE_TRANSPORT)
+ {
+ cond = local ? COND_NAT_HERE : COND_NAT_THERE;
+ if (this->ike_sa->has_condition(this->ike_sa, cond))
+ {
+ out = get_transport_nat_ts(this, local, in);
+ if (out->get_count(out) == 0)
+ {
+ out->destroy(out);
+ out = NULL;
+ }
+ }
+ }
+ return out;
+}
+
+/**
+ * Select a matching CHILD config as responder
+ */
+static child_cfg_t* select_child_cfg(private_child_create_t *this)
+{
+ peer_cfg_t *peer_cfg;
+ child_cfg_t *child_cfg = NULL;;
+
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ if (peer_cfg && this->tsi && this->tsr)
+ {
+ linked_list_t *listr, *listi, *tsr, *tsi;
+
+ tsr = get_ts_if_nat_transport(this, TRUE, this->tsr);
+ tsi = get_ts_if_nat_transport(this, FALSE, this->tsi);
+
+ listr = get_dynamic_hosts(this->ike_sa, TRUE);
+ listi = get_dynamic_hosts(this->ike_sa, FALSE);
+ child_cfg = peer_cfg->select_child_cfg(peer_cfg,
+ tsr ?: this->tsr, tsi ?: this->tsi,
+ listr, listi);
+ if ((tsi || tsr) && child_cfg &&
+ child_cfg->get_mode(child_cfg) != MODE_TRANSPORT)
+ {
+ /* found a CHILD config, but it doesn't use transport mode */
+ child_cfg->destroy(child_cfg);
+ child_cfg = NULL;
+ }
+ if (!child_cfg && (tsi || tsr))
+ {
+ /* no match for the substituted NAT selectors, try it without */
+ child_cfg = peer_cfg->select_child_cfg(peer_cfg,
+ this->tsr, this->tsi, listr, listi);
+ }
+ listr->destroy(listr);
+ listi->destroy(listi);
+ DESTROY_OFFSET_IF(tsi, offsetof(traffic_selector_t, destroy));
+ DESTROY_OFFSET_IF(tsr, offsetof(traffic_selector_t, destroy));
+ }
+
+ return child_cfg;
+}
+
METHOD(task_t, build_r, status_t,
private_child_create_t *this, message_t *message)
{
- peer_cfg_t *peer_cfg;
payload_t *payload;
enumerator_t *enumerator;
bool no_dh = TRUE, ike_auth = FALSE;
@@ -1040,19 +1179,10 @@ METHOD(task_t, build_r, status_t,
return SUCCESS;
}
- peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
- if (!this->config && peer_cfg && this->tsi && this->tsr)
+ if (this->config == NULL)
{
- linked_list_t *listr, *listi;
-
- listr = get_dynamic_hosts(this->ike_sa, TRUE);
- listi = get_dynamic_hosts(this->ike_sa, FALSE);
- this->config = peer_cfg->select_child_cfg(peer_cfg,
- this->tsr, this->tsi, listr, listi);
- listr->destroy(listr);
- listi->destroy(listi);
+ this->config = select_child_cfg(this);
}
-
if (this->config == NULL)
{
DBG1(DBG_IKE, "traffic selectors %#R=== %#R inacceptable",
@@ -1131,15 +1261,6 @@ METHOD(task_t, build_r, status_t,
build_payloads(this, message);
- DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
- "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
- this->child_sa->get_name(this->child_sa),
- this->child_sa->get_reqid(this->child_sa),
- ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
- ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
- this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
- this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
-
if (!this->rekey)
{ /* invoke the child_up() hook if we are not rekeying */
charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
@@ -1147,6 +1268,57 @@ METHOD(task_t, build_r, status_t,
return SUCCESS;
}
+/**
+ * Raise alerts for received notify errors
+ */
+static void raise_alerts(private_child_create_t *this, notify_type_t type)
+{
+ linked_list_t *list;
+
+ switch (type)
+ {
+ case NO_PROPOSAL_CHOSEN:
+ list = this->config->get_proposals(this->config, FALSE);
+ charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_CHILD, list);
+ list->destroy_offset(list, offsetof(proposal_t, destroy));
+ break;
+ default:
+ break;
+ }
+}
+
+METHOD(task_t, build_i_delete, status_t,
+ private_child_create_t *this, message_t *message)
+{
+ message->set_exchange_type(message, INFORMATIONAL);
+ if (this->child_sa && this->proposal)
+ {
+ protocol_id_t proto;
+ delete_payload_t *del;
+ u_int32_t spi;
+
+ proto = this->proposal->get_protocol(this->proposal);
+ spi = this->child_sa->get_spi(this->child_sa, TRUE);
+ del = delete_payload_create(DELETE, proto);
+ del->add_spi(del, spi);
+ message->add_payload(message, (payload_t*)del);
+
+ DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
+ protocol_id_names, proto, ntohl(spi));
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Change task to delete the failed CHILD_SA as initiator
+ */
+static status_t delete_failed_sa(private_child_create_t *this)
+{
+ this->public.task.build = _build_i_delete;
+ this->public.task.process = (void*)return_success;
+ return NEED_MORE;
+}
+
METHOD(task_t, process_i, status_t,
private_child_create_t *this, message_t *message)
{
@@ -1195,6 +1367,7 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received %N notify, no CHILD_SA built",
notify_type_names, type);
enumerator->destroy(enumerator);
+ raise_alerts(this, type);
handle_child_sa_failure(this, message);
/* an error in CHILD_SA creation is not critical */
return SUCCESS;
@@ -1247,7 +1420,7 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify without requesting"
" one, no CHILD_SA built");
handle_child_sa_failure(this, message);
- return SUCCESS;
+ return delete_failed_sa(this);
}
else if (this->ipcomp != IPCOMP_NONE && this->ipcomp_received == IPCOMP_NONE)
{
@@ -1260,20 +1433,11 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify we didn't propose, "
"no CHILD_SA built");
handle_child_sa_failure(this, message);
- return SUCCESS;
+ return delete_failed_sa(this);
}
if (select_and_install(this, no_dh, ike_auth) == SUCCESS)
{
- DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
- "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
- this->child_sa->get_name(this->child_sa),
- this->child_sa->get_reqid(this->child_sa),
- ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
- ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
- this->child_sa->get_traffic_selectors(this->child_sa, TRUE),
- this->child_sa->get_traffic_selectors(this->child_sa, FALSE));
-
if (!this->rekey)
{ /* invoke the child_up() hook if we are not rekeying */
charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
@@ -1282,6 +1446,7 @@ METHOD(task_t, process_i, status_t,
else
{
handle_child_sa_failure(this, message);
+ return delete_failed_sa(this);
}
return SUCCESS;
}
diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c
index 8652942ad..eaaca2039 100644
--- a/src/libcharon/sa/ikev2/tasks/child_delete.c
+++ b/src/libcharon/sa/ikev2/tasks/child_delete.c
@@ -177,8 +177,11 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
default:
break;
}
-
- this->child_sas->insert_last(this->child_sas, child_sa);
+ if (this->child_sas->find_first(this->child_sas, NULL,
+ (void**)&child_sa) != SUCCESS)
+ {
+ this->child_sas->insert_last(this->child_sas, child_sa);
+ }
}
spis->destroy(spis);
}
@@ -219,12 +222,13 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
{
case ACTION_RESTART:
child_cfg->get_ref(child_cfg);
- status = this->ike_sa->initiate(this->ike_sa, child_cfg, 0,
- NULL, NULL);
+ status = this->ike_sa->initiate(this->ike_sa, child_cfg,
+ child_sa->get_reqid(child_sa), NULL, NULL);
break;
case ACTION_ROUTE:
charon->traps->install(charon->traps,
- this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg);
+ this->ike_sa->get_peer_cfg(this->ike_sa), child_cfg,
+ child_sa->get_reqid(child_sa));
break;
default:
break;
@@ -245,6 +249,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
*/
static void log_children(private_child_delete_t *this)
{
+ linked_list_t *my_ts, *other_ts;
enumerator_t *enumerator;
child_sa_t *child_sa;
u_int64_t bytes_in, bytes_out;
@@ -252,15 +257,17 @@ static void log_children(private_child_delete_t *this)
enumerator = this->child_sas->create_enumerator(this->child_sas);
while (enumerator->enumerate(enumerator, (void**)&child_sa))
{
+ my_ts = linked_list_create_from_enumerator(
+ child_sa->create_ts_enumerator(child_sa, TRUE));
+ other_ts = linked_list_create_from_enumerator(
+ child_sa->create_ts_enumerator(child_sa, FALSE));
if (this->expired)
{
DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)),
- ntohl(child_sa->get_spi(child_sa, FALSE)),
- child_sa->get_traffic_selectors(child_sa, TRUE),
- child_sa->get_traffic_selectors(child_sa, FALSE));
+ ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
}
else
{
@@ -272,9 +279,10 @@ static void log_children(private_child_delete_t *this)
child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
- child_sa->get_traffic_selectors(child_sa, TRUE),
- child_sa->get_traffic_selectors(child_sa, FALSE));
+ my_ts, other_ts);
}
+ my_ts->destroy(my_ts);
+ other_ts->destroy(other_ts);
}
enumerator->destroy(enumerator);
}
@@ -310,10 +318,6 @@ METHOD(task_t, build_i, status_t,
METHOD(task_t, process_i, status_t,
private_child_delete_t *this, message_t *message)
{
- /* flush the list before adding new SAs */
- this->child_sas->destroy(this->child_sas);
- this->child_sas = linked_list_create();
-
process_payloads(this, message);
DBG1(DBG_IKE, "CHILD_SA closed");
return destroy_and_reestablish(this);
diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c
index 262cb10e0..d2003bb45 100644
--- a/src/libcharon/sa/ikev2/tasks/child_rekey.c
+++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c
@@ -399,12 +399,19 @@ METHOD(child_rekey_t, collide, void,
else if (other->get_type(other) == TASK_CHILD_DELETE)
{
child_delete_t *del = (child_delete_t*)other;
- if (del->get_child(del) == this->child_create->get_child(this->child_create))
+ if (this->collision &&
+ this->collision->get_type(this->collision) == TASK_CHILD_REKEY)
{
- /* peer deletes redundant child created in collision */
- this->other_child_destroyed = TRUE;
- other->destroy(other);
- return;
+ private_child_rekey_t *rekey;
+
+ rekey = (private_child_rekey_t*)this->collision;
+ if (del->get_child(del) == rekey->child_create->get_child(rekey->child_create))
+ {
+ /* peer deletes redundant child created in collision */
+ this->other_child_destroyed = TRUE;
+ other->destroy(other);
+ return;
+ }
}
if (del->get_child(del) != this->child_sa)
{
diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c
index 942f97cf5..8f83c4884 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_auth.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_auth.c
@@ -852,6 +852,33 @@ local_auth_failed:
return FAILED;
}
+/**
+ * Send an INFORMATIONAL message with an AUTH_FAILED before closing IKE_SA
+ */
+static void send_auth_failed_informational(private_ike_auth_t *this,
+ message_t *reply)
+{
+ message_t *message;
+ packet_t *packet;
+ host_t *host;
+
+ message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION);
+ message->set_message_id(message, reply->get_message_id(reply) + 1);
+ host = this->ike_sa->get_my_host(this->ike_sa);
+ message->set_source(message, host->clone(host));
+ host = this->ike_sa->get_other_host(this->ike_sa);
+ message->set_destination(message, host->clone(host));
+ message->set_exchange_type(message, INFORMATIONAL);
+ message->add_notify(message, FALSE, AUTHENTICATION_FAILED, chunk_empty);
+
+ if (this->ike_sa->generate_message(this->ike_sa, message,
+ &packet) == SUCCESS)
+ {
+ charon->sender->send(charon->sender, packet);
+ }
+ message->destroy(message);
+}
+
METHOD(task_t, process_i, status_t,
private_ike_auth_t *this, message_t *message)
{
@@ -908,6 +935,7 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received %N notify error",
notify_type_names, type);
enumerator->destroy(enumerator);
+ charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
return FAILED;
}
DBG2(DBG_IKE, "received %N notify",
@@ -1004,6 +1032,7 @@ METHOD(task_t, process_i, status_t,
break;
default:
charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
+ send_auth_failed_informational(this, message);
return FAILED;
}
}
@@ -1048,6 +1077,7 @@ METHOD(task_t, process_i, status_t,
peer_auth_failed:
charon->bus->alert(charon->bus, ALERT_PEER_AUTH_FAILED);
+ send_auth_failed_informational(this, message);
return FAILED;
}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h
index ac1a85c29..c1f8635ce 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h
+++ b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h
@@ -28,7 +28,7 @@ typedef struct ike_cert_pre_t ike_cert_pre_t;
#include <sa/task.h>
/**
- * Task of type ike_cert_post, certificate processing before authentication.
+ * Task of type ike_cert_pre, certificate processing before authentication.
*/
struct ike_cert_pre_t {
diff --git a/src/libcharon/sa/ikev2/tasks/ike_delete.c b/src/libcharon/sa/ikev2/tasks/ike_delete.c
index f127b0c15..9bc62bf2a 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_delete.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_delete.c
@@ -109,6 +109,14 @@ METHOD(task_t, process_r, status_t,
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
+ if (message->get_exchange_type(message) == INFORMATIONAL &&
+ message->get_notify(message, AUTHENTICATION_FAILED))
+ {
+ /* a late AUTHENTICATION_FAILED notify from the initiator after
+ * we have established the IKE_SA: signal auth failure */
+ charon->bus->alert(charon->bus, ALERT_LOCAL_AUTH_FAILED);
+ }
+
switch (this->ike_sa->get_state(this->ike_sa))
{
case IKE_ESTABLISHED:
diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c
index 7542937b3..278bdc3f2 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_init.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_init.c
@@ -420,6 +420,25 @@ METHOD(task_t, build_r, status_t,
return SUCCESS;
}
+/**
+ * Raise alerts for received notify errors
+ */
+static void raise_alerts(private_ike_init_t *this, notify_type_t type)
+{
+ linked_list_t *list;
+
+ switch (type)
+ {
+ case NO_PROPOSAL_CHOSEN:
+ list = this->config->get_proposals(this->config);
+ charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_IKE, list);
+ list->destroy_offset(list, offsetof(proposal_t, destroy));
+ break;
+ default:
+ break;
+ }
+}
+
METHOD(task_t, process_i, status_t,
private_ike_init_t *this, message_t *message)
{
@@ -482,6 +501,7 @@ METHOD(task_t, process_i, status_t,
DBG1(DBG_IKE, "received %N notify error",
notify_type_names, type);
enumerator->destroy(enumerator);
+ raise_alerts(this, type);
return FAILED;
}
DBG2(DBG_IKE, "received %N notify",
diff --git a/src/libcharon/sa/ikev2/tasks/ike_natd.c b/src/libcharon/sa/ikev2/tasks/ike_natd.c
index 0a93db9ed..4fc968f25 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_natd.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_natd.c
@@ -78,6 +78,19 @@ struct private_ike_natd_t {
bool mapping_changed;
};
+/**
+ * Check if UDP encapsulation has to be forced either by config or required
+ * by the kernel interface
+ */
+static bool force_encap(ike_cfg_t *ike_cfg)
+{
+ if (!ike_cfg->force_encap(ike_cfg))
+ {
+ return hydra->kernel_interface->get_features(hydra->kernel_interface) &
+ KERNEL_REQUIRE_UDP_ENCAPSULATION;
+ }
+ return TRUE;
+}
/**
* Build NAT detection hash for a host
@@ -147,7 +160,7 @@ static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
ike_sa_id = this->ike_sa->get_id(this->ike_sa);
config = this->ike_sa->get_ike_cfg(this->ike_sa);
- if (config->force_encap(config) && type == NAT_DETECTION_SOURCE_IP)
+ if (force_encap(config) && type == NAT_DETECTION_SOURCE_IP)
{
hash = generate_natd_hash_faked(this);
}
@@ -256,7 +269,7 @@ static void process_payloads(private_ike_natd_t *this, message_t *message)
!this->src_matched);
config = this->ike_sa->get_ike_cfg(this->ike_sa);
if (this->dst_matched && this->src_matched &&
- config->force_encap(config))
+ force_encap(config))
{
this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE);
}
@@ -316,7 +329,7 @@ METHOD(task_t, build_i, status_t,
* 3. Include all possbile addresses
*/
host = message->get_source(message);
- if (!host->is_anyaddr(host) || ike_cfg->force_encap(ike_cfg))
+ if (!host->is_anyaddr(host) || force_encap(ike_cfg))
{ /* 1. or if we force UDP encap, as it doesn't matter if it's %any */
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
if (notify)
diff --git a/src/libcharon/sa/keymat.h b/src/libcharon/sa/keymat.h
index 02db5ca58..bc40b3d92 100644
--- a/src/libcharon/sa/keymat.h
+++ b/src/libcharon/sa/keymat.h
@@ -79,7 +79,7 @@ struct keymat_t {
*/
nonce_gen_t* (*create_nonce_gen)(keymat_t *this);
- /*
+ /**
* Get a AEAD transform to en-/decrypt and sign/verify IKE messages.
*
* @param in TRUE for inbound (decrypt), FALSE for outbound (encrypt)
diff --git a/src/libcharon/sa/task.h b/src/libcharon/sa/task.h
index c37221a77..f2c4299cc 100644
--- a/src/libcharon/sa/task.h
+++ b/src/libcharon/sa/task.h
@@ -67,7 +67,7 @@ enum task_type_t {
TASK_CHILD_CREATE,
/** delete an established CHILD_SA */
TASK_CHILD_DELETE,
- /** rekey an CHILD_SA */
+ /** rekey a CHILD_SA */
TASK_CHILD_REKEY,
/** IKEv1 main mode */
TASK_MAIN_MODE,
diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h
index c649cf78e..a1ebb4117 100644
--- a/src/libcharon/sa/task_manager.h
+++ b/src/libcharon/sa/task_manager.h
@@ -202,7 +202,7 @@ struct task_manager_t {
status_t (*retransmit) (task_manager_t *this, u_int32_t message_id);
/**
- * Migrate all tasks from other to this.
+ * Migrate all queued tasks from other to this.
*
* To rekey or reestablish an IKE_SA completely, all queued or active
* tasks should get migrated to the new IKE_SA.
@@ -212,6 +212,13 @@ struct task_manager_t {
void (*adopt_tasks) (task_manager_t *this, task_manager_t *other);
/**
+ * Migrate all active or queued CHILD_SA-creating tasks from other to this.
+ *
+ * @param other manager which gives away its tasks
+ */
+ void (*adopt_child_tasks) (task_manager_t *this, task_manager_t *other);
+
+ /**
* Increment a message ID counter, in- or outbound.
*
* If a message is processed outside of the manager, this call increments
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c
index 6c0ae19c7..37426fc47 100644
--- a/src/libcharon/sa/trap_manager.c
+++ b/src/libcharon/sa/trap_manager.c
@@ -92,7 +92,8 @@ static void destroy_entry(entry_t *entry)
}
METHOD(trap_manager_t, install, u_int32_t,
- private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child)
+ private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child,
+ u_int32_t reqid)
{
entry_t *entry, *found = NULL;
ike_cfg_t *ike_cfg;
@@ -101,7 +102,6 @@ METHOD(trap_manager_t, install, u_int32_t,
linked_list_t *my_ts, *other_ts, *list;
enumerator_t *enumerator;
status_t status;
- u_int32_t reqid = 0;
/* try to resolve addresses */
ike_cfg = peer->get_ike_cfg(peer);
@@ -109,6 +109,7 @@ METHOD(trap_manager_t, install, u_int32_t,
0, ike_cfg->get_other_port(ike_cfg));
if (!other || other->is_anyaddr(other))
{
+ DESTROY_IF(other);
DBG1(DBG_CFG, "installing trap failed, remote address unknown");
return 0;
}
@@ -141,6 +142,8 @@ METHOD(trap_manager_t, install, u_int32_t,
}
}
enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
if (found)
{ /* config might have changed so update everything */
DBG1(DBG_CFG, "updating already routed CHILD_SA '%s'",
@@ -179,10 +182,11 @@ METHOD(trap_manager_t, install, u_int32_t,
.child_sa = child_sa,
.peer_cfg = peer->get_ref(peer),
);
+ this->lock->write_lock(this->lock);
this->traps->insert_last(this->traps, entry);
+ this->lock->unlock(this->lock);
reqid = child_sa->get_reqid(child_sa);
}
- this->lock->unlock(this->lock);
if (status != SUCCESS)
{
@@ -251,6 +255,31 @@ METHOD(trap_manager_t, create_enumerator, enumerator_t*,
(void*)this->lock->unlock);
}
+METHOD(trap_manager_t, find_reqid, u_int32_t,
+ private_trap_manager_t *this, child_cfg_t *child)
+{
+ enumerator_t *enumerator;
+ child_cfg_t *current;
+ entry_t *entry;
+ u_int32_t reqid = 0;
+
+ this->lock->read_lock(this->lock);
+ enumerator = this->traps->create_enumerator(this->traps);
+ while (enumerator->enumerate(enumerator, &entry))
+ {
+ current = entry->child_sa->get_config(entry->child_sa);
+ if (streq(current->get_name(current), child->get_name(child)))
+ {
+ reqid = entry->child_sa->get_reqid(entry->child_sa);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ return reqid;
+}
+
METHOD(trap_manager_t, acquire, void,
private_trap_manager_t *this, u_int32_t reqid,
traffic_selector_t *src, traffic_selector_t *dst)
@@ -319,8 +348,7 @@ METHOD(trap_manager_t, acquire, void,
}
else
{
- charon->ike_sa_manager->checkin_and_destroy(
- charon->ike_sa_manager, ike_sa);
+ ike_sa->destroy(ike_sa);
}
}
peer->destroy(peer);
@@ -417,6 +445,7 @@ trap_manager_t *trap_manager_create(void)
.install = _install,
.uninstall = _uninstall,
.create_enumerator = _create_enumerator,
+ .find_reqid = _find_reqid,
.acquire = _acquire,
.flush = _flush,
.destroy = _destroy,
@@ -435,4 +464,3 @@ trap_manager_t *trap_manager_create(void)
return &this->public;
}
-
diff --git a/src/libcharon/sa/trap_manager.h b/src/libcharon/sa/trap_manager.h
index e3d355662..0491107fd 100644
--- a/src/libcharon/sa/trap_manager.h
+++ b/src/libcharon/sa/trap_manager.h
@@ -37,10 +37,11 @@ struct trap_manager_t {
*
* @param peer peer configuration to initiate on trap
* @param child child configuration to install as a trap
+ * @param reqid optional reqid to use
* @return reqid of installed CHILD_SA, 0 if failed
*/
u_int32_t (*install)(trap_manager_t *this, peer_cfg_t *peer,
- child_cfg_t *child);
+ child_cfg_t *child, u_int32_t reqid);
/**
* Uninstall a trap policy.
@@ -58,6 +59,14 @@ struct trap_manager_t {
enumerator_t* (*create_enumerator)(trap_manager_t *this);
/**
+ * Find the reqid of a child config installed as a trap.
+ *
+ * @param child CHILD_SA config to get the reqid for
+ * @return reqid of trap, 0 if not found
+ */
+ u_int32_t (*find_reqid)(trap_manager_t *this, child_cfg_t *child);
+
+ /**
* Acquire an SA triggered by an installed trap.
*
* @param reqid requid of the triggering CHILD_SA