fixed some exchange collisions (except IKE/CHILD rekeying)

This commit is contained in:
Martin Willi
2007-03-20 16:13:21 +00:00
parent e70d5576fa
commit 0f33e8264a
7 changed files with 188 additions and 126 deletions
+7
View File
@@ -553,6 +553,13 @@ static status_t build_r(private_child_create_t *this, message_t *message)
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)
{
SIG(CHILD_UP_FAILED, "no acceptable policy found");
+17 -5
View File
@@ -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, "
"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);
@@ -155,7 +164,6 @@ static void destroy_children(private_child_delete_t *this)
iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
while (iterator->iterate(iterator, (void**)&child_sa))
{
/* TODO: can we do this more cleanly? */
spi = child_sa->get_spi(child_sa, TRUE);
protocol = child_sa->get_protocol(child_sa);
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)
{
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);
return SUCCESS;
}
+18 -55
View File
@@ -141,53 +141,6 @@ static void find_child(private_child_rekey_t *this, message_t *message)
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
*/
@@ -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);
this->child_create->use_reqid(this->child_create, reqid);
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);
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);
@@ -268,16 +230,17 @@ static status_t process_i(private_child_rekey_t *this, message_t *message)
u_int32_t spi;
this->child_create->task.process(&this->child_create->task, message);
/*if (!simultaneous_won(this, message))
if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
{
* delete the redundant CHILD_SA, instead of the rekeyed *
this->child_sa = this->create_child->get_child(this->create_child);
}*/
/* establishing new child failed, fallback */
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);
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)
{
return FAILED;
+6 -3
View File
@@ -92,11 +92,14 @@ static status_t process_r(private_ike_delete_t *this, message_t *message)
break;
case IKE_ESTABLISHED:
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:
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
break;
}
this->ike_sa->set_state(this->ike_sa, IKE_DELETING);
return NEED_MORE;
}
@@ -107,7 +110,7 @@ static status_t build_r(private_ike_delete_t *this, message_t *message)
{
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;
}
/* completed, delete IKE_SA by returning FAILED */
+36 -1
View File
@@ -98,6 +98,32 @@ static status_t process_r(private_ike_rekey_t *this, message_t *message)
connection_t *connection;
policy_t *policy;
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);
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)
{
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)
{
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)
{
/* rekeying failed, fallback to old SA */
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
/* TODO: reschedule rekeying */
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),
TRUE);
charon->job_queue->add(charon->job_queue, job);
return SUCCESS;
}