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")
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 _
/* *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)
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
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);
}
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));
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)
{
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;
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);
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)
{
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);
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);
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);
REPLY_MACRO (VL_API_IKEV2_SET_SA_LIFETIME_REPLY);
}
+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)
#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>
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;
}
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* */
u64 lifetime_maxdata;
u32 lifetime_jitter;
u32 handover;
+ u16 dst_port;
u32 tun_itf;
u8 udp_encap;
u8 is_tun_itf_set;
u32 tun_itf;
u8 udp_encap;
+ u16 dst_port;
f64 old_id_expiration;
u32 current_remote_id_mask;
/* 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;
vam->result_ready = 1;
}
+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)
{
_(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
{
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);
&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;
&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;
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);
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),
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;
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);
#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>
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);
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
*/