aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilip Tehlar <ftehlar@cisco.com>2020-03-02 15:17:37 +0000
committerDamjan Marion <dmarion@me.com>2020-03-21 11:50:03 +0000
commite5d34919b4561a5ee11e41dec6b0184537b39696 (patch)
tree9ceae975f3ce8da4a5ef7da8922b1ab4781cb231
parent7f6d145accc6e63b150ab4efc282f19cbe996b57 (diff)
ikev2: add support for custom ipsec-over-udp port
Type: feature Change-Id: Ifee2b3dca85ea915067b9285e3636802bf0c19a8 Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
-rw-r--r--src/plugins/ikev2/ikev2.api16
-rw-r--r--src/plugins/ikev2/ikev2.c103
-rw-r--r--src/plugins/ikev2/ikev2.h3
-rw-r--r--src/plugins/ikev2/ikev2_api.c24
-rw-r--r--src/plugins/ikev2/ikev2_cli.c12
-rw-r--r--src/plugins/ikev2/ikev2_priv.h5
-rw-r--r--src/plugins/ikev2/ikev2_test.c6
-rw-r--r--src/vnet/api_errno.h4
-rw-r--r--src/vnet/ipsec/ipsec_api.c8
-rw-r--r--src/vnet/ipsec/ipsec_cli.c7
-rw-r--r--src/vnet/ipsec/ipsec_sa.c15
-rw-r--r--src/vnet/ipsec/ipsec_sa.h5
12 files changed, 193 insertions, 15 deletions
diff --git a/src/plugins/ikev2/ikev2.api b/src/plugins/ikev2/ikev2.api
index c872c6f0088..274d496a032 100644
--- a/src/plugins/ikev2/ikev2.api
+++ b/src/plugins/ikev2/ikev2.api
@@ -330,6 +330,22 @@ autoreply define ikev2_profile_set_udp_encap
string name[64];
};
+/** \brief IKEv2: Set/unset custom ipsec-over-udp port
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param is_set - whether set or unset custom port
+ @port - port number
+ @param name - IKEv2 profile name
+*/
+autoreply define ikev2_profile_set_ipsec_udp_port
+{
+ u32 client_index;
+ u32 context;
+
+ u8 is_set;
+ u16 port;
+ string name[64];
+};
/*
* Local Variables:
* eval: (c-set-style "gnu")
diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c
index 2dd0819a485..ea99e375ea0 100644
--- a/src/plugins/ikev2/ikev2.c
+++ b/src/plugins/ikev2/ikev2.c
@@ -399,6 +399,7 @@ ikev2_complete_sa_data (ikev2_sa_t * sa, ikev2_sa_t * sai)
sa->last_sa_init_req_packet_data = _(sai->last_sa_init_req_packet_data);
sa->childs = _(sai->childs);
sa->udp_encap = sai->udp_encap;
+ sa->dst_port = sai->dst_port;
#undef _
@@ -1379,8 +1380,10 @@ ikev2_sa_auth (ikev2_sa_t * sa)
/* *INDENT-ON* */
if (sel_p)
- sa->udp_encap = sel_p->udp_encap;
-
+ {
+ sa->udp_encap = sel_p->udp_encap;
+ sa->dst_port = sel_p->dst_port;
+ }
vec_free (authmsg);
if (sa->state == IKEV2_STATE_AUTHENTICATED)
@@ -1502,6 +1505,7 @@ typedef struct
ipsec_key_t loc_ckey, rem_ckey, loc_ikey, rem_ikey;
u8 is_rekey;
u32 old_remote_sa_id;
+ u16 dst_port;
} ikev2_add_ipsec_tunnel_args_t;
static void
@@ -1559,13 +1563,13 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a)
IPSEC_PROTOCOL_ESP, a->encr_type,
&a->loc_ckey, a->integ_type, &a->loc_ikey,
a->flags, 0, a->salt_local, &a->local_ip,
- &a->remote_ip, NULL);
+ &a->remote_ip, NULL, a->dst_port);
rv |= ipsec_sa_add_and_lock (a->remote_sa_id, a->remote_spi,
IPSEC_PROTOCOL_ESP, a->encr_type, &a->rem_ckey,
a->integ_type, &a->rem_ikey,
(a->flags | IPSEC_SA_FLAG_IS_INBOUND), 0,
a->salt_remote, &a->remote_ip,
- &a->local_ip, NULL);
+ &a->local_ip, NULL, a->dst_port);
rv |= ipsec_tun_protect_update (sw_if_index, NULL, a->local_sa_id, sas_in);
}
@@ -1799,6 +1803,7 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm,
child->remote_sa_id = a.remote_sa_id = remote_sa_id;
a.sw_if_index = (sa->is_tun_itf_set ? sa->tun_itf : ~0);
+ a.dst_port = sa->dst_port;
vl_api_rpc_call_main_thread (ikev2_add_tunnel_from_main,
(u8 *) & a, sizeof (a));
@@ -2928,6 +2933,58 @@ ikev2_set_local_key (vlib_main_t * vm, u8 * file)
return 0;
}
+static_always_inline vnet_api_error_t
+ikev2_register_udp_port (ikev2_profile_t * p, u16 port)
+{
+ ikev2_main_t *km = &ikev2_main;
+ udp_dst_port_info_t *pi;
+
+ uword *v = hash_get (km->udp_ports, port);
+ pi = udp_get_dst_port_info (&udp_main, port, UDP_IP4);
+
+ if (v)
+ {
+ /* IKE already uses this port, only increment reference counter */
+ ASSERT (pi);
+ v[0]++;
+ }
+ else
+ {
+ if (pi)
+ return VNET_API_ERROR_UDP_PORT_TAKEN;
+
+ udp_register_dst_port (km->vlib_main, port,
+ ipsec4_tun_input_node.index, 1);
+ hash_set (km->udp_ports, port, 1);
+ }
+ p->dst_port = port;
+ return 0;
+}
+
+static_always_inline void
+ikev2_unregister_udp_port (ikev2_profile_t * p)
+{
+ ikev2_main_t *km = &ikev2_main;
+ uword *v;
+
+ if (p->dst_port == IPSEC_UDP_PORT_NONE)
+ return;
+
+ v = hash_get (km->udp_ports, p->dst_port);
+ if (!v)
+ return;
+
+ v[0]--;
+
+ if (v[0] == 0)
+ {
+ udp_unregister_dst_port (km->vlib_main, p->dst_port, 1);
+ hash_unset (km->udp_ports, p->dst_port);
+ }
+
+ p->dst_port = IPSEC_UDP_PORT_NONE;
+}
+
clib_error_t *
ikev2_add_del_profile (vlib_main_t * vm, u8 * name, int is_add)
{
@@ -2942,6 +2999,7 @@ ikev2_add_del_profile (vlib_main_t * vm, u8 * name, int is_add)
pool_get (km->profiles, p);
clib_memset (p, 0, sizeof (*p));
p->name = vec_dup (name);
+ p->dst_port = IPSEC_UDP_PORT_NONE;
p->responder.sw_if_index = ~0;
p->tun_itf = ~0;
uword index = p - km->profiles;
@@ -2953,6 +3011,8 @@ ikev2_add_del_profile (vlib_main_t * vm, u8 * name, int is_add)
if (!p)
return clib_error_return (0, "policy %v does not exists", name);
+ ikev2_unregister_udp_port (p);
+
vec_free (p->name);
pool_put (km->profiles, p);
mhash_unset (&km->profile_index_by_name, name, 0);
@@ -3161,6 +3221,39 @@ ikev2_set_profile_tunnel_interface (vlib_main_t * vm,
return 0;
}
+vnet_api_error_t
+ikev2_set_profile_ipsec_udp_port (vlib_main_t * vm, u8 * name, u16 port,
+ u8 is_set)
+{
+ ikev2_profile_t *p = ikev2_profile_index_by_name (name);
+ ikev2_main_t *km = &ikev2_main;
+ vnet_api_error_t rv = 0;
+ uword *v;
+
+ if (!p)
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ if (is_set)
+ {
+ if (p->dst_port != IPSEC_UDP_PORT_NONE)
+ return VNET_API_ERROR_VALUE_EXIST;
+
+ rv = ikev2_register_udp_port (p, port);
+ }
+ else
+ {
+ v = hash_get (km->udp_ports, port);
+ if (!v)
+ return VNET_API_ERROR_IKE_NO_PORT;
+
+ if (p->dst_port == IPSEC_UDP_PORT_NONE)
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ ikev2_unregister_udp_port (p);
+ }
+ return rv;
+}
+
clib_error_t *
ikev2_set_profile_udp_encap (vlib_main_t * vm, u8 * name)
{
@@ -3262,6 +3355,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name)
sa.state = IKEV2_STATE_SA_INIT;
sa.tun_itf = p->tun_itf;
sa.udp_encap = p->udp_encap;
+ sa.dst_port = p->dst_port;
sa.is_tun_itf_set = 1;
sa.initial_contact = 1;
ikev2_generate_sa_init_data (&sa);
@@ -3606,6 +3700,7 @@ ikev2_init (vlib_main_t * vm)
km->sa_by_ispi = hash_create (0, sizeof (uword));
km->sw_if_indices = hash_create (0, 0);
+ km->udp_ports = hash_create (0, sizeof (uword));
udp_register_dst_port (vm, 500, ikev2_node.index, 1);
diff --git a/src/plugins/ikev2/ikev2.h b/src/plugins/ikev2/ikev2.h
index c73df152909..d79a031c490 100644
--- a/src/plugins/ikev2/ikev2.h
+++ b/src/plugins/ikev2/ikev2.h
@@ -394,6 +394,9 @@ clib_error_t *ikev2_set_profile_sa_lifetime (vlib_main_t * vm, u8 * name,
u32 handover, u64 maxdata);
clib_error_t *ikev2_set_profile_tunnel_interface (vlib_main_t * vm, u8 * name,
u32 sw_if_index);
+vnet_api_error_t ikev2_set_profile_ipsec_udp_port (vlib_main_t * vm,
+ u8 * name, u16 port,
+ u8 is_set);
clib_error_t *ikev2_set_profile_udp_encap (vlib_main_t * vm, u8 * name);
clib_error_t *ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name);
clib_error_t *ikev2_initiate_delete_child_sa (vlib_main_t * vm, u32 ispi);
diff --git a/src/plugins/ikev2/ikev2_api.c b/src/plugins/ikev2/ikev2_api.c
index f846bfab9f0..0064f57483f 100644
--- a/src/plugins/ikev2/ikev2_api.c
+++ b/src/plugins/ikev2/ikev2_api.c
@@ -312,6 +312,30 @@ vl_api_ikev2_set_sa_lifetime_t_handler (vl_api_ikev2_set_sa_lifetime_t * mp)
}
static void
+ vl_api_ikev2_profile_set_ipsec_udp_port_t_handler
+ (vl_api_ikev2_profile_set_ipsec_udp_port_t * mp)
+{
+ vl_api_ikev2_profile_set_ipsec_udp_port_reply_t *rmp;
+ int rv = 0;
+
+#if WITH_LIBSSL > 0
+ vlib_main_t *vm = vlib_get_main ();
+
+ u8 *tmp = format (0, "%s", mp->name);
+
+ rv =
+ ikev2_set_profile_ipsec_udp_port (vm, tmp,
+ clib_net_to_host_u16 (mp->port),
+ mp->is_set);
+ vec_free (tmp);
+#else
+ rv = VNET_API_ERROR_UNIMPLEMENTED;
+#endif
+
+ REPLY_MACRO (VL_API_IKEV2_PROFILE_SET_IPSEC_UDP_PORT_REPLY);
+}
+
+static void
vl_api_ikev2_set_tunnel_interface_t_handler
(vl_api_ikev2_set_tunnel_interface_t * mp)
{
diff --git a/src/plugins/ikev2/ikev2_cli.c b/src/plugins/ikev2/ikev2_cli.c
index 1acae91c777..03f9efd696f 100644
--- a/src/plugins/ikev2/ikev2_cli.c
+++ b/src/plugins/ikev2/ikev2_cli.c
@@ -17,6 +17,7 @@
#include <vnet/pg/pg.h>
#include <vppinfra/error.h>
#include <vnet/udp/udp.h>
+#include <vnet/ipsec/ipsec_sa.h>
#include <plugins/ikev2/ikev2.h>
#include <plugins/ikev2/ikev2_priv.h>
@@ -391,6 +392,14 @@ ikev2_profile_add_del_command_fn (vlib_main_t * vm,
r = ikev2_set_profile_udp_encap (vm, name);
goto done;
}
+ else if (unformat (line_input, "set %U ipsec-over-udp port %u",
+ unformat_token, valid_chars, &name, &tmp1))
+ {
+ int rv = ikev2_set_profile_ipsec_udp_port (vm, name, tmp1, 1);
+ if (rv)
+ r = clib_error_return (0, "Error: %U", format_vnet_api_errno, rv);
+ goto done;
+ }
else
break;
}
@@ -502,6 +511,9 @@ show_ikev2_profile_command_fn (vlib_main_t * vm,
format_vnet_sw_if_index_name, vnet_get_main(), p->tun_itf);
if (p->udp_encap)
vlib_cli_output(vm, " udp-encap");
+
+ if (p->dst_port != IPSEC_UDP_PORT_NONE)
+ vlib_cli_output(vm, " ipsec-over-udp port %d", p->dst_port);
}));
/* *INDENT-ON* */
diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h
index 1cae47b4290..d2f5f056917 100644
--- a/src/plugins/ikev2/ikev2_priv.h
+++ b/src/plugins/ikev2/ikev2_priv.h
@@ -358,6 +358,7 @@ typedef struct
u64 lifetime_maxdata;
u32 lifetime_jitter;
u32 handover;
+ u16 dst_port;
u32 tun_itf;
u8 udp_encap;
@@ -424,6 +425,7 @@ typedef struct
u8 is_tun_itf_set;
u32 tun_itf;
u8 udp_encap;
+ u16 dst_port;
f64 old_id_expiration;
u32 current_remote_id_mask;
@@ -481,6 +483,9 @@ typedef struct
/* logging level */
ikev2_log_level_t log_level;
+
+ /* custom ipsec-over-udp ports managed by ike */
+ uword *udp_ports;
} ikev2_main_t;
extern ikev2_main_t ikev2_main;
diff --git a/src/plugins/ikev2/ikev2_test.c b/src/plugins/ikev2/ikev2_test.c
index 9ff4bbcc58c..8be42fef427 100644
--- a/src/plugins/ikev2/ikev2_test.c
+++ b/src/plugins/ikev2/ikev2_test.c
@@ -100,6 +100,12 @@ static void vl_api_ikev2_plugin_get_version_reply_t_handler
}
static int
+api_ikev2_profile_set_ipsec_udp_port (vat_main_t * vam)
+{
+ return 0;
+}
+
+static int
api_ikev2_profile_add_del (vat_main_t * vam)
{
unformat_input_t *i = vam->input;
diff --git a/src/vnet/api_errno.h b/src/vnet/api_errno.h
index eb25f05a853..15b17a86d5d 100644
--- a/src/vnet/api_errno.h
+++ b/src/vnet/api_errno.h
@@ -153,7 +153,9 @@ _(FIB_PATH_UNSUPPORTED_NH_PROTO, -157, "Unsupported FIB Path protocol") \
_(API_ENDIAN_FAILED, -159, "Endian mismatch detected") \
_(NO_CHANGE, -160, "No change in table") \
_(MISSING_CERT_KEY, -161, "Missing certifcate or key") \
-_(LIMIT_EXCEEDED, -162, "limit exceeded")
+_(LIMIT_EXCEEDED, -162, "limit exceeded") \
+_(IKE_NO_PORT, -163, "port not managed by IKE") \
+_(UDP_PORT_TAKEN, -164, "UDP port already taken") \
typedef enum
{
diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c
index c7ce3ef83d5..177300aeb9a 100644
--- a/src/vnet/ipsec/ipsec_api.c
+++ b/src/vnet/ipsec/ipsec_api.c
@@ -372,7 +372,7 @@ static void vl_api_ipsec_sad_entry_add_del_t_handler
crypto_alg, &crypto_key,
integ_alg, &integ_key, flags,
0, mp->entry.salt, &tun_src, &tun_dst,
- &sa_index);
+ &sa_index, IPSEC_UDP_PORT_NONE);
else
rv = ipsec_sa_unlock_id (id);
@@ -662,7 +662,8 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
&integ_key,
(flags | IPSEC_SA_FLAG_IS_INBOUND),
ntohl (mp->tx_table_id),
- mp->salt, &remote_ip, &local_ip, NULL);
+ mp->salt, &remote_ip, &local_ip, NULL,
+ IPSEC_UDP_PORT_NONE);
if (rv)
goto done;
@@ -676,7 +677,8 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
&integ_key,
flags,
ntohl (mp->tx_table_id),
- mp->salt, &local_ip, &remote_ip, NULL);
+ mp->salt, &local_ip, &remote_ip, NULL,
+ IPSEC_UDP_PORT_NONE);
if (rv)
goto done;
diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c
index 04061901ccc..7779e79f067 100644
--- a/src/vnet/ipsec/ipsec_cli.c
+++ b/src/vnet/ipsec/ipsec_cli.c
@@ -149,7 +149,8 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm,
rv = ipsec_sa_add_and_lock (id, spi, proto, crypto_alg,
&ck, integ_alg, &ik, flags,
0, clib_host_to_net_u32 (salt),
- &tun_src, &tun_dst, NULL);
+ &tun_src, &tun_dst, NULL,
+ IPSEC_UDP_PORT_NONE);
else
rv = ipsec_sa_unlock_id (id);
@@ -852,14 +853,14 @@ create_ipsec_tunnel_command_fn (vlib_main_t * vm,
local_spi, IPSEC_PROTOCOL_ESP, crypto_alg,
&lck, integ_alg, &lik, flags, table_id,
clib_host_to_net_u32 (salt), &local_ip,
- &remote_ip, NULL);
+ &remote_ip, NULL, IPSEC_UDP_PORT_NONE);
rv |=
ipsec_sa_add_and_lock (ipsec_tun_mk_remote_sa_id (sw_if_index),
remote_spi, IPSEC_PROTOCOL_ESP, crypto_alg,
&rck, integ_alg, &rik,
(flags | IPSEC_SA_FLAG_IS_INBOUND), table_id,
clib_host_to_net_u32 (salt), &remote_ip,
- &local_ip, NULL);
+ &local_ip, NULL, IPSEC_UDP_PORT_NONE);
rv |=
ipsec_tun_protect_update_one (sw_if_index, &nh,
ipsec_tun_mk_local_sa_id (sw_if_index),
diff --git a/src/vnet/ipsec/ipsec_sa.c b/src/vnet/ipsec/ipsec_sa.c
index 4401c2e3d74..0e1e63d0db4 100644
--- a/src/vnet/ipsec/ipsec_sa.c
+++ b/src/vnet/ipsec/ipsec_sa.c
@@ -135,7 +135,8 @@ ipsec_sa_add_and_lock (u32 id,
u32 tx_table_id,
u32 salt,
const ip46_address_t * tun_src,
- const ip46_address_t * tun_dst, u32 * sa_out_index)
+ const ip46_address_t * tun_dst, u32 * sa_out_index,
+ u16 dst_port)
{
vlib_main_t *vm = vlib_get_main ();
ipsec_main_t *im = &ipsec_main;
@@ -269,8 +270,16 @@ ipsec_sa_add_and_lock (u32 id,
if (ipsec_sa_is_set_UDP_ENCAP (sa))
{
- sa->udp_hdr.src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
- sa->udp_hdr.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
+ if (dst_port == IPSEC_UDP_PORT_NONE)
+ {
+ sa->udp_hdr.src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
+ sa->udp_hdr.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
+ }
+ else
+ {
+ sa->udp_hdr.src_port = clib_host_to_net_u16 (dst_port);
+ sa->udp_hdr.dst_port = clib_host_to_net_u16 (dst_port);
+ }
}
hash_set (im->sa_index_by_sa_id, sa->id, sa_index);
diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h
index e0d74e1309e..0997eb7d8bc 100644
--- a/src/vnet/ipsec/ipsec_sa.h
+++ b/src/vnet/ipsec/ipsec_sa.h
@@ -16,6 +16,7 @@
#define __IPSEC_SPD_SA_H__
#include <vlib/vlib.h>
+#include <vnet/crypto/crypto.h>
#include <vnet/ip/ip.h>
#include <vnet/fib/fib_node.h>
@@ -209,7 +210,7 @@ extern int ipsec_sa_add_and_lock (u32 id,
u32 salt,
const ip46_address_t * tunnel_src_addr,
const ip46_address_t * tunnel_dst_addr,
- u32 * sa_index);
+ u32 * sa_index, u16 dst_port);
extern index_t ipsec_sa_find_and_lock (u32 id);
extern int ipsec_sa_unlock_id (u32 id);
extern void ipsec_sa_unlock (index_t sai);
@@ -233,6 +234,8 @@ extern uword unformat_ipsec_integ_alg (unformat_input_t * input,
va_list * args);
extern uword unformat_ipsec_key (unformat_input_t * input, va_list * args);
+#define IPSEC_UDP_PORT_NONE ((u16)~0)
+
/*
* Anti Replay definitions
*/