diff options
author | Matthew Smith <mgsmith@netgate.com> | 2017-10-12 12:06:59 -0500 |
---|---|---|
committer | Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com> | 2017-10-26 13:48:54 +0000 |
commit | ca514fda1125573d513215cb6ea7f22057a82d6b (patch) | |
tree | c40b3964b2f295e541cb7fffc3feea378c66f24d | |
parent | db41776a92e3e13178d7a565b7700a2a05336f04 (diff) |
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>
-rw-r--r-- | src/vat/api_format.c | 54 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.api | 16 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.c | 2 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.h | 3 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_api.c | 24 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_if.c | 79 |
6 files changed, 177 insertions, 1 deletions
diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 08d0c2e033e..d8f72090ef7 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -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) \ @@ -14402,6 +14404,57 @@ api_ipsec_tunnel_if_set_key (vat_main_t * vam) } 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) { unformat_input_t *i = vam->input; @@ -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>)") \ diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api index 67c333665b7..1b2e4bdd01c 100644 --- a/src/vnet/ipsec/ipsec.api +++ b/src/vnet/ipsec/ipsec.api @@ -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") diff --git a/src/vnet/ipsec/ipsec.c b/src/vnet/ipsec/ipsec.c index 2adcfd0b9bd..cd05c1bb9bf 100644 --- a/src/vnet/ipsec/ipsec.c +++ b/src/vnet/ipsec/ipsec.c @@ -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; diff --git a/src/vnet/ipsec/ipsec.h b/src/vnet/ipsec/ipsec.h index 222025dbee8..1572e5501e2 100644 --- a/src/vnet/ipsec/ipsec.h +++ b/src/vnet/ipsec/ipsec.h @@ -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); /* diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c index c3f5745b85f..e96da8168fa 100644 --- a/src/vnet/ipsec/ipsec_api.c +++ b/src/vnet/ipsec/ipsec_api.c @@ -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); @@ -566,6 +568,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) { vl_api_ikev2_profile_add_del_reply_t *rmp; diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c index 974553489ea..5a0d4898ccb 100644 --- a/src/vnet/ipsec/ipsec_if.c +++ b/src/vnet/ipsec/ipsec_if.c @@ -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) { |