]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
libipsec: Enforce byte/packet lifetimes on SAs
authorMartin Willi <martin@revosec.ch>
Mon, 30 Sep 2013 13:47:27 +0000 (15:47 +0200)
committerMartin Willi <martin@revosec.ch>
Fri, 11 Oct 2013 08:23:18 +0000 (10:23 +0200)
src/libipsec/ipsec_sa.c
src/libipsec/ipsec_sa.h
src/libipsec/ipsec_sa_mgr.c

index 3fbe56240da10ddefeafd366402d08cff64f62f2..6ec8bd25ef7082acd35a5995d3618461f3a59f24 100644 (file)
@@ -15,6 +15,7 @@
  * for more details.
  */
 
+#include "ipsec.h"
 #include "ipsec_sa.h"
 
 #include <library.h>
@@ -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),
index 9b77c80409660d8814bdf6ec47b72e2d5bf03ba6..5e69f18cfed7223a0a55fd7e51d704937575a01c 100644 (file)
@@ -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
index 8da20cdc5e7dafc2b3805acf57200fa646509e3f..1db1776c06670e7caa941d8a723237fca11e96e3 100644 (file)
@@ -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;