> Our send/receive_delay testing hooks are insufficient to simulate this,
> I'll have to add some conditional packet delays to reproduce it.
I have added a simple conditional packet delay mechanism, it allows us
to delay some specific packets and reproduce this issue.
> I'll try to reproduce this condition
I configured box with:
strongswan.conf:
send_delay = 1000
receive_delay = 5000
receive_delay_type = 36
receive_delay_request = no
ipsec.conf:
lifetime=30s
margintime=11s
rekeyfuzz=0%
For xob, I used:
strongswan.conf:
send_delay = 1000
ipsec.conf:
lifetime=30s
margintime=10s
rekeyfuzz=0%
This will trigger a simultaneous rekey in ~20s, but will delay the
problematic CREATE_CHILD_SA response a little more. With this
configuration, I could reproduce the problem.
> I think it should be possible to catch this in the collide() check.
I additionally checked in a patch that fixes the problem for this
configuration for both cases, if xob wins the nonce compare, but also if
it loses.
Patches attached, please verify.
Best regards
Martin
>From 45def2147be9b6443bab69fe5457e3cf87279bc7 Mon Sep 17 00:00:00 2001
From: Martin Willi <[email protected]>
Date: Tue, 18 May 2010 12:20:32 +0200
Subject: [PATCH 1/3] Added simple conditional packet send delay
---
src/libcharon/network/sender.c | 41 ++++++++++++++++++++++++++++++++++++++-
1 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/src/libcharon/network/sender.c b/src/libcharon/network/sender.c
index c18f113..bb6d506 100644
--- a/src/libcharon/network/sender.c
+++ b/src/libcharon/network/sender.c
@@ -67,6 +67,21 @@ struct private_sender_t {
* Delay for sending outgoing packets, to simulate larger RTT
*/
int send_delay;
+
+ /**
+ * Specific message type to delay, 0 for any
+ */
+ int send_delay_type;
+
+ /**
+ * Delay request messages?
+ */
+ bool send_delay_request;
+
+ /**
+ * Delay response messages?
+ */
+ bool send_delay_response;
};
METHOD(sender_t, send_, void,
@@ -80,7 +95,23 @@ METHOD(sender_t, send_, void,
if (this->send_delay)
{
- usleep(this->send_delay * 1000);
+ message_t *message;
+
+ message = message_create_from_packet(packet->clone(packet));
+ if (message->parse_header(message) == SUCCESS)
+ {
+ if (this->send_delay_type == 0 ||
+ this->send_delay_type == message->get_exchange_type(message))
+ {
+ if ((message->get_request(message) && this->send_delay_request) ||
+ (!message->get_request(message) && this->send_delay_response))
+ {
+ DBG1(DBG_NET, "using send delay: %dms", this->send_delay);
+ usleep(this->send_delay * 1000);
+ }
+ }
+ }
+ message->destroy(message);
}
this->mutex->lock(this->mutex);
@@ -155,7 +186,13 @@ sender_t * sender_create()
.job = callback_job_create((callback_job_cb_t)send_packets,
this, NULL, NULL),
.send_delay = lib->settings->get_int(lib->settings,
- "charon.send_delay", 0),
+ "charon.send_delay", 0),
+ .send_delay_type = lib->settings->get_int(lib->settings,
+ "charon.send_delay_type", 0),
+ .send_delay_request = lib->settings->get_bool(lib->settings,
+ "charon.send_delay_request", TRUE),
+ .send_delay_response = lib->settings->get_int(lib->settings,
+ "charon.send_delay_response", TRUE),
);
charon->processor->queue_job(charon->processor, (job_t*)this->job);
--
1.7.0.4
>From d235274486e52ca2b8fc02fee541f316827906e3 Mon Sep 17 00:00:00 2001
From: Martin Willi <[email protected]>
Date: Tue, 18 May 2010 12:21:05 +0200
Subject: [PATCH 2/3] Added simple conditional packet receive delay
---
src/libcharon/network/receiver.c | 47 ++++++++++++++++++++++++++++++-------
1 files changed, 38 insertions(+), 9 deletions(-)
diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c
index df89702..bf6ccf7 100644
--- a/src/libcharon/network/receiver.c
+++ b/src/libcharon/network/receiver.c
@@ -103,7 +103,22 @@ struct private_receiver_t {
/**
* Delay for receiving incoming packets, to simulate larger RTT
*/
- u_int receive_delay;
+ int receive_delay;
+
+ /**
+ * Specific message type to delay, 0 for any
+ */
+ int receive_delay_type;
+
+ /**
+ * Delay request messages?
+ */
+ bool receive_delay_request;
+
+ /**
+ * Delay response messages?
+ */
+ bool receive_delay_response;
};
/**
@@ -259,7 +274,6 @@ static job_requeue_t receive_packets(private_receiver_t *this)
{
packet_t *packet;
message_t *message;
- job_t *job;
/* read in a packet */
if (charon->socket->receive(charon->socket, &packet) != SUCCESS)
@@ -329,16 +343,25 @@ static job_requeue_t receive_packets(private_receiver_t *this)
return JOB_REQUEUE_DIRECT;
}
}
- job = (job_t*)process_message_job_create(message);
if (this->receive_delay)
{
- charon->scheduler->schedule_job_ms(charon->scheduler,
- job, this->receive_delay);
- }
- else
- {
- charon->processor->queue_job(charon->processor, job);
+ if (this->receive_delay_type == 0 ||
+ this->receive_delay_type == message->get_exchange_type(message))
+ {
+ if ((message->get_request(message) && this->receive_delay_request) ||
+ (!message->get_request(message) && this->receive_delay_response))
+ {
+ DBG1(DBG_NET, "using receive delay: %dms",
+ this->receive_delay);
+ charon->scheduler->schedule_job_ms(charon->scheduler,
+ (job_t*)process_message_job_create(message),
+ this->receive_delay);
+ return JOB_REQUEUE_DIRECT;
+ }
+ }
}
+ charon->processor->queue_job(charon->processor,
+ (job_t*)process_message_job_create(message));
return JOB_REQUEUE_DIRECT;
}
@@ -374,6 +397,12 @@ receiver_t *receiver_create()
}
this->receive_delay = lib->settings->get_int(lib->settings,
"charon.receive_delay", 0);
+ this->receive_delay_type = lib->settings->get_int(lib->settings,
+ "charon.receive_delay_type", 0),
+ this->receive_delay_request = lib->settings->get_bool(lib->settings,
+ "charon.receive_delay_request", TRUE),
+ this->receive_delay_response = lib->settings->get_int(lib->settings,
+ "charon.receive_delay_response", TRUE),
this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_PREFERRED);
if (this->hasher == NULL)
--
1.7.0.4
>From ea409980b9a3178b4860f2957685f7ec91956b1d Mon Sep 17 00:00:00 2001
From: Martin Willi <[email protected]>
Date: Tue, 18 May 2010 12:21:38 +0200
Subject: [PATCH 3/3] Handle collisions between rekey and the following delete properly
---
src/libcharon/sa/tasks/child_rekey.c | 90 +++++++++++++++++++++++----------
1 files changed, 63 insertions(+), 27 deletions(-)
diff --git a/src/libcharon/sa/tasks/child_rekey.c b/src/libcharon/sa/tasks/child_rekey.c
index b5e4e84..5331419 100644
--- a/src/libcharon/sa/tasks/child_rekey.c
+++ b/src/libcharon/sa/tasks/child_rekey.c
@@ -215,6 +215,59 @@ static status_t build_r(private_child_rekey_t *this, message_t *message)
}
/**
+ * Handle a rekey collision
+ */
+static child_sa_t *handle_collision(private_child_rekey_t *this)
+{
+ child_sa_t *to_delete;
+
+ if (this->collision->get_type(this->collision) == CHILD_REKEY)
+ {
+ chunk_t this_nonce, other_nonce;
+ private_child_rekey_t *other = (private_child_rekey_t*)this->collision;
+
+ this_nonce = this->child_create->get_lower_nonce(this->child_create);
+ other_nonce = other->child_create->get_lower_nonce(other->child_create);
+
+ /* if we have the lower nonce, delete rekeyed SA. If not, delete
+ * the redundant. */
+ if (memcmp(this_nonce.ptr, other_nonce.ptr,
+ min(this_nonce.len, other_nonce.len)) < 0)
+ {
+ DBG1(DBG_IKE, "CHILD_SA rekey collision won, "
+ "deleting rekeyed child");
+ to_delete = this->child_sa;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "CHILD_SA rekey collision lost, "
+ "deleting redundant child");
+ to_delete = this->child_create->get_child(this->child_create);
+ }
+ }
+ else
+ { /* CHILD_DELETE */
+ child_delete_t *del = (child_delete_t*)this->collision;
+
+ /* we didn't had a chance to compare the nonces, so we delete
+ * the CHILD_SA the other is not deleting. */
+ if (del->get_child(del) != this->child_sa)
+ {
+ DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, "
+ "deleting rekeyed child");
+ to_delete = this->child_sa;
+ }
+ else
+ {
+ DBG1(DBG_IKE, "CHILD_SA rekey/delete collision, "
+ "deleting redundant child");
+ to_delete = this->child_create->get_child(this->child_create);
+ }
+ }
+ return to_delete;
+}
+
+/**
* Implementation of task_t.process for initiator
*/
static status_t process_i(private_child_rekey_t *this, message_t *message)
@@ -263,35 +316,14 @@ static status_t process_i(private_child_rekey_t *this, message_t *message)
return SUCCESS;
}
- to_delete = this->child_sa;
-
/* check for rekey collisions */
- if (this->collision &&
- this->collision->get_type(this->collision) == CHILD_REKEY)
+ if (this->collision)
{
- chunk_t this_nonce, other_nonce;
- private_child_rekey_t *other = (private_child_rekey_t*)this->collision;
-
- this_nonce = this->child_create->get_lower_nonce(this->child_create);
- other_nonce = other->child_create->get_lower_nonce(other->child_create);
-
- /* if we have the lower nonce, delete rekeyed SA. If not, delete
- * the redundant. */
- if (memcmp(this_nonce.ptr, other_nonce.ptr,
- min(this_nonce.len, other_nonce.len)) < 0)
- {
- DBG1(DBG_IKE, "CHILD_SA rekey collision won, deleting rekeyed child");
- }
- else
- {
- DBG1(DBG_IKE, "CHILD_SA rekey collision lost, deleting redundant child");
- to_delete = this->child_create->get_child(this->child_create);
- if (to_delete == NULL)
- {
- /* ooops, should not happen, fallback */
- to_delete = this->child_sa;
- }
- }
+ to_delete = handle_collision(this);
+ }
+ else
+ {
+ to_delete = this->child_sa;
}
if (to_delete != this->child_create->get_child(this->child_create))
@@ -300,6 +332,10 @@ static status_t process_i(private_child_rekey_t *this, message_t *message)
this->child_create->get_child(this->child_create));
}
+ if (to_delete == NULL)
+ {
+ return SUCCESS;
+ }
spi = to_delete->get_spi(to_delete, TRUE);
protocol = to_delete->get_protocol(to_delete);
--
1.7.0.4
_______________________________________________
Dev mailing list
[email protected]
https://lists.strongswan.org/mailman/listinfo/dev