From 0b1de23a189cdf133a03379ccd1e34ff4fbb77c6 Mon Sep 17 00:00:00 2001
From: Keerthana K <keerthanak@vmware.com>
Date: Thu, 7 Jul 2022 07:16:15 +0000
Subject: [PATCH 4/4] Add new configs min_spi and max_spi

---
 src/libcharon/config/child_cfg.c              | 26 ++++++++++++
 src/libcharon/config/child_cfg.h              | 18 ++++++++
 src/libcharon/kernel/kernel_interface.c       |  4 +-
 src/libcharon/kernel/kernel_interface.h       |  2 +-
 src/libcharon/kernel/kernel_ipsec.h           |  2 +-
 .../kernel_netlink/kernel_netlink_ipsec.c     | 12 +++++-
 src/libcharon/plugins/stroke/stroke_config.c  |  8 ++++
 src/libcharon/plugins/vici/vici_config.c      |  2 +
 src/libcharon/sa/child_sa.c                   | 37 +++++++++++++++-
 src/libcharon/sa/child_sa.h                   | 10 +++++
 src/libipsec/ipsec_sa_mgr.c                   |  2 +-
 src/libipsec/ipsec_sa_mgr.h                   |  2 +-
 src/starter/args.c                            |  2 +
 src/starter/confread.c                        | 42 +++++++++++++++++++
 src/starter/confread.h                        |  2 +
 src/starter/keywords.h.in                     |  3 +-
 src/starter/keywords.txt                      |  2 +
 src/starter/starterstroke.c                   |  2 +
 src/stroke/stroke_msg.h                       |  2 +
 19 files changed, 170 insertions(+), 10 deletions(-)

diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c
index 33e1439..d1f255d 100644
--- a/src/libcharon/config/child_cfg.c
+++ b/src/libcharon/config/child_cfg.c
@@ -188,6 +188,16 @@ struct private_child_cfg_t {
 	 * clear DF flag in outer IP header
 	 */
 	bool clear_df;
+	
+	/**
+	 * min SPI value to use
+	 */
+	u_int32_t min_spi;
+
+	/**
+	 * max SPI value to use
+	 */
+	u_int32_t max_spi;
 };
 
 METHOD(child_cfg_t, get_name, char*,
@@ -738,6 +748,18 @@ METHOD(child_cfg_t, is_clear_df, bool,
 	return this->clear_df;
 }
 
+METHOD(child_cfg_t, min_spi, u_int32_t,
+	private_child_cfg_t *this)
+{
+	return this->min_spi;
+}
+
+METHOD(child_cfg_t, max_spi, u_int32_t,
+	private_child_cfg_t *this)
+{
+	return this->max_spi;
+}
+
 METHOD(child_cfg_t, destroy, void,
 	private_child_cfg_t *this)
 {
@@ -793,6 +815,8 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
 			.equals = _equals,
 			.get_ref = _get_ref,
 			.is_clear_df = _is_clear_df,
+			.min_spi = _min_spi,
+			.max_spi = _max_spi,
 			.destroy = _destroy,
 			.get_hw_offload = _get_hw_offload,
 			.get_copy_dscp = _get_copy_dscp,
@@ -829,5 +853,7 @@ child_cfg_t *child_cfg_create(char *name, child_cfg_create_t *data)
 		.copy_dscp = data->copy_dscp,
 	);
 	this->clear_df = data->clear_df;
+	this->min_spi = data->min_spi;
+	this->max_spi = data->max_spi;
 	return &this->public;
 }
diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h
index 26fa897..2cdfde0 100644
--- a/src/libcharon/config/child_cfg.h
+++ b/src/libcharon/config/child_cfg.h
@@ -354,6 +354,20 @@ struct child_cfg_t {
 	 */
 	bool (*is_clear_df)(child_cfg_t *this);
 
+	/**
+	 * Get the min SPI value to use
+	 *
+	 * @return				min SPI value
+	 */
+	u_int32_t (*min_spi)(child_cfg_t *this);
+
+	/**
+	 * Get the max SPI value to use
+	 *
+	 * @return				max SPI value
+	 */
+	u_int32_t (*max_spi)(child_cfg_t *this);
+
 	/**
 	 * Destroys the child_cfg object.
 	 *
@@ -446,6 +460,10 @@ struct child_cfg_create_t {
 	dscp_copy_t copy_dscp;
 	/** DF clear bit */
 	bool clear_df;
+	/** min SPI value to use */
+	u_int32_t min_spi;
+	/** max SPI value to use */
+	u_int32_t max_spi;
 };
 
 /**
diff --git a/src/libcharon/kernel/kernel_interface.c b/src/libcharon/kernel/kernel_interface.c
index 207cb8e..818d72e 100644
--- a/src/libcharon/kernel/kernel_interface.c
+++ b/src/libcharon/kernel/kernel_interface.c
@@ -171,13 +171,13 @@ METHOD(kernel_interface_t, get_features, kernel_feature_t,
 
 METHOD(kernel_interface_t, get_spi, status_t,
 	private_kernel_interface_t *this, host_t *src, host_t *dst,
-	uint8_t protocol, uint32_t *spi)
+	uint8_t protocol, u_int32_t min, u_int32_t max, uint32_t *spi)
 {
 	if (!this->ipsec)
 	{
 		return NOT_SUPPORTED;
 	}
-	return this->ipsec->get_spi(this->ipsec, src, dst, protocol, spi);
+	return this->ipsec->get_spi(this->ipsec, src, dst, protocol, min, max, spi);
 }
 
 METHOD(kernel_interface_t, get_cpi, status_t,
diff --git a/src/libcharon/kernel/kernel_interface.h b/src/libcharon/kernel/kernel_interface.h
index 657afd8..8eb68f6 100644
--- a/src/libcharon/kernel/kernel_interface.h
+++ b/src/libcharon/kernel/kernel_interface.h
@@ -116,7 +116,7 @@ struct kernel_interface_t {
 	 * @return			SUCCESS if operation completed
 	 */
 	status_t (*get_spi)(kernel_interface_t *this, host_t *src, host_t *dst,
-						uint8_t protocol, uint32_t *spi);
+						uint8_t protocol, u_int32_t min, u_int32_t max, uint32_t *spi);
 
 	/**
 	 * Get a Compression Parameter Index (CPI) from the kernel.
diff --git a/src/libcharon/kernel/kernel_ipsec.h b/src/libcharon/kernel/kernel_ipsec.h
index 6c60850..5a2fa8b 100644
--- a/src/libcharon/kernel/kernel_ipsec.h
+++ b/src/libcharon/kernel/kernel_ipsec.h
@@ -224,7 +224,7 @@ struct kernel_ipsec_t {
 	 * @return			SUCCESS if operation completed
 	 */
 	status_t (*get_spi)(kernel_ipsec_t *this, host_t *src, host_t *dst,
-						uint8_t protocol, uint32_t *spi);
+						uint8_t protocol, u_int32_t min, u_int32_t max, uint32_t *spi);
 
 	/**
 	 * Get a Compression Parameter Index (CPI) from the kernel.
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
index 78df0da..0458993 100644
--- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
+++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
@@ -1244,17 +1244,25 @@ static status_t get_spi_internal(private_kernel_netlink_ipsec_t *this,
 
 METHOD(kernel_ipsec_t, get_spi, status_t,
 	private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
-	uint8_t protocol, uint32_t *spi)
+	uint8_t protocol, u_int32_t min, u_int32_t max, uint32_t *spi)
 {
 	uint32_t spi_min, spi_max;
+	uint32_t max_t;
+	bool is_hcx_enabled = false;
 
 	spi_min = lib->settings->get_int(lib->settings, "%s.spi_min",
 									 KERNEL_SPI_MIN, lib->ns);
 	spi_max = lib->settings->get_int(lib->settings, "%s.spi_max",
 									 KERNEL_SPI_MAX, lib->ns);
+	is_hcx_enabled = lib->settings->get_bool(lib->settings,
+				"%s.is_hcx_enabled", FALSE, lib->ns);
+	if (is_hcx_enabled)
+		max_t = max(min, max);
+	else
+		max_t = max(spi_min, spi_max);
 
 	if (get_spi_internal(this, src, dst, protocol, min(spi_min, spi_max),
-						 max(spi_min, spi_max), spi) != SUCCESS)
+						 max_t, spi) != SUCCESS)
 	{
 		DBG1(DBG_KNL, "unable to get SPI");
 		return FAILED;
diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c
index e271b3a..7edac87 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -1098,10 +1098,18 @@ static child_cfg_t *build_child_cfg(private_stroke_config_t *this,
 		.close_action = map_action(msg->add_conn.close_action),
 		.updown = msg->add_conn.me.updown,
 		.clear_df = msg->add_conn.clear_df != 0,
+		.min_spi = msg->add_conn.min_spi,
+		.max_spi = msg->add_conn.max_spi,
 	};
 
 	DBG1(DBG_CFG, "build_child_cfg: conn %s, clear_df %d",
 					msg->add_conn.name, msg->add_conn.clear_df);
+ 
+	DBG1(DBG_CFG, "build_child_cfg: conn %s, min_spi %u",
+					msg->add_conn.name, msg->add_conn.min_spi);
+
+	DBG1(DBG_CFG, "build_child_cfg: conn %s, max_spi %u",
+					msg->add_conn.name, msg->add_conn.max_spi);
 
 	child_cfg = child_cfg_create(msg->add_conn.name, &child);
 	if (msg->add_conn.replay_window != -1)
diff --git a/src/libcharon/plugins/vici/vici_config.c b/src/libcharon/plugins/vici/vici_config.c
index 87e93ed..afec9be 100644
--- a/src/libcharon/plugins/vici/vici_config.c
+++ b/src/libcharon/plugins/vici/vici_config.c
@@ -2082,6 +2082,8 @@ CALLBACK(children_sn, bool,
 	log_child_data(&child, name);
 
 	child.cfg.clear_df = false;
+	child.cfg.max_spi = 0;
+	child.cfg.min_spi = 0;
 
 	cfg = child_cfg_create(name, &child.cfg);
 
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index ab5a3d0..db119b4 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -284,6 +284,16 @@ struct private_child_sa_t {
 	 * clear DF bit in outer IP
 	 */
 	bool clear_df;
