child-sa: Add methods that allow partial installation of CHILD_SA

Using install() for the inbound SA and register_outbound() for the
outbound SA followed by install_policies(), will delay the installation of
the outbound SA as well as the installation of the outbound policies
in the kernel until install_outbound() is called later.
This commit is contained in:
Tobias Brunner
2017-05-23 18:46:03 +02:00
parent 83186d3cf7
commit 8a3a389e3d
2 changed files with 144 additions and 5 deletions
+117 -5
View File
@@ -92,6 +92,26 @@ struct private_child_sa_t {
*/
array_t *other_ts;
/**
* Outbound encryption key cached during a rekeying
*/
chunk_t encr_r;
/**
* Outbound integrity key cached during a rekeying
*/
chunk_t integ_r;
/**
* Whether the outbound SA has only been registered yet during a rekeying
*/
bool outbound_registered;
/**
* Whether the peer supports TFCv3
*/
bool tfcv3;
/**
* Protocol used to protect this SA, ESP|AH
*/
@@ -692,9 +712,12 @@ METHOD(child_sa_t, alloc_cpi, uint16_t,
return 0;
}
METHOD(child_sa_t, install, status_t,
private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
uint16_t cpi, bool initiator, bool inbound, bool tfcv3)
/**
* Install the given SA in the kernel
*/
static status_t install_internal(private_child_sa_t *this, chunk_t encr,
chunk_t integ, uint32_t spi, uint16_t cpi, bool initiator, bool inbound,
bool tfcv3)
{
uint16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
uint16_t esn = NO_EXT_SEQ_NUMBERS;
@@ -834,6 +857,14 @@ METHOD(child_sa_t, install, status_t,
return status;
}
METHOD(child_sa_t, install, status_t,
private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
uint16_t cpi, bool initiator, bool inbound, bool tfcv3)
{
return install_internal(this, encr, integ, spi, cpi, initiator, inbound,
tfcv3);
}
/**
* Check kernel interface if policy updates are required
*/
@@ -1167,7 +1198,7 @@ METHOD(child_sa_t, install_policies, status_t,
/* install outbound drop policy to avoid packets leaving unencrypted
* when updating policies */
if (priority == POLICY_PRIORITY_DEFAULT && manual_prio == 0 &&
require_policy_update())
require_policy_update() && !this->outbound_registered)
{
status |= install_policies_outbound(this, this->my_addr,
this->other_addr, my_ts, other_ts,
@@ -1175,11 +1206,19 @@ METHOD(child_sa_t, install_policies, status_t,
POLICY_PRIORITY_FALLBACK, 0);
}
status |= install_policies_internal(this, this->my_addr,
status |= install_policies_inbound(this, this->my_addr,
this->other_addr, my_ts, other_ts,
&my_sa, &other_sa, POLICY_IPSEC,
priority, manual_prio);
if (!this->outbound_registered)
{
status |= install_policies_outbound(this, this->my_addr,
this->other_addr, my_ts, other_ts,
&my_sa, &other_sa, POLICY_IPSEC,
priority, manual_prio);
}
if (status != SUCCESS)
{
break;
@@ -1195,6 +1234,75 @@ METHOD(child_sa_t, install_policies, status_t,
return status;
}
METHOD(child_sa_t, register_outbound, void,
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_registered = TRUE;
}
METHOD(child_sa_t, install_outbound, status_t,
private_child_sa_t *this)
{
enumerator_t *enumerator;
traffic_selector_t *my_ts, *other_ts;
status_t status;
this->outbound_registered = FALSE;
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 (status != SUCCESS)
{
return status;
}
if (!this->config->has_option(this->config, OPT_NO_POLICIES))
{
ipsec_sa_cfg_t my_sa, other_sa;
uint32_t manual_prio;
prepare_sa_cfg(this, &my_sa, &other_sa);
manual_prio = this->config->get_manual_prio(this->config);
enumerator = create_policy_enumerator(this);
while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
{
/* install outbound drop policy to avoid packets leaving unencrypted
* when updating policies */
if (manual_prio == 0 && require_policy_update())
{
status |= install_policies_outbound(this, this->my_addr,
this->other_addr, my_ts, other_ts,
&my_sa, &other_sa, POLICY_DROP,
POLICY_PRIORITY_FALLBACK, 0);
}
status |= install_policies_outbound(this, this->my_addr,
this->other_addr, my_ts, other_ts,
&my_sa, &other_sa, POLICY_IPSEC,
POLICY_PRIORITY_DEFAULT, manual_prio);
if (status != SUCCESS)
{
break;
}
}
enumerator->destroy(enumerator);
}
return status;
}
/**
* Callback to reinstall a virtual IP
*/
@@ -1451,6 +1559,8 @@ METHOD(child_sa_t, destroy, void,
this->other_addr->destroy(this->other_addr);
DESTROY_IF(this->proposal);
this->config->destroy(this->config);
chunk_clear(&this->encr_r);
chunk_clear(&this->integ_r);
free(this);
}
@@ -1530,6 +1640,8 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
.alloc_spi = _alloc_spi,
.alloc_cpi = _alloc_cpi,
.install = _install,
.register_outbound = _register_outbound,
.install_outbound = _install_outbound,
.update = _update,
.set_policies = _set_policies,
.install_policies = _install_policies,
+27
View File
@@ -367,6 +367,29 @@ struct child_sa_t {
uint32_t spi, uint16_t cpi,
bool initiator, bool inbound, bool tfcv3);
/**
* Register data for the installation of an outbound SA as responder during
* a rekeying.
*
* The SA is not 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
*/
void (*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.
*
* @return SUCCESS or FAILED
*/
status_t (*install_outbound)(child_sa_t *this);
/**
* Configure the policies using some traffic selectors.
*
@@ -387,6 +410,10 @@ struct child_sa_t {
/**
* Install the configured policies.
*
* If register_outbound() was called previously this only installs the
* inbound and forward policies, the outbound policies are installed when
* install_outbound() is called.
*
* @return SUCCESS or FAILED
*/
status_t (*install_policies)(child_sa_t *this);