diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/charon-tkm/src/tkm/tkm_kernel_ipsec.c | 4 | ||||
-rw-r--r-- | src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c | 4 | ||||
-rw-r--r-- | src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c | 9 | ||||
-rw-r--r-- | src/libcharon/plugins/load_tester/load_tester_ipsec.c | 4 | ||||
-rw-r--r-- | src/libcharon/sa/child_sa.c | 10 | ||||
-rw-r--r-- | src/libhydra/kernel/kernel_interface.c | 4 | ||||
-rw-r--r-- | src/libhydra/kernel/kernel_interface.h | 8 | ||||
-rw-r--r-- | src/libhydra/kernel/kernel_ipsec.h | 6 | ||||
-rw-r--r-- | src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c | 4 | ||||
-rw-r--r-- | src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c | 4 | ||||
-rw-r--r-- | src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c | 4 | ||||
-rw-r--r-- | src/libipsec/ip_packet.c | 6 | ||||
-rw-r--r-- | src/libipsec/ipsec_processor.c | 9 | ||||
-rw-r--r-- | src/libipsec/ipsec_sa.c | 102 | ||||
-rw-r--r-- | src/libipsec/ipsec_sa.h | 31 | ||||
-rw-r--r-- | src/libipsec/ipsec_sa_mgr.c | 31 | ||||
-rw-r--r-- | src/libipsec/ipsec_sa_mgr.h | 17 |
17 files changed, 216 insertions, 41 deletions
diff --git a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c index 1d070fd5f..72c247da5 100644 --- a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c +++ b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c @@ -217,7 +217,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_int32_t *time) + u_int64_t *packets, time_t *time) { return NOT_SUPPORTED; } @@ -271,7 +271,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t, private_tkm_kernel_ipsec_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - u_int32_t *use_time) + time_t *use_time) { return NOT_SUPPORTED; } diff --git a/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c b/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c index 98fa33d55..48f148770 100644 --- a/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c +++ b/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c @@ -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_int32_t *time) + u_int64_t *bytes, u_int64_t *packets, time_t *time) { return NOT_SUPPORTED; } @@ -118,7 +118,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t, private_kernel_android_ipsec_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - u_int32_t *use_time) + time_t *use_time) { return NOT_SUPPORTED; } diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c index 40f253d5a..9d95aa7fd 100644 --- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c @@ -226,7 +226,7 @@ static void expire(u_int32_t reqid, u_int8_t protocol, u_int32_t spi, bool hard) METHOD(kernel_ipsec_t, get_features, kernel_feature_t, private_kernel_libipsec_ipsec_t *this) { - return KERNEL_REQUIRE_UDP_ENCAPSULATION; + return KERNEL_REQUIRE_UDP_ENCAPSULATION | KERNEL_ESP_V3_TFC; } METHOD(kernel_ipsec_t, get_spi, status_t, @@ -268,9 +268,10 @@ METHOD(kernel_ipsec_t, update_sa, status_t, METHOD(kernel_ipsec_t, query_sa, status_t, private_kernel_libipsec_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_int32_t *time) + u_int64_t *packets, time_t *time) { - return NOT_SUPPORTED; + return ipsec->sas->query_sa(ipsec->sas, src, dst, spi, protocol, mark, + bytes, packets, time); } METHOD(kernel_ipsec_t, del_sa, status_t, @@ -555,7 +556,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t, private_kernel_libipsec_ipsec_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - u_int32_t *use_time) + time_t *use_time) { return NOT_SUPPORTED; } diff --git a/src/libcharon/plugins/load_tester/load_tester_ipsec.c b/src/libcharon/plugins/load_tester/load_tester_ipsec.c index bf08d2c9c..02b1d4216 100644 --- a/src/libcharon/plugins/load_tester/load_tester_ipsec.c +++ b/src/libcharon/plugins/load_tester/load_tester_ipsec.c @@ -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_int32_t *time) + u_int64_t *bytes, u_int64_t *packets, time_t *time) { return NOT_SUPPORTED; } @@ -95,7 +95,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t, private_load_tester_ipsec_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - u_int32_t *use_time) + time_t *use_time) { *use_time = 1; return SUCCESS; diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c index 9bd0c05ad..9c3876a94 100644 --- a/src/libcharon/sa/child_sa.c +++ b/src/libcharon/sa/child_sa.c @@ -167,12 +167,12 @@ struct private_child_sa_t { /** * time of last use in seconds (inbound) */ - u_int32_t my_usetime; + time_t my_usetime; /** * time of last use in seconds (outbound) */ - u_int32_t other_usetime; + time_t other_usetime; /** * last number of inbound bytes @@ -429,7 +429,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; + time_t time; if (inbound) { @@ -489,12 +489,12 @@ static bool update_usetime(private_child_sa_t *this, bool inbound) { enumerator_t *enumerator; traffic_selector_t *my_ts, *other_ts; - u_int32_t last_use = 0; + time_t last_use = 0; enumerator = create_policy_enumerator(this); while (enumerator->enumerate(enumerator, &my_ts, &other_ts)) { - u_int32_t in, out, fwd; + time_t in, out, fwd; if (inbound) { diff --git a/src/libhydra/kernel/kernel_interface.c b/src/libhydra/kernel/kernel_interface.c index 68a8c3ec1..cbfddd03b 100644 --- a/src/libhydra/kernel/kernel_interface.c +++ b/src/libhydra/kernel/kernel_interface.c @@ -208,7 +208,7 @@ 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_int32_t *time) + u_int64_t *bytes, u_int64_t *packets, time_t *time) { if (!this->ipsec) { @@ -256,7 +256,7 @@ METHOD(kernel_interface_t, add_policy, status_t, METHOD(kernel_interface_t, query_policy, status_t, private_kernel_interface_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - u_int32_t *use_time) + time_t *use_time) { if (!this->ipsec) { diff --git a/src/libhydra/kernel/kernel_interface.h b/src/libhydra/kernel/kernel_interface.h index 1d96f1c35..cc47d3c4a 100644 --- a/src/libhydra/kernel/kernel_interface.h +++ b/src/libhydra/kernel/kernel_interface.h @@ -200,12 +200,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 + * @param[out] time last (monotonic) 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_int32_t *time); + u_int64_t *bytes, u_int64_t *packets, time_t *time); /** * Delete a previously installed SA from the SAD. @@ -264,14 +264,14 @@ struct kernel_interface_t { * @param dst_ts traffic selector to match traffic dest * @param direction direction of traffic, POLICY_(IN|OUT|FWD) * @param mark optional mark - * @param[out] use_time the time of this SA's last use + * @param[out] use_time the (monotonic) time of this SA's last use * @return SUCCESS if operation completed */ status_t (*query_policy) (kernel_interface_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - u_int32_t *use_time); + time_t *use_time); /** * Remove a policy from the SPD. diff --git a/src/libhydra/kernel/kernel_ipsec.h b/src/libhydra/kernel/kernel_ipsec.h index 413e5920f..25f5b38fd 100644 --- a/src/libhydra/kernel/kernel_ipsec.h +++ b/src/libhydra/kernel/kernel_ipsec.h @@ -156,12 +156,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 + * @param[out] time last (monotonic) 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_int32_t *time); + u_int64_t *bytes, u_int64_t *packets, time_t *time); /** * Delete a previusly installed SA from the SAD. @@ -228,7 +228,7 @@ struct kernel_ipsec_t { traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - u_int32_t *use_time); + time_t *use_time); /** * Remove a policy from the SPD. diff --git a/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c b/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c index 82f80fd4c..a226162c3 100644 --- a/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c +++ b/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c @@ -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_int32_t *time) + u_int64_t *bytes, u_int64_t *packets, time_t *time) { return NOT_SUPPORTED; /* TODO */ } @@ -2207,7 +2207,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t, private_kernel_klips_ipsec_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - u_int32_t *use_time) + time_t *use_time) { #define IDLE_PREFIX "idle=" static const char *path_eroute = "/proc/net/ipsec_eroute"; diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index e06c8eaa9..e23f22023 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1611,7 +1611,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_int32_t *time) + u_int64_t *bytes, u_int64_t *packets, time_t *time) { netlink_buf_t request; struct nlmsghdr *out = NULL, *hdr; @@ -2302,7 +2302,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t, private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - u_int32_t *use_time) + time_t *use_time) { netlink_buf_t request; struct nlmsghdr *out = NULL, *hdr; diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c index 668c581e1..feff3a753 100644 --- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c +++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c @@ -1802,7 +1802,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_int32_t *time) + u_int64_t *bytes, u_int64_t *packets, time_t *time) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; @@ -2382,7 +2382,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t, METHOD(kernel_ipsec_t, query_policy, status_t, private_kernel_pfkey_ipsec_t *this, traffic_selector_t *src_ts, traffic_selector_t *dst_ts, policy_dir_t direction, mark_t mark, - u_int32_t *use_time) + time_t *use_time) { unsigned char request[PFKEY_BUFFER_SIZE]; struct sadb_msg *msg, *out; diff --git a/src/libipsec/ip_packet.c b/src/libipsec/ip_packet.c index 41e364379..ede9d100a 100644 --- a/src/libipsec/ip_packet.c +++ b/src/libipsec/ip_packet.c @@ -139,6 +139,9 @@ ip_packet_t *ip_packet_create(chunk_t packet) goto failed; } ip = (struct ip*)packet.ptr; + /* remove any RFC 4303 TFC extra padding */ + packet.len = min(packet.len, untoh16(&ip->ip_len)); + src = host_create_from_chunk(AF_INET, chunk_from_thing(ip->ip_src), 0); dst = host_create_from_chunk(AF_INET, @@ -157,6 +160,9 @@ ip_packet_t *ip_packet_create(chunk_t packet) goto failed; } ip = (struct ip6_hdr*)packet.ptr; + /* remove any RFC 4303 TFC extra padding */ + packet.len = min(packet.len, untoh16(&ip->ip6_plen)); + src = host_create_from_chunk(AF_INET6, chunk_from_thing(ip->ip6_src), 0); dst = host_create_from_chunk(AF_INET6, diff --git a/src/libipsec/ipsec_processor.c b/src/libipsec/ipsec_processor.c index eae2ed2f1..ee297a34b 100644 --- a/src/libipsec/ipsec_processor.c +++ b/src/libipsec/ipsec_processor.c @@ -91,6 +91,7 @@ static void deliver_inbound(private_ipsec_processor_t *this, static job_requeue_t process_inbound(private_ipsec_processor_t *this) { esp_packet_t *packet; + ip_packet_t *ip_packet; ipsec_sa_t *sa; u_int8_t next_header; u_int32_t spi, reqid; @@ -126,6 +127,8 @@ static job_requeue_t process_inbound(private_ipsec_processor_t *this) packet->destroy(packet); return JOB_REQUEUE_DIRECT; } + ip_packet = packet->get_payload(packet); + sa->update_usestats(sa, ip_packet->get_encoding(ip_packet).len); reqid = sa->get_reqid(sa); ipsec->sas->checkin(ipsec->sas, sa); @@ -136,13 +139,11 @@ static job_requeue_t process_inbound(private_ipsec_processor_t *this) case IPPROTO_IPV6: { ipsec_policy_t *policy; - ip_packet_t *ip_packet; - ip_packet = packet->get_payload(packet); policy = ipsec->policies->find_by_packet(ipsec->policies, ip_packet, TRUE, reqid); if (policy) - { /* TODO-IPSEC: update policy/sa stats? */ + { deliver_inbound(this, packet); policy->destroy(policy); break; @@ -225,7 +226,7 @@ static job_requeue_t process_outbound(private_ipsec_processor_t *this) policy->destroy(policy); return JOB_REQUEUE_DIRECT; } - /* TODO-IPSEC: update policy/sa counters? */ + sa->update_usestats(sa, packet->get_encoding(packet).len); ipsec->sas->checkin(ipsec->sas, sa); policy->destroy(policy); send_outbound(this, esp_packet); diff --git a/src/libipsec/ipsec_sa.c b/src/libipsec/ipsec_sa.c index 2ff5cff55..6ec8bd25e 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 <library.h> @@ -81,6 +82,28 @@ struct private_ipsec_sa_t { * ESP context */ esp_context_t *esp_context; + + /** + * Usage statistics + */ + struct { + /** last time of use */ + time_t time; + /** number of packets processed */ + u_int64_t packets; + /** 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*, @@ -145,10 +168,81 @@ METHOD(ipsec_sa_t, get_esp_context, esp_context_t*, return this->esp_context; } +METHOD(ipsec_sa_t, get_usestats, void, + private_ipsec_sa_t *this, u_int64_t *bytes, u_int64_t *packets, + time_t *time) +{ + if (bytes) + { + *bytes = this->use.bytes; + } + if (packets) + { + *packets = this->use.packets; + } + if (time) + { + *time = this->use.time; + } +} + +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, @@ -161,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, @@ -227,6 +322,9 @@ ipsec_sa_t *ipsec_sa_create(u_int32_t spi, host_t *src, host_t *dst, .match_by_spi_src_dst = _match_by_spi_src_dst, .match_by_reqid = _match_by_reqid, .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 dec688e68..5e69f18cf 100644 --- a/src/libipsec/ipsec_sa.h +++ b/src/libipsec/ipsec_sa.h @@ -110,8 +110,37 @@ struct ipsec_sa_t { esp_context_t *(*get_esp_context)(ipsec_sa_t *this); /** + * Get usage statistics for this SA. + * + * @param bytes receives number of processed bytes, or NULL + * @param packets receives number of processed packets, or NULL + * @param time receives last use time of this SA, or NULL + */ + void (*get_usestats)(ipsec_sa_t *this, u_int64_t *bytes, u_int64_t *packets, + time_t *time); + + /** + * Record en/decryption of a packet to update usage statistics. + * + * @param bytes length of packet processed + */ + 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 @@ -132,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 928a53d50..1db1776c0 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; @@ -530,6 +528,28 @@ METHOD(ipsec_sa_mgr_t, update_sa, status_t, return SUCCESS; } +METHOD(ipsec_sa_mgr_t, query_sa, status_t, + private_ipsec_sa_mgr_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, time_t *time) +{ + ipsec_sa_entry_t *entry = NULL; + + this->mutex->lock(this->mutex); + if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst, + (void**)&entry, &spi, src, dst) == SUCCESS && + wait_for_entry(this, entry)) + { + entry->sa->get_usestats(entry->sa, bytes, packets, time); + /* checkin the entry */ + entry->locked = FALSE; + entry->condvar->signal(entry->condvar); + } + this->mutex->unlock(this->mutex); + + return entry ? SUCCESS : NOT_FOUND; +} + METHOD(ipsec_sa_mgr_t, del_sa, status_t, private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int32_t spi, u_int8_t protocol, u_int16_t cpi, mark_t mark) @@ -653,6 +673,7 @@ ipsec_sa_mgr_t *ipsec_sa_mgr_create() .get_spi = _get_spi, .add_sa = _add_sa, .update_sa = _update_sa, + .query_sa = _query_sa, .del_sa = _del_sa, .checkout_by_spi = _checkout_by_spi, .checkout_by_reqid = _checkout_by_reqid, diff --git a/src/libipsec/ipsec_sa_mgr.h b/src/libipsec/ipsec_sa_mgr.h index e9ce5ee8f..8c234cefa 100644 --- a/src/libipsec/ipsec_sa_mgr.h +++ b/src/libipsec/ipsec_sa_mgr.h @@ -109,6 +109,23 @@ struct ipsec_sa_mgr_t { bool encap, bool new_encap, mark_t mark); /** + * Query the number of bytes processed by an SA from the SAD. + * + * @param src source address for this SA + * @param dst destination address for this SA + * @param spi SPI allocated by us or remote peer + * @param protocol protocol for this SA (ESP/AH) + * @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 (monotonic) time of SA use + * @return SUCCESS if operation completed + */ + status_t (*query_sa)(ipsec_sa_mgr_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, time_t *time); + + /** * Delete a previously added SA * * @param spi SPI of the SA |