From 28029530963223c5c3b94f7a2f9d1343662a1a04 Mon Sep 17 00:00:00 2001 From: Matthew Smith Date: Tue, 26 Sep 2017 13:33:44 -0500 Subject: [PATCH] Add API support to dump IPsec SAs Add an API request message type to dump IPsec SAs. Either all IPsec SAs can be dumped or it can be limited to a single SA ID (numeric ID set at creation time - not an index). Add a handler for incoming messages with the new request type. Add an API response message type containing the data for an IPsec SA. Add VAT support for new message type. Change-Id: Id7828d000efc637dee7f988a87d3f707a8b466b7 Signed-off-by: Matthew Smith --- src/vat/api_format.c | 117 +++++++++++++++++++++++++++++++++++++++++++++ src/vnet/ipsec/ipsec.api | 69 ++++++++++++++++++++++++++ src/vnet/ipsec/ipsec_api.c | 106 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 292 insertions(+) diff --git a/src/vat/api_format.c b/src/vat/api_format.c index 1010a0570b7..08f90dc498e 100644 --- a/src/vat/api_format.c +++ b/src/vat/api_format.c @@ -5232,6 +5232,7 @@ _(IPSEC_SPD_ADD_DEL_REPLY, ipsec_spd_add_del_reply) \ _(IPSEC_INTERFACE_ADD_DEL_SPD_REPLY, ipsec_interface_add_del_spd_reply) \ _(IPSEC_SPD_ADD_DEL_ENTRY_REPLY, ipsec_spd_add_del_entry_reply) \ _(IPSEC_SAD_ADD_DEL_ENTRY_REPLY, ipsec_sad_add_del_entry_reply) \ +_(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) \ _(IKEV2_PROFILE_ADD_DEL_REPLY, ikev2_profile_add_del_reply) \ @@ -13774,6 +13775,121 @@ api_ipsec_tunnel_if_add_del (vat_main_t * vam) return ret; } +static void +vl_api_ipsec_sa_details_t_handler (vl_api_ipsec_sa_details_t * mp) +{ + vat_main_t *vam = &vat_main; + + print (vam->ofp, "sa_id %u sw_if_index %u spi %u proto %u crypto_alg %u " + "crypto_key %U integ_alg %u integ_key %U use_esn %u " + "use_anti_replay %u is_tunnel %u is_tunnel_ip6 %u " + "tunnel_src_addr %U tunnel_dst_addr %U " + "salt %u seq_outbound %lu last_seq_inbound %lu " + "replay_window %lu total_data_size %lu\n", + ntohl (mp->sa_id), ntohl (mp->sw_if_index), ntohl (mp->spi), + mp->protocol, + mp->crypto_alg, format_hex_bytes, mp->crypto_key, mp->crypto_key_len, + mp->integ_alg, format_hex_bytes, mp->integ_key, mp->integ_key_len, + mp->use_esn, mp->use_anti_replay, mp->is_tunnel, mp->is_tunnel_ip6, + (mp->is_tunnel_ip6) ? format_ip6_address : format_ip4_address, + mp->tunnel_src_addr, + (mp->is_tunnel_ip6) ? format_ip6_address : format_ip4_address, + mp->tunnel_dst_addr, + ntohl (mp->salt), + clib_net_to_host_u64 (mp->seq_outbound), + clib_net_to_host_u64 (mp->last_seq_inbound), + clib_net_to_host_u64 (mp->replay_window), + clib_net_to_host_u64 (mp->total_data_size)); +} + +#define vl_api_ipsec_sa_details_t_endian vl_noop_handler +#define vl_api_ipsec_sa_details_t_print vl_noop_handler + +static void vl_api_ipsec_sa_details_t_handler_json + (vl_api_ipsec_sa_details_t * mp) +{ + vat_main_t *vam = &vat_main; + vat_json_node_t *node = NULL; + struct in_addr src_ip4, dst_ip4; + struct in6_addr src_ip6, dst_ip6; + + if (VAT_JSON_ARRAY != vam->json_tree.type) + { + ASSERT (VAT_JSON_NONE == vam->json_tree.type); + vat_json_init_array (&vam->json_tree); + } + node = vat_json_array_add (&vam->json_tree); + + vat_json_init_object (node); + vat_json_object_add_uint (node, "sa_id", ntohl (mp->sa_id)); + vat_json_object_add_uint (node, "sw_if_index", ntohl (mp->sw_if_index)); + vat_json_object_add_uint (node, "spi", ntohl (mp->spi)); + vat_json_object_add_uint (node, "proto", mp->protocol); + vat_json_object_add_uint (node, "crypto_alg", mp->crypto_alg); + vat_json_object_add_uint (node, "integ_alg", mp->integ_alg); + vat_json_object_add_uint (node, "use_esn", mp->use_esn); + vat_json_object_add_uint (node, "use_anti_replay", mp->use_anti_replay); + vat_json_object_add_uint (node, "is_tunnel", mp->is_tunnel); + vat_json_object_add_uint (node, "is_tunnel_ip6", mp->is_tunnel_ip6); + vat_json_object_add_bytes (node, "crypto_key", mp->crypto_key, + mp->crypto_key_len); + vat_json_object_add_bytes (node, "integ_key", mp->integ_key, + mp->integ_key_len); + if (mp->is_tunnel_ip6) + { + clib_memcpy (&src_ip6, mp->tunnel_src_addr, sizeof (src_ip6)); + vat_json_object_add_ip6 (node, "tunnel_src_addr", src_ip6); + clib_memcpy (&dst_ip6, mp->tunnel_dst_addr, sizeof (dst_ip6)); + vat_json_object_add_ip6 (node, "tunnel_dst_addr", dst_ip6); + } + else + { + clib_memcpy (&src_ip4, mp->tunnel_src_addr, sizeof (src_ip4)); + vat_json_object_add_ip4 (node, "tunnel_src_addr", src_ip4); + clib_memcpy (&dst_ip4, mp->tunnel_dst_addr, sizeof (dst_ip4)); + vat_json_object_add_ip4 (node, "tunnel_dst_addr", dst_ip4); + } + vat_json_object_add_uint (node, "replay_window", + clib_net_to_host_u64 (mp->replay_window)); + vat_json_object_add_uint (node, "total_data_size", + clib_net_to_host_u64 (mp->total_data_size)); + +} + +static int +api_ipsec_sa_dump (vat_main_t * vam) +{ + unformat_input_t *i = vam->input; + vl_api_ipsec_sa_dump_t *mp; + vl_api_control_ping_t *mp_ping; + u32 sa_id = ~0; + int ret; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sa_id %d", &sa_id)) + ; + else + { + clib_warning ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + M (IPSEC_SA_DUMP, mp); + + mp->sa_id = ntohl (sa_id); + + S (mp); + + /* Use a control ping for synchronization */ + M (CONTROL_PING, mp_ping); + S (mp_ping); + + W (ret); + return ret; +} + static int api_ikev2_profile_add_del (vat_main_t * vam) { @@ -20838,6 +20954,7 @@ _(ipsec_tunnel_if_add_del, "local_spi remote_spi \n" \ " crypto_alg local_crypto_key remote_crypto_key \n" \ " integ_alg local_integ_key remote_integ_key \n" \ " local_ip remote_ip [esn] [anti_replay] [del]\n") \ +_(ipsec_sa_dump, "[sa_id ]") \ _(ikev2_profile_add_del, "name [del]") \ _(ikev2_profile_set_auth, "name auth_method \n" \ "(auth_data 0x | auth_data )") \ diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api index 011b0d4b1ff..4e283b6069e 100644 --- a/src/vnet/ipsec/ipsec.api +++ b/src/vnet/ipsec/ipsec.api @@ -544,6 +544,75 @@ define ipsec_tunnel_if_add_del_reply { u32 sw_if_index; }; +/** \brief Dump IPsec security association + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sa_id - optional ID of an SA to dump, if ~0 dump all SAs in SAD +*/ +define ipsec_sa_dump { + u32 client_index; + u32 context; + u32 sa_id; +}; + +/** \brief IPsec security association database response + @param context - sender context which was passed in the request + @param sa_id - SA ID, policy-based SAs >=0, tunnel interface SAs = 0 + @param sw_if_index - sw_if_index of tunnel interface, policy-based SAs = ~0 + @param spi - security parameter index + @param protocol - IPsec protocol (value from ipsec_protocol_t) + @param crypto_alg - crypto algorithm (value from ipsec_crypto_alg_t) + @param crypto_key_len - length of crypto_key in bytes + @param crypto_key - crypto keying material + @param integ_alg - integrity algorithm (value from ipsec_integ_alg_t) + @param integ_key_len - length of integ_key in bytes + @param integ_key - integrity keying material + @param use_esn - using extended sequence numbers when non-zero + @param use_anti_replay - using anti-replay window when non-zero + @param is_tunnel - IPsec tunnel mode when non-zero, else transport mode + @param is_tunnel_ipv6 - If using tunnel mode, endpoints are IPv6 + @param tunnel_src_addr - Tunnel source address if using tunnel mode + @param tunnel_dst_addr - Tunnel destination address is using tunnel mode + @param salt - 4 byte salt + @param seq - current sequence number for outbound + @param seq_hi - high 32 bits of ESN for outbound + @param last_seq - highest sequence number received inbound + @param last_seq_hi - high 32 bits of highest ESN received inbound + @param replay_window - bit map of seq nums received relative to last_seq if using anti-replay + @param total_data_size - total bytes sent or received +*/ +define ipsec_sa_details { + u32 context; + u32 sa_id; + u32 sw_if_index; + + u32 spi; + u8 protocol; + + u8 crypto_alg; + u8 crypto_key_len; + u8 crypto_key[128]; + + u8 integ_alg; + u8 integ_key_len; + u8 integ_key[128]; + + u8 use_esn; + u8 use_anti_replay; + + u8 is_tunnel; + u8 is_tunnel_ip6; + u8 tunnel_src_addr[16]; + u8 tunnel_dst_addr[16]; + + u32 salt; + u64 seq_outbound; + u64 last_seq_inbound; + u64 replay_window; + + u64 total_data_size; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c index 3a5b89feb7d..ae62ade35fb 100644 --- a/src/vnet/ipsec/ipsec_api.c +++ b/src/vnet/ipsec/ipsec_api.c @@ -53,6 +53,7 @@ _(IPSEC_INTERFACE_ADD_DEL_SPD, ipsec_interface_add_del_spd) \ _(IPSEC_SPD_ADD_DEL_ENTRY, ipsec_spd_add_del_entry) \ _(IPSEC_SAD_ADD_DEL_ENTRY, ipsec_sad_add_del_entry) \ _(IPSEC_SA_SET_KEY, ipsec_sa_set_key) \ +_(IPSEC_SA_DUMP, ipsec_sa_dump) \ _(IPSEC_SPD_DUMP, ipsec_spd_dump) \ _(IPSEC_TUNNEL_IF_ADD_DEL, ipsec_tunnel_if_add_del) \ _(IKEV2_PROFILE_ADD_DEL, ikev2_profile_add_del) \ @@ -402,6 +403,111 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t * })); } +static void +send_ipsec_sa_details (ipsec_sa_t * sa, unix_shared_memory_queue_t * q, + u32 context, u32 sw_if_index) +{ + vl_api_ipsec_sa_details_t *mp; + + mp = vl_msg_api_alloc (sizeof (*mp)); + memset (mp, 0, sizeof (*mp)); + mp->_vl_msg_id = ntohs (VL_API_IPSEC_SA_DETAILS); + mp->context = context; + + mp->sa_id = htonl (sa->id); + mp->sw_if_index = htonl (sw_if_index); + + mp->spi = htonl (sa->spi); + mp->protocol = sa->protocol; + + mp->crypto_alg = sa->crypto_alg; + mp->crypto_key_len = sa->crypto_key_len; + memcpy (mp->crypto_key, sa->crypto_key, sa->crypto_key_len); + + mp->integ_alg = sa->integ_alg; + mp->integ_key_len = sa->integ_key_len; + memcpy (mp->integ_key, sa->integ_key, sa->integ_key_len); + + mp->use_esn = sa->use_esn; + mp->use_anti_replay = sa->use_anti_replay; + + mp->is_tunnel = sa->is_tunnel; + mp->is_tunnel_ip6 = sa->is_tunnel_ip6; + + if (sa->is_tunnel) + { + if (sa->is_tunnel_ip6) + { + memcpy (mp->tunnel_src_addr, &sa->tunnel_src_addr.ip6, 16); + memcpy (mp->tunnel_dst_addr, &sa->tunnel_dst_addr.ip6, 16); + } + else + { + memcpy (mp->tunnel_src_addr, &sa->tunnel_src_addr.ip4, 4); + memcpy (mp->tunnel_dst_addr, &sa->tunnel_dst_addr.ip4, 4); + } + } + + mp->salt = clib_host_to_net_u32 (sa->salt); + mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq)); + mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq)); + if (sa->use_esn) + { + mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi)); + mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->last_seq_hi)); + } + if (sa->use_anti_replay) + mp->replay_window = clib_host_to_net_u64 (sa->replay_window); + mp->total_data_size = clib_host_to_net_u64 (sa->total_data_size); + + vl_msg_api_send_shmem (q, (u8 *) & mp); +} + + +static void +vl_api_ipsec_sa_dump_t_handler (vl_api_ipsec_sa_dump_t * mp) +{ + unix_shared_memory_queue_t *q; + ipsec_main_t *im = &ipsec_main; + vnet_main_t *vnm = im->vnet_main; + ipsec_sa_t *sa; + ipsec_tunnel_if_t *t; + u32 *sa_index_to_tun_if_index = 0; + +#if WITH_LIBSSL > 0 + q = vl_api_client_index_to_input_queue (mp->client_index); + if (q == 0 || pool_elts (im->sad) == 0) + return; + + vec_validate_init_empty (sa_index_to_tun_if_index, vec_len (im->sad) - 1, + ~0); + + /* *INDENT-OFF* */ + pool_foreach (t, im->tunnel_interfaces, + ({ + vnet_hw_interface_t *hi; + u32 sw_if_index = ~0; + + hi = vnet_get_hw_interface (vnm, t->hw_if_index); + sw_if_index = hi->sw_if_index; + sa_index_to_tun_if_index[t->input_sa_index] = sw_if_index; + sa_index_to_tun_if_index[t->output_sa_index] = sw_if_index; + })); + + pool_foreach (sa, im->sad, + ({ + if (mp->sa_id == ~(0) || ntohl (mp->sa_id) == sa->id) + send_ipsec_sa_details (sa, q, mp->context, + sa_index_to_tun_if_index[sa - im->sad]); + })); + /* *INDENT-ON* */ + + vec_free (sa_index_to_tun_if_index); +#else + clib_warning ("unimplemented"); +#endif +} + static void vl_api_ikev2_profile_add_del_t_handler (vl_api_ikev2_profile_add_del_t * mp) -- 2.16.6