+
+	/**
+	 * min SPI value to use
+	 */
+	u_int32_t min_spi;
+
+	/**
+	 * max SPI value to use
+	 */
+	u_int32_t max_spi;
 };
 
 /**
@@ -510,6 +520,17 @@ METHOD(child_sa_t, is_clear_df, bool,
 	return this->clear_df;
 }
 
+METHOD(child_sa_t, min_spi, u_int32_t,
+	   private_child_sa_t *this)
+{
+	return this->min_spi;
+}
+
+METHOD(child_sa_t, max_spi, u_int32_t,
+	   private_child_sa_t *this)
+{
+	return this->max_spi;
+}
 
 typedef struct policy_enumerator_t policy_enumerator_t;
 
@@ -833,7 +854,7 @@ METHOD(child_sa_t, alloc_spi, uint32_t,
 	   private_child_sa_t *this, protocol_id_t protocol)
 {
 	if (charon->kernel->get_spi(charon->kernel, this->other_addr, this->my_addr,
-							proto_ike2ip(protocol), &this->my_spi) == SUCCESS)
+							proto_ike2ip(protocol), this->min_spi, this->max_spi, &this->my_spi) == SUCCESS)
 	{
 		/* if we allocate a SPI, but then are unable to establish the SA, we
 		 * need to know the protocol family to delete the partial SA */
@@ -2067,6 +2088,8 @@ child_sa_t *child_sa_create(host_t *me, host_t *other, child_cfg_t *config,
 			.create_policy_enumerator = _create_policy_enumerator,
 			.destroy = _destroy,
 			.is_clear_df = _is_clear_df,
+			.min_spi = _min_spi,
+			.max_spi = _max_spi,
 		},
 		.encap = data->encap,
 		.ipcomp = IPCOMP_NONE,
@@ -2097,6 +2120,18 @@ child_sa_t *child_sa_create(host_t *me, host_t *other, child_cfg_t *config,
 		this->clear_df = false;
 	}
 
