"ESTABLISHED",
"PASSIVE",
"REKEYING",
+ "REKEYED",
"DELETING",
"DESTROYING",
);
reestablish(this);
break;
}
- if (this->state != IKE_CONNECTING)
+ if (this->state != IKE_CONNECTING &&
+ this->state != IKE_REKEYED)
{
charon->bus->ike_updown(charon->bus, &this->public, FALSE);
}
case IKE_DELETING:
case IKE_DESTROYING:
case IKE_PASSIVE:
+ case IKE_REKEYED:
return SUCCESS;
default:
break;
*/
IKE_REKEYING,
+ /**
+ * IKE_SA has been rekeyed (or is redundant)
+ */
+ IKE_REKEYED,
+
/**
* IKE_SA is in progress of deletion
*/
{
continue;
}
- if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING)
+ if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING ||
+ entry->ike_sa->get_state(entry->ike_sa) == IKE_REKEYED)
{ /* skip IKE_SAs which are not usable, wake other waiting threads */
entry->condvar->signal(entry->condvar);
continue;
break;
}
case IKE_REKEYING:
+ case IKE_REKEYED:
if (activate_task(this, TASK_IKE_DELETE))
{
exchange = INFORMATIONAL;
case FAILED:
default:
this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
- if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING)
+ if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING &&
+ this->ike_sa->get_state(this->ike_sa) != IKE_REKEYED)
{
charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
}
payload_t *payload;
notify_payload_t *notify;
delete_payload_t *delete;
+ ike_sa_state_t state;
if (array_count(this->passive_tasks) == 0)
{ /* create tasks depending on request type, if not already some queued */
+ state = this->ike_sa->get_state(this->ike_sa);
switch (message->get_exchange_type(message))
{
case IKE_SA_INIT:
{ /* FIXME: we should prevent this on mediation connections */
bool notify_found = FALSE, ts_found = FALSE;
- if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED ||
- this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING)
+ if (state == IKE_CREATED ||
+ state == IKE_CONNECTING)
{
DBG1(DBG_IKE, "received CREATE_CHILD_SA request for "
"unestablished IKE_SA, rejected");
case PLV2_NOTIFY:
{
notify = (notify_payload_t*)payload;
+ if (state == IKE_REKEYED)
+ {
+ DBG1(DBG_IKE, "received unexpected notify %N "
+ "for rekeyed IKE_SA, ignored",
+ notify_type_names,
+ notify->get_notify_type(notify));
+ break;
+ }
switch (notify->get_notify_type(notify))
{
case ADDITIONAL_IP4_ADDRESS:
status_t status;
uint32_t mid;
bool schedule_delete_job = FALSE;
+ ike_sa_state_t state;
+ exchange_type_t type;
charon->bus->message(charon->bus, msg, TRUE, FALSE);
status = parse_message(this, msg);
{
if (mid == this->responding.mid)
{
- /* reject initial messages if not received in specific states */
- if ((msg->get_exchange_type(msg) == IKE_SA_INIT &&
- this->ike_sa->get_state(this->ike_sa) != IKE_CREATED) ||
- (msg->get_exchange_type(msg) == IKE_AUTH &&
- this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING))
+ /* reject initial messages if not received in specific states,
+ * after rekeying we only expect a DELETE in an INFORMATIONAL */
+ type = msg->get_exchange_type(msg);
+ state = this->ike_sa->get_state(this->ike_sa);
+ if ((type == IKE_SA_INIT && state != IKE_CREATED) ||
+ (type == IKE_AUTH && state != IKE_CONNECTING) ||
+ (state == IKE_REKEYED && type != INFORMATIONAL))
{
DBG1(DBG_IKE, "ignoring %N in IKE_SA state %N",
- exchange_type_names, msg->get_exchange_type(msg),
- ike_sa_state_names, this->ike_sa->get_state(this->ike_sa));
+ exchange_type_names, type, ike_sa_state_names, state);
return FAILED;
}
if (!this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE))
delete_payload = delete_payload_create(PLV2_DELETE, PROTO_IKE);
message->add_payload(message, (payload_t*)delete_payload);
- if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING)
+ if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING ||
+ this->ike_sa->get_state(this->ike_sa) == IKE_REKEYED)
{
this->rekeyed = TRUE;
}
switch (this->ike_sa->get_state(this->ike_sa))
{
+ case IKE_REKEYING:
case IKE_ESTABLISHED:
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
this->ike_sa->reestablish(this->ike_sa);
return NEED_MORE;
- case IKE_REKEYING:
+ case IKE_REKEYED:
this->rekeyed = TRUE;
break;
case IKE_DELETING:
job = (job_t*)initiate_tasks_job_create(ike_sa->get_id(ike_sa));
}
enumerator->destroy(enumerator);
-
return job;
}
}
this->new_sa = NULL;
charon->bus->set_sa(charon->bus, this->ike_sa);
- }
-}
-
-METHOD(task_t, process_r_delete, status_t,
- private_ike_rekey_t *this, message_t *message)
-{
- return this->ike_delete->task.process(&this->ike_delete->task, message);
-}
-METHOD(task_t, build_r_delete, status_t,
- private_ike_rekey_t *this, message_t *message)
-{
- return this->ike_delete->task.build(&this->ike_delete->task, message);
+ this->ike_sa->set_state(this->ike_sa, IKE_REKEYED);
+ }
}
METHOD(task_t, build_i_delete, status_t,
if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING)
{ /* in case of a collision we let the initiating task handle this */
establish_new(this);
- this->ike_sa->set_state(this->ike_sa, IKE_REKEYING);
+ /* make sure the IKE_SA is gone in case the peer fails to delete it */
+ lib->scheduler->schedule_job(lib->scheduler, (job_t*)
+ delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE),
+ 90);
}
-
- /* rekeying successful, delete the IKE_SA using a subtask */
- this->ike_delete = ike_delete_create(this->ike_sa, FALSE);
- this->public.task.build = _build_r_delete;
- this->public.task.process = _process_r_delete;
-
- /* the peer does have to delete the IKE_SA. If it does not, we get a
- * unusable IKE_SA in REKEYING state without a replacement. We consider
- * this a timeout condition by the peer, and trigger a delete actively. */
- lib->scheduler->schedule_job(lib->scheduler, (job_t*)
- delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE), 90);
-
- return NEED_MORE;
+ return SUCCESS;
}
METHOD(task_t, process_i, status_t,
/* peer should delete this SA. Add a timeout just in case. */
job_t *job = (job_t*)delete_ike_sa_job_create(
other->new_sa->get_id(other->new_sa), TRUE);
- lib->scheduler->schedule_job(lib->scheduler, job, 10);
+ lib->scheduler->schedule_job(lib->scheduler, job,
+ HALF_OPEN_IKE_SA_TIMEOUT);
DBG1(DBG_IKE, "IKE_SA rekey collision won, waiting for delete "
"for redundant IKE_SA %s[%d]",
other->new_sa->get_name(other->new_sa),
other->new_sa->get_unique_id(other->new_sa));
+ other->new_sa->set_state(other->new_sa, IKE_REKEYED);
charon->ike_sa_manager->checkin(charon->ike_sa_manager,
other->new_sa);
other->new_sa = NULL;
this->new_sa->set_my_host(this->new_sa, host->clone(host));
host = this->ike_sa->get_other_host(this->ike_sa);
this->new_sa->set_other_host(this->new_sa, host->clone(host));
- this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
+ /* IKE_SAs in state IKE_REKEYED are silently deleted, so we use
+ * IKE_REKEYING */
this->new_sa->set_state(this->new_sa, IKE_REKEYING);
if (this->new_sa->delete(this->new_sa) == DESTROY_ME)
{
assert_hook_rekey(ike_rekey, 1, 3);
assert_no_notify(IN, REKEY_SA);
exchange_test_helper->process_message(exchange_test_helper, b, NULL);
- assert_ike_sa_state(b, IKE_REKEYING);
+ assert_ike_sa_state(b, IKE_REKEYED);
assert_child_sa_count(b, 0);
new_sa = assert_ike_sa_checkout(3, 4, FALSE);
assert_ike_sa_state(new_sa, IKE_ESTABLISHED);