aboutsummaryrefslogtreecommitdiffstats
path: root/src/libcharon/sa
diff options
context:
space:
mode:
authorTobias Brunner <tobias@strongswan.org>2015-04-30 12:44:56 +0200
committerTobias Brunner <tobias@strongswan.org>2016-03-04 16:03:00 +0100
commitc6ebd0332ec01ab50b4046874d111c942fc59b55 (patch)
tree6628b3f10cb9ef5930a7bdb8cf9ba190cd702e8f /src/libcharon/sa
parent7505fb8d457983892b3cba049a4b6a8bae78b49d (diff)
downloadstrongswan-c6ebd0332ec01ab50b4046874d111c942fc59b55.tar.bz2
strongswan-c6ebd0332ec01ab50b4046874d111c942fc59b55.tar.xz
ike-sa: Add limit for the number of redirects within a defined time period
Diffstat (limited to 'src/libcharon/sa')
-rw-r--r--src/libcharon/sa/ike_sa.c44
-rw-r--r--src/libcharon/sa/ike_sa.h10
2 files changed, 54 insertions, 0 deletions
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index f5245417e..b07ff0e74 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -294,6 +294,11 @@ struct private_ike_sa_t {
* Original gateway address from which we got redirected
*/
host_t *redirected_from;
+
+ /**
+ * Timestamps of redirect attempts to handle loops
+ */
+ array_t *redirected_at;
};
/**
@@ -2020,6 +2025,7 @@ static bool redirect_established(private_ike_sa_t *this, identification_t *to)
private_ike_sa_t *new_priv;
ike_sa_t *new;
host_t *other;
+ time_t redirect;
new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
this->version, TRUE);
@@ -2039,6 +2045,11 @@ static bool redirect_established(private_ike_sa_t *this, identification_t *to)
* resolve the local address */
new_priv->remote_host = other;
resolve_hosts(new_priv);
+ new_priv->redirected_at = array_create(sizeof(time_t), MAX_REDIRECTS);
+ while (array_remove(this->redirected_at, ARRAY_HEAD, &redirect))
+ {
+ array_insert(new_priv->redirected_at, ARRAY_TAIL, &redirect);
+ }
if (reestablish_children(this, new, TRUE) != DESTROY_ME)
{
#ifdef USE_IKEV2
@@ -2082,6 +2093,32 @@ static bool redirect_connecting(private_ike_sa_t *this, identification_t *to)
return TRUE;
}
+/**
+ * Check if the current redirect exceeds the limits for redirects
+ */
+static bool redirect_count_exceeded(private_ike_sa_t *this)
+{
+ time_t now, redirect;
+
+ now = time_monotonic(NULL);
+ /* remove entries outside the defined period */
+ while (array_get(this->redirected_at, ARRAY_HEAD, &redirect) &&
+ now - redirect >= REDIRECT_LOOP_DETECT_PERIOD)
+ {
+ array_remove(this->redirected_at, ARRAY_HEAD, NULL);
+ }
+ if (array_count(this->redirected_at) < MAX_REDIRECTS)
+ {
+ if (!this->redirected_at)
+ {
+ this->redirected_at = array_create(sizeof(time_t), MAX_REDIRECTS);
+ }
+ array_insert(this->redirected_at, ARRAY_TAIL, &now);
+ return FALSE;
+ }
+ return TRUE;
+}
+
METHOD(ike_sa_t, handle_redirect, bool,
private_ike_sa_t *this, identification_t *gateway)
{
@@ -2091,6 +2128,12 @@ METHOD(ike_sa_t, handle_redirect, bool,
DBG1(DBG_IKE, "server sent REDIRECT even though we disabled it");
return FALSE;
}
+ if (redirect_count_exceeded(this))
+ {
+ DBG1(DBG_IKE, "only %d redirects are allowed within %d seconds",
+ MAX_REDIRECTS, REDIRECT_LOOP_DETECT_PERIOD);
+ return FALSE;
+ }
switch (this->state)
{
@@ -2658,6 +2701,7 @@ METHOD(ike_sa_t, destroy, void,
DESTROY_IF(this->local_host);
DESTROY_IF(this->remote_host);
DESTROY_IF(this->redirected_from);
+ array_destroy(this->redirected_at);
DESTROY_IF(this->ike_cfg);
DESTROY_IF(this->peer_cfg);
diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h
index 08c19971f..158a690df 100644
--- a/src/libcharon/sa/ike_sa.h
+++ b/src/libcharon/sa/ike_sa.h
@@ -66,6 +66,16 @@ typedef struct ike_sa_t ike_sa_t;
#define RETRY_JITTER 20
/**
+ * Number of redirects allowed within REDIRECT_LOOP_DETECT_PERIOD.
+ */
+#define MAX_REDIRECTS 5
+
+/**
+ * Time period in seconds in which at most MAX_REDIRECTS are allowed.
+ */
+#define REDIRECT_LOOP_DETECT_PERIOD 300
+
+/**
* Extensions (or optional features) the peer supports
*/
enum ike_extension_t {