+	if (config != NULL && config->min_spi != NULL) {
+		this->min_spi = config->min_spi(config);
+	} else {
+		this->min_spi = 0;
+	}
+
+	if (config != NULL && config->max_spi != NULL) {
+		this->max_spi = config->max_spi(config);
+	} else {
+		this->max_spi = 0;
+	}
+
 	if (data->mark_in)
 	{
 		this->mark_in.value = data->mark_in;
diff --git a/src/libcharon/sa/child_sa.h b/src/libcharon/sa/child_sa.h
index 742fa86..c1aad3b 100644
--- a/src/libcharon/sa/child_sa.h
+++ b/src/libcharon/sa/child_sa.h
@@ -527,6 +527,16 @@ struct child_sa_t {
 	 * Clear DF bit in outer IP
 	 */
 	bool (*is_clear_df) (child_sa_t *this);
+
+	/**
+	 * Min SPI to use
+	 */
+	u_int32_t (*min_spi) (child_sa_t *this);
+
+	/**
+	 * Max SPI to use
+	 */
+	u_int32_t (*max_spi) (child_sa_t *this);
 };
 
 /**
diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c
index ab6a2f0..f258f5c 100644
--- a/src/libipsec/ipsec_sa_mgr.c
+++ b/src/libipsec/ipsec_sa_mgr.c
@@ -421,7 +421,7 @@ static bool allocate_spi(private_ipsec_sa_mgr_t *this, uint32_t spi)
 
 METHOD(ipsec_sa_mgr_t, get_spi, status_t,
 	private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, uint8_t protocol,
-	uint32_t *spi)
+	u_int32_t min, u_int32_t max, uint32_t *spi)
 {
 	uint32_t spi_min, spi_max, spi_new;
 
diff --git a/src/libipsec/ipsec_sa_mgr.h b/src/libipsec/ipsec_sa_mgr.h
index 549b9f2..2092d86 100644
--- a/src/libipsec/ipsec_sa_mgr.h
+++ b/src/libipsec/ipsec_sa_mgr.h
@@ -50,7 +50,7 @@ struct ipsec_sa_mgr_t {
 	 * @return				SUCCESS of operation successful
 	 */
 	status_t (*get_spi)(ipsec_sa_mgr_t *this, host_t *src, host_t *dst,
-						uint8_t protocol, uint32_t *spi);
+						uint8_t protocol, u_int32_t min, u_int32_t max, uint32_t *spi);
 
 	/**
 	 * Add a new SA
diff --git a/src/starter/args.c b/src/starter/args.c
index cd72730..eeaebb7 100644
--- a/src/starter/args.c
+++ b/src/starter/args.c
@@ -179,6 +179,8 @@ static const token_info_t token_info[] =
 	{ ARG_MISC, 0, NULL  /* KW_MARK_OUT */                                         },
 	{ ARG_MISC, 0, NULL  /* KW_TFC */                                              },
 	{ ARG_MISC, 0, NULL  /* KW_CLEAR_DF */                                         },
+	{ ARG_MISC, 0, NULL  /* KW_MIN_SPI */                                          },
+	{ ARG_MISC, 0, NULL  /* KW_MAX_SPI */                                          },
 	{ ARG_MISC, 0, NULL  /* KW_PFS_DEPRECATED */                                   },
 	{ ARG_MISC, 0, NULL  /* KW_CONN_DEPRECATED */                                  },
 
diff --git a/src/starter/confread.c b/src/starter/confread.c
index 1aa7ccc..6719759 100644
--- a/src/starter/confread.c
+++ b/src/starter/confread.c
@@ -213,6 +213,8 @@ static void conn_defaults(starter_conn_t *conn)
 	conn->dpd_timeout           = 150; /* seconds */
 	conn->replay_window         = SA_REPLAY_WINDOW_DEFAULT;
 	conn->clear_df              = false;
+	conn->min_spi               = 0;
+	conn->max_spi               = 0;
 	conn->fragmentation         = FRAGMENTATION_YES;
 
 	conn->left.sendcert = CERT_SEND_IF_ASKED;
@@ -526,6 +528,46 @@ static void handle_keyword(kw_token_t token, starter_conn_t *conn, char *key,
 				conn->clear_df = false;
 			}
 			break;
