StrongSwan has a HA system that will synchronize the IKE and IPsec HA
state and so does not need to support RFC 6311 when StrongSwan is
configured as a HA cluster.

However, if the peer device is in a HA cluster and would prefer to use
RFC 6311 IKEV2_MESSAGE_ID_SYNC to synchronize the IKE SA message ID
counters then this will not work since StrongSwan does not support
responding to a IKEV2_MESSAGE_ID_SYNC message.  As to why the peer
device may prefer to use IKEV2_MESSAGE_ID_SYNC where possible,
consider the case where the peer is actually a small HA cluster of C
devices (say C=3) which act as VPN concentrators for N clients (say
N=60,000) and the traffic is uni-directional (from client to server
and so DPD on the client will continually being triggered due to lack
of traffic from concentrator end).  In this case the VPN concentrator
is receiving N/D DPD probes a second where D is the DPD period (say 5
seconds) and that could mean 12,000 IKE HAs a second that need their
sequence numbers synchronizing to the other cluster nodes.  That can
certainly be done, but that's a lot of traffic that can be avoided
if both sides support IKEV2_MESSAGE_ID_SYNC.

Attached is a patch
(0001-RFC-6311-IKEV2_MESSAGE_ID_SYNC-responder-support.patch) which
adds minimal RFC 6311 to StrongSwan.  Specifially with the patch
applied when StrongSwan initiates a connection then an
IKEV2_MESSAGE_ID_SYNC_SUPPORTED is uncondtionally included in the
IKE_AUTH.  If the peer responds with an
IKEV2_MESSAGE_ID_SYNC_SUPPORTED then StrongSwan is now prepared to
accept an INFORMATIONAL message containing an IKEV2_MESSAGE_ID_SYNC
and respond with a IKEV2_MESSAGE_ID_SYNC containing the updated
sequence numbers.

There patch does not include support for
IPSEC_REPLAY_COUNTER_SYNC_SUPPORTED, nor is there any support for
StrongSwan initiating IKEV2_MESSAGE_ID_SYNC on StrongSwan HA failover.

The patch was made against a tree containing the following at the tip :-

  commit d9fe0ec7122c1890836226f703a9774958876f3e
  Author: Tobias Brunner <[email protected]>
  Date:   Wed Aug 24 11:34:36 2016 +0200

      ikev2: (Re-)Queue tasks used to establish an IKE_SA in reset()

Note that RFC 6311 is rather invasive to the IKEv2 state machine since
it alters message ID numbers.  I've tried to fit in with the general
architecture of StrongSwan as best as I understand it.  For example,
I'm not entirely clear whether IKEV2_MESSAGE_ID_SYNC_SUPPORTED should
be handled as a task like IKEV2_MESSAGE_ID_SYNC or whether it is
acceptable to handle it in ike_auth.c.  I tried both and in the end
decided on putting IKEV2_MESSAGE_ID_SYNC_SUPPORTED in ike_auth.c since
it resulted in a smaller patch.

The patch was lightly tested against a Fortinet FortiGate.  I have
some debug showing the IKE SA negotiation, the FortiGate performing a
HA switch, sending IKEV2_MESSAGE_ID_SYNC to StrongSwan, receiving a
reply, re-synchronizing its sequence numbers and DPD in both
directions continuing to work.  However, my attempt to include
that in the submission pushed the email about the 100KB limit so
I've omitted them.
From ee2b4d3997338171a16d8a94bb73bd08376ce867 Mon Sep 17 00:00:00 2001
From: "Stephen J. Bevan" <[email protected]>
Date: Mon, 12 Sep 2016 12:09:56 -0700
Subject: [PATCH] RFC 6311 IKEV2_MESSAGE_ID_SYNC responder support

---
 src/libcharon/Makefile.am                          |   1 +
 src/libcharon/sa/ike_sa.c                          |  19 ++
 src/libcharon/sa/ike_sa.h                          |  20 +++
 src/libcharon/sa/ikev2/task_manager_v2.c           | 126 +++++++++++---
 src/libcharon/sa/ikev2/tasks/ike_auth.c            |   7 +
 src/libcharon/sa/ikev2/tasks/ike_message_id_sync.c | 193 +++++++++++++++++++++
 src/libcharon/sa/ikev2/tasks/ike_message_id_sync.h |  65 +++++++
 src/libcharon/sa/task.h                            |   2 +
 src/libcharon/sa/task_manager.h                    |  15 ++
 9 files changed, 420 insertions(+), 28 deletions(-)
 create mode 100644 src/libcharon/sa/ikev2/tasks/ike_message_id_sync.c
 create mode 100644 src/libcharon/sa/ikev2/tasks/ike_message_id_sync.h

diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am
index 550f6eb..9510214 100644
--- a/src/libcharon/Makefile.am
+++ b/src/libcharon/Makefile.am
@@ -105,6 +105,7 @@ sa/ikev2/tasks/ike_delete.c sa/ikev2/tasks/ike_delete.h \
 sa/ikev2/tasks/ike_dpd.c sa/ikev2/tasks/ike_dpd.h \
 sa/ikev2/tasks/ike_init.c sa/ikev2/tasks/ike_init.h \
 sa/ikev2/tasks/ike_natd.c sa/ikev2/tasks/ike_natd.h \
+sa/ikev2/tasks/ike_message_id_sync.c sa/ikev2/tasks/ike_message_id_sync.h \
 sa/ikev2/tasks/ike_mobike.c sa/ikev2/tasks/ike_mobike.h \
 sa/ikev2/tasks/ike_rekey.c sa/ikev2/tasks/ike_rekey.h \
 sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c
index 239e260..0993c15 100644
--- a/src/libcharon/sa/ike_sa.c
+++ b/src/libcharon/sa/ike_sa.c
@@ -2432,6 +2432,24 @@ METHOD(ike_sa_t, set_auth_lifetime, status_t,
 	return SUCCESS;
 }
 
+
+/*
+ * RFC 6311.
+ *
+ * The IKEv2 peer has send a IKEV2_MESSAGE_SYNC_ID containing its
+ * expected send message ID and expected receive message ID.  The goal
+ * is to update the send/recv numbers with the ones that the task
+ * manager has for this IKE SA so that they can be sent back to the
+ * peer to re-synchronize its message IDs.
+ */
+METHOD(ike_sa_t, message_id_sync, status_t,
+	private_ike_sa_t *this, uint32_t *send, uint32_t *recv)
+{
+	if (!this->task_manager->request_mid_update(this->task_manager, send, recv))
+		return SUCCESS;
+	return NEED_MORE;
+}
+
 /**
  * Check if the current combination of source and destination address is still
  * valid.
@@ -2927,6 +2945,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator,
 			.reauth = _reauth,
 			.reestablish = _reestablish,
 			.set_auth_lifetime = _set_auth_lifetime,
+			.message_id_sync = _message_id_sync,
 			.roam = _roam,
 			.inherit_pre = _inherit_pre,
 			.inherit_post = _inherit_post,
diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h
index 6f5040d..ae2e89f 100644
--- a/src/libcharon/sa/ike_sa.h
+++ b/src/libcharon/sa/ike_sa.h
@@ -151,6 +151,11 @@ enum ike_extension_t {
 	 * IKEv2 Redirect Mechanism, RFC 5685
 	 */
 	EXT_IKE_REDIRECTION = (1<<13),
+
+	/**
+	 * IKEv2 Message ID sync, RFC 6311
+	 */
+	EXT_IKE_MESSAGE_ID_SYNC = (1<<14),
 };
 
 /**
@@ -1036,6 +1041,21 @@ struct ike_sa_t {
 	status_t (*set_auth_lifetime)(ike_sa_t *this, uint32_t lifetime);
 
 	/**
+	 * The IKEv2 peer has sent a IKEV2_MESSAGE_SYNC_ID containing its
+	 * expected send message ID and expected receive message ID which
+	 * are almost certainly wrong since they come from a device that
+	 * is not in HA sync with the peer that the last IKE messages were
+	 * sent to or received from.  The goal is to update the send/recv
+	 * numbers with the ones that IKE SA has so that the updated values
+	 * can be sent back to the peer to re-synchronize its message IDs.
+	 *
+	 * @param send		expected send message ID
+	 * @param recv		expected receive message ID
+	 * @return			DESTROY_ME to destroy the IKE_SA
+	 */
+	status_t (*message_id_sync)(ike_sa_t *this, uint32_t *send, uint32_t *recv);
+
+	/**
 	 * Add a virtual IP to use for this IKE_SA and its children.
 	 *
 	 * The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same
diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c
index 41a4e1b..ba80151 100644
--- a/src/libcharon/sa/ikev2/task_manager_v2.c
+++ b/src/libcharon/sa/ikev2/task_manager_v2.c
@@ -34,6 +34,7 @@
 #include <sa/ikev2/tasks/ike_delete.h>
 #include <sa/ikev2/tasks/ike_config.h>
 #include <sa/ikev2/tasks/ike_dpd.h>
+#include <sa/ikev2/tasks/ike_message_id_sync.h>
 #include <sa/ikev2/tasks/ike_vendor.h>
 #include <sa/ikev2/tasks/ike_verify_peer_cert.h>
 #include <sa/ikev2/tasks/child_create.h>
@@ -86,6 +87,11 @@ struct private_task_manager_t {
 		 */
 		message_t *defrag;
 
