fixed some exchange collisions (except IKE/CHILD rekeying)
This commit is contained in:
+53
-29
@@ -448,39 +448,57 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
|
|||||||
ike_sa_state_names, this->state,
|
ike_sa_state_names, this->state,
|
||||||
ike_sa_state_names, state);
|
ike_sa_state_names, state);
|
||||||
|
|
||||||
if (state == IKE_ESTABLISHED)
|
switch (state)
|
||||||
{
|
{
|
||||||
job_t *job;
|
case IKE_ESTABLISHED:
|
||||||
u_int32_t now = time(NULL);
|
|
||||||
u_int32_t soft, hard;
|
|
||||||
bool reauth;
|
|
||||||
|
|
||||||
this->time.established = now;
|
|
||||||
/* start DPD checks */
|
|
||||||
send_dpd(this);
|
|
||||||
|
|
||||||
/* schedule rekeying/reauthentication */
|
|
||||||
soft = this->connection->get_soft_lifetime(this->connection);
|
|
||||||
hard = this->connection->get_hard_lifetime(this->connection);
|
|
||||||
reauth = this->connection->get_reauth(this->connection);
|
|
||||||
DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds",
|
|
||||||
reauth ? "reauthentication": "rekeying", soft, hard);
|
|
||||||
|
|
||||||
if (soft)
|
|
||||||
{
|
{
|
||||||
this->time.rekey = now + soft;
|
if (this->state == IKE_CONNECTING)
|
||||||
job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
|
{
|
||||||
charon->event_queue->add_relative(charon->event_queue, job,
|
job_t *job;
|
||||||
soft * 1000);
|
u_int32_t now = time(NULL);
|
||||||
}
|
u_int32_t soft, hard;
|
||||||
|
bool reauth;
|
||||||
|
|
||||||
if (hard)
|
this->time.established = now;
|
||||||
{
|
/* start DPD checks */
|
||||||
this->time.delete = now + hard;
|
send_dpd(this);
|
||||||
job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
|
|
||||||
charon->event_queue->add_relative(charon->event_queue, job,
|
/* schedule rekeying/reauthentication */
|
||||||
hard * 1000);
|
soft = this->connection->get_soft_lifetime(this->connection);
|
||||||
|
hard = this->connection->get_hard_lifetime(this->connection);
|
||||||
|
reauth = this->connection->get_reauth(this->connection);
|
||||||
|
DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds",
|
||||||
|
reauth ? "reauthentication": "rekeying", soft, hard);
|
||||||
|
|
||||||
|
if (soft)
|
||||||
|
{
|
||||||
|
this->time.rekey = now + soft;
|
||||||
|
job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
|
||||||
|
charon->event_queue->add_relative(charon->event_queue, job,
|
||||||
|
soft * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hard)
|
||||||
|
{
|
||||||
|
this->time.delete = now + hard;
|
||||||
|
job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
|
||||||
|
charon->event_queue->add_relative(charon->event_queue, job,
|
||||||
|
hard * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case IKE_DELETING:
|
||||||
|
{
|
||||||
|
/* delete may fail if a packet gets lost, so set a timeout */
|
||||||
|
job_t *job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
|
||||||
|
charon->event_queue->add_relative(charon->event_queue, job,
|
||||||
|
charon->configuration->get_half_open_ike_sa_timeout(
|
||||||
|
charon->configuration));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->state = state;
|
this->state = state;
|
||||||
@@ -681,6 +699,7 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
|
|||||||
/* if this IKE_SA is virgin, we check for a connection */
|
/* if this IKE_SA is virgin, we check for a connection */
|
||||||
if (this->connection == NULL)
|
if (this->connection == NULL)
|
||||||
{
|
{
|
||||||
|
job_t *job;
|
||||||
this->connection = charon->connections->get_connection_by_hosts(
|
this->connection = charon->connections->get_connection_by_hosts(
|
||||||
charon->connections, me, other);
|
charon->connections, me, other);
|
||||||
if (this->connection == NULL)
|
if (this->connection == NULL)
|
||||||
@@ -691,6 +710,11 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
|
|||||||
send_notify_response(this, message, NO_PROPOSAL_CHOSEN);
|
send_notify_response(this, message, NO_PROPOSAL_CHOSEN);
|
||||||
return DESTROY_ME;
|
return DESTROY_ME;
|
||||||
}
|
}
|
||||||
|
/* add a timeout if peer does not establish it completely */
|
||||||
|
job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE);
|
||||||
|
charon->event_queue->add_relative(charon->event_queue, job,
|
||||||
|
charon->configuration->get_half_open_ike_sa_timeout(
|
||||||
|
charon->configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if message is trustworthy, and update connection information */
|
/* check if message is trustworthy, and update connection information */
|
||||||
|
|||||||
@@ -130,6 +130,51 @@ struct private_task_manager_t {
|
|||||||
linked_list_t *passive_tasks;
|
linked_list_t *passive_tasks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* flush all tasks in the task manager
|
||||||
|
*/
|
||||||
|
static void flush(private_task_manager_t *this)
|
||||||
|
{
|
||||||
|
task_t *task;
|
||||||
|
|
||||||
|
this->queued_tasks->destroy_offset(this->queued_tasks,
|
||||||
|
offsetof(task_t, destroy));
|
||||||
|
this->passive_tasks->destroy_offset(this->passive_tasks,
|
||||||
|
offsetof(task_t, destroy));
|
||||||
|
|
||||||
|
/* emmit outstanding signals for tasks */
|
||||||
|
while (this->active_tasks->remove_last(this->active_tasks,
|
||||||
|
(void**)&task) == SUCCESS)
|
||||||
|
{
|
||||||
|
switch (task->get_type(task))
|
||||||
|
{
|
||||||
|
case IKE_AUTH:
|
||||||
|
SIG(IKE_UP_FAILED, "establishing IKE_SA failed");
|
||||||
|
break;
|
||||||
|
case IKE_DELETE:
|
||||||
|
SIG(IKE_DOWN_FAILED, "IKE_SA deleted");
|
||||||
|
break;
|
||||||
|
case IKE_REKEY:
|
||||||
|
SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed");
|
||||||
|
break;
|
||||||
|
case CHILD_CREATE:
|
||||||
|
SIG(CHILD_UP_FAILED, "establishing CHILD_SA failed");
|
||||||
|
break;
|
||||||
|
case CHILD_DELETE:
|
||||||
|
SIG(CHILD_DOWN_FAILED, "deleting CHILD_SA failed");
|
||||||
|
break;
|
||||||
|
case CHILD_REKEY:
|
||||||
|
SIG(IKE_REKEY_FAILED, "rekeying CHILD_SA failed");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
task->destroy(task);
|
||||||
|
}
|
||||||
|
this->queued_tasks = linked_list_create();
|
||||||
|
this->passive_tasks = linked_list_create();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* move a task of a specific type from the queue to the active list
|
* move a task of a specific type from the queue to the active list
|
||||||
*/
|
*/
|
||||||
@@ -322,6 +367,7 @@ static status_t build_request(private_task_manager_t *this)
|
|||||||
/* critical failure, destroy IKE_SA */
|
/* critical failure, destroy IKE_SA */
|
||||||
iterator->destroy(iterator);
|
iterator->destroy(iterator);
|
||||||
message->destroy(message);
|
message->destroy(message);
|
||||||
|
flush(this);
|
||||||
return DESTROY_ME;
|
return DESTROY_ME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -335,6 +381,7 @@ static status_t build_request(private_task_manager_t *this)
|
|||||||
{
|
{
|
||||||
/* message generation failed. There is nothing more to do than to
|
/* message generation failed. There is nothing more to do than to
|
||||||
* close the SA */
|
* close the SA */
|
||||||
|
flush(this);
|
||||||
return DESTROY_ME;
|
return DESTROY_ME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,6 +655,7 @@ static status_t process_message(private_task_manager_t *this, message_t *msg)
|
|||||||
{
|
{
|
||||||
if (process_request(this, msg) != SUCCESS)
|
if (process_request(this, msg) != SUCCESS)
|
||||||
{
|
{
|
||||||
|
flush(this);
|
||||||
return DESTROY_ME;
|
return DESTROY_ME;
|
||||||
}
|
}
|
||||||
this->responding.mid++;
|
this->responding.mid++;
|
||||||
@@ -632,6 +680,7 @@ static status_t process_message(private_task_manager_t *this, message_t *msg)
|
|||||||
{
|
{
|
||||||
if (process_response(this, msg) != SUCCESS)
|
if (process_response(this, msg) != SUCCESS)
|
||||||
{
|
{
|
||||||
|
flush(this);
|
||||||
return DESTROY_ME;
|
return DESTROY_ME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -716,43 +765,12 @@ static void reset(private_task_manager_t *this)
|
|||||||
*/
|
*/
|
||||||
static void destroy(private_task_manager_t *this)
|
static void destroy(private_task_manager_t *this)
|
||||||
{
|
{
|
||||||
task_t *task;
|
flush(this);
|
||||||
|
|
||||||
this->queued_tasks->destroy_offset(this->queued_tasks,
|
|
||||||
offsetof(task_t, destroy));
|
|
||||||
this->passive_tasks->destroy_offset(this->passive_tasks,
|
|
||||||
offsetof(task_t, destroy));
|
|
||||||
|
|
||||||
/* emmit outstanding signals for tasks */
|
|
||||||
while (this->active_tasks->remove_last(this->active_tasks,
|
|
||||||
(void**)&task) == SUCCESS)
|
|
||||||
{
|
|
||||||
switch (task->get_type(task))
|
|
||||||
{
|
|
||||||
case IKE_AUTH:
|
|
||||||
SIG(IKE_UP_FAILED, "establishing IKE_SA failed");
|
|
||||||
break;
|
|
||||||
case IKE_DELETE:
|
|
||||||
SIG(IKE_DOWN_FAILED, "IKE_SA deleted");
|
|
||||||
break;
|
|
||||||
case IKE_REKEY:
|
|
||||||
SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed");
|
|
||||||
break;
|
|
||||||
case CHILD_CREATE:
|
|
||||||
SIG(CHILD_UP_FAILED, "establishing CHILD_SA failed");
|
|
||||||
break;
|
|
||||||
case CHILD_DELETE:
|
|
||||||
SIG(CHILD_DOWN_FAILED, "deleting CHILD_SA failed");
|
|
||||||
break;
|
|
||||||
case CHILD_REKEY:
|
|
||||||
SIG(IKE_REKEY_FAILED, "rekeying CHILD_SA failed");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
task->destroy(task);
|
|
||||||
}
|
|
||||||
this->active_tasks->destroy(this->active_tasks);
|
this->active_tasks->destroy(this->active_tasks);
|
||||||
|
this->queued_tasks->destroy(this->queued_tasks);
|
||||||
|
this->passive_tasks->destroy(this->passive_tasks);
|
||||||
|
|
||||||
DESTROY_IF(this->responding.packet);
|
DESTROY_IF(this->responding.packet);
|
||||||
DESTROY_IF(this->initiating.packet);
|
DESTROY_IF(this->initiating.packet);
|
||||||
free(this);
|
free(this);
|
||||||
|
|||||||
@@ -553,6 +553,13 @@ static status_t build_r(private_child_create_t *this, message_t *message)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING)
|
||||||
|
{
|
||||||
|
SIG(CHILD_UP_FAILED, "unable to create CHILD_SA while rekeying IKE_SA");
|
||||||
|
message->add_notify(message, TRUE, NO_ADDITIONAL_SAS, chunk_empty);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->policy == NULL)
|
if (this->policy == NULL)
|
||||||
{
|
{
|
||||||
SIG(CHILD_UP_FAILED, "no acceptable policy found");
|
SIG(CHILD_UP_FAILED, "no acceptable policy found");
|
||||||
|
|||||||
@@ -126,12 +126,21 @@ static void process_payloads(private_child_delete_t *this, message_t *message)
|
|||||||
{
|
{
|
||||||
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, "
|
DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI 0x%x, "
|
||||||
"but no such SA", protocol_id_names, protocol, ntohl(*spi));
|
"but no such SA", protocol_id_names, protocol, ntohl(*spi));
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child_sa->get_state(child_sa) == CHILD_REKEYING)
|
switch (child_sa->get_state(child_sa))
|
||||||
{
|
{
|
||||||
/* TODO: handle rekeying */
|
case CHILD_REKEYING:
|
||||||
|
/* we reply as usual, rekeying will fail */
|
||||||
|
break;
|
||||||
|
case CHILD_DELETING:
|
||||||
|
/* we don't send back a delete */
|
||||||
|
this->ike_sa->destroy_child_sa(this->ike_sa,
|
||||||
|
protocol, *spi);
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->child_sas->insert_last(this->child_sas, child_sa);
|
this->child_sas->insert_last(this->child_sas, child_sa);
|
||||||
@@ -155,7 +164,6 @@ static void destroy_children(private_child_delete_t *this)
|
|||||||
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
|
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
|
||||||
while (iterator->iterate(iterator, (void**)&child_sa))
|
while (iterator->iterate(iterator, (void**)&child_sa))
|
||||||
{
|
{
|
||||||
/* TODO: can we do this more cleanly? */
|
|
||||||
spi = child_sa->get_spi(child_sa, TRUE);
|
spi = child_sa->get_spi(child_sa, TRUE);
|
||||||
protocol = child_sa->get_protocol(child_sa);
|
protocol = child_sa->get_protocol(child_sa);
|
||||||
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
|
this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi);
|
||||||
@@ -200,7 +208,11 @@ static status_t process_r(private_child_delete_t *this, message_t *message)
|
|||||||
*/
|
*/
|
||||||
static status_t build_r(private_child_delete_t *this, message_t *message)
|
static status_t build_r(private_child_delete_t *this, message_t *message)
|
||||||
{
|
{
|
||||||
build_payloads(this, message);
|
/* if we are rekeying, we send an empty informational */
|
||||||
|
if (this->ike_sa->get_state(this->ike_sa) != IKE_REKEYING)
|
||||||
|
{
|
||||||
|
build_payloads(this, message);
|
||||||
|
}
|
||||||
destroy_children(this);
|
destroy_children(this);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,53 +141,6 @@ static void find_child(private_child_rekey_t *this, message_t *message)
|
|||||||
iterator->destroy(iterator);
|
iterator->destroy(iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
/**
|
|
||||||
* handle a detected simultaneous rekeying situation as responder
|
|
||||||
*/
|
|
||||||
static void simultaneous_r(private_child_rekey_t *this, message_t *message)
|
|
||||||
{
|
|
||||||
private_child_rekey_t *other = NULL;
|
|
||||||
task_t *task;
|
|
||||||
iterator_t *iterator;
|
|
||||||
|
|
||||||
this->ike_sa->create_task_iterator(this->ike_sa);
|
|
||||||
while (iterator->iterate(iterator, (void**)&task))
|
|
||||||
{
|
|
||||||
if (task->get_type(task) == CHILD_REKEY)
|
|
||||||
{
|
|
||||||
other = (private_child_rekey_t*)task;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iterator->destroy(iterator);
|
|
||||||
|
|
||||||
if (other)
|
|
||||||
{
|
|
||||||
other->simultaneous = this->child_create->get_child(this->child_create);
|
|
||||||
|
|
||||||
if (!get_nonce(other, message))
|
|
||||||
{
|
|
||||||
/* this wins the race, other lost */
|
|
||||||
other->winner = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* was there a simultaneous rekeying, did we win the nonce compare?
|
|
||||||
*/
|
|
||||||
static bool simultaneous_i(private_child_rekey_t *this, message_t *message)
|
|
||||||
{
|
|
||||||
if (this->winner || get_nonce(this, message))
|
|
||||||
{
|
|
||||||
/* we have the lower nonce and win */
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of task_t.build for initiator
|
* Implementation of task_t.build for initiator
|
||||||
*/
|
*/
|
||||||
@@ -247,11 +200,20 @@ static status_t build_r(private_child_rekey_t *this, message_t *message)
|
|||||||
reqid = this->child_sa->get_reqid(this->child_sa);
|
reqid = this->child_sa->get_reqid(this->child_sa);
|
||||||
this->child_create->use_reqid(this->child_create, reqid);
|
this->child_create->use_reqid(this->child_create, reqid);
|
||||||
this->child_create->task.build(&this->child_create->task, message);
|
this->child_create->task.build(&this->child_create->task, message);
|
||||||
|
|
||||||
|
if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
|
||||||
|
{
|
||||||
|
/* rekeying failed, reuse old child */
|
||||||
|
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
|
||||||
|
/* TODO: reschedule rekeying */
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
get_nonce(this, message);
|
get_nonce(this, message);
|
||||||
|
|
||||||
if (this->child_sa->get_state(this->child_sa) == CHILD_REKEYING)
|
if (this->child_sa->get_state(this->child_sa) == CHILD_REKEYING)
|
||||||
{
|
{
|
||||||
/* simultaneous_detected(this); */
|
/* TODO: handle simultaneous rekeying */
|
||||||
}
|
}
|
||||||
|
|
||||||
this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
|
this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
|
||||||
@@ -268,16 +230,17 @@ static status_t process_i(private_child_rekey_t *this, message_t *message)
|
|||||||
u_int32_t spi;
|
u_int32_t spi;
|
||||||
|
|
||||||
this->child_create->task.process(&this->child_create->task, message);
|
this->child_create->task.process(&this->child_create->task, message);
|
||||||
|
if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
|
||||||
/*if (!simultaneous_won(this, message))
|
|
||||||
{
|
{
|
||||||
* delete the redundant CHILD_SA, instead of the rekeyed *
|
/* establishing new child failed, fallback */
|
||||||
this->child_sa = this->create_child->get_child(this->create_child);
|
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
|
||||||
}*/
|
/* TODO: rescedule rekeying */
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: delete the redundant CHILD_SA, instead of the rekeyed */
|
||||||
spi = this->child_sa->get_spi(this->child_sa, TRUE);
|
spi = this->child_sa->get_spi(this->child_sa, TRUE);
|
||||||
protocol = this->child_sa->get_protocol(this->child_sa);
|
protocol = this->child_sa->get_protocol(this->child_sa);
|
||||||
|
|
||||||
/* TODO: don't delete when rekeying failed */
|
|
||||||
if (this->ike_sa->delete_child_sa(this->ike_sa, protocol, spi) != SUCCESS)
|
if (this->ike_sa->delete_child_sa(this->ike_sa, protocol, spi) != SUCCESS)
|
||||||
{
|
{
|
||||||
return FAILED;
|
return FAILED;
|
||||||
|
|||||||
@@ -92,11 +92,14 @@ static status_t process_r(private_ike_delete_t *this, message_t *message)
|
|||||||
break;
|
break;
|
||||||
case IKE_ESTABLISHED:
|
case IKE_ESTABLISHED:
|
||||||
DBG1(DBG_IKE, "deleting IKE_SA on request");
|
DBG1(DBG_IKE, "deleting IKE_SA on request");
|
||||||
/* warn only if we are established */
|
break;
|
||||||
|
case IKE_REKEYING:
|
||||||
|
DBG1(DBG_IKE, "initiated rekeying, but received delete for IKE_SA");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +110,7 @@ static status_t build_r(private_ike_delete_t *this, message_t *message)
|
|||||||
{
|
{
|
||||||
if (this->simultaneous)
|
if (this->simultaneous)
|
||||||
{
|
{
|
||||||
/* wait for peers response for our delete request */
|
/* wait for peers response for our delete request, but set a timeout */
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
/* completed, delete IKE_SA by returning FAILED */
|
/* completed, delete IKE_SA by returning FAILED */
|
||||||
|
|||||||
@@ -98,6 +98,32 @@ static status_t process_r(private_ike_rekey_t *this, message_t *message)
|
|||||||
connection_t *connection;
|
connection_t *connection;
|
||||||
policy_t *policy;
|
policy_t *policy;
|
||||||
ike_sa_id_t *id;
|
ike_sa_id_t *id;
|
||||||
|
iterator_t *iterator;
|
||||||
|
child_sa_t *child_sa;
|
||||||
|
|
||||||
|
if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "peer initiated rekeying, but we are deleting");
|
||||||
|
return NEED_MORE;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa);
|
||||||
|
while (iterator->iterate(iterator, (void**)&child_sa))
|
||||||
|
{
|
||||||
|
switch (child_sa->get_state(child_sa))
|
||||||
|
{
|
||||||
|
case CHILD_CREATED:
|
||||||
|
case CHILD_REKEYING:
|
||||||
|
case CHILD_DELETING:
|
||||||
|
/* we do not allow rekeying while we have children in-progress */
|
||||||
|
DBG1(DBG_IKE, "peer initiated rekeying, but a child is half-open");
|
||||||
|
iterator->destroy(iterator);
|
||||||
|
return NEED_MORE;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iterator->destroy(iterator);
|
||||||
|
|
||||||
id = ike_sa_id_create(0, 0, FALSE);
|
id = ike_sa_id_create(0, 0, FALSE);
|
||||||
this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
|
this->new_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
|
||||||
@@ -119,6 +145,13 @@ static status_t process_r(private_ike_rekey_t *this, message_t *message)
|
|||||||
*/
|
*/
|
||||||
static status_t build_r(private_ike_rekey_t *this, message_t *message)
|
static status_t build_r(private_ike_rekey_t *this, message_t *message)
|
||||||
{
|
{
|
||||||
|
if (this->new_sa == NULL)
|
||||||
|
{
|
||||||
|
/* IKE_SA/a CHILD_SA is in an inacceptable state, deny rekeying */
|
||||||
|
message->add_notify(message, TRUE, NO_PROPOSAL_CHOSEN, chunk_empty);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED)
|
if (this->ike_init->task.build(&this->ike_init->task, message) == FAILED)
|
||||||
{
|
{
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
@@ -142,6 +175,9 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message)
|
|||||||
|
|
||||||
if (this->ike_init->task.process(&this->ike_init->task, message) == FAILED)
|
if (this->ike_init->task.process(&this->ike_init->task, message) == FAILED)
|
||||||
{
|
{
|
||||||
|
/* rekeying failed, fallback to old SA */
|
||||||
|
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||||
|
/* TODO: reschedule rekeying */
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +188,6 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message)
|
|||||||
|
|
||||||
job = (job_t*)delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa),
|
job = (job_t*)delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa),
|
||||||
TRUE);
|
TRUE);
|
||||||
|
|
||||||
charon->job_queue->add(charon->job_queue, job);
|
charon->job_queue->add(charon->job_queue, job);
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user