Allow IPsec interface to have SAs reset
Make it easier to integrate with external IKE daemon. IPsec interfaces can have one or both SAs replaced after creation. This allows for the possibility of setting a new child SA on an interface when rekeying occurs. It also allows for the possibility of creating an interface ahead of time and updating the SA when parameters that are negotiated during IKE exchange become known. Change-Id: I0a31afdcc2bdff7098a924a51abbc58bdab2bd08 Signed-off-by: Matthew Smith <mgsmith@netgate.com>
This commit is contained in:
committed by
Sergio Gonzalez Monroy
parent
db41776a92
commit
ca514fda11
@@ -5107,6 +5107,7 @@ _(ipsec_sad_add_del_entry_reply) \
|
||||
_(ipsec_sa_set_key_reply) \
|
||||
_(ipsec_tunnel_if_add_del_reply) \
|
||||
_(ipsec_tunnel_if_set_key_reply) \
|
||||
_(ipsec_tunnel_if_set_sa_reply) \
|
||||
_(ikev2_profile_add_del_reply) \
|
||||
_(ikev2_profile_set_auth_reply) \
|
||||
_(ikev2_profile_set_id_reply) \
|
||||
@@ -5341,6 +5342,7 @@ _(IPSEC_SA_DETAILS, ipsec_sa_details) \
|
||||
_(IPSEC_SA_SET_KEY_REPLY, ipsec_sa_set_key_reply) \
|
||||
_(IPSEC_TUNNEL_IF_ADD_DEL_REPLY, ipsec_tunnel_if_add_del_reply) \
|
||||
_(IPSEC_TUNNEL_IF_SET_KEY_REPLY, ipsec_tunnel_if_set_key_reply) \
|
||||
_(IPSEC_TUNNEL_IF_SET_SA_REPLY, ipsec_tunnel_if_set_sa_reply) \
|
||||
_(IKEV2_PROFILE_ADD_DEL_REPLY, ikev2_profile_add_del_reply) \
|
||||
_(IKEV2_PROFILE_SET_AUTH_REPLY, ikev2_profile_set_auth_reply) \
|
||||
_(IKEV2_PROFILE_SET_ID_REPLY, ikev2_profile_set_id_reply) \
|
||||
@@ -14401,6 +14403,57 @@ api_ipsec_tunnel_if_set_key (vat_main_t * vam)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
api_ipsec_tunnel_if_set_sa (vat_main_t * vam)
|
||||
{
|
||||
unformat_input_t *i = vam->input;
|
||||
vl_api_ipsec_tunnel_if_set_sa_t *mp;
|
||||
u32 sw_if_index = ~0;
|
||||
u32 sa_id = ~0;
|
||||
u8 is_outbound = (u8) ~ 0;
|
||||
int ret;
|
||||
|
||||
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
|
||||
{
|
||||
if (unformat (i, "%U", api_unformat_sw_if_index, vam, &sw_if_index))
|
||||
;
|
||||
else if (unformat (i, "sa_id %d", &sa_id))
|
||||
;
|
||||
else if (unformat (i, "outbound"))
|
||||
is_outbound = 1;
|
||||
else if (unformat (i, "inbound"))
|
||||
is_outbound = 0;
|
||||
else
|
||||
{
|
||||
clib_warning ("parse error '%U'", format_unformat_error, i);
|
||||
return -99;
|
||||
}
|
||||
}
|
||||
|
||||
if (sw_if_index == ~0)
|
||||
{
|
||||
errmsg ("interface must be specified");
|
||||
return -99;
|
||||
}
|
||||
|
||||
if (sa_id == ~0)
|
||||
{
|
||||
errmsg ("SA ID must be specified");
|
||||
return -99;
|
||||
}
|
||||
|
||||
M (IPSEC_TUNNEL_IF_SET_SA, mp);
|
||||
|
||||
mp->sw_if_index = htonl (sw_if_index);
|
||||
mp->sa_id = htonl (sa_id);
|
||||
mp->is_outbound = is_outbound;
|
||||
|
||||
S (mp);
|
||||
W (ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
api_ikev2_profile_add_del (vat_main_t * vam)
|
||||
{
|
||||
@@ -21708,6 +21761,7 @@ _(ipsec_tunnel_if_add_del, "local_spi <n> remote_spi <n>\n" \
|
||||
_(ipsec_sa_dump, "[sa_id <n>]") \
|
||||
_(ipsec_tunnel_if_set_key, "<intfc> <local|remote> <crypto|integ>\n" \
|
||||
" <alg> <hex>\n") \
|
||||
_(ipsec_tunnel_if_set_sa, "<intfc> sa_id <n> <inbound|outbound>\n") \
|
||||
_(ikev2_profile_add_del, "name <profile_name> [del]") \
|
||||
_(ikev2_profile_set_auth, "name <profile_name> auth_method <method>\n" \
|
||||
"(auth_data 0x<data> | auth_data <data>)") \
|
||||
|
||||
@@ -157,6 +157,7 @@ autoreply define ipsec_sad_add_del_entry
|
||||
u8 integrity_key[128];
|
||||
|
||||
u8 use_extended_sequence_number;
|
||||
u8 use_anti_replay;
|
||||
|
||||
u8 is_tunnel;
|
||||
u8 is_tunnel_ipv6;
|
||||
@@ -634,6 +635,21 @@ autoreply define ipsec_tunnel_if_set_key {
|
||||
u8 key[128];
|
||||
};
|
||||
|
||||
/** \brief Set new SA on IPsec interface
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - index of tunnel interface
|
||||
@param sa_id - ID of SA to use
|
||||
@param is_outbound - 1 if outbound (local) SA, 0 if inbound (remote)
|
||||
*/
|
||||
autoreply define ipsec_tunnel_if_set_sa {
|
||||
u32 client_index;
|
||||
u32 context;
|
||||
u32 sw_if_index;
|
||||
u32 sa_id;
|
||||
u8 is_outbound;
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
|
||||
@@ -379,7 +379,7 @@ ipsec_add_del_policy (vlib_main_t * vm, ipsec_policy_t * policy, int is_add)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8
|
||||
u8
|
||||
ipsec_is_sa_used (u32 sa_index)
|
||||
{
|
||||
ipsec_main_t *im = &ipsec_main;
|
||||
|
||||
@@ -306,6 +306,7 @@ int ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add);
|
||||
int ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update);
|
||||
|
||||
u32 ipsec_get_sa_index_by_sa_id (u32 sa_id);
|
||||
u8 ipsec_is_sa_used (u32 sa_index);
|
||||
u8 *format_ipsec_if_output_trace (u8 * s, va_list * args);
|
||||
u8 *format_ipsec_policy_action (u8 * s, va_list * args);
|
||||
u8 *format_ipsec_crypto_alg (u8 * s, va_list * args);
|
||||
@@ -324,6 +325,8 @@ int ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
|
||||
args);
|
||||
int ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
|
||||
ipsec_if_set_key_type_t type, u8 alg, u8 * key);
|
||||
int ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
|
||||
u8 is_outbound);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -57,6 +57,7 @@ _(IPSEC_SA_DUMP, ipsec_sa_dump) \
|
||||
_(IPSEC_SPD_DUMP, ipsec_spd_dump) \
|
||||
_(IPSEC_TUNNEL_IF_ADD_DEL, ipsec_tunnel_if_add_del) \
|
||||
_(IPSEC_TUNNEL_IF_SET_KEY, ipsec_tunnel_if_set_key) \
|
||||
_(IPSEC_TUNNEL_IF_SET_SA, ipsec_tunnel_if_set_sa) \
|
||||
_(IKEV2_PROFILE_ADD_DEL, ikev2_profile_add_del) \
|
||||
_(IKEV2_PROFILE_SET_AUTH, ikev2_profile_set_auth) \
|
||||
_(IKEV2_PROFILE_SET_ID, ikev2_profile_set_id) \
|
||||
@@ -236,6 +237,7 @@ static void vl_api_ipsec_sad_add_del_entry_t_handler
|
||||
clib_memcpy (&sa.tunnel_src_addr.ip4.data, mp->tunnel_src_address, 4);
|
||||
clib_memcpy (&sa.tunnel_dst_addr.ip4.data, mp->tunnel_dst_address, 4);
|
||||
}
|
||||
sa.use_anti_replay = mp->use_anti_replay;
|
||||
|
||||
ASSERT (im->cb.check_support_cb);
|
||||
clib_error_t *err = im->cb.check_support_cb (&sa);
|
||||
@@ -565,6 +567,28 @@ out:
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vl_api_ipsec_tunnel_if_set_sa_t_handler (vl_api_ipsec_tunnel_if_set_sa_t * mp)
|
||||
{
|
||||
vl_api_ipsec_tunnel_if_set_sa_reply_t *rmp;
|
||||
ipsec_main_t *im = &ipsec_main;
|
||||
vnet_main_t *vnm = im->vnet_main;
|
||||
vnet_sw_interface_t *sw;
|
||||
int rv;
|
||||
|
||||
#if WITH_LIBSSL > 0
|
||||
sw = vnet_get_sw_interface (vnm, ntohl (mp->sw_if_index));
|
||||
|
||||
rv = ipsec_set_interface_sa (vnm, sw->hw_if_index, ntohl (mp->sa_id),
|
||||
mp->is_outbound);
|
||||
#else
|
||||
clib_warning ("unimplemented");
|
||||
#endif
|
||||
|
||||
REPLY_MACRO (VL_API_IPSEC_TUNNEL_IF_SET_SA_REPLY);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vl_api_ikev2_profile_add_del_t_handler (vl_api_ikev2_profile_add_del_t * mp)
|
||||
{
|
||||
|
||||
@@ -399,6 +399,85 @@ ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
|
||||
u8 is_outbound)
|
||||
{
|
||||
ipsec_main_t *im = &ipsec_main;
|
||||
vnet_hw_interface_t *hi;
|
||||
ipsec_tunnel_if_t *t;
|
||||
ipsec_sa_t *sa, *old_sa;
|
||||
u32 sa_index, old_sa_index;
|
||||
uword *p;
|
||||
|
||||
hi = vnet_get_hw_interface (vnm, hw_if_index);
|
||||
t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
|
||||
|
||||
sa_index = ipsec_get_sa_index_by_sa_id (sa_id);
|
||||
if (sa_index == ~0)
|
||||
{
|
||||
clib_warning ("SA with ID %u not found", sa_id);
|
||||
return VNET_API_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
if (ipsec_is_sa_used (sa_index))
|
||||
{
|
||||
clib_warning ("SA with ID %u is already in use", sa_id);
|
||||
return VNET_API_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
sa = pool_elt_at_index (im->sad, sa_index);
|
||||
if (sa->is_tunnel_ip6)
|
||||
{
|
||||
clib_warning ("IPsec interface not supported with IPv6 endpoints");
|
||||
return VNET_API_ERROR_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
if (!is_outbound)
|
||||
{
|
||||
u64 key;
|
||||
|
||||
old_sa_index = t->input_sa_index;
|
||||
old_sa = pool_elt_at_index (im->sad, old_sa_index);
|
||||
|
||||
/* unset old inbound hash entry. packets should stop arriving */
|
||||
key =
|
||||
(u64) old_sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) old_sa->spi;
|
||||
p = hash_get (im->ipsec_if_pool_index_by_key, key);
|
||||
if (p)
|
||||
hash_unset (im->ipsec_if_pool_index_by_key, key);
|
||||
|
||||
/* set new inbound SA, then set new hash entry */
|
||||
t->input_sa_index = sa_index;
|
||||
key = (u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) sa->spi;
|
||||
hash_set (im->ipsec_if_pool_index_by_key, key, hi->dev_instance);
|
||||
}
|
||||
else
|
||||
{
|
||||
old_sa_index = t->output_sa_index;
|
||||
old_sa = pool_elt_at_index (im->sad, old_sa_index);
|
||||
t->output_sa_index = sa_index;
|
||||
}
|
||||
|
||||
/* remove sa_id to sa_index mapping on old SA */
|
||||
if (ipsec_get_sa_index_by_sa_id (old_sa->id) == old_sa_index)
|
||||
hash_unset (im->sa_index_by_sa_id, old_sa->id);
|
||||
|
||||
if (im->cb.add_del_sa_sess_cb)
|
||||
{
|
||||
clib_error_t *err;
|
||||
|
||||
err = im->cb.add_del_sa_sess_cb (old_sa_index, 0);
|
||||
if (err)
|
||||
return VNET_API_ERROR_SYSCALL_ERROR_1;
|
||||
}
|
||||
|
||||
pool_put (im->sad, old_sa);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
clib_error_t *
|
||||
ipsec_tunnel_if_init (vlib_main_t * vm)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user