aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon')
-rw-r--r--src/libcharon/Android.mk2
-rw-r--r--src/libcharon/Makefile.am1
-rw-r--r--src/libcharon/control/controller.c32
-rw-r--r--src/libcharon/control/controller.h4
-rw-r--r--src/libcharon/daemon.c2
-rw-r--r--src/libcharon/daemon.h6
-rw-r--r--src/libcharon/kernel/kernel_handler.c24
-rw-r--r--src/libcharon/plugins/ha/ha_child.c2
-rw-r--r--src/libcharon/plugins/ha/ha_dispatcher.c5
-rw-r--r--src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c17
-rw-r--r--src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c17
-rw-r--r--src/libcharon/plugins/load_tester/load_tester_ipsec.c6
-rw-r--r--src/libcharon/plugins/stroke/stroke_control.c8
-rw-r--r--src/libcharon/plugins/stroke/stroke_list.c11
-rw-r--r--src/libcharon/plugins/unity/unity_handler.c22
-rw-r--r--src/libcharon/plugins/unity/unity_handler.h5
-rw-r--r--src/libcharon/plugins/unity/unity_narrow.c4
-rw-r--r--src/libcharon/plugins/vici/README.md1
-rw-r--r--src/libcharon/plugins/vici/vici_config.c20
-rw-r--r--src/libcharon/plugins/vici/vici_control.c4
-rw-r--r--src/libcharon/plugins/vici/vici_query.c1
-rw-r--r--src/libcharon/processing/jobs/delete_child_sa_job.c26
-rw-r--r--src/libcharon/processing/jobs/delete_child_sa_job.h9
-rw-r--r--src/libcharon/processing/jobs/inactivity_job.c16
-rw-r--r--src/libcharon/processing/jobs/inactivity_job.h4
-rw-r--r--src/libcharon/processing/jobs/migrate_job.c62
-rw-r--r--src/libcharon/processing/jobs/migrate_job.h2
-rw-r--r--src/libcharon/processing/jobs/rekey_child_sa_job.c27
-rw-r--r--src/libcharon/processing/jobs/rekey_child_sa_job.h10
-rw-r--r--src/libcharon/processing/jobs/update_sa_job.c33
-rw-r--r--src/libcharon/processing/jobs/update_sa_job.h8
-rw-r--r--src/libcharon/sa/child_sa.c128
-rw-r--r--src/libcharon/sa/child_sa.h15
-rw-r--r--src/libcharon/sa/child_sa_manager.c333
-rw-r--r--src/libcharon/sa/child_sa_manager.h89
-rw-r--r--src/libcharon/sa/ike_sa.c65
-rw-r--r--src/libcharon/sa/ike_sa_manager.c39
-rw-r--r--src/libcharon/sa/ike_sa_manager.h10
-rw-r--r--src/libcharon/sa/ikev1/task_manager_v1.c5
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_delete.c4
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.c44
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.h8
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c39
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.h8
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_delete.c4
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_rekey.c10
-rw-r--r--src/libcharon/sa/ikev2/tasks/ike_mobike.c27
-rw-r--r--src/libcharon/sa/trap_manager.c2
48 files changed, 923 insertions, 298 deletions
diff --git a/src/libcharon/Android.mk b/src/libcharon/Android.mk
index 4212ee87a..ab71d4016 100644
--- a/src/libcharon/Android.mk
+++ b/src/libcharon/Android.mk
@@ -72,6 +72,7 @@ sa/ike_sa.c sa/ike_sa.h \
sa/ike_sa_id.c sa/ike_sa_id.h \
sa/keymat.h sa/keymat.c \
sa/ike_sa_manager.c sa/ike_sa_manager.h \
+sa/child_sa_manager.c sa/child_sa_manager.h \
sa/task_manager.h sa/task_manager.c \
sa/shunt_manager.c sa/shunt_manager.h \
sa/trap_manager.c sa/trap_manager.h \
@@ -238,4 +239,3 @@ LOCAL_PRELINK_MODULE := false
LOCAL_SHARED_LIBRARIES += libstrongswan libhydra
include $(BUILD_SHARED_LIBRARY)
-
diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am
index e98f5e137..e666950f1 100644
--- a/src/libcharon/Makefile.am
+++ b/src/libcharon/Makefile.am
@@ -70,6 +70,7 @@ sa/ike_sa.c sa/ike_sa.h \
sa/ike_sa_id.c sa/ike_sa_id.h \
sa/keymat.h sa/keymat.c \
sa/ike_sa_manager.c sa/ike_sa_manager.h \
+sa/child_sa_manager.c sa/child_sa_manager.h \
sa/task_manager.h sa/task_manager.c \
sa/shunt_manager.c sa/shunt_manager.h \
sa/trap_manager.c sa/trap_manager.h \
diff --git a/src/libcharon/control/controller.c b/src/libcharon/control/controller.c
index 60d186e27..fd8349e2f 100644
--- a/src/libcharon/control/controller.c
+++ b/src/libcharon/control/controller.c
@@ -449,7 +449,7 @@ METHOD(job_t, terminate_ike_execute, job_requeue_t,
ike_sa_t *ike_sa;
ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
- unique_id, FALSE);
+ unique_id);
if (!ike_sa)
{
DBG1(DBG_IKE, "unable to terminate IKE_SA: ID %d not found", unique_id);
@@ -534,17 +534,15 @@ METHOD(job_t, terminate_child_execute, job_requeue_t,
interface_job_t *job)
{
interface_listener_t *listener = &job->listener;
- u_int32_t reqid = listener->id;
- enumerator_t *enumerator;
+ u_int32_t id = listener->id;
child_sa_t *child_sa;
ike_sa_t *ike_sa;
- ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
- reqid, TRUE);
+ ike_sa = charon->child_sa_manager->checkout_by_id(charon->child_sa_manager,
+ id, &child_sa);
if (!ike_sa)
{
- DBG1(DBG_IKE, "unable to terminate, CHILD_SA with ID %d not found",
- reqid);
+ DBG1(DBG_IKE, "unable to terminate, CHILD_SA with ID %d not found", id);
listener->status = NOT_FOUND;
/* release listener */
listener_done(listener);
@@ -554,22 +552,10 @@ METHOD(job_t, terminate_child_execute, job_requeue_t,
listener->ike_sa = ike_sa;
listener->lock->unlock(listener->lock);
- enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
- while (enumerator->enumerate(enumerator, (void**)&child_sa))
- {
- if (child_sa->get_state(child_sa) != CHILD_ROUTED &&
- child_sa->get_reqid(child_sa) == reqid)
- {
- break;
- }
- child_sa = NULL;
- }
- enumerator->destroy(enumerator);
-
- if (!child_sa)
+ if (child_sa->get_state(child_sa) == CHILD_ROUTED)
{
DBG1(DBG_IKE, "unable to terminate, established "
- "CHILD_SA with ID %d not found", reqid);
+ "CHILD_SA with ID %d not found", id);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
listener->status = NOT_FOUND;
/* release listener */
@@ -596,7 +582,7 @@ METHOD(job_t, terminate_child_execute, job_requeue_t,
}
METHOD(controller_t, terminate_child, status_t,
- controller_t *this, u_int32_t reqid,
+ controller_t *this, u_int32_t unique_id,
controller_cb_t callback, void *param, u_int timeout)
{
interface_job_t *job;
@@ -617,7 +603,7 @@ METHOD(controller_t, terminate_child, status_t,
.param = param,
},
.status = FAILED,
- .id = reqid,
+ .id = unique_id,
.lock = spinlock_create(),
},
.public = {
diff --git a/src/libcharon/control/controller.h b/src/libcharon/control/controller.h
index 222285cde..02f4ebb2b 100644
--- a/src/libcharon/control/controller.h
+++ b/src/libcharon/control/controller.h
@@ -118,7 +118,7 @@ struct controller_t {
* If a callback is provided the function is synchronous and thus blocks
* until the CHILD_SA is properly deleted, or the call timed out.
*
- * @param reqid reqid of the CHILD_SA to terminate
+ * @param unique_id CHILD_SA unique ID to terminate
* @param cb logging callback
* @param param parameter to include in each call of cb
* @param timeout timeout in ms to wait for callbacks, 0 to disable
@@ -128,7 +128,7 @@ struct controller_t {
* - NEED_MORE, if callback returned FALSE
* - OUT_OF_RES if timed out
*/
- status_t (*terminate_child)(controller_t *this, u_int32_t reqid,
+ status_t (*terminate_child)(controller_t *this, u_int32_t unique_id,
controller_cb_t callback, void *param,
u_int timeout);
diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c
index 3ae7c4e6f..f3859f912 100644
--- a/src/libcharon/daemon.c
+++ b/src/libcharon/daemon.c
@@ -480,6 +480,7 @@ static void destroy(private_daemon_t *this)
DESTROY_IF(this->kernel_handler);
DESTROY_IF(this->public.traps);
DESTROY_IF(this->public.shunts);
+ DESTROY_IF(this->public.child_sa_manager);
DESTROY_IF(this->public.ike_sa_manager);
DESTROY_IF(this->public.controller);
DESTROY_IF(this->public.eap);
@@ -606,6 +607,7 @@ METHOD(daemon_t, initialize, bool,
{
return FALSE;
}
+ this->public.child_sa_manager = child_sa_manager_create();
/* Queue start_action job */
lib->processor->queue_job(lib->processor, (job_t*)start_action_job_create());
diff --git a/src/libcharon/daemon.h b/src/libcharon/daemon.h
index 36242bb04..8ec1ec253 100644
--- a/src/libcharon/daemon.h
+++ b/src/libcharon/daemon.h
@@ -158,6 +158,7 @@ typedef struct daemon_t daemon_t;
#include <control/controller.h>
#include <bus/bus.h>
#include <sa/ike_sa_manager.h>
+#include <sa/child_sa_manager.h>
#include <sa/trap_manager.h>
#include <sa/shunt_manager.h>
#include <config/backend_manager.h>
@@ -215,6 +216,11 @@ struct daemon_t {
ike_sa_manager_t *ike_sa_manager;
/**
+ * A child_sa_manager_t instance.
+ */
+ child_sa_manager_t *child_sa_manager;
+
+ /**
* Manager for triggering policies, called traps
*/
trap_manager_t *traps;
diff --git a/src/libcharon/kernel/kernel_handler.c b/src/libcharon/kernel/kernel_handler.c
index 059124e35..96a51fabd 100644
--- a/src/libcharon/kernel/kernel_handler.c
+++ b/src/libcharon/kernel/kernel_handler.c
@@ -72,36 +72,38 @@ METHOD(kernel_listener_t, acquire, bool,
}
METHOD(kernel_listener_t, expire, bool,
- private_kernel_handler_t *this, u_int32_t reqid, u_int8_t protocol,
- u_int32_t spi, bool hard)
+ private_kernel_handler_t *this, u_int8_t protocol, u_int32_t spi,
+ host_t *dst, bool hard)
{
protocol_id_t proto = proto_ip2ike(protocol);
- DBG1(DBG_KNL, "creating %s job for %N CHILD_SA with SPI %.8x and reqid {%u}",
- hard ? "delete" : "rekey", protocol_id_names, proto, ntohl(spi), reqid);
+ DBG1(DBG_KNL, "creating %s job for CHILD_SA %N/0x%08x/%H",
+ hard ? "delete" : "rekey", protocol_id_names, proto, ntohl(spi), dst);
if (hard)
{
lib->processor->queue_job(lib->processor,
- (job_t*)delete_child_sa_job_create(reqid, proto, spi, hard));
+ (job_t*)delete_child_sa_job_create(proto, spi, dst, hard));
}
else
{
lib->processor->queue_job(lib->processor,
- (job_t*)rekey_child_sa_job_create(reqid, proto, spi));
+ (job_t*)rekey_child_sa_job_create(proto, spi, dst));
}
return TRUE;
}
METHOD(kernel_listener_t, mapping, bool,
- private_kernel_handler_t *this, u_int32_t reqid, u_int32_t spi,
- host_t *remote)
+ private_kernel_handler_t *this, u_int8_t protocol, u_int32_t spi,
+ host_t *dst, host_t *remote)
{
- DBG1(DBG_KNL, "NAT mappings of ESP CHILD_SA with SPI %.8x and reqid {%u} "
- "changed, queuing update job", ntohl(spi), reqid);
+ protocol_id_t proto = proto_ip2ike(protocol);
+
+ DBG1(DBG_KNL, "NAT mappings of CHILD_SA %N/0x%08x/%H changed, "
+ "queuing update job", protocol_id_names, proto, ntohl(spi), dst);
lib->processor->queue_job(lib->processor,
- (job_t*)update_sa_job_create(reqid, remote));
+ (job_t*)update_sa_job_create(proto, spi, dst, remote));
return TRUE;
}
diff --git a/src/libcharon/plugins/ha/ha_child.c b/src/libcharon/plugins/ha/ha_child.c
index c166d72ac..ed6ca7196 100644
--- a/src/libcharon/plugins/ha/ha_child.c
+++ b/src/libcharon/plugins/ha/ha_child.c
@@ -128,7 +128,7 @@ METHOD(listener_t, child_keys, bool,
ike_sa->get_other_host(ike_sa), child_sa->get_spi(child_sa, FALSE));
DBG1(DBG_CFG, "handling HA CHILD_SA %s{%d} %#R=== %#R "
"(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
- child_sa->get_reqid(child_sa), local_ts, remote_ts,
+ child_sa->get_unique_id(child_sa), local_ts, remote_ts,
seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c
index e20e872c1..983f9d8fc 100644
--- a/src/libcharon/plugins/ha/ha_dispatcher.c
+++ b/src/libcharon/plugins/ha/ha_dispatcher.c
@@ -718,7 +718,8 @@ static void process_child_add(private_ha_dispatcher_t *this,
child_sa = child_sa_create(ike_sa->get_my_host(ike_sa),
ike_sa->get_other_host(ike_sa), config, 0,
- ike_sa->has_condition(ike_sa, COND_NAT_ANY));
+ ike_sa->has_condition(ike_sa, COND_NAT_ANY),
+ 0, 0);
child_sa->set_mode(child_sa, mode);
child_sa->set_protocol(child_sa, PROTO_ESP);
child_sa->set_ipcomp(child_sa, ipcomp);
@@ -835,7 +836,7 @@ static void process_child_add(private_ha_dispatcher_t *this,
DBG1(DBG_CFG, "installed HA CHILD_SA %s{%d} %#R=== %#R "
"(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
- child_sa->get_reqid(child_sa), local_ts, remote_ts,
+ child_sa->get_unique_id(child_sa), local_ts, remote_ts,
seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
child_sa->add_policies(child_sa, local_ts, remote_ts);
diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
index bd07a67a2..e6c5d6a1d 100644
--- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
+++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c
@@ -222,10 +222,10 @@ static inline bool policy_entry_equals(policy_entry_t *a,
/**
* Expiration callback
*/
-static void expire(u_int32_t reqid, u_int8_t protocol, u_int32_t spi, bool hard)
+static void expire(u_int8_t protocol, u_int32_t spi, host_t *dst, bool hard)
{
- hydra->kernel_interface->expire(hydra->kernel_interface, reqid, protocol,
- spi, hard);
+ hydra->kernel_interface->expire(hydra->kernel_interface, protocol,
+ spi, dst, hard);
}
METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
@@ -236,14 +236,14 @@ METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
METHOD(kernel_ipsec_t, get_spi, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst,
- u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
+ u_int8_t protocol, u_int32_t *spi)
{
- return ipsec->sas->get_spi(ipsec->sas, src, dst, protocol, reqid, spi);
+ return ipsec->sas->get_spi(ipsec->sas, src, dst, protocol, spi);
}
METHOD(kernel_ipsec_t, get_cpi, status_t,
private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst,
- u_int32_t reqid, u_int16_t *cpi)
+ u_int16_t *cpi)
{
return NOT_SUPPORTED;
}
@@ -255,12 +255,11 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
u_int16_t ipcomp, u_int16_t cpi, u_int32_t replay_window,
bool initiator, bool encap, bool esn, bool inbound,
- traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
+ linked_list_t *src_ts, linked_list_t *dst_ts)
{
return ipsec->sas->add_sa(ipsec->sas, src, dst, spi, protocol, reqid, mark,
tfc, lifetime, enc_alg, enc_key, int_alg, int_key,
- mode, ipcomp, cpi, initiator, encap, esn, inbound,
- src_ts, dst_ts);
+ mode, ipcomp, cpi, initiator, encap, esn, inbound);
}
METHOD(kernel_ipsec_t, update_sa, status_t,
diff --git a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c
index 39e37b1c9..86db9e643 100644
--- a/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c
+++ b/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c
@@ -1981,7 +1981,7 @@ static u_int permute(u_int x, u_int p)
METHOD(kernel_ipsec_t, get_spi, status_t,
private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
- u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
+ u_int8_t protocol, u_int32_t *spi)
{
/* To avoid sequencial SPIs, we use a one-to-one permuation function on
* an incrementing counter, that is a full period PRNG for the range we
@@ -1998,7 +1998,7 @@ METHOD(kernel_ipsec_t, get_spi, status_t,
METHOD(kernel_ipsec_t, get_cpi, status_t,
private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
- u_int32_t reqid, u_int16_t *cpi)
+ u_int16_t *cpi)
{
return NOT_SUPPORTED;
}
@@ -2032,9 +2032,8 @@ static void expire_data_destroy(expire_data_t *data)
static job_requeue_t expire_job(expire_data_t *data)
{
private_kernel_wfp_ipsec_t *this = data->this;
- u_int32_t reqid = 0;
u_int8_t protocol;
- entry_t *entry;
+ entry_t *entry = NULL;
sa_entry_t key = {
.spi = data->spi,
.dst = data->dst,
@@ -2048,7 +2047,6 @@ static job_requeue_t expire_job(expire_data_t *data)
if (entry)
{
protocol = entry->isa.protocol;
- reqid = entry->reqid;
if (entry->osa.dst)
{
key.dst = entry->osa.dst;
@@ -2065,15 +2063,14 @@ static job_requeue_t expire_job(expire_data_t *data)
if (entry)
{
protocol = entry->isa.protocol;
- reqid = entry->reqid;
}
this->mutex->unlock(this->mutex);
}
- if (reqid)
+ if (entry)
{
- hydra->kernel_interface->expire(hydra->kernel_interface,
- reqid, protocol, data->spi, data->hard);
+ hydra->kernel_interface->expire(hydra->kernel_interface, protocol,
+ data->spi, data->dst, data->hard);
}
return JOB_REQUEUE_NONE;
@@ -2107,7 +2104,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
u_int16_t ipcomp, u_int16_t cpi, u_int32_t replay_window,
bool initiator, bool encap, bool esn, bool inbound,
- traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
+ linked_list_t *src_ts, linked_list_t *dst_ts)
{
host_t *local, *remote;
entry_t *entry;
diff --git a/src/libcharon/plugins/load_tester/load_tester_ipsec.c b/src/libcharon/plugins/load_tester/load_tester_ipsec.c
index 3f256ddd0..68af4794d 100644
--- a/src/libcharon/plugins/load_tester/load_tester_ipsec.c
+++ b/src/libcharon/plugins/load_tester/load_tester_ipsec.c
@@ -36,7 +36,7 @@ struct private_load_tester_ipsec_t {
METHOD(kernel_ipsec_t, get_spi, status_t,
private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
- u_int8_t protocol, u_int32_t reqid, u_int32_t *spi)
+ u_int8_t protocol, u_int32_t *spi)
{
*spi = (uint32_t)ref_get(&this->spi);
return SUCCESS;
@@ -44,7 +44,7 @@ METHOD(kernel_ipsec_t, get_spi, status_t,
METHOD(kernel_ipsec_t, get_cpi, status_t,
private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
- u_int32_t reqid, u_int16_t *cpi)
+ u_int16_t *cpi)
{
return FAILED;
}
@@ -56,7 +56,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
u_int16_t ipcomp, u_int16_t cpi, u_int32_t replay_window,
bool initiator, bool encap, bool esn, bool inbound,
- traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
+ linked_list_t *src_ts, linked_list_t *dst_ts)
{
return SUCCESS;
}
diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c
index f770d7c9e..0084fbf93 100644
--- a/src/libcharon/plugins/stroke/stroke_control.c
+++ b/src/libcharon/plugins/stroke/stroke_control.c
@@ -352,7 +352,7 @@ METHOD(stroke_control_t, terminate, void,
if (streq(name, child_sa->get_name(child_sa)))
{
child_list->insert_last(child_list,
- (void*)(uintptr_t)child_sa->get_reqid(child_sa));
+ (void*)(uintptr_t)child_sa->get_unique_id(child_sa));
if (!all)
{
break;
@@ -432,13 +432,13 @@ METHOD(stroke_control_t, rekey, void,
while (children->enumerate(children, (void**)&child_sa))
{
if ((name && streq(name, child_sa->get_name(child_sa))) ||
- (id && id == child_sa->get_reqid(child_sa)))
+ (id && id == child_sa->get_unique_id(child_sa)))
{
lib->processor->queue_job(lib->processor,
(job_t*)rekey_child_sa_job_create(
- child_sa->get_reqid(child_sa),
child_sa->get_protocol(child_sa),
- child_sa->get_spi(child_sa, TRUE)));
+ child_sa->get_spi(child_sa, TRUE),
+ ike_sa->get_my_host(ike_sa)));
if (!all)
{
finished = TRUE;
diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c
index 1aa49ce0d..490983100 100644
--- a/src/libcharon/plugins/stroke/stroke_list.c
+++ b/src/libcharon/plugins/stroke/stroke_list.c
@@ -214,11 +214,12 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
config = child_sa->get_config(child_sa);
now = time_monotonic(NULL);
- fprintf(out, "%12s{%d}: %N, %N%s",
- child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
+ fprintf(out, "%12s{%d}: %N, %N%s, reqid %u",
+ child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
child_sa_state_names, child_sa->get_state(child_sa),
ipsec_mode_names, child_sa->get_mode(child_sa),
- config->use_proxy_mode(config) ? "_PROXY" : "");
+ config->use_proxy_mode(config) ? "_PROXY" : "",
+ child_sa->get_reqid(child_sa));
if (child_sa->get_state(child_sa) == CHILD_INSTALLED)
{
@@ -238,7 +239,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
if (all)
{
fprintf(out, "\n%12s{%d}: ", child_sa->get_name(child_sa),
- child_sa->get_reqid(child_sa));
+ child_sa->get_unique_id(child_sa));
proposal = child_sa->get_proposal(child_sa);
if (proposal)
@@ -333,7 +334,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
other_ts = linked_list_create_from_enumerator(
child_sa->create_ts_enumerator(child_sa, FALSE));
fprintf(out, "\n%12s{%d}: %#R=== %#R\n",
- child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
+ child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
my_ts, other_ts);
my_ts->destroy(my_ts);
other_ts->destroy(other_ts);
diff --git a/src/libcharon/plugins/unity/unity_handler.c b/src/libcharon/plugins/unity/unity_handler.c
index bcef0dc25..eb0ddba5d 100644
--- a/src/libcharon/plugins/unity/unity_handler.c
+++ b/src/libcharon/plugins/unity/unity_handler.c
@@ -50,8 +50,8 @@ struct private_unity_handler_t {
* Traffic selector entry for networks to include under a given IKE_SA
*/
typedef struct {
- /** associated IKE_SA, unique ID */
- u_int32_t sa;
+ /** associated IKE_SA COOKIEs */
+ ike_sa_id_t *id;
/** traffic selector to include/exclude */
traffic_selector_t *ts;
} entry_t;
@@ -61,6 +61,7 @@ typedef struct {
*/
static void entry_destroy(entry_t *this)
{
+ this->id->destroy(this->id);
this->ts->destroy(this->ts);
free(this);
}
@@ -131,9 +132,10 @@ static bool add_include(private_unity_handler_t *this, chunk_t data)
while (list->remove_first(list, (void**)&ts) == SUCCESS)
{
INIT(entry,
- .sa = ike_sa->get_unique_id(ike_sa),
+ .id = ike_sa->get_id(ike_sa),
.ts = ts,
);
+ entry->id = entry->id->clone(entry->id);
this->mutex->lock(this->mutex);
this->include->insert_last(this->include, entry);
@@ -171,7 +173,7 @@ static bool remove_include(private_unity_handler_t *this, chunk_t data)
enumerator = this->include->create_enumerator(this->include);
while (enumerator->enumerate(enumerator, &entry))
{
- if (entry->sa == ike_sa->get_unique_id(ike_sa) &&
+ if (entry->id->equals(entry->id, ike_sa->get_id(ike_sa)) &&
ts->equals(ts, entry->ts))
{
this->include->remove_at(this->include, enumerator);
@@ -209,8 +211,7 @@ static job_requeue_t add_exclude_async(entry_t *entry)
char name[128];
host_t *host;
- ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
- entry->sa, FALSE);
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, entry->id);
if (ike_sa)
{
create_shunt_name(ike_sa, entry->ts, name, sizeof(name));
@@ -267,9 +268,10 @@ static bool add_exclude(private_unity_handler_t *this, chunk_t data)
while (list->remove_first(list, (void**)&ts) == SUCCESS)
{
INIT(entry,
- .sa = ike_sa->get_unique_id(ike_sa),
+ .id = ike_sa->get_id(ike_sa),
.ts = ts,
);
+ entry->id = entry->id->clone(entry->id);
/* we can't install the shunt policy yet, as we don't know the virtual IP.
* Defer installation using an async callback. */
@@ -402,7 +404,7 @@ typedef struct {
/** mutex to unlock */
mutex_t *mutex;
/** IKE_SA ID to filter for */
- u_int32_t id;
+ ike_sa_id_t *id;
} include_filter_t;
/**
@@ -411,7 +413,7 @@ typedef struct {
static bool include_filter(include_filter_t *data,
entry_t **entry, traffic_selector_t **ts)
{
- if ((*entry)->sa == data->id)
+ if (data->id->equals(data->id, (*entry)->id))
{
*ts = (*entry)->ts;
return TRUE;
@@ -429,7 +431,7 @@ static void destroy_filter(include_filter_t *data)
}
METHOD(unity_handler_t, create_include_enumerator, enumerator_t*,
- private_unity_handler_t *this, u_int32_t id)
+ private_unity_handler_t *this, ike_sa_id_t *id)
{
include_filter_t *data;
diff --git a/src/libcharon/plugins/unity/unity_handler.h b/src/libcharon/plugins/unity/unity_handler.h
index 8656fd372..18efe293b 100644
--- a/src/libcharon/plugins/unity/unity_handler.h
+++ b/src/libcharon/plugins/unity/unity_handler.h
@@ -21,6 +21,7 @@
#ifndef UNITY_HANDLER_H_
#define UNITY_HANDLER_H_
+#include <sa/ike_sa_id.h>
#include <attributes/attribute_handler.h>
typedef struct unity_handler_t unity_handler_t;
@@ -38,11 +39,11 @@ struct unity_handler_t {
/**
* Create an enumerator over Split-Include attributes received for an IKE_SA.
*
- * @param id IKE_SA unique ID to get Split-Includes for
+ * @param id IKE_SA ID to get Split-Includes for
* @return enumerator over traffic_selector_t*
*/
enumerator_t* (*create_include_enumerator)(unity_handler_t *this,
- u_int32_t id);
+ ike_sa_id_t *id);
/**
* Destroy a unity_handler_t.
diff --git a/src/libcharon/plugins/unity/unity_narrow.c b/src/libcharon/plugins/unity/unity_narrow.c
index 94089563d..227d24be8 100644
--- a/src/libcharon/plugins/unity/unity_narrow.c
+++ b/src/libcharon/plugins/unity/unity_narrow.c
@@ -75,7 +75,7 @@ static void narrow_initiator(private_unity_narrow_t *this, ike_sa_t *ike_sa,
enumerator_t *enumerator;
enumerator = this->handler->create_include_enumerator(this->handler,
- ike_sa->get_unique_id(ike_sa));
+ ike_sa->get_id(ike_sa));
while (enumerator->enumerate(enumerator, &current))
{
if (orig == NULL)
@@ -159,7 +159,7 @@ static bool has_split_includes(private_unity_narrow_t *this, ike_sa_t *ike_sa)
bool has;
enumerator = this->handler->create_include_enumerator(this->handler,
- ike_sa->get_unique_id(ike_sa));
+ ike_sa->get_id(ike_sa));
has = enumerator->enumerate(enumerator, &ts);
enumerator->destroy(enumerator);
diff --git a/src/libcharon/plugins/vici/README.md b/src/libcharon/plugins/vici/README.md
index b74ef0f15..c25b99e1d 100644
--- a/src/libcharon/plugins/vici/README.md
+++ b/src/libcharon/plugins/vici/README.md
@@ -559,6 +559,7 @@ command.
]
child-sas = {
<child-sa-name>* = {
+ uniqueid = <unique CHILD_SA identifier>
reqid = <reqid of CHILD_SA>
state = <state string of CHILD_SA>
mode = <IPsec mode, tunnel|transport|beet>
diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c
index 113d48084..43b3f0712 100644
--- a/src/libcharon/plugins/vici/vici_config.c
+++ b/src/libcharon/plugins/vici/vici_config.c
@@ -1551,8 +1551,8 @@ static void clear_start_action(private_vici_config_t *this,
enumerator_t *enumerator, *children;
child_sa_t *child_sa;
ike_sa_t *ike_sa;
- u_int32_t reqid = 0, *del;
- array_t *reqids = NULL;
+ u_int32_t id = 0, *del;
+ array_t *ids = NULL;
char *name;
name = child_cfg->get_name(child_cfg);
@@ -1568,23 +1568,23 @@ static void clear_start_action(private_vici_config_t *this,
{
if (streq(name, child_sa->get_name(child_sa)))
{
- reqid = child_sa->get_reqid(child_sa);
- array_insert_create(&reqids, ARRAY_TAIL, &reqid);
+ id = child_sa->get_unique_id(child_sa);
+ array_insert_create(&ids, ARRAY_TAIL, &id);
}
}
children->destroy(children);
}
enumerator->destroy(enumerator);
- if (array_count(reqids))
+ if (array_count(ids))
{
- while (array_remove(reqids, ARRAY_HEAD, &del))
+ while (array_remove(ids, ARRAY_HEAD, &del))
{
DBG1(DBG_CFG, "closing '%s' #%u", name, *del);
charon->controller->terminate_child(charon->controller,
*del, NULL, NULL, 0);
}
- array_destroy(reqids);
+ array_destroy(ids);
}
break;
case ACTION_ROUTE:
@@ -1601,14 +1601,14 @@ static void clear_start_action(private_vici_config_t *this,
{
if (streq(name, child_sa->get_name(child_sa)))
{
- reqid = child_sa->get_reqid(child_sa);
+ id = child_sa->get_reqid(child_sa);
break;
}
}
enumerator->destroy(enumerator);
- if (reqid)
+ if (id)
{
- charon->traps->uninstall(charon->traps, reqid);
+ charon->traps->uninstall(charon->traps, id);
}
break;
}
diff --git a/src/libcharon/plugins/vici/vici_control.c b/src/libcharon/plugins/vici/vici_control.c
index 292a40032..01d503644 100644
--- a/src/libcharon/plugins/vici/vici_control.c
+++ b/src/libcharon/plugins/vici/vici_control.c
@@ -264,11 +264,11 @@ CALLBACK(terminate, vici_message_t*,
{
continue;
}
- if (child_id && child_sa->get_reqid(child_sa) != child_id)
+ if (child_id && child_sa->get_unique_id(child_sa) != child_id)
{
continue;
}
- current = child_sa->get_reqid(child_sa);
+ current = child_sa->get_unique_id(child_sa);
array_insert(ids, ARRAY_TAIL, &current);
}
csas->destroy(csas);
diff --git a/src/libcharon/plugins/vici/vici_query.c b/src/libcharon/plugins/vici/vici_query.c
index 54833abde..5a8ef25d8 100644
--- a/src/libcharon/plugins/vici/vici_query.c
+++ b/src/libcharon/plugins/vici/vici_query.c
@@ -63,6 +63,7 @@ static void list_child(private_vici_query_t *this, vici_builder_t *b,
enumerator_t *enumerator;
traffic_selector_t *ts;
+ b->add_kv(b, "uniqueid", "%u", child->get_unique_id(child));
b->add_kv(b, "reqid", "%u", child->get_reqid(child));
b->add_kv(b, "state", "%N", child_sa_state_names, child->get_state(child));
b->add_kv(b, "mode", "%N", ipsec_mode_names, child->get_mode(child));
diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.c b/src/libcharon/processing/jobs/delete_child_sa_job.c
index 9afbac02b..0d85883be 100644
--- a/src/libcharon/processing/jobs/delete_child_sa_job.c
+++ b/src/libcharon/processing/jobs/delete_child_sa_job.c
@@ -31,11 +31,6 @@ struct private_delete_child_sa_job_t {
delete_child_sa_job_t public;
/**
- * reqid of the CHILD_SA
- */
- u_int32_t reqid;
-
- /**
* protocol of the CHILD_SA (ESP/AH)
*/
protocol_id_t protocol;
@@ -46,6 +41,11 @@ struct private_delete_child_sa_job_t {
u_int32_t spi;
/**
+ * SA destination address
+ */
+ host_t *dst;
+
+ /**
* Delete for an expired CHILD_SA
*/
bool expired;
@@ -54,6 +54,7 @@ struct private_delete_child_sa_job_t {
METHOD(job_t, destroy, void,
private_delete_child_sa_job_t *this)
{
+ this->dst->destroy(this->dst);
free(this);
}
@@ -62,12 +63,12 @@ METHOD(job_t, execute, job_requeue_t,
{
ike_sa_t *ike_sa;
- ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
- this->reqid, TRUE);
+ ike_sa = charon->child_sa_manager->checkout(charon->child_sa_manager,
+ this->protocol, this->spi, this->dst, NULL);
if (ike_sa == NULL)
{
- DBG1(DBG_JOB, "CHILD_SA with reqid %d not found for delete",
- this->reqid);
+ DBG1(DBG_JOB, "CHILD_SA %N/0x%08x/%H not found for delete",
+ protocol_id_names, this->protocol, htonl(this->spi), this->dst);
}
else
{
@@ -87,8 +88,8 @@ METHOD(job_t, get_priority, job_priority_t,
/*
* Described in header
*/
-delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid,
- protocol_id_t protocol, u_int32_t spi, bool expired)
+delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol,
+ u_int32_t spi, host_t *dst, bool expired)
{
private_delete_child_sa_job_t *this;
@@ -100,12 +101,11 @@ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid,
.destroy = _destroy,
},
},
- .reqid = reqid,
.protocol = protocol,
.spi = spi,
+ .dst = dst->clone(dst),
.expired = expired,
);
return &this->public;
}
-
diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.h b/src/libcharon/processing/jobs/delete_child_sa_job.h
index be6d578bc..6fa53644c 100644
--- a/src/libcharon/processing/jobs/delete_child_sa_job.h
+++ b/src/libcharon/processing/jobs/delete_child_sa_job.h
@@ -44,16 +44,13 @@ struct delete_child_sa_job_t {
/**
* Creates a job of type DELETE_CHILD_SA.
*
- * The CHILD_SA is identified by its reqid, protocol (AH/ESP) and its
- * inbound SPI.
- *
- * @param reqid reqid of the CHILD_SA, as used in kernel
* @param protocol protocol of the CHILD_SA
* @param spi security parameter index of the CHILD_SA
+ * @param dst SA destination address
* @param expired TRUE if CHILD_SA already expired
* @return delete_child_sa_job_t object
*/
-delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid,
- protocol_id_t protocol, u_int32_t spi, bool expired);
+delete_child_sa_job_t *delete_child_sa_job_create(protocol_id_t protocol,
+ u_int32_t spi, host_t *dst, bool expired);
#endif /** DELETE_CHILD_SA_JOB_H_ @}*/
diff --git a/src/libcharon/processing/jobs/inactivity_job.c b/src/libcharon/processing/jobs/inactivity_job.c
index 197733979..f0f90eedf 100644
--- a/src/libcharon/processing/jobs/inactivity_job.c
+++ b/src/libcharon/processing/jobs/inactivity_job.c
@@ -30,9 +30,9 @@ struct private_inactivity_job_t {
inactivity_job_t public;
/**
- * Reqid of CHILD_SA to check
+ * Unique CHILD_SA identifier to check
*/
- u_int32_t reqid;
+ u_int32_t id;
/**
* Inactivity timeout
@@ -57,8 +57,8 @@ METHOD(job_t, execute, job_requeue_t,
ike_sa_t *ike_sa;
u_int32_t reschedule = 0;
- ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
- this->reqid, TRUE);
+ ike_sa = charon->child_sa_manager->checkout_by_id(charon->child_sa_manager,
+ this->id, NULL);
if (ike_sa)
{
enumerator_t *enumerator;
@@ -69,9 +69,9 @@ METHOD(job_t, execute, job_requeue_t,
status_t status = SUCCESS;
enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
- while (enumerator->enumerate(enumerator, (void**)&child_sa))
+ while (enumerator->enumerate(enumerator, &child_sa))
{
- if (child_sa->get_reqid(child_sa) == this->reqid)
+ if (child_sa->get_unique_id(child_sa) == this->id)
{
time_t in, out, install, diff;
@@ -136,7 +136,7 @@ METHOD(job_t, get_priority, job_priority_t,
/**
* See header
*/
-inactivity_job_t *inactivity_job_create(u_int32_t reqid, u_int32_t timeout,
+inactivity_job_t *inactivity_job_create(u_int32_t unique_id, u_int32_t timeout,
bool close_ike)
{
private_inactivity_job_t *this;
@@ -149,7 +149,7 @@ inactivity_job_t *inactivity_job_create(u_int32_t reqid, u_int32_t timeout,
.destroy = _destroy,
},
},
- .reqid = reqid,
+ .id = unique_id,
.timeout = timeout,
.close_ike = close_ike,
);
diff --git a/src/libcharon/processing/jobs/inactivity_job.h b/src/libcharon/processing/jobs/inactivity_job.h
index 890f7704b..ff19fe560 100644
--- a/src/libcharon/processing/jobs/inactivity_job.h
+++ b/src/libcharon/processing/jobs/inactivity_job.h
@@ -42,12 +42,12 @@ struct inactivity_job_t {
/**
* Create a inactivity_job instance.
*
- * @param reqid reqid of CHILD_SA to check for inactivity
+ * @param unique_id unique CHILD_SA identifier to check for inactivity
* @param timeout inactivity timeout in s
* @param close_ike close IKE_SA if the last remaining CHILD_SA is inactive?
* @return inactivity checking job
*/
-inactivity_job_t *inactivity_job_create(u_int32_t reqid, u_int32_t timeout,
+inactivity_job_t *inactivity_job_create(u_int32_t unique_id, u_int32_t timeout,
bool close_ike);
#endif /** INACTIVITY_JOB_H_ @}*/
diff --git a/src/libcharon/processing/jobs/migrate_job.c b/src/libcharon/processing/jobs/migrate_job.c
index 2ebfc6714..097dbdffd 100644
--- a/src/libcharon/processing/jobs/migrate_job.c
+++ b/src/libcharon/processing/jobs/migrate_job.c
@@ -70,29 +70,34 @@ METHOD(job_t, destroy, void,
METHOD(job_t, execute, job_requeue_t,
private_migrate_job_t *this)
{
- ike_sa_t *ike_sa = NULL;
+ enumerator_t *ike_sas, *children;
+ ike_sa_t *ike_sa;
- if (this->reqid)
+ ike_sas = charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager,
+ TRUE);
+ while (ike_sas->enumerate(ike_sas, &ike_sa))
{
- ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
- this->reqid, TRUE);
- }
- if (ike_sa)
- {
- enumerator_t *children, *enumerator;
- child_sa_t *child_sa;
- host_t *host;
+ child_sa_t *current, *child_sa = NULL;
linked_list_t *vips;
+ status_t status;
+ host_t *host;
children = ike_sa->create_child_sa_enumerator(ike_sa);
- while (children->enumerate(children, (void**)&child_sa))
+ while (children->enumerate(children, &current))
{
- if (child_sa->get_reqid(child_sa) == this->reqid)
+ if (current->get_reqid(current) == this->reqid)
{
+ child_sa = current;
break;
}
}
children->destroy(children);
+
+ if (!child_sa)
+ {
+ continue;
+ }
+
DBG2(DBG_JOB, "found CHILD_SA with reqid {%d}", this->reqid);
ike_sa->set_kmaddress(ike_sa, this->local, this->remote);
@@ -105,27 +110,28 @@ METHOD(job_t, execute, job_requeue_t,
host->set_port(host, IKEV2_UDP_PORT);
ike_sa->set_other_host(ike_sa, host);
- vips = linked_list_create();
- enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
- while (enumerator->enumerate(enumerator, &host))
- {
- vips->insert_last(vips, host);
- }
- enumerator->destroy(enumerator);
+ vips = linked_list_create_from_enumerator(
+ ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE));
- if (child_sa->update(child_sa, this->local, this->remote, vips,
- ike_sa->has_condition(ike_sa, COND_NAT_ANY)) == NOT_SUPPORTED)
+ status = child_sa->update(child_sa, this->local, this->remote, vips,
+ ike_sa->has_condition(ike_sa, COND_NAT_ANY));
+ switch (status)
{
- ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa),
- child_sa->get_spi(child_sa, TRUE));
+ case NOT_SUPPORTED:
+ ike_sa->rekey_child_sa(ike_sa, child_sa->get_protocol(child_sa),
+ child_sa->get_spi(child_sa, TRUE));
+ break;
+ case SUCCESS:
+ charon->child_sa_manager->remove(charon->child_sa_manager,
+ child_sa);
+ charon->child_sa_manager->add(charon->child_sa_manager,
+ child_sa, ike_sa);
+ default:
+ break;
}
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
vips->destroy(vips);
}
- else
- {
- DBG1(DBG_JOB, "no CHILD_SA found with reqid {%d}", this->reqid);
- }
+ ike_sas->destroy(ike_sas);
return JOB_REQUEUE_NONE;
}
diff --git a/src/libcharon/processing/jobs/migrate_job.h b/src/libcharon/processing/jobs/migrate_job.h
index 30c0ad0ac..0f2b9aaad 100644
--- a/src/libcharon/processing/jobs/migrate_job.h
+++ b/src/libcharon/processing/jobs/migrate_job.h
@@ -46,7 +46,7 @@ struct migrate_job_t {
*
* We use the reqid or the traffic selectors to find a matching CHILD_SA.
*
- * @param reqid reqid of the CHILD_SA to acquire
+ * @param reqid reqid of the CHILD_SA to migrate
* @param src_ts source traffic selector to be used in the policy
* @param dst_ts destination traffic selector to be used in the policy
* @param dir direction of the policy (in|out)
diff --git a/src/libcharon/processing/jobs/rekey_child_sa_job.c b/src/libcharon/processing/jobs/rekey_child_sa_job.c
index 1bf8dc0cb..8f17d39ab 100644
--- a/src/libcharon/processing/jobs/rekey_child_sa_job.c
+++ b/src/libcharon/processing/jobs/rekey_child_sa_job.c
@@ -24,17 +24,13 @@ typedef struct private_rekey_child_sa_job_t private_rekey_child_sa_job_t;
* Private data of an rekey_child_sa_job_t object.
*/
struct private_rekey_child_sa_job_t {
+
/**
* Public rekey_child_sa_job_t interface.
*/
rekey_child_sa_job_t public;
/**
- * reqid of the child to rekey
- */
- u_int32_t reqid;
-
- /**
* protocol of the CHILD_SA (ESP/AH)
*/
protocol_id_t protocol;
@@ -43,11 +39,17 @@ struct private_rekey_child_sa_job_t {
* inbound SPI of the CHILD_SA
*/
u_int32_t spi;
+
+ /**
+ * SA destination address
+ */
+ host_t *dst;
};
METHOD(job_t, destroy, void,
private_rekey_child_sa_job_t *this)
{
+ this->dst->destroy(this->dst);
free(this);
}
@@ -56,12 +58,12 @@ METHOD(job_t, execute, job_requeue_t,
{
ike_sa_t *ike_sa;
- ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
- this->reqid, TRUE);
+ ike_sa = charon->child_sa_manager->checkout(charon->child_sa_manager,
+ this->protocol, this->spi, this->dst, NULL);
if (ike_sa == NULL)
{
- DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for rekeying",
- this->reqid);
+ DBG1(DBG_JOB, "CHILD_SA %N/0x%08x/%H not found for rekey",
+ protocol_id_names, this->protocol, htonl(this->spi), this->dst);
}
else
{
@@ -80,9 +82,8 @@ METHOD(job_t, get_priority, job_priority_t,
/*
* Described in header
*/
-rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid,
- protocol_id_t protocol,
- u_int32_t spi)
+rekey_child_sa_job_t *rekey_child_sa_job_create(protocol_id_t protocol,
+ u_int32_t spi, host_t *dst)
{
private_rekey_child_sa_job_t *this;
@@ -94,9 +95,9 @@ rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid,
.destroy = _destroy,
},
},
- .reqid = reqid,
.protocol = protocol,
.spi = spi,
+ .dst = dst->clone(dst),
);
return &this->public;
diff --git a/src/libcharon/processing/jobs/rekey_child_sa_job.h b/src/libcharon/processing/jobs/rekey_child_sa_job.h
index fcbe65a06..364bb5ae7 100644
--- a/src/libcharon/processing/jobs/rekey_child_sa_job.h
+++ b/src/libcharon/processing/jobs/rekey_child_sa_job.h
@@ -43,15 +43,11 @@ struct rekey_child_sa_job_t {
/**
* Creates a job of type REKEY_CHILD_SA.
*
- * The CHILD_SA is identified by its protocol (AH/ESP) and its
- * inbound SPI.
- *
- * @param reqid reqid of the CHILD_SA to rekey
* @param protocol protocol of the CHILD_SA
* @param spi security parameter index of the CHILD_SA
+ * @param dst SA destination address
* @return rekey_child_sa_job_t object
*/
-rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid,
- protocol_id_t protocol,
- u_int32_t spi);
+rekey_child_sa_job_t *rekey_child_sa_job_create(protocol_id_t protocol,
+ u_int32_t spi, host_t *dst);
#endif /** REKEY_CHILD_SA_JOB_H_ @}*/
diff --git a/src/libcharon/processing/jobs/update_sa_job.c b/src/libcharon/processing/jobs/update_sa_job.c
index e6d7da2c6..862506d90 100644
--- a/src/libcharon/processing/jobs/update_sa_job.c
+++ b/src/libcharon/processing/jobs/update_sa_job.c
@@ -27,15 +27,26 @@ typedef struct private_update_sa_job_t private_update_sa_job_t;
* Private data of an update_sa_job_t Object
*/
struct private_update_sa_job_t {
+
/**
* public update_sa_job_t interface
*/
update_sa_job_t public;
/**
- * reqid of the CHILD_SA
+ * protocol of the CHILD_SA (ESP/AH)
+ */
+ protocol_id_t protocol;
+
+ /**
+ * SPI of the CHILD_SA
*/
- u_int32_t reqid;
+ u_int32_t spi;
+
+ /**
+ * Old SA destination address
+ */
+ host_t *dst;
/**
* New SA address and port
@@ -46,6 +57,7 @@ struct private_update_sa_job_t {
METHOD(job_t, destroy, void,
private_update_sa_job_t *this)
{
+ this->dst->destroy(this->dst);
this->new->destroy(this->new);
free(this);
}
@@ -55,11 +67,12 @@ METHOD(job_t, execute, job_requeue_t,
{
ike_sa_t *ike_sa;
- ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
- this->reqid, TRUE);
+ ike_sa = charon->child_sa_manager->checkout(charon->child_sa_manager,
+ this->protocol, this->spi, this->dst, NULL);
if (ike_sa == NULL)
{
- DBG1(DBG_JOB, "CHILD_SA with reqid %d not found for update", this->reqid);
+ DBG1(DBG_JOB, "CHILD_SA %N/0x%08x/%H not found for update",
+ protocol_id_names, this->protocol, htonl(this->spi), this->dst);
}
else
{
@@ -78,7 +91,8 @@ METHOD(job_t, get_priority, job_priority_t,
/*
* Described in header
*/
-update_sa_job_t *update_sa_job_create(u_int32_t reqid, host_t *new)
+update_sa_job_t *update_sa_job_create(protocol_id_t protocol,
+ u_int32_t spi, host_t *dst, host_t *new)
{
private_update_sa_job_t *this;
@@ -90,10 +104,11 @@ update_sa_job_t *update_sa_job_create(u_int32_t reqid, host_t *new)
.destroy = _destroy,
},
},
- .reqid = reqid,
- .new = new,
+ .protocol = protocol,
+ .spi = spi,
+ .dst = dst->clone(dst),
+ .new = new->clone(new),
);
return &this->public;
}
-
diff --git a/src/libcharon/processing/jobs/update_sa_job.h b/src/libcharon/processing/jobs/update_sa_job.h
index 55a3df83e..9c19f5b6e 100644
--- a/src/libcharon/processing/jobs/update_sa_job.h
+++ b/src/libcharon/processing/jobs/update_sa_job.h
@@ -26,6 +26,7 @@ typedef struct update_sa_job_t update_sa_job_t;
#include <library.h>
#include <networking/host.h>
#include <processing/jobs/job.h>
+#include <config/proposal.h>
/**
* Update the addresses of an IKE and its CHILD_SAs.
@@ -41,10 +42,13 @@ struct update_sa_job_t {
/**
* Creates a job to update IKE and CHILD_SA addresses.
*
- * @param reqid reqid of the CHILD_SA
+ * @param protocol IPsec protocol of SA to update
+ * @param spi SPI of SA to update
+ * @param dst old destination host of SA to update
* @param new new address and port
* @return update_sa_job_t object
*/
-update_sa_job_t *update_sa_job_create(u_int32_t reqid, host_t *new);
+update_sa_job_t *update_sa_job_create(protocol_id_t protocol,
+ u_int32_t spi, host_t *dst, host_t *new);
#endif /** UPDATE_SA_JOB_H_ @}*/
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 66be5fe61..fdeb605ee 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -101,6 +101,16 @@ struct private_child_sa_t {
u_int32_t reqid;
/**
+ * Did we allocate/confirm and must release the reqid?
+ */
+ bool reqid_allocated;
+
+ /*
+ * Unique CHILD_SA identifier
+ */
+ u_int32_t unique_id;
+
+ /**
* inbound mark used for this child_sa
*/
mark_t mark_in;
@@ -229,6 +239,12 @@ METHOD(child_sa_t, get_reqid, u_int32_t,
return this->reqid;
}
+METHOD(child_sa_t, get_unique_id, u_int32_t,
+ private_child_sa_t *this)
+{
+ return this->unique_id;
+}
+
METHOD(child_sa_t, get_config, child_cfg_t*,
private_child_sa_t *this)
{
@@ -603,7 +619,7 @@ METHOD(child_sa_t, alloc_spi, u_int32_t,
{
if (hydra->kernel_interface->get_spi(hydra->kernel_interface,
this->other_addr, this->my_addr,
- proto_ike2ip(protocol), this->reqid,
+ proto_ike2ip(protocol),
&this->my_spi) == SUCCESS)
{
/* if we allocate a SPI, but then are unable to establish the SA, we
@@ -619,7 +635,7 @@ METHOD(child_sa_t, alloc_cpi, u_int16_t,
{
if (hydra->kernel_interface->get_cpi(hydra->kernel_interface,
this->other_addr, this->my_addr,
- this->reqid, &this->my_cpi) == SUCCESS)
+ &this->my_cpi) == SUCCESS)
{
return this->my_cpi;
}
@@ -633,13 +649,12 @@ METHOD(child_sa_t, install, status_t,
{
u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
u_int16_t esn = NO_EXT_SEQ_NUMBERS;
- traffic_selector_t *src_ts = NULL, *dst_ts = NULL;
+ linked_list_t *src_ts = NULL, *dst_ts = NULL;
time_t now;
lifetime_cfg_t *lifetime;
u_int32_t tfc = 0;
host_t *src, *dst;
status_t status;
- bool update = FALSE;
/* now we have to decide which spi to use. Use self allocated, if "in",
* or the one in the proposal, if not "in" (others). Additionally,
@@ -648,10 +663,6 @@ METHOD(child_sa_t, install, status_t,
{
dst = this->my_addr;
src = this->other_addr;
- if (this->my_spi == spi)
- { /* alloc_spi has been called, do an SA update */
- update = TRUE;
- }
this->my_spi = spi;
this->my_cpi = cpi;
}
@@ -681,6 +692,18 @@ METHOD(child_sa_t, install, status_t,
this->proposal->get_algorithm(this->proposal, EXTENDED_SEQUENCE_NUMBERS,
&esn, NULL);
+ if (!this->reqid_allocated)
+ {
+ status = hydra->kernel_interface->alloc_reqid(hydra->kernel_interface,
+ my_ts, other_ts, this->mark_in, this->mark_out,
+ &this->reqid);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ this->reqid_allocated = TRUE;
+ }
+
lifetime = this->config->get_lifetime(this->config);
now = time_monotonic(NULL);
@@ -705,18 +728,16 @@ METHOD(child_sa_t, install, status_t,
lifetime->time.rekey = 0;
}
- /* BEET requires the bound address from the traffic selectors.
- * TODO: We add just the first traffic selector for now, as the
- * kernel accepts a single TS per SA only */
+ /* BEET requires the bound address from the traffic selectors */
if (inbound)
{
- my_ts->get_first(my_ts, (void**)&dst_ts);
- other_ts->get_first(other_ts, (void**)&src_ts);
+ dst_ts = my_ts;
+ src_ts = other_ts;
}
else
{
- my_ts->get_first(my_ts, (void**)&src_ts);
- other_ts->get_first(other_ts, (void**)&dst_ts);
+ src_ts = my_ts;
+ dst_ts = other_ts;
}
status = hydra->kernel_interface->add_sa(hydra->kernel_interface,
@@ -724,7 +745,7 @@ METHOD(child_sa_t, install, status_t,
inbound ? this->mark_in : this->mark_out, tfc,
lifetime, enc_alg, encr, int_alg, integ, this->mode,
this->ipcomp, cpi, this->config->get_replay_window(this->config),
- initiator, this->encap, esn, update, src_ts, dst_ts);
+ initiator, this->encap, esn, inbound, src_ts, dst_ts);
free(lifetime);
@@ -799,6 +820,19 @@ METHOD(child_sa_t, add_policies, status_t,
traffic_selector_t *my_ts, *other_ts;
status_t status = SUCCESS;
+ if (!this->reqid_allocated)
+ {
+ /* trap policy, get or confirm reqid */
+ status = hydra->kernel_interface->alloc_reqid(
+ hydra->kernel_interface, my_ts_list, other_ts_list,
+ this->mark_in, this->mark_out, &this->reqid);
+ if (status != SUCCESS)
+ {
+ return status;
+ }
+ this->reqid_allocated = TRUE;
+ }
+
/* apply traffic selectors */
enumerator = my_ts_list->create_enumerator(my_ts_list);
while (enumerator->enumerate(enumerator, &my_ts))
@@ -806,12 +840,15 @@ METHOD(child_sa_t, add_policies, status_t,
array_insert(this->my_ts, ARRAY_TAIL, my_ts->clone(my_ts));
}
enumerator->destroy(enumerator);
+ array_sort(this->my_ts, (void*)traffic_selector_cmp, NULL);
+
enumerator = other_ts_list->create_enumerator(other_ts_list);
while (enumerator->enumerate(enumerator, &other_ts))
{
array_insert(this->other_ts, ARRAY_TAIL, other_ts->clone(other_ts));
}
enumerator->destroy(enumerator);
+ array_sort(this->other_ts, (void*)traffic_selector_cmp, NULL);
if (this->config->install_policy(this->config))
{
@@ -1104,6 +1141,15 @@ METHOD(child_sa_t, destroy, void,
enumerator->destroy(enumerator);
}
+ if (this->reqid_allocated)
+ {
+ if (hydra->kernel_interface->release_reqid(hydra->kernel_interface,
+ this->reqid, this->mark_in, this->mark_out) != SUCCESS)
+ {
+ DBG1(DBG_CHD, "releasing reqid %u failed", this->reqid);
+ }
+ }
+
array_destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
array_destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
this->my_addr->destroy(this->my_addr);
@@ -1152,15 +1198,17 @@ static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local)
* Described in header.
*/
child_sa_t * child_sa_create(host_t *me, host_t* other,
- child_cfg_t *config, u_int32_t rekey, bool encap)
+ child_cfg_t *config, u_int32_t rekey, bool encap,
+ u_int mark_in, u_int mark_out)
{
- static refcount_t reqid = 0;
private_child_sa_t *this;
+ static refcount_t unique_id = 0, unique_mark = 0, mark;
INIT(this,
.public = {
.get_name = _get_name,
.get_reqid = _get_reqid,
+ .get_unique_id = _get_unique_id,
.get_config = _get_config,
.get_state = _get_state,
.set_state = _set_state,
@@ -1202,6 +1250,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
.close_action = config->get_close_action(config),
.dpd_action = config->get_dpd_action(config),
.reqid = config->get_reqid(config),
+ .unique_id = ref_get(&unique_id),
.mark_in = config->get_mark(config, TRUE),
.mark_out = config->get_mark(config, FALSE),
.install_time = time_monotonic(NULL),
@@ -1210,9 +1259,37 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->config = config;
config->get_ref(config);
+ if (mark_in)
+ {
+ this->mark_in.value = mark_in;
+ }
+ if (mark_out)
+ {
+ this->mark_out.value = mark_out;
+ }
+ if (this->mark_in.value == MARK_UNIQUE ||
+ this->mark_out.value == MARK_UNIQUE)
+ {
+ mark = ref_get(&unique_mark);
+ if (this->mark_in.value == MARK_UNIQUE)
+ {
+ this->mark_in.value = mark;
+ }
+ if (this->mark_out.value == MARK_UNIQUE)
+ {
+ this->mark_out.value = mark;
+ }
+ }
+
if (!this->reqid)
{
- /* reuse old reqid if we are rekeying an existing CHILD_SA */
+ /* reuse old reqid if we are rekeying an existing CHILD_SA. While the
+ * reqid cache would find the same reqid for our selectors, this does
+ * not work in a special case: If an SA is triggered by a trap policy,
+ * but the negotiated SA gets narrowed, we still must reuse the same
+ * reqid to succesfully "trigger" the SA on the kernel level. Rekeying
+ * such an SA requires an explicit reqid, as the cache currently knows
+ * the original selectors only for that reqid. */
if (rekey)
{
this->reqid = rekey;
@@ -1220,22 +1297,9 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
else
{
this->reqid = charon->traps->find_reqid(charon->traps, config);
- if (!this->reqid)
- {
- this->reqid = ref_get(&reqid);
- }
}
}
- if (this->mark_in.value == MARK_REQID)
- {
- this->mark_in.value = this->reqid;
- }
- if (this->mark_out.value == MARK_REQID)
- {
- this->mark_out.value = this->reqid;
- }
-
/* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
if (config->get_mode(config) == MODE_TRANSPORT &&
config->use_proxy_mode(config))
diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h
index 30a0edf42..83b8c096c 100644
--- a/src/libcharon/sa/child_sa.h
+++ b/src/libcharon/sa/child_sa.h
@@ -126,6 +126,16 @@ struct child_sa_t {
u_int32_t (*get_reqid)(child_sa_t *this);
/**
+ * Get the unique numerical identifier for this CHILD_SA.
+ *
+ * While the same reqid might be shared between multiple SAs, the unique_id
+ * is truly unique for all CHILD_SA instances.
+ *
+ * @return unique CHILD_SA identifier
+ */
+ u_int32_t (*get_unique_id)(child_sa_t *this);
+
+ /**
* Get the config used to set up this child sa.
*
* @return child_cfg
@@ -384,9 +394,12 @@ struct child_sa_t {
* @param config config to use for this CHILD_SA
* @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise
* @param encap TRUE to enable UDP encapsulation (NAT traversal)
+ * @param mark_in explicit inbound mark value to use, 0 for config
+ * @param mark_out explicit outbound mark value to use, 0 for config
* @return child_sa_t object
*/
child_sa_t * child_sa_create(host_t *me, host_t *other, child_cfg_t *config,
- u_int32_t reqid, bool encap);
+ u_int32_t reqid, bool encap,
+ u_int mark_in, u_int mark_out);
#endif /** CHILD_SA_H_ @}*/
diff --git a/src/libcharon/sa/child_sa_manager.c b/src/libcharon/sa/child_sa_manager.c
new file mode 100644
index 000000000..071a119da
--- /dev/null
+++ b/src/libcharon/sa/child_sa_manager.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "child_sa_manager.h"
+
+#include <daemon.h>
+#include <threading/mutex.h>
+#include <collections/hashtable.h>
+
+typedef struct private_child_sa_manager_t private_child_sa_manager_t;
+
+/**
+ * Private data of an child_sa_manager_t object.
+ */
+struct private_child_sa_manager_t {
+
+ /**
+ * Public child_sa_manager_t interface.
+ */
+ child_sa_manager_t public;
+
+ /**
+ * CHILD_SAs by inbound SPI/dst, child_entry_t => child_entry_t
+ */
+ hashtable_t *in;
+
+ /**
+ * CHILD_SAs by outbound SPI/dst, child_entry_t => child_entry_t
+ */
+ hashtable_t *out;
+
+ /**
+ * CHILD_SAs by unique ID, child_entry_t => child_entry_t
+ */
+ hashtable_t *ids;
+
+ /**
+ * Mutex to access any hashtable
+ */
+ mutex_t *mutex;
+};
+
+/**
+ * Hashtable entry for a known CHILD_SA
+ */
+typedef struct {
+ /** the associated IKE_SA */
+ ike_sa_id_t *ike_id;
+ /** unique CHILD_SA identifier */
+ u_int32_t unique_id;
+ /** inbound SPI */
+ u_int32_t spi_in;
+ /** outbound SPI */
+ u_int32_t spi_out;
+ /** inbound host address */
+ host_t *host_in;
+ /** outbound host address and port */
+ host_t *host_out;
+ /** IPsec protocol, AH|ESP */
+ protocol_id_t proto;
+} child_entry_t;
+
+/**
+ * Destroy a CHILD_SA entry
+ */
+static void child_entry_destroy(child_entry_t *entry)
+{
+ entry->ike_id->destroy(entry->ike_id);
+ entry->host_in->destroy(entry->host_in);
+ entry->host_out->destroy(entry->host_out);
+ free(entry);
+}
+
+/**
+ * Hashtable hash function for inbound SAs
+ */
+static u_int hash_in(child_entry_t *entry)
+{
+ return chunk_hash_inc(chunk_from_thing(entry->spi_in),
+ chunk_hash_inc(entry->host_in->get_address(entry->host_in),
+ chunk_hash(chunk_from_thing(entry->proto))));
+}
+
+/**
+ * Hashtable equals function for inbound SAs
+ */
+static bool equals_in(child_entry_t *a, child_entry_t *b)
+{
+ return a->spi_in == b->spi_in &&
+ a->proto == b->proto &&
+ a->host_in->ip_equals(a->host_in, b->host_in);
+}
+
+/**
+ * Hashtable hash function for outbound SAs
+ */
+static u_int hash_out(child_entry_t *entry)
+{
+ return chunk_hash_inc(chunk_from_thing(entry->spi_out),
+ chunk_hash_inc(entry->host_out->get_address(entry->host_out),
+ chunk_hash(chunk_from_thing(entry->proto))));
+}
+
+/**
+ * Hashtable equals function for outbound SAs
+ */
+static bool equals_out(child_entry_t *a, child_entry_t *b)
+{
+ return a->spi_out == b->spi_out &&
+ a->proto == b->proto &&
+ a->host_out->ip_equals(a->host_out, b->host_out);
+}
+
+/**
+ * Hashtable hash function for SAs by unique ID
+ */
+static u_int hash_id(child_entry_t *entry)
+{
+ return chunk_hash(chunk_from_thing(entry->unique_id));
+}
+
+/**
+ * Hashtable equals function for SAs by unique ID
+ */
+static bool equals_id(child_entry_t *a, child_entry_t *b)
+{
+ return a->unique_id == b->unique_id;
+}
+
+METHOD(child_sa_manager_t, add, void,
+ private_child_sa_manager_t *this, child_sa_t *child_sa, ike_sa_t *ike_sa)
+{
+ child_entry_t *entry;
+ host_t *in, *out;
+ ike_sa_id_t *id;
+
+ id = ike_sa->get_id(ike_sa);
+ in = ike_sa->get_my_host(ike_sa);
+ out = ike_sa->get_other_host(ike_sa);
+
+ INIT(entry,
+ .ike_id = id->clone(id),
+ .unique_id = child_sa->get_unique_id(child_sa),
+ .proto = child_sa->get_protocol(child_sa),
+ .spi_in = child_sa->get_spi(child_sa, TRUE),
+ .spi_out = child_sa->get_spi(child_sa, FALSE),
+ .host_in = in->clone(in),
+ .host_out = out->clone(out),
+ );
+
+ this->mutex->lock(this->mutex);
+ if (!this->in->get(this->in, entry) &&
+ !this->out->get(this->out, entry))
+ {
+ this->in->put(this->in, entry, entry);
+ this->out->put(this->out, entry, entry);
+ entry = this->ids->put(this->ids, entry, entry);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (entry)
+ {
+ child_entry_destroy(entry);
+ }
+}
+
+METHOD(child_sa_manager_t, remove_, void,
+ private_child_sa_manager_t *this, child_sa_t *child_sa)
+{
+ child_entry_t *entry, key = {
+ .unique_id = child_sa->get_unique_id(child_sa),
+ };
+
+ this->mutex->lock(this->mutex);
+ entry = this->ids->remove(this->ids, &key);
+ if (entry)
+ {
+ this->in->remove(this->in, entry);
+ this->out->remove(this->out, entry);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (entry)
+ {
+ child_entry_destroy(entry);
+ }
+}
+
+/**
+ * Check out an IKE_SA for a given CHILD_SA
+ */
+static ike_sa_t *checkout_ikesa(private_child_sa_manager_t *this,
+ ike_sa_id_t *id, u_int32_t unique_id, child_sa_t **child_sa)
+{
+ enumerator_t *enumerator;
+ child_sa_t *current;
+ ike_sa_t *ike_sa;
+ bool found = FALSE;
+
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
+ id->destroy(id);
+ if (ike_sa)
+ {
+ enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ found = current->get_unique_id(current) == unique_id;
+ if (found)
+ {
+ if (child_sa)
+ {
+ *child_sa = current;
+ }
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (found)
+ {
+ return ike_sa;
+ }
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ return NULL;
+}
+
+METHOD(child_sa_manager_t, checkout_by_id, ike_sa_t*,
+ private_child_sa_manager_t *this, u_int32_t unique_id,
+ child_sa_t **child_sa)
+{
+ ike_sa_id_t *id;
+ child_entry_t *entry, key = {
+ .unique_id = unique_id,
+ };
+
+ this->mutex->lock(this->mutex);
+ entry = this->ids->get(this->ids, &key);
+ if (entry)
+ {
+ id = entry->ike_id->clone(entry->ike_id);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (entry)
+ {
+ return checkout_ikesa(this, id, unique_id, child_sa);
+ }
+ return NULL;
+}
+
+METHOD(child_sa_manager_t, checkout, ike_sa_t*,
+ private_child_sa_manager_t *this, protocol_id_t protocol, u_int32_t spi,
+ host_t *dst, child_sa_t **child_sa)
+{
+ ike_sa_id_t *id;
+ u_int32_t unique_id;
+ child_entry_t *entry, key = {
+ .spi_in = spi,
+ .spi_out = spi,
+ .host_in = dst,
+ .host_out = dst,
+ .proto = protocol,
+ };
+
+ this->mutex->lock(this->mutex);
+ entry = this->in->get(this->in, &key);
+ if (!entry)
+ {
+ entry = this->out->get(this->out, &key);
+ }
+ if (entry)
+ {
+ unique_id = entry->unique_id;
+ id = entry->ike_id->clone(entry->ike_id);
+ }
+ this->mutex->unlock(this->mutex);
+
+ if (entry)
+ {
+ return checkout_ikesa(this, id, unique_id, child_sa);
+ }
+ return NULL;
+}
+
+METHOD(child_sa_manager_t, destroy, void,
+ private_child_sa_manager_t *this)
+{
+ this->in->destroy(this->in);
+ this->out->destroy(this->out);
+ this->ids->destroy(this->ids);
+ this->mutex->destroy(this->mutex);
+ free(this);
+}
+
+/**
+ * See header
+ */
+child_sa_manager_t *child_sa_manager_create()
+{
+ private_child_sa_manager_t *this;
+
+ INIT(this,
+ .public = {
+ .add = _add,
+ .remove = _remove_,
+ .checkout = _checkout,
+ .checkout_by_id = _checkout_by_id,
+ .destroy = _destroy,
+ },
+ .in = hashtable_create((hashtable_hash_t)hash_in,
+ (hashtable_equals_t)equals_in, 8),
+ .out = hashtable_create((hashtable_hash_t)hash_out,
+ (hashtable_equals_t)equals_out, 8),
+ .ids = hashtable_create((hashtable_hash_t)hash_id,
+ (hashtable_equals_t)equals_id, 8),
+ .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ );
+
+ return &this->public;
+}
diff --git a/src/libcharon/sa/child_sa_manager.h b/src/libcharon/sa/child_sa_manager.h
new file mode 100644
index 000000000..4d57528e8
--- /dev/null
+++ b/src/libcharon/sa/child_sa_manager.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 Martin Willi
+ * Copyright (C) 2014 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup child_sa_manager child_sa_manager
+ * @{ @ingroup sa
+ */
+
+#ifndef CHILD_SA_MANAGER_H_
+#define CHILD_SA_MANAGER_H_
+
+#include <sa/ike_sa.h>
+#include <sa/child_sa.h>
+
+typedef struct child_sa_manager_t child_sa_manager_t;
+
+/**
+ * Handle CHILD_SA to IKE_SA relations
+ */
+struct child_sa_manager_t {
+
+ /**
+ * Register a CHILD_SA/IKE_SA relation.
+ *
+ * @param child_sa CHILD_SA to register
+ * @param ike_sa IKE_SA owning the CHILD_SA
+ */
+ void (*add)(child_sa_manager_t *this, child_sa_t *child_sa, ike_sa_t *ike_sa);
+
+ /**
+ * Unregister a CHILD_SA/IKE_SA relation.
+ *
+ * @param child_sa CHILD_SA to unregister
+ */
+ void (*remove)(child_sa_manager_t *this, child_sa_t *child_sa);
+
+ /**
+ * Find a CHILD_SA and check out the associated IKE_SA by SPI.
+ *
+ * On success, the returned IKE_SA must be checked in after use to
+ * the IKE_SA manager.
+ *
+ * @param protocol IPsec protocol, AH|ESP
+ * @param spi SPI of CHILD_SA to check out
+ * @param dst SA destination host related to SPI
+ * @param child_sa returns CHILD_SA managed by IKE_SA
+ * @return IKE_SA, NULL if not found
+ */
+ ike_sa_t *(*checkout)(child_sa_manager_t *this,
+ protocol_id_t protocol, u_int32_t spi, host_t *dst,
+ child_sa_t **child_sa);
+
+ /**
+ * Find a CHILD_SA and check out the associated IKE_SA by unique_id.
+ *
+ * On success, the returned IKE_SA must be checked in after use to
+ * the IKE_SA manager.
+ *
+ * @param unique_id unique ID of CHILD_SA to check out
+ * @param child_sa returns CHILD_SA managed by IKE_SA
+ * @return IKE_SA, NULL if not found
+ */
+ ike_sa_t *(*checkout_by_id)(child_sa_manager_t *this, u_int32_t unique_id,
+ child_sa_t **child_sa);
+
+ /**
+ * Destroy a child_sa_manager_t.
+ */
+ void (*destroy)(child_sa_manager_t *this);
+};
+
+/**
+ * Create a child_sa_manager instance.
+ */
+child_sa_manager_t *child_sa_manager_create();
+
+#endif /** CHILD_SA_MANAGER_H_ @}*/
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index d92b9df8e..54f22e61e 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -964,6 +964,10 @@ METHOD(ike_sa_t, update_hosts, void,
enumerator = array_create_enumerator(this->child_sas);
while (enumerator->enumerate(enumerator, &child_sa))
{
+ charon->child_sa_manager->remove(charon->child_sa_manager, child_sa);
+ charon->child_sa_manager->add(charon->child_sa_manager,
+ child_sa, &this->public);
+
if (child_sa->update(child_sa, this->my_host, this->other_host,
vips, has_condition(this, COND_NAT_ANY)) == NOT_SUPPORTED)
{
@@ -971,6 +975,7 @@ METHOD(ike_sa_t, update_hosts, void,
child_sa->get_protocol(child_sa),
child_sa->get_spi(child_sa, TRUE));
}
+
}
enumerator->destroy(enumerator);
@@ -1444,6 +1449,8 @@ METHOD(ike_sa_t, add_child_sa, void,
private_ike_sa_t *this, child_sa_t *child_sa)
{
array_insert_create(&this->child_sas, ARRAY_TAIL, child_sa);
+ charon->child_sa_manager->add(charon->child_sa_manager,
+ child_sa, &this->public);
}
METHOD(ike_sa_t, get_child_sa, child_sa_t*,
@@ -1471,16 +1478,58 @@ METHOD(ike_sa_t, get_child_count, int,
return array_count(this->child_sas);
}
+/**
+ * Private data of a create_child_sa_enumerator()
+ */
+typedef struct {
+ /** implements enumerator */
+ enumerator_t public;
+ /** inner array enumerator */
+ enumerator_t *inner;
+ /** current item */
+ child_sa_t *current;
+} child_enumerator_t;
+
+METHOD(enumerator_t, child_enumerate, bool,
+ child_enumerator_t *this, child_sa_t **child_sa)
+{
+ if (this->inner->enumerate(this->inner, &this->current))
+ {
+ *child_sa = this->current;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, child_enumerator_destroy, void,
+ child_enumerator_t *this)
+{
+ this->inner->destroy(this->inner);
+ free(this);
+}
+
METHOD(ike_sa_t, create_child_sa_enumerator, enumerator_t*,
private_ike_sa_t *this)
{
- return array_create_enumerator(this->child_sas);
+ child_enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_child_enumerate,
+ .destroy = _child_enumerator_destroy,
+ },
+ .inner = array_create_enumerator(this->child_sas),
+ );
+ return &enumerator->public;
}
METHOD(ike_sa_t, remove_child_sa, void,
private_ike_sa_t *this, enumerator_t *enumerator)
{
- array_remove_at(this->child_sas, enumerator);
+ child_enumerator_t *ce = (child_enumerator_t*)enumerator;
+
+ charon->child_sa_manager->remove(charon->child_sa_manager, ce->current);
+ array_remove_at(this->child_sas, ce->inner);
}
METHOD(ike_sa_t, rekey_child_sa, status_t,
@@ -1513,13 +1562,13 @@ METHOD(ike_sa_t, destroy_child_sa, status_t,
child_sa_t *child_sa;
status_t status = NOT_FOUND;
- enumerator = array_create_enumerator(this->child_sas);
+ enumerator = create_child_sa_enumerator(this);
while (enumerator->enumerate(enumerator, (void**)&child_sa))
{
if (child_sa->get_protocol(child_sa) == protocol &&
child_sa->get_spi(child_sa, TRUE) == spi)
{
- array_remove_at(this->child_sas, enumerator);
+ remove_child_sa(this, enumerator);
child_sa->destroy(child_sa);
status = SUCCESS;
break;
@@ -1771,7 +1820,7 @@ METHOD(ike_sa_t, reestablish, status_t,
#endif /* ME */
{
/* handle existing CHILD_SAs */
- enumerator = array_create_enumerator(this->child_sas);
+ enumerator = create_child_sa_enumerator(this);
while (enumerator->enumerate(enumerator, (void**)&child_sa))
{
if (has_condition(this, COND_REAUTHENTICATING))
@@ -1780,7 +1829,7 @@ METHOD(ike_sa_t, reestablish, status_t,
{
case CHILD_ROUTED:
{ /* move routed child directly */
- array_remove_at(this->child_sas, enumerator);
+ remove_child_sa(this, enumerator);
new->add_child_sa(new, child_sa);
action = ACTION_NONE;
break;
@@ -2251,7 +2300,8 @@ METHOD(ike_sa_t, inherit_post, void,
/* adopt all children */
while (array_remove(other->child_sas, ARRAY_HEAD, &child_sa))
{
- array_insert_create(&this->child_sas, ARRAY_TAIL, child_sa);
+ charon->child_sa_manager->remove(charon->child_sa_manager, child_sa);
+ add_child_sa(this, child_sa);
}
/* move pending tasks to the new IKE_SA */
@@ -2305,6 +2355,7 @@ METHOD(ike_sa_t, destroy, void,
* routes that the CHILD_SA tries to uninstall. */
while (array_remove(this->child_sas, ARRAY_TAIL, &child_sa))
{
+ charon->child_sa_manager->remove(charon->child_sa_manager, child_sa);
child_sa->destroy(child_sa);
}
while (array_remove(this->my_vips, ARRAY_TAIL, &vip))
diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c
index 144cd7d3f..7ca72f3c1 100644
--- a/src/libcharon/sa/ike_sa_manager.c
+++ b/src/libcharon/sa/ike_sa_manager.c
@@ -1383,54 +1383,35 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
}
METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*,
- private_ike_sa_manager_t *this, u_int32_t id, bool child)
+ private_ike_sa_manager_t *this, u_int32_t id)
{
- enumerator_t *enumerator, *children;
+ enumerator_t *enumerator;
entry_t *entry;
ike_sa_t *ike_sa = NULL;
- child_sa_t *child_sa;
u_int segment;
- DBG2(DBG_MGR, "checkout IKE_SA by ID");
+ DBG2(DBG_MGR, "checkout IKE_SA by ID %u", id);
enumerator = create_table_enumerator(this);
while (enumerator->enumerate(enumerator, &entry, &segment))
{
if (wait_for_entry(this, entry, segment))
{
- /* look for a child with such a reqid ... */
- if (child)
- {
- children = entry->ike_sa->create_child_sa_enumerator(entry->ike_sa);
- while (children->enumerate(children, (void**)&child_sa))
- {
- if (child_sa->get_reqid(child_sa) == id)
- {
- ike_sa = entry->ike_sa;
- break;
- }
- }
- children->destroy(children);
- }
- else /* ... or for a IKE_SA with such a unique id */
- {
- if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
- {
- ike_sa = entry->ike_sa;
- }
- }
- /* got one, return */
- if (ike_sa)
+ if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
{
+ ike_sa = entry->ike_sa;
entry->checked_out = TRUE;
- DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out",
- ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
break;
}
}
}
enumerator->destroy(enumerator);
+ if (ike_sa)
+ {
+ DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out",
+ ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
+ }
charon->bus->set_sa(charon->bus, ike_sa);
return ike_sa;
}
diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h
index a68ae7763..f259d8e56 100644
--- a/src/libcharon/sa/ike_sa_manager.h
+++ b/src/libcharon/sa/ike_sa_manager.h
@@ -129,19 +129,15 @@ struct ike_sa_manager_t {
/**
* Check out an IKE_SA a unique ID.
*
- * Every IKE_SA and every CHILD_SA is uniquely identified by an ID.
- * These checkout function uses, depending
- * on the child parameter, the unique ID of the IKE_SA or the reqid
- * of one of a IKE_SAs CHILD_SA.
+ * Every IKE_SA is uniquely identified by a numerical ID. This checkout
+ * function uses the unique ID of the IKE_SA to check it out.
*
* @param id unique ID of the object
- * @param child TRUE to use CHILD, FALSE to use IKE_SA
* @return
* - checked out IKE_SA, if found
* - NULL, if not found
*/
- ike_sa_t* (*checkout_by_id) (ike_sa_manager_t* this, u_int32_t id,
- bool child);
+ ike_sa_t* (*checkout_by_id) (ike_sa_manager_t* this, u_int32_t id);
/**
* Check out an IKE_SA by the policy/connection name.
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index 0f8e8bc6d..cb22bf606 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -1596,7 +1596,8 @@ static bool is_redundant(private_task_manager_t *this, child_sa_t *child_sa)
child_sa->get_lifetime(child_sa, FALSE))
{
DBG1(DBG_IKE, "deleting redundant CHILD_SA %s{%d}",
- child_sa->get_name(child_sa), child_sa->get_reqid(child_sa));
+ child_sa->get_name(child_sa),
+ child_sa->get_unique_id(child_sa));
redundant = TRUE;
break;
}
@@ -1647,6 +1648,8 @@ METHOD(task_manager_t, queue_child_rekey, void,
task = quick_mode_create(this->ike_sa, cfg->get_ref(cfg),
get_first_ts(child_sa, TRUE), get_first_ts(child_sa, FALSE));
task->use_reqid(task, child_sa->get_reqid(child_sa));
+ task->use_marks(task, child_sa->get_mark(child_sa, TRUE).value,
+ child_sa->get_mark(child_sa, FALSE).value);
task->rekey(task, child_sa->get_spi(child_sa, TRUE));
queue_task(this, &task->task);
diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c
index 499081caa..4206182a0 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_delete.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c
@@ -116,7 +116,7 @@ static bool delete_child(private_quick_delete_t *this, protocol_id_t protocol,
{
DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
- child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
+ child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)),
ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
}
@@ -127,7 +127,7 @@ static bool delete_child(private_quick_delete_t *this, protocol_id_t protocol,
DBG0(DBG_IKE, "closing CHILD_SA %s{%d} 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),
+ child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
my_ts, other_ts);
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 1133aab65..828b166d0 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -156,6 +156,16 @@ struct private_quick_mode_t {
u_int32_t reqid;
/**
+ * Explicit inbound mark value to use, if any
+ */
+ u_int mark_in;
+
+ /**
+ * Explicit inbound mark value to use, if any
+ */
+ u_int mark_out;
+
+ /**
* SPI of SA we rekey
*/
u_int32_t rekey;
@@ -196,8 +206,8 @@ static void schedule_inactivity_timeout(private_quick_mode_t *this)
close_ike = lib->settings->get_bool(lib->settings,
"%s.inactivity_close_ike", FALSE, lib->ns);
lib->scheduler->schedule_job(lib->scheduler, (job_t*)
- inactivity_job_create(this->child_sa->get_reqid(this->child_sa),
- timeout, close_ike), timeout);
+ inactivity_job_create(this->child_sa->get_unique_id(this->child_sa),
+ timeout, close_ike), timeout);
}
}
@@ -375,7 +385,7 @@ static bool install(private_quick_mode_t *this)
DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
this->child_sa->get_name(this->child_sa),
- this->child_sa->get_reqid(this->child_sa),
+ this->child_sa->get_unique_id(this->child_sa),
ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts);
@@ -396,10 +406,7 @@ static bool install(private_quick_mode_t *this)
{
charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
}
- if (!this->rekey)
- {
- schedule_inactivity_timeout(this);
- }
+ schedule_inactivity_timeout(this);
this->child_sa = NULL;
return TRUE;
}
@@ -788,7 +795,8 @@ METHOD(task_t, build_i, status_t,
this->child_sa = child_sa_create(
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
- this->config, this->reqid, this->udp);
+ this->config, this->reqid, this->udp,
+ this->mark_in, this->mark_out);
if (this->udp && this->mode == MODE_TRANSPORT)
{
@@ -972,9 +980,14 @@ static void check_for_rekeyed_child(private_quick_mode_t *this)
{
this->reqid = child_sa->get_reqid(child_sa);
this->rekey = child_sa->get_spi(child_sa, TRUE);
+ this->mark_in = child_sa->get_mark(child_sa,
+ TRUE).value;
+ this->mark_out = child_sa->get_mark(child_sa,
+ FALSE).value;
child_sa->set_state(child_sa, CHILD_REKEYING);
DBG1(DBG_IKE, "detected rekeying of CHILD_SA %s{%u}",
- child_sa->get_name(child_sa), this->reqid);
+ child_sa->get_name(child_sa),
+ child_sa->get_unique_id(child_sa));
}
policies->destroy(policies);
break;
@@ -1097,7 +1110,8 @@ METHOD(task_t, process_r, status_t,
this->child_sa = child_sa_create(
this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa),
- this->config, this->reqid, this->udp);
+ this->config, this->reqid, this->udp,
+ this->mark_in, this->mark_out);
tsi = linked_list_create_with_items(this->tsi, NULL);
tsr = linked_list_create_with_items(this->tsr, NULL);
@@ -1307,6 +1321,13 @@ METHOD(quick_mode_t, use_reqid, void,
this->reqid = reqid;
}
+METHOD(quick_mode_t, use_marks, void,
+ private_quick_mode_t *this, u_int in, u_int out)
+{
+ this->mark_in = in;
+ this->mark_out = out;
+}
+
METHOD(quick_mode_t, rekey, void,
private_quick_mode_t *this, u_int32_t spi)
{
@@ -1334,6 +1355,8 @@ METHOD(task_t, migrate, void,
this->dh = NULL;
this->spi_i = 0;
this->spi_r = 0;
+ this->mark_in = 0;
+ this->mark_out = 0;
if (!this->initiator)
{
@@ -1372,6 +1395,7 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config,
.destroy = _destroy,
},
.use_reqid = _use_reqid,
+ .use_marks = _use_marks,
.rekey = _rekey,
},
.ike_sa = ike_sa,
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.h b/src/libcharon/sa/ikev1/tasks/quick_mode.h
index 0b80cb836..ee9b64d13 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.h
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.h
@@ -45,6 +45,14 @@ struct quick_mode_t {
void (*use_reqid)(quick_mode_t *this, u_int32_t reqid);
/**
+ * Use specific mark values, overriding configuration.
+ *
+ * @param in inbound mark value
+ * @param out outbound mark value
+ */
+ void (*use_marks)(quick_mode_t *this, u_int in, u_int out);
+
+ /**
* Set the SPI of the old SA, if rekeying.
*
* @param spi spi of SA to rekey
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index e7a914875..1bb934002 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -160,6 +160,16 @@ struct private_child_create_t {
u_int32_t reqid;
/**
+ * Explicit inbound mark value
+ */
+ u_int mark_in;
+
+ /**
+ * Explicit outbound mark value
+ */
+ u_int mark_out;
+
+ /**
* CHILD_SA which gets established
*/
child_sa_t *child_sa;
@@ -286,7 +296,7 @@ static bool allocate_spi(private_child_create_t *this)
*/
static void schedule_inactivity_timeout(private_child_create_t *this)
{
- u_int32_t timeout;
+ u_int32_t timeout, id;
bool close_ike;
timeout = this->config->get_inactivity(this->config);
@@ -294,9 +304,9 @@ static void schedule_inactivity_timeout(private_child_create_t *this)
{
close_ike = lib->settings->get_bool(lib->settings,
"%s.inactivity_close_ike", FALSE, lib->ns);
+ id = this->child_sa->get_unique_id(this->child_sa);
lib->scheduler->schedule_job(lib->scheduler, (job_t*)
- inactivity_job_create(this->child_sa->get_reqid(this->child_sa),
- timeout, close_ike), timeout);
+ inactivity_job_create(id, timeout, close_ike), timeout);
}
}
@@ -683,10 +693,7 @@ static status_t select_and_install(private_child_create_t *this,
this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
this->established = TRUE;
- if (!this->rekey)
- { /* a rekeyed SA uses the same reqid, no need for a new job */
- schedule_inactivity_timeout(this);
- }
+ schedule_inactivity_timeout(this);
my_ts = linked_list_create_from_enumerator(
this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
@@ -696,7 +703,7 @@ static status_t select_and_install(private_child_create_t *this,
DBG0(DBG_IKE, "CHILD_SA %s{%d} established "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
this->child_sa->get_name(this->child_sa),
- this->child_sa->get_reqid(this->child_sa),
+ this->child_sa->get_unique_id(this->child_sa),
ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), my_ts, other_ts);
@@ -996,7 +1003,8 @@ METHOD(task_t, build_i, status_t,
this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid,
- this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
+ this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY),
+ this->mark_in, this->mark_out);
if (!allocate_spi(this))
{
@@ -1241,7 +1249,8 @@ METHOD(task_t, build_r, status_t,
this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
this->ike_sa->get_other_host(this->ike_sa), this->config, this->reqid,
- this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
+ this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY),
+ this->mark_in, this->mark_out);
if (this->ipcomp_received != IPCOMP_NONE)
{
@@ -1478,6 +1487,13 @@ METHOD(child_create_t, use_reqid, void,
this->reqid = reqid;
}
+METHOD(child_create_t, use_marks, void,
+ private_child_create_t *this, u_int in, u_int out)
+{
+ this->mark_in = in;
+ this->mark_out = out;
+}
+
METHOD(child_create_t, get_child, child_sa_t*,
private_child_create_t *this)
{
@@ -1545,6 +1561,8 @@ METHOD(task_t, migrate, void,
this->ipcomp_received = IPCOMP_NONE;
this->other_cpi = 0;
this->reqid = 0;
+ this->mark_in = 0;
+ this->mark_out = 0;
this->established = FALSE;
}
@@ -1593,6 +1611,7 @@ child_create_t *child_create_create(ike_sa_t *ike_sa,
.set_config = _set_config,
.get_lower_nonce = _get_lower_nonce,
.use_reqid = _use_reqid,
+ .use_marks = _use_marks,
.task = {
.get_type = _get_type,
.migrate = _migrate,
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.h b/src/libcharon/sa/ikev2/tasks/child_create.h
index d29ba3d98..46d9403ee 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.h
+++ b/src/libcharon/sa/ikev2/tasks/child_create.h
@@ -52,6 +52,14 @@ struct child_create_t {
void (*use_reqid) (child_create_t *this, u_int32_t reqid);
/**
+ * Use specific mark values to override configuration.
+ *
+ * @param in inbound mark value
+ * @param out outbound mark value
+ */
+ void (*use_marks)(child_create_t *this, u_int in, u_int out);
+
+ /**
* Get the lower of the two nonces, used for rekey collisions.
*
* @return lower nonce
diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c
index 2b1697423..f0b11e291 100644
--- a/src/libcharon/sa/ikev2/tasks/child_delete.c
+++ b/src/libcharon/sa/ikev2/tasks/child_delete.c
@@ -267,7 +267,7 @@ static void log_children(private_child_delete_t *this)
{
DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} "
"with SPIs %.8x_i %.8x_o and TS %#R=== %#R",
- child_sa->get_name(child_sa), child_sa->get_reqid(child_sa),
+ child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)),
ntohl(child_sa->get_spi(child_sa, FALSE)), my_ts, other_ts);
}
@@ -278,7 +278,7 @@ static void log_children(private_child_delete_t *this)
DBG0(DBG_IKE, "closing CHILD_SA %s{%d} 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),
+ child_sa->get_name(child_sa), child_sa->get_unique_id(child_sa),
ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in,
ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out,
my_ts, other_ts);
diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c
index db872827d..c806e19ca 100644
--- a/src/libcharon/sa/ikev2/tasks/child_rekey.c
+++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c
@@ -96,9 +96,9 @@ static void schedule_delayed_rekey(private_child_rekey_t *this)
retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
job = (job_t*)rekey_child_sa_job_create(
- this->child_sa->get_reqid(this->child_sa),
this->child_sa->get_protocol(this->child_sa),
- this->child_sa->get_spi(this->child_sa, TRUE));
+ this->child_sa->get_spi(this->child_sa, TRUE),
+ this->ike_sa->get_my_host(this->ike_sa));
DBG1(DBG_IKE, "CHILD_SA rekeying failed, trying again in %d seconds", retry);
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
lib->scheduler->schedule_job(lib->scheduler, job, retry);
@@ -184,6 +184,9 @@ METHOD(task_t, build_i, status_t,
}
reqid = this->child_sa->get_reqid(this->child_sa);
this->child_create->use_reqid(this->child_create, reqid);
+ this->child_create->use_marks(this->child_create,
+ this->child_sa->get_mark(this->child_sa, TRUE).value,
+ this->child_sa->get_mark(this->child_sa, FALSE).value);
if (this->child_create->task.build(&this->child_create->task,
message) != NEED_MORE)
@@ -224,6 +227,9 @@ METHOD(task_t, build_r, status_t,
/* let the CHILD_CREATE task build the response */
reqid = this->child_sa->get_reqid(this->child_sa);
this->child_create->use_reqid(this->child_create, reqid);
+ this->child_create->use_marks(this->child_create,
+ this->child_sa->get_mark(this->child_sa, TRUE).value,
+ this->child_sa->get_mark(this->child_sa, FALSE).value);
config = this->child_sa->get_config(this->child_sa);
this->child_create->set_config(this->child_create, config->get_ref(config));
this->child_create->task.build(&this->child_create->task, message);
diff --git a/src/libcharon/sa/ikev2/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
index d91fa5862..6295d7960 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_mobike.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c
@@ -256,6 +256,7 @@ static void update_children(private_ike_mobike_t *this)
enumerator_t *enumerator;
child_sa_t *child_sa;
linked_list_t *vips;
+ status_t status;
host_t *host;
vips = linked_list_create();
@@ -270,15 +271,25 @@ static void update_children(private_ike_mobike_t *this)
enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
while (enumerator->enumerate(enumerator, (void**)&child_sa))
{
- if (child_sa->update(child_sa,
- this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa), vips,
- this->ike_sa->has_condition(this->ike_sa,
- COND_NAT_ANY)) == NOT_SUPPORTED)
+ status = child_sa->update(child_sa,
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa), vips,
+ this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
+ switch (status)
{
- this->ike_sa->rekey_child_sa(this->ike_sa,
- child_sa->get_protocol(child_sa),
- child_sa->get_spi(child_sa, TRUE));
+ case NOT_SUPPORTED:
+ this->ike_sa->rekey_child_sa(this->ike_sa,
+ child_sa->get_protocol(child_sa),
+ child_sa->get_spi(child_sa, TRUE));
+ break;
+ case SUCCESS:
+ charon->child_sa_manager->remove(charon->child_sa_manager,
+ child_sa);
+ charon->child_sa_manager->add(charon->child_sa_manager,
+ child_sa, this->ike_sa);
+ break;
+ default:
+ break;
}
}
enumerator->destroy(enumerator);
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c
index 7e55d6b0f..534d4d5ff 100644
--- a/src/libcharon/sa/trap_manager.c
+++ b/src/libcharon/sa/trap_manager.c
@@ -171,7 +171,7 @@ METHOD(trap_manager_t, install, u_int32_t,
this->lock->unlock(this->lock);
/* create and route CHILD_SA */
- child_sa = child_sa_create(me, other, child, reqid, FALSE);
+ child_sa = child_sa_create(me, other, child, reqid, FALSE, 0, 0);
list = linked_list_create_with_items(me, NULL);
my_ts = child->get_traffic_selectors(child, TRUE, NULL, list);