kernel-interface: query SAD for last use time if SPD query didn't yield one
authorMartin Willi <martin@revosec.ch>
Sun, 21 Apr 2013 15:05:08 +0000 (17:05 +0200)
committerMartin Willi <martin@revosec.ch>
Mon, 6 May 2013 15:01:13 +0000 (17:01 +0200)
src/charon-tkm/src/tkm/tkm_kernel_ipsec.c
src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c
src/libcharon/plugins/load_tester/load_tester_ipsec.c
src/libcharon/sa/child_sa.c
src/libhydra/kernel/kernel_interface.c
src/libhydra/kernel/kernel_interface.h
src/libhydra/kernel/kernel_ipsec.h
src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c
src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c

index 69aefea..a276166 100644 (file)
@@ -216,7 +216,7 @@ sad_failure:
 METHOD(kernel_ipsec_t, query_sa, status_t,
        private_tkm_kernel_ipsec_t *this, host_t *src, host_t *dst,
        u_int32_t spi, u_int8_t protocol, mark_t mark, u_int64_t *bytes,
-       u_int64_t *packets)
+       u_int64_t *packets, u_int32_t *time)
 {
        return NOT_SUPPORTED;
 }
index 8e85341..c37ca26 100644 (file)
@@ -86,7 +86,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 METHOD(kernel_ipsec_t, query_sa, status_t,
        private_kernel_android_ipsec_t *this, host_t *src, host_t *dst,
        u_int32_t spi, u_int8_t protocol, mark_t mark,
-       u_int64_t *bytes, u_int64_t *packets)
+       u_int64_t *bytes, u_int64_t *packets, u_int32_t *time)
 {
        return NOT_SUPPORTED;
 }
index 4f84845..49e35c4 100644 (file)
@@ -71,7 +71,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 METHOD(kernel_ipsec_t, query_sa, status_t,
        private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
        u_int32_t spi, u_int8_t protocol, mark_t mark,
-       u_int64_t *bytes, u_int64_t *packets)
+       u_int64_t *bytes, u_int64_t *packets, u_int32_t *time)
 {
        return NOT_SUPPORTED;
 }
