summaryrefslogtreecommitdiff
path: root/src/libcharon/sa/ike_sa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/sa/ike_sa.c')
-rw-r--r--src/libcharon/sa/ike_sa.c305
1 files changed, 174 insertions, 131 deletions
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,