+		case KW_MIN_SPI:
+			DBG1(DBG_APP, "handle_keyword: %s=%s", key, value);
+			{
+				char *endptr;
+
+				conn->min_spi = strtoul(value, &endptr, 0);
+				if (*endptr != '\0')
+				{
+					DBG1(DBG_APP, "# bad integer value: %s=%s", key, value);
+					cfg->err;
+				}
+				if ((conn->max_spi != 0) && (conn->min_spi >= conn->max_spi))
+				{
+					DBG1(DBG_APP, "# min spi %x >= max_spi %x", conn->min_spi,
+					     conn->max_spi);
+					cfg->err;
+				}
+			}
+			DBG1(DBG_APP, "confread min_spi: %x", conn->min_spi);
+			break;
+		case KW_MAX_SPI:
+			DBG1(DBG_APP, "handle_keyword: %s=%s", key, value);
+			{
+				char *endptr;
+
+				conn->max_spi = strtoul(value, &endptr, 0);
+				if (*endptr != '\0')
+				{
+					DBG1(DBG_APP, "# bad integer value: %s=%s", key, value);
+					cfg->err;
+				}
+				if ((conn->min_spi != 0) && (conn->max_spi <= conn->min_spi))
+				{
+					DBG1(DBG_APP, "# max spi %x <= min_spi %x", conn->max_spi,
+					     conn->min_spi);
+					cfg->err;
+				}
+			}
+			DBG1(DBG_APP, "confread max_spi: %x", conn->max_spi);
+			break;
 		default:
 			break;
 	}
diff --git a/src/starter/confread.h b/src/starter/confread.h
index fbbe85e..63ce7ad 100644
--- a/src/starter/confread.h
+++ b/src/starter/confread.h
@@ -148,6 +148,8 @@ struct starter_conn {
 		bool            install_policy;
 		bool            aggressive;
 		bool            clear_df;
+		u_int32_t       min_spi;
+		u_int32_t       max_spi;
 		starter_end_t   left, right;
 
 		unsigned long   id;
diff --git a/src/starter/keywords.h.in b/src/starter/keywords.h.in
index 071e344..f3d2b41 100644
--- a/src/starter/keywords.h.in
+++ b/src/starter/keywords.h.in
@@ -78,6 +78,8 @@ enum kw_token_t {
 	KW_MARK_OUT,
 	KW_TFC,
 	KW_CLEAR_DF,
+	KW_MIN_SPI,
+	KW_MAX_SPI,
 	KW_PFS_DEPRECATED,
 	KW_CONN_DEPRECATED,
 
@@ -188,7 +190,6 @@ enum kw_token_t {
 	/* general section keywords */
 	KW_ALSO,
 	KW_AUTO,
-
 };
 
 struct kw_entry_t {
diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt
index c0005ba..2eadae0 100644
--- a/src/starter/keywords.txt
+++ b/src/starter/keywords.txt
@@ -167,3 +167,5 @@ eap,               KW_CONN_DEPRECATED
 leftnexthop,       KW_LEFT_DEPRECATED
 rightnexthop,      KW_RIGHT_DEPRECATED
 cleardf,           KW_CLEAR_DF
+min_spi,           KW_MIN_SPI
+max_spi,           KW_MAX_SPI
diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c
index 80e0620..c8ad0dc 100644
--- a/src/starter/starterstroke.c
+++ b/src/starter/starterstroke.c
@@ -243,6 +243,8 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn)
 	msg->add_conn.mark_out.mask = conn->mark_out.mask;
 	msg->add_conn.tfc = conn->tfc;
 	msg->add_conn.clear_df = conn->clear_df ? 1 : 0;
+	msg->add_conn.min_spi = conn->min_spi ? conn->min_spi : 0xc0000000;
+	msg->add_conn.max_spi = conn->max_spi ? conn->max_spi : 0xcfffffff;
 
 	add_end(&msg, offsetof(stroke_msg_t, add_conn.me), &conn->left);
 	add_end(&msg, offsetof(stroke_msg_t, add_conn.other), &conn->right);
diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h
index f5aa63b..0d49132 100644
--- a/src/stroke/stroke_msg.h
+++ b/src/stroke/stroke_msg.h
@@ -305,6 +305,8 @@ struct stroke_msg_t {
 			uint32_t replay_window;
 			bool sha256_96;
 			int clear_df;
+			u_int32_t min_spi;
+			u_int32_t max_spi;
 		} add_conn;
 
 		/* data for STR_ADD_CA */
-- 
2.35.6