index 5861fe3..34435a1 100644 (file)
@@ -424,6 +424,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
 {
        status_t status = FAILED;
        u_int64_t bytes, packets;
+       u_int32_t time;
 
        if (inbound)
        {
@@ -432,13 +433,17 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
                        status = hydra->kernel_interface->query_sa(hydra->kernel_interface,
                                                        this->other_addr, this->my_addr, this->my_spi,
                                                        proto_ike2ip(this->protocol), this->mark_in,
-                                                       &bytes, &packets);
+                                                       &bytes, &packets, &time);
                        if (status == SUCCESS)
                        {
                                if (bytes > this->my_usebytes)
                                {
                                        this->my_usebytes = bytes;
                                        this->my_usepackets = packets;
+                                       if (time)
+                                       {
+                                               this->my_usetime = time;
+                                       }
                                        return SUCCESS;
                                }
                                return FAILED;
@@ -452,13 +457,17 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
                        status = hydra->kernel_interface->query_sa(hydra->kernel_interface,
                                                        this->my_addr, this->other_addr, this->other_spi,
                                                        proto_ike2ip(this->protocol), this->mark_out,
-                                                       &bytes, &packets);
+                                                       &bytes, &packets, &time);
                        if (status == SUCCESS)
                        {
                                if (bytes > this->other_usebytes)
                                {
                                        this->other_usebytes = bytes;
                                        this->other_usepackets = packets;
+                                       if (time)
+                                       {
+                                               this->other_usetime = time;
+                                       }
                                        return SUCCESS;
                                }
                                return FAILED;
@@ -471,7 +480,7 @@ static status_t update_usebytes(private_child_sa_t *this, bool inbound)
 /**
  * updates the cached usetime
  */
-static void update_usetime(private_child_sa_t *this, bool inbound)
+static bool update_usetime(private_child_sa_t *this, bool inbound)
 {
        enumerator_t *enumerator;
        traffic_selector_t *my_ts, *other_ts;
@@ -511,7 +520,7 @@ static void update_usetime(private_child_sa_t *this, bool inbound)
 
        if (last_use == 0)
        {
-               return;
+               return FALSE;
        }
        if (inbound)
        {
@@ -521,6 +530,7 @@ static void update_usetime(private_child_sa_t *this, bool inbound)
        {
                this->other_usetime = last_use;
        }
+       return TRUE;
 }
 
 METHOD(child_sa_t, get_usestats, void,
@@ -534,7 +544,11 @@ METHOD(child_sa_t, get_usestats, void,
                 */
                if (time)
                {
-                       update_usetime(this, inbound);
+                       if (!update_usetime(this, inbound) && !bytes && !packets)
+                       {
+                               /* if policy query did not yield a usetime, query SAs instead */
+                               update_usebytes(this, inbound);
+                       }
                }
        }
        if (time)
index 290c25a..d81fa33 100644 (file)
@@ -208,14 +208,14 @@ METHOD(kernel_interface_t, update_sa, status_t,
 METHOD(kernel_interface_t, query_sa, status_t,
        private_kernel_interface_t *this, host_t *src, host_t *dst,
        u_int32_t spi, u_int8_t protocol, mark_t mark,
-       u_int64_t *bytes, u_int64_t *packets)
+       u_int64_t *bytes, u_int64_t *packets, u_int32_t *time)
 {
        if (!this->ipsec)
        {
                return NOT_SUPPORTED;
        }
        return this->ipsec->query_sa(this->ipsec, src, dst, spi, protocol, mark,
-                                                                bytes, packets);
+                                                                bytes, packets, time);
 }
 
 METHOD(kernel_interface_t, del_sa, status_t,
index fd64f50..b333cae 100644 (file)
@@ -197,11 +197,12 @@ struct kernel_interface_t {
         * @param mark                  optional mark for this SA
         * @param[out] bytes    the number of bytes processed by SA
         * @param[out] packets  number of packets processed by SA
+        * @param[out] time             last time of SA use
         * @return                              SUCCESS if operation completed
         */
        status_t (*query_sa) (kernel_interface_t *this, host_t *src, host_t *dst,
                                                  u_int32_t spi, u_int8_t protocol, mark_t mark,
-                                                 u_int64_t *bytes, u_int64_t *packets);
+                                                 u_int64_t *bytes, u_int64_t *packets, u_int32_t *time);
 
        /**
         * Delete a previously installed SA from the SAD.
index ba67238..f61f3c3 100644 (file)
@@ -155,11 +155,12 @@ struct kernel_ipsec_t {
         * @param mark                  optional mark for this SA
         * @param[out] bytes    the number of bytes processed by SA
         * @param[out] packets  number of packets processed by SA
+        * @param[out] time             last time of SA use
         * @return                              SUCCESS if operation completed
         */
        status_t (*query_sa) (kernel_ipsec_t *this, host_t *src, host_t *dst,
                                                  u_int32_t spi, u_int8_t protocol, mark_t mark,
-                                                 u_int64_t *bytes, u_int64_t *packets);
+                                                 u_int64_t *bytes, u_int64_t *packets, u_int32_t *time);
 
        /**
         * Delete a previusly installed SA from the SAD.
index 2d09d33..32bea73 100644 (file)
@@ -1911,7 +1911,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 METHOD(kernel_ipsec_t, query_sa, status_t,
        private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
        u_int32_t spi, u_int8_t protocol, mark_t mark,
-       u_int64_t *bytes, u_int64_t *packets)
+       u_int64_t *bytes, u_int64_t *packets, u_int32_t *time)
 {
        return NOT_SUPPORTED;  /* TODO */
 }
index b30c953..58bce62 100644 (file)
@@ -1595,7 +1595,7 @@ static void get_replay_state(private_kernel_netlink_ipsec_t *this,
 METHOD(kernel_ipsec_t, query_sa, status_t,
        private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
        u_int32_t spi, u_int8_t protocol, mark_t mark,
-       u_int64_t *bytes, u_int64_t *packets)
+       u_int64_t *bytes, u_int64_t *packets, u_int32_t *time)
 {
        netlink_buf_t request;
        struct nlmsghdr *out = NULL, *hdr;
@@ -1680,6 +1680,12 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
                {
                        *packets = sa->curlft.packets;
                }
+               if (time)
+               {       /* curlft contains an "use" time, but that contains a timestamp
+                        * of the first use, not the last. Last use time must be queried
+                        * on the policy on Linux */
+                       *time = 0;
+               }
                status = SUCCESS;
        }
        memwipe(out, len);
index 3ade6f4..ecab282 100644 (file)
@@ -1804,7 +1804,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
 METHOD(kernel_ipsec_t, query_sa, status_t,
        private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
        u_int32_t spi, u_int8_t protocol, mark_t mark,
-       u_int64_t *bytes, u_int64_t *packets)
+       u_int64_t *bytes, u_int64_t *packets, u_int32_t *time)
 {
        unsigned char request[PFKEY_BUFFER_SIZE];
        struct sadb_msg *msg, *out;
@@ -1862,6 +1862,18 @@ METHOD(kernel_ipsec_t, query_sa, status_t,
                /* not supported by PF_KEY */
                *packets = 0;
        }
+       if (time)
+       {
+#ifdef __APPLE__
+               /* OS X uses the "last" time of use in usetime */
+               *time = response.lft_current->sadb_lifetime_usetime;
+#else /* !__APPLE__ */
+               /* on Linux, sadb_lifetime_usetime is set to the "first" time of use,
+                * which is actually correct according to PF_KEY. We have to query
+                * policies for the last usetime. */
+               *time = 0;
+#endif /* !__APPLE__ */
+       }
 
        free(out);
        return SUCCESS;
@@ -2435,7 +2447,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
        }
        else if (response.lft_current == NULL)
        {
-               DBG1(DBG_KNL, "unable to query policy %R === %R %N: kernel reports no "
+               DBG2(DBG_KNL, "unable to query policy %R === %R %N: kernel reports no "
                                          "use time", src_ts, dst_ts, policy_dir_names, direction);
                free(out);
                return FAILED;