diff options
author | Tobias Brunner <tobias@strongswan.org> | 2015-04-30 12:44:56 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2016-03-04 16:03:00 +0100 |
commit | c6ebd0332ec01ab50b4046874d111c942fc59b55 (patch) | |
tree | 6628b3f10cb9ef5930a7bdb8cf9ba190cd702e8f /src/libcharon | |
parent | 7505fb8d457983892b3cba049a4b6a8bae78b49d (diff) | |
download | strongswan-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')
-rw-r--r-- | src/libcharon/sa/ike_sa.c | 44 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa.h | 10 |
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 { |