summaryrefslogtreecommitdiff
path: root/src/libcharon
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2019-01-02 10:45:36 +0100
committerYves-Alexis Perez <corsac@debian.org>2019-01-02 11:07:05 +0100
commit918094fde55fa0dbfd59a5f88d576efb513a88db (patch)
tree61e31656c60a6cc928c50cd633568043673e2cbd /src/libcharon
parent69bc96f6b0b388d35e983f8d27224fa49d92918c (diff)
downloadvyos-strongswan-918094fde55fa0dbfd59a5f88d576efb513a88db.tar.gz
vyos-strongswan-918094fde55fa0dbfd59a5f88d576efb513a88db.zip
New upstream version 5.7.2
Diffstat (limited to 'src/libcharon')
-rw-r--r--src/libcharon/bus/bus.c5
-rw-r--r--src/libcharon/bus/bus.h4
-rw-r--r--src/libcharon/bus/listeners/listener.h4
-rw-r--r--src/libcharon/plugins/bypass_lan/bypass_lan_listener.c26
-rw-r--r--src/libcharon/plugins/dhcp/dhcp_socket.c10
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius.c12
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_accounting.c59
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_accounting.h10
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_provider.c32
-rw-r--r--src/libcharon/plugins/eap_radius/eap_radius_provider.h11
-rw-r--r--src/libcharon/plugins/ha/ha_attribute.c13
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.c4
-rw-r--r--src/libcharon/plugins/ha/ha_ike.c6
-rw-r--r--src/libcharon/plugins/ha/ha_message.c2
-rw-r--r--src/libcharon/plugins/ha/ha_message.h2
-rw-r--r--src/libcharon/plugins/ha/ha_segments.c7
-rw-r--r--src/libcharon/plugins/ha/ha_segments.h7
-rw-r--r--src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c17
-rw-r--r--src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c27
-rw-r--r--src/libcharon/plugins/vici/libvici.h8
-rw-r--r--src/libcharon/plugins/vici/vici_config.c7
-rw-r--r--src/libcharon/processing/jobs/adopt_children_job.c52
-rw-r--r--src/libcharon/sa/child_sa.c4
-rw-r--r--src/libcharon/sa/ike_sa.c45
-rw-r--r--src/libcharon/sa/ike_sa.h17
-rw-r--r--src/libcharon/sa/ike_sa_manager.c2
-rw-r--r--src/libcharon/sa/ikev1/phase1.c3
-rw-r--r--src/libcharon/sa/ikev1/task_manager_v1.c134
-rw-r--r--src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c1
-rw-r--r--src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c1
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.c9
-rw-r--r--src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c97
-rw-r--r--src/libcharon/sa/ikev2/task_manager_v2.c227
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_delete.c24
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_init.c16
-rw-r--r--src/libcharon/sa/task_manager.h19
-rw-r--r--src/libcharon/tests/suites/test_child_rekey.c46
37 files changed, 723 insertions, 247 deletions
diff --git a/src/libcharon/bus/bus.c b/src/libcharon/bus/bus.c
index f4c01c22e..b7348f0f9 100644
--- a/src/libcharon/bus/bus.c
+++ b/src/libcharon/bus/bus.c
@@ -575,7 +575,7 @@ METHOD(bus_t, message, void,
METHOD(bus_t, ike_keys, void,
private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r,
- ike_sa_t *rekey, shared_key_t *shared)
+ ike_sa_t *rekey, shared_key_t *shared, auth_method_t method)
{
enumerator_t *enumerator;
entry_t *entry;
@@ -591,7 +591,8 @@ METHOD(bus_t, ike_keys, void,
}
entry->calling++;
keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, dh_other,
- nonce_i, nonce_r, rekey, shared);
+ nonce_i, nonce_r, rekey, shared,
+ method);
entry->calling--;
if (!keep)
{
diff --git a/src/libcharon/bus/bus.h b/src/libcharon/bus/bus.h
index df75683be..8a97e8dfc 100644
--- a/src/libcharon/bus/bus.h
+++ b/src/libcharon/bus/bus.h
@@ -353,10 +353,12 @@ struct bus_t {
* @param nonce_r responder's nonce
* @param rekey IKE_SA we are rekeying, if any (IKEv2 only)
* @param shared shared key used for key derivation (IKEv1-PSK only)
+ * @param method auth method for key derivation (IKEv1-non-PSK only)
*/
void (*ike_keys)(bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r,
- ike_sa_t *rekey, shared_key_t *shared);
+ ike_sa_t *rekey, shared_key_t *shared,
+ auth_method_t method);
/**
* IKE_SA derived keys hook.
diff --git a/src/libcharon/bus/listeners/listener.h b/src/libcharon/bus/listeners/listener.h
index 06057eb73..0f3b8578a 100644
--- a/src/libcharon/bus/listeners/listener.h
+++ b/src/libcharon/bus/listeners/listener.h
@@ -88,11 +88,13 @@ struct listener_t {
* @param nonce_r responder's nonce
* @param rekey IKE_SA we are rekeying, if any (IKEv2 only)
* @param shared shared key used for key derivation (IKEv1-PSK only)
+ * @param method auth method for key derivation (IKEv1-non-PSK only)
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*ike_keys)(listener_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r,
- ike_sa_t *rekey, shared_key_t *shared);
+ ike_sa_t *rekey, shared_key_t *shared,
+ auth_method_t method);
/**
* Hook called with derived IKE_SA keys.
diff --git a/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c b/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c
index 644cff029..1abbf7731 100644
--- a/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c
+++ b/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c
@@ -64,6 +64,7 @@ typedef struct {
private_bypass_lan_listener_t *listener;
host_t *net;
uint8_t mask;
+ char *iface;
child_cfg_t *cfg;
} bypass_policy_t;
@@ -85,6 +86,7 @@ static void bypass_policy_destroy(bypass_policy_t *this)
ts->destroy(ts);
}
this->net->destroy(this->net);
+ free(this->iface);
free(this);
}
@@ -126,6 +128,7 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
enumerator_t *enumerator;
hashtable_t *seen;
bypass_policy_t *found, *lookup;
+ traffic_selector_t *ts;
host_t *net;
uint8_t mask;
char *iface;
@@ -146,6 +149,7 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
INIT(lookup,
.net = net->clone(net),
.mask = mask,
+ .iface = strdupnull(iface),
);
found = seen->put(seen, lookup, lookup);
if (found)
@@ -160,7 +164,6 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
.mode = MODE_PASS,
};
child_cfg_t *cfg;
- traffic_selector_t *ts;
char name[128];
ts = traffic_selector_create_from_subnet(net->clone(net), mask,
@@ -176,6 +179,7 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
INIT(found,
.net = net->clone(net),
.mask = mask,
+ .iface = strdupnull(iface),
.cfg = cfg,
);
this->policies->put(this->policies, found, found);
@@ -186,11 +190,29 @@ static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
enumerator = this->policies->create_enumerator(this->policies);
while (enumerator->enumerate(enumerator, NULL, &lookup))
{
- if (!seen->get(seen, lookup))
+ found = seen->get(seen, lookup);
+ if (!found)
{
this->policies->remove_at(this->policies, enumerator);
bypass_policy_destroy(lookup);
}
+ else if (!streq(lookup->iface, found->iface))
+ { /* if the subnet is on multiple interfaces, we only get the last
+ * one (hopefully, they are enumerated in a consistent order) */
+ ts = traffic_selector_create_from_subnet(
+ lookup->net->clone(lookup->net),
+ lookup->mask, 0, 0, 65535);
+ DBG1(DBG_IKE, "interface change for bypass policy for %R (from %s "
+ "to %s)", ts, lookup->iface, found->iface);
+ ts->destroy(ts);
+ free(lookup->iface);
+ lookup->iface = strdupnull(found->iface);
+ /* there is currently no API to update shunts, so we remove and
+ * reinstall it to update the route */
+ charon->shunts->uninstall(charon->shunts, "bypass-lan",
+ lookup->cfg->get_name(lookup->cfg));
+ charon->shunts->install(charon->shunts, "bypass-lan", lookup->cfg);
+ }
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
diff --git a/src/libcharon/plugins/dhcp/dhcp_socket.c b/src/libcharon/plugins/dhcp/dhcp_socket.c
index 1e208d094..ecd92f2ef 100644
--- a/src/libcharon/plugins/dhcp/dhcp_socket.c
+++ b/src/libcharon/plugins/dhcp/dhcp_socket.c
@@ -489,6 +489,16 @@ static void handle_offer(private_dhcp_socket_t *this, dhcp_t *dhcp, int optlen)
offer = host_create_from_chunk(AF_INET,
chunk_from_thing(dhcp->your_address), 0);
+ if (offer->is_anyaddr(offer))
+ {
+ server = host_create_from_chunk(AF_INET,
+ chunk_from_thing(dhcp->server_address), 0);
+ DBG1(DBG_CFG, "ignoring DHCP OFFER %+H from %H", offer, server);
+ server->destroy(server);
+ offer->destroy(offer);
+ return;
+ }
+
this->mutex->lock(this->mutex);
enumerator = this->discover->create_enumerator(this->discover);
while (enumerator->enumerate(enumerator, &transaction))
diff --git a/src/libcharon/plugins/eap_radius/eap_radius.c b/src/libcharon/plugins/eap_radius/eap_radius.c
index fbbf6da83..ae1371b45 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2017 Tobias Brunner
+ * Copyright (C) 2012-2018 Tobias Brunner
* Copyright (C) 2009 Martin Willi
* HSR Hochschule fuer Technik Rapperswil
*
@@ -156,7 +156,7 @@ void eap_radius_build_attributes(radius_message_t *request)
{
ike_sa_t *ike_sa;
host_t *host;
- char buf[40], *station_id_fmt;;
+ char buf[40], *station_id_fmt, *session_id;
uint32_t value;
chunk_t chunk;
@@ -202,6 +202,14 @@ void eap_radius_build_attributes(radius_message_t *request)
host = ike_sa->get_other_host(ike_sa);
snprintf(buf, sizeof(buf), station_id_fmt, host);
request->add(request, RAT_CALLING_STATION_ID, chunk_from_str(buf));
+
+ session_id = eap_radius_accounting_session_id(ike_sa);
+ if (session_id)
+ {
+ request->add(request, RAT_ACCT_SESSION_ID,
+ chunk_from_str(session_id));
+ free(session_id);
+ }
}
}
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
index 92611492b..ecb2083c9 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015-2017 Tobias Brunner
+ * Copyright (C) 2015-2018 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2012 Martin Willi
@@ -17,6 +17,7 @@
*/
#include "eap_radius_accounting.h"
+#include "eap_radius_provider.h"
#include "eap_radius_plugin.h"
#include <time.h>
@@ -461,6 +462,37 @@ static void add_ike_sa_parameters(private_eap_radius_accounting_t *this,
}
/**
+ * Add any unclaimed IP addresses to the message
+ */
+static void add_unclaimed_ips(radius_message_t *message, ike_sa_t *ike_sa)
+{
+ eap_radius_provider_t *provider;
+ enumerator_t *enumerator;
+ host_t *vip;
+
+ provider = eap_radius_provider_get();
+ enumerator = provider->clear_unclaimed(provider,
+ ike_sa->get_unique_id(ike_sa));
+ while (enumerator->enumerate(enumerator, &vip))
+ {
+ switch (vip->get_family(vip))
+ {
+ case AF_INET:
+ message->add(message, RAT_FRAMED_IP_ADDRESS,
+ vip->get_address(vip));
+ break;
+ case AF_INET6:
+ message->add(message, RAT_FRAMED_IPV6_ADDRESS,
+ vip->get_address(vip));
+ break;
+ default:
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+/**
* Add the Class attributes received in the Access-Accept message to the
* RADIUS accounting message
*/
@@ -790,6 +822,7 @@ static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
chunk_create(entry->sid, strlen(entry->sid)));
add_class_attributes(message, entry);
add_ike_sa_parameters(this, message, ike_sa);
+ add_unclaimed_ips(message, ike_sa);
value = htonl(entry->usage.bytes.sent);
message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value));
@@ -816,7 +849,6 @@ static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
value = htonl(time_monotonic(NULL) - entry->created);
message->add(message, RAT_ACCT_SESSION_TIME, chunk_from_thing(value));
-
value = htonl(entry->cause);
message->add(message, RAT_ACCT_TERMINATE_CAUSE, chunk_from_thing(value));
@@ -1070,8 +1102,27 @@ eap_radius_accounting_t *eap_radius_accounting_create()
return &this->public;
}
-/**
- * See header
+/*
+ * Described in header
+ */
+char *eap_radius_accounting_session_id(ike_sa_t *ike_sa)
+{
+ entry_t *entry;
+ char *sid = NULL;
+
+ if (singleton)
+ {
+ singleton->mutex->lock(singleton->mutex);
+ entry = get_or_create_entry(singleton, ike_sa->get_id(ike_sa),
+ ike_sa->get_unique_id(ike_sa));
+ sid = strdup(entry->sid);
+ singleton->mutex->unlock(singleton->mutex);
+ }
+ return sid;
+}
+
+/*
+ * Described in header
*/
void eap_radius_accounting_start_interim(ike_sa_t *ike_sa, uint32_t interval)
{
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_accounting.h b/src/libcharon/plugins/eap_radius/eap_radius_accounting.h
index dc1edcf54..1fe1107ea 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_accounting.h
+++ b/src/libcharon/plugins/eap_radius/eap_radius_accounting.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 Tobias Brunner
+ * Copyright (C) 2017-2018 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2012 Martin Willi
@@ -50,6 +50,14 @@ struct eap_radius_accounting_t {
eap_radius_accounting_t *eap_radius_accounting_create();
/**
+ * Get the Accounting session ID for the given IKE_SA.
+ *
+ * @param ike_sa IKE_SA for which to determine the session ID
+ * @return allocated session ID
+ */
+char *eap_radius_accounting_session_id(ike_sa_t *ike_sa);
+
+/**
* Schedule Accounting interim updates for the given IKE_SA.
*
* @param ike_sa IKE_SA to send updates for
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_provider.c b/src/libcharon/plugins/eap_radius/eap_radius_provider.c
index 8188bb764..defabb782 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_provider.c
+++ b/src/libcharon/plugins/eap_radius/eap_radius_provider.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
@@ -131,7 +134,7 @@ static entry_t* get_or_create_entry(hashtable_t *hashtable, uintptr_t id)
}
/**
- * Put an entry to hashtable, or destroy it ife empty
+ * Put an entry to hashtable, or destroy it if empty
*/
static void put_or_destroy_entry(hashtable_t *hashtable, entry_t *entry)
{
@@ -494,6 +497,24 @@ METHOD(eap_radius_provider_t, add_attribute, void,
this->listener.mutex->unlock(this->listener.mutex);
}
+METHOD(eap_radius_provider_t, clear_unclaimed, enumerator_t*,
+ private_eap_radius_provider_t *this, uint32_t id)
+{
+ entry_t *entry;
+
+ this->listener.mutex->lock(this->listener.mutex);
+ entry = this->listener.unclaimed->remove(this->listener.unclaimed,
+ (void*)(uintptr_t)id);
+ this->listener.mutex->unlock(this->listener.mutex);
+ if (!entry)
+ {
+ return enumerator_create_empty();
+ }
+ return enumerator_create_cleaner(
+ entry->addrs->create_enumerator(entry->addrs),
+ (void*)destroy_entry, entry);
+}
+
METHOD(eap_radius_provider_t, destroy, void,
private_eap_radius_provider_t *this)
{
@@ -523,6 +544,7 @@ eap_radius_provider_t *eap_radius_provider_create()
},
.add_framed_ip = _add_framed_ip,
.add_attribute = _add_attribute,
+ .clear_unclaimed = _clear_unclaimed,
.destroy = _destroy,
},
.listener = {
@@ -539,6 +561,14 @@ eap_radius_provider_t *eap_radius_provider_create()
},
);
+ if (lib->settings->get_bool(lib->settings,
+ "%s.plugins.eap-radius.accounting", FALSE, lib->ns))
+ {
+ /* if RADIUS accounting is enabled, keep unclaimed IPs around until
+ * the Accounting-Stop message is sent */
+ this->listener.public.message = NULL;
+ }
+
charon->bus->add_listener(charon->bus, &this->listener.public);
singleton = &this->public;
diff --git a/src/libcharon/plugins/eap_radius/eap_radius_provider.h b/src/libcharon/plugins/eap_radius/eap_radius_provider.h
index 80971bddb..9f1121ca3 100644
--- a/src/libcharon/plugins/eap_radius/eap_radius_provider.h
+++ b/src/libcharon/plugins/eap_radius/eap_radius_provider.h
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2018 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
+ *
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
@@ -56,6 +59,14 @@ struct eap_radius_provider_t {
configuration_attribute_type_t type, chunk_t data);
/**
+ * Clears any unclaimed IP addresses and attributes for the given IKE_SA.
+ *
+ * @param id IKE_SA unique identifier
+ * @return enumerator over unclaimed IP addresses, if any
+ */
+ enumerator_t *(*clear_unclaimed)(eap_radius_provider_t *this, uint32_t id);
+
+ /**
* Destroy a eap_radius_provider_t.
*/
void (*destroy)(eap_radius_provider_t *this);
diff --git a/src/libcharon/plugins/ha/ha_attribute.c b/src/libcharon/plugins/ha/ha_attribute.c
index 34d6efc48..2553fd014 100644
--- a/src/libcharon/plugins/ha/ha_attribute.c
+++ b/src/libcharon/plugins/ha/ha_attribute.c
@@ -159,13 +159,13 @@ static pool_t* get_pool(private_ha_attribute_t *this, char *name)
}
/**
- * Check if we are responsible for a bit in our bitmask
+ * Check if we are responsible for an offset
*/
-static bool responsible_for(private_ha_attribute_t *this, int bit)
+static bool responsible_for(private_ha_attribute_t *this, int offset)
{
u_int segment;
- segment = this->kernel->get_segment_int(this->kernel, bit);
+ segment = offset % this->segments->count(this->segments) + 1;
return this->segments->is_active(this->segments, segment);
}
@@ -175,7 +175,7 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
{
enumerator_t *enumerator;
pool_t *pool = NULL;
- int offset = -1, byte, bit;
+ int offset = -1, tmp_offset, byte, bit;
host_t *address;
char *name;
@@ -199,10 +199,11 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
{
for (bit = 0; bit < 8; bit++)
{
+ tmp_offset = byte * 8 + bit;
if (!(pool->mask[byte] & 1 << bit) &&
- responsible_for(this, bit))
+ responsible_for(this, tmp_offset))
{
- offset = byte * 8 + bit;
+ offset = tmp_offset;
pool->mask[byte] |= 1 << bit;
break;
}
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c
index 4e3803892..ab845317f 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -138,6 +138,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
chunk_t dh_local = chunk_empty, dh_remote = chunk_empty, psk = chunk_empty;
host_t *other = NULL;
bool ok = FALSE;
+ auth_method_t method = AUTH_RSA;
enumerator = message->create_attribute_enumerator(message);
while (enumerator->enumerate(enumerator, &attribute, &value))
@@ -197,6 +198,8 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
case HA_ALG_DH:
dh_grp = value.u16;
break;
+ case HA_AUTH_METHOD:
+ method = value.u16;
default:
break;
}
@@ -238,7 +241,6 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message
{
keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
shared_key_t *shared = NULL;
- auth_method_t method = AUTH_RSA;
if (psk.len)
{
diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c
index 2854ab76d..aae402d50 100644
--- a/src/libcharon/plugins/ha/ha_ike.c
+++ b/src/libcharon/plugins/ha/ha_ike.c
@@ -73,7 +73,7 @@ static ike_extension_t copy_extension(ike_sa_t *ike_sa, ike_extension_t ext)
METHOD(listener_t, ike_keys, bool,
private_ha_ike_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh,
chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey,
- shared_key_t *shared)
+ shared_key_t *shared, auth_method_t method)
{
ha_message_t *m;
chunk_t secret;
@@ -141,6 +141,10 @@ METHOD(listener_t, ike_keys, bool,
{
m->add_attribute(m, HA_PSK, shared->get_key(shared));
}
+ else
+ {
+ m->add_attribute(m, HA_AUTH_METHOD, method);
+ }
}
m->add_attribute(m, HA_REMOTE_ADDR, ike_sa->get_other_host(ike_sa));
diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c
index 7891b1654..28b7b0d5b 100644
--- a/src/libcharon/plugins/ha/ha_message.c
+++ b/src/libcharon/plugins/ha/ha_message.c
@@ -240,6 +240,7 @@ METHOD(ha_message_t, add_attribute, void,
case HA_OUTBOUND_CPI:
case HA_SEGMENT:
case HA_ESN:
+ case HA_AUTH_METHOD:
{
uint16_t val;
@@ -463,6 +464,7 @@ METHOD(enumerator_t, attribute_enumerate, bool,
case HA_OUTBOUND_CPI:
case HA_SEGMENT:
case HA_ESN:
+ case HA_AUTH_METHOD:
{
if (this->buf.len < sizeof(uint16_t))
{
diff --git a/src/libcharon/plugins/ha/ha_message.h b/src/libcharon/plugins/ha/ha_message.h
index 3e43dc8dc..3c0058d99 100644
--- a/src/libcharon/plugins/ha/ha_message.h
+++ b/src/libcharon/plugins/ha/ha_message.h
@@ -156,6 +156,8 @@ enum ha_message_attribute_t {
HA_PSK,
/** chunk_t, IV for next IKEv1 message */
HA_IV,
+ /** uint16_t, auth_method_t for IKEv1 key derivation */
+ HA_AUTH_METHOD,
};
/**
diff --git a/src/libcharon/plugins/ha/ha_segments.c b/src/libcharon/plugins/ha/ha_segments.c
index 0a407f9ef..153534915 100644
--- a/src/libcharon/plugins/ha/ha_segments.c
+++ b/src/libcharon/plugins/ha/ha_segments.c
@@ -433,6 +433,12 @@ METHOD(ha_segments_t, is_active, bool,
return (this->active & SEGMENTS_BIT(segment)) != 0;
}
+METHOD(ha_segments_t, count, u_int,
+ private_ha_segments_t *this)
+{
+ return this->count;
+}
+
METHOD(ha_segments_t, destroy, void,
private_ha_segments_t *this)
{
@@ -459,6 +465,7 @@ ha_segments_t *ha_segments_create(ha_socket_t *socket, ha_kernel_t *kernel,
.deactivate = _deactivate,
.handle_status = _handle_status,
.is_active = _is_active,
+ .count = _count,
.destroy = _destroy,
},
.socket = socket,
diff --git a/src/libcharon/plugins/ha/ha_segments.h b/src/libcharon/plugins/ha/ha_segments.h
index 10d5812c6..bc96a8d3e 100644
--- a/src/libcharon/plugins/ha/ha_segments.h
+++ b/src/libcharon/plugins/ha/ha_segments.h
@@ -83,6 +83,13 @@ struct ha_segments_t {
bool (*is_active)(ha_segments_t *this, u_int segment);
/**
+ * Return the number of segments
+ *
+ * @return number of segments
+ */
+ u_int (*count)(ha_segments_t *this);
+
+ /**
* Destroy a ha_segments_t.
*/
void (*destroy)(ha_segments_t *this);
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
index 1292e0895..40fff7e05 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
@@ -2257,6 +2257,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
uint32_t replay_esn_len = 0;
kernel_ipsec_del_sa_t del = { 0 };
status_t status = FAILED;
+ traffic_selector_t *ts;
char markstr[32] = "";
/* if IPComp is used, we first update the IPComp SA */
@@ -2360,10 +2361,26 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
if (!id->src->ip_equals(id->src, data->new_src))
{
host2xfrm(data->new_src, &sa->saddr);
+
+ ts = selector2ts(&sa->sel, TRUE);
+ if (ts && ts->is_host(ts, id->src))
+ {
+ ts->set_address(ts, data->new_src);
+ ts2subnet(ts, &sa->sel.saddr, &sa->sel.prefixlen_s);
+ }
+ DESTROY_IF(ts);
}
if (!id->dst->ip_equals(id->dst, data->new_dst))
{
host2xfrm(data->new_dst, &sa->id.daddr);
+
+ ts = selector2ts(&sa->sel, FALSE);
+ if (ts && ts->is_host(ts, id->dst))
+ {
+ ts->set_address(ts, data->new_dst);
+ ts2subnet(ts, &sa->sel.daddr, &sa->sel.prefixlen_d);
+ }
+ DESTROY_IF(ts);
}
rta = XFRM_RTA(out_hdr, struct xfrm_usersa_info);
diff --git a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
index dbe409a62..37170a310 100644
--- a/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
+++ b/src/libcharon/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2017 Tobias Brunner
+ * Copyright (C) 2008-2018 Tobias Brunner
* Copyright (C) 2008 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
@@ -1287,20 +1287,27 @@ static void process_acquire(private_kernel_pfkey_ipsec_t *this,
return;
}
- index = response.x_policy->sadb_x_policy_id;
- this->mutex->lock(this->mutex);
- if (this->policies->find_first(this->policies, policy_entry_match_byindex,
- (void**)&policy, index) &&
- policy->used_by->get_first(policy->used_by, (void**)&sa) == SUCCESS)
+ if (response.x_sa2)
{
- reqid = sa->sa->cfg.reqid;
+ reqid = response.x_sa2->sadb_x_sa2_reqid;
}
else
{
- DBG1(DBG_KNL, "received an SADB_ACQUIRE with policy id %d but no "
- "matching policy found", index);
+ index = response.x_policy->sadb_x_policy_id;
+ this->mutex->lock(this->mutex);
+ if (this->policies->find_first(this->policies, policy_entry_match_byindex,
+ (void**)&policy, index) &&
+ policy->used_by->get_first(policy->used_by, (void**)&sa) == SUCCESS)
+ {
+ reqid = sa->sa->cfg.reqid;
+ }
+ else
+ {
+ DBG1(DBG_KNL, "received an SADB_ACQUIRE with policy id %d but no "
+ "matching policy found", index);
+ }
+ this->mutex->unlock(this->mutex);
}
- this->mutex->unlock(this->mutex);
src_ts = sadb_address2ts(response.src);
dst_ts = sadb_address2ts(response.dst);
diff --git a/src/libcharon/plugins/vici/libvici.h b/src/libcharon/plugins/vici/libvici.h
index d69597881..964752f53 100644
--- a/src/libcharon/plugins/vici/libvici.h
+++ b/src/libcharon/plugins/vici/libvici.h
@@ -86,6 +86,10 @@
#include <stdio.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/**
* Opaque vici connection contex.
*/
@@ -465,4 +469,8 @@ void vici_init();
*/
void vici_deinit();
+#ifdef __cplusplus
+}
+#endif
+
#endif /** LIBVICI_H_ @}*/
diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c
index 10c62dc89..ace7a4528 100644
--- a/src/libcharon/plugins/vici/vici_config.c
+++ b/src/libcharon/plugins/vici/vici_config.c
@@ -733,7 +733,7 @@ CALLBACK(parse_ts, bool,
if (host_create_from_range(buf, &lower, &upper))
{
type = (lower->get_family(lower) == AF_INET) ?
- TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE;
+ TS_IPV4_ADDR_RANGE : TS_IPV6_ADDR_RANGE;
ts = traffic_selector_create_from_bytes(proto, type,
lower->get_address(lower), from,
upper->get_address(upper), to);
@@ -2494,7 +2494,10 @@ CALLBACK(config_sn, bool,
if (peer.mediated_by)
{
cfg.mediated_by = peer.mediated_by;
- cfg.peer_id = peer.peer_id->clone(peer.peer_id);
+ if (peer.peer_id)
+ {
+ cfg.peer_id = peer.peer_id->clone(peer.peer_id);
+ }
}
#endif /* ME */
peer_cfg = peer_cfg_create(name, ike_cfg, &cfg);
diff --git a/src/libcharon/processing/jobs/adopt_children_job.c b/src/libcharon/processing/jobs/adopt_children_job.c
index 998af0d3f..e2a7f6b20 100644
--- a/src/libcharon/processing/jobs/adopt_children_job.c
+++ b/src/libcharon/processing/jobs/adopt_children_job.c
@@ -53,6 +53,36 @@ METHOD(job_t, destroy, void,
free(this);
}
+METHOD(adopt_children_job_t, queue_task, void,
+ private_adopt_children_job_t *this, task_t *task)
+{
+ array_insert_create(&this->tasks, ARRAY_TAIL, task);
+}
+
+/**
+ * Adopt child-creating tasks from the given IKE_SA
+ */
+static u_int adopt_child_tasks(private_adopt_children_job_t *this,
+ ike_sa_t *ike_sa, task_queue_t queue)
+{
+ enumerator_t *tasks;
+ task_t *task;
+ u_int count = 0;
+
+ tasks = ike_sa->create_task_enumerator(ike_sa, queue);
+ while (tasks->enumerate(tasks, &task))
+ {
+ if (task->get_type(task) == TASK_QUICK_MODE)
+ {
+ ike_sa->remove_task(ike_sa, tasks);
+ queue_task(this, task);
+ count++;
+ }
+ }
+ tasks->destroy(tasks);
+ return count;
+}
+
METHOD(job_t, execute, job_requeue_t,
private_adopt_children_job_t *this)
{
@@ -65,6 +95,7 @@ METHOD(job_t, execute, job_requeue_t,
ike_sa_t *ike_sa;
child_sa_t *child_sa;
uint32_t unique;
+ u_int tasks = 0;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->id);
if (ike_sa)
@@ -127,11 +158,17 @@ METHOD(job_t, execute, job_requeue_t,
* it does trigger an assign_vips(FALSE) event, so we also
* trigger one below */
ike_sa->clear_virtual_ips(ike_sa, FALSE);
- if (children->get_count(children) || vips->get_count(vips))
+
+ tasks += adopt_child_tasks(this, ike_sa, TASK_QUEUE_ACTIVE);
+ tasks += adopt_child_tasks(this, ike_sa, TASK_QUEUE_QUEUED);
+
+ if (children->get_count(children) || tasks ||
+ vips->get_count(vips))
{
DBG1(DBG_IKE, "detected reauth of existing IKE_SA, "
- "adopting %d children and %d virtual IPs",
- children->get_count(children), vips->get_count(vips));
+ "adopting %d children, %d child tasks, and %d "
+ "virtual IPs", children->get_count(children),
+ tasks, vips->get_count(vips));
}
if (ike_sa->get_state(ike_sa) == IKE_PASSIVE)
{
@@ -152,7 +189,8 @@ METHOD(job_t, execute, job_requeue_t,
charon->ike_sa_manager->checkin(
charon->ike_sa_manager, ike_sa);
}
- if (children->get_count(children) || vips->get_count(vips))
+ if (children->get_count(children) || tasks ||
+ vips->get_count(vips))
{
break;
}
@@ -237,12 +275,6 @@ METHOD(job_t, get_priority, job_priority_t,
return JOB_PRIO_HIGH;
}
-METHOD(adopt_children_job_t, queue_task, void,
- private_adopt_children_job_t *this, task_t *task)
-{
- array_insert_create(&this->tasks, ARRAY_TAIL, task);
-}
-
/**
* See header
*/
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index c33398bee..bdc96a4bc 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -978,7 +978,7 @@ static void prepare_sa_cfg(private_child_sa_t *this, ipsec_sa_cfg_t *my_sa,
}
/**
- * Install inbound policie(s): in, fwd
+ * Install inbound policies: in, fwd
*/
static status_t install_policies_inbound(private_child_sa_t *this,
host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
@@ -1012,7 +1012,7 @@ static status_t install_policies_inbound(private_child_sa_t *this,
}
/**
- * Install outbound policie(s): out, [fwd]
+ * Install outbound policies: out, [fwd]
*/
static status_t install_policies_outbound(private_child_sa_t *this,
host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index a4ad866d3..3d576a0e8 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -1996,8 +1996,7 @@ static status_t reestablish_children(private_ike_sa_t *this, ike_sa_t *new,
/* 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);
+ new->adopt_child_tasks(new, &this->public);
if (new->get_state(new) == IKE_CREATED)
{
status = new->initiate(new, NULL, 0, NULL, NULL);
@@ -2404,7 +2403,9 @@ METHOD(ike_sa_t, retransmit, status_t,
}
case IKE_DELETING:
DBG1(DBG_IKE, "proper IKE_SA delete failed, peer not responding");
- if (has_condition(this, COND_REAUTHENTICATING))
+ if (has_condition(this, COND_REAUTHENTICATING) &&
+ !lib->settings->get_bool(lib->settings,
+ "%s.make_before_break", FALSE, lib->ns))
{
DBG1(DBG_IKE, "delete during reauthentication failed, "
"trying to reestablish IKE_SA anyway");
@@ -2719,6 +2720,12 @@ METHOD(ike_sa_t, create_task_enumerator, enumerator_t*,
return this->task_manager->create_task_enumerator(this->task_manager, queue);
}
+METHOD(ike_sa_t, remove_task, void,
+ private_ike_sa_t *this, enumerator_t *enumerator)
+{
+ return this->task_manager->remove_task(this->task_manager, enumerator);
+}
+
METHOD(ike_sa_t, flush_queue, void,
private_ike_sa_t *this, task_queue_t queue)
{
@@ -2737,6 +2744,36 @@ METHOD(ike_sa_t, queue_task_delayed, void,
this->task_manager->queue_task_delayed(this->task_manager, task, delay);
}
+/**
+ * Migrate and queue child-creating tasks from another IKE_SA
+ */
+static void migrate_child_tasks(private_ike_sa_t *this, ike_sa_t *other,
+ task_queue_t queue)
+{
+ enumerator_t *enumerator;
+ task_t *task;
+
+ enumerator = other->create_task_enumerator(other, queue);
+ while (enumerator->enumerate(enumerator, &task))
+ {
+ if (task->get_type(task) == TASK_CHILD_CREATE ||
+ task->get_type(task) == TASK_QUICK_MODE)
+ {
+ other->remove_task(other, enumerator);
+ task->migrate(task, &this->public);
+ queue_task(this, task);
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+METHOD(ike_sa_t, adopt_child_tasks, void,
+ private_ike_sa_t *this, ike_sa_t *other)
+{
+ migrate_child_tasks(this, other, TASK_QUEUE_ACTIVE);
+ migrate_child_tasks(this, other, TASK_QUEUE_QUEUED);
+}
+
METHOD(ike_sa_t, inherit_pre, void,
private_ike_sa_t *this, ike_sa_t *other_public)
{
@@ -3052,9 +3089,11 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
.create_attribute_enumerator = _create_attribute_enumerator,
.set_kmaddress = _set_kmaddress,
.create_task_enumerator = _create_task_enumerator,
+ .remove_task = _remove_task,
.flush_queue = _flush_queue,
.queue_task = _queue_task,
.queue_task_delayed = _queue_task_delayed,
+ .adopt_child_tasks = _adopt_child_tasks,
#ifdef ME
.act_as_mediation_server = _act_as_mediation_server,
.get_server_reflexive_host = _get_server_reflexive_host,
diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h
index c1d3e1d7a..be480eac8 100644
--- a/src/libcharon/sa/ike_sa.h
+++ b/src/libcharon/sa/ike_sa.h
@@ -1125,6 +1125,16 @@ struct ike_sa_t {
enumerator_t* (*create_task_enumerator)(ike_sa_t *this, task_queue_t queue);
/**
+ * Remove the task the given enumerator points to.
+ *
+ * @note This should be used with caution, in partciular, for tasks in the
+ * active and passive queues.
+ *
+ * @param enumerator enumerator created with the method above
+ */
+ void (*remove_task)(ike_sa_t *this, enumerator_t *enumerator);
+
+ /**
* Flush a task queue, cancelling all tasks in it.
*
* @param queue queue type to flush
@@ -1148,6 +1158,13 @@ struct ike_sa_t {
void (*queue_task_delayed)(ike_sa_t *this, task_t *task, uint32_t delay);
/**
+ * Adopt child creating tasks from the given IKE_SA.
+ *
+ * @param other other IKE_SA to adopt tasks from
+ */
+ void (*adopt_child_tasks)(ike_sa_t *this, ike_sa_t *other);
+
+ /**
* Inherit required attributes to new SA before rekeying.
*
* Some properties of the SA must be applied before starting IKE_SA
diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
index c50c70860..3bac4b109 100644
--- a/src/libcharon/sa/ike_sa_manager.c
+++ b/src/libcharon/sa/ike_sa_manager.c
@@ -1967,6 +1967,8 @@ static void adopt_children_and_vips(ike_sa_t *old, ike_sa_t *new)
}
enumerator->destroy(enumerator);
+ new->adopt_child_tasks(new, old);
+
enumerator = old->create_virtual_ip_enumerator(old, FALSE);
while (enumerator->enumerate(enumerator, &vip))
{
diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c
index b99d75142..ac2899f11 100644
--- a/src/libcharon/sa/ikev1/phase1.c
+++ b/src/libcharon/sa/ikev1/phase1.c
@@ -251,7 +251,8 @@ METHOD(phase1_t, derive_keys, bool,
return FALSE;
}
charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, this->dh_value,
- this->nonce_i, this->nonce_r, NULL, shared_key);
+ this->nonce_i, this->nonce_r, NULL, shared_key,
+ method);
DESTROY_IF(shared_key);
return TRUE;
}
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index 5f6c3bbe8..f76471e78 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007-2016 Tobias Brunner
+ * Copyright (C) 2007-2018 Tobias Brunner
* Copyright (C) 2007-2011 Martin Willi
* HSR Hochschule fuer Technik Rapperswil
*
@@ -544,20 +544,20 @@ METHOD(task_manager_t, initiate, status_t,
new_mid = TRUE;
break;
}
- if (!mode_config_expected(this) &&
- activate_task(this, TASK_QUICK_MODE))
+ if (activate_task(this, TASK_ISAKMP_DPD))
{
- exchange = QUICK_MODE;
+ exchange = INFORMATIONAL_V1;
new_mid = TRUE;
break;
}
- if (activate_task(this, TASK_INFORMATIONAL))
+ if (!mode_config_expected(this) &&
+ activate_task(this, TASK_QUICK_MODE))
{
- exchange = INFORMATIONAL_V1;
+ exchange = QUICK_MODE;
new_mid = TRUE;
break;
}
- if (activate_task(this, TASK_ISAKMP_DPD))
+ if (activate_task(this, TASK_INFORMATIONAL))
{
exchange = INFORMATIONAL_V1;
new_mid = TRUE;
@@ -1121,7 +1121,15 @@ static status_t process_request(private_task_manager_t *this,
}
}
else
- { /* We don't send a response, so don't retransmit one if we get
+ {
+ if (this->responding.retransmitted > 1)
+ {
+ packet_t *packet = NULL;
+ array_get(this->responding.packets, 0, &packet);
+ charon->bus->alert(charon->bus, ALERT_RETRANSMIT_SEND_CLEARED,
+ packet);
+ }
+ /* We don't send a response, so don't retransmit one if we get
* the same message again. */
clear_packets(this->responding.packets);
}
@@ -1883,39 +1891,6 @@ 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)
{
@@ -1976,19 +1951,86 @@ METHOD(task_manager_t, reset, void,
}
}
+/**
+ * Data for a task queue enumerator
+ */
+typedef struct {
+ enumerator_t public;
+ task_queue_t queue;
+ enumerator_t *inner;
+} task_enumerator_t;
+
+METHOD(enumerator_t, task_enumerator_destroy, void,
+ task_enumerator_t *this)
+{
+ this->inner->destroy(this->inner);
+ free(this);
+}
+
+METHOD(enumerator_t, task_enumerator_enumerate, bool,
+ task_enumerator_t *this, va_list args)
+{
+ task_t **task;
+
+ VA_ARGS_VGET(args, task);
+ return this->inner->enumerate(this->inner, task);
+}
+
METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
private_task_manager_t *this, task_queue_t queue)
{
+ task_enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = enumerator_enumerate_default,
+ .venumerate = _task_enumerator_enumerate,
+ .destroy = _task_enumerator_destroy,
+ },
+ .queue = queue,
+ );
switch (queue)
{
case TASK_QUEUE_ACTIVE:
- return this->active_tasks->create_enumerator(this->active_tasks);
+ enumerator->inner = this->active_tasks->create_enumerator(
+ this->active_tasks);
+ break;
+ case TASK_QUEUE_PASSIVE:
+ enumerator->inner = this->passive_tasks->create_enumerator(
+ this->passive_tasks);
+ break;
+ case TASK_QUEUE_QUEUED:
+ enumerator->inner = this->queued_tasks->create_enumerator(
+ this->queued_tasks);
+ break;
+ default:
+ enumerator->inner = enumerator_create_empty();
+ break;
+ }
+ return &enumerator->public;
+}
+
+METHOD(task_manager_t, remove_task, void,
+ private_task_manager_t *this, enumerator_t *enumerator_public)
+{
+ task_enumerator_t *enumerator = (task_enumerator_t*)enumerator_public;
+
+ switch (enumerator->queue)
+ {
+ case TASK_QUEUE_ACTIVE:
+ this->active_tasks->remove_at(this->active_tasks,
+ enumerator->inner);
+ break;
case TASK_QUEUE_PASSIVE:
- return this->passive_tasks->create_enumerator(this->passive_tasks);
+ this->passive_tasks->remove_at(this->passive_tasks,
+ enumerator->inner);
+ break;
case TASK_QUEUE_QUEUED:
- return this->queued_tasks->create_enumerator(this->queued_tasks);
+ this->queued_tasks->remove_at(this->queued_tasks,
+ enumerator->inner);
+ break;
default:
- return enumerator_create_empty();
+ break;
}
}
@@ -2039,9 +2081,9 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa)
.get_mid = _get_mid,
.reset = _reset,
.adopt_tasks = _adopt_tasks,
- .adopt_child_tasks = _adopt_child_tasks,
.busy = _busy,
.create_task_enumerator = _create_task_enumerator,
+ .remove_task = _remove_task,
.flush = _flush,
.flush_queue = _flush_queue,
.destroy = _destroy,
diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c
index 7dbbdc92f..b652d926f 100644
--- a/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c
+++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c
@@ -287,7 +287,6 @@ METHOD(task_t, process_i, status_t,
default:
return FAILED;
}
- break;
}
case AGGRESSIVE:
{
diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c
index 58f856e3f..566bfe83a 100644
--- a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c
+++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c
@@ -605,7 +605,6 @@ METHOD(task_t, process_i, status_t,
default:
return FAILED;
}
- break;
}
case AGGRESSIVE:
{
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 007e94d96..b0a42b8bd 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -1110,14 +1110,17 @@ METHOD(task_t, process_r, status_t,
this->tsi = select_ts(this, FALSE, tsi);
this->tsr = select_ts(this, TRUE, tsr);
}
- tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
- tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
if (!this->config || !this->tsi || !this->tsr ||
this->mode != this->config->get_mode(this->config))
{
- DBG1(DBG_IKE, "no matching CHILD_SA config found");
+ DBG1(DBG_IKE, "no matching CHILD_SA config found for "
+ "%#R === %#R", tsi, tsr);
+ tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+ tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
return send_notify(this, INVALID_ID_INFORMATION);
}
+ tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy));
+ tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy));
if (this->config->has_option(this->config, OPT_IPCOMP))
{
diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
index 1fcef03cc..97d33a89e 100644
--- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
+++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c
@@ -111,6 +111,40 @@ static bool build_signature_auth_data(chunk_t *auth_data,
}
/**
+ * Check if the given scheme is supported by the key and, if so, add it to the
+ * first array (we add the scheme supported by the key in case the parameters
+ * are different)
+ */
+static void add_scheme_if_supported(array_t *selected, array_t *supported,
+ signature_params_t *config)
+{
+ signature_params_t *sup;
+ int i;
+
+ if (!supported)
+ {
+ array_insert(selected, ARRAY_TAIL, signature_params_clone(config));
+ return;
+ }
+
+ for (i = 0; i < array_count(supported); i++)
+ {
+ array_get(supported, i, &sup);
+ if (signature_params_comply(sup, config))
+ {
+ array_insert(selected, ARRAY_TAIL, signature_params_clone(sup));
+ return;
+ }
+ }
+}
+
+CALLBACK(destroy_scheme, void,
+ signature_params_t *params, int idx, void *user)
+{
+ signature_params_destroy(params);
+}
+
+/**
* Selects possible signature schemes based on our configuration, the other
* peer's capabilities and the private key
*/
@@ -123,10 +157,32 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
auth_rule_t rule;
key_type_t key_type;
bool have_config = FALSE;
- array_t *selected;
+ array_t *supported = NULL, *selected;
selected = array_create(0, 0);
key_type = private->get_type(private);
+
+ if (private->supported_signature_schemes)
+ {
+ enumerator = private->supported_signature_schemes(private);
+ while (enumerator->enumerate(enumerator, &config))
+ {
+ if (keymat->hash_algorithm_supported(keymat,
+ hasher_from_signature_scheme(config->scheme,
+ config->params)))
+ {
+ array_insert_create(&supported, ARRAY_TAIL,
+ signature_params_clone(config));
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (!supported)
+ {
+ return selected;
+ }
+ }
+
enumerator = auth->create_enumerator(auth);
while (enumerator->enumerate(enumerator, &rule, &config))
{
@@ -134,21 +190,32 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
{
continue;
}
- have_config = TRUE;
if (key_type == key_type_from_signature_scheme(config->scheme) &&
keymat->hash_algorithm_supported(keymat,
hasher_from_signature_scheme(config->scheme,
config->params)))
{
- array_insert(selected, ARRAY_TAIL, signature_params_clone(config));
+ add_scheme_if_supported(selected, supported, config);
}
+ have_config = TRUE;
}
enumerator->destroy(enumerator);
- if (!have_config)
+ if (have_config)
{
- /* if no specific configuration, find schemes appropriate for the key
- * and supported by the other peer */
+ array_destroy_function(supported, destroy_scheme, NULL);
+ }
+ else
+ {
+ /* if we have no config, return either whatever schemes the key (and
+ * peer) support or.. */
+ if (supported)
+ {
+ array_destroy(selected);
+ return supported;
+ }
+
+ /* ...find schemes appropriate for the key and supported by the peer */
enumerator = signature_schemes_for_key(key_type,
private->get_keysize(private));
while (enumerator->enumerate(enumerator, &config))
@@ -207,12 +274,6 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat,
return selected;
}
-CALLBACK(destroy_scheme, void,
- signature_params_t *params, int idx, void *user)
-{
- signature_params_destroy(params);
-}
-
/**
* Adds the given auth data to the message, either in an AUTH payload or
* a NO_PPK_AUTH notify.
@@ -310,9 +371,9 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this,
if (params->scheme == SIGN_RSA_EMSA_PSS)
{
rsa_pss_params_t *pss = params->params;
- DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N_%N %s", id,
- signature_scheme_names, params->scheme,
- hash_algorithm_short_names_upper, pss->hash,
+ DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N_%N_SALT_%zd "
+ "%s", id, signature_scheme_names, params->scheme,
+ hash_algorithm_short_names_upper, pss->hash, pss->salt_len,
status == SUCCESS ? "successful" : "failed");
}
else
@@ -586,9 +647,9 @@ METHOD(authenticator_t, process, status_t,
else if (params->scheme == SIGN_RSA_EMSA_PSS)
{
rsa_pss_params_t *pss = params->params;
- DBG1(DBG_IKE, "authentication of '%Y' with %N_%N successful",
- id, signature_scheme_names, params->scheme,
- hash_algorithm_short_names_upper, pss->hash);
+ DBG1(DBG_IKE, "authentication of '%Y' with %N_%N_SALT_%zd "
+ "successful", id, signature_scheme_names, params->scheme,
+ hash_algorithm_short_names_upper, pss->hash, pss->salt_len);
}
else
{
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index 910c77a2d..e9142d79b 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -1459,6 +1459,59 @@ static bool looks_like_mid_sync(private_task_manager_t *this, message_t *msg,
}
/**
+ * Check whether we should reject the given request message
+ */
+static inline bool reject_request(private_task_manager_t *this,
+ message_t *msg)
+{
+ ike_sa_state_t state;
+ exchange_type_t type;
+ ike_sa_id_t *ike_sa_id;
+ bool reject = FALSE;
+
+ state = this->ike_sa->get_state(this->ike_sa);
+ type = msg->get_exchange_type(msg);
+
+ /* reject initial messages if not received in specific states */
+ switch (type)
+ {
+ case IKE_SA_INIT:
+ reject = state != IKE_CREATED;
+ break;
+ case IKE_AUTH:
+ reject = state != IKE_CONNECTING;
+ break;
+ default:
+ break;
+ }
+
+ if (!reject)
+ {
+ switch (state)
+ {
+ /* after rekeying we only expect a DELETE in an INFORMATIONAL */
+ case IKE_REKEYED:
+ reject = type != INFORMATIONAL;
+ break;
+ /* also reject requests for half-open IKE_SAs as initiator */
+ case IKE_CREATED:
+ case IKE_CONNECTING:
+ ike_sa_id = this->ike_sa->get_id(this->ike_sa);
+ reject = ike_sa_id->is_initiator(ike_sa_id);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (reject)
+ {
+ DBG1(DBG_IKE, "ignoring %N in IKE_SA state %N", exchange_type_names,
+ type, ike_sa_state_names, state);
+ }
+ return reject;
+}
+/**
* Check if a message with message ID 0 looks like it is used to synchronize
* the message IDs and we are prepared to process it.
*
@@ -1483,8 +1536,6 @@ METHOD(task_manager_t, process_message, status_t,
status_t status;
uint32_t mid;
bool schedule_delete_job = FALSE;
- ike_sa_state_t state;
- exchange_type_t type;
charon->bus->message(charon->bus, msg, TRUE, FALSE);
status = parse_message(this, msg);
@@ -1517,24 +1568,14 @@ METHOD(task_manager_t, process_message, status_t,
/* add a timeout if peer does not establish it completely */
schedule_delete_job = TRUE;
}
- this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
- time_monotonic(NULL));
mid = msg->get_message_id(msg);
if (msg->get_request(msg))
{
if (mid == this->responding.mid || (mid == 0 && is_mid_sync(this, msg)))
{
- /* reject initial messages if not received in specific states,
- * after rekeying we only expect a DELETE in an INFORMATIONAL */
- type = msg->get_exchange_type(msg);
- state = this->ike_sa->get_state(this->ike_sa);
- if ((type == IKE_SA_INIT && state != IKE_CREATED) ||
- (type == IKE_AUTH && state != IKE_CONNECTING) ||
- (state == IKE_REKEYED && type != INFORMATIONAL))
+ if (reject_request(this, msg))
{
- DBG1(DBG_IKE, "ignoring %N in IKE_SA state %N",
- exchange_type_names, type, ike_sa_state_names, state);
return FAILED;
}
if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE))
@@ -1544,6 +1585,11 @@ METHOD(task_manager_t, process_message, status_t,
status = handle_fragment(this, &this->responding.defrag, msg);
if (status != SUCCESS)
{
+ if (status == NEED_MORE)
+ {
+ this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
+ time_monotonic(NULL));
+ }
return status;
}
charon->bus->message(charon->bus, msg, TRUE, TRUE);
@@ -1554,6 +1600,8 @@ METHOD(task_manager_t, process_message, status_t,
switch (process_request(this, msg))
{
case SUCCESS:
+ this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
+ time_monotonic(NULL));
this->responding.mid++;
break;
case NEED_MORE:
@@ -1570,10 +1618,17 @@ METHOD(task_manager_t, process_message, status_t,
status = handle_fragment(this, &this->responding.defrag, msg);
if (status != SUCCESS)
{
+ if (status == NEED_MORE)
+ {
+ this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
+ time_monotonic(NULL));
+ }
return status;
}
DBG1(DBG_IKE, "received retransmit of request with ID %d, "
"retransmitting response", mid);
+ this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
+ time_monotonic(NULL));
charon->bus->alert(charon->bus, ALERT_RETRANSMIT_RECEIVE, msg);
send_packets(this, this->responding.packets,
msg->get_destination(msg), msg->get_source(msg));
@@ -1603,6 +1658,11 @@ METHOD(task_manager_t, process_message, status_t,
status = handle_fragment(this, &this->initiating.defrag, msg);
if (status != SUCCESS)
{
+ if (status == NEED_MORE)
+ {
+ this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
+ time_monotonic(NULL));
+ }
return status;
}
charon->bus->message(charon->bus, msg, TRUE, TRUE);
@@ -1615,6 +1675,8 @@ METHOD(task_manager_t, process_message, status_t,
flush(this);
return DESTROY_ME;
}
+ this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND,
+ time_monotonic(NULL));
}
else
{
@@ -2014,61 +2076,6 @@ METHOD(task_manager_t, adopt_tasks, void,
}
}
-/**
- * Migrates child-creating tasks from other to this
- */
-static void migrate_child_tasks(private_task_manager_t *this,
- private_task_manager_t *other,
- task_queue_t queue)
-{
- enumerator_t *enumerator;
- array_t *array;
- task_t *task;
-
- switch (queue)
- {
- case TASK_QUEUE_ACTIVE:
- array = other->active_tasks;
- break;
- case TASK_QUEUE_QUEUED:
- array = other->queued_tasks;
- break;
- default:
- return;
- }
-
- enumerator = array_create_enumerator(array);
- while (enumerator->enumerate(enumerator, &task))
- {
- queued_task_t *queued = NULL;
-
- if (queue == TASK_QUEUE_QUEUED)
- {
- queued = (queued_task_t*)task;
- task = queued->task;
- }
- if (task->get_type(task) == TASK_CHILD_CREATE)
- {
- array_remove_at(array, enumerator);
- task->migrate(task, this->ike_sa);
- queue_task(this, task);
- free(queued);
- }
- }
- 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, TASK_QUEUE_ACTIVE);
- /* do the same for queued tasks */
- migrate_child_tasks(this, other, TASK_QUEUE_QUEUED);
-}
-
METHOD(task_manager_t, busy, bool,
private_task_manager_t *this)
{
@@ -2124,17 +2131,39 @@ METHOD(task_manager_t, reset, void,
this->reset = TRUE;
}
-CALLBACK(filter_queued, bool,
- void *unused, enumerator_t *orig, va_list args)
-{
+/**
+ * Data for a task queue enumerator
+ */
+typedef struct {
+ enumerator_t public;
+ task_queue_t queue;
+ enumerator_t *inner;
queued_task_t *queued;
+} task_enumerator_t;
+
+METHOD(enumerator_t, task_enumerator_destroy, void,
+ task_enumerator_t *this)
+{
+ this->inner->destroy(this->inner);
+ free(this);
+}
+
+METHOD(enumerator_t, task_enumerator_enumerate, bool,
+ task_enumerator_t *this, va_list args)
+{
task_t **task;
VA_ARGS_VGET(args, task);
-
- if (orig->enumerate(orig, &queued))
+ if (this->queue == TASK_QUEUE_QUEUED)
+ {
+ if (this->inner->enumerate(this->inner, &this->queued))
+ {
+ *task = this->queued->task;
+ return TRUE;
+ }
+ }
+ else if (this->inner->enumerate(this->inner, task))
{
- *task = queued->task;
return TRUE;
}
return FALSE;
@@ -2143,18 +2172,54 @@ CALLBACK(filter_queued, bool,
METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
private_task_manager_t *this, task_queue_t queue)
{
+ task_enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = enumerator_enumerate_default,
+ .venumerate = _task_enumerator_enumerate,
+ .destroy = _task_enumerator_destroy,
+ },
+ .queue = queue,
+ );
switch (queue)
{
case TASK_QUEUE_ACTIVE:
- return array_create_enumerator(this->active_tasks);
+ enumerator->inner = array_create_enumerator(this->active_tasks);
+ break;
case TASK_QUEUE_PASSIVE:
- return array_create_enumerator(this->passive_tasks);
+ enumerator->inner = array_create_enumerator(this->passive_tasks);
+ break;
case TASK_QUEUE_QUEUED:
- return enumerator_create_filter(
- array_create_enumerator(this->queued_tasks),
- filter_queued, NULL, NULL);
+ enumerator->inner = array_create_enumerator(this->queued_tasks);
+ break;
default:
- return enumerator_create_empty();
+ enumerator->inner = enumerator_create_empty();
+ break;
+ }
+ return &enumerator->public;
+}
+
+METHOD(task_manager_t, remove_task, void,
+ private_task_manager_t *this, enumerator_t *enumerator_public)
+{
+ task_enumerator_t *enumerator = (task_enumerator_t*)enumerator_public;
+
+ switch (enumerator->queue)
+ {
+ case TASK_QUEUE_ACTIVE:
+ array_remove_at(this->active_tasks, enumerator->inner);
+ break;
+ case TASK_QUEUE_PASSIVE:
+ array_remove_at(this->passive_tasks, enumerator->inner);
+ break;
+ case TASK_QUEUE_QUEUED:
+ array_remove_at(this->queued_tasks, enumerator->inner);
+ free(enumerator->queued);
+ enumerator->queued = NULL;
+ break;
+ default:
+ break;
}
}
@@ -2204,9 +2269,9 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
.get_mid = _get_mid,
.reset = _reset,
.adopt_tasks = _adopt_tasks,
- .adopt_child_tasks = _adopt_child_tasks,
.busy = _busy,
.create_task_enumerator = _create_task_enumerator,
+ .remove_task = _remove_task,
.flush = _flush,
.flush_queue = _flush_queue,
.destroy = _destroy,
diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c
index 6c8b29018..0e3711898 100644
--- a/src/libcharon/sa/ikev2/tasks/child_delete.c
+++ b/src/libcharon/sa/ikev2/tasks/child_delete.c
@@ -174,6 +174,11 @@ static void install_outbound(private_child_delete_t *this,
linked_list_t *my_ts, *other_ts;
status_t status;
+ if (!spi)
+ {
+ return;
+ }
+
child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol,
spi, FALSE);
if (!child_sa)
@@ -312,7 +317,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
child_sa_t *child_sa;
child_cfg_t *child_cfg;
protocol_id_t protocol;
- uint32_t spi, reqid, rekey_spi;
+ uint32_t spi, reqid;
action_t action;
status_t status = SUCCESS;
time_t now, expire;
@@ -335,11 +340,7 @@ static status_t destroy_and_reestablish(private_child_delete_t *this)
}
else
{
- rekey_spi = child_sa->get_rekey_spi(child_sa);
- if (rekey_spi)
- {
- install_outbound(this, protocol, rekey_spi);
- }
+ install_outbound(this, protocol, child_sa->get_rekey_spi(child_sa));
/* for rekeyed CHILD_SAs we uninstall the outbound SA but don't
* immediately destroy it, by default, so we can process delayed
* packets */
@@ -459,6 +460,17 @@ METHOD(task_t, build_i, status_t,
this->spi = child_sa->get_spi(child_sa, TRUE);
}
+ if (this->expired && child_sa->get_state(child_sa) == CHILD_REKEYED)
+ { /* the peer was expected to delete this SA, but if we send a DELETE
+ * we might cause a collision there if the CREATE_CHILD_SA response
+ * is delayed (the peer wouldn't know if we deleted this SA due to an
+ * expire or because of a forced delete by the user and might then
+ * ignore the CREATE_CHILD_SA response once it arrives) */
+ child_sa->set_state(child_sa, CHILD_DELETED);
+ install_outbound(this, this->protocol,
+ child_sa->get_rekey_spi(child_sa));
+ }
+
if (child_sa->get_state(child_sa) == CHILD_DELETED)
{ /* DELETEs for this CHILD_SA were already exchanged, but it was not yet
* destroyed to allow delayed packets to get processed */
diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c
index 307d99264..b570904e2 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_init.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_init.c
@@ -773,7 +773,7 @@ static bool derive_keys(private_ike_init_t *this,
return FALSE;
}
charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, chunk_empty,
- nonce_i, nonce_r, this->old_sa, NULL);
+ nonce_i, nonce_r, this->old_sa, NULL, AUTH_NONE);
return TRUE;
}
@@ -890,6 +890,20 @@ METHOD(task_t, pre_process_i, status_t,
switch (type)
{
+ case COOKIE:
+ {
+ chunk_t cookie;
+
+ cookie = notify->get_notification_data(notify);
+ if (chunk_equals(cookie, this->cookie))
+ {
+ DBG1(DBG_IKE, "ignore response with duplicate COOKIE "
+ "notify");
+ enumerator->destroy(enumerator);
+ return FAILED;
+ }
+ break;
+ }
case REDIRECT:
{
identification_t *gateway;
diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h
index 9545da4f3..c357d5035 100644
--- a/src/libcharon/sa/task_manager.h
+++ b/src/libcharon/sa/task_manager.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2016 Tobias Brunner
+ * Copyright (C) 2013-2018 Tobias Brunner
* Copyright (C) 2006 Martin Willi
* HSR Hochschule fuer Technik Rapperswil
*
@@ -228,13 +228,6 @@ 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
@@ -285,6 +278,16 @@ struct task_manager_t {
task_queue_t queue);
/**
+ * Remove the task the given enumerator points to.
+ *
+ * @note This should be used with caution, in partciular, for tasks in the
+ * active and passive queues.
+ *
+ * @param enumerator enumerator created with the method above
+ */
+ void (*remove_task)(task_manager_t *this, enumerator_t *enumerator);
+
+ /**
* Flush all tasks, regardless of the queue.
*/
void (*flush)(task_manager_t *this);
diff --git a/src/libcharon/tests/suites/test_child_rekey.c b/src/libcharon/tests/suites/test_child_rekey.c
index 51d577cd8..b9f6ea0bc 100644
--- a/src/libcharon/tests/suites/test_child_rekey.c
+++ b/src/libcharon/tests/suites/test_child_rekey.c
@@ -370,8 +370,8 @@ END_TEST
/**
* Check that the responder handles hard expires properly while waiting for the
- * delete after a rekeying (e.g. if the initiator of the rekeying fails to
- * delete the CHILD_SA for some reason).
+ * delete after a rekeying (e.g. if the rekey settings are tight or the
+ * CREATE_CHILD_SA response is delayed).
*/
START_TEST(test_regular_responder_handle_hard_expire)
{
@@ -405,28 +405,22 @@ START_TEST(test_regular_responder_handle_hard_expire)
/* we don't expect this to get called anymore */
assert_hook_not_called(child_rekey);
- /* this is similar to a regular delete collision */
- assert_single_payload(OUT, PLV2_DELETE);
+ /* this is similar to a regular delete collision, but we don't actually
+ * want to send a delete back as that might conflict with a delayed
+ * CREATE_CHILD_SA response */
call_ikesa(b, delete_child_sa, PROTO_ESP, 2, TRUE);
- assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
- assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
- /* since the SAs expired they would not actually be installed in the kernel
- * anymore and since we have not yet installed a new outbound SA this
- * will result in dropped packets and possibly acquires */
- assert_ipsec_sas_installed(b, 1, 2, 4);
+ assert_child_sa_count(b, 1);
+ assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+ /* the expire causes the outbound SA to get installed */
+ assert_ipsec_sas_installed(b, 3, 4);
/* INFORMATIONAL { D } --> */
+ assert_no_jobs_scheduled();
assert_single_payload(IN, PLV2_DELETE);
exchange_test_helper->process_message(exchange_test_helper, b, NULL);
- assert_child_sa_state(b, 2, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
- assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_REGISTERED);
- assert_ipsec_sas_installed(b, 1, 2, 4);
- /* <-- INFORMATIONAL { D } */
- assert_single_payload(IN, PLV2_DELETE);
- exchange_test_helper->process_message(exchange_test_helper, a, NULL);
- assert_child_sa_state(a, 1, CHILD_DELETING, CHILD_OUTBOUND_INSTALLED);
- assert_child_sa_state(a, 3, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
- assert_ipsec_sas_installed(a, 1, 2, 3, 4);
+ assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
+ assert_ipsec_sas_installed(b, 3, 4);
+ assert_scheduler();
/* <-- INFORMATIONAL { } */
assert_jobs_scheduled(1);
assert_message_empty(IN);
@@ -436,23 +430,11 @@ START_TEST(test_regular_responder_handle_hard_expire)
assert_child_sa_count(a, 2);
assert_ipsec_sas_installed(a, 1, 3, 4);
assert_scheduler();
- /* INFORMATIONAL { } --> */
- assert_jobs_scheduled(1);
- assert_message_empty(IN);
- exchange_test_helper->process_message(exchange_test_helper, b, NULL);
- assert_child_sa_state(b, 2, CHILD_DELETED, CHILD_OUTBOUND_NONE);
- assert_child_sa_state(b, 4, CHILD_INSTALLED, CHILD_OUTBOUND_INSTALLED);
- assert_child_sa_count(b, 2);
- assert_ipsec_sas_installed(b, 2, 3, 4);
- assert_scheduler();
- /* simulate the execution of the scheduled jobs */
+ /* simulate the execution of the scheduled job */
destroy_rekeyed(a, 1);
assert_child_sa_count(a, 1);
assert_ipsec_sas_installed(a, 3, 4);
- destroy_rekeyed(b, 2);
- assert_child_sa_count(b, 1);
- assert_ipsec_sas_installed(b, 3, 4);
/* child_rekey/child_updown */
assert_hook();