+		/*
+		 * RFC 6311
+		 */
+		uint32_t override_mid;
+
 	} responding;
 
 	/**
@@ -809,6 +815,41 @@ static bool handle_collisions(private_task_manager_t *this, task_t *task)
 }
 
 /**
+ * After handling a RFC 6311 IKEV2_MESSAGE_SYNC_ID sent by the peer
+ * then we need to delete any active tasks (most likely DPD) otherwise
+ * they will get stuck.
+ */
+static void partial_reset(private_task_manager_t *this)
+{
+	enumerator_t *enumerator;
+	queued_task_t *queued;
+	task_t *task;
+	timeval_t now;
+
+	time_monotonic(&now);
+	/* reset queued tasks */
+	enumerator = array_create_enumerator(this->queued_tasks);
+	while (enumerator->enumerate(enumerator, &queued))
+	{
+		queued->time = now;
+		queued->task->migrate(queued->task, this->ike_sa);
+	}
+	enumerator->destroy(enumerator);
+
+	/* reset active tasks */
+	while (array_remove(this->active_tasks, ARRAY_TAIL, &task))
+	{
+		task->migrate(task, this->ike_sa);
+		INIT(queued,
+			.task = task,
+			.time = now,
+		);
+		array_insert(this->queued_tasks, ARRAY_HEAD, queued);
+	}
+}
+
+
+/**
  * build a response depending on the "passive" task list
  */
 static status_t build_response(private_task_manager_t *this, message_t *request)
@@ -893,6 +934,12 @@ static status_t build_response(private_task_manager_t *this, message_t *request)
 	{
 		id->set_responder_spi(id, responder_spi);
 	}
+	if (this->responding.override_mid)
+	{
+		this->responding.mid = this->responding.override_mid;
+		this->responding.override_mid = 0;
+		partial_reset(this);
+	}
 	if (!result)
 	{
 		charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE);
@@ -1069,6 +1116,9 @@ static status_t process_request(private_task_manager_t *this,
 									task = (task_t*)ike_redirect_create(
 															this->ike_sa, NULL);
 									break;
+								case IKEV2_MESSAGE_ID_SYNC:
+									task = (task_t*)ike_message_id_sync_create(this->ike_sa);
+									break;
 								default:
 									break;
 							}
@@ -1421,7 +1471,12 @@ METHOD(task_manager_t, process_message, status_t,
 	mid = msg->get_message_id(msg);
 	if (msg->get_request(msg))
 	{
-		if (mid == this->responding.mid)
+		if ((mid == this->responding.mid) ||
+			((mid == 0) &&
+			 (msg->get_exchange_type(msg) == INFORMATIONAL) &&
+			 (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) &&
+			 (this->ike_sa->supports_extension(this->ike_sa,
+											   EXT_IKE_MESSAGE_ID_SYNC))))
 		{
 			/* reject initial messages if not received in specific states,
 			 * after rekeying we only expect a DELETE in an INFORMATIONAL */
@@ -1923,11 +1978,6 @@ METHOD(task_manager_t, busy, bool,
 METHOD(task_manager_t, reset, void,
 	private_task_manager_t *this, uint32_t initiate, uint32_t respond)
 {
-	enumerator_t *enumerator;
-	queued_task_t *queued;
-	task_t *task;
-	timeval_t now;
-
 	/* reset message counters and retransmit packets */
 	clear_packets(this->responding.packets);
 	clear_packets(this->initiating.packets);
@@ -1944,28 +1994,7 @@ METHOD(task_manager_t, reset, void,
 		this->responding.mid = respond;
 	}
 	this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
-
-	time_monotonic(&now);
-	/* reset queued tasks */
-	enumerator = array_create_enumerator(this->queued_tasks);
-	while (enumerator->enumerate(enumerator, &queued))
-	{
-		queued->time = now;
-		queued->task->migrate(queued->task, this->ike_sa);
-	}
-	enumerator->destroy(enumerator);
-
-	/* reset active tasks */
-	while (array_remove(this->active_tasks, ARRAY_TAIL, &task))
-	{
-		task->migrate(task, this->ike_sa);
-		INIT(queued,
-			.task = task,
-			.time = now,
-		);
-		array_insert(this->queued_tasks, ARRAY_HEAD, queued);
-	}
-
+	partial_reset(this);
 	this->reset = TRUE;
 }
 
@@ -1978,6 +2007,46 @@ static bool filter_queued(void *unused, queued_task_t **queued, task_t **task)
 	return TRUE;
 }
 
+/*
+ * RFC 6311 section 5.1
+ *
+ *  o  The peer MUST silently drop any received synchronization message
+ *     if M1 is lower than or equal to the highest value it has seen from
+ *     the cluster.  This includes any previous received synchronization
+ *     messages.
+ *
+ *  o  M2 MUST be at least the higher of the received M1, and one more
+ *     than the highest sender value received from the cluster.  This
+ *     includes any previous received synchronization messages.
+ *
+ *  o  P2 MUST be the higher of the received P1 value, and one more than
+ *     the highest sender value used by the peer.
+ */
+
+METHOD(task_manager_t, request_mid_update, bool,
+	private_task_manager_t *this, uint32_t *send, uint32_t *recv)
+{
+	const uint32_t m1 = *send;
+	const uint32_t p1 = *recv;
+	uint32_t m2 = m1;
+	uint32_t p2 = p1;
+
+	if ((this->responding.mid != 0) &&
+		(m1 <= this->responding.mid-1))
+		return FALSE;
+	if (m2 <= this->responding.mid)
+		m2 = this->responding.mid;
+	if (p2 <= this->initiating.mid)
+		p2 = this->initiating.mid;
+	this->initiating.mid = p2;
+	this->responding.mid = 0;
+	this->responding.override_mid = m2-1;
+	*send = p2;
+	*recv = m2;
+	return TRUE;
+}
+
+
 METHOD(task_manager_t, create_task_enumerator, enumerator_t*,
 	private_task_manager_t *this, task_queue_t queue)
 {
@@ -2039,6 +2108,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa)
 				.initiate = _initiate,
 				.retransmit = _retransmit,
 				.incr_mid = _incr_mid,
+				.request_mid_update = _request_mid_update,
 				.reset = _reset,
 				.adopt_tasks = _adopt_tasks,
 				.adopt_child_tasks = _adopt_child_tasks,
diff --git a/src/libcharon/sa/ikev2/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c
index 036910d..de29f45 100644
--- a/src/libcharon/sa/ikev2/tasks/ike_auth.c
+++ b/src/libcharon/sa/ikev2/tasks/ike_auth.c
@@ -417,6 +417,9 @@ METHOD(task_t, build_i, status_t,
 		/* indicate support for EAP-only authentication */
 		message->add_notify(message, FALSE, EAP_ONLY_AUTHENTICATION,
 							chunk_empty);
+		/* indicate support for RFC 6311 Message ID synchronization */
+		message->add_notify(message, FALSE, IKEV2_MESSAGE_ID_SYNC_SUPPORTED,
+							chunk_empty);
 	}
 
 	if (!this->do_another_auth && !this->my_auth)
@@ -991,6 +994,10 @@ METHOD(task_t, process_i, status_t,
 						DBG1(DBG_IKE, "received invalid REDIRECT notify");
 					}
 					break;
+				case IKEV2_MESSAGE_ID_SYNC_SUPPORTED:
+					this->ike_sa->enable_extension(this->ike_sa,
+												   EXT_IKE_MESSAGE_ID_SYNC);
+					break;
 				default:
 				{
 					if (type <= 16383)
diff --git a/src/libcharon/sa/ikev2/tasks/ike_message_id_sync.c b/src/libcharon/sa/ikev2/tasks/ike_message_id_sync.c
new file mode 100644
index 0000000..d121891
--- /dev/null
+++ b/src/libcharon/sa/ikev2/tasks/ike_message_id_sync.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2016 Stephen J. Bevan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "ike_message_id_sync.h"
+#include <time.h>
+
+#include <bio/bio_reader.h>
+#include <daemon.h>
+#include <encoding/payloads/notify_payload.h>
+
+
+typedef struct private_ike_message_id_sync_t private_ike_message_id_sync_t;
+
+/**
+ * Private members of a ike_message_id_sync_t task.
+ */
+struct private_ike_message_id_sync_t {
+
+	/**
+	 * Public methods and task_t interface.
+	 */
+	ike_message_id_sync_t public;
+
+	/**
+	 * Assigned IKE_SA.
+	 */
+	ike_sa_t *ike_sa;
+
+	chunk_t nonce;
+	uint32_t send;
+	uint32_t recv;
+	int reply_needed;
+};
+
+
+METHOD(task_t, build, status_t,
+	private_ike_message_id_sync_t *this, message_t *message)
+{
+	chunk_t chunk;
+	uint32_t send = htonl(this->send);
+	uint32_t recv = htonl(this->recv);
+
+	if (this->reply_needed &&
+	    (message->get_exchange_type(message) == INFORMATIONAL))
+	{
+		chunk = chunk_cata("ccc", this->nonce, chunk_from_thing(send), chunk_from_thing(recv));
+		message->add_notify(message, FALSE, IKEV2_MESSAGE_ID_SYNC, chunk);
+		this->reply_needed = 0;
+		return SUCCESS;
+	}
+	return NEED_MORE;
+}
+
+
+/*
+ * Encoding of IKEV2_MESSAGE_SYNC_ID
+ *
+
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   | Next Payload  |C|  RESERVED   |         Payload Length        |
+
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |Protocol ID(=0)| SPI Size (=0) |      Notify Message Type      |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+   |             Nonce Data                                        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |             EXPECTED_SEND_REQ_MESSAGE_ID                      |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |             EXPECTED_RECV_REQ_MESSAGE_ID                      |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * read notifies from message and evaluate them
+ */
+static status_t process_info(private_ike_message_id_sync_t *this,
+							 message_t *message)
+{
+	bio_reader_t *reader;
+	notify_payload_t *notify;
+	chunk_t data;
+
+	if (message->get_message_id(message) != 0)
+		return NEED_MORE;
+	notify = message->get_notify(message, IKEV2_MESSAGE_ID_SYNC);
+	if (!notify)
+		return NEED_MORE;
+	data = notify->get_notification_data(notify);
+	reader = bio_reader_create(data);
+	if (!reader)
+		return NEED_MORE;
+	if (this->reply_needed)
+		chunk_free(&this->nonce);
+	if (!reader->read_data(reader, 4, &this->nonce))
+		goto invalid_msg;
+	this->reply_needed = 1;
+	if (!reader->read_uint32(reader, &this->send)) 
+		goto invalid_msg;
+	if (!reader->read_uint32(reader, &this->recv))
+		goto invalid_msg;
+	reader->destroy(reader);
+	this->ike_sa->message_id_sync(this->ike_sa, &this->send, &this->recv);
+	return NEED_MORE;
+
+invalid_msg:
+	if (this->reply_needed)
+	{
+		chunk_free(&this->nonce);
+		this->reply_needed = 0;
+	}
+	reader->destroy(reader);
+	DBG1(DBG_ENC, "invalid IKEV2_MESSAGE_ID_SYNC notify data");
+	return NEED_MORE;
+}
+
+
+METHOD(task_t, process, status_t,
+	private_ike_message_id_sync_t *this, message_t *message)
+{
+	if (message->get_exchange_type(message) != INFORMATIONAL)
+		goto done;
+	if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)
+		goto done;
+	if (!this->ike_sa->supports_extension(this->ike_sa, EXT_IKE_MESSAGE_ID_SYNC))
+		goto done;
+	return process_info(this, message);
+done:
+	return NEED_MORE;
+}
+
+
+METHOD(task_t, get_type, task_type_t,
+	private_ike_message_id_sync_t *this)
+{
+	return TASK_IKE_MESSAGE_ID_SYNC;
+}
+
+METHOD(task_t, migrate, void,
+	private_ike_message_id_sync_t *this, ike_sa_t *ike_sa)
+{
+	this->ike_sa = ike_sa;
+}
+
+METHOD(task_t, destroy, void,
+	private_ike_message_id_sync_t *this)
+{
+	free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_message_id_sync_t *ike_message_id_sync_create(ike_sa_t *ike_sa)
+{
+	private_ike_message_id_sync_t *this;
+
+	INIT(this,
+		.public = {
+			.task = {
+				.get_type = _get_type,
+				.build = _build,
+				.process = _process,
+				.migrate = _migrate,
+				.destroy = _destroy,
+			},
+		},
+		.ike_sa = ike_sa,
+		.nonce = chunk_empty,
+		.reply_needed = 0,
+	);
+	return &this->public;
+}
diff --git a/src/libcharon/sa/ikev2/tasks/ike_message_id_sync.h b/src/libcharon/sa/ikev2/tasks/ike_message_id_sync.h
new file mode 100644
index 0000000..9e48582
--- /dev/null
+++ b/src/libcharon/sa/ikev2/tasks/ike_message_id_sync.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 Stephen J. Bevan
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+/**
+ * @defgroup ike_message_id_sync ike_message_id_sync
+ * @{ @ingroup tasks_v2
+ */
+
+#ifndef IKE_MESSAGE_ID_SYNC_H_
+#define IKE_MESSAGE_ID_SYNC_H_
+
+typedef struct ike_message_id_sync_t ike_message_id_sync_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/task.h>
+
+/**
+ * Task of type TASK_IKE_MESSAGE_ID_SYNC, implements RFC 6311 responder.
+ *
+ * This task handles a IKEV2_MESSAGE_ID_SYNC message send by a peer
+ * and if acceptable updates the SA MIDs and replies with the updated
+ * MID values.
+ *
+ * Note there is no support for initiating IKEV2_MESSAGE_ID_SYNC since
+ * the HA system takes care of syncing IKE SAs and so initiating a
+ * IKEV2_MESSAGE_ID_SYNC is not necessary.
+ */
+struct ike_message_id_sync_t {
+
+	/**
+	 * Implements the task_t interface
+	 */
+	task_t task;
+};
+
+/**
+ * Create a new TASK_IKE_MESSAGE_ID_SYNC task.
+ *
+ * @param ike_sa		IKE_SA this task works for
+ * @return			ike_message_id_sync task to handle by the task_manager
+ */
+ike_message_id_sync_t *ike_message_id_sync_create(ike_sa_t *ike_sa);
+
+#endif /** IKE_MESSAGE_ID_SYNC_H_ @}*/
diff --git a/src/libcharon/sa/task.h b/src/libcharon/sa/task.h
index 31d70fb..d6ba436 100644
--- a/src/libcharon/sa/task.h
+++ b/src/libcharon/sa/task.h
@@ -103,6 +103,8 @@ enum task_type_t {
 	TASK_ISAKMP_CERT_PRE,
 	/** IKEv1 post-authentication certificate handling */
 	TASK_ISAKMP_CERT_POST,
+	/** IKEv2_MESSAGE_ID_SYNC handling, RFC6311 */
+	TASK_IKE_MESSAGE_ID_SYNC,
 };
 
 /**
diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h
index 86077d3..f0ef2eb 100644
--- a/src/libcharon/sa/task_manager.h
+++ b/src/libcharon/sa/task_manager.h
@@ -256,6 +256,21 @@ struct task_manager_t {
 	void (*reset) (task_manager_t *this, uint32_t initiate, uint32_t respond);
 
 	/**
+	 * The IKEv2 peer has sent a IKEV2_MESSAGE_SYNC_ID containing its
+	 * expected send message ID and expected receive message ID which
+	 * are almost certainly wrong since they come from a device that
+	 * is not in HA sync with the peer that the last IKE messages were
+	 * sent to or received from.  The goal is to update the send/recv
+	 * numbers with the ones that IKE SA has so that the updated values
+	 * can be sent back to the peer to re-synchronize its message IDs.
+	 *
+	 * @param send			expected send message ID
+	 * @param recv			expected receive message ID
+	 * @return				true if the message IDs are updated
+	 */
+	bool (*request_mid_update) (task_manager_t *this, uint32_t *send, uint32_t *recv);
+
+	/**
 	 * Check if we are currently waiting for a reply.
 	 *
 	 * @return				TRUE if we are waiting, FALSE otherwise
-- 
1.9.1

_______________________________________________
Dev mailing list
[email protected]
https://lists.strongswan.org/mailman/listinfo/dev

Reply via email to