From: Martin Willi Date: Mon, 30 Sep 2013 13:47:27 +0000 (+0200) Subject: libipsec: Enforce byte/packet lifetimes on SAs X-Git-Tag: 5.1.1rc1~47^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d53002f088c588bb65215bb9a6e5100ba321738e;p=thirdparty%2Fstrongswan.git libipsec: Enforce byte/packet lifetimes on SAs --- diff --git a/src/libipsec/ipsec_sa.c b/src/libipsec/ipsec_sa.c index 3fbe56240d..6ec8bd25ef 100644 --- a/src/libipsec/ipsec_sa.c +++ b/src/libipsec/ipsec_sa.c @@ -15,6 +15,7 @@ * for more details. */ +#include "ipsec.h" #include "ipsec_sa.h" #include @@ -93,6 +94,16 @@ struct private_ipsec_sa_t { /** number of bytes processed */ u_int64_t bytes; } 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*, @@ -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, private_ipsec_sa_t *this, u_int32_t bytes) { this->use.time = time_monotonic(NULL); this->use.packets++; 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, 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, @@ -199,7 +255,8 @@ METHOD(ipsec_sa_t, match_by_spi_src_dst, bool, METHOD(ipsec_sa_t, match_by_reqid, bool, 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, @@ -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_usestats = _get_usestats, .update_usestats = _update_usestats, + .expire = _expire, }, .spi = spi, .src = src->clone(src), diff --git a/src/libipsec/ipsec_sa.h b/src/libipsec/ipsec_sa.h index 9b77c80409..5e69f18cfe 100644 --- a/src/libipsec/ipsec_sa.h +++ b/src/libipsec/ipsec_sa.h @@ -126,9 +126,21 @@ struct ipsec_sa_t { */ 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 * + * Only matches if the SA has not yet expired. + * * @param spi SPI * @param dst destination address * @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 * + * Only matches if the SA has not yet expired. + * * @param reqid reqid * @param inbound TRUE for inbound SA, FALSE for outbound * @return TRUE if this SA matches all parameters, FALSE otherwise diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c index 8da20cdc5e..1db1776c06 100644 --- a/src/libipsec/ipsec_sa_mgr.c +++ b/src/libipsec/ipsec_sa_mgr.c @@ -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, NULL, expired->entry) == SUCCESS) { - u_int32_t hard_offset = expired->hard_offset; - ipsec_sa_t *sa = expired->entry->sa; + u_int32_t hard_offset; - ipsec->events->expire(ipsec->events, sa->get_reqid(sa), - sa->get_protocol(sa), sa->get_spi(sa), - hard_offset == 0); + hard_offset = expired->hard_offset; + expired->entry->sa->expire(expired->entry->sa, hard_offset == 0); if (hard_offset) { /* soft limit reached, schedule hard expire */ expired->hard_offset = 0;