kernel-interface: add an exchange initiator parameter to add_sa()

This new flag gives the kernel-interface a hint how it should priorize the
use of newly installed SAs during rekeying.

Consider the following rekey procedure in IKEv2:

Initiator  ---    Responder

I1 -------CREATE-------> R1
I2 <------CREATE--------
   -------DELETE-------> R2
I3 <------DELETE--------

SAs are always handled as pairs, the following happens at the SA level:

  * Initiator starts the exchange at I1
  * Responder installs new SA pair at R1
  * Initiator installs new SA pair at I2
  * Responder removes old SA pair at R2
  * Initiator removes old SA pair at I3

This makes sure SAs get installed/removed overlapping during rekeying. However,
to avoid any packet loss, it is crucial that the new outbound SA gets
activated at the correct position:

  * as exchange initiator, in I2
  * as exchange responder, in R2

This should guarantee that we don't use the new outbound SA before the peer
could install its corresponding inbound SA.

The new parameter allows the kernel backend to install the new SA with
appropriate priorities, i.e. it should:

  * as exchange inititator, have the new outbound SA installed with higher
    priority than the old SA
  * as exchange responder, have the new outbound SA installed with lower
    priority than the old SA

While we could split up the SA installation at the responder, this approach
has another advantage: it allows the kernel backend to switch SAs based on
other criteria, for example when receiving traffic on the new inbound SA.
This commit is contained in:
Martin Willi
2013-06-11 15:58:48 +02:00
parent d024a4652c
commit a8c9454423
14 changed files with 46 additions and 35 deletions
+2 -1
View File
@@ -92,7 +92,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
u_int16_t cpi, bool encap, bool esn, bool inbound,
u_int16_t cpi, bool _initiator, bool encap, bool esn, bool inbound,
traffic_selector_t* src_ts, traffic_selector_t* dst_ts)
{
esa_info_t esa;
@@ -120,6 +120,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
}
/* Initiator if encr_r is passed as enc_key to the inbound add_sa call */
/* TODO: does the new _initiator parameter have the same meaning? */
initiator = esa.is_encr_r && inbound;
if (initiator)
{
@@ -65,7 +65,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
u_int16_t cpi, bool encap, bool esn, bool inbound,
u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
{
return ipsec->sas->add_sa(ipsec->sas, src, dst, spi, protocol, reqid, mark,
@@ -54,7 +54,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
u_int16_t cpi, bool encap, bool esn, bool inbound,
u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
{
return SUCCESS;
+5 -4
View File
@@ -607,9 +607,9 @@ METHOD(child_sa_t, alloc_cpi, u_int16_t,
}
METHOD(child_sa_t, install, status_t,
private_child_sa_t *this, chunk_t encr, chunk_t integ, u_int32_t spi,
u_int16_t cpi, bool inbound, bool tfcv3, linked_list_t *my_ts,
linked_list_t *other_ts)
private_child_sa_t *this, chunk_t encr, chunk_t integ, u_int32_t spi,
u_int16_t cpi, bool initiator, bool inbound, bool tfcv3,
linked_list_t *my_ts, linked_list_t *other_ts)
{
u_int16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
u_int16_t esn = NO_EXT_SEQ_NUMBERS;
@@ -703,7 +703,8 @@ METHOD(child_sa_t, install, status_t,
src, dst, spi, proto_ike2ip(this->protocol), this->reqid,
inbound ? this->mark_in : this->mark_out, tfc,
lifetime, enc_alg, encr, int_alg, integ, this->mode,
this->ipcomp, cpi, this->encap, esn, update, src_ts, dst_ts);
this->ipcomp, cpi, initiator, this->encap, esn, update,
src_ts, dst_ts);
free(lifetime);
+3 -1
View File
@@ -321,6 +321,7 @@ struct child_sa_t {
* @param integ integrity key
* @param spi SPI to use, allocated for inbound
* @param cpi CPI to use, allocated for outbound
* @param initiator TRUE if initiator of exchange resulting in this SA
* @param inbound TRUE to install an inbound SA, FALSE for outbound
* @param tfcv3 TRUE if peer supports ESPv3 TFC
* @param my_ts negotiated local traffic selector list
@@ -328,7 +329,8 @@ struct child_sa_t {
* @return SUCCESS or FAILED
*/
status_t (*install)(child_sa_t *this, chunk_t encr, chunk_t integ,
u_int32_t spi, u_int16_t cpi, bool inbound, bool tfcv3,
u_int32_t spi, u_int16_t cpi,
bool initiator, bool inbound, bool tfcv3,
linked_list_t *my_ts, linked_list_t *other_ts);
/**
* Install the policies using some traffic selectors.
+12 -8
View File
@@ -306,17 +306,21 @@ static bool install(private_quick_mode_t *this)
{
if (this->initiator)
{
status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
this->spi_i, this->cpi_i, TRUE, FALSE, tsi, tsr);
status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
this->spi_r, this->cpi_r, FALSE, FALSE, tsi, tsr);
status_i = this->child_sa->install(this->child_sa,
encr_r, integ_r, this->spi_i, this->cpi_i,
this->initiator, TRUE, FALSE, tsi, tsr);
status_o = this->child_sa->install(this->child_sa,
encr_i, integ_i, this->spi_r, this->cpi_r,
this->initiator, FALSE, FALSE, tsi, tsr);
}
else
{
status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
this->spi_r, this->cpi_r, TRUE, FALSE, tsr, tsi);
status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
this->spi_i, this->cpi_i, FALSE, FALSE, tsr, tsi);
status_i = this->child_sa->install(this->child_sa,
encr_i, integ_i, this->spi_r, this->cpi_r,
this->initiator, TRUE, FALSE, tsr, tsi);
status_o = this->child_sa->install(this->child_sa,
encr_r, integ_r, this->spi_i, this->cpi_i,
this->initiator, FALSE, FALSE, tsr, tsi);
}
}
chunk_clear(&integ_i);
+8 -8
View File
@@ -526,20 +526,20 @@ static status_t select_and_install(private_child_create_t *this,
{
if (this->initiator)
{
status_i = this->child_sa->install(this->child_sa,
encr_r, integ_r, this->my_spi, this->my_cpi,
status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
this->my_spi, this->my_cpi, this->initiator,
TRUE, this->tfcv3, my_ts, other_ts);
status_o = this->child_sa->install(this->child_sa,
encr_i, integ_i, this->other_spi, this->other_cpi,
status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
this->other_spi, this->other_cpi, this->initiator,
FALSE, this->tfcv3, my_ts, other_ts);
}
else
{
status_i = this->child_sa->install(this->child_sa,
encr_i, integ_i, this->my_spi, this->my_cpi,
status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
this->my_spi, this->my_cpi, this->initiator,
TRUE, this->tfcv3, my_ts, other_ts);
status_o = this->child_sa->install(this->child_sa,
encr_r, integ_r, this->other_spi, this->other_cpi,
status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
this->other_spi, this->other_cpi, this->initiator,
FALSE, this->tfcv3, my_ts, other_ts);
}
}
+2 -2
View File
@@ -180,7 +180,7 @@ METHOD(kernel_interface_t, add_sa, status_t,
u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
u_int16_t cpi, bool encap, bool esn, bool inbound,
u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
{
if (!this->ipsec)
@@ -189,7 +189,7 @@ METHOD(kernel_interface_t, add_sa, status_t,
}
return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid,
mark, tfc, lifetime, enc_alg, enc_key, int_alg, int_key, mode,
ipcomp, cpi, encap, esn, inbound, src_ts, dst_ts);
ipcomp, cpi, initiator, encap, esn, inbound, src_ts, dst_ts);
}
METHOD(kernel_interface_t, update_sa, status_t,
+2 -1
View File
@@ -143,6 +143,7 @@ struct kernel_interface_t {
* @param mode mode of the SA (tunnel, transport)
* @param ipcomp IPComp transform to use
* @param cpi CPI for IPComp
* @param initiator TRUE if initiator of the exchange creating this SA
* @param encap enable UDP encapsulation for NAT traversal
* @param esn TRUE to use Extended Sequence Numbers
* @param inbound TRUE if this is an inbound SA
@@ -157,7 +158,7 @@ struct kernel_interface_t {
u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key,
ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
bool encap, bool esn, bool inbound,
bool initiator, bool encap, bool esn, bool inbound,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts);
/**
+2 -1
View File
@@ -101,6 +101,7 @@ struct kernel_ipsec_t {
* @param mode mode of the SA (tunnel, transport)
* @param ipcomp IPComp transform to use
* @param cpi CPI for IPComp
* @param initiator TRUE if initiator of the exchange creating this SA
* @param encap enable UDP encapsulation for NAT traversal
* @param esn TRUE to use Extended Sequence Numbers
* @param inbound TRUE if this is an inbound SA
@@ -115,7 +116,7 @@ struct kernel_ipsec_t {
u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key,
ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
bool encap, bool esn, bool inbound,
bool initiator, bool encap, bool esn, bool inbound,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts);
/**
@@ -1682,8 +1682,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc,
lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
u_int16_t ipcomp, u_int16_t cpi, bool encap, bool esn, bool inbound,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
u_int16_t ipcomp, u_int16_t cpi, bool initiator, bool encap, bool esn,
bool inbound, traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
@@ -1170,7 +1170,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
u_int16_t cpi, bool encap, bool esn, bool inbound,
u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
traffic_selector_t* src_ts, traffic_selector_t* dst_ts)
{
netlink_buf_t request;
@@ -1187,7 +1187,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}};
add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, mark,
tfc, &lft, ENCR_UNDEFINED, chunk_empty, AUTH_UNDEFINED,
chunk_empty, mode, ipcomp, 0, FALSE, FALSE, inbound, NULL, NULL);
chunk_empty, mode, ipcomp, 0, initiator, FALSE, FALSE, inbound,
NULL, NULL);
ipcomp = IPCOMP_NONE;
/* use transport mode ESP SA, IPComp uses tunnel mode */
mode = MODE_TRANSPORT;
@@ -1523,8 +1523,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc,
lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
u_int16_t ipcomp, u_int16_t cpi, bool encap, bool esn, bool inbound,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
u_int16_t ipcomp, u_int16_t cpi, bool initiator, bool encap, bool esn,
bool inbound, traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
{
unsigned char request[PFKEY_BUFFER_SIZE];
struct sadb_msg *msg, *out;
+1 -1
View File
@@ -438,7 +438,7 @@ METHOD(ipsec_sa_mgr_t, add_sa, status_t,
u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc,
lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
u_int16_t cpi, bool encap, bool esn, bool inbound,
u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
{
ipsec_sa_entry_t *entry;