738 lines
27 KiB
Diff
738 lines
27 KiB
Diff
From d421aeb263d81bacb92e392c65910054f71f9843 Mon Sep 17 00:00:00 2001
|
|
From: Andrew Cagney <cagney@gnu.org>
|
|
Date: Thu, 16 Jan 2025 19:28:00 -0500
|
|
Subject: [PATCH 1/4] revival: move state specific pexpects to
|
|
scheduled_{ike,child}_revival()
|
|
|
|
---
|
|
programs/pluto/revival.c | 101 +++++++++++++++++++--------------------
|
|
programs/pluto/revival.h | 4 +-
|
|
programs/pluto/routing.c | 21 ++++++--
|
|
3 files changed, 66 insertions(+), 60 deletions(-)
|
|
|
|
diff --git a/programs/pluto/revival.c b/programs/pluto/revival.c
|
|
index 0da0d7e4d2..8a2c779c18 100644
|
|
--- a/programs/pluto/revival.c
|
|
+++ b/programs/pluto/revival.c
|
|
@@ -191,58 +191,9 @@ static void schedule_revival_event(struct connection *c, struct logger *logger,
|
|
(impair.revival ? "revival" : NULL), logger);
|
|
}
|
|
|
|
-bool scheduled_revival(struct connection *c, struct state *st/*can be NULL*/,
|
|
- const char *subplot, struct logger *logger)
|
|
+static bool scheduled_revival(struct connection *c, struct state *st/*can be NULL*/,
|
|
+ const char *subplot, struct logger *logger)
|
|
{
|
|
- if (st != NULL) {
|
|
- /*
|
|
- * pexpect() ST is the owner. Routing should never
|
|
- * call when it isn't.
|
|
- */
|
|
- if (IS_CHILD_SA(st)) {
|
|
- if (c->negotiating_child_sa != SOS_NOBODY &&
|
|
- c->negotiating_child_sa != st->st_serialno) {
|
|
- /*
|
|
- * There's a newer SA playing with the routing.
|
|
- * Presumably this is an old Child SA that is in the
|
|
- * process of being rekeyed or replaced.
|
|
- */
|
|
- llog_pexpect(st->logger, HERE,
|
|
- "revival: skipping, .negotiating_child_sa "PRI_SO" is not us",
|
|
- pri_so(c->negotiating_child_sa));
|
|
- return false;
|
|
- }
|
|
-
|
|
- if (c->established_child_sa != SOS_NOBODY &&
|
|
- c->established_child_sa != st->st_serialno) {
|
|
- /* should be covered by above */
|
|
- llog_pexpect(st->logger, HERE,
|
|
- "revival: skipping, .established_child_sa "PRI_SO" is not us",
|
|
- pri_so(c->established_child_sa));
|
|
- return false;
|
|
- }
|
|
- }
|
|
-
|
|
- if (IS_IKE_SA(st)) {
|
|
- if (c->negotiating_ike_sa != SOS_NOBODY &&
|
|
- c->negotiating_ike_sa != st->st_serialno) {
|
|
- /* should be covered by above */
|
|
- llog_pexpect(st->logger, HERE,
|
|
- "revival: skipping, .negotiating_ike_sa "PRI_SO" is is not us",
|
|
- pri_so(c->negotiating_ike_sa));
|
|
- return false;
|
|
- }
|
|
- if (c->established_ike_sa != SOS_NOBODY &&
|
|
- c->established_ike_sa != st->st_serialno) {
|
|
- /* should be covered by above */
|
|
- llog_pexpect(st->logger, HERE,
|
|
- "revival: skipping, .established_ike_sa "PRI_SO" is is not us",
|
|
- pri_so(c->established_ike_sa));
|
|
- return false;
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
if (!revival_plausable(c, logger)) {
|
|
return false;
|
|
}
|
|
@@ -275,14 +226,58 @@ bool scheduled_revival(struct connection *c, struct state *st/*can be NULL*/,
|
|
|
|
}
|
|
|
|
+bool scheduled_connection_revival(struct connection *c, const char *subplot)
|
|
+{
|
|
+ return scheduled_revival(c, NULL, subplot, c->logger);
|
|
+}
|
|
+
|
|
bool scheduled_child_revival(struct child_sa *child, const char *subplot)
|
|
{
|
|
- return scheduled_revival(child->sa.st_connection, &child->sa, subplot, child->sa.logger);
|
|
+ struct connection *c = child->sa.st_connection;
|
|
+ if (c->negotiating_child_sa != SOS_NOBODY &&
|
|
+ c->negotiating_child_sa != child->sa.st_serialno) {
|
|
+ /*
|
|
+ * There's a newer SA playing with the routing.
|
|
+ * Presumably this is an old Child SA that is in the
|
|
+ * process of being rekeyed or replaced.
|
|
+ */
|
|
+ llog_pexpect(child->sa.logger, HERE,
|
|
+ "revival: skipping, .negotiating_child_sa "PRI_SO" is not us",
|
|
+ pri_so(c->negotiating_child_sa));
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (c->established_child_sa != SOS_NOBODY &&
|
|
+ c->established_child_sa != child->sa.st_serialno) {
|
|
+ /* should be covered by above */
|
|
+ llog_pexpect(child->sa.logger, HERE,
|
|
+ "revival: skipping, .established_child_sa "PRI_SO" is not us",
|
|
+ pri_so(c->established_child_sa));
|
|
+ return false;
|
|
+ }
|
|
+ return scheduled_revival(c, &child->sa, subplot, child->sa.logger);
|
|
}
|
|
|
|
bool scheduled_ike_revival(struct ike_sa *ike, const char *subplot)
|
|
{
|
|
- return scheduled_revival(ike->sa.st_connection, &ike->sa, subplot, ike->sa.logger);
|
|
+ struct connection *c = ike->sa.st_connection;
|
|
+ if (c->negotiating_ike_sa != SOS_NOBODY &&
|
|
+ c->negotiating_ike_sa != ike->sa.st_serialno) {
|
|
+ /* should be covered by above */
|
|
+ llog_pexpect(ike->sa.logger, HERE,
|
|
+ "revival: skipping, .negotiating_ike_sa "PRI_SO" is is not us",
|
|
+ pri_so(c->negotiating_ike_sa));
|
|
+ return false;
|
|
+ }
|
|
+ if (c->established_ike_sa != SOS_NOBODY &&
|
|
+ c->established_ike_sa != ike->sa.st_serialno) {
|
|
+ /* should be covered by above */
|
|
+ llog_pexpect(ike->sa.logger, HERE,
|
|
+ "revival: skipping, .established_ike_sa "PRI_SO" is is not us",
|
|
+ pri_so(c->established_ike_sa));
|
|
+ return false;
|
|
+ }
|
|
+ return scheduled_revival(c, &ike->sa, subplot, ike->sa.logger);
|
|
}
|
|
|
|
void revive_connection(struct connection *c, const char *subplot,
|
|
diff --git a/programs/pluto/revival.h b/programs/pluto/revival.h
|
|
index dad6705301..13b00980dd 100644
|
|
--- a/programs/pluto/revival.h
|
|
+++ b/programs/pluto/revival.h
|
|
@@ -25,14 +25,12 @@ struct timer_event;
|
|
void revive_connection(struct connection *c, const char *subplot,
|
|
const threadtime_t *inception);
|
|
|
|
-bool scheduled_revival(struct connection *c, struct state *st, /*could-be-NULL*/
|
|
- const char *subplot, struct logger *logger);
|
|
-
|
|
/*
|
|
* As in the SA's connection should be kept up so the call scheduled a
|
|
* revival. Caller should adjust routing accordingly.
|
|
*/
|
|
|
|
+bool scheduled_connection_revival(struct connection *c, const char *subplot);
|
|
bool scheduled_child_revival(struct child_sa *child, const char *subplot);
|
|
bool scheduled_ike_revival(struct ike_sa *ike, const char *subplot);
|
|
|
|
diff --git a/programs/pluto/routing.c b/programs/pluto/routing.c
|
|
index 91115ab081..dd9b39721c 100644
|
|
--- a/programs/pluto/routing.c
|
|
+++ b/programs/pluto/routing.c
|
|
@@ -104,14 +104,27 @@ static bool connection_cannot_die(enum routing_event event,
|
|
struct logger *logger,
|
|
const struct routing_annex *e)
|
|
{
|
|
- struct state *st = (e->child != NULL && (*e->child) != NULL ? &(*e->child)->sa :
|
|
- e->ike != NULL && (*e->ike) != NULL ? &(*e->ike)->sa :
|
|
- NULL);
|
|
const char *subplot = (event == CONNECTION_TEARDOWN_IKE ? e->story :
|
|
event == CONNECTION_TEARDOWN_CHILD ? e->story :
|
|
event == CONNECTION_RESCHEDULE ? e->story :
|
|
"???");
|
|
- return scheduled_revival(c, st, subplot, logger);
|
|
+ if (e->child != NULL) {
|
|
+ struct child_sa *child = (*e->child);
|
|
+ if (child != NULL) {
|
|
+ PEXPECT(logger, child->sa.st_connection == c);
|
|
+ return scheduled_child_revival(child, subplot);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (e->ike != NULL) {
|
|
+ struct ike_sa *ike = (*e->ike);
|
|
+ if (ike != NULL) {
|
|
+ PEXPECT(logger, ike->sa.st_connection == c);
|
|
+ return scheduled_ike_revival(ike, subplot);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return scheduled_connection_revival(c, subplot);
|
|
}
|
|
|
|
static void jam_sa(struct jambuf *buf, struct state *st, const char **sep)
|
|
--
|
|
2.48.1
|
|
|
|
|
|
From e474d36c43798898fa89d28ba302868399329f95 Mon Sep 17 00:00:00 2001
|
|
From: Andrew Cagney <cagney@gnu.org>
|
|
Date: Thu, 16 Jan 2025 20:20:24 -0500
|
|
Subject: [PATCH 2/4] revival: don't expect the IKE SA have
|
|
.{established,negotiating}_ike_sa
|
|
|
|
A crossing stream where this end initiated the connection's
|
|
IKE SA but is then crossed by the peer establishing the
|
|
connection's IKE SA only to connswitch to another
|
|
connection for the Child SA - leaves .negotiating_sa
|
|
but nothing else.
|
|
|
|
see #1989 EXPECTATION FAILED: revival: skipping, .negotiating_ike_sa is not us
|
|
---
|
|
programs/pluto/revival.c | 25 +++++++++++++++----------
|
|
1 file changed, 15 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/programs/pluto/revival.c b/programs/pluto/revival.c
|
|
index 8a2c779c18..fe76d1039e 100644
|
|
--- a/programs/pluto/revival.c
|
|
+++ b/programs/pluto/revival.c
|
|
@@ -261,21 +261,26 @@ bool scheduled_child_revival(struct child_sa *child, const char *subplot)
|
|
bool scheduled_ike_revival(struct ike_sa *ike, const char *subplot)
|
|
{
|
|
struct connection *c = ike->sa.st_connection;
|
|
- if (c->negotiating_ike_sa != SOS_NOBODY &&
|
|
- c->negotiating_ike_sa != ike->sa.st_serialno) {
|
|
- /* should be covered by above */
|
|
+ if (c->routing_sa != ike->sa.st_serialno) {
|
|
llog_pexpect(ike->sa.logger, HERE,
|
|
- "revival: skipping, .negotiating_ike_sa "PRI_SO" is is not us",
|
|
- pri_so(c->negotiating_ike_sa));
|
|
+ "revival: skipping, .routing_sa "PRI_SO" is is not us",
|
|
+ pri_so(c->routing_sa));
|
|
return false;
|
|
}
|
|
+ if (c->negotiating_ike_sa != SOS_NOBODY &&
|
|
+ c->negotiating_ike_sa != ike->sa.st_serialno) {
|
|
+ /*
|
|
+ * For instance, crossing stream establishes IKE SA,
|
|
+ * but some other Child SA, leaving .routing_sa
|
|
+ * hanging.
|
|
+ */
|
|
+ ldbg(ike->sa.logger, "revival: .negotiating_ike_sa "PRI_SO" is is not us",
|
|
+ pri_so(c->negotiating_ike_sa));
|
|
+ }
|
|
if (c->established_ike_sa != SOS_NOBODY &&
|
|
c->established_ike_sa != ike->sa.st_serialno) {
|
|
- /* should be covered by above */
|
|
- llog_pexpect(ike->sa.logger, HERE,
|
|
- "revival: skipping, .established_ike_sa "PRI_SO" is is not us",
|
|
- pri_so(c->established_ike_sa));
|
|
- return false;
|
|
+ ldbg(ike->sa.logger, "revival: .established_ike_sa "PRI_SO" is is not us",
|
|
+ pri_so(c->established_ike_sa));
|
|
}
|
|
return scheduled_revival(c, &ike->sa, subplot, ike->sa.logger);
|
|
}
|
|
--
|
|
2.48.1
|
|
|
|
|
|
From c70b4bf00dee27d35a438bdac9ed78ea76127384 Mon Sep 17 00:00:00 2001
|
|
From: Andrew Cagney <cagney@gnu.org>
|
|
Date: Thu, 16 Jan 2025 17:22:09 -0500
|
|
Subject: [PATCH 3/4] testing: add WIP
|
|
crossing-streams-23-conswitch-ike-sa-init-ikev2, see #1989
|
|
|
|
---
|
|
testing/pluto/TESTLIST | 1 +
|
|
.../01-east-init.sh | 11 ++
|
|
.../02-west-init.sh | 9 ++
|
|
.../03-west-ike-sa-init.sh | 13 +++
|
|
.../04-east-establish.sh | 6 ++
|
|
.../05-west-crossing-stream.sh | 9 ++
|
|
.../description.txt | 34 ++++++
|
|
.../east.console.txt | 74 +++++++++++++
|
|
.../final.sh | 6 ++
|
|
.../ipsec.conf | 32 ++++++
|
|
.../ipsec.secrets | 1 +
|
|
.../west.console.txt | 101 ++++++++++++++++++
|
|
12 files changed, 297 insertions(+)
|
|
create mode 100755 testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/01-east-init.sh
|
|
create mode 100755 testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/02-west-init.sh
|
|
create mode 100644 testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/03-west-ike-sa-init.sh
|
|
create mode 100644 testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/04-east-establish.sh
|
|
create mode 100644 testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/05-west-crossing-stream.sh
|
|
create mode 100644 testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/description.txt
|
|
create mode 100644 testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/east.console.txt
|
|
create mode 100755 testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/final.sh
|
|
create mode 100644 testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/ipsec.conf
|
|
create mode 100644 testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/ipsec.secrets
|
|
create mode 100644 testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/west.console.txt
|
|
|
|
diff --git a/testing/pluto/TESTLIST b/testing/pluto/TESTLIST
|
|
index 49d65fb534..24697f3786 100644
|
|
--- a/testing/pluto/TESTLIST
|
|
+++ b/testing/pluto/TESTLIST
|
|
@@ -1562,6 +1562,7 @@ kvmplutotest crossing-streams-20-peer-restarts-ondemand-ike-auth good github/163
|
|
|
|
kvmplutotest crossing-streams-21-second-child-crypto-ikev2 good
|
|
kvmplutotest crossing-streams-22-ikev2-ipsec-interface wip github:557
|
|
+kvmplutotest crossing-streams-23-conswitch-ike-sa-init-ikev2 wip github/1989
|
|
|
|
# uses the kernel-pfkeyv2.c code
|
|
|
|
diff --git a/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/01-east-init.sh b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/01-east-init.sh
|
|
new file mode 100755
|
|
index 0000000000..5eac31179d
|
|
--- /dev/null
|
|
+++ b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/01-east-init.sh
|
|
@@ -0,0 +1,11 @@
|
|
+/testing/guestbin/swan-prep --nokey
|
|
+
|
|
+../../guestbin/ifconfig.sh eth0 add 192.0.20.254/24
|
|
+
|
|
+ipsec start
|
|
+../../guestbin/wait-until-pluto-started
|
|
+
|
|
+ipsec whack --impair suppress_retransmits
|
|
+
|
|
+ipsec add a
|
|
+ipsec add b
|
|
diff --git a/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/02-west-init.sh b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/02-west-init.sh
|
|
new file mode 100755
|
|
index 0000000000..3690498351
|
|
--- /dev/null
|
|
+++ b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/02-west-init.sh
|
|
@@ -0,0 +1,9 @@
|
|
+/testing/guestbin/swan-prep --nokey
|
|
+ipsec start
|
|
+../../guestbin/wait-until-pluto-started
|
|
+
|
|
+ipsec whack --impair suppress_retransmits
|
|
+
|
|
+# note order
|
|
+ipsec add a
|
|
+ipsec add b
|
|
diff --git a/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/03-west-ike-sa-init.sh b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/03-west-ike-sa-init.sh
|
|
new file mode 100644
|
|
index 0000000000..65837088f5
|
|
--- /dev/null
|
|
+++ b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/03-west-ike-sa-init.sh
|
|
@@ -0,0 +1,13 @@
|
|
+# Initiate "a" with all packets blocked.
|
|
+#
|
|
+# This will create the negotiating IKE SA #1, and then hang.
|
|
+
|
|
+ipsec whack --impair block_outbound:yes
|
|
+ipsec up a --asynchronous
|
|
+../../guestbin/wait-for-pluto.sh --match '"a" #1: IMPAIR: blocking outbound message 1'
|
|
+../../guestbin/wait-for-pluto.sh --match '"a" #1: sent IKE_SA_INIT request'
|
|
+
|
|
+# With connection "a"'s IKE SA #1 stuck, unblock so that the peer's
|
|
+# IKE SA #2, which will cross "a", can establish
|
|
+
|
|
+ipsec whack --impair block_outbound:no
|
|
diff --git a/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/04-east-establish.sh b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/04-east-establish.sh
|
|
new file mode 100644
|
|
index 0000000000..668613881b
|
|
--- /dev/null
|
|
+++ b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/04-east-establish.sh
|
|
@@ -0,0 +1,6 @@
|
|
+# Initiate "b" from EAST.
|
|
+#
|
|
+# On WEST this is will match and establish connection "a" with IKE SA
|
|
+# #2, and then switch to connection "b" for Child SA #3.
|
|
+
|
|
+ipsec up b
|
|
diff --git a/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/05-west-crossing-stream.sh b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/05-west-crossing-stream.sh
|
|
new file mode 100644
|
|
index 0000000000..dc8387a82f
|
|
--- /dev/null
|
|
+++ b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/05-west-crossing-stream.sh
|
|
@@ -0,0 +1,9 @@
|
|
+# confirm that the peer's IKE SA established "a", and then the peer's
|
|
+# Child SA needed to switch to "b" before establishing.
|
|
+
|
|
+../../guestbin/wait-for-pluto.sh --match '"a" #2: responder established IKE SA'
|
|
+../../guestbin/wait-for-pluto.sh --match '"a" #3: switched to "b"'
|
|
+../../guestbin/wait-for-pluto.sh --match '"b" #3: responder established Child SA using #2'
|
|
+
|
|
+# this is where pluto realises that the stream crossed
|
|
+../../guestbin/wait-for-pluto.sh --match '#1: dropping negotiation'
|
|
diff --git a/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/description.txt b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/description.txt
|
|
new file mode 100644
|
|
index 0000000000..52806b90d5
|
|
--- /dev/null
|
|
+++ b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/description.txt
|
|
@@ -0,0 +1,34 @@
|
|
+IKE exchange crosses, initiator conswitches peer's child leaving local ike hanging
|
|
+
|
|
+each end has two connections that can share their IKE SA
|
|
+
|
|
+- WEST sends "a":IKE_SA_INIT to EAST
|
|
+ - creates IKE SA #1
|
|
+ - initiator sets "a".{routing,negotiating}_ike_sa to #1
|
|
+
|
|
+- EAST sends "b":IKE_SA_INIT to WEST
|
|
+
|
|
+- WEST responds to EAST'S "b":IKE_SA_INIT
|
|
+ - creates IKE_SA #2 using connection "a"
|
|
+ - responder leaves "a".{routing,negotiating}_ike_sa et.al. untouched
|
|
+
|
|
+- EAST sends "b":IKE_AUTH to WEST
|
|
+
|
|
+- WEST responds to EAST's "b":IKE_AUTH
|
|
+ IKE
|
|
+ - establishes IKE SA #2
|
|
+ - sets "a".{established,negotiating}_ike_sa #2
|
|
+ - leaves "a".routing_sa set to #1
|
|
+ Child:
|
|
+ - creates Child SA #3
|
|
+ - connswitches Child SA #3 to "b"
|
|
+ - establishes Child SA #3
|
|
+ - sets "b".{routing,negotiating,established}_child_sa to #3
|
|
+
|
|
+- WEST retransmits "a":IKE_SA_INIT #1 to EAST
|
|
+ - sees .established_ike_sa(?) is #2 stops negotiation
|
|
+ "tun-out-1" #1: suppressing retransmit because IKE SA was superseded #2; drop this negotiation
|
|
+ - tries to revive:
|
|
+ EXPECTATION FAILED: "a" #1: revival: skipping, .negotiating_ike_sa #2 is is not us
|
|
+
|
|
+ref github #1989
|
|
diff --git a/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/east.console.txt b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/east.console.txt
|
|
new file mode 100644
|
|
index 0000000000..d386cabf02
|
|
--- /dev/null
|
|
+++ b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/east.console.txt
|
|
@@ -0,0 +1,74 @@
|
|
+/testing/guestbin/swan-prep --nokey
|
|
+Creating empty NSS database
|
|
+east #
|
|
+ ../../guestbin/ifconfig.sh eth0 add 192.0.20.254/24
|
|
+ inet 192.0.20.254/24 scope global eth0
|
|
+east #
|
|
+ ipsec start
|
|
+Redirecting to: [initsystem]
|
|
+east #
|
|
+ ../../guestbin/wait-until-pluto-started
|
|
+east #
|
|
+ ipsec whack --impair suppress_retransmits
|
|
+east #
|
|
+ ipsec add a
|
|
+"a": added IKEv2 connection
|
|
+east #
|
|
+ ipsec add b
|
|
+"b": added IKEv2 connection
|
|
+east #
|
|
+ # Initiate "b" from EAST.
|
|
+east #
|
|
+ #
|
|
+east #
|
|
+ # On WEST this is will match and establish connection "a" with IKE SA
|
|
+east #
|
|
+ # #2, and then switch to connection "b" for Child SA #3.
|
|
+east #
|
|
+ ipsec up b
|
|
+"b" #1: initiating IKEv2 connection to 192.1.2.45 using UDP
|
|
+"b" #1: sent IKE_SA_INIT request to 192.1.2.45:UDP/500
|
|
+"b" #1: processed IKE_SA_INIT response from 192.1.2.45:UDP/500 {cipher=AES_GCM_16_256 integ=n/a prf=HMAC_SHA2_512 group=DH19}, initiating IKE_AUTH
|
|
+"b" #1: sent IKE_AUTH request to 192.1.2.45:UDP/500
|
|
+"b" #1: initiator established IKE SA; authenticated peer using authby=secret and ID_FQDN '@west'
|
|
+"b" #2: initiator established Child SA using #1; IPsec tunnel [192.0.20.0/24===192.0.3.0/24] {ESP/ESN=>0xESPESP <0xESPESP xfrm=AES_GCM_16_256-NONE DPD=passive}
|
|
+east #
|
|
+ # non-zero counts confirm encrypted traffic flowing
|
|
+east #
|
|
+ ipsec trafficstatus
|
|
+#2: "b", type=ESP, add_time=1234567890, inBytes=0, outBytes=0, maxBytes=2^63B, id='@west'
|
|
+east #
|
|
+ # do things line up?
|
|
+east #
|
|
+ ../../guestbin/ipsec-kernel-state.sh
|
|
+src 192.1.2.23 dst 192.1.2.45
|
|
+ proto esp spi 0xSPISPI reqid REQID mode tunnel
|
|
+ replay-window 0 flag af-unspec esn
|
|
+ aead rfc4106(gcm(aes)) 0xENCAUTHKEY 128
|
|
+ anti-replay esn context:
|
|
+ seq-hi 0x0, seq 0xXX, oseq-hi 0x0, oseq 0xXX
|
|
+ replay_window 0, bitmap-length 0
|
|
+src 192.1.2.45 dst 192.1.2.23
|
|
+ proto esp spi 0xSPISPI reqid REQID mode tunnel
|
|
+ replay-window 0 flag af-unspec esn
|
|
+ aead rfc4106(gcm(aes)) 0xENCAUTHKEY 128
|
|
+ anti-replay esn context:
|
|
+ seq-hi 0x0, seq 0xXX, oseq-hi 0x0, oseq 0xXX
|
|
+ replay_window 128, bitmap-length 4
|
|
+ 00000000 00000000 00000000 XXXXXXXX
|
|
+east #
|
|
+ ../../guestbin/ipsec-kernel-policy.sh
|
|
+src 192.0.3.0/24 dst 192.0.20.0/24
|
|
+ dir fwd priority PRIORITY ptype main
|
|
+ tmpl src 192.1.2.45 dst 192.1.2.23
|
|
+ proto esp reqid REQID mode tunnel
|
|
+src 192.0.3.0/24 dst 192.0.20.0/24
|
|
+ dir in priority PRIORITY ptype main
|
|
+ tmpl src 192.1.2.45 dst 192.1.2.23
|
|
+ proto esp reqid REQID mode tunnel
|
|
+src 192.0.20.0/24 dst 192.0.3.0/24
|
|
+ dir out priority PRIORITY ptype main
|
|
+ tmpl src 192.1.2.23 dst 192.1.2.45
|
|
+ proto esp reqid REQID mode tunnel
|
|
+east #
|
|
+
|
|
diff --git a/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/final.sh b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/final.sh
|
|
new file mode 100755
|
|
index 0000000000..c84a482b6a
|
|
--- /dev/null
|
|
+++ b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/final.sh
|
|
@@ -0,0 +1,6 @@
|
|
+# non-zero counts confirm encrypted traffic flowing
|
|
+ipsec trafficstatus
|
|
+
|
|
+# do things line up?
|
|
+../../guestbin/ipsec-kernel-state.sh
|
|
+../../guestbin/ipsec-kernel-policy.sh
|
|
diff --git a/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/ipsec.conf b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/ipsec.conf
|
|
new file mode 100644
|
|
index 0000000000..cb3d584bc2
|
|
--- /dev/null
|
|
+++ b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/ipsec.conf
|
|
@@ -0,0 +1,32 @@
|
|
+config setup
|
|
+ logfile=/tmp/pluto.log
|
|
+ logtime=no
|
|
+ logappend=no
|
|
+ dumpdir=/var/tmp
|
|
+ plutodebug=all
|
|
+ nhelpers=0
|
|
+
|
|
+conn base
|
|
+ keyexchange=ikev2
|
|
+ auto=ignore
|
|
+ # host
|
|
+ left=192.1.2.45
|
|
+ right=192.1.2.23
|
|
+ # auth
|
|
+ leftid=@west
|
|
+ rightid=@east
|
|
+ authby=secret
|
|
+ leftsubnet=192.0.3.0/24
|
|
+ retransmit-timeout=10s
|
|
+
|
|
+conn a
|
|
+ also=base
|
|
+ # client
|
|
+ leftsourceip=192.0.3.253
|
|
+ rightsubnet=192.0.2.0/24
|
|
+
|
|
+conn b
|
|
+ also=base
|
|
+ # client
|
|
+ leftsourceip=192.0.3.254
|
|
+ rightsubnet=192.0.20.0/24
|
|
diff --git a/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/ipsec.secrets b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/ipsec.secrets
|
|
new file mode 100644
|
|
index 0000000000..d3ed5698d0
|
|
--- /dev/null
|
|
+++ b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/ipsec.secrets
|
|
@@ -0,0 +1 @@
|
|
+@west @east : PSK "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
|
diff --git a/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/west.console.txt b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/west.console.txt
|
|
new file mode 100644
|
|
index 0000000000..00c98494e5
|
|
--- /dev/null
|
|
+++ b/testing/pluto/crossing-streams-23-conswitch-ike-sa-init-ikev2/west.console.txt
|
|
@@ -0,0 +1,101 @@
|
|
+/testing/guestbin/swan-prep --nokey
|
|
+Creating empty NSS database
|
|
+west #
|
|
+ ipsec start
|
|
+Redirecting to: [initsystem]
|
|
+west #
|
|
+ ../../guestbin/wait-until-pluto-started
|
|
+west #
|
|
+ ipsec whack --impair suppress_retransmits
|
|
+west #
|
|
+ # note order
|
|
+west #
|
|
+ ipsec add a
|
|
+"a": added IKEv2 connection
|
|
+west #
|
|
+ ipsec add b
|
|
+"b": added IKEv2 connection
|
|
+west #
|
|
+ # Initiate "a" with all packets blocked.
|
|
+west #
|
|
+ #
|
|
+west #
|
|
+ # This will create the negotiating IKE SA #1, and then hang.
|
|
+west #
|
|
+ ipsec whack --impair block_outbound:yes
|
|
+IMPAIR: recording all outbound messages
|
|
+IMPAIR: block all outbound messages: no -> yes
|
|
+west #
|
|
+ ipsec up a --asynchronous
|
|
+"a" #1: initiating IKEv2 connection to 192.1.2.23 using UDP
|
|
+west #
|
|
+ ../../guestbin/wait-for-pluto.sh --match '"a" #1: IMPAIR: blocking outbound message 1'
|
|
+"a" #1: IMPAIR: blocking outbound message 1
|
|
+west #
|
|
+ ../../guestbin/wait-for-pluto.sh --match '"a" #1: sent IKE_SA_INIT request'
|
|
+"a" #1: sent IKE_SA_INIT request to 192.1.2.23:UDP/500
|
|
+west #
|
|
+ # With connection "a"'s IKE SA #1 stuck, unblock so that the peer's
|
|
+west #
|
|
+ # IKE SA #2, which will cross "a", can establish
|
|
+west #
|
|
+ ipsec whack --impair block_outbound:no
|
|
+IMPAIR: block all outbound messages: yes -> no
|
|
+west #
|
|
+ # confirm that the peer's IKE SA established "a", and then the peer's
|
|
+west #
|
|
+ # Child SA needed to switch to "b" before establishing.
|
|
+west #
|
|
+ ../../guestbin/wait-for-pluto.sh --match '"a" #2: responder established IKE SA'
|
|
+"a" #2: responder established IKE SA; authenticated peer using authby=secret and ID_FQDN '@east'
|
|
+west #
|
|
+ ../../guestbin/wait-for-pluto.sh --match '"a" #3: switched to "b"'
|
|
+"a" #3: switched to "b"
|
|
+west #
|
|
+ ../../guestbin/wait-for-pluto.sh --match '"b" #3: responder established Child SA using #2'
|
|
+"b" #3: responder established Child SA using #2; IPsec tunnel [192.0.3.0/24===192.0.20.0/24] {ESP/ESN=>0xESPESP <0xESPESP xfrm=AES_GCM_16_256-NONE DPD=passive}
|
|
+west #
|
|
+ # this is where pluto realises that the stream crossed
|
|
+west #
|
|
+ ../../guestbin/wait-for-pluto.sh --match '#1: dropping negotiation'
|
|
+"a" #1: dropping negotiation as superseeded by established IKE SA #2
|
|
+west #
|
|
+ # non-zero counts confirm encrypted traffic flowing
|
|
+west #
|
|
+ ipsec trafficstatus
|
|
+#3: "b", type=ESP, add_time=1234567890, inBytes=0, outBytes=0, maxBytes=2^63B, id='@east'
|
|
+west #
|
|
+ # do things line up?
|
|
+west #
|
|
+ ../../guestbin/ipsec-kernel-state.sh
|
|
+src 192.1.2.45 dst 192.1.2.23
|
|
+ proto esp spi 0xSPISPI reqid REQID mode tunnel
|
|
+ replay-window 0 flag af-unspec esn
|
|
+ aead rfc4106(gcm(aes)) 0xENCAUTHKEY 128
|
|
+ anti-replay esn context:
|
|
+ seq-hi 0x0, seq 0xXX, oseq-hi 0x0, oseq 0xXX
|
|
+ replay_window 0, bitmap-length 0
|
|
+src 192.1.2.23 dst 192.1.2.45
|
|
+ proto esp spi 0xSPISPI reqid REQID mode tunnel
|
|
+ replay-window 0 flag af-unspec esn
|
|
+ aead rfc4106(gcm(aes)) 0xENCAUTHKEY 128
|
|
+ anti-replay esn context:
|
|
+ seq-hi 0x0, seq 0xXX, oseq-hi 0x0, oseq 0xXX
|
|
+ replay_window 128, bitmap-length 4
|
|
+ 00000000 00000000 00000000 XXXXXXXX
|
|
+west #
|
|
+ ../../guestbin/ipsec-kernel-policy.sh
|
|
+src 192.0.3.0/24 dst 192.0.20.0/24
|
|
+ dir out priority PRIORITY ptype main
|
|
+ tmpl src 192.1.2.45 dst 192.1.2.23
|
|
+ proto esp reqid REQID mode tunnel
|
|
+src 192.0.20.0/24 dst 192.0.3.0/24
|
|
+ dir fwd priority PRIORITY ptype main
|
|
+ tmpl src 192.1.2.23 dst 192.1.2.45
|
|
+ proto esp reqid REQID mode tunnel
|
|
+src 192.0.20.0/24 dst 192.0.3.0/24
|
|
+ dir in priority PRIORITY ptype main
|
|
+ tmpl src 192.1.2.23 dst 192.1.2.45
|
|
+ proto esp reqid REQID mode tunnel
|
|
+west #
|
|
+
|
|
--
|
|
2.48.1
|
|
|
|
|
|
From ee7a62dc7f400f4b830e64e0385a6d16fda234b3 Mon Sep 17 00:00:00 2001
|
|
From: Andrew Cagney <cagney@gnu.org>
|
|
Date: Mon, 6 Jan 2025 15:38:03 -0500
|
|
Subject: [PATCH 4/4] ikev2: in event_v2_retransmit() check .established_ike_sa
|
|
!= SOS_NOBODY
|
|
|
|
That is:
|
|
!IS_IKE_SA_ESTABLISHED(&ike->sa) && c->established_ike_sa != SOS_NOBODY
|
|
when the streams cross, the etablished IKE SA may be older.
|
|
---
|
|
programs/pluto/ikev2_retransmit.c | 32 ++++++++++++++++++++-----------
|
|
1 file changed, 21 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/programs/pluto/ikev2_retransmit.c b/programs/pluto/ikev2_retransmit.c
|
|
index df6ab99e63..7b0197445c 100644
|
|
--- a/programs/pluto/ikev2_retransmit.c
|
|
+++ b/programs/pluto/ikev2_retransmit.c
|
|
@@ -49,25 +49,35 @@ void event_v2_retransmit(struct state *ike_sa, monotime_t now UNUSED)
|
|
return;
|
|
}
|
|
|
|
- /* if this connection has a newer Child SA than this state
|
|
- * this negotiation is not relevant any more. would this
|
|
- * cover if there are multiple CREATE_CHILD_SA pending on this
|
|
- * IKE negotiation ???
|
|
- *
|
|
+ /*
|
|
* XXX: Suspect this is to handle a race where the other end
|
|
* brings up the connection first? For that case, shouldn't
|
|
* this state have been deleted?
|
|
*
|
|
- * NOTE: a larger serialno does not mean superseded. crossed
|
|
+ * NOTE: a larger serialno does not mean superseded. Crossed
|
|
* streams could mean the lower serial established later and
|
|
- * is the "newest". Should > be replaced with != ?
|
|
+ * is the "newest". Hence the equality check (and not >).
|
|
*/
|
|
|
|
struct connection *c = ike->sa.st_connection;
|
|
- if (!IS_IKE_SA_ESTABLISHED(&ike->sa) && c->established_ike_sa > ike->sa.st_serialno) {
|
|
- llog_sa(RC_LOG, ike,
|
|
- "suppressing retransmit because IKE SA was superseded #%lu; drop this negotiation",
|
|
- c->established_ike_sa);
|
|
+ if (!IS_IKE_SA_ESTABLISHED(&ike->sa) && c->established_ike_sa != SOS_NOBODY) {
|
|
+ /*
|
|
+ * The connection is established, yet this IKE SA is
|
|
+ * not. Presumably this means that the peer also
|
|
+ * initiated and established an IKE SA leaving this
|
|
+ * IKE SA in limbo.
|
|
+ *
|
|
+ * Note: since it isn't established it can't be the
|
|
+ * connection's established IKE SA.
|
|
+ *
|
|
+ * Note: this may also leave the Child SA for the
|
|
+ * connection in limbo. Hopefully revival code will
|
|
+ * pick that up.
|
|
+ */
|
|
+ PEXPECT(ike->sa.logger, c->established_ike_sa != ike->sa.st_serialno);
|
|
+ llog(RC_LOG, ike->sa.logger,
|
|
+ "suppressing retransmit because IKE SA was superseded by #%lu; drop this negotiation",
|
|
+ c->established_ike_sa);
|
|
pstat_sa_failed(&ike->sa, REASON_SUPERSEDED_BY_NEW_SA);
|
|
connection_delete_ike_family(&ike, HERE);
|
|
return;
|
|
--
|
|
2.48.1
|
|
|