summaryrefslogtreecommitdiff
path: root/src/libcharon/sa
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@corsac.net>2017-09-01 17:21:25 +0200
committerYves-Alexis Perez <corsac@corsac.net>2017-09-01 17:21:25 +0200
commit11d6b62db969bdd808d0f56706cb18f113927a31 (patch)
tree8aa7d8fb611c3da6a3523cb78a082f62ffd0dac8 /src/libcharon/sa
parentbba25e2ff6c4a193acb54560ea4417537bd2954e (diff)
downloadvyos-strongswan-11d6b62db969bdd808d0f56706cb18f113927a31.tar.gz
vyos-strongswan-11d6b62db969bdd808d0f56706cb18f113927a31.zip
New upstream version 5.6.0
Diffstat (limited to 'src/libcharon/sa')
-rw-r--r--src/libcharon/sa/child_sa.c143
-rw-r--r--src/libcharon/sa/child_sa.h34
-rw-r--r--src/libcharon/sa/ikev1/task_manager_v1.c6
-rw-r--r--src/libcharon/sa/ikev1/tasks/quick_mode.c7
-rw-r--r--src/libcharon/sa/ikev2/keymat_v2.c7
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_create.c81
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_delete.c1
-rw-r--r--src/libcharon/sa/ikev2/tasks/child_rekey.c62
-rw-r--r--src/libcharon/sa/trap_manager.c59
9 files changed, 277 insertions, 123 deletions
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 3d9f6133b..4133d9182 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -40,10 +40,10 @@ ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
"DESTROYING",
);
-ENUM(child_sa_outbound_state_names, CHILD_OUTBOUND_NONE, CHILD_OUTBOUND_INSTALLED,
- "NONE",
+ENUM_FLAGS(child_sa_outbound_state_names, CHILD_OUTBOUND_REGISTERED, CHILD_OUTBOUND_POLICIES,
"REGISTERED",
- "INSTALLED",
+ "SA",
+ "POLICIES",
);
typedef struct private_child_sa_t private_child_sa_t;
@@ -296,12 +296,15 @@ METHOD(child_sa_t, get_config, child_cfg_t*,
METHOD(child_sa_t, set_state, void,
private_child_sa_t *this, child_sa_state_t state)
{
- DBG2(DBG_CHD, "CHILD_SA %s{%d} state change: %N => %N",
- get_name(this), this->unique_id,
- child_sa_state_names, this->state,
- child_sa_state_names, state);
- charon->bus->child_state_change(charon->bus, &this->public, state);
- this->state = state;
+ if (this->state != state)
+ {
+ DBG2(DBG_CHD, "CHILD_SA %s{%d} state change: %N => %N",
+ get_name(this), this->unique_id,
+ child_sa_state_names, this->state,
+ child_sa_state_names, state);
+ charon->bus->child_state_change(charon->bus, &this->public, state);
+ this->state = state;
+ }
}
METHOD(child_sa_t, get_state, child_sa_state_t,
@@ -547,7 +550,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
}
else
{
- if (this->other_spi && this->outbound_state == CHILD_OUTBOUND_INSTALLED)
+ if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA))
{
kernel_ipsec_sa_id_t id = {
.src = this->my_addr,
@@ -788,7 +791,7 @@ static status_t install_internal(private_child_sa_t *this, chunk_t encr,
{
tfc = this->config->get_tfc(this->config);
}
- this->outbound_state = CHILD_OUTBOUND_INSTALLED;
+ this->outbound_state |= CHILD_OUTBOUND_SA;
}
DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound",
@@ -1188,6 +1191,7 @@ METHOD(child_sa_t, install_policies, status_t,
linked_list_t *my_ts_list, *other_ts_list;
traffic_selector_t *my_ts, *other_ts;
status_t status = SUCCESS;
+ bool install_outbound = FALSE;
if (!this->reqid_allocated && !this->static_reqid)
{
@@ -1207,12 +1211,17 @@ METHOD(child_sa_t, install_policies, status_t,
this->reqid_allocated = TRUE;
}
+ if (!(this->outbound_state & CHILD_OUTBOUND_REGISTERED))
+ {
+ install_outbound = TRUE;
+ this->outbound_state |= CHILD_OUTBOUND_POLICIES;
+ }
+
if (!this->config->has_option(this->config, OPT_NO_POLICIES))
{
policy_priority_t priority;
ipsec_sa_cfg_t my_sa, other_sa;
uint32_t manual_prio;
- bool install_outbound;
prepare_sa_cfg(this, &my_sa, &other_sa);
manual_prio = this->config->get_manual_prio(this->config);
@@ -1222,7 +1231,6 @@ METHOD(child_sa_t, install_policies, status_t,
this->trap = this->state == CHILD_CREATED;
priority = this->trap ? POLICY_PRIORITY_ROUTED
: POLICY_PRIORITY_DEFAULT;
- install_outbound = this->outbound_state != CHILD_OUTBOUND_REGISTERED;
/* enumerate pairs of traffic selectors */
enumerator = create_policy_enumerator(this);
@@ -1250,7 +1258,6 @@ METHOD(child_sa_t, install_policies, status_t,
this->other_addr, my_ts, other_ts,
&my_sa, &other_sa, POLICY_IPSEC,
priority, manual_prio);
-
}
if (status != SUCCESS)
{
@@ -1267,21 +1274,35 @@ METHOD(child_sa_t, install_policies, status_t,
return status;
}
-METHOD(child_sa_t, register_outbound, void,
+METHOD(child_sa_t, register_outbound, status_t,
private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
uint16_t cpi, bool tfcv3)
{
- DBG2(DBG_CHD, "registering outbound %N SA", protocol_id_names,
- this->protocol);
- DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), this->my_addr,
- this->other_addr);
-
- this->other_spi = spi;
- this->other_cpi = cpi;
- this->encr_r = chunk_clone(encr);
- this->integ_r = chunk_clone(integ);
- this->tfcv3 = tfcv3;
- this->outbound_state = CHILD_OUTBOUND_REGISTERED;
+ status_t status;
+
+ /* if the kernel supports installing SPIs with policies we install the
+ * SA immediately as it will only be used once we update the policies */
+ if (charon->kernel->get_features(charon->kernel) & KERNEL_POLICY_SPI)
+ {
+ status = install_internal(this, encr, integ, spi, cpi, FALSE, FALSE,
+ tfcv3);
+ }
+ else
+ {
+ DBG2(DBG_CHD, "registering outbound %N SA", protocol_id_names,
+ this->protocol);
+ DBG2(DBG_CHD, " SPI 0x%.8x, src %H dst %H", ntohl(spi), this->my_addr,
+ this->other_addr);
+
+ this->other_spi = spi;
+ this->other_cpi = cpi;
+ this->encr_r = chunk_clone(encr);
+ this->integ_r = chunk_clone(integ);
+ this->tfcv3 = tfcv3;
+ status = SUCCESS;
+ }
+ this->outbound_state |= CHILD_OUTBOUND_REGISTERED;
+ return status;
}
METHOD(child_sa_t, install_outbound, status_t,
@@ -1289,18 +1310,23 @@ METHOD(child_sa_t, install_outbound, status_t,
{
enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts;
- status_t status;
+ status_t status = SUCCESS;
- status = install_internal(this, this->encr_r, this->integ_r,
- this->other_spi, this->other_cpi, FALSE, FALSE,
- this->tfcv3);
- chunk_clear(&this->encr_r);
- chunk_clear(&this->integ_r);
+ if (!(this->outbound_state & CHILD_OUTBOUND_SA))
+ {
+ status = install_internal(this, this->encr_r, this->integ_r,
+ this->other_spi, this->other_cpi, FALSE,
+ FALSE, this->tfcv3);
+ chunk_clear(&this->encr_r);
+ chunk_clear(&this->integ_r);
+ }
+ this->outbound_state &= ~CHILD_OUTBOUND_REGISTERED;
if (status != SUCCESS)
{
return status;
}
- if (!this->config->has_option(this->config, OPT_NO_POLICIES))
+ if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
+ !(this->outbound_state & CHILD_OUTBOUND_POLICIES))
{
ipsec_sa_cfg_t my_sa, other_sa;
uint32_t manual_prio;
@@ -1331,6 +1357,7 @@ METHOD(child_sa_t, install_outbound, status_t,
}
enumerator->destroy(enumerator);
}
+ this->outbound_state |= CHILD_OUTBOUND_POLICIES;
return status;
}
@@ -1340,20 +1367,19 @@ METHOD(child_sa_t, remove_outbound, void,
enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts;
- switch (this->outbound_state)
+ if (!(this->outbound_state & CHILD_OUTBOUND_SA))
{
- case CHILD_OUTBOUND_INSTALLED:
- break;
- case CHILD_OUTBOUND_REGISTERED:
+ if (this->outbound_state & CHILD_OUTBOUND_REGISTERED)
+ {
chunk_clear(&this->encr_r);
chunk_clear(&this->integ_r);
this->outbound_state = CHILD_OUTBOUND_NONE;
- /* fall-through */
- case CHILD_OUTBOUND_NONE:
- return;
+ }
+ return;
}
- if (!this->config->has_option(this->config, OPT_NO_POLICIES))
+ if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
+ (this->outbound_state & CHILD_OUTBOUND_POLICIES))
{
ipsec_sa_cfg_t my_sa, other_sa;
uint32_t manual_prio;
@@ -1598,8 +1624,8 @@ METHOD(child_sa_t, destroy, void,
prepare_sa_cfg(this, &my_sa, &other_sa);
manual_prio = this->config->get_manual_prio(this->config);
- del_outbound = this->trap ||
- this->outbound_state == CHILD_OUTBOUND_INSTALLED;
+ del_outbound = (this->outbound_state & CHILD_OUTBOUND_POLICIES) ||
+ this->trap;
/* delete all policies in the kernel */
enumerator = create_policy_enumerator(this);
@@ -1640,7 +1666,7 @@ METHOD(child_sa_t, destroy, void,
};
charon->kernel->del_sa(charon->kernel, &id, &sa);
}
- if (this->other_spi && this->outbound_state == CHILD_OUTBOUND_INSTALLED)
+ if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA))
{
kernel_ipsec_sa_id_t id = {
.src = this->my_addr,
@@ -1719,7 +1745,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
{
private_child_sa_t *this;
static refcount_t unique_id = 0, unique_mark = 0;
- refcount_t mark;
+ refcount_t mark = 0;
INIT(this,
.public = {
@@ -1792,16 +1818,33 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
{
this->mark_out.value = mark_out;
}
- if (this->mark_in.value == MARK_UNIQUE ||
- this->mark_out.value == MARK_UNIQUE)
+
+ if (MARK_IS_UNIQUE(this->mark_in.value) ||
+ MARK_IS_UNIQUE(this->mark_out.value))
{
- mark = ref_get(&unique_mark);
- if (this->mark_in.value == MARK_UNIQUE)
+ bool unique_dir;
+
+ unique_dir = this->mark_in.value == MARK_UNIQUE_DIR ||
+ this->mark_out.value == MARK_UNIQUE_DIR;
+
+ if (!unique_dir)
+ {
+ mark = ref_get(&unique_mark);
+ }
+ if (MARK_IS_UNIQUE(this->mark_in.value))
{
+ if (unique_dir)
+ {
+ mark = ref_get(&unique_mark);
+ }
this->mark_in.value = mark;
}
- if (this->mark_out.value == MARK_UNIQUE)
+ if (MARK_IS_UNIQUE(this->mark_out.value))
{
+ if (unique_dir)
+ {
+ mark = ref_get(&unique_mark);
+ }
this->mark_out.value = mark;
}
}
diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h
index b9a913da1..082404d93 100644
--- a/src/libcharon/sa/child_sa.h
+++ b/src/libcharon/sa/child_sa.h
@@ -102,17 +102,28 @@ enum child_sa_outbound_state_t {
/**
* Outbound SA is not installed
*/
- CHILD_OUTBOUND_NONE,
+ CHILD_OUTBOUND_NONE = 0,
/**
- * Data for the outbound SA has been registered, but not installed yet
+ * Data for the outbound SA has been registered during a rekeying (not set
+ * once the SA and policies are both installed)
*/
- CHILD_OUTBOUND_REGISTERED,
+ CHILD_OUTBOUND_REGISTERED = (1<<0),
/**
- * The outbound SA is currently installed
+ * The outbound SA has been installed
*/
- CHILD_OUTBOUND_INSTALLED,
+ CHILD_OUTBOUND_SA = (1<<1),
+
+ /**
+ * The outbound policies have been installed
+ */
+ CHILD_OUTBOUND_POLICIES = (1<<2),
+
+ /**
+ * The outbound SA and policies are both installed
+ */
+ CHILD_OUTBOUND_INSTALLED = (CHILD_OUTBOUND_SA|CHILD_OUTBOUND_POLICIES),
};
/**
@@ -400,20 +411,23 @@ struct child_sa_t {
* Register data for the installation of an outbound SA as responder during
* a rekeying.
*
- * The SA is not installed until install_outbound() is called.
+ * If the kernel is able to handle SPIs on policies the SA is installed
+ * immediately, if not it won't be installed until install_outbound() is
+ * called.
*
* @param encr encryption key, if any (cloned)
* @param integ integrity key (cloned)
* @param spi SPI to use, allocated for inbound
* @param cpi CPI to use, allocated for outbound
* @param tfcv3 TRUE if peer supports ESPv3 TFC
+ * @return SUCCESS or FAILED
*/
- void (*register_outbound)(child_sa_t *this, chunk_t encr, chunk_t integ,
- uint32_t spi, uint16_t cpi, bool tfcv3);
+ status_t (*register_outbound)(child_sa_t *this, chunk_t encr, chunk_t integ,
+ uint32_t spi, uint16_t cpi, bool tfcv3);
/**
- * Install the outbound SA and the outbound policies as responder during a
- * rekeying.
+ * Install the outbound policies and, if not already done, the outbound SA
+ * as responder during a rekeying.
*
* @return SUCCESS or FAILED
*/
diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c
index 48ec3e7f5..3472d2c35 100644
--- a/src/libcharon/sa/ikev1/task_manager_v1.c
+++ b/src/libcharon/sa/ikev1/task_manager_v1.c
@@ -1805,8 +1805,12 @@ METHOD(task_manager_t, queue_child_rekey, void,
if (is_redundant(this, child_sa))
{
child_sa->set_state(child_sa, CHILD_REKEYED);
- queue_task(this, (task_t*)quick_delete_create(this->ike_sa,
+ if (lib->settings->get_bool(lib->settings, "%s.delete_rekeyed",
+ FALSE, lib->ns))
+ {
+ queue_task(this, (task_t*)quick_delete_create(this->ike_sa,
protocol, spi, FALSE, FALSE));
+ }
}
else
{
diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c
index 8be82ebe2..49b476ad8 100644
--- a/src/libcharon/sa/ikev1/tasks/quick_mode.c
+++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c
@@ -396,10 +396,6 @@ static bool install(private_quick_mode_t *this)
charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
this->dh, this->nonce_i, this->nonce_r);
- /* add to IKE_SA, and remove from task */
- this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
- this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
-
my_ts = linked_list_create_from_enumerator(
this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
other_ts = linked_list_create_from_enumerator(
@@ -415,6 +411,9 @@ static bool install(private_quick_mode_t *this)
my_ts->destroy(my_ts);
other_ts->destroy(other_ts);
+ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
+ this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
+
if (this->rekey)
{
old = this->ike_sa->get_child_sa(this->ike_sa,
diff --git a/src/libcharon/sa/ikev2/keymat_v2.c b/src/libcharon/sa/ikev2/keymat_v2.c
index 70dacd1dc..0c41c68d0 100644
--- a/src/libcharon/sa/ikev2/keymat_v2.c
+++ b/src/libcharon/sa/ikev2/keymat_v2.c
@@ -342,10 +342,13 @@ METHOD(keymat_v2_t, derive_ike_keys, bool,
* the nonces. */
switch (alg)
{
+ case PRF_AES128_CMAC:
+ /* while variable keys may be used according to RFC 4615, RFC 7296
+ * explicitly limits the key size to 128 bit for this application */
case PRF_AES128_XCBC:
- /* while rfc4434 defines variable keys for AES-XCBC, rfc3664 does
+ /* while RFC 4434 defines variable keys for AES-XCBC, RFC 3664 does
* not and therefore fixed key semantics apply to XCBC for key
- * derivation. */
+ * derivation, which is also reinforced by RFC 7296 */
case PRF_CAMELLIA128_XCBC:
/* draft-kanno-ipsecme-camellia-xcbc refers to rfc 4434, we
* assume fixed key length. */
diff --git a/src/libcharon/sa/ikev2/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c
index 896cabb2b..cac3bc0a2 100644
--- a/src/libcharon/sa/ikev2/tasks/child_create.c
+++ b/src/libcharon/sa/ikev2/tasks/child_create.c
@@ -478,6 +478,7 @@ static status_t select_and_install(private_child_create_t *this,
bool no_dh, bool ike_auth)
{
status_t status, status_i, status_o;
+ child_sa_outbound_state_t out_state;
chunk_t nonce_i, nonce_r;
chunk_t encr_i = chunk_empty, encr_r = chunk_empty;
chunk_t integ_i = chunk_empty, integ_r = chunk_empty;
@@ -678,29 +679,42 @@ static status_t select_and_install(private_child_create_t *this,
status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
this->my_spi, this->my_cpi, this->initiator,
TRUE, this->tfcv3);
- status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
- this->other_spi, this->other_cpi, this->initiator,
- FALSE, this->tfcv3);
}
- else if (!this->rekey)
+ else
{
status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
this->my_spi, this->my_cpi, this->initiator,
TRUE, this->tfcv3);
- status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
+ }
+ if (this->rekey)
+ { /* during rekeyings we install the outbound SA and/or policies
+ * separately: as responder when we receive the delete for the old
+ * SA, as initiator pretty much immediately in the ike-rekey task,
+ * unless there was a rekey collision that we lost */
+ if (this->initiator)
+ {
+ status_o = this->child_sa->register_outbound(this->child_sa,
+ encr_i, integ_i, this->other_spi, this->other_cpi,
+ this->tfcv3);
+ }
+ else
+ {
+ status_o = this->child_sa->register_outbound(this->child_sa,
+ encr_r, integ_r, this->other_spi, this->other_cpi,
+ this->tfcv3);
+ }
+ }
+ else if (this->initiator)
+ {
+ status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
this->other_spi, this->other_cpi, this->initiator,
FALSE, this->tfcv3);
}
else
- { /* as responder during a rekeying we only install the inbound
- * SA now, the outbound SA and policies are installed when we
- * receive the delete for the old SA */
- status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
- this->my_spi, this->my_cpi, this->initiator,
- TRUE, this->tfcv3);
- this->child_sa->register_outbound(this->child_sa, encr_r, integ_r,
- this->other_spi, this->other_cpi, this->tfcv3);
- status_o = SUCCESS;
+ {
+ status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
+ this->other_spi, this->other_cpi, this->initiator,
+ FALSE, this->tfcv3);
}
}
@@ -745,20 +759,15 @@ static status_t select_and_install(private_child_create_t *this,
charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
this->dh, nonce_i, nonce_r);
- this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
- this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
- this->established = TRUE;
-
- schedule_inactivity_timeout(this);
-
my_ts = linked_list_create_from_enumerator(
this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
other_ts = linked_list_create_from_enumerator(
this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
+ out_state = this->child_sa->get_outbound_state(this->child_sa);
DBG0(DBG_IKE, "%sCHILD_SA %s{%d} established "
"with SPIs %.8x_i %.8x_o and TS %#R === %#R",
- this->rekey && !this->initiator ? "inbound " : "",
+ (out_state == CHILD_OUTBOUND_INSTALLED) ? "" : "inbound ",
this->child_sa->get_name(this->child_sa),
this->child_sa->get_unique_id(this->child_sa),
ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
@@ -767,6 +776,12 @@ static status_t select_and_install(private_child_create_t *this,
my_ts->destroy(my_ts);
other_ts->destroy(other_ts);
+
+ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
+ this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
+ this->established = TRUE;
+
+ schedule_inactivity_timeout(this);
return SUCCESS;
}
@@ -1007,17 +1022,6 @@ METHOD(task_t, build_i, status_t,
break;
}
- if (this->reqid)
- {
- DBG0(DBG_IKE, "establishing CHILD_SA %s{%d}",
- this->config->get_name(this->config), this->reqid);
- }
- else
- {
- DBG0(DBG_IKE, "establishing CHILD_SA %s",
- this->config->get_name(this->config));
- }
-
/* check if we want a virtual IP, but don't have one */
list = linked_list_create();
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
@@ -1070,6 +1074,19 @@ METHOD(task_t, build_i, status_t,
this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY),
this->mark_in, this->mark_out);
+ if (this->reqid)
+ {
+ DBG0(DBG_IKE, "establishing CHILD_SA %s{%d} reqid %d",
+ this->child_sa->get_name(this->child_sa),
+ this->child_sa->get_unique_id(this->child_sa), this->reqid);
+ }
+ else
+ {
+ DBG0(DBG_IKE, "establishing CHILD_SA %s{%d}",
+ this->child_sa->get_name(this->child_sa),
+ this->child_sa->get_unique_id(this->child_sa));
+ }
+
if (!allocate_spi(this))
{
DBG1(DBG_IKE, "unable to allocate SPIs from kernel");
diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c
index 626796383..2217295b6 100644
--- a/src/libcharon/sa/ikev2/tasks/child_delete.c
+++ b/src/libcharon/sa/ikev2/tasks/child_delete.c
@@ -196,7 +196,6 @@ static void install_outbound(private_child_delete_t *this,
/* FIXME: delete the new child_sa? */
return;
}
- child_sa->set_state(child_sa, CHILD_INSTALLED);
my_ts = linked_list_create_from_enumerator(
child_sa->create_ts_enumerator(child_sa, TRUE));
diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c
index 761c860e7..b67e9b80f 100644
--- a/src/libcharon/sa/ikev2/tasks/child_rekey.c
+++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2016 Tobias Brunner
+ * Copyright (C) 2009-2017 Tobias Brunner
* Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* HSR Hochschule fuer Technik Rapperswil
@@ -283,7 +283,8 @@ METHOD(task_t, build_r, status_t,
/**
* Handle a rekey collision
*/
-static child_sa_t *handle_collision(private_child_rekey_t *this)
+static child_sa_t *handle_collision(private_child_rekey_t *this,
+ child_sa_t **to_install)
{
child_sa_t *to_delete;
@@ -302,8 +303,11 @@ static child_sa_t *handle_collision(private_child_rekey_t *this)
{
child_sa_t *child_sa;
- DBG1(DBG_IKE, "CHILD_SA rekey collision won, deleting old child");
+ *to_install = this->child_create->get_child(this->child_create);
to_delete = this->child_sa;
+ DBG1(DBG_IKE, "CHILD_SA rekey collision won, deleting old child "
+ "%s{%d}", to_delete->get_name(to_delete),
+ to_delete->get_unique_id(to_delete));
/* don't touch child other created, it has already been deleted */
if (!this->other_child_destroyed)
{
@@ -321,9 +325,10 @@ static child_sa_t *handle_collision(private_child_rekey_t *this)
}
else
{
- DBG1(DBG_IKE, "CHILD_SA rekey collision lost, "
- "deleting rekeyed child");
to_delete = this->child_create->get_child(this->child_create);
+ DBG1(DBG_IKE, "CHILD_SA rekey collision lost, deleting redundant "
+ "child %s{%d}", to_delete->get_name(to_delete),
+ to_delete->get_unique_id(to_delete));
}
}
else
@@ -334,15 +339,17 @@ static child_sa_t *handle_collision(private_child_rekey_t *this)
* the CHILD_SA the other is not deleting. */
if (del->get_child(del) != this->child_sa)
{
- DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, "
- "deleting rekeyed child");
to_delete = this->child_sa;
+ DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, deleting old child "
+ "%s{%d}", to_delete->get_name(to_delete),
+ to_delete->get_unique_id(to_delete));
}
else
{
- DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, "
- "deleting redundant child");
to_delete = this->child_create->get_child(this->child_create);
+ DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, deleting redundant "
+ "child %s{%d}", to_delete->get_name(to_delete),
+ to_delete->get_unique_id(to_delete));
}
}
return to_delete;
@@ -353,7 +360,7 @@ METHOD(task_t, process_i, status_t,
{
protocol_id_t protocol;
uint32_t spi;
- child_sa_t *to_delete;
+ child_sa_t *to_delete, *to_install = NULL;
if (message->get_notify(message, NO_ADDITIONAL_SAS))
{
@@ -415,19 +422,48 @@ METHOD(task_t, process_i, status_t,
/* check for rekey collisions */
if (this->collision)
{
- to_delete = handle_collision(this);
+ to_delete = handle_collision(this, &to_install);
}
else
{
+ to_install = this->child_create->get_child(this->child_create);
to_delete = this->child_sa;
}
-
+ if (to_install)
+ {
+ if (to_install->install_outbound(to_install) != SUCCESS)
+ {
+ DBG1(DBG_IKE, "unable to install outbound IPsec SA (SAD) in kernel");
+ charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
+ to_install);
+ /* FIXME: delete the child_sa? fail the task? */
+ }
+ else
+ {
+ linked_list_t *my_ts, *other_ts;
+
+ my_ts = linked_list_create_from_enumerator(
+ to_install->create_ts_enumerator(to_install, TRUE));
+ other_ts = linked_list_create_from_enumerator(
+ to_install->create_ts_enumerator(to_install, FALSE));
+
+ DBG0(DBG_IKE, "outbound CHILD_SA %s{%d} established "
+ "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
+ to_install->get_name(to_install),
+ to_install->get_unique_id(to_install),
+ ntohl(to_install->get_spi(to_install, TRUE)),
+ ntohl(to_install->get_spi(to_install, FALSE)),
+ my_ts, other_ts);
+
+ my_ts->destroy(my_ts);
+ other_ts->destroy(other_ts);
+ }
+ }
if (to_delete != this->child_create->get_child(this->child_create))
{ /* invoke rekey hook if rekeying successful */
charon->bus->child_rekey(charon->bus, this->child_sa,
this->child_create->get_child(this->child_create));
}
-
if (to_delete == NULL)
{
return SUCCESS;
diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c
index f9fee5e7e..6436a2549 100644
--- a/src/libcharon/sa/trap_manager.c
+++ b/src/libcharon/sa/trap_manager.c
@@ -158,6 +158,31 @@ CALLBACK(acquire_by_dst, bool,
return this->dst && this->dst->ip_equals(this->dst, dst);
}
+/**
+ * Check if any remote TS are dynamic
+ */
+static bool dynamic_remote_ts(child_cfg_t *child)
+{
+ enumerator_t *enumerator;
+ linked_list_t *other_ts;
+ traffic_selector_t *ts;
+ bool found = FALSE;
+
+ other_ts = child->get_traffic_selectors(child, FALSE, NULL, NULL);
+ enumerator = other_ts->create_enumerator(other_ts);
+ while (enumerator->enumerate(enumerator, &ts))
+ {
+ if (ts->is_dynamic(ts))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
+ return found;
+}
+
METHOD(trap_manager_t, install, uint32_t,
private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child,
uint32_t reqid)
@@ -184,25 +209,39 @@ METHOD(trap_manager_t, install, uint32_t,
me = host_create_any(other->get_family(other));
wildcard = TRUE;
}
- else if (!other || other->is_anyaddr(other))
+ else if (other && other->is_anyaddr(other))
{
- DESTROY_IF(other);
+ other->destroy(other);
DBG1(DBG_CFG, "installing trap failed, remote address unknown");
return 0;
}
else
- {
- me = ike_cfg->resolve_me(ike_cfg, other->get_family(other));
- if (!me || me->is_anyaddr(me))
+ { /* depending on the traffic selectors we don't really need a remote
+ * host yet, but we might fail later if no IP can be resolved */
+ if (!other && dynamic_remote_ts(child))
+ { /* with dynamic TS we do need a host, otherwise 0.0.0.0/0 is used,
+ * which is probably not what users expect*/
+ DBG1(DBG_CFG, "installing trap failed, remote address unknown with "
+ "dynamic traffic selector");
+ return 0;
+ }
+ me = ike_cfg->resolve_me(ike_cfg, other ? other->get_family(other)
+ : AF_UNSPEC);
+ if (!other)
+ {
+ other = host_create_any(me ? me->get_family(me) : AF_INET);
+ }
+ other->set_port(other, ike_cfg->get_other_port(ike_cfg));
+ if ((!me || me->is_anyaddr(me)) && !other->is_anyaddr(other))
{
DESTROY_IF(me);
me = charon->kernel->get_source_addr(charon->kernel, other, NULL);
- if (!me)
- {
- me = host_create_any(other->get_family(other));
- }
- me->set_port(me, ike_cfg->get_my_port(ike_cfg));
}
+ if (!me)
+ {
+ me = host_create_any(other->get_family(other));
+ }
+ me->set_port(me, ike_cfg->get_my_port(ike_cfg));
}
this->lock->write_lock(this->lock);