libipsec: Enforce byte/packet lifetimes on SAs
This commit is contained in:
+60
-2
@@ -15,6 +15,7 @@
|
|||||||
* for more details.
|
* for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "ipsec.h"
|
||||||
#include "ipsec_sa.h"
|
#include "ipsec_sa.h"
|
||||||
|
|
||||||
#include <library.h>
|
#include <library.h>
|
||||||
@@ -93,6 +94,16 @@ struct private_ipsec_sa_t {
|
|||||||
/** number of bytes processed */
|
/** number of bytes processed */
|
||||||
u_int64_t bytes;
|
u_int64_t bytes;
|
||||||
} use;
|
} use;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has the SA soft-expired?
|
||||||
|
*/
|
||||||
|
bool soft_expired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has the SA hard-expired?
|
||||||
|
*/
|
||||||
|
bool hard_expired;
|
||||||
};
|
};
|
||||||
|
|
||||||
METHOD(ipsec_sa_t, get_source, host_t*,
|
METHOD(ipsec_sa_t, get_source, host_t*,
|
||||||
@@ -175,18 +186,63 @@ METHOD(ipsec_sa_t, get_usestats, void,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(ipsec_sa_t, expire, void,
|
||||||
|
private_ipsec_sa_t *this, bool hard)
|
||||||
|
{
|
||||||
|
if (hard)
|
||||||
|
{
|
||||||
|
if (!this->hard_expired)
|
||||||
|
{
|
||||||
|
this->hard_expired = TRUE;
|
||||||
|
ipsec->events->expire(ipsec->events, this->reqid, this->protocol,
|
||||||
|
this->spi, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!this->hard_expired && !this->soft_expired)
|
||||||
|
{
|
||||||
|
this->soft_expired = TRUE;
|
||||||
|
ipsec->events->expire(ipsec->events, this->reqid, this->protocol,
|
||||||
|
this->spi, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(ipsec_sa_t, update_usestats, void,
|
METHOD(ipsec_sa_t, update_usestats, void,
|
||||||
private_ipsec_sa_t *this, u_int32_t bytes)
|
private_ipsec_sa_t *this, u_int32_t bytes)
|
||||||
{
|
{
|
||||||
this->use.time = time_monotonic(NULL);
|
this->use.time = time_monotonic(NULL);
|
||||||
this->use.packets++;
|
this->use.packets++;
|
||||||
this->use.bytes += bytes;
|
this->use.bytes += bytes;
|
||||||
|
|
||||||
|
if (this->lifetime.packets.life &&
|
||||||
|
this->use.packets >= this->lifetime.packets.life)
|
||||||
|
{
|
||||||
|
return expire(this, TRUE);
|
||||||
|
}
|
||||||
|
if (this->lifetime.bytes.life &&
|
||||||
|
this->use.bytes >= this->lifetime.bytes.life)
|
||||||
|
{
|
||||||
|
return expire(this, TRUE);
|
||||||
|
}
|
||||||
|
if (this->lifetime.packets.rekey &&
|
||||||
|
this->use.packets >= this->lifetime.packets.rekey)
|
||||||
|
{
|
||||||
|
return expire(this, FALSE);
|
||||||
|
}
|
||||||
|
if (this->lifetime.bytes.rekey &&
|
||||||
|
this->use.bytes >= this->lifetime.bytes.rekey)
|
||||||
|
{
|
||||||
|
return expire(this, FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(ipsec_sa_t, match_by_spi_dst, bool,
|
METHOD(ipsec_sa_t, match_by_spi_dst, bool,
|
||||||
private_ipsec_sa_t *this, u_int32_t spi, host_t *dst)
|
private_ipsec_sa_t *this, u_int32_t spi, host_t *dst)
|
||||||
{
|
{
|
||||||
return this->spi == spi && this->dst->ip_equals(this->dst, dst);
|
return this->spi == spi && this->dst->ip_equals(this->dst, dst) &&
|
||||||
|
!this->hard_expired;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(ipsec_sa_t, match_by_spi_src_dst, bool,
|
METHOD(ipsec_sa_t, match_by_spi_src_dst, bool,
|
||||||
@@ -199,7 +255,8 @@ METHOD(ipsec_sa_t, match_by_spi_src_dst, bool,
|
|||||||
METHOD(ipsec_sa_t, match_by_reqid, bool,
|
METHOD(ipsec_sa_t, match_by_reqid, bool,
|
||||||
private_ipsec_sa_t *this, u_int32_t reqid, bool inbound)
|
private_ipsec_sa_t *this, u_int32_t reqid, bool inbound)
|
||||||
{
|
{
|
||||||
return this->reqid == reqid && this->inbound == inbound;
|
return this->reqid == reqid && this->inbound == inbound &&
|
||||||
|
!this->hard_expired;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(ipsec_sa_t, destroy, void,
|
METHOD(ipsec_sa_t, destroy, void,
|
||||||
@@ -267,6 +324,7 @@ ipsec_sa_t *ipsec_sa_create(u_int32_t spi, host_t *src, host_t *dst,
|
|||||||
.get_esp_context = _get_esp_context,
|
.get_esp_context = _get_esp_context,
|
||||||
.get_usestats = _get_usestats,
|
.get_usestats = _get_usestats,
|
||||||
.update_usestats = _update_usestats,
|
.update_usestats = _update_usestats,
|
||||||
|
.expire = _expire,
|
||||||
},
|
},
|
||||||
.spi = spi,
|
.spi = spi,
|
||||||
.src = src->clone(src),
|
.src = src->clone(src),
|
||||||
|
|||||||
@@ -126,9 +126,21 @@ struct ipsec_sa_t {
|
|||||||
*/
|
*/
|
||||||
void (*update_usestats)(ipsec_sa_t *this, u_int32_t bytes);
|
void (*update_usestats)(ipsec_sa_t *this, u_int32_t bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expire this SA, soft or hard.
|
||||||
|
*
|
||||||
|
* A soft expire triggers a rekey, a hard expire blocks the SA and
|
||||||
|
* triggers a delete for the SA.
|
||||||
|
*
|
||||||
|
* @param hard TRUE for hard, FALSE for soft
|
||||||
|
*/
|
||||||
|
void (*expire)(ipsec_sa_t *this, bool hard);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this SA matches all given parameters
|
* Check if this SA matches all given parameters
|
||||||
*
|
*
|
||||||
|
* Only matches if the SA has not yet expired.
|
||||||
|
*
|
||||||
* @param spi SPI
|
* @param spi SPI
|
||||||
* @param dst destination address
|
* @param dst destination address
|
||||||
* @return TRUE if this SA matches all parameters, FALSE otherwise
|
* @return TRUE if this SA matches all parameters, FALSE otherwise
|
||||||
@@ -149,6 +161,8 @@ struct ipsec_sa_t {
|
|||||||
/**
|
/**
|
||||||
* Check if this SA matches all given parameters
|
* Check if this SA matches all given parameters
|
||||||
*
|
*
|
||||||
|
* Only matches if the SA has not yet expired.
|
||||||
|
*
|
||||||
* @param reqid reqid
|
* @param reqid reqid
|
||||||
* @param inbound TRUE for inbound SA, FALSE for outbound
|
* @param inbound TRUE for inbound SA, FALSE for outbound
|
||||||
* @return TRUE if this SA matches all parameters, FALSE otherwise
|
* @return TRUE if this SA matches all parameters, FALSE otherwise
|
||||||
|
|||||||
@@ -299,12 +299,10 @@ static job_requeue_t sa_expired(ipsec_sa_expired_t *expired)
|
|||||||
if (this->sas->find_first(this->sas, (void*)match_entry_by_ptr,
|
if (this->sas->find_first(this->sas, (void*)match_entry_by_ptr,
|
||||||
NULL, expired->entry) == SUCCESS)
|
NULL, expired->entry) == SUCCESS)
|
||||||
{
|
{
|
||||||
u_int32_t hard_offset = expired->hard_offset;
|
u_int32_t hard_offset;
|
||||||
ipsec_sa_t *sa = expired->entry->sa;
|
|
||||||
|
|
||||||
ipsec->events->expire(ipsec->events, sa->get_reqid(sa),
|
hard_offset = expired->hard_offset;
|
||||||
sa->get_protocol(sa), sa->get_spi(sa),
|
expired->entry->sa->expire(expired->entry->sa, hard_offset == 0);
|
||||||
hard_offset == 0);
|
|
||||||
if (hard_offset)
|
if (hard_offset)
|
||||||
{ /* soft limit reached, schedule hard expire */
|
{ /* soft limit reached, schedule hard expire */
|
||||||
expired->hard_offset = 0;
|
expired->hard_offset = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user