ike: Delay actively initiated reauthentication when other exchanges in progress

If any other IKE or CHILD_SA operation takes places, we should not start
initiating reauthentication to avoid any potential races.
This commit is contained in:
Martin Willi
2014-04-17 09:59:06 +02:00
parent f02cabbe35
commit 0b3bea3965
@@ -46,11 +46,47 @@ METHOD(job_t, destroy, void,
free(this);
}
/**
* Check if we should delay a reauth, and by how many seconds
*/
static u_int32_t get_retry_delay(ike_sa_t *ike_sa)
{
enumerator_t *enumerator;
child_sa_t *child_sa;
u_int32_t retry = 0;
/* avoid reauth collisions for certain IKE_SA/CHILD_SA states */
if (ike_sa->get_state(ike_sa) != IKE_ESTABLISHED)
{
retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
DBG1(DBG_IKE, "unable to reauthenticate in %N state, delaying for %us",
ike_sa_state_names, ike_sa->get_state(ike_sa), retry);
}
else
{
enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
while (enumerator->enumerate(enumerator, &child_sa))
{
if (child_sa->get_state(child_sa) != CHILD_INSTALLED)
{
retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
DBG1(DBG_IKE, "unable to reauthenticate in CHILD_SA %N state, "
"delaying for %us", child_sa_state_names,
child_sa->get_state(child_sa), retry);
break;
}
}
enumerator->destroy(enumerator);
}
return retry;
}
METHOD(job_t, execute, job_requeue_t,
private_rekey_ike_sa_job_t *this)
{
ike_sa_t *ike_sa;
status_t status = SUCCESS;
u_int32_t retry = 0;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id);
@@ -62,7 +98,11 @@ METHOD(job_t, execute, job_requeue_t,
{
if (this->reauth)
{
status = ike_sa->reauth(ike_sa);
retry = get_retry_delay(ike_sa);
if (!retry)
{
status = ike_sa->reauth(ike_sa);
}
}
else
{
@@ -71,13 +111,18 @@ METHOD(job_t, execute, job_requeue_t,
if (status == DESTROY_ME)
{
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
ike_sa);
}
else
{
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
}
if (retry)
{
return JOB_RESCHEDULE(retry);
}
return JOB_REQUEUE_NONE;
}