summaryrefslogtreecommitdiff
path: root/src/charon/sa
diff options
context:
space:
mode:
Diffstat (limited to 'src/charon/sa')
-rw-r--r--src/charon/sa/authenticators/eap/eap_manager.c2
-rw-r--r--src/charon/sa/child_sa.c135
-rw-r--r--src/charon/sa/child_sa.h34
-rw-r--r--src/charon/sa/connect_manager.c2
-rw-r--r--src/charon/sa/ike_sa.c45
-rw-r--r--src/charon/sa/ike_sa.h5
-rw-r--r--src/charon/sa/ike_sa_manager.c40
-rw-r--r--src/charon/sa/keymat.c3
-rw-r--r--src/charon/sa/mediation_manager.c2
-rw-r--r--src/charon/sa/task_manager.c30
-rw-r--r--src/charon/sa/tasks/child_create.c39
-rw-r--r--src/charon/sa/tasks/child_create.h4
-rw-r--r--src/charon/sa/tasks/child_delete.c29
-rw-r--r--src/charon/sa/tasks/child_rekey.c15
-rw-r--r--src/charon/sa/tasks/ike_auth.c2
-rw-r--r--src/charon/sa/tasks/ike_delete.c36
-rw-r--r--src/charon/sa/tasks/ike_rekey.c2
-rw-r--r--src/charon/sa/tasks/task.h4
-rw-r--r--src/charon/sa/trap_manager.c6
19 files changed, 359 insertions, 76 deletions
diff --git a/src/charon/sa/authenticators/eap/eap_manager.c b/src/charon/sa/authenticators/eap/eap_manager.c
index b8316036e..24a4fd6ed 100644
--- a/src/charon/sa/authenticators/eap/eap_manager.c
+++ b/src/charon/sa/authenticators/eap/eap_manager.c
@@ -163,7 +163,7 @@ eap_manager_t *eap_manager_create()
this->public.destroy = (void(*)(eap_manager_t*))destroy;
this->methods = linked_list_create();
- this->lock = rwlock_create(RWLOCK_DEFAULT);
+ this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
return &this->public;
}
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c
index 9202e972e..14d174ab5 100644
--- a/src/charon/sa/child_sa.c
+++ b/src/charon/sa/child_sa.c
@@ -136,6 +136,26 @@ struct private_child_sa_t {
* config used to create this child
*/
child_cfg_t *config;
+
+ /**
+ * time of last use in seconds (inbound)
+ */
+ u_int32_t my_usetime;
+
+ /**
+ * time of last use in seconds (outbound)
+ */
+ u_int32_t other_usetime;
+
+ /**
+ * last number of inbound bytes
+ */
+ u_int64_t my_usebytes;
+
+ /**
+ * last number of outbound bytes
+ */
+ u_int64_t other_usebytes;
};
/**
@@ -355,20 +375,72 @@ static enumerator_t* create_policy_enumerator(private_child_sa_t *this)
}
/**
- * Implementation of child_sa_t.get_usetime
+ * update the cached usebytes
+ * returns SUCCESS if the usebytes have changed, FAILED if not or no SPIs
+ * are available, and NOT_SUPPORTED if the kernel interface does not support
+ * querying the usebytes.
+ */
+static status_t update_usebytes(private_child_sa_t *this, bool inbound)
+{
+ status_t status = FAILED;
+ u_int64_t bytes;
+
+ if (inbound)
+ {
+ if (this->my_spi)
+ {
+ status = charon->kernel_interface->query_sa(
+ charon->kernel_interface,
+ this->other_addr, this->my_addr,
+ this->my_spi, this->protocol, &bytes);
+ if (status == SUCCESS)
+ {
+ if (bytes > this->my_usebytes)
+ {
+ this->my_usebytes = bytes;
+ return SUCCESS;
+ }
+ return FAILED;
+ }
+ }
+ }
+ else
+ {
+ if (this->other_spi)
+ {
+ status = charon->kernel_interface->query_sa(
+ charon->kernel_interface,
+ this->my_addr, this->other_addr,
+ this->other_spi, this->protocol, &bytes);
+ if (status == SUCCESS)
+ {
+ if (bytes > this->other_usebytes)
+ {
+ this->other_usebytes = bytes;
+ return SUCCESS;
+ }
+ return FAILED;
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * updates the cached usetime
*/
-static u_int32_t get_usetime(private_child_sa_t *this, bool inbound)
+static void update_usetime(private_child_sa_t *this, bool inbound)
{
enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts;
u_int32_t last_use = 0;
-
+
enumerator = create_policy_enumerator(this);
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
{
u_int32_t in, out, fwd;
- if (inbound)
+ if (inbound)
{
if (charon->kernel_interface->query_policy(charon->kernel_interface,
other_ts, my_ts, POLICY_IN, &in) == SUCCESS)
@@ -394,7 +466,42 @@ static u_int32_t get_usetime(private_child_sa_t *this, bool inbound)
}
}
enumerator->destroy(enumerator);
- return last_use;
+
+ if (last_use == 0)
+ {
+ return;
+ }
+ if (inbound)
+ {
+ this->my_usetime = last_use;
+ }
+ else
+ {
+ this->other_usetime = last_use;
+ }
+}
+
+/**
+ * Implementation of child_sa_t.get_usestats
+ */
+static void get_usestats(private_child_sa_t *this, bool inbound,
+ time_t *time, u_int64_t *bytes)
+{
+ if (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)
+ {
+ *time = inbound ? this->my_usetime : this->other_usetime;
+ }
+ if (bytes)
+ {
+ *bytes = inbound ? this->my_usebytes : this->other_usebytes;
+ }
}
/**
@@ -566,13 +673,13 @@ static status_t add_policies(private_child_sa_t *this,
* Implementation of child_sa_t.update.
*/
static status_t update(private_child_sa_t *this, host_t *me, host_t *other,
- host_t *vip, bool encap)
+ host_t *vip, bool encap)
{
child_sa_state_t old;
bool transport_proxy_mode;
/* anything changed at all? */
- if (me->equals(me, this->my_addr) &&
+ if (me->equals(me, this->my_addr) &&
other->equals(other, this->other_addr) && this->encap == encap)
{
return SUCCESS;
@@ -661,7 +768,7 @@ static status_t update(private_child_sa_t *this, host_t *me, host_t *other,
me, other, my_ts, other_ts, POLICY_OUT, this->other_spi,
this->protocol, this->reqid, this->mode, this->ipcomp,
this->other_cpi, FALSE);
- charon->kernel_interface->add_policy(charon->kernel_interface,
+ charon->kernel_interface->add_policy(charon->kernel_interface,
other, me, other_ts, my_ts, POLICY_IN, this->my_spi,
this->protocol, this->reqid, this->mode, this->ipcomp,
this->my_cpi, FALSE);
@@ -775,7 +882,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->public.get_proposal = (proposal_t*(*)(child_sa_t*))get_proposal;
this->public.set_proposal = (void(*)(child_sa_t*, proposal_t *proposal))set_proposal;
this->public.get_lifetime = (u_int32_t(*)(child_sa_t*, bool))get_lifetime;
- this->public.get_usetime = (u_int32_t(*)(child_sa_t*, bool))get_usetime;
+ this->public.get_usestats = (void(*)(child_sa_t*,bool,time_t*,u_int64_t*))get_usestats;
this->public.has_encap = (bool(*)(child_sa_t*))has_encap;
this->public.get_ipcomp = (ipcomp_transform_t(*)(child_sa_t*))get_ipcomp;
this->public.set_ipcomp = (void(*)(child_sa_t*,ipcomp_transform_t))set_ipcomp;
@@ -798,6 +905,10 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->encap = encap;
this->ipcomp = IPCOMP_NONE;
this->state = CHILD_CREATED;
+ this->my_usetime = 0;
+ this->other_usetime = 0;
+ this->my_usebytes = 0;
+ this->other_usebytes = 0;
/* reuse old reqid if we are rekeying an existing CHILD_SA */
this->reqid = rekey ? rekey : ++reqid;
this->my_ts = linked_list_create();
@@ -810,7 +921,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->config = config;
config->get_ref(config);
- /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
+ /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
if (config->get_mode(config) == MODE_TRANSPORT &&
config->use_proxy_mode(config))
{
@@ -837,7 +948,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
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, host);
this->my_addr->destroy(this->my_addr);
this->my_addr = host;
}
@@ -858,7 +969,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
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, host);
this->other_addr->destroy(this->other_addr);
this->other_addr = host;
}
diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h
index ec9b36dab..698da8bc7 100644
--- a/src/charon/sa/child_sa.h
+++ b/src/charon/sa/child_sa.h
@@ -85,11 +85,11 @@ extern enum_name_t *child_sa_state_names;
/**
* Represents an IPsec SAs between two hosts.
- *
+ *
* A child_sa_t contains two SAs. SAs for both
* directions are managed in one child_sa_t object. Both
* SAs and the policies have the same reqid.
- *
+ *
* The procedure for child sa setup is as follows:
* - A gets SPIs for a all protocols in its proposals via child_sa_t.alloc
* - A send the proposals with the allocated SPIs to B
@@ -98,7 +98,7 @@ extern enum_name_t *child_sa_state_names;
* - B calls child_sa_t.install for both, the allocated and received SPI
* - B sends the proposal with the allocated SPI to A
* - A calls child_sa_t.install for both, the allocated and recevied SPI
- *
+ *
* Once SAs are set up, policies can be added using add_policies.
*/
struct child_sa_t {
@@ -112,7 +112,7 @@ struct child_sa_t {
/**
* Get the reqid of the CHILD SA.
- *
+ *
* Every CHILD_SA has a reqid. The kernel uses this ID to
* identify it.
*
@@ -131,19 +131,19 @@ struct child_sa_t {
* Get the state of the CHILD_SA.
*
* @return CHILD_SA state
- */
+ */
child_sa_state_t (*get_state) (child_sa_t *this);
/**
* Set the state of the CHILD_SA.
*
* @param state state to set on CHILD_SA
- */
+ */
void (*set_state) (child_sa_t *this, child_sa_state_t state);
/**
* Get the SPI of this CHILD_SA.
- *
+ *
* Set the boolean parameter inbound to TRUE to
* get the SPI for which we receive packets, use
* FALSE to get those we use for sending packets.
@@ -155,7 +155,7 @@ struct child_sa_t {
/**
* Get the CPI of this CHILD_SA.
- *
+ *
* Set the boolean parameter inbound to TRUE to
* get the CPI for which we receive packets, use
* FALSE to get those we use for sending packets.
@@ -202,7 +202,7 @@ struct child_sa_t {
/**
* Set the IPComp algorithm to use.
- *
+ *
* @param ipcomp the IPComp transform to use
*/
void (*set_ipcomp)(child_sa_t *this, ipcomp_transform_t ipcomp);
@@ -219,7 +219,7 @@ struct child_sa_t {
*
* @param proposal selected proposal
*/
- void (*set_proposal)(child_sa_t *this, proposal_t *proposal);
+ void (*set_proposal)(child_sa_t *this, proposal_t *proposal);
/**
* Check if this CHILD_SA uses UDP encapsulation.
@@ -237,19 +237,21 @@ struct child_sa_t {
u_int32_t (*get_lifetime)(child_sa_t *this, bool hard);
/**
- * Get last use time of the CHILD_SA.
+ * Get last use time and the number of bytes processed.
*
- * @param inbound TRUE for inbound traffic, FALSE for outbound
- * @return time of last use in seconds
+ * @param inbound TRUE for inbound traffic, FALSE for outbound
+ * @param[out] time time of last use in seconds (NULL to ignore)
+ * @param[out] bytes number of processed bytes (NULL to ignore)
*/
- u_int32_t (*get_usetime)(child_sa_t *this, bool inbound);
+ void (*get_usestats)(child_sa_t *this, bool inbound, time_t *time,
+ u_int64_t *bytes);
/**
* Get the traffic selectors list added for one side.
*
* @param local TRUE for own traffic selectors, FALSE for remote
* @return list of traffic selectors
- */
+ */
linked_list_t* (*get_traffic_selectors) (child_sa_t *this, bool local);
/**
@@ -296,7 +298,7 @@ struct child_sa_t {
* @param my_ts traffic selectors for local site
* @param other_ts traffic selectors for remote site
* @return SUCCESS or FAILED
- */
+ */
status_t (*add_policies)(child_sa_t *this, linked_list_t *my_ts_list,
linked_list_t *other_ts_list);
/**
diff --git a/src/charon/sa/connect_manager.c b/src/charon/sa/connect_manager.c
index a1b037de4..f26cf9405 100644
--- a/src/charon/sa/connect_manager.c
+++ b/src/charon/sa/connect_manager.c
@@ -1568,7 +1568,7 @@ connect_manager_t *connect_manager_create()
this->checklists = linked_list_create();
this->initiated = linked_list_create();
- this->mutex = mutex_create(MUTEX_DEFAULT);
+ this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
return (connect_manager_t*)this;
}
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c
index 6b7fa3582..be973a2ce 100644
--- a/src/charon/sa/ike_sa.c
+++ b/src/charon/sa/ike_sa.c
@@ -260,7 +260,7 @@ static time_t get_use_time(private_ike_sa_t* this, bool inbound)
{
enumerator_t *enumerator;
child_sa_t *child_sa;
- time_t use_time;
+ time_t use_time, current;
if (inbound)
{
@@ -273,7 +273,8 @@ static time_t get_use_time(private_ike_sa_t* this, bool inbound)
enumerator = this->child_sas->create_enumerator(this->child_sas);
while (enumerator->enumerate(enumerator, &child_sa))
{
- use_time = max(use_time, child_sa->get_usetime(child_sa, inbound));
+ child_sa->get_usestats(child_sa, inbound, &current, NULL);
+ use_time = max(use_time, current);
}
enumerator->destroy(enumerator);
@@ -1169,7 +1170,8 @@ static status_t initiate(private_ike_sa_t *this,
#endif /* ME */
{
/* normal IKE_SA with CHILD_SA */
- task = (task_t*)child_create_create(&this->public, child_cfg, tsi, tsr);
+ task = (task_t*)child_create_create(&this->public, child_cfg, FALSE,
+ tsi, tsr);
child_cfg->destroy(child_cfg);
if (reqid)
{
@@ -1747,6 +1749,7 @@ static status_t roam(private_ike_sa_t *this, bool address)
{
case IKE_CREATED:
case IKE_DELETING:
+ case IKE_DESTROYING:
case IKE_PASSIVE:
return SUCCESS;
default:
@@ -1775,10 +1778,46 @@ static status_t roam(private_ike_sa_t *this, bool address)
DBG2(DBG_IKE, "keeping connection path %H - %H",
src, this->other_host);
src->destroy(src);
+ set_condition(this, COND_STALE, FALSE);
+ return SUCCESS;
+ }
+ src->destroy(src);
+
+ }
+ else
+ {
+ /* check if we find a route at all */
+ enumerator_t *enumerator;
+ host_t *addr;
+
+ src = charon->kernel_interface->get_source_addr(charon->kernel_interface,
+ this->other_host, NULL);
+ if (!src)
+ {
+ enumerator = this->additional_addresses->create_enumerator(
+ this->additional_addresses);
+ while (enumerator->enumerate(enumerator, &addr))
+ {
+ DBG1(DBG_IKE, "looking for a route to %H ...", addr);
+ src = charon->kernel_interface->get_source_addr(
+ charon->kernel_interface, addr, NULL);
+ if (src)
+ {
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
+ if (!src)
+ {
+ DBG1(DBG_IKE, "no route found to reach %H, MOBIKE update deferred",
+ this->other_host);
+ set_condition(this, COND_STALE, TRUE);
return SUCCESS;
}
src->destroy(src);
}
+ set_condition(this, COND_STALE, FALSE);
/* update addresses with mobike, if supported ... */
if (supports_extension(this, EXT_MOBIKE))
diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h
index b751bda0c..41d7a7976 100644
--- a/src/charon/sa/ike_sa.h
+++ b/src/charon/sa/ike_sa.h
@@ -127,6 +127,11 @@ enum ike_condition_t {
* Local peer is the "original" IKE initiator. Unaffected from rekeying.
*/
COND_ORIGINAL_INITIATOR = (1<<6),
+
+ /**
+ * IKE_SA is stale, the peer is currently unreachable (MOBIKE)
+ */
+ COND_STALE = (1<<7),
};
/**
diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c
index efe7c228c..ec1a7f741 100644
--- a/src/charon/sa/ike_sa_manager.c
+++ b/src/charon/sa/ike_sa_manager.c
@@ -133,7 +133,7 @@ static entry_t *entry_create()
entry_t *this = malloc_thing(entry_t);
this->waiting_threads = 0;
- this->condvar = condvar_create(CONDVAR_DEFAULT);
+ this->condvar = condvar_create(CONDVAR_TYPE_DEFAULT);
/* we set checkout flag when we really give it out */
this->checked_out = FALSE;
@@ -1050,7 +1050,8 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this,
enumerator_t *enumerator;
entry_t *entry;
ike_sa_t *ike_sa = NULL;
- peer_cfg_t *current_cfg;
+ peer_cfg_t *current_peer;
+ ike_cfg_t *current_ike;
u_int segment;
if (!this->reuse_ikesa)
@@ -1072,14 +1073,18 @@ static ike_sa_t* checkout_by_config(private_ike_sa_manager_t *this,
continue;
}
- current_cfg = entry->ike_sa->get_peer_cfg(entry->ike_sa);
- if (current_cfg && current_cfg->equals(current_cfg, peer_cfg))
+ current_peer = entry->ike_sa->get_peer_cfg(entry->ike_sa);
+ if (current_peer && current_peer->equals(current_peer, peer_cfg))
{
- DBG2(DBG_MGR, "found an existing IKE_SA with a '%s' config",
- current_cfg->get_name(current_cfg));
- entry->checked_out = TRUE;
- ike_sa = entry->ike_sa;
- break;
+ current_ike = current_peer->get_ike_cfg(current_peer);
+ if (current_ike->equals(current_ike, peer_cfg->get_ike_cfg(peer_cfg)))
+ {
+ DBG2(DBG_MGR, "found an existing IKE_SA with a '%s' config",
+ current_peer->get_name(current_peer));
+ entry->checked_out = TRUE;
+ ike_sa = entry->ike_sa;
+ break;
+ }
}
}
enumerator->destroy(enumerator);
@@ -1554,6 +1559,17 @@ static void flush(private_ike_sa_manager_t *this)
while (enumerator->enumerate(enumerator, &entry, &segment))
{
charon->bus->set_sa(charon->bus, entry->ike_sa);
+ /* as the delete never gets processed, fire down events */
+ switch (entry->ike_sa->get_state(entry->ike_sa))
+ {
+ case IKE_ESTABLISHED:
+ case IKE_REKEYING:
+ case IKE_DELETING:
+ charon->bus->ike_updown(charon->bus, entry->ike_sa, FALSE);
+ break;
+ default:
+ break;
+ }
entry->ike_sa->delete(entry->ike_sa);
}
enumerator->destroy(enumerator);
@@ -1695,7 +1711,7 @@ ike_sa_manager_t *ike_sa_manager_create()
this->segments = (segment_t*)calloc(this->segment_count, sizeof(segment_t));
for (i = 0; i < this->segment_count; ++i)
{
- this->segments[i].mutex = mutex_create(MUTEX_RECURSIVE);
+ this->segments[i].mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
this->segments[i].count = 0;
}
@@ -1704,7 +1720,7 @@ ike_sa_manager_t *ike_sa_manager_create()
this->half_open_segments = calloc(this->segment_count, sizeof(shareable_segment_t));
for (i = 0; i < this->segment_count; ++i)
{
- this->half_open_segments[i].lock = rwlock_create(RWLOCK_DEFAULT);
+ this->half_open_segments[i].lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
this->half_open_segments[i].count = 0;
}
@@ -1713,7 +1729,7 @@ ike_sa_manager_t *ike_sa_manager_create()
this->connected_peers_segments = calloc(this->segment_count, sizeof(shareable_segment_t));
for (i = 0; i < this->segment_count; ++i)
{
- this->connected_peers_segments[i].lock = rwlock_create(RWLOCK_DEFAULT);
+ this->connected_peers_segments[i].lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
this->connected_peers_segments[i].count = 0;
}
diff --git a/src/charon/sa/keymat.c b/src/charon/sa/keymat.c
index 117d260ba..46fb79587 100644
--- a/src/charon/sa/keymat.c
+++ b/src/charon/sa/keymat.c
@@ -419,6 +419,9 @@ static bool derive_child_keys(private_keymat_t *this,
case ENCR_AES_CCM_ICV8:
case ENCR_AES_CCM_ICV12:
case ENCR_AES_CCM_ICV16:
+ case ENCR_CAMELLIA_CCM_ICV8:
+ case ENCR_CAMELLIA_CCM_ICV12:
+ case ENCR_CAMELLIA_CCM_ICV16:
enc_size += 3;
break;
case ENCR_AES_GCM_ICV8:
diff --git a/src/charon/sa/mediation_manager.c b/src/charon/sa/mediation_manager.c
index 890e567c7..a69c00173 100644
--- a/src/charon/sa/mediation_manager.c
+++ b/src/charon/sa/mediation_manager.c
@@ -331,7 +331,7 @@ mediation_manager_t *mediation_manager_create()
this->public.check_and_register = (ike_sa_id_t*(*)(mediation_manager_t*,identification_t*,identification_t*))check_and_register;
this->peers = linked_list_create();
- this->mutex = mutex_create(MUTEX_DEFAULT);
+ this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
return (mediation_manager_t*)this;
}
diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c
index 2cd9532eb..f33fcd6d4 100644
--- a/src/charon/sa/task_manager.c
+++ b/src/charon/sa/task_manager.c
@@ -220,6 +220,10 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
{
DBG1(DBG_IKE, "giving up after %d retransmits",
this->initiating.retransmitted - 1);
+ if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING)
+ {
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+ }
return DESTROY_ME;
}
@@ -240,6 +244,7 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
{
DBG1(DBG_IKE, "giving up after %d path probings",
this->initiating.retransmitted - 1);
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
return DESTROY_ME;
}
@@ -431,6 +436,12 @@ static status_t build_request(private_task_manager_t *this)
break;
case FAILED:
default:
+ if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING)
+ {
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+ }
+ /* FALL */
+ case DESTROY_ME:
/* critical failure, destroy IKE_SA */
iterator->destroy(iterator);
message->destroy(message);
@@ -451,6 +462,7 @@ static status_t build_request(private_task_manager_t *this)
* close the SA */
message->destroy(message);
flush(this);
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
return DESTROY_ME;
}
@@ -474,6 +486,7 @@ static status_t process_response(private_task_manager_t *this,
DBG1(DBG_IKE, "received %N response, but expected %N",
exchange_type_names, message->get_exchange_type(message),
exchange_type_names, this->initiating.type);
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
return DESTROY_ME;
}
@@ -494,6 +507,9 @@ static status_t process_response(private_task_manager_t *this,
break;
case FAILED:
default:
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+ /* FALL */
+ case DESTROY_ME:
/* critical failure, destroy IKE_SA */
iterator->remove(iterator);
iterator->destroy(iterator);
@@ -604,6 +620,9 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
break;
case FAILED:
default:
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+ /* FALL */
+ case DESTROY_ME:
/* destroy IKE_SA, but SEND response first */
delete = TRUE;
break;
@@ -631,6 +650,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
message->destroy(message);
if (status != SUCCESS)
{
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
return DESTROY_ME;
}
@@ -678,7 +698,8 @@ static status_t process_request(private_task_manager_t *this,
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)ike_config_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
- task = (task_t*)child_create_create(this->ike_sa, NULL, NULL, NULL);
+ task = (task_t*)child_create_create(this->ike_sa, NULL, FALSE,
+ NULL, NULL);
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)ike_auth_lifetime_create(this->ike_sa, FALSE);
this->passive_tasks->insert_last(this->passive_tasks, task);
@@ -726,8 +747,8 @@ static status_t process_request(private_task_manager_t *this,
}
else
{
- task = (task_t*)child_create_create(this->ike_sa,
- NULL, NULL, NULL);
+ task = (task_t*)child_create_create(this->ike_sa, NULL,
+ FALSE, NULL, NULL);
}
}
else
@@ -831,6 +852,9 @@ static status_t process_request(private_task_manager_t *this,
break;
case FAILED:
default:
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+ /* FALL */
+ case DESTROY_ME:
/* critical failure, destroy IKE_SA */
iterator->remove(iterator);
iterator->destroy(iterator);
diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c
index f51443738..558938f2e 100644
--- a/src/charon/sa/tasks/child_create.c
+++ b/src/charon/sa/tasks/child_create.c
@@ -158,6 +158,11 @@ struct private_child_create_t {
* successfully established the CHILD?
*/
bool established;
+
+ /**
+ * whether the CHILD_SA rekeys an existing one
+ */
+ bool rekey;
};
/**
@@ -249,7 +254,7 @@ static bool allocate_spi(private_child_create_t *this)
*/
static status_t select_and_install(private_child_create_t *this, bool no_dh)
{
- status_t status;
+ status_t status, status_i, status_o;
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;
@@ -401,22 +406,22 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
this->my_cpi = this->other_cpi = 0;
this->ipcomp = IPCOMP_NONE;
}
- status = FAILED;
+ status_i = status_o = FAILED;
if (this->keymat->derive_child_keys(this->keymat, this->proposal,
this->dh, nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r))
{
if (this->initiator)
{
- status = this->child_sa->install(this->child_sa, encr_r, integ_r,
+ status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
this->my_spi, this->my_cpi, TRUE);
- status = this->child_sa->install(this->child_sa, encr_i, integ_i,
+ status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
this->other_spi, this->other_cpi, FALSE);
}
else
{
- status = this->child_sa->install(this->child_sa, encr_i, integ_i,
+ status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
this->my_spi, this->my_cpi, TRUE);
- status = this->child_sa->install(this->child_sa, encr_r, integ_r,
+ status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
this->other_spi, this->other_cpi, FALSE);
}
}
@@ -425,9 +430,12 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
chunk_clear(&encr_i);
chunk_clear(&encr_r);
- if (status != SUCCESS)
+ if (status_i != SUCCESS || status_o != SUCCESS)
{
- DBG1(DBG_IKE, "unable to install IPsec SA (SAD) in kernel");
+ DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel",
+ (status_i != SUCCESS) ? "inbound " : "",
+ (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
+ (status_o != SUCCESS) ? "outbound " : "");
return FAILED;
}
@@ -939,7 +947,11 @@ static status_t build_r(private_child_create_t *this, message_t *message)
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);
+ }
return SUCCESS;
}
@@ -1052,6 +1064,11 @@ static status_t process_i(private_child_create_t *this, message_t *message)
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);
+ }
}
else
{
@@ -1174,7 +1191,8 @@ static void destroy(private_child_create_t *this)
/*
* Described in header.
*/
-child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config,
+child_create_t *child_create_create(ike_sa_t *ike_sa,
+ child_cfg_t *config, bool rekey,
traffic_selector_t *tsi, traffic_selector_t *tsr)
{
private_child_create_t *this = malloc_thing(private_child_create_t);
@@ -1222,6 +1240,7 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config,
this->other_cpi = 0;
this->reqid = 0;
this->established = FALSE;
+ this->rekey = rekey;
return &this->public;
}
diff --git a/src/charon/sa/tasks/child_create.h b/src/charon/sa/tasks/child_create.h
index ce2829a9a..41f4fe2c8 100644
--- a/src/charon/sa/tasks/child_create.h
+++ b/src/charon/sa/tasks/child_create.h
@@ -71,11 +71,13 @@ struct child_create_t {
*
* @param ike_sa IKE_SA this task works for
* @param config child_cfg if task initiator, NULL if responder
+ * @param rekey whether we do a rekey or not
* @param tsi source of triggering packet, or NULL
* @param tsr destination of triggering packet, or NULL
* @return child_create task to handle by the task_manager
*/
-child_create_t *child_create_create(ike_sa_t *ike_sa, child_cfg_t *config,
+child_create_t *child_create_create(ike_sa_t *ike_sa,
+ child_cfg_t *config, bool rekey,
traffic_selector_t *tsi, traffic_selector_t *tsr);
#endif /** CHILD_CREATE_H_ @}*/
diff --git a/src/charon/sa/tasks/child_delete.c b/src/charon/sa/tasks/child_delete.c
index 0d89c148e..7abb07a84 100644
--- a/src/charon/sa/tasks/child_delete.c
+++ b/src/charon/sa/tasks/child_delete.c
@@ -52,11 +52,16 @@ struct private_child_delete_t {
u_int32_t spi;
/**
- * wheter to enforce delete action policy
+ * whether to enforce delete action policy
*/
bool check_delete_action;
/**
+ * is this delete exchange following a rekey?
+ */
+ bool rekeyed;
+
+ /**
* CHILD_SAs which get deleted
*/
linked_list_t *child_sas;
@@ -148,6 +153,7 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
switch (child_sa->get_state(child_sa))
{
case CHILD_REKEYING:
+ this->rekeyed = TRUE;
/* we reply as usual, rekeying will fail */
break;
case CHILD_DELETING:
@@ -190,6 +196,11 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
+ /* signal child down event if we are not rekeying */
+ if (!this->rekeyed)
+ {
+ charon->bus->child_updown(charon->bus, child_sa, FALSE);
+ }
spi = child_sa->get_spi(child_sa, TRUE);
protocol = child_sa->get_protocol(child_sa);
child_cfg = child_sa->get_config(child_sa);
@@ -229,15 +240,19 @@ static void log_children(private_child_delete_t *this)
{
iterator_t *iterator;
child_sa_t *child_sa;
+ u_int64_t bytes_in, bytes_out;
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
+ child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in);
+ child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out);
+
DBG0(DBG_IKE, "closing CHILD_SA %s{%d} "
- "with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
+ "with SPIs %.8x_i (%llu bytes) %.8x_o (%llu bytes) 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)),
+ 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));
}
@@ -258,7 +273,10 @@ static status_t build_i(private_child_delete_t *this, message_t *message)
return SUCCESS;
}
this->child_sas->insert_last(this->child_sas, child_sa);
-
+ if (child_sa->get_state(child_sa) == CHILD_REKEYING)
+ {
+ this->rekeyed = TRUE;
+ }
log_children(this);
build_payloads(this, message);
return NEED_MORE;
@@ -359,6 +377,7 @@ child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol,
this->child_sas = linked_list_create();
this->protocol = protocol;
this->spi = spi;
+ this->rekeyed = FALSE;
if (protocol != PROTO_NONE)
{
diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c
index 6ab00dc5b..601e054ea 100644
--- a/src/charon/sa/tasks/child_rekey.c
+++ b/src/charon/sa/tasks/child_rekey.c
@@ -157,7 +157,8 @@ static status_t build_i(private_child_rekey_t *this, message_t *message)
/* ... our CHILD_CREATE task does the hard work for us. */
reqid = this->child_sa->get_reqid(this->child_sa);
- this->child_create = child_create_create(this->ike_sa, config, NULL, NULL);
+ this->child_create = child_create_create(this->ike_sa, config, TRUE,
+ NULL, NULL);
this->child_create->use_reqid(this->child_create, reqid);
this->child_create->task.build(&this->child_create->task, message);
@@ -207,6 +208,10 @@ static status_t build_r(private_child_rekey_t *this, message_t *message)
}
this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
+
+ /* invoke rekey hook */
+ charon->bus->child_rekey(charon->bus, this->child_sa,
+ this->child_create->get_child(this->child_create));
return SUCCESS;
}
@@ -303,6 +308,12 @@ static status_t process_i(private_child_rekey_t *this, message_t *message)
}
}
+ if (to_delete != this->child_create->get_child(this->child_create))
+ { /* invoke rekey hook if rekeying successful */
+ charon->bus->child_rekey(charon->bus, this->child_sa,
+ this->child_create->get_child(this->child_create));
+ }
+
spi = to_delete->get_spi(to_delete, TRUE);
protocol = to_delete->get_protocol(to_delete);
@@ -416,7 +427,7 @@ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol,
this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
this->initiator = FALSE;
- this->child_create = child_create_create(ike_sa, NULL, NULL, NULL);
+ this->child_create = child_create_create(ike_sa, NULL, TRUE, NULL, NULL);
}
this->ike_sa = ike_sa;
diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c
index 8d6cd56bd..d0b2a7e91 100644
--- a/src/charon/sa/tasks/ike_auth.c
+++ b/src/charon/sa/tasks/ike_auth.c
@@ -738,6 +738,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message)
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
+ charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
return SUCCESS;
}
return NEED_MORE;
@@ -916,6 +917,7 @@ static status_t process_i(private_ike_auth_t *this, message_t *message)
this->ike_sa->get_my_id(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
this->ike_sa->get_other_id(this->ike_sa));
+ charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE);
return SUCCESS;
}
return NEED_MORE;
diff --git a/src/charon/sa/tasks/ike_delete.c b/src/charon/sa/tasks/ike_delete.c
index f308a6358..cde117934 100644
--- a/src/charon/sa/tasks/ike_delete.c
+++ b/src/charon/sa/tasks/ike_delete.c
@@ -21,7 +21,7 @@
typedef struct private_ike_delete_t private_ike_delete_t;
-/**file
+/**
* Private members of a ike_delete_t task.
*/
struct private_ike_delete_t {
@@ -42,6 +42,11 @@ struct private_ike_delete_t {
bool initiator;
/**
+ * are we deleting a rekeyed SA?
+ */
+ bool rekeyed;
+
+ /**
* are we responding to a delete, but have initated our own?
*/
bool simultaneous;
@@ -64,6 +69,11 @@ static status_t build_i(private_ike_delete_t *this, message_t *message)
delete_payload = delete_payload_create(PROTO_IKE);
message->add_payload(message, (payload_t*)delete_payload);
+
+ if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING)
+ {
+ this->rekeyed = TRUE;
+ }
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
DBG1(DBG_IKE, "sending DELETE for IKE_SA %s[%d]",
@@ -79,8 +89,12 @@ static status_t build_i(private_ike_delete_t *this, message_t *message)
static status_t process_i(private_ike_delete_t *this, message_t *message)
{
DBG0(DBG_IKE, "IKE_SA deleted");
- /* completed, delete IKE_SA by returning FAILED */
- return FAILED;
+ if (!this->rekeyed)
+ { /* invoke ike_down() hook if SA has not been rekeyed */
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+ }
+ /* completed, delete IKE_SA by returning DESTROY_ME */
+ return DESTROY_ME;
}
/**
@@ -106,14 +120,17 @@ static status_t process_r(private_ike_delete_t *this, message_t *message)
case IKE_ESTABLISHED:
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
this->ike_sa->reestablish(this->ike_sa);
+ return NEED_MORE;
+ case IKE_REKEYING:
+ this->rekeyed = TRUE;
break;
case IKE_DELETING:
this->simultaneous = TRUE;
- /* FALL */
+ break;
default:
- this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
break;
}
+ this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
return NEED_MORE;
}
@@ -129,8 +146,12 @@ static status_t build_r(private_ike_delete_t *this, message_t *message)
/* wait for peer's response for our delete request, but set a timeout */
return SUCCESS;
}
- /* completed, delete IKE_SA by returning FAILED */
- return FAILED;
+ if (!this->rekeyed)
+ { /* invoke ike_down() hook if SA has not been rekeyed */
+ charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
+ }
+ /* completed, delete IKE_SA by returning DESTROY_ME */
+ return DESTROY_ME;
}
/**
@@ -182,6 +203,7 @@ ike_delete_t *ike_delete_create(ike_sa_t *ike_sa, bool initiator)
this->ike_sa = ike_sa;
this->initiator = initiator;
+ this->rekeyed = FALSE;
this->simultaneous = FALSE;
return &this->public;
diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c
index bead408a6..3a049b566 100644
--- a/src/charon/sa/tasks/ike_rekey.c
+++ b/src/charon/sa/tasks/ike_rekey.c
@@ -367,6 +367,8 @@ static void destroy(private_ike_rekey_t *this)
if (this->new_sa->get_state(this->new_sa) == IKE_ESTABLISHED &&
this->new_sa->inherit(this->new_sa, this->ike_sa) != DESTROY_ME)
{
+ /* invoke hook if rekeying was successful */
+ charon->bus->ike_rekey(charon->bus, this->ike_sa, this->new_sa);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, this->new_sa);
}
else
diff --git a/src/charon/sa/tasks/task.h b/src/charon/sa/tasks/task.h
index f9b409f35..3d2014599 100644
--- a/src/charon/sa/tasks/task.h
+++ b/src/charon/sa/tasks/task.h
@@ -100,7 +100,8 @@ struct task_t {
*
* @param message message to add payloads to
* @return
- * - FAILED if a critical error occured
+ * - FAILED if a critical error occured
+ * - DESTROY_ME if IKE_SA has been properly deleted
* - NEED_MORE if another call to build/process needed
* - SUCCESS if task completed
*/
@@ -112,6 +113,7 @@ struct task_t {
* @param message message to read payloads from
* @return
* - FAILED if a critical error occured
+ * - DESTROY_ME if IKE_SA has been properly deleted
* - NEED_MORE if another call to build/process needed
* - SUCCESS if task completed
*/
diff --git a/src/charon/sa/trap_manager.c b/src/charon/sa/trap_manager.c
index a74fab93f..570335eb4 100644
--- a/src/charon/sa/trap_manager.c
+++ b/src/charon/sa/trap_manager.c
@@ -156,6 +156,10 @@ static u_int32_t install(private_trap_manager_t *this, peer_cfg_t *peer,
me->destroy(me);
other->destroy(other);
+ /* while we don't know the finally negotiated protocol (ESP|AH), we
+ * could iterate all proposals for a best guest (TODO). But as we
+ * support ESP only for now, we set here. */
+ child_sa->set_protocol(child_sa, PROTO_ESP);
child_sa->set_mode(child_sa, child->get_mode(child));
status = child_sa->add_policies(child_sa, my_ts, other_ts);
my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
@@ -358,7 +362,7 @@ trap_manager_t *trap_manager_create()
this->public.destroy = (void(*)(trap_manager_t*))destroy;
this->traps = linked_list_create();
- this->lock = rwlock_create(RWLOCK_DEFAULT);
+ this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
/* register listener for IKE state changes */
this->listener.traps = this;