diff options
Diffstat (limited to 'src/plugins/ikev2')
-rw-r--r-- | src/plugins/ikev2/CMakeLists.txt | 9 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2.api | 74 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2.c | 872 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2.h | 11 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2_api.c | 421 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2_cli.c | 51 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2_crypto.c | 6 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2_payload.c | 42 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2_priv.h | 64 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2_test.c | 229 | ||||
-rw-r--r-- | src/plugins/ikev2/ikev2_types.api | 76 |
11 files changed, 1400 insertions, 455 deletions
diff --git a/src/plugins/ikev2/CMakeLists.txt b/src/plugins/ikev2/CMakeLists.txt index 6f2e5a68153..568271ed7d9 100644 --- a/src/plugins/ikev2/CMakeLists.txt +++ b/src/plugins/ikev2/CMakeLists.txt @@ -11,8 +11,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_definitions (-DWITH_LIBSSL=1) +if(NOT OPENSSL_FOUND) + message(WARNING "openssl headers not found - ikev2 plugin disabled") + return() +endif() + include_directories(${OPENSSL_INCLUDE_DIR}) +add_compile_definitions(OPENSSL_SUPPRESS_DEPRECATED) add_vpp_plugin(ikev2 SOURCES @@ -35,5 +40,5 @@ add_vpp_plugin(ikev2 ikev2_priv.h LINK_LIBRARIES - ${OPENSSL_LIBRARIES} + ${OPENSSL_CRYPTO_LIBRARIES} ) diff --git a/src/plugins/ikev2/ikev2.api b/src/plugins/ikev2/ikev2.api index ff9ed72e888..de276e7f3ea 100644 --- a/src/plugins/ikev2/ikev2.api +++ b/src/plugins/ikev2/ikev2.api @@ -72,7 +72,26 @@ define ikev2_sa_dump { u32 client_index; u32 context; +}; +/** \brief Dump all SAs + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define ikev2_sa_v2_dump +{ + u32 client_index; + u32 context; +}; + +/** \brief Dump all SAs + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define ikev2_sa_v3_dump +{ + u32 client_index; + u32 context; option status = "in_progress"; }; @@ -87,6 +106,32 @@ define ikev2_sa_details i32 retval; vl_api_ikev2_sa_t sa; +}; + +/** \brief Details about IKE SA + @param context - sender context, to match reply w/ request + @param retval - return code + @param sa - SA data +*/ +define ikev2_sa_v2_details +{ + u32 context; + i32 retval; + + vl_api_ikev2_sa_v2_t sa; +}; + +/** \brief Details about IKE SA + @param context - sender context, to match reply w/ request + @param retval - return code + @param sa - SA data +*/ +define ikev2_sa_v3_details +{ + u32 context; + i32 retval; + + vl_api_ikev2_sa_v3_t sa; option status = "in_progress"; }; @@ -102,7 +147,6 @@ define ikev2_child_sa_dump u32 sa_index; option vat_help = "sa_index <index>"; - option status = "in_progress"; }; /** \brief Child SA details @@ -116,6 +160,34 @@ define ikev2_child_sa_details i32 retval; vl_api_ikev2_child_sa_t child_sa; +}; + +/** \brief Dump child SA of specific SA + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param sa_index - index of specific sa +*/ +define ikev2_child_sa_v2_dump +{ + u32 client_index; + u32 context; + + u32 sa_index; + option vat_help = "sa_index <index>"; + option status = "in_progress"; +}; + +/** \brief Child SA details + @param context - sender context, to match reply w/ request + @param retval - return code + @param child_sa - child SA data +*/ +define ikev2_child_sa_v2_details +{ + u32 context; + i32 retval; + + vl_api_ikev2_child_sa_v2_t child_sa; option status = "in_progress"; }; diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index fa653760b1d..9bea2c96d12 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -110,14 +110,14 @@ typedef enum typedef u32 ikev2_non_esp_marker; -static_always_inline u16 -ikev2_get_port (ikev2_sa_t * sa) +static u16 +ikev2_get_port (ikev2_sa_t *sa) { return ikev2_natt_active (sa) ? IKEV2_PORT_NATT : IKEV2_PORT; } -static_always_inline int -ikev2_insert_non_esp_marker (ike_header_t * ike, int len) +static int +ikev2_insert_non_esp_marker (ike_header_t *ike, int len) { memmove ((u8 *) ike + sizeof (ikev2_non_esp_marker), ike, len); clib_memset (ike, 0, sizeof (ikev2_non_esp_marker)); @@ -211,6 +211,8 @@ ikev2_select_proposal (ikev2_sa_proposal_t * proposals, rv->proposal_num = proposal->proposal_num; rv->protocol_id = proposal->protocol_id; RAND_bytes ((u8 *) & rv->spi, sizeof (rv->spi)); + if (rv->protocol_id != IKEV2_PROTOCOL_IKE) + rv->spi &= 0xffffffff; goto done; } else @@ -405,8 +407,8 @@ ikev2_generate_sa_init_data (ikev2_sa_t * sa) RAND_bytes ((u8 *) & sa->rspi, 8); /* generate nonce */ - sa->r_nonce = vec_new (u8, IKEV2_NONCE_SIZE); - RAND_bytes ((u8 *) sa->r_nonce, IKEV2_NONCE_SIZE); + sa->r_nonce = vec_new (u8, vec_len (sa->i_nonce)); + RAND_bytes ((u8 *) sa->r_nonce, vec_len (sa->i_nonce)); } /* generate dh keys */ @@ -480,11 +482,10 @@ ikev2_complete_sa_data (ikev2_sa_t * sa, ikev2_sa_t * sai) } static void -ikev2_calc_keys (ikev2_sa_t * sa) +ikev2_calc_keys_internal (ikev2_sa_t *sa, u8 *skeyseed) { u8 *tmp; /* calculate SKEYSEED = prf(Ni | Nr, g^ir) */ - u8 *skeyseed = 0; u8 *s = 0; u16 integ_key_len = 0, salt_len = 0; ikev2_sa_transform_t *tr_encr, *tr_prf, *tr_integ; @@ -502,7 +503,6 @@ ikev2_calc_keys (ikev2_sa_t * sa) vec_append (s, sa->i_nonce); vec_append (s, sa->r_nonce); - skeyseed = ikev2_calc_prf (tr_prf, s, sa->dh_shared_key); /* Calculate S = Ni | Nr | SPIi | SPIr */ u64 *spi; @@ -520,7 +520,6 @@ ikev2_calc_keys (ikev2_sa_t * sa) salt_len * 2; keymat = ikev2_calc_prfplus (tr_prf, skeyseed, s, len); - vec_free (skeyseed); vec_free (s); int pos = 0; @@ -568,7 +567,42 @@ ikev2_calc_keys (ikev2_sa_t * sa) } static void -ikev2_calc_child_keys (ikev2_sa_t * sa, ikev2_child_sa_t * child) +ikev2_calc_keys_rekey (ikev2_sa_t *sa_new, ikev2_sa_t *sa_old) +{ + u8 *s = 0, *skeyseed = 0; + ikev2_sa_transform_t *tr_prf = + ikev2_sa_get_td_for_type (sa_old->r_proposals, IKEV2_TRANSFORM_TYPE_PRF); + + vec_append (s, sa_new->dh_shared_key); + vec_append (s, sa_new->i_nonce); + vec_append (s, sa_new->r_nonce); + skeyseed = ikev2_calc_prf (tr_prf, sa_old->sk_d, s); + + ikev2_calc_keys_internal (sa_new, skeyseed); + + vec_free (skeyseed); + vec_free (s); +} + +static void +ikev2_calc_keys (ikev2_sa_t *sa) +{ + u8 *s = 0, *skeyseed = 0; + ikev2_sa_transform_t *tr_prf = + ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF); + + vec_append (s, sa->i_nonce); + vec_append (s, sa->r_nonce); + skeyseed = ikev2_calc_prf (tr_prf, s, sa->dh_shared_key); + + ikev2_calc_keys_internal (sa, skeyseed); + + vec_free (skeyseed); + vec_free (s); +} + +static void +ikev2_calc_child_keys (ikev2_sa_t *sa, ikev2_child_sa_t *child, u8 kex) { u8 *s = 0; u16 integ_key_len = 0; @@ -587,6 +621,8 @@ ikev2_calc_child_keys (ikev2_sa_t * sa, ikev2_child_sa_t * child) else salt_len = sizeof (u32); + if (kex) + vec_append (s, sa->dh_shared_key); vec_append (s, sa->i_nonce); vec_append (s, sa->r_nonce); /* calculate PRFplus */ @@ -638,8 +674,8 @@ ikev2_calc_child_keys (ikev2_sa_t * sa, ikev2_child_sa_t * child) vec_free (keymat); } -static_always_inline u8 * -ikev2_compute_nat_sha1 (u64 ispi, u64 rspi, ip_address_t * ia, u16 port) +static u8 * +ikev2_compute_nat_sha1 (u64 ispi, u64 rspi, ip_address_t *ia, u16 port) { const u32 max_buf_size = sizeof (ispi) + sizeof (rspi) + sizeof (ip6_address_t) + sizeof (u16); @@ -662,7 +698,10 @@ ikev2_parse_ke_payload (const void *p, u32 rlen, ikev2_sa_t * sa, u16 plen = clib_net_to_host_u16 (ke->length); ASSERT (plen >= sizeof (*ke) && plen <= rlen); if (sizeof (*ke) > rlen) - return 0; + { + ikev2_elog_error ("KE: packet too small"); + return 0; + } sa->dh_group = clib_net_to_host_u16 (ke->dh_group); vec_reset_length (ke_data[0]); @@ -671,13 +710,20 @@ ikev2_parse_ke_payload (const void *p, u32 rlen, ikev2_sa_t * sa, } static int -ikev2_parse_nonce_payload (const void *p, u32 rlen, u8 * nonce) +ikev2_parse_nonce_payload (const void *p, u32 rlen, const u8 **nonce) { const ike_payload_header_t *ikep = p; u16 plen = clib_net_to_host_u16 (ikep->length); ASSERT (plen >= sizeof (*ikep) && plen <= rlen); - clib_memcpy_fast (nonce, ikep->payload, plen - sizeof (*ikep)); - return 1; + int len = plen - sizeof (*ikep); + ASSERT (len >= 16 && len <= 256); + if (PREDICT_FALSE (len < 16 || len > 256)) + { + ikev2_elog_error ("NONCE: bad size"); + return 0; + } + *nonce = ikep->payload; + return len; } static int @@ -685,10 +731,16 @@ ikev2_check_payload_length (const ike_payload_header_t * ikep, int rlen, u16 * plen) { if (sizeof (*ikep) > rlen) - return 0; + { + ikev2_elog_error ("payload: packet too small"); + return 0; + } *plen = clib_net_to_host_u16 (ikep->length); if (*plen < sizeof (*ikep) || *plen > rlen) - return 0; + { + ikev2_elog_error ("payload: bad size"); + return 0; + } return 1; } @@ -696,7 +748,6 @@ static int ikev2_process_sa_init_req (vlib_main_t *vm, ikev2_sa_t *sa, ike_header_t *ike, udp_header_t *udp, u32 len, u32 sw_if_index) { - u8 nonce[IKEV2_NONCE_SIZE]; int p = 0; u8 payload = ike->nextpayload; ike_payload_header_t *ikep; @@ -716,7 +767,10 @@ ikev2_process_sa_init_req (vlib_main_t *vm, ikev2_sa_t *sa, ike_header_t *ike, vec_add (sa->last_sa_init_req_packet_data, ike, len); if (len < sizeof (*ike)) - return 0; + { + ikev2_elog_error ("IKE_INIT request too small"); + return 0; + } len -= sizeof (*ike); while (p < len && payload != IKEV2_PAYLOAD_NONE) @@ -739,9 +793,13 @@ ikev2_process_sa_init_req (vlib_main_t *vm, ikev2_sa_t *sa, ike_header_t *ike, } else if (payload == IKEV2_PAYLOAD_NONCE) { + const u8 *nonce; + int nonce_len; vec_reset_length (sa->i_nonce); - if (ikev2_parse_nonce_payload (ikep, current_length, nonce)) - vec_add (sa->i_nonce, nonce, plen - sizeof (*ikep)); + if ((nonce_len = ikev2_parse_nonce_payload (ikep, current_length, + &nonce)) <= 0) + return 0; + vec_add (sa->i_nonce, nonce, nonce_len); } else if (payload == IKEV2_PAYLOAD_NOTIFY) { @@ -805,7 +863,6 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, ikev2_sa_t * sa, ike_header_t * ike, udp_header_t * udp, u32 len) { - u8 nonce[IKEV2_NONCE_SIZE]; int p = 0; u8 payload = ike->nextpayload; ike_payload_header_t *ikep; @@ -824,7 +881,10 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, vec_add (sa->last_sa_init_res_packet_data, ike, len); if (sizeof (*ike) > len) - return; + { + ikev2_elog_error ("IKE_INIT response too small"); + return; + } len -= sizeof (*ike); while (p < len && payload != IKEV2_PAYLOAD_NONE) @@ -853,9 +913,13 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, } else if (payload == IKEV2_PAYLOAD_NONCE) { + const u8 *nonce; + int nonce_len; vec_reset_length (sa->r_nonce); - if (ikev2_parse_nonce_payload (ikep, current_length, nonce)) - vec_add (sa->r_nonce, nonce, plen - sizeof (*ikep)); + if ((nonce_len = ikev2_parse_nonce_payload (ikep, current_length, + &nonce)) <= 0) + return; + vec_add (sa->r_nonce, nonce, nonce_len); } else if (payload == IKEV2_PAYLOAD_NOTIFY) { @@ -1021,8 +1085,8 @@ ikev2_decrypt_sk_payload (ikev2_sa_t * sa, ike_header_t * ike, return plaintext; } -static_always_inline int -ikev2_is_id_equal (ikev2_id_t * i1, ikev2_id_t * i2) +static int +ikev2_is_id_equal (const ikev2_id_t *i1, const ikev2_id_t *i2) { if (i1->type != i2->type) return 0; @@ -1046,7 +1110,6 @@ ikev2_initial_contact_cleanup_internal (ikev2_main_per_thread_data_t * ptd, ikev2_child_sa_t *c; /* find old IKE SAs with the same authenticated identity */ - /* *INDENT-OFF* */ pool_foreach (tmp, ptd->sas) { if (!ikev2_is_id_equal (&tmp->i_id, &sa->i_id) || !ikev2_is_id_equal(&tmp->r_id, &sa->r_id)) @@ -1055,7 +1118,6 @@ ikev2_initial_contact_cleanup_internal (ikev2_main_per_thread_data_t * ptd, if (sa->rspi != tmp->rspi) vec_add1(delete, tmp - ptd->sas); } - /* *INDENT-ON* */ for (i = 0; i < vec_len (delete); i++) { @@ -1332,6 +1394,159 @@ ikev2_process_informational_req (vlib_main_t * vm, } static int +ikev2_process_create_child_sa_rekey (ikev2_sa_t *sa, ikev2_sa_t *sar, + ikev2_rekey_t *rekey, + ikev2_sa_proposal_t *proposal, + ikev2_ts_t *tsi, ikev2_ts_t *tsr, + const u8 *nonce, int nonce_len) +{ + ikev2_sa_transform_t *tr; + + rekey->i_proposal = proposal; + rekey->r_proposal = ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP); + + if (sar->dh_group) + { + tr = + ikev2_sa_get_td_for_type (rekey->r_proposal, IKEV2_TRANSFORM_TYPE_DH); + + if (!tr || tr->dh_type != sar->dh_group) + { + rekey->notify_type = IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD; + ikev2_sa_free_proposal_vector (&rekey->r_proposal); + return 0; + } + + vec_free (sa->dh_shared_key); + vec_free (sa->dh_private_key); + vec_free (sa->i_dh_data); + vec_free (sa->r_dh_data); + + sa->dh_group = sar->dh_group; + sa->i_dh_data = sar->i_dh_data; + sar->i_dh_data = 0; + + ikev2_generate_dh (sa, tr); + rekey->kex = 1; + } + + vec_reset_length (sa->i_nonce); + vec_add (sa->i_nonce, nonce, nonce_len); + + vec_validate (sa->r_nonce, nonce_len - 1); + RAND_bytes ((u8 *) sa->r_nonce, nonce_len); + + rekey->tsi = tsi; + rekey->tsr = tsr; + + return 1; +} + +static void +ikev2_complete_sa_rekey (ikev2_sa_t *sa_new, ikev2_sa_t *sa_old, + ikev2_sa_rekey_t *sa_rekey) +{ + sa_new->del = 0; + sa_new->rekey = 0; + sa_new->new_child = 0; + sa_new->sa_rekey = 0; + sa_new->last_sa_init_req_packet_data = 0; + sa_new->last_sa_init_res_packet_data = 0; + sa_new->last_msg_id = ~0; + sa_new->last_res_packet_data = 0; + sa_new->last_init_msg_id = 0; + clib_memset (&sa_new->stats, 0, sizeof (sa_new->stats)); + + sa_new->ispi = sa_rekey->ispi; + sa_new->rspi = sa_rekey->rspi; + sa_new->i_nonce = sa_rekey->i_nonce; + sa_new->r_nonce = sa_rekey->r_nonce; + sa_new->dh_group = sa_rekey->dh_group; + sa_new->dh_shared_key = sa_rekey->dh_shared_key; + sa_new->dh_private_key = sa_rekey->dh_private_key; + sa_new->i_dh_data = sa_rekey->i_dh_data; + sa_new->r_dh_data = sa_rekey->r_dh_data; + sa_new->i_proposals = sa_rekey->i_proposals; + sa_new->r_proposals = sa_rekey->r_proposals; + + sa_new->sk_d = 0; + sa_new->sk_ai = 0; + sa_new->sk_ar = 0; + sa_new->sk_ei = 0; + sa_new->sk_er = 0; + sa_new->sk_pi = 0; + sa_new->sk_pr = 0; + ikev2_calc_keys_rekey (sa_new, sa_old); + + sa_new->i_auth.data = vec_dup (sa_old->i_auth.data); + sa_new->i_auth.key = sa_old->i_auth.key; + if (sa_new->i_auth.key) + EVP_PKEY_up_ref (sa_new->i_auth.key); + + sa_new->r_auth.data = vec_dup (sa_old->r_auth.data); + sa_new->r_auth.key = sa_old->r_auth.key; + if (sa_new->r_auth.key) + EVP_PKEY_up_ref (sa_new->r_auth.key); + + sa_new->i_id.data = vec_dup (sa_old->i_id.data); + sa_new->r_id.data = vec_dup (sa_old->r_id.data); + + sa_old->is_tun_itf_set = 0; + sa_old->tun_itf = ~0; + sa_old->old_id_expiration = 0; + sa_old->current_remote_id_mask = 0; + sa_old->old_remote_id = 0; + sa_old->old_remote_id_present = 0; + sa_old->childs = 0; + sa_old->sw_if_index = ~0; +} + +static void +ikev2_process_sa_rekey (ikev2_sa_t *sa_new, ikev2_sa_t *sa_old, + ikev2_sa_rekey_t *sa_rekey) +{ + ikev2_sa_transform_t *tr; + + if (ikev2_generate_sa_init_data (sa_new) != IKEV2_GENERATE_SA_INIT_OK) + { + sa_rekey->notify_type = IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD; + return; + } + + sa_new->r_proposals = + ikev2_select_proposal (sa_new->i_proposals, IKEV2_PROTOCOL_IKE); + + tr = ikev2_sa_get_td_for_type (sa_new->r_proposals, IKEV2_TRANSFORM_TYPE_DH); + if (!tr || tr->dh_type != sa_new->dh_group) + { + sa_rekey->notify_type = IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD; + return; + } + + sa_rekey->notify_type = 0; + sa_rekey->ispi = sa_new->i_proposals[0].spi; + sa_rekey->rspi = sa_new->r_proposals[0].spi; + sa_rekey->i_nonce = sa_new->i_nonce; + sa_rekey->r_nonce = sa_new->r_nonce; + sa_rekey->dh_group = sa_new->dh_group; + sa_rekey->dh_shared_key = sa_new->dh_shared_key; + sa_rekey->dh_private_key = sa_new->dh_private_key; + sa_rekey->i_dh_data = sa_new->i_dh_data; + sa_rekey->r_dh_data = sa_new->r_dh_data; + sa_rekey->i_proposals = sa_new->i_proposals; + sa_rekey->r_proposals = sa_new->r_proposals; + + sa_new->i_nonce = 0; + sa_new->r_nonce = 0; + sa_new->dh_shared_key = 0; + sa_new->dh_private_key = 0; + sa_new->i_dh_data = 0; + sa_new->r_dh_data = 0; + sa_new->i_proposals = 0; + sa_new->r_proposals = 0; +} + +static int ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_sa_t * sa, ike_header_t * ike, u32 len) @@ -1339,8 +1554,6 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, int p = 0; u8 payload = ike->nextpayload; u8 *plaintext = 0; - u8 rekeying = 0; - u8 nonce[IKEV2_NONCE_SIZE]; ikev2_rekey_t *rekey; ike_payload_header_t *ikep; ikev2_notify_t *n = 0; @@ -1350,6 +1563,11 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_child_sa_t *child_sa; u32 dlen = 0, src; u16 plen; + const u8 *nonce = 0; + int nonce_len = 0; + ikev2_sa_t sar; + + clib_memset (&sar, 0, sizeof (sar)); if (sa->is_initiator) src = ip_addr_v4 (&sa->raddr).as_u32; @@ -1379,13 +1597,23 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, { proposal = ikev2_parse_sa_payload (ikep, current_length); } + else if (payload == IKEV2_PAYLOAD_KE) + { + if (!ikev2_parse_ke_payload (ikep, current_length, &sar, + &sar.i_dh_data)) + goto cleanup_and_exit; + } else if (payload == IKEV2_PAYLOAD_NOTIFY) { - n = ikev2_parse_notify_payload (ikep, current_length); - if (n->msg_type == IKEV2_NOTIFY_MSG_REKEY_SA) + ikev2_notify_t *n0; + n0 = ikev2_parse_notify_payload (ikep, current_length); + if (n0->msg_type == IKEV2_NOTIFY_MSG_REKEY_SA) { - rekeying = 1; + vec_free (n); + n = n0; } + else + vec_free (n0); } else if (payload == IKEV2_PAYLOAD_DELETE) { @@ -1397,7 +1625,9 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, } else if (payload == IKEV2_PAYLOAD_NONCE) { - ikev2_parse_nonce_payload (ikep, current_length, nonce); + nonce_len = ikev2_parse_nonce_payload (ikep, current_length, &nonce); + if (nonce_len <= 0) + goto cleanup_and_exit; } else if (payload == IKEV2_PAYLOAD_TSI) { @@ -1421,7 +1651,9 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, p += plen; } - if (!proposal || proposal->protocol_id != IKEV2_PROTOCOL_ESP) + if (!proposal || !nonce || + (proposal->protocol_id != IKEV2_PROTOCOL_ESP && + proposal->protocol_id != IKEV2_PROTOCOL_IKE)) goto cleanup_and_exit; if (sa->is_initiator) @@ -1429,6 +1661,7 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, rekey = sa->rekey; if (vec_len (rekey) == 0) goto cleanup_and_exit; + rekey->notify_type = 0; rekey->protocol_id = proposal->protocol_id; rekey->i_proposal = ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP); @@ -1438,7 +1671,7 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, rekey->tsr = tsr; /* update Nr */ vec_reset_length (sa->r_nonce); - vec_add (sa->r_nonce, nonce, IKEV2_NONCE_SIZE); + vec_add (sa->r_nonce, nonce, nonce_len); child_sa = ikev2_sa_get_child (sa, rekey->ispi, IKEV2_PROTOCOL_ESP, 1); if (child_sa) { @@ -1447,7 +1680,7 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, } else { - if (rekeying) + if (n) { child_sa = ikev2_sa_get_child (sa, n->spi, n->protocol_id, 1); if (!child_sa) @@ -1457,36 +1690,52 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, goto cleanup_and_exit; } vec_add2 (sa->rekey, rekey, 1); + rekey->notify_type = 0; + rekey->kex = 0; rekey->protocol_id = n->protocol_id; rekey->spi = n->spi; - rekey->i_proposal = proposal; - rekey->r_proposal = - ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP); - /* update Ni */ - vec_reset_length (sa->i_nonce); - vec_add (sa->i_nonce, nonce, IKEV2_NONCE_SIZE); - /* generate new Nr */ - vec_validate (sa->r_nonce, IKEV2_NONCE_SIZE - 1); - RAND_bytes ((u8 *) sa->r_nonce, IKEV2_NONCE_SIZE); + if (sa->old_remote_id_present) + { + rekey->notify_type = IKEV2_NOTIFY_MSG_TEMPORARY_FAILURE; + vec_free (proposal); + vec_free (tsr); + vec_free (tsi); + } + else if (!ikev2_process_create_child_sa_rekey ( + sa, &sar, rekey, proposal, tsi, tsr, nonce, nonce_len)) + { + vec_free (proposal); + vec_free (tsr); + vec_free (tsi); + } + } + else if (proposal[0].protocol_id == IKEV2_PROTOCOL_IKE) + { + ikev2_sa_rekey_t *sa_rekey; + if (tsi || tsr) + goto cleanup_and_exit; + sar.i_proposals = proposal; + vec_add (sar.i_nonce, nonce, nonce_len); + vec_add2 (sa->sa_rekey, sa_rekey, 1); + ikev2_process_sa_rekey (&sar, sa, sa_rekey); } else { /* create new child SA */ vec_add2 (sa->new_child, rekey, 1); - rekey->i_proposal = proposal; - rekey->r_proposal = - ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP); - /* update Ni */ - vec_reset_length (sa->i_nonce); - vec_add (sa->i_nonce, nonce, IKEV2_NONCE_SIZE); - /* generate new Nr */ - vec_validate (sa->r_nonce, IKEV2_NONCE_SIZE - 1); - RAND_bytes ((u8 *) sa->r_nonce, IKEV2_NONCE_SIZE); + rekey->notify_type = 0; + rekey->kex = 0; + if (!ikev2_process_create_child_sa_rekey ( + sa, &sar, rekey, proposal, tsi, tsr, nonce, nonce_len)) + { + vec_free (proposal); + vec_free (tsr); + vec_free (tsi); + } } - rekey->tsi = tsi; - rekey->tsr = tsr; } vec_free (n); + ikev2_sa_free_all_vec (&sar); return 1; cleanup_and_exit: @@ -1494,6 +1743,7 @@ cleanup_and_exit: vec_free (proposal); vec_free (tsr); vec_free (tsi); + ikev2_sa_free_all_vec (&sar); return 0; } @@ -1541,6 +1791,25 @@ ikev2_sa_generate_authmsg (ikev2_sa_t * sa, int is_responder) } static int +ikev2_match_profile (const ikev2_profile_t *p, const ikev2_id_t *id_loc, + const ikev2_id_t *id_rem, int is_initiator) +{ + /* on the initiator, IDi is always present and must match + * however on the responder, IDr (which is our local id) is optional */ + if ((is_initiator || id_loc->type != 0) && + !ikev2_is_id_equal (&p->loc_id, id_loc)) + return 0; + + /* on the initiator, we might not have configured a specific remote id + * however on the responder, the remote id should always be configured */ + if ((!is_initiator || p->rem_id.type != 0) && + !ikev2_is_id_equal (&p->rem_id, id_rem)) + return 0; + + return 1; +} + +static int ikev2_ts_cmp (ikev2_ts_t * ts1, ikev2_ts_t * ts2) { if (ts1->ts_type == ts2->ts_type && ts1->protocol_id == ts2->protocol_id && @@ -1560,7 +1829,6 @@ ikev2_sa_match_ts (ikev2_sa_t * sa) ikev2_ts_t *ts, *p_tsi, *p_tsr, *tsi = 0, *tsr = 0; ikev2_id_t *id_rem, *id_loc; - /* *INDENT-OFF* */ pool_foreach (p, km->profiles) { if (sa->is_initiator) @@ -1578,9 +1846,7 @@ ikev2_sa_match_ts (ikev2_sa_t * sa) id_loc = &sa->r_id; } - /* check id */ - if (!ikev2_is_id_equal (&p->rem_id, id_rem) - || !ikev2_is_id_equal (&p->loc_id, id_loc)) + if (!ikev2_match_profile (p, id_loc, id_rem, sa->is_initiator)) continue; sa->profile_index = p - km->profiles; @@ -1605,7 +1871,6 @@ ikev2_sa_match_ts (ikev2_sa_t * sa) break; } - /* *INDENT-ON* */ if (tsi && tsr) { @@ -1623,7 +1888,7 @@ ikev2_sa_match_ts (ikev2_sa_t * sa) } static ikev2_profile_t * -ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa, +ikev2_select_profile (vlib_main_t *vm, ikev2_main_t *km, ikev2_sa_t *sa, ikev2_sa_transform_t *tr_prf, u8 *key_pad) { ikev2_profile_t *ret = 0, *p; @@ -1648,9 +1913,7 @@ ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa, pool_foreach (p, km->profiles) { - /* check id */ - if (!ikev2_is_id_equal (&p->rem_id, id_rem) || - !ikev2_is_id_equal (&p->loc_id, id_loc)) + if (!ikev2_match_profile (p, id_loc, id_rem, sa->is_initiator)) continue; if (sa_auth->method == IKEV2_AUTH_METHOD_SHARED_KEY_MIC) @@ -1665,6 +1928,7 @@ ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa, if (!clib_memcmp (auth, sa_auth->data, vec_len (sa_auth->data))) { ikev2_set_state (sa, IKEV2_STATE_AUTHENTICATED); + sa->auth_timestamp = vlib_time_now (vm); vec_free (auth); ret = p; break; @@ -1683,6 +1947,7 @@ ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa, if (ikev2_verify_sign (p->auth.key, sa_auth->data, authmsg) == 1) { ikev2_set_state (sa, IKEV2_STATE_AUTHENTICATED); + sa->auth_timestamp = vlib_time_now (vm); ret = p; break; } @@ -1698,7 +1963,7 @@ ikev2_select_profile (ikev2_main_t *km, ikev2_sa_t *sa, } static void -ikev2_sa_auth (ikev2_sa_t *sa) +ikev2_sa_auth (ikev2_sa_t *sa, vlib_main_t *vm) { ikev2_main_t *km = &ikev2_main; ikev2_profile_t *sel_p = 0; @@ -1719,7 +1984,7 @@ ikev2_sa_auth (ikev2_sa_t *sa) } key_pad = format (0, "%s", IKEV2_KEY_PAD); - sel_p = ikev2_select_profile (km, sa, tr_prf, key_pad); + sel_p = ikev2_select_profile (vm, km, sa, tr_prf, key_pad); if (sel_p) { @@ -1864,8 +2129,8 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) .t_mode = TUNNEL_MODE_P2P, .t_table_id = 0, .t_hop_limit = 255, - .t_src = a->local_ip, - .t_dst = a->remote_ip, + .t_src = a->remote_ip, + .t_dst = a->local_ip, }; tunnel_t tun_out = { .t_flags = TUNNEL_FLAG_NONE, @@ -1874,8 +2139,8 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) .t_mode = TUNNEL_MODE_P2P, .t_table_id = 0, .t_hop_limit = 255, - .t_src = a->remote_ip, - .t_dst = a->local_ip, + .t_src = a->local_ip, + .t_dst = a->remote_ip, }; if (~0 == a->sw_if_index) @@ -1924,7 +2189,7 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) rv = ipsec_sa_add_and_lock (a->local_sa_id, a->local_spi, IPSEC_PROTOCOL_ESP, a->encr_type, &a->loc_ckey, a->integ_type, &a->loc_ikey, a->flags, a->salt_local, - a->src_port, a->dst_port, &tun_out, NULL); + a->src_port, a->dst_port, 0, &tun_out, NULL); if (rv) goto err0; @@ -1932,7 +2197,7 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) 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), a->salt_remote, - a->ipsec_over_udp_port, a->ipsec_over_udp_port, &tun_in, NULL); + a->ipsec_over_udp_port, a->ipsec_over_udp_port, 0, &tun_in, NULL); if (rv) goto err1; @@ -1951,10 +2216,9 @@ err0: } static int -ikev2_create_tunnel_interface (vlib_main_t * vm, - ikev2_sa_t * sa, - ikev2_child_sa_t * child, u32 sa_index, - u32 child_index, u8 is_rekey) +ikev2_create_tunnel_interface (vlib_main_t *vm, ikev2_sa_t *sa, + ikev2_child_sa_t *child, u32 sa_index, + u32 child_index, u8 is_rekey, u8 kex) { u32 thread_index = vlib_get_thread_index (); ikev2_main_t *km = &ikev2_main; @@ -1968,6 +2232,8 @@ ikev2_create_tunnel_interface (vlib_main_t * vm, clib_memset (&a, 0, sizeof (a)); + child->timestamp = vlib_time_now (vm); + if (!child->r_proposals) { ikev2_set_state (sa, IKEV2_STATE_NO_PROPOSAL_CHOSEN); @@ -2097,7 +2363,7 @@ ikev2_create_tunnel_interface (vlib_main_t * vm, } a.integ_type = integ_type; - ikev2_calc_child_keys (sa, child); + ikev2_calc_child_keys (sa, child, kex); if (sa->is_initiator) { @@ -2202,7 +2468,7 @@ typedef struct u32 sw_if_index; } ikev2_del_ipsec_tunnel_args_t; -static_always_inline u32 +static u32 ikev2_flip_alternate_sa_bit (u32 id) { u32 mask = 0x800; @@ -2220,14 +2486,12 @@ ikev2_del_tunnel_from_main (ikev2_del_ipsec_tunnel_args_t * a) if (~0 == a->sw_if_index) { - /* *INDENT-OFF* */ ipip_tunnel_key_t key = { .src = a->local_ip, .dst = a->remote_ip, .transport = IPIP_TRANSPORT_IP4, .fib_index = 0, }; - /* *INDENT-ON* */ ipip = ipip_tunnel_db_find (&key); @@ -2284,6 +2548,47 @@ ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, return 0; } +static void +ikev2_add_invalid_ke_payload (ikev2_sa_t *sa, ikev2_payload_chain_t *chain) +{ + u8 *data = vec_new (u8, 2); + ikev2_sa_transform_t *tr_dh = + ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_DH); + ASSERT (tr_dh && tr_dh->dh_type); + data[0] = (tr_dh->dh_type >> 8) & 0xff; + data[1] = (tr_dh->dh_type) & 0xff; + ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD, data); + vec_free (data); +} + +static void +ikev2_add_notify_payload (ikev2_sa_t *sa, ikev2_payload_chain_t *chain, + u16 notify_type) +{ + if (notify_type == IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD) + ikev2_add_invalid_ke_payload (sa, chain); + else + ikev2_payload_add_notify (chain, notify_type, 0); +} + +static void +ikev2_add_create_child_resp (ikev2_sa_t *sa, ikev2_rekey_t *rekey, + ikev2_payload_chain_t *chain) +{ + if (rekey->notify_type) + { + ikev2_add_notify_payload (sa, chain, rekey->notify_type); + return; + } + + ikev2_payload_add_sa (chain, rekey->r_proposal, 0); + ikev2_payload_add_nonce (chain, sa->r_nonce); + if (rekey->kex) + ikev2_payload_add_ke (chain, sa->dh_group, sa->r_dh_data); + ikev2_payload_add_ts (chain, rekey->tsi, IKEV2_PAYLOAD_TSI); + ikev2_payload_add_ts (chain, rekey->tsr, IKEV2_PAYLOAD_TSR); +} + static u32 ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, void *user, udp_header_t *udp, ikev2_stats_t *stats) @@ -2314,20 +2619,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, } else if (sa->dh_group == IKEV2_TRANSFORM_DH_TYPE_NONE) { - u8 *data = vec_new (u8, 2); - ikev2_sa_transform_t *tr_dh; - tr_dh = - ikev2_sa_get_td_for_type (sa->r_proposals, - IKEV2_TRANSFORM_TYPE_DH); - ASSERT (tr_dh && tr_dh->dh_type); - - data[0] = (tr_dh->dh_type >> 8) & 0xff; - data[1] = (tr_dh->dh_type) & 0xff; - - ikev2_payload_add_notify (chain, - IKEV2_NOTIFY_MSG_INVALID_KE_PAYLOAD, - data); - vec_free (data); + ikev2_add_invalid_ke_payload (sa, chain); ikev2_set_state (sa, IKEV2_STATE_NOTIFY_AND_DELETE); } else if (sa->state == IKEV2_STATE_NOTIFY_AND_DELETE) @@ -2345,7 +2637,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, ASSERT (udp); ike->rspi = clib_host_to_net_u64 (sa->rspi); - ikev2_payload_add_sa (chain, sa->r_proposals); + ikev2_payload_add_sa (chain, sa->r_proposals, 0); ikev2_payload_add_ke (chain, sa->dh_group, sa->r_dh_data); ikev2_payload_add_nonce (chain, sa->r_nonce); @@ -2372,9 +2664,8 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, if (sa->state == IKEV2_STATE_AUTHENTICATED) { ikev2_payload_add_id (chain, &sa->r_id, IKEV2_PAYLOAD_IDR); - ikev2_payload_add_id (chain, &sa->i_id, IKEV2_PAYLOAD_IDI); ikev2_payload_add_auth (chain, &sa->r_auth); - ikev2_payload_add_sa (chain, sa->childs[0].r_proposals); + ikev2_payload_add_sa (chain, sa->childs[0].r_proposals, 0); ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI); ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR); } @@ -2414,9 +2705,12 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, else if (sa->state == IKEV2_STATE_SA_INIT) { ikev2_payload_add_id (chain, &sa->i_id, IKEV2_PAYLOAD_IDI); - ikev2_payload_add_id (chain, &sa->r_id, IKEV2_PAYLOAD_IDR); + /* IDr is optional when sending INIT from the initiator */ + ASSERT (sa->r_id.type != 0 || sa->is_initiator); + if (sa->r_id.type != 0) + ikev2_payload_add_id (chain, &sa->r_id, IKEV2_PAYLOAD_IDR); ikev2_payload_add_auth (chain, &sa->i_auth); - ikev2_payload_add_sa (chain, sa->childs[0].i_proposals); + ikev2_payload_add_sa (chain, sa->childs[0].i_proposals, 0); ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI); ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR); ikev2_payload_add_notify (chain, IKEV2_NOTIFY_MSG_INITIAL_CONTACT, @@ -2493,7 +2787,7 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, notify.spi = sa->childs[0].i_proposals->spi; *(u32 *) data = clib_host_to_net_u32 (notify.spi); - ikev2_payload_add_sa (chain, proposals); + ikev2_payload_add_sa (chain, proposals, 0); ikev2_payload_add_nonce (chain, sa->i_nonce); ikev2_payload_add_ts (chain, sa->childs[0].tsi, IKEV2_PAYLOAD_TSI); ikev2_payload_add_ts (chain, sa->childs[0].tsr, IKEV2_PAYLOAD_TSR); @@ -2504,22 +2798,27 @@ ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike, } else if (vec_len (sa->rekey) > 0) { - ikev2_payload_add_sa (chain, sa->rekey[0].r_proposal); - ikev2_payload_add_nonce (chain, sa->r_nonce); - ikev2_payload_add_ts (chain, sa->rekey[0].tsi, IKEV2_PAYLOAD_TSI); - ikev2_payload_add_ts (chain, sa->rekey[0].tsr, IKEV2_PAYLOAD_TSR); + ikev2_add_create_child_resp (sa, &sa->rekey[0], chain); vec_del1 (sa->rekey, 0); } else if (vec_len (sa->new_child) > 0) { - ikev2_payload_add_sa (chain, sa->new_child[0].r_proposal); - ikev2_payload_add_nonce (chain, sa->r_nonce); - ikev2_payload_add_ts (chain, sa->new_child[0].tsi, - IKEV2_PAYLOAD_TSI); - ikev2_payload_add_ts (chain, sa->new_child[0].tsr, - IKEV2_PAYLOAD_TSR); + ikev2_add_create_child_resp (sa, &sa->new_child[0], chain); vec_del1 (sa->new_child, 0); } + else if (vec_len (sa->sa_rekey) > 0) + { + if (sa->sa_rekey[0].notify_type) + ikev2_add_notify_payload (sa, chain, sa->sa_rekey[0].notify_type); + else + { + ikev2_payload_add_sa (chain, sa->sa_rekey[0].r_proposals, 1); + ikev2_payload_add_nonce (chain, sa->sa_rekey[0].r_nonce); + ikev2_payload_add_ke (chain, sa->sa_rekey[0].dh_group, + sa->sa_rekey[0].r_dh_data); + } + vec_del1 (sa->sa_rekey, 0); + } else if (sa->unsupported_cp) { u8 *data = vec_new (u8, 1); @@ -2712,13 +3011,11 @@ ikev2_retransmit_sa_init (ike_header_t * ike, ip_address_t iaddr, u32 res; ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data (); - /* *INDENT-OFF* */ pool_foreach (sa, ptd->sas) { res = ikev2_retransmit_sa_init_one (sa, ike, iaddr, raddr, rlen); if (res) return res; } - /* *INDENT-ON* */ /* req is not retransmit */ return 0; @@ -2796,8 +3093,8 @@ ikev2_del_sa_init (u64 ispi) sizeof (ispi)); } -static_always_inline void -ikev2_rewrite_v6_addrs (ikev2_sa_t * sa, ip6_header_t * ih) +static void +ikev2_rewrite_v6_addrs (ikev2_sa_t *sa, ip6_header_t *ih) { if (sa->is_initiator) { @@ -2811,8 +3108,8 @@ ikev2_rewrite_v6_addrs (ikev2_sa_t * sa, ip6_header_t * ih) } } -static_always_inline void -ikev2_rewrite_v4_addrs (ikev2_sa_t * sa, ip4_header_t * ih) +static void +ikev2_rewrite_v4_addrs (ikev2_sa_t *sa, ip4_header_t *ih) { if (sa->is_initiator) { @@ -2826,7 +3123,7 @@ ikev2_rewrite_v4_addrs (ikev2_sa_t * sa, ip4_header_t * ih) } } -static_always_inline void +static void ikev2_set_ip_address (ikev2_sa_t *sa, const void *iaddr, const void *raddr, const ip_address_family_t af) { @@ -2881,7 +3178,7 @@ ikev2_update_stats (vlib_main_t *vm, u32 node_index, ikev2_stats_t *s) s->n_sa_auth_req); } -static_always_inline uword +static uword ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, u8 is_ip4, u8 natt) { @@ -3131,18 +3428,19 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, sa0->dst_port = clib_net_to_host_u16 (udp0->src_port); res = ikev2_process_auth_req (vm, sa0, ike0, rlen); if (res) - ikev2_sa_auth (sa0); + ikev2_sa_auth (sa0, vm); else vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_MALFORMED_PACKET, 1); if (sa0->state == IKEV2_STATE_AUTHENTICATED) { ikev2_initial_contact_cleanup (ptd, sa0); + p = hash_get (ptd->sa_by_rspi, + clib_net_to_host_u64 (ike0->rspi)); ikev2_sa_match_ts (sa0); if (sa0->state != IKEV2_STATE_TS_UNACCEPTABLE) - ikev2_create_tunnel_interface (vm, sa0, - &sa0->childs[0], - p[0], 0, 0); + ikev2_create_tunnel_interface (vm, sa0, &sa0->childs[0], + p[0], 0, 0, 0); } if (sa0->is_initiator) @@ -3267,11 +3565,12 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, goto dispatch0; } - if (sa0->rekey) + if (vec_len (sa0->rekey) > 0) { - if (sa0->rekey[0].protocol_id != IKEV2_PROTOCOL_IKE) + if (!sa0->rekey[0].notify_type && + sa0->rekey[0].protocol_id != IKEV2_PROTOCOL_IKE) { - if (sa0->childs) + if (vec_len (sa0->childs) > 0) ikev2_sa_free_all_child_sa (&sa0->childs); ikev2_child_sa_t *child; vec_add2 (sa0->childs, child, 1); @@ -3281,7 +3580,8 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, child->tsi = sa0->rekey[0].tsi; child->tsr = sa0->rekey[0].tsr; ikev2_create_tunnel_interface (vm, sa0, child, p[0], - child - sa0->childs, 1); + child - sa0->childs, 1, + sa0->rekey[0].kex); } if (ike_hdr_is_response (ike0)) { @@ -3300,7 +3600,7 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, 1); } } - else if (sa0->new_child) + else if (vec_len (sa0->new_child) > 0) { ikev2_child_sa_t *c; vec_add2 (sa0->childs, c, 1); @@ -3310,7 +3610,8 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, c->tsi = sa0->new_child[0].tsi; c->tsr = sa0->new_child[0].tsr; ikev2_create_tunnel_interface (vm, sa0, c, p[0], - c - sa0->childs, 0); + c - sa0->childs, 0, + sa0->new_child[0].kex); if (ike_hdr_is_request (ike0)) { ike0->flags = IKEV2_HDR_FLAG_RESPONSE; @@ -3321,6 +3622,38 @@ ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, 1); } } + else if (vec_len (sa0->sa_rekey) > 0) + { + if (!sa0->sa_rekey[0].notify_type) + { + ikev2_sa_t *sar, *tmp = 0; + pool_get (ptd->sas, tmp); + sa0 = pool_elt_at_index (ptd->sas, p[0]); + /* swap old/new SAs to keep index and inherit IPsec SA */ + clib_memcpy_fast (tmp, sa0, sizeof (*tmp)); + sar = sa0; + sa0 = tmp; + hash_set (ptd->sa_by_rspi, sa0->rspi, sa0 - ptd->sas); + p = hash_get (ptd->sa_by_rspi, sa0->rspi); + ikev2_complete_sa_rekey (sar, sa0, &sa0->sa_rekey[0]); + hash_set (ptd->sa_by_rspi, sar->rspi, sar - ptd->sas); + } + if (ike_hdr_is_response (ike0)) + { + vec_free (sa0->sa_rekey); + } + else + { + stats->n_rekey_req++; + sa0->stats.n_rekey_req++; + ike0->flags = IKEV2_HDR_FLAG_RESPONSE; + slen = + ikev2_generate_message (b0, sa0, ike0, 0, udp0, stats); + if (~0 == slen) + vlib_node_increment_counter ( + vm, node->node_index, IKEV2_ERROR_NO_BUFF_SPACE, 1); + } + } } } else @@ -3429,7 +3762,6 @@ ikev2_ip6 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) return ikev2_node_internal (vm, node, frame, 0 /* is_ip4 */, 0); } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ikev2_node_ip4,static) = { .function = ikev2_ip4, .name = "ikev2-ip4", @@ -3480,7 +3812,6 @@ VLIB_REGISTER_NODE (ikev2_node_ip6,static) = { [IKEV2_NEXT_IP6_ERROR_DROP] = "error-drop", }, }; -/* *INDENT-ON* */ // set ikev2 proposals when vpp is used as initiator static clib_error_t * @@ -3721,21 +4052,23 @@ 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) +static vnet_api_error_t +ikev2_register_udp_port (ikev2_profile_t *p, u16 port) { - ipsec_register_udp_port (port); + ipsec_register_udp_port (port, 0 /* is_ip4 */); + ipsec_register_udp_port (port, 1 /* is_ip4 */); p->ipsec_over_udp_port = port; return 0; } -static_always_inline void -ikev2_unregister_udp_port (ikev2_profile_t * p) +static void +ikev2_unregister_udp_port (ikev2_profile_t *p) { if (p->ipsec_over_udp_port == IPSEC_UDP_PORT_NONE) return; - ipsec_unregister_udp_port (p->ipsec_over_udp_port); + ipsec_unregister_udp_port (p->ipsec_over_udp_port, 0 /* is_ip4 */); + ipsec_unregister_udp_port (p->ipsec_over_udp_port, 1 /* is_ip4 */); p->ipsec_over_udp_port = IPSEC_UDP_PORT_NONE; } @@ -3820,12 +4153,10 @@ ikev2_cleanup_profile_sessions (ikev2_main_t * km, ikev2_profile_t * p) u32 *sai; u32 *del_sai = 0; - /* *INDENT-OFF* */ pool_foreach (sa, km->sais) { if (pi == sa->profile_index) vec_add1 (del_sai, sa - km->sais); } - /* *INDENT-ON* */ vec_foreach (sai, del_sai) { @@ -3838,12 +4169,10 @@ ikev2_cleanup_profile_sessions (ikev2_main_t * km, ikev2_profile_t * p) vec_foreach (tkm, km->per_thread_data) { - /* *INDENT-OFF* */ pool_foreach (sa, tkm->sas) { if (sa->profile_index != ~0 && pi == sa->profile_index) vec_add1 (del_sai, sa - tkm->sas); } - /* *INDENT-ON* */ vec_foreach (sai, del_sai) { @@ -3878,12 +4207,51 @@ ikev2_profile_free (ikev2_profile_t * p) vec_free (p->rem_id.data); } +static void +ikev2_bind (vlib_main_t *vm, ikev2_main_t *km) +{ + if (0 == km->bind_refcount) + { + udp_register_dst_port (vm, IKEV2_PORT, ikev2_node_ip4.index, 1); + udp_register_dst_port (vm, IKEV2_PORT, ikev2_node_ip6.index, 0); + udp_register_dst_port (vm, IKEV2_PORT_NATT, ikev2_node_ip4.index, 1); + udp_register_dst_port (vm, IKEV2_PORT_NATT, ikev2_node_ip6.index, 0); + + vlib_punt_register (km->punt_hdl, + ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0], + "ikev2-ip4-natt"); + } + + km->bind_refcount++; +} + +static void +ikev2_unbind (vlib_main_t *vm, ikev2_main_t *km) +{ + km->bind_refcount--; + if (0 == km->bind_refcount) + { + vlib_punt_unregister (km->punt_hdl, + ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0], + "ikev2-ip4-natt"); + + udp_unregister_dst_port (vm, IKEV2_PORT_NATT, 0); + udp_unregister_dst_port (vm, IKEV2_PORT_NATT, 1); + udp_unregister_dst_port (vm, IKEV2_PORT, 0); + udp_unregister_dst_port (vm, IKEV2_PORT, 1); + } +} + +static void ikev2_lazy_init (ikev2_main_t *km); + clib_error_t * ikev2_add_del_profile (vlib_main_t * vm, u8 * name, int is_add) { ikev2_main_t *km = &ikev2_main; ikev2_profile_t *p; + ikev2_lazy_init (km); + if (is_add) { if (ikev2_profile_index_by_name (name)) @@ -3897,6 +4265,8 @@ ikev2_add_del_profile (vlib_main_t * vm, u8 * name, int is_add) p->tun_itf = ~0; uword index = p - km->profiles; mhash_set_mem (&km->profile_index_by_name, name, &index, 0); + + ikev2_bind (vm, km); } else { @@ -3904,6 +4274,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_unbind (vm, km); + ikev2_unregister_udp_port (p); ikev2_cleanup_profile_sessions (km, p); @@ -3995,8 +4367,8 @@ ikev2_set_profile_id (vlib_main_t * vm, u8 * name, u8 id_type, u8 * data, return 0; } -static_always_inline void -ikev2_set_ts_type (ikev2_ts_t * ts, const ip_address_t * addr) +static void +ikev2_set_ts_type (ikev2_ts_t *ts, const ip_address_t *addr) { if (ip_addr_version (addr) == AF_IP4) ts->ts_type = TS_IPV4_ADDR_RANGE; @@ -4004,9 +4376,9 @@ ikev2_set_ts_type (ikev2_ts_t * ts, const ip_address_t * addr) ts->ts_type = TS_IPV6_ADDR_RANGE; } -static_always_inline void -ikev2_set_ts_addrs (ikev2_ts_t * ts, const ip_address_t * start, - const ip_address_t * end) +static void +ikev2_set_ts_addrs (ikev2_ts_t *ts, const ip_address_t *start, + const ip_address_t *end) { ip_address_copy (&ts->start_addr, start); ip_address_copy (&ts->end_addr, end); @@ -4103,15 +4475,15 @@ ikev2_set_profile_ike_transforms (vlib_main_t * vm, u8 * name, u32 crypto_key_size) { ikev2_profile_t *p; - clib_error_t *r; p = ikev2_profile_index_by_name (name); - if (!p) - { - r = clib_error_return (0, "unknown profile %v", name); - return r; - } + return clib_error_return (0, "unknown profile %v", name); + + if ((IKEV2_TRANSFORM_INTEG_TYPE_NONE != integ_alg) + + (IKEV2_TRANSFORM_ENCR_TYPE_AES_GCM_16 == crypto_alg) != + 1) + return clib_error_return (0, "invalid cipher + integrity algorithm"); p->ike_ts.crypto_alg = crypto_alg; p->ike_ts.integ_alg = integ_alg; @@ -4264,13 +4636,20 @@ ikev2_resolve_responder_hostname (vlib_main_t *vm, ikev2_responder_t *r) dns_cache_entry_t *ep = 0; dns_pending_request_t _t0, *t0 = &_t0; dns_resolve_name_t _rn, *rn = &_rn; + u8 *name; int rv; - if (!km->dns_resolve_name) + if (!km->dns_resolve_name_ptr) return clib_error_return (0, "cannot load symbols from dns plugin"); t0->request_type = DNS_API_PENDING_NAME_TO_IP; - rv = km->dns_resolve_name (r->hostname, &ep, t0, rn); + /* VPP main curse: IKEv2 uses only non-NULL terminated vectors internally + * whereas DNS resolver expects a NULL-terminated C-string */ + name = vec_dup (r->hostname); + vec_terminate_c_string (name); + rv = ((__typeof__ (dns_resolve_name) *) km->dns_resolve_name_ptr) (name, &ep, + t0, rn); + vec_free (name); if (rv < 0) return clib_error_return (0, "dns lookup failure"); @@ -4339,7 +4718,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) proposals[0].protocol_id = IKEV2_PROTOCOL_IKE; /* Add and then cleanup proposal data */ - ikev2_payload_add_sa (chain, proposals); + ikev2_payload_add_sa (chain, proposals, 0); ikev2_sa_free_proposal_vector (&proposals); sa.is_initiator = 1; @@ -4373,6 +4752,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) sa.childs[0].i_proposals[0].protocol_id = IKEV2_PROTOCOL_ESP; RAND_bytes ((u8 *) & sa.childs[0].i_proposals[0].spi, sizeof (sa.childs[0].i_proposals[0].spi)); + sa.childs[0].i_proposals[0].spi &= 0xffffffff; /* Add NAT detection notification messages (mandatory) */ u8 *nat_detection_sha1 = ikev2_compute_nat_sha1 ( @@ -4524,7 +4904,6 @@ ikev2_initiate_delete_child_sa (vlib_main_t * vm, u32 ispi) ikev2_sa_t *sa; if (fchild) break; - /* *INDENT-OFF* */ pool_foreach (sa, tkm->sas) { fchild = ikev2_sa_get_child(sa, ispi, IKEV2_PROTOCOL_ESP, 1); if (fchild) @@ -4533,7 +4912,6 @@ ikev2_initiate_delete_child_sa (vlib_main_t * vm, u32 ispi) break; } } - /* *INDENT-ON* */ } if (!fchild || !fsa) @@ -4564,7 +4942,6 @@ ikev2_initiate_delete_ike_sa (vlib_main_t * vm, u64 ispi) ikev2_sa_t *sa; if (fsa) break; - /* *INDENT-OFF* */ pool_foreach (sa, tkm->sas) { if (sa->ispi == ispi) { @@ -4573,7 +4950,6 @@ ikev2_initiate_delete_ike_sa (vlib_main_t * vm, u64 ispi) break; } } - /* *INDENT-ON* */ } if (!fsa) @@ -4615,10 +4991,12 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, ikev2_rekey_t *rekey; vec_reset_length (sa->rekey); vec_add2 (sa->rekey, rekey, 1); + rekey->kex = 0; ikev2_sa_proposal_t *proposals = vec_dup (csa->i_proposals); /*need new ispi */ RAND_bytes ((u8 *) & proposals[0].spi, sizeof (proposals[0].spi)); + proposals[0].spi &= 0xffffffff; rekey->spi = proposals[0].spi; rekey->ispi = csa->i_proposals->spi; len = ikev2_generate_message (b0, sa, ike0, proposals, 0, 0); @@ -4647,7 +5025,6 @@ ikev2_initiate_rekey_child_sa (vlib_main_t * vm, u32 ispi) ikev2_sa_t *sa; if (fchild) break; - /* *INDENT-OFF* */ pool_foreach (sa, tkm->sas) { fchild = ikev2_sa_get_child(sa, ispi, IKEV2_PROTOCOL_ESP, 1); if (fchild) @@ -4656,7 +5033,6 @@ ikev2_initiate_rekey_child_sa (vlib_main_t * vm, u32 ispi) break; } } - /* *INDENT-ON* */ } if (!fchild || !fsa) @@ -4689,12 +5065,10 @@ ikev2_sa_del (ikev2_profile_t * p, u32 sw_if_index) vec_foreach (tkm, km->per_thread_data) { - /* *INDENT-OFF* */ pool_foreach (sa, tkm->sas) { if (ikev2_sa_sw_if_match (sa, sw_if_index)) vec_add1 (sa_vec, sa); } - /* *INDENT-ON* */ vec_foreach (sap, sa_vec) { @@ -4704,12 +5078,10 @@ ikev2_sa_del (ikev2_profile_t * p, u32 sw_if_index) } vec_free (sa_vec); - /* *INDENT-OFF* */ pool_foreach (sa, km->sais) { if (ikev2_sa_sw_if_match (sa, sw_if_index)) vec_add1 (ispi_vec, sa->ispi); } - /* *INDENT-ON* */ vec_foreach (ispi, ispi_vec) { @@ -4728,12 +5100,10 @@ ikev2_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add) if (is_add) return 0; - /* *INDENT-OFF* */ pool_foreach (p, km->profiles) { if (p->responder.sw_if_index == sw_if_index) ikev2_sa_del (p, sw_if_index); } - /* *INDENT-ON* */ return 0; } @@ -4744,67 +5114,24 @@ clib_error_t * ikev2_init (vlib_main_t * vm) { ikev2_main_t *km = &ikev2_main; - vlib_thread_main_t *tm = vlib_get_thread_main (); - int thread_id; clib_memset (km, 0, sizeof (ikev2_main_t)); + + km->log_level = IKEV2_LOG_ERROR; + km->log_class = vlib_log_register_class ("ikev2", 0); + km->vnet_main = vnet_get_main (); km->vlib_main = vm; km->liveness_period = IKEV2_LIVENESS_PERIOD_CHECK; km->liveness_max_retries = IKEV2_LIVENESS_RETRIES; - ikev2_crypto_init (km); - - mhash_init_vec_string (&km->profile_index_by_name, sizeof (uword)); - - vec_validate_aligned (km->per_thread_data, tm->n_vlib_mains - 1, - CLIB_CACHE_LINE_BYTES); - for (thread_id = 0; thread_id < tm->n_vlib_mains; thread_id++) - { - ikev2_main_per_thread_data_t *ptd = - vec_elt_at_index (km->per_thread_data, thread_id); - ptd->sa_by_rspi = hash_create (0, sizeof (uword)); - -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - ptd->evp_ctx = EVP_CIPHER_CTX_new (); - ptd->hmac_ctx = HMAC_CTX_new (); -#else - EVP_CIPHER_CTX_init (&ptd->_evp_ctx); - ptd->evp_ctx = &ptd->_evp_ctx; - HMAC_CTX_init (&(ptd->_hmac_ctx)); - ptd->hmac_ctx = &ptd->_hmac_ctx; -#endif - } - - km->sa_by_ispi = hash_create (0, sizeof (uword)); - km->sw_if_indices = hash_create (0, 0); - - udp_register_dst_port (vm, IKEV2_PORT, ikev2_node_ip4.index, 1); - udp_register_dst_port (vm, IKEV2_PORT, ikev2_node_ip6.index, 0); - udp_register_dst_port (vm, IKEV2_PORT_NATT, ikev2_node_ip4.index, 1); - udp_register_dst_port (vm, IKEV2_PORT_NATT, ikev2_node_ip6.index, 0); - - vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("ikev2-ip4-natt"); - vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0], - "ikev2-ip4-natt"); - ikev2_cli_reference (); - - km->dns_resolve_name = - vlib_get_plugin_symbol ("dns_plugin.so", "dns_resolve_name"); - if (!km->dns_resolve_name) - ikev2_log_error ("cannot load symbols from dns plugin"); - - km->log_level = IKEV2_LOG_ERROR; - km->log_class = vlib_log_register_class ("ikev2", 0); return 0; } -/* *INDENT-OFF* */ VLIB_INIT_FUNCTION (ikev2_init) = { - .runs_after = VLIB_INITS ("ipsec_init", "ipsec_punt_init", "dns_init"), + .runs_after = VLIB_INITS ("ipsec_init", "ipsec_punt_init"), }; -/* *INDENT-ON* */ static u8 ikev2_mngr_process_child_sa (ikev2_sa_t * sa, ikev2_child_sa_t * csa, @@ -4875,14 +5202,12 @@ ikev2_mngr_process_child_sa (ikev2_sa_t * sa, ikev2_child_sa_t * csa, ip_addr_bytes (&sa->iaddr)); } - /* *INDENT-OFF* */ ipip_tunnel_key_t key = { .src = local_ip, .dst = remote_ip, .transport = IPIP_TRANSPORT_IP4, .fib_index = 0, }; - /* *INDENT-ON* */ ipip = ipip_tunnel_db_find (&key); @@ -4963,7 +5288,6 @@ ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa) ikev2_sa_t *sa; if (fchild) break; - /* *INDENT-OFF* */ pool_foreach (sa, tkm->sas) { fchild = ikev2_sa_get_child(sa, ipsec_sa->spi, IKEV2_PROTOCOL_ESP, 1); if (fchild) @@ -4972,7 +5296,6 @@ ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa) break; } } - /* *INDENT-ON* */ } vlib_get_combined_counter (&ipsec_sa_counters, ipsec_sa->stat_index, &counts); @@ -5070,7 +5393,6 @@ ikev2_process_pending_sa_init (vlib_main_t *vm, ikev2_main_t *km) u64 ispi; ikev2_sa_t *sa; - /* *INDENT-OFF* */ hash_foreach (ispi, sai, km->sa_by_ispi, ({ sa = pool_elt_at_index (km->sais, sai); @@ -5079,7 +5401,6 @@ ikev2_process_pending_sa_init (vlib_main_t *vm, ikev2_main_t *km) ikev2_process_pending_sa_init_one (vm, km, sa); })); - /* *INDENT-ON* */ } static void @@ -5137,8 +5458,8 @@ ikev2_disable_dpd (void) km->dpd_disabled = 1; } -static_always_inline int -ikev2_mngr_process_responder_sas (ikev2_sa_t * sa) +static int +ikev2_mngr_process_responder_sas (ikev2_sa_t *sa) { ikev2_main_t *km = &ikev2_main; vlib_main_t *vm = km->vlib_main; @@ -5169,6 +5490,9 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, ikev2_child_sa_t *c; u32 *sai; + /* lazy init will wake it up */ + vlib_process_wait_for_event (vm); + while (1) { vlib_process_wait_for_event_or_clock (vm, 2); @@ -5181,34 +5505,38 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, ikev2_sa_t *sa; u32 *to_be_deleted = 0; - /* *INDENT-OFF* */ pool_foreach (sa, tkm->sas) { ikev2_child_sa_t *c; u8 del_old_ids = 0; - if (sa->state != IKEV2_STATE_AUTHENTICATED) - continue; + if (sa->state == IKEV2_STATE_SA_INIT) + { + if (vec_len (sa->childs) > 0) + vec_add1 (to_be_deleted, sa - tkm->sas); + } + else if (sa->state != IKEV2_STATE_AUTHENTICATED) + continue; - if (sa->old_remote_id_present && 0 > sa->old_id_expiration) - { - sa->old_remote_id_present = 0; - del_old_ids = 1; - } - else - sa->old_id_expiration -= 1; + if (sa->old_remote_id_present && 0 > sa->old_id_expiration) + { + sa->old_remote_id_present = 0; + del_old_ids = 1; + } + else + sa->old_id_expiration -= 1; - vec_foreach (c, sa->childs) - ikev2_mngr_process_child_sa(sa, c, del_old_ids); + vec_foreach (c, sa->childs) + ikev2_mngr_process_child_sa (sa, c, del_old_ids); - if (!km->dpd_disabled && ikev2_mngr_process_responder_sas (sa)) - vec_add1 (to_be_deleted, sa - tkm->sas); - } - /* *INDENT-ON* */ + if (!km->dpd_disabled && ikev2_mngr_process_responder_sas (sa)) + vec_add1 (to_be_deleted, sa - tkm->sas); + } vec_foreach (sai, to_be_deleted) { sa = pool_elt_at_index (tkm->sas, sai[0]); - u8 reinitiate = (sa->is_initiator && sa->profile_index != ~0); + const u32 profile_index = sa->profile_index; + const int reinitiate = (sa->is_initiator && profile_index != ~0); vec_foreach (c, sa->childs) { ikev2_delete_tunnel_interface (km->vnet_main, sa, c); @@ -5220,7 +5548,7 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, if (reinitiate) { - p = pool_elt_at_index (km->profiles, sa->profile_index); + p = pool_elt_at_index (km->profiles, profile_index); if (p) { clib_error_t *e = ikev2_initiate_sa_init (vm, p->name); @@ -5237,19 +5565,16 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, /* process ipsec sas */ ipsec_sa_t *sa; - /* *INDENT-OFF* */ pool_foreach (sa, ipsec_sa_pool) { ikev2_mngr_process_ipsec_sa (sa); } - /* *INDENT-ON* */ ikev2_process_pending_sa_init (vm, km); } return 0; } -/* *INDENT-OFF* */ VLIB_REGISTER_NODE (ikev2_mngr_process_node, static) = { .function = ikev2_mngr_process_fn, .type = VLIB_NODE_TYPE_PROCESS, @@ -5257,11 +5582,60 @@ VLIB_REGISTER_NODE (ikev2_mngr_process_node, static) = { "ikev2-manager-process", }; +static void +ikev2_lazy_init (ikev2_main_t *km) +{ + vlib_thread_main_t *tm = vlib_get_thread_main (); + int thread_id; + + if (km->lazy_init_done) + return; + + ikev2_crypto_init (km); + + mhash_init_vec_string (&km->profile_index_by_name, sizeof (uword)); + + vec_validate_aligned (km->per_thread_data, tm->n_vlib_mains - 1, + CLIB_CACHE_LINE_BYTES); + for (thread_id = 0; thread_id < tm->n_vlib_mains; thread_id++) + { + ikev2_main_per_thread_data_t *ptd = + vec_elt_at_index (km->per_thread_data, thread_id); + + ptd->sa_by_rspi = hash_create (0, sizeof (uword)); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + ptd->evp_ctx = EVP_CIPHER_CTX_new (); + ptd->hmac_ctx = HMAC_CTX_new (); +#else + EVP_CIPHER_CTX_init (&ptd->_evp_ctx); + ptd->evp_ctx = &ptd->_evp_ctx; + HMAC_CTX_init (&(ptd->_hmac_ctx)); + ptd->hmac_ctx = &ptd->_hmac_ctx; +#endif + } + + km->sa_by_ispi = hash_create (0, sizeof (uword)); + km->sw_if_indices = hash_create (0, 0); + + km->punt_hdl = vlib_punt_client_register ("ikev2"); + + km->dns_resolve_name_ptr = + vlib_get_plugin_symbol ("dns_plugin.so", "dns_resolve_name"); + if (!km->dns_resolve_name_ptr) + ikev2_log_error ("cannot load symbols from dns plugin"); + + /* wake up ikev2 process */ + vlib_process_signal_event (vlib_get_first_main (), + ikev2_mngr_process_node.index, 0, 0); + + km->lazy_init_done = 1; +} + VLIB_PLUGIN_REGISTER () = { .version = VPP_BUILD_VER, .description = "Internet Key Exchange (IKEv2) Protocol", }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/ikev2/ikev2.h b/src/plugins/ikev2/ikev2.h index 308ffe52ba4..9ed0ecc494c 100644 --- a/src/plugins/ikev2/ikev2.h +++ b/src/plugins/ikev2/ikev2.h @@ -32,7 +32,6 @@ typedef u8 v8; -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { u64 ispi; u64 rspi; @@ -42,14 +41,12 @@ typedef CLIB_PACKED (struct { u8 flags; u32 msgid; u32 length; u8 payload[0]; }) ike_header_t; -/* *INDENT-ON* */ #define ike_hdr_is_response(_h) ((_h)->flags & IKEV2_HDR_FLAG_RESPONSE) #define ike_hdr_is_request(_h) (!ike_hdr_is_response(_h)) #define ike_hdr_is_initiator(_h) ((_h)->flags & IKEV2_HDR_FLAG_INITIATOR) #define ike_hdr_is_responder(_h) (!(ike_hdr_is_initiator(_h))) -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { u8 nextpayload; u8 flags; @@ -58,17 +55,13 @@ typedef CLIB_PACKED (struct { u8 reserved[2]; u8 payload[0]; }) ike_ke_payload_header_t; -/* *INDENT-ON* */ -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { u8 nextpayload; u8 flags; u16 length; u8 payload[0]; }) ike_payload_header_t; -/* *INDENT-ON* */ -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { u8 nextpayload; u8 flags; @@ -77,9 +70,7 @@ typedef CLIB_PACKED (struct { u8 reserved[3]; u8 payload[0]; }) ike_auth_payload_header_t; -/* *INDENT-ON* */ -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { u8 nextpayload; u8 flags; @@ -87,7 +78,6 @@ typedef CLIB_PACKED (struct { u8 id_type; u8 reserved[3]; u8 payload[0]; }) ike_id_payload_header_t; -/* *INDENT-ON* */ #define IKE_VERSION_2 0x20 @@ -451,7 +441,6 @@ uword unformat_ikev2_transform_dh_type (unformat_input_t * input, va_list * args); uword unformat_ikev2_transform_esn_type (unformat_input_t * input, va_list * args); -void ikev2_cli_reference (void); clib_error_t *ikev2_set_liveness_params (u32 period, u32 max_retries); diff --git a/src/plugins/ikev2/ikev2_api.c b/src/plugins/ikev2/ikev2_api.c index d104e54579a..c9608aa660b 100644 --- a/src/plugins/ikev2/ikev2_api.c +++ b/src/plugins/ikev2/ikev2_api.c @@ -173,7 +173,7 @@ send_profile (ikev2_profile_t * profile, vl_api_registration_t * reg, rmp->profile.lifetime_jitter = profile->lifetime_jitter; rmp->profile.handover = profile->handover; - vl_api_ikev2_profile_t_endian (&rmp->profile); + vl_api_ikev2_profile_t_endian (&rmp->profile, 1 /* to network */); vl_api_send_msg (reg, (u8 *) rmp); } @@ -188,12 +188,10 @@ vl_api_ikev2_profile_dump_t_handler (vl_api_ikev2_profile_dump_t * mp) if (!reg) return; - /* *INDENT-OFF* */ pool_foreach (profile, im->profiles) { send_profile (profile, reg, mp->context); } - /* *INDENT-ON* */ } static void @@ -207,6 +205,32 @@ ikev2_copy_stats (vl_api_ikev2_sa_stats_t *dst, const ikev2_stats_t *src) dst->n_sa_auth_req = src->n_sa_auth_req; } +static vl_api_ikev2_state_t +ikev2_state_encode (ikev2_state_t state) +{ + switch (state) + { + case IKEV2_STATE_UNKNOWN: + return UNKNOWN; + case IKEV2_STATE_SA_INIT: + return SA_INIT; + case IKEV2_STATE_DELETED: + return DELETED; + case IKEV2_STATE_AUTH_FAILED: + return AUTH_FAILED; + case IKEV2_STATE_AUTHENTICATED: + return AUTHENTICATED; + case IKEV2_STATE_NOTIFY_AND_DELETE: + return NOTIFY_AND_DELETE; + case IKEV2_STATE_TS_UNACCEPTABLE: + return TS_UNACCEPTABLE; + case IKEV2_STATE_NO_PROPOSAL_CHOSEN: + return NO_PROPOSAL_CHOSEN; + } + + return UNKNOWN; +} + static void send_sa (ikev2_sa_t * sa, vl_api_ikev2_sa_dump_t * mp, u32 api_sa_index) { @@ -214,7 +238,6 @@ send_sa (ikev2_sa_t * sa, vl_api_ikev2_sa_dump_t * mp, u32 api_sa_index) int rv = 0; ikev2_sa_transform_t *tr; - /* *INDENT-OFF* */ REPLY_MACRO2_ZERO (VL_API_IKEV2_SA_DETAILS, { vl_api_ikev2_sa_t *rsa = &rmp->sa; @@ -268,9 +291,8 @@ send_sa (ikev2_sa_t * sa, vl_api_ikev2_sa_dump_t * mp, u32 api_sa_index) ikev2_copy_stats (&rsa->stats, &sa->stats); - vl_api_ikev2_sa_t_endian(rsa); + vl_api_ikev2_sa_t_endian (rsa, 1 /* to network */); }); - /* *INDENT-ON* */ } static void @@ -282,17 +304,199 @@ vl_api_ikev2_sa_dump_t_handler (vl_api_ikev2_sa_dump_t * mp) vec_foreach (tkm, km->per_thread_data) { - /* *INDENT-OFF* */ pool_foreach (sa, tkm->sas) { u32 api_sa_index = ikev2_encode_sa_index (sa - tkm->sas, tkm - km->per_thread_data); send_sa (sa, mp, api_sa_index); } - /* *INDENT-ON* */ } } +static void +send_sa_v2 (ikev2_sa_t *sa, vl_api_ikev2_sa_v2_dump_t *mp, u32 api_sa_index) +{ + ikev2_main_t *km = &ikev2_main; + vl_api_ikev2_sa_v2_details_t *rmp = 0; + int rv = 0; + ikev2_sa_transform_t *tr; + ikev2_profile_t *p; + p = pool_elt_at_index (km->profiles, sa->profile_index); + + REPLY_MACRO2_ZERO (VL_API_IKEV2_SA_V2_DETAILS, { + vl_api_ikev2_sa_v2_t *rsa = &rmp->sa; + vl_api_ikev2_keys_t *k = &rsa->keys; + + int size_data = sizeof (rsa->profile_name) - 1; + if (vec_len (p->name) < size_data) + size_data = vec_len (p->name); + clib_memcpy (rsa->profile_name, p->name, size_data); + + rsa->state = ikev2_state_encode (sa->state); + + rsa->sa_index = api_sa_index; + ip_address_encode2 (&sa->iaddr, &rsa->iaddr); + ip_address_encode2 (&sa->raddr, &rsa->raddr); + rsa->ispi = sa->ispi; + rsa->rspi = sa->rspi; + cp_id (&rsa->i_id, &sa->i_id); + cp_id (&rsa->r_id, &sa->r_id); + + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); + if (tr) + cp_sa_transform (&rsa->encryption, tr); + + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF); + if (tr) + cp_sa_transform (&rsa->prf, tr); + + tr = + ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG); + if (tr) + cp_sa_transform (&rsa->integrity, tr); + + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_DH); + if (tr) + cp_sa_transform (&rsa->dh, tr); + + k->sk_d_len = vec_len (sa->sk_d); + clib_memcpy (&k->sk_d, sa->sk_d, k->sk_d_len); + + k->sk_ai_len = vec_len (sa->sk_ai); + clib_memcpy (&k->sk_ai, sa->sk_ai, k->sk_ai_len); + + k->sk_ar_len = vec_len (sa->sk_ar); + clib_memcpy (&k->sk_ar, sa->sk_ar, k->sk_ar_len); + + k->sk_ei_len = vec_len (sa->sk_ei); + clib_memcpy (&k->sk_ei, sa->sk_ei, k->sk_ei_len); + + k->sk_er_len = vec_len (sa->sk_er); + clib_memcpy (&k->sk_er, sa->sk_er, k->sk_er_len); + + k->sk_pi_len = vec_len (sa->sk_pi); + clib_memcpy (&k->sk_pi, sa->sk_pi, k->sk_pi_len); + + k->sk_pr_len = vec_len (sa->sk_pr); + clib_memcpy (&k->sk_pr, sa->sk_pr, k->sk_pr_len); + + ikev2_copy_stats (&rsa->stats, &sa->stats); + + vl_api_ikev2_sa_v2_t_endian (rsa, 1 /* to network */); + }); +} + +static void +vl_api_ikev2_sa_v2_dump_t_handler (vl_api_ikev2_sa_v2_dump_t *mp) +{ + ikev2_main_t *km = &ikev2_main; + ikev2_main_per_thread_data_t *tkm; + ikev2_sa_t *sa; + + vec_foreach (tkm, km->per_thread_data) + { + pool_foreach (sa, tkm->sas) + { + u32 api_sa_index = + ikev2_encode_sa_index (sa - tkm->sas, tkm - km->per_thread_data); + send_sa_v2 (sa, mp, api_sa_index); + } + } +} + +static void +send_sa_v3 (ikev2_sa_t *sa, vl_api_ikev2_sa_v3_dump_t *mp, u32 api_sa_index) +{ + ikev2_main_t *km = &ikev2_main; + vl_api_ikev2_sa_v3_details_t *rmp = 0; + int rv = 0; + ikev2_sa_transform_t *tr; + ikev2_profile_t *p; + p = pool_elt_at_index (km->profiles, sa->profile_index); + vlib_main_t *vm = vlib_get_main (); + + REPLY_MACRO2_ZERO (VL_API_IKEV2_SA_V3_DETAILS, { + vl_api_ikev2_sa_v3_t *rsa = &rmp->sa; + vl_api_ikev2_keys_t *k = &rsa->keys; + + int size_data = sizeof (rsa->profile_name) - 1; + if (vec_len (p->name) < size_data) + size_data = vec_len (p->name); + clib_memcpy (rsa->profile_name, p->name, size_data); + + rsa->state = ikev2_state_encode (sa->state); + + rsa->uptime = vlib_time_now (vm) - sa->auth_timestamp; + + rsa->sa_index = api_sa_index; + ip_address_encode2 (&sa->iaddr, &rsa->iaddr); + ip_address_encode2 (&sa->raddr, &rsa->raddr); + rsa->ispi = sa->ispi; + rsa->rspi = sa->rspi; + cp_id (&rsa->i_id, &sa->i_id); + cp_id (&rsa->r_id, &sa->r_id); + + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); + if (tr) + cp_sa_transform (&rsa->encryption, tr); + + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_PRF); + if (tr) + cp_sa_transform (&rsa->prf, tr); + + tr = + ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_INTEG); + if (tr) + cp_sa_transform (&rsa->integrity, tr); + + tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_DH); + if (tr) + cp_sa_transform (&rsa->dh, tr); + + k->sk_d_len = vec_len (sa->sk_d); + clib_memcpy (&k->sk_d, sa->sk_d, k->sk_d_len); + + k->sk_ai_len = vec_len (sa->sk_ai); + clib_memcpy (&k->sk_ai, sa->sk_ai, k->sk_ai_len); + + k->sk_ar_len = vec_len (sa->sk_ar); + clib_memcpy (&k->sk_ar, sa->sk_ar, k->sk_ar_len); + + k->sk_ei_len = vec_len (sa->sk_ei); + clib_memcpy (&k->sk_ei, sa->sk_ei, k->sk_ei_len); + + k->sk_er_len = vec_len (sa->sk_er); + clib_memcpy (&k->sk_er, sa->sk_er, k->sk_er_len); + + k->sk_pi_len = vec_len (sa->sk_pi); + clib_memcpy (&k->sk_pi, sa->sk_pi, k->sk_pi_len); + + k->sk_pr_len = vec_len (sa->sk_pr); + clib_memcpy (&k->sk_pr, sa->sk_pr, k->sk_pr_len); + + ikev2_copy_stats (&rsa->stats, &sa->stats); + + vl_api_ikev2_sa_v3_t_endian (rsa, 1 /* to network */); + }); +} + +static void +vl_api_ikev2_sa_v3_dump_t_handler (vl_api_ikev2_sa_v3_dump_t *mp) +{ + ikev2_main_t *km = &ikev2_main; + ikev2_main_per_thread_data_t *tkm; + ikev2_sa_t *sa; + + vec_foreach (tkm, km->per_thread_data) + { + pool_foreach (sa, tkm->sas) + { + u32 api_sa_index = + ikev2_encode_sa_index (sa - tkm->sas, tkm - km->per_thread_data); + send_sa_v3 (sa, mp, api_sa_index); + } + } +} static void send_child_sa (ikev2_child_sa_t * child, @@ -303,7 +507,6 @@ send_child_sa (ikev2_child_sa_t * child, int rv = 0; ikev2_sa_transform_t *tr; - /* *INDENT-OFF* */ REPLY_MACRO2_ZERO (VL_API_IKEV2_CHILD_SA_DETAILS, { vl_api_ikev2_keys_t *k = &rmp->child_sa.keys; @@ -346,9 +549,8 @@ send_child_sa (ikev2_child_sa_t * child, k->sk_ar_len); } - vl_api_ikev2_child_sa_t_endian (&rmp->child_sa); + vl_api_ikev2_child_sa_t_endian (&rmp->child_sa, 1 /* to network */); }); - /* *INDENT-ON* */ } static void @@ -380,6 +582,85 @@ vl_api_ikev2_child_sa_dump_t_handler (vl_api_ikev2_child_sa_dump_t * mp) } static void +send_child_sa_v2 (ikev2_child_sa_t *child, vl_api_ikev2_child_sa_v2_dump_t *mp, + u32 child_sa_index, u32 sa_index) +{ + vl_api_ikev2_child_sa_v2_details_t *rmp = 0; + int rv = 0; + ikev2_sa_transform_t *tr; + vlib_main_t *vm = vlib_get_main (); + + REPLY_MACRO2_ZERO (VL_API_IKEV2_CHILD_SA_V2_DETAILS, { + vl_api_ikev2_keys_t *k = &rmp->child_sa.keys; + rmp->child_sa.child_sa_index = child_sa_index; + rmp->child_sa.uptime = vlib_time_now (vm) - child->timestamp; + rmp->child_sa.sa_index = sa_index; + rmp->child_sa.i_spi = child->i_proposals ? child->i_proposals[0].spi : 0; + rmp->child_sa.r_spi = child->r_proposals ? child->r_proposals[0].spi : 0; + + tr = + ikev2_sa_get_td_for_type (child->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); + if (tr) + cp_sa_transform (&rmp->child_sa.encryption, tr); + + tr = ikev2_sa_get_td_for_type (child->r_proposals, + IKEV2_TRANSFORM_TYPE_INTEG); + if (tr) + cp_sa_transform (&rmp->child_sa.integrity, tr); + + tr = + ikev2_sa_get_td_for_type (child->r_proposals, IKEV2_TRANSFORM_TYPE_ESN); + if (tr) + cp_sa_transform (&rmp->child_sa.esn, tr); + + k->sk_ei_len = vec_len (child->sk_ei); + clib_memcpy (&k->sk_ei, child->sk_ei, k->sk_ei_len); + + k->sk_er_len = vec_len (child->sk_er); + clib_memcpy (&k->sk_er, child->sk_er, k->sk_er_len); + + if (vec_len (child->sk_ai)) + { + k->sk_ai_len = vec_len (child->sk_ai); + clib_memcpy (&k->sk_ai, child->sk_ai, k->sk_ai_len); + + k->sk_ar_len = vec_len (child->sk_ar); + clib_memcpy (&k->sk_ar, child->sk_ar, k->sk_ar_len); + } + + vl_api_ikev2_child_sa_v2_t_endian (&rmp->child_sa, 1 /* to network */); + }); +} + +static void +vl_api_ikev2_child_sa_v2_dump_t_handler (vl_api_ikev2_child_sa_v2_dump_t *mp) +{ + ikev2_main_t *im = &ikev2_main; + ikev2_main_per_thread_data_t *tkm; + ikev2_sa_t *sa; + ikev2_child_sa_t *child; + u32 sai = ~0, ti = ~0; + + ikev2_decode_sa_index (clib_net_to_host_u32 (mp->sa_index), &sai, &ti); + + if (vec_len (im->per_thread_data) <= ti) + return; + + tkm = vec_elt_at_index (im->per_thread_data, ti); + + if (pool_len (tkm->sas) <= sai || pool_is_free_index (tkm->sas, sai)) + return; + + sa = pool_elt_at_index (tkm->sas, sai); + + vec_foreach (child, sa->childs) + { + u32 child_sa_index = child - sa->childs; + send_child_sa_v2 (child, mp, child_sa_index, sai); + } +} + +static void vl_api_ikev2_traffic_selector_dump_t_handler (vl_api_ikev2_traffic_selector_dump_t * mp) { @@ -414,15 +695,13 @@ static void vl_api_ikev2_traffic_selector_details_t *rmp = 0; int rv = 0; - /* *INDENT-OFF* */ REPLY_MACRO2_ZERO (VL_API_IKEV2_TRAFFIC_SELECTOR_DETAILS, { rmp->ts.sa_index = api_sa_index; rmp->ts.child_sa_index = child_sa_index; cp_ts (&rmp->ts, ts, mp->is_initiator); - vl_api_ikev2_ts_t_endian (&rmp->ts); + vl_api_ikev2_ts_t_endian (&rmp->ts, 1 /* to network */); }); - /* *INDENT-ON* */ } } @@ -451,13 +730,11 @@ vl_api_ikev2_nonce_get_t_handler (vl_api_ikev2_nonce_get_t * mp) int data_len = vec_len (nonce); int rv = 0; - /* *INDENT-OFF* */ REPLY_MACRO3_ZERO (VL_API_IKEV2_NONCE_GET_REPLY, data_len, { rmp->data_len = clib_host_to_net_u32 (data_len); clib_memcpy (rmp->nonce, nonce, data_len); }); - /* *INDENT-ON* */ } static void @@ -490,8 +767,6 @@ static void { vl_api_ikev2_profile_set_liveness_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 clib_error_t *error; error = ikev2_set_liveness_params (clib_net_to_host_u32 (mp->period), clib_net_to_host_u32 (mp->max_retries)); @@ -501,10 +776,6 @@ static void clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_PROFILE_SET_LIVENESS_REPLY); } @@ -513,8 +784,6 @@ 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; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; u8 *tmp = format (0, "%s", mp->name); @@ -526,10 +795,6 @@ vl_api_ikev2_profile_add_del_t_handler (vl_api_ikev2_profile_add_del_t * mp) clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_PROFILE_ADD_DEL_REPLY); } @@ -539,8 +804,6 @@ static void { vl_api_ikev2_profile_set_auth_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; int data_len = ntohl (mp->data_len); @@ -562,10 +825,6 @@ static void } else rv = VNET_API_ERROR_INVALID_VALUE; -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_PROFILE_SET_AUTH_REPLY); } @@ -574,8 +833,6 @@ vl_api_ikev2_profile_set_id_t_handler (vl_api_ikev2_profile_set_id_t * mp) { vl_api_ikev2_profile_set_id_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; u8 *tmp = format (0, "%s", mp->name); @@ -596,9 +853,6 @@ vl_api_ikev2_profile_set_id_t_handler (vl_api_ikev2_profile_set_id_t * mp) } else rv = VNET_API_ERROR_INVALID_VALUE; -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif REPLY_MACRO (VL_API_IKEV2_PROFILE_SET_ID_REPLY); } @@ -609,8 +863,6 @@ static void { vl_api_ikev2_profile_set_udp_encap_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; u8 *tmp = format (0, "%s", mp->name); @@ -622,10 +874,6 @@ static void clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_PROFILE_SET_UDP_ENCAP_REPLY); } @@ -634,8 +882,6 @@ vl_api_ikev2_profile_set_ts_t_handler (vl_api_ikev2_profile_set_ts_t * mp) { vl_api_ikev2_profile_set_ts_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; u8 *tmp = format (0, "%s", mp->name); @@ -654,10 +900,6 @@ vl_api_ikev2_profile_set_ts_t_handler (vl_api_ikev2_profile_set_ts_t * mp) clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_PROFILE_SET_TS_REPLY); } @@ -666,8 +908,6 @@ vl_api_ikev2_set_local_key_t_handler (vl_api_ikev2_set_local_key_t * mp) { vl_api_ikev2_set_local_key_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; @@ -678,10 +918,6 @@ vl_api_ikev2_set_local_key_t_handler (vl_api_ikev2_set_local_key_t * mp) clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_SET_LOCAL_KEY_REPLY); } @@ -691,8 +927,6 @@ vl_api_ikev2_set_responder_hostname_t_handler ( { vl_api_ikev2_set_responder_hostname_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; @@ -710,10 +944,6 @@ vl_api_ikev2_set_responder_hostname_t_handler ( clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_SET_RESPONDER_HOSTNAME_REPLY); } @@ -722,8 +952,6 @@ vl_api_ikev2_set_responder_t_handler (vl_api_ikev2_set_responder_t * mp) { vl_api_ikev2_set_responder_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; @@ -740,10 +968,6 @@ vl_api_ikev2_set_responder_t_handler (vl_api_ikev2_set_responder_t * mp) clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_SET_RESPONDER_REPLY); } @@ -753,8 +977,6 @@ vl_api_ikev2_set_ike_transforms_t_handler (vl_api_ikev2_set_ike_transforms_t * { vl_api_ikev2_set_ike_transforms_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; @@ -772,10 +994,6 @@ vl_api_ikev2_set_ike_transforms_t_handler (vl_api_ikev2_set_ike_transforms_t * clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_SET_IKE_TRANSFORMS_REPLY); } @@ -785,8 +1003,6 @@ vl_api_ikev2_set_esp_transforms_t_handler (vl_api_ikev2_set_esp_transforms_t * { vl_api_ikev2_set_esp_transforms_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; @@ -803,10 +1019,6 @@ vl_api_ikev2_set_esp_transforms_t_handler (vl_api_ikev2_set_esp_transforms_t * clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_SET_ESP_TRANSFORMS_REPLY); } @@ -815,8 +1027,6 @@ vl_api_ikev2_set_sa_lifetime_t_handler (vl_api_ikev2_set_sa_lifetime_t * mp) { vl_api_ikev2_set_sa_lifetime_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; @@ -836,10 +1046,6 @@ vl_api_ikev2_set_sa_lifetime_t_handler (vl_api_ikev2_set_sa_lifetime_t * mp) clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_SET_SA_LIFETIME_REPLY); } @@ -849,8 +1055,6 @@ static void { 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); @@ -860,10 +1064,6 @@ static void 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); } @@ -876,7 +1076,6 @@ static void VALIDATE_SW_IF_INDEX (mp); -#if WITH_LIBSSL > 0 u8 *tmp = format (0, "%s", mp->name); clib_error_t *error; @@ -890,10 +1089,6 @@ static void rv = VNET_API_ERROR_UNSPECIFIED; } vec_free (tmp); -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - BAD_SW_IF_INDEX_LABEL; REPLY_MACRO (VL_API_IKEV2_SET_TUNNEL_INTERFACE_REPLY); } @@ -903,8 +1098,6 @@ vl_api_ikev2_initiate_sa_init_t_handler (vl_api_ikev2_initiate_sa_init_t * mp) { vl_api_ikev2_initiate_sa_init_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; @@ -918,10 +1111,6 @@ vl_api_ikev2_initiate_sa_init_t_handler (vl_api_ikev2_initiate_sa_init_t * mp) clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_INITIATE_SA_INIT_REPLY); } @@ -931,8 +1120,6 @@ vl_api_ikev2_initiate_del_ike_sa_t_handler (vl_api_ikev2_initiate_del_ike_sa_t { vl_api_ikev2_initiate_del_ike_sa_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; @@ -943,10 +1130,6 @@ vl_api_ikev2_initiate_del_ike_sa_t_handler (vl_api_ikev2_initiate_del_ike_sa_t clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_INITIATE_DEL_IKE_SA_REPLY); } @@ -956,8 +1139,6 @@ static void { vl_api_ikev2_initiate_del_child_sa_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; @@ -968,10 +1149,6 @@ static void clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_INITIATE_DEL_CHILD_SA_REPLY); } @@ -981,8 +1158,6 @@ static void { vl_api_ikev2_profile_disable_natt_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 clib_error_t *error; u8 *tmp = format (0, "%s", mp->name); @@ -994,10 +1169,6 @@ static void clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_PROFILE_DISABLE_NATT_REPLY); } @@ -1007,8 +1178,6 @@ static void { vl_api_ikev2_initiate_rekey_child_sa_reply_t *rmp; int rv = 0; - -#if WITH_LIBSSL > 0 vlib_main_t *vm = vlib_get_main (); clib_error_t *error; @@ -1019,10 +1188,6 @@ static void clib_error_free (error); rv = VNET_API_ERROR_UNSPECIFIED; } -#else - rv = VNET_API_ERROR_UNIMPLEMENTED; -#endif - REPLY_MACRO (VL_API_IKEV2_INITIATE_REKEY_CHILD_SA_REPLY); } diff --git a/src/plugins/ikev2/ikev2_cli.c b/src/plugins/ikev2/ikev2_cli.c index 3523ce079b6..975774c48d5 100644 --- a/src/plugins/ikev2/ikev2_cli.c +++ b/src/plugins/ikev2/ikev2_cli.c @@ -74,12 +74,16 @@ format_ikev2_child_sa (u8 * s, va_list * va) ikev2_ts_t *ts; ikev2_sa_transform_t *tr; u8 *c = 0; + vlib_main_t *vm = vlib_get_main (); u32 indent = format_get_indent (s); indent += 1; s = format (s, "child sa %u:", index); + s = format (s, "\n uptime: %f (s)\n ", + vlib_time_now (vm) - child->timestamp); + tr = ikev2_sa_get_td_for_type (child->r_proposals, IKEV2_TRANSFORM_TYPE_ENCR); c = format (c, "%U ", format_ikev2_sa_transform, tr); @@ -121,6 +125,12 @@ format_ikev2_child_sa (u8 * s, va_list * va) return s; } +static char *stateNames[] = { +#define _(v, f, s) s, + foreach_ikev2_state +#undef _ +}; + static u8 * format_ikev2_sa (u8 * s, va_list * va) { @@ -129,6 +139,12 @@ format_ikev2_sa (u8 * s, va_list * va) ikev2_sa_transform_t *tr; ikev2_child_sa_t *child; u32 indent = 1; + vlib_main_t *vm = vlib_get_main (); + + ikev2_main_t *km = &ikev2_main; + ikev2_profile_t *p; + + p = pool_elt_at_index (km->profiles, sa->profile_index); s = format (s, "iip %U ispi %lx rip %U rspi %lx", format_ip_address, &sa->iaddr, sa->ispi, @@ -150,6 +166,16 @@ format_ikev2_sa (u8 * s, va_list * va) tr = ikev2_sa_get_td_for_type (sa->r_proposals, IKEV2_TRANSFORM_TYPE_DH); s = format (s, "%U", format_ikev2_sa_transform, tr); + s = format (s, "\n profile: %v", p->name); + + if (sa->state <= IKEV2_STATE_NO_PROPOSAL_CHOSEN) + { + s = format (s, "\n state: %s", stateNames[sa->state]); + } + + s = + format (s, "\n uptime: %f (s)\n", vlib_time_now (vm) - sa->auth_timestamp); + s = format (s, "\n%U", format_white_space, indent); s = format (s, "nonce i:%U\n%Ur:%U\n", @@ -232,7 +258,6 @@ show_ikev2_sa_command_fn (vlib_main_t * vm, vec_foreach (tkm, km->per_thread_data) { - /* *INDENT-OFF* */ pool_foreach (sa, tkm->sas) { if (show_one) { @@ -245,7 +270,6 @@ show_ikev2_sa_command_fn (vlib_main_t * vm, else s = format (s, "%U\n", format_ikev2_sa, sa, details); } - /* *INDENT-ON* */ } vlib_cli_output (vm, "%v", s); @@ -253,13 +277,11 @@ show_ikev2_sa_command_fn (vlib_main_t * vm, return 0; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_ikev2_sa_command, static) = { .path = "show ikev2 sa", .short_help = "show ikev2 sa [rspi <rspi>] [details]", .function = show_ikev2_sa_command_fn, }; -/* *INDENT-ON* */ static clib_error_t * ikev2_disable_dpd_command_fn (vlib_main_t * vm, @@ -270,13 +292,11 @@ ikev2_disable_dpd_command_fn (vlib_main_t * vm, return 0; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (ikev2_cli_disable_dpd_command, static) = { .path = "ikev2 dpd disable", .short_help = "ikev2 dpd disable", .function = ikev2_disable_dpd_command_fn, }; -/* *INDENT-ON* */ static uword unformat_ikev2_token (unformat_input_t * input, va_list * va) @@ -553,7 +573,6 @@ done: return r; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (ikev2_profile_add_del_command, static) = { .path = "ikev2 profile", .short_help = @@ -574,7 +593,6 @@ VLIB_CLI_COMMAND (ikev2_profile_add_del_command, static) = { "ikev2 profile set <id> disable natt\n", .function = ikev2_profile_add_del_command_fn, }; -/* *INDENT-ON* */ static clib_error_t * show_ikev2_profile_command_fn (vlib_main_t * vm, @@ -584,7 +602,6 @@ show_ikev2_profile_command_fn (vlib_main_t * vm, ikev2_main_t *km = &ikev2_main; ikev2_profile_t *p; - /* *INDENT-OFF* */ pool_foreach (p, km->profiles) { vlib_cli_output(vm, "profile %v", p->name); @@ -651,18 +668,15 @@ show_ikev2_profile_command_fn (vlib_main_t * vm, vlib_cli_output(vm, " lifetime %d jitter %d handover %d maxdata %d", p->lifetime, p->lifetime_jitter, p->handover, p->lifetime_maxdata); } - /* *INDENT-ON* */ return 0; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_ikev2_profile_command, static) = { .path = "show ikev2 profile", .short_help = "show ikev2 profile", .function = show_ikev2_profile_command_fn, }; -/* *INDENT-ON* */ static clib_error_t * set_ikev2_liveness_period_fn (vlib_main_t * vm, @@ -695,13 +709,11 @@ done: return r; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (set_ikev2_liveness_command, static) = { .path = "ikev2 set liveness", .short_help = "ikev2 set liveness <period> <max-retires>", .function = set_ikev2_liveness_period_fn, }; -/* *INDENT-ON* */ static clib_error_t * set_ikev2_local_key_command_fn (vlib_main_t * vm, @@ -735,14 +747,12 @@ done: return r; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (set_ikev2_local_key_command, static) = { .path = "set ikev2 local key", .short_help = "set ikev2 local key <file>", .function = set_ikev2_local_key_command_fn, }; -/* *INDENT-ON* */ static clib_error_t * @@ -793,7 +803,6 @@ done: return r; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (ikev2_initiate_command, static) = { .path = "ikev2 initiate", .short_help = @@ -803,12 +812,6 @@ VLIB_CLI_COMMAND (ikev2_initiate_command, static) = { "ikev2 initiate rekey-child-sa <child sa ispi>\n", .function = ikev2_initiate_command_fn, }; -/* *INDENT-ON* */ - -void -ikev2_cli_reference (void) -{ -} static clib_error_t * ikev2_set_log_level_command_fn (vlib_main_t * vm, @@ -838,13 +841,11 @@ done: return error; } -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (ikev2_set_log_level_command, static) = { .path = "ikev2 set logging level", .function = ikev2_set_log_level_command_fn, .short_help = "ikev2 set logging level <0-5>", }; -/* *INDENT-ON* */ /* * fd.io coding-style-patch-verification: ON diff --git a/src/plugins/ikev2/ikev2_crypto.c b/src/plugins/ikev2/ikev2_crypto.c index a9ab1bc8067..3d4ad0a28ed 100644 --- a/src/plugins/ikev2/ikev2_crypto.c +++ b/src/plugins/ikev2/ikev2_crypto.c @@ -488,7 +488,7 @@ BN_bn2binpad (const BIGNUM * a, unsigned char *to, int tolen) { vec_insert (to, pad, 0); clib_memset (to, 0, pad); - _vec_len (to) -= pad; + vec_dec_len (to, pad); } return tolen; } @@ -553,7 +553,7 @@ ikev2_generate_dh (ikev2_sa_t * sa, ikev2_sa_transform_t * t) { vec_insert (sa->dh_shared_key, pad, 0); clib_memset (sa->dh_shared_key, 0, pad); - _vec_len (sa->dh_shared_key) -= pad; + vec_dec_len (sa->dh_shared_key, pad); } BN_clear_free (ex); } @@ -679,7 +679,7 @@ ikev2_complete_dh (ikev2_sa_t * sa, ikev2_sa_transform_t * t) { vec_insert (sa->dh_shared_key, pad, 0); clib_memset (sa->dh_shared_key, 0, pad); - _vec_len (sa->dh_shared_key) -= pad; + vec_dec_len (sa->dh_shared_key, pad); } BN_clear_free (ex); DH_free (dh); diff --git a/src/plugins/ikev2/ikev2_payload.c b/src/plugins/ikev2/ikev2_payload.c index 294864d8c43..5801a1b3e87 100644 --- a/src/plugins/ikev2/ikev2_payload.c +++ b/src/plugins/ikev2/ikev2_payload.c @@ -24,7 +24,6 @@ #include <plugins/ikev2/ikev2.h> #include <plugins/ikev2/ikev2_priv.h> -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { u8 nextpayload; u8 flags; @@ -34,9 +33,7 @@ typedef CLIB_PACKED (struct { u16 msg_type; u8 payload[0]; }) ike_notify_payload_header_t; -/* *INDENT-ON* */ -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { ip4_address_t start_addr; ip4_address_t end_addr; @@ -55,9 +52,7 @@ typedef CLIB_PACKED (struct { u16 end_port; u8 addr_pair[0]; }) ikev2_ts_payload_entry_t; -/* *INDENT-OFF* */ -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { u8 nextpayload; u8 flags; @@ -66,9 +61,7 @@ typedef CLIB_PACKED (struct { u8 reserved[3]; ikev2_ts_payload_entry_t ts[0]; }) ike_ts_payload_header_t; -/* *INDENT-OFF* */ -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { u8 last_or_more; u8 reserved; @@ -78,9 +71,7 @@ typedef CLIB_PACKED (struct { u8 spi_size; u8 num_transforms; u32 spi[0]; }) ike_sa_proposal_data_t; -/* *INDENT-OFF* */ -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { u8 last_or_more; u8 reserved; @@ -90,9 +81,7 @@ typedef CLIB_PACKED (struct { u16 transform_id; u8 attributes[0]; }) ike_sa_transform_data_t; -/* *INDENT-OFF* */ -/* *INDENT-OFF* */ typedef CLIB_PACKED (struct { u8 nextpayload; u8 flags; @@ -102,7 +91,6 @@ typedef CLIB_PACKED (struct { u16 num_of_spi; u32 spi[0]; }) ike_delete_payload_header_t; -/* *INDENT-OFF* */ static ike_payload_header_t * ikev2_payload_add_hdr (ikev2_payload_chain_t * c, u8 payload_type, int len) @@ -167,8 +155,8 @@ ikev2_payload_add_notify_2 (ikev2_payload_chain_t * c, u16 msg_type, } void -ikev2_payload_add_sa (ikev2_payload_chain_t * c, - ikev2_sa_proposal_t * proposals) +ikev2_payload_add_sa (ikev2_payload_chain_t *c, ikev2_sa_proposal_t *proposals, + u8 force_spi) { ike_payload_header_t *ph; ike_sa_proposal_data_t *prop; @@ -184,7 +172,13 @@ ikev2_payload_add_sa (ikev2_payload_chain_t * c, vec_foreach (p, proposals) { - int spi_size = (p->protocol_id == IKEV2_PROTOCOL_ESP) ? 4 : 0; + int spi_size = 0; + + if (p->protocol_id == IKEV2_PROTOCOL_ESP) + spi_size = 4; + else if (force_spi && p->protocol_id == IKEV2_PROTOCOL_IKE) + spi_size = 8; + pr_data = vec_new (u8, sizeof (ike_sa_proposal_data_t) + spi_size); prop = (ike_sa_proposal_data_t *) pr_data; prop->last_or_more = proposals - p + 1 < vec_len (proposals) ? 2 : 0; @@ -193,8 +187,13 @@ ikev2_payload_add_sa (ikev2_payload_chain_t * c, prop->spi_size = spi_size; prop->num_transforms = vec_len (p->transforms); - if (spi_size) + if (spi_size == 4) prop->spi[0] = clib_host_to_net_u32 (p->spi); + else if (spi_size == 8) + { + u64 s = clib_host_to_net_u64 (p->spi); + clib_memcpy_fast (prop->spi, &s, sizeof (s)); + } vec_foreach (t, p->transforms) { @@ -384,8 +383,9 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep, u32 rlen) sap = (ike_sa_proposal_data_t *) & ikep->payload[proposal_ptr]; int i, transform_ptr; - /* IKE proposal should not have SPI */ - if (sap->protocol_id == IKEV2_PROTOCOL_IKE && sap->spi_size != 0) + /* IKE proposal should have 8 bytes or no SPI */ + if (sap->protocol_id == IKEV2_PROTOCOL_IKE && sap->spi_size != 0 && + sap->spi_size != 8) goto data_corrupted; /* IKE proposal should not have SPI */ @@ -404,6 +404,12 @@ ikev2_parse_sa_payload (ike_payload_header_t * ikep, u32 rlen) { proposal->spi = clib_net_to_host_u32 (sap->spi[0]); } + else if (sap->spi_size == 8) + { + u64 s; + clib_memcpy_fast (&s, &sap->spi[0], sizeof (s)); + proposal->spi = clib_net_to_host_u64 (s); + } for (i = 0; i < sap->num_transforms; i++) { diff --git a/src/plugins/ikev2/ikev2_priv.h b/src/plugins/ikev2/ikev2_priv.h index 4c56b980f1c..0639809e9b1 100644 --- a/src/plugins/ikev2/ikev2_priv.h +++ b/src/plugins/ikev2/ikev2_priv.h @@ -184,16 +184,21 @@ do { \ #define ikev2_log_debug(...) \ vlib_log(VLIB_LOG_LEVEL_DEBUG, ikev2_main.log_class, __VA_ARGS__) +#define foreach_ikev2_state \ + _ (0, UNKNOWN, "UNKNOWN") \ + _ (1, SA_INIT, "SA_INIT") \ + _ (2, DELETED, "DELETED") \ + _ (3, AUTH_FAILED, "AUTH_FAILED") \ + _ (4, AUTHENTICATED, "AUTHENTICATED") \ + _ (5, NOTIFY_AND_DELETE, "NOTIFY_AND_DELETE") \ + _ (6, TS_UNACCEPTABLE, "TS_UNACCEPTABLE") \ + _ (7, NO_PROPOSAL_CHOSEN, "NO_PROPOSAL_CHOSEN") + typedef enum { - IKEV2_STATE_UNKNOWN, - IKEV2_STATE_SA_INIT, - IKEV2_STATE_DELETED, - IKEV2_STATE_AUTH_FAILED, - IKEV2_STATE_AUTHENTICATED, - IKEV2_STATE_NOTIFY_AND_DELETE, - IKEV2_STATE_TS_UNACCEPTABLE, - IKEV2_STATE_NO_PROPOSAL_CHOSEN, +#define _(v, f, s) IKEV2_STATE_##f = v, + foreach_ikev2_state +#undef _ } ikev2_state_t; typedef struct @@ -238,7 +243,7 @@ typedef struct { u8 proposal_num; ikev2_protocol_id_t protocol_id:8; - u32 spi; + u64 spi; ikev2_sa_transform_t *transforms; } ikev2_sa_proposal_t; @@ -302,6 +307,8 @@ typedef struct f64 time_to_expiration; u8 is_expired; i8 rekey_retries; + + f64 timestamp; } ikev2_child_sa_t; typedef struct @@ -312,6 +319,8 @@ typedef struct typedef struct { + u16 notify_type; + u8 kex; u8 protocol_id; u32 spi; u32 ispi; @@ -323,6 +332,22 @@ typedef struct typedef struct { + u16 notify_type; + u16 dh_group; + u64 ispi; + u64 rspi; + u8 *i_nonce; + u8 *r_nonce; + u8 *dh_shared_key; + u8 *dh_private_key; + u8 *i_dh_data; + u8 *r_dh_data; + ikev2_sa_proposal_t *i_proposals; + ikev2_sa_proposal_t *r_proposals; +} ikev2_sa_rekey_t; + +typedef struct +{ u16 msg_type; u8 protocol_id; u32 spi; @@ -425,6 +450,9 @@ typedef struct ikev2_rekey_t *new_child; + /* pending sa rekeyings */ + ikev2_sa_rekey_t *sa_rekey; + /* packet data */ u8 *last_sa_init_req_packet_data; u8 *last_sa_init_res_packet_data; @@ -462,6 +490,8 @@ typedef struct u8 keys_generated; ikev2_stats_t stats; + + f64 auth_timestamp; } ikev2_sa_t; @@ -530,7 +560,17 @@ typedef struct u8 dpd_disabled; /* pointer to name resolver function in dns plugin */ - int (*dns_resolve_name) (); + void *dns_resolve_name_ptr; + + /* flag indicating whether lazy init is done or not */ + int lazy_init_done; + + /* refcount for IKEv2 udp ports and IPsec NATT punt registration */ + int bind_refcount; + + /* punt handle for IPsec NATT IPSEC_PUNT_IP4_SPI_UDP_0 reason */ + vlib_punt_hdl_t punt_hdl; + } ikev2_main_t; extern ikev2_main_t ikev2_main; @@ -584,8 +624,8 @@ void ikev2_payload_add_notify (ikev2_payload_chain_t * c, u16 msg_type, u8 * data); void ikev2_payload_add_notify_2 (ikev2_payload_chain_t * c, u16 msg_type, u8 * data, ikev2_notify_t * notify); -void ikev2_payload_add_sa (ikev2_payload_chain_t * c, - ikev2_sa_proposal_t * proposals); +void ikev2_payload_add_sa (ikev2_payload_chain_t *c, + ikev2_sa_proposal_t *proposals, u8 force_spi); void ikev2_payload_add_ke (ikev2_payload_chain_t * c, u16 dh_group, u8 * dh_data); void ikev2_payload_add_nonce (ikev2_payload_chain_t * c, u8 * nonce); diff --git a/src/plugins/ikev2/ikev2_test.c b/src/plugins/ikev2/ikev2_test.c index b63778ed103..93683a5b5dc 100644 --- a/src/plugins/ikev2/ikev2_test.c +++ b/src/plugins/ikev2/ikev2_test.c @@ -32,7 +32,7 @@ #include <vnet/format_fns.h> #include <ikev2/ikev2.api_enum.h> #include <ikev2/ikev2.api_types.h> -#include <vpp/api/vpe.api_types.h> +#include <vlibmemory/vlib.api_types.h> #define vl_endianfun /* define message structures */ #include <plugins/ikev2/ikev2.api.h> @@ -391,13 +391,83 @@ vl_api_ikev2_sa_details_t_handler (vl_api_ikev2_sa_details_t * mp) ip_address_t iaddr; ip_address_t raddr; vl_api_ikev2_keys_t *k = &sa->keys; - vl_api_ikev2_sa_t_endian (sa); + vl_api_ikev2_sa_t_endian (sa, 0 /* from network */); ip_address_decode2 (&sa->iaddr, &iaddr); ip_address_decode2 (&sa->raddr, &raddr); - fformat (vam->ofp, "profile index %d sa index: %d\n", - mp->sa.profile_index, mp->sa.sa_index); + fformat (vam->ofp, "profile index %u sa index: %d\n", mp->sa.profile_index, + mp->sa.sa_index); + fformat (vam->ofp, " iip %U ispi %lx rip %U rspi %lx\n", format_ip_address, + &iaddr, sa->ispi, format_ip_address, &raddr, sa->rspi); + fformat (vam->ofp, " %U ", format_ikev2_sa_transform, &sa->encryption); + fformat (vam->ofp, "%U ", format_ikev2_sa_transform, &sa->prf); + fformat (vam->ofp, "%U ", format_ikev2_sa_transform, &sa->integrity); + fformat (vam->ofp, "%U \n", format_ikev2_sa_transform, &sa->dh); + + fformat (vam->ofp, " SK_d %U\n", format_hex_bytes, k->sk_d, k->sk_d_len); + + fformat (vam->ofp, " SK_a i:%U\n r:%U\n", format_hex_bytes, + k->sk_ai, k->sk_ai_len, format_hex_bytes, k->sk_ar, k->sk_ar_len); + + fformat (vam->ofp, " SK_e i:%U\n r:%U\n", format_hex_bytes, + k->sk_ei, k->sk_ei_len, format_hex_bytes, k->sk_er, k->sk_er_len); + + fformat (vam->ofp, " SK_p i:%U\n r:%U\n", format_hex_bytes, + k->sk_pi, k->sk_pi_len, format_hex_bytes, k->sk_pr, k->sk_pr_len); + + fformat (vam->ofp, " identifier (i) %U\n", format_ikev2_id_type_and_data, + &sa->i_id); + fformat (vam->ofp, " identifier (r) %U\n", format_ikev2_id_type_and_data, + &sa->r_id); + + vam->result_ready = 1; +} + +static int +api_ikev2_sa_v2_dump (vat_main_t *vam) +{ + ikev2_test_main_t *im = &ikev2_test_main; + vl_api_ikev2_sa_v2_dump_t *mp; + vl_api_control_ping_t *mp_ping; + int ret; + + /* Construct the API message */ + M (IKEV2_SA_V2_DUMP, mp); + + /* send it... */ + S (mp); + + /* Use a control ping for synchronization */ + if (!im->ping_id) + im->ping_id = vl_msg_api_get_msg_index ((u8 *) (VL_API_CONTROL_PING_CRC)); + mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping)); + mp_ping->_vl_msg_id = htons (im->ping_id); + mp_ping->client_index = vam->my_client_index; + vam->result_ready = 0; + + S (mp_ping); + + /* Wait for a reply... */ + W (ret); + return ret; +} + +static void +vl_api_ikev2_sa_v2_details_t_handler (vl_api_ikev2_sa_v2_details_t *mp) +{ + vat_main_t *vam = ikev2_test_main.vat_main; + vl_api_ikev2_sa_v2_t *sa = &mp->sa; + ip_address_t iaddr; + ip_address_t raddr; + vl_api_ikev2_keys_t *k = &sa->keys; + vl_api_ikev2_sa_v2_t_endian (sa, 0 /* from network */); + + ip_address_decode2 (&sa->iaddr, &iaddr); + ip_address_decode2 (&sa->raddr, &raddr); + + fformat (vam->ofp, "profile name %s sa index: %d\n", mp->sa.profile_name, + mp->sa.sa_index); fformat (vam->ofp, " iip %U ispi %lx rip %U rspi %lx\n", format_ip_address, &iaddr, sa->ispi, format_ip_address, &raddr, sa->rspi); fformat (vam->ofp, " %U ", format_ikev2_sa_transform, &sa->encryption); @@ -427,6 +497,76 @@ vl_api_ikev2_sa_details_t_handler (vl_api_ikev2_sa_details_t * mp) } static int +api_ikev2_sa_v3_dump (vat_main_t *vam) +{ + ikev2_test_main_t *im = &ikev2_test_main; + vl_api_ikev2_sa_v3_dump_t *mp; + vl_api_control_ping_t *mp_ping; + int ret; + + /* Construct the API message */ + M (IKEV2_SA_V3_DUMP, mp); + + /* send it... */ + S (mp); + + /* Use a control ping for synchronization */ + if (!im->ping_id) + im->ping_id = vl_msg_api_get_msg_index ((u8 *) (VL_API_CONTROL_PING_CRC)); + mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping)); + mp_ping->_vl_msg_id = htons (im->ping_id); + mp_ping->client_index = vam->my_client_index; + vam->result_ready = 0; + + S (mp_ping); + + /* Wait for a reply... */ + W (ret); + return ret; +} + +static void +vl_api_ikev2_sa_v3_details_t_handler (vl_api_ikev2_sa_v3_details_t *mp) +{ + vat_main_t *vam = ikev2_test_main.vat_main; + vl_api_ikev2_sa_v3_t *sa = &mp->sa; + ip_address_t iaddr; + ip_address_t raddr; + vl_api_ikev2_keys_t *k = &sa->keys; + vl_api_ikev2_sa_v3_t_endian (sa, 0 /* from network */); + + ip_address_decode2 (&sa->iaddr, &iaddr); + ip_address_decode2 (&sa->raddr, &raddr); + + fformat (vam->ofp, "profile name %s sa index: %d\n", mp->sa.profile_name, + mp->sa.sa_index); + fformat (vam->ofp, " iip %U ispi %lx rip %U rspi %lx\n", format_ip_address, + &iaddr, sa->ispi, format_ip_address, &raddr, sa->rspi); + fformat (vam->ofp, " %U ", format_ikev2_sa_transform, &sa->encryption); + fformat (vam->ofp, "%U ", format_ikev2_sa_transform, &sa->prf); + fformat (vam->ofp, "%U ", format_ikev2_sa_transform, &sa->integrity); + fformat (vam->ofp, "%U \n", format_ikev2_sa_transform, &sa->dh); + + fformat (vam->ofp, " SK_d %U\n", format_hex_bytes, k->sk_d, k->sk_d_len); + + fformat (vam->ofp, " SK_a i:%U\n r:%U\n", format_hex_bytes, + k->sk_ai, k->sk_ai_len, format_hex_bytes, k->sk_ar, k->sk_ar_len); + + fformat (vam->ofp, " SK_e i:%U\n r:%U\n", format_hex_bytes, + k->sk_ei, k->sk_ei_len, format_hex_bytes, k->sk_er, k->sk_er_len); + + fformat (vam->ofp, " SK_p i:%U\n r:%U\n", format_hex_bytes, + k->sk_pi, k->sk_pi_len, format_hex_bytes, k->sk_pr, k->sk_pr_len); + + fformat (vam->ofp, " identifier (i) %U\n", format_ikev2_id_type_and_data, + &sa->i_id); + fformat (vam->ofp, " identifier (r) %U\n", format_ikev2_id_type_and_data, + &sa->r_id); + + vam->result_ready = 1; +} + +static int api_ikev2_child_sa_dump (vat_main_t * vam) { unformat_input_t *i = vam->input; @@ -479,7 +619,84 @@ vl_api_ikev2_child_sa_details_t_handler (vl_api_ikev2_child_sa_details_t * mp) vat_main_t *vam = ikev2_test_main.vat_main; vl_api_ikev2_child_sa_t *child_sa = &mp->child_sa; vl_api_ikev2_keys_t *k = &child_sa->keys; - vl_api_ikev2_child_sa_t_endian (child_sa); + vl_api_ikev2_child_sa_t_endian (child_sa, 0 /* from network */); + + fformat (vam->ofp, " child sa %u:\n", child_sa->child_sa_index); + + fformat (vam->ofp, " %U ", format_ikev2_sa_transform, + &child_sa->encryption); + fformat (vam->ofp, "%U ", format_ikev2_sa_transform, &child_sa->integrity); + fformat (vam->ofp, "%U \n", format_ikev2_sa_transform, &child_sa->esn); + + fformat (vam->ofp, " spi(i) %lx spi(r) %lx\n", child_sa->i_spi, + child_sa->r_spi); + + fformat (vam->ofp, " SK_e i:%U\n r:%U\n", format_hex_bytes, + k->sk_ei, k->sk_ei_len, format_hex_bytes, k->sk_er, k->sk_er_len); + if (k->sk_ai_len) + { + fformat (vam->ofp, " SK_a i:%U\n r:%U\n", format_hex_bytes, + k->sk_ai, k->sk_ai_len, format_hex_bytes, k->sk_ar, + k->sk_ar_len); + } + vam->result_ready = 1; +} + +static int +api_ikev2_child_sa_v2_dump (vat_main_t *vam) +{ + unformat_input_t *i = vam->input; + ikev2_test_main_t *im = &ikev2_test_main; + vl_api_ikev2_child_sa_dump_t *mp; + vl_api_control_ping_t *mp_ping; + int ret; + u32 sa_index = ~0; + + while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT) + { + if (unformat (i, "sa_index %d", &sa_index)) + ; + else + { + errmsg ("parse error '%U'", format_unformat_error, i); + return -99; + } + } + + if (sa_index == ~0) + return -99; + + /* Construct the API message */ + M (IKEV2_CHILD_SA_DUMP, mp); + + mp->sa_index = clib_net_to_host_u32 (sa_index); + + /* send it... */ + S (mp); + + /* Use a control ping for synchronization */ + if (!im->ping_id) + im->ping_id = vl_msg_api_get_msg_index ((u8 *) (VL_API_CONTROL_PING_CRC)); + mp_ping = vl_msg_api_alloc_as_if_client (sizeof (*mp_ping)); + mp_ping->_vl_msg_id = htons (im->ping_id); + mp_ping->client_index = vam->my_client_index; + vam->result_ready = 0; + + S (mp_ping); + + /* Wait for a reply... */ + W (ret); + return ret; +} + +static void +vl_api_ikev2_child_sa_v2_details_t_handler ( + vl_api_ikev2_child_sa_details_t *mp) +{ + vat_main_t *vam = ikev2_test_main.vat_main; + vl_api_ikev2_child_sa_t *child_sa = &mp->child_sa; + vl_api_ikev2_keys_t *k = &child_sa->keys; + vl_api_ikev2_child_sa_t_endian (child_sa, 0 /* from network */); fformat (vam->ofp, " child sa %u:\n", child_sa->child_sa_index); @@ -567,7 +784,7 @@ static void vat_main_t *vam = ikev2_test_main.vat_main; vl_api_ikev2_ts_t *ts = &mp->ts; ip_address_t start_addr, end_addr; - vl_api_ikev2_ts_t_endian (ts); + vl_api_ikev2_ts_t_endian (ts, 0 /* from network */); ip_address_decode2 (&ts->start_addr, &start_addr); ip_address_decode2 (&ts->end_addr, &end_addr); diff --git a/src/plugins/ikev2/ikev2_types.api b/src/plugins/ikev2/ikev2_types.api index b279026c2b9..2492611703d 100644 --- a/src/plugins/ikev2/ikev2_types.api +++ b/src/plugins/ikev2/ikev2_types.api @@ -128,6 +128,19 @@ typedef ikev2_child_sa vl_api_ikev2_sa_transform_t esn; }; +typedef ikev2_child_sa_v2 +{ + u32 sa_index; + u32 child_sa_index; + u32 i_spi; + u32 r_spi; + vl_api_ikev2_keys_t keys; + vl_api_ikev2_sa_transform_t encryption; + vl_api_ikev2_sa_transform_t integrity; + vl_api_ikev2_sa_transform_t esn; + f64 uptime; +}; + typedef ikev2_sa_stats { u16 n_keepalives; @@ -138,6 +151,18 @@ typedef ikev2_sa_stats u16 n_init_sa_retransmit; }; +enum ikev2_state +{ + UNKNOWN, + SA_INIT, + DELETED, + AUTH_FAILED, + AUTHENTICATED, + NOTIFY_AND_DELETE, + TS_UNACCEPTABLE, + NO_PROPOSAL_CHOSEN, +}; + typedef ikev2_sa { u32 sa_index; @@ -161,3 +186,54 @@ typedef ikev2_sa vl_api_ikev2_sa_stats_t stats; }; + +typedef ikev2_sa_v2 +{ + u32 sa_index; + string profile_name[64]; + vl_api_ikev2_state_t state; + + u64 ispi; + u64 rspi; + vl_api_address_t iaddr; + vl_api_address_t raddr; + + vl_api_ikev2_keys_t keys; + + /* ID */ + vl_api_ikev2_id_t i_id; + vl_api_ikev2_id_t r_id; + + vl_api_ikev2_sa_transform_t encryption; + vl_api_ikev2_sa_transform_t integrity; + vl_api_ikev2_sa_transform_t prf; + vl_api_ikev2_sa_transform_t dh; + + vl_api_ikev2_sa_stats_t stats; +}; + +typedef ikev2_sa_v3 +{ + u32 sa_index; + string profile_name[64]; + vl_api_ikev2_state_t state; + + u64 ispi; + u64 rspi; + vl_api_address_t iaddr; + vl_api_address_t raddr; + + vl_api_ikev2_keys_t keys; + + /* ID */ + vl_api_ikev2_id_t i_id; + vl_api_ikev2_id_t r_id; + + vl_api_ikev2_sa_transform_t encryption; + vl_api_ikev2_sa_transform_t integrity; + vl_api_ikev2_sa_transform_t prf; + vl_api_ikev2_sa_transform_t dh; + + vl_api_ikev2_sa_stats_t stats; + f64 uptime; +};
\ No newline at end of file |