ike-sa: Add limit for the number of redirects within a defined time period

This commit is contained in:
Tobias Brunner 2015-04-30 12:44:56 +02:00
parent 7505fb8d45
commit c6ebd0332e
2 changed files with 54 additions and 0 deletions

View File

@ -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);

View File

@ -65,6 +65,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
*/