X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fikev2%2Fikev2.c;h=0df7faa9bab21ea8a6d1d6b92d76e9ff6059fd18;hb=9ec846c26;hp=ad727a9e3555b4834cdc80c327f86491a8077b30;hpb=d7fc12f07313f9147159f2562f6fcc928af7a963;p=vpp.git diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index ad727a9e355..0df7faa9bab 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -28,6 +28,7 @@ #include #include #include +#include #define IKEV2_LIVENESS_RETRIES 3 #define IKEV2_LIVENESS_PERIOD_CHECK 30 @@ -38,9 +39,9 @@ static int ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, ikev2_child_sa_t * child); -#define ikev2_set_state(sa, v) do { \ +#define ikev2_set_state(sa, v, ...) do { \ (sa)->state = v; \ - ikev2_elog_sa_state("ispi %lx SA state changed to " #v, sa->ispi); \ + ikev2_elog_sa_state("ispi %lx SA state changed to " #v __VA_ARGS__, sa->ispi); \ } while(0); typedef struct @@ -61,30 +62,36 @@ format_ikev2_trace (u8 * s, va_list * args) return s; } -#define foreach_ikev2_error \ -_(PROCESSED, "IKEv2 packets processed") \ -_(IKE_SA_INIT_RETRANSMIT, "IKE_SA_INIT retransmit ") \ -_(IKE_SA_INIT_IGNORE, "IKE_SA_INIT ignore (IKE SA already auth)") \ -_(IKE_REQ_RETRANSMIT, "IKE request retransmit") \ -_(IKE_REQ_IGNORE, "IKE request ignore (old msgid)") \ -_(NOT_IKEV2, "Non IKEv2 packets received") \ -_(BAD_LENGTH, "Bad packet length") \ -_(MALFORMED_PACKET, "Malformed packet") \ -_(NO_BUFF_SPACE, "No buffer space") +#define IKEV2_GENERATE_SA_INIT_OK_str "" +#define IKEV2_GENERATE_SA_INIT_OK_ERR_NO_DH_STR \ + "no DH group configured for IKE proposals!" +#define IKEV2_GENERATE_SA_INIT_OK_ERR_UNSUPP_STR \ + "DH group not supported!" typedef enum { -#define _(sym,str) IKEV2_ERROR_##sym, - foreach_ikev2_error -#undef _ - IKEV2_N_ERROR, -} ikev2_error_t; + IKEV2_GENERATE_SA_INIT_OK, + IKEV2_GENERATE_SA_INIT_ERR_NO_DH, + IKEV2_GENERATE_SA_INIT_ERR_UNSUPPORTED_DH, +} ikev2_generate_sa_error_t; -static char *ikev2_error_strings[] = { -#define _(sym,string) string, - foreach_ikev2_error -#undef _ -}; +static u8 * +format_ikev2_gen_sa_error (u8 * s, va_list * args) +{ + ikev2_generate_sa_error_t e = va_arg (*args, ikev2_generate_sa_error_t); + switch (e) + { + case IKEV2_GENERATE_SA_INIT_OK: + break; + case IKEV2_GENERATE_SA_INIT_ERR_NO_DH: + s = format (s, IKEV2_GENERATE_SA_INIT_OK_ERR_NO_DH_STR); + break; + case IKEV2_GENERATE_SA_INIT_ERR_UNSUPPORTED_DH: + s = format (s, IKEV2_GENERATE_SA_INIT_OK_ERR_UNSUPP_STR); + break; + } + return s; +} typedef enum { @@ -357,16 +364,14 @@ ikev2_delete_sa (ikev2_main_per_thread_data_t * ptd, ikev2_sa_t * sa) } } -static void +static ikev2_generate_sa_error_t ikev2_generate_sa_init_data (ikev2_sa_t * sa) { ikev2_sa_transform_t *t = 0, *t2; ikev2_main_t *km = &ikev2_main; if (sa->dh_group == IKEV2_TRANSFORM_DH_TYPE_NONE) - { - return; - } + return IKEV2_GENERATE_SA_INIT_ERR_NO_DH; /* check if received DH group is on our list of supported groups */ vec_foreach (t2, km->supported_transforms) @@ -381,7 +386,7 @@ ikev2_generate_sa_init_data (ikev2_sa_t * sa) if (!t) { sa->dh_group = IKEV2_TRANSFORM_DH_TYPE_NONE; - return; + return IKEV2_GENERATE_SA_INIT_ERR_UNSUPPORTED_DH; } if (sa->is_initiator) @@ -406,6 +411,7 @@ ikev2_generate_sa_init_data (ikev2_sa_t * sa) /* generate dh keys */ ikev2_generate_dh (sa, t); + return IKEV2_GENERATE_SA_INIT_OK; } static void @@ -427,7 +433,8 @@ ikev2_complete_sa_data (ikev2_sa_t * sa, ikev2_sa_t * sai) sa->profile_index = sai->profile_index; sa->tun_itf = sai->tun_itf; sa->is_tun_itf_set = sai->is_tun_itf_set; - sa->natt_state = sai->natt_state; + if (sai->natt_state == IKEV2_NATT_DISABLED) + sa->natt_state = IKEV2_NATT_DISABLED; sa->i_id.data = _(sai->i_id.data); sa->r_id.data = _(sai->r_id.data); sa->i_auth.method = sai->i_auth.method; @@ -435,6 +442,7 @@ ikev2_complete_sa_data (ikev2_sa_t * sa, ikev2_sa_t * sai) sa->i_auth.data = _(sai->i_auth.data); sa->i_auth.key = _(sai->i_auth.key); sa->last_sa_init_req_packet_data = _(sai->last_sa_init_req_packet_data); + sa->last_init_msg_id = sai->last_init_msg_id; sa->childs = _(sai->childs); sa->udp_encap = sai->udp_encap; sa->ipsec_over_udp_port = sai->ipsec_over_udp_port; @@ -684,9 +692,8 @@ ikev2_check_payload_length (const ike_payload_header_t * ikep, int rlen, } 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) +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; @@ -701,6 +708,7 @@ ikev2_process_sa_init_req (vlib_main_t * vm, ip_addr_version (&sa->iaddr) == AF_IP4); sa->ispi = clib_net_to_host_u64 (ike->ispi); + sa->sw_if_index = sw_if_index; /* store whole IKE payload - needed for PSK auth */ vec_reset_length (sa->last_sa_init_req_packet_data); @@ -1038,14 +1046,14 @@ ikev2_initial_contact_cleanup_internal (ikev2_main_per_thread_data_t * ptd, /* find old IKE SAs with the same authenticated identity */ /* *INDENT-OFF* */ - pool_foreach (tmp, ptd->sas, ({ + 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)) continue; if (sa->rspi != tmp->rspi) vec_add1(delete, tmp - ptd->sas); - })); + } /* *INDENT-ON* */ for (i = 0; i < vec_len (delete); i++) @@ -1248,7 +1256,7 @@ ikev2_process_auth_req (vlib_main_t * vm, ikev2_sa_t * sa, return 1; malformed: - ikev2_set_state (sa, IKEV2_STATE_DELETED); + ikev2_set_state (sa, IKEV2_STATE_DELETED, ": malformed IKE_AUTH"); return 0; } @@ -1339,13 +1347,17 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, ikev2_ts_t *tsr = 0; ikev2_sa_proposal_t *proposal = 0; ikev2_child_sa_t *child_sa; - u32 dlen = 0; + u32 dlen = 0, src; u16 plen; - ikev2_elog_exchange ("ispi %lx rspi %lx CREATE_CHILD_SA received " - "from ", clib_host_to_net_u64 (ike->ispi), - clib_host_to_net_u64 (ike->rspi), - ip_addr_v4 (&sa->raddr).as_u32, + if (sa->is_initiator) + src = ip_addr_v4 (&sa->raddr).as_u32; + else + src = ip_addr_v4 (&sa->iaddr).as_u32; + + ikev2_elog_exchange ("ispi %lx rspi %lx CREATE_CHILD_SA received from", + clib_host_to_net_u64 (ike->ispi), + clib_host_to_net_u64 (ike->rspi), src, ip_addr_version (&sa->raddr) == AF_IP4); plaintext = ikev2_decrypt_sk_payload (sa, ike, &payload, len, &dlen); @@ -1408,9 +1420,12 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, p += plen; } - if (sa->is_initiator && proposal->protocol_id == IKEV2_PROTOCOL_ESP) + if (sa->is_initiator && proposal + && proposal->protocol_id == IKEV2_PROTOCOL_ESP) { - ikev2_rekey_t *rekey = &sa->rekey[0]; + ikev2_rekey_t *rekey = sa->rekey; + if (vec_len (rekey) == 0) + goto cleanup_and_exit; rekey->protocol_id = proposal->protocol_id; rekey->i_proposal = ikev2_select_proposal (proposal, IKEV2_PROTOCOL_ESP); @@ -1529,7 +1544,7 @@ ikev2_sa_match_ts (ikev2_sa_t * sa) ikev2_id_t *id_rem, *id_loc; /* *INDENT-OFF* */ - pool_foreach (p, km->profiles, ({ + pool_foreach (p, km->profiles) { if (sa->is_initiator) { @@ -1572,7 +1587,7 @@ ikev2_sa_match_ts (ikev2_sa_t * sa) } break; - })); + } /* *INDENT-ON* */ if (tsi && tsr) @@ -1632,7 +1647,7 @@ ikev2_sa_auth (ikev2_sa_t * sa) } /* *INDENT-OFF* */ - pool_foreach (p, km->profiles, ({ + pool_foreach (p, km->profiles) { /* check id */ if (!ikev2_is_id_equal (&p->rem_id, id_rem) @@ -1655,7 +1670,11 @@ ikev2_sa_auth (ikev2_sa_t * sa) sel_p = p; break; } - + else + { + ikev2_elog_uint (IKEV2_LOG_ERROR, "shared key mismatch! ispi %lx", + sa->ispi); + } } else if (sa_auth->method == IKEV2_AUTH_METHOD_RSA_SIG) { @@ -1668,11 +1687,16 @@ ikev2_sa_auth (ikev2_sa_t * sa) sel_p = p; break; } + else + { + ikev2_elog_uint (IKEV2_LOG_ERROR, + "cert verification failed! ispi %lx", sa->ispi); + } } vec_free(auth); vec_free(psk); - })); + } /* *INDENT-ON* */ if (sel_p) @@ -1799,8 +1823,8 @@ typedef struct u32 remote_spi; ipsec_crypto_alg_t encr_type; ipsec_integ_alg_t integ_type; - ip46_address_t local_ip; - ip46_address_t remote_ip; + ip_address_t local_ip; + ip_address_t remote_ip; ipsec_key_t loc_ckey, rem_ckey, loc_ikey, rem_ikey; u8 is_rekey; u32 old_remote_sa_id; @@ -1815,13 +1839,32 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) ikev2_main_t *km = &ikev2_main; u32 sw_if_index; int rv = 0; - ip46_address_t zero_addr = ip46_address_initializer; + tunnel_t tun_in = { + .t_flags = TUNNEL_FLAG_NONE, + .t_encap_decap_flags = TUNNEL_ENCAP_DECAP_FLAG_NONE, + .t_dscp = 0, + .t_mode = TUNNEL_MODE_P2P, + .t_table_id = 0, + .t_hop_limit = 255, + .t_src = a->local_ip, + .t_dst = a->remote_ip, + }; + tunnel_t tun_out = { + .t_flags = TUNNEL_FLAG_NONE, + .t_encap_decap_flags = TUNNEL_ENCAP_DECAP_FLAG_NONE, + .t_dscp = 0, + .t_mode = TUNNEL_MODE_P2P, + .t_table_id = 0, + .t_hop_limit = 255, + .t_src = a->remote_ip, + .t_dst = a->local_ip, + }; if (~0 == a->sw_if_index) { /* no tunnel associated with the SA/profile - create a new one */ - rv = ipip_add_tunnel (IPIP_TRANSPORT_IP4, ~0, - &a->local_ip, &a->remote_ip, 0, + rv = ipip_add_tunnel (IPIP_TRANSPORT_IP4, ~0, &ip_addr_46 (&a->local_ip), + &ip_addr_46 (&a->remote_ip), 0, TUNNEL_ENCAP_DECAP_FLAG_NONE, IP_DSCP_CS0, TUNNEL_MODE_P2P, &sw_if_index); @@ -1860,25 +1903,33 @@ ikev2_add_tunnel_from_main (ikev2_add_ipsec_tunnel_args_t * a) vec_add1 (sas_in, a->old_remote_sa_id); } - 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, 0, a->salt_local, &zero_addr, - &zero_addr, TUNNEL_ENCAP_DECAP_FLAG_NONE, - IP_DSCP_CS0, NULL, a->src_port, a->dst_port); - - rv |= ipsec_sa_add_and_lock (a->remote_sa_id, a->remote_spi, - IPSEC_PROTOCOL_ESP, a->encr_type, &a->rem_ckey, - a->integ_type, &a->rem_ikey, - (a->flags | IPSEC_SA_FLAG_IS_INBOUND), 0, - a->salt_remote, &zero_addr, - &zero_addr, TUNNEL_ENCAP_DECAP_FLAG_NONE, - IP_DSCP_CS0, NULL, - a->ipsec_over_udp_port, - a->ipsec_over_udp_port); - - rv |= ipsec_tun_protect_update (sw_if_index, NULL, a->local_sa_id, sas_in); + 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); + if (rv) + goto err0; + + rv = ipsec_sa_add_and_lock ( + a->remote_sa_id, a->remote_spi, IPSEC_PROTOCOL_ESP, a->encr_type, + &a->rem_ckey, a->integ_type, &a->rem_ikey, + (a->flags | IPSEC_SA_FLAG_IS_INBOUND), a->salt_remote, + a->ipsec_over_udp_port, a->ipsec_over_udp_port, &tun_in, NULL); + if (rv) + goto err1; + + rv = ipsec_tun_protect_update (sw_if_index, NULL, a->local_sa_id, sas_in); + if (rv) + goto err2; + + return; + +err2: + ipsec_sa_unlock_id (a->remote_sa_id); +err1: + ipsec_sa_unlock_id (a->local_sa_id); +err0: + vec_free (sas_in); } static int @@ -1907,16 +1958,16 @@ ikev2_create_tunnel_interface (vlib_main_t * vm, if (sa->is_initiator) { - ip_address_to_46 (&sa->iaddr, &a.local_ip); - ip_address_to_46 (&sa->raddr, &a.remote_ip); + ip_address_copy (&a.local_ip, &sa->iaddr); + ip_address_copy (&a.remote_ip, &sa->raddr); proposals = child->r_proposals; a.local_spi = child->r_proposals[0].spi; a.remote_spi = child->i_proposals[0].spi; } else { - ip_address_to_46 (&sa->raddr, &a.local_ip); - ip_address_to_46 (&sa->iaddr, &a.remote_ip); + ip_address_copy (&a.local_ip, &sa->raddr); + ip_address_copy (&a.remote_ip, &sa->iaddr); proposals = child->i_proposals; a.local_spi = child->i_proposals[0].spi; a.remote_spi = child->r_proposals[0].spi; @@ -2216,8 +2267,8 @@ ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, } static u32 -ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, - ike_header_t * ike, void *user, udp_header_t * udp) +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) { ikev2_main_t *km = &ikev2_main; u16 buffer_data_size = vlib_buffer_get_default_data_size (km->vlib_main); @@ -2355,7 +2406,7 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, } else { - ikev2_set_state (sa, IKEV2_STATE_DELETED); + ikev2_set_state (sa, IKEV2_STATE_DELETED, ": unexpected IKE_AUTH"); goto done; } } @@ -2385,7 +2436,7 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, /* received N(AUTHENTICATION_FAILED) */ else if (sa->state == IKEV2_STATE_AUTH_FAILED) { - ikev2_set_state (sa, IKEV2_STATE_DELETED); + ikev2_set_state (sa, IKEV2_STATE_DELETED, ": auth failed"); goto done; } /* received unsupported critical payload */ @@ -2400,7 +2451,16 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, vec_free (data); sa->unsupported_cp = 0; } - /* else send empty response */ + else + /* else send empty response */ + { + if (ike_hdr_is_response (ike)) + { + ASSERT (stats != 0); + stats->n_keepalives++; + sa->stats.n_keepalives++; + } + } } else if (ike->exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA) { @@ -2464,11 +2524,6 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, if (sa->is_initiator) ike->flags |= IKEV2_HDR_FLAG_INITIATOR; - if (ike_hdr_is_request (ike)) - { - sa->last_init_msg_id = clib_net_to_host_u32 (ike->msgid); - } - if (ike->exchange == IKEV2_EXCHANGE_SA_INIT) { tlen += vec_len (chain->data); @@ -2588,6 +2643,7 @@ ikev2_retransmit_sa_init_one (ikev2_sa_t * sa, ike_header_t * ike, /* req is retransmit */ if (sa->state == IKEV2_STATE_SA_INIT) { + sa->stats.n_init_retransmit++; tmp = (ike_header_t *) sa->last_sa_init_res_packet_data; u32 slen = clib_net_to_host_u32 (tmp->length); ike->ispi = tmp->ispi; @@ -2636,11 +2692,11 @@ ikev2_retransmit_sa_init (ike_header_t * ike, ip_address_t iaddr, ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data (); /* *INDENT-OFF* */ - pool_foreach (sa, ptd->sas, ({ + 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 */ @@ -2665,6 +2721,7 @@ ikev2_retransmit_resp (ikev2_sa_t * sa, ike_header_t * ike) /* retransmitted req */ if (msg_id == sa->last_msg_id) { + sa->stats.n_retransmit++; ike_header_t *tmp = (ike_header_t *) sa->last_res_packet_data; u32 slen = clib_net_to_host_u32 (tmp->length); ike->ispi = tmp->ispi; @@ -2749,8 +2806,8 @@ ikev2_rewrite_v4_addrs (ikev2_sa_t * sa, ip4_header_t * ih) } static_always_inline void -ikev2_set_ip_address (ikev2_sa_t * sa, const void *iaddr, - const void *raddr, const int af) +ikev2_set_ip_address (ikev2_sa_t *sa, const void *iaddr, const void *raddr, + const ip_address_family_t af) { ip_address_set (&sa->raddr, raddr, af); ip_address_set (&sa->iaddr, iaddr, af); @@ -2776,18 +2833,46 @@ ikev2_elog_uint_peers_addr (u32 exchange, ip4_header_t * ip4, exchange, src, dst); } +static void +ikev2_generate_sa_init_data_and_log (ikev2_sa_t * sa) +{ + ikev2_generate_sa_error_t rc = ikev2_generate_sa_init_data (sa); + + if (PREDICT_TRUE (rc == IKEV2_GENERATE_SA_INIT_OK)) + return; + + if (rc == IKEV2_GENERATE_SA_INIT_ERR_NO_DH) + ikev2_elog_error (IKEV2_GENERATE_SA_INIT_OK_ERR_NO_DH_STR); + else if (rc == IKEV2_GENERATE_SA_INIT_ERR_UNSUPPORTED_DH) + ikev2_elog_error (IKEV2_GENERATE_SA_INIT_OK_ERR_UNSUPP_STR); +} + +static void +ikev2_update_stats (vlib_main_t *vm, u32 node_index, ikev2_stats_t *s) +{ + vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_KEEPALIVE, + s->n_keepalives); + vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_REKEY_REQ, + s->n_rekey_req); + vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_INIT_SA_REQ, + s->n_sa_init_req); + vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_IKE_AUTH_REQ, + s->n_sa_auth_req); +} + static_always_inline uword -ikev2_node_internal (vlib_main_t * vm, - vlib_node_runtime_t * node, vlib_frame_t * frame, - u8 is_ip4) +ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, u8 is_ip4, u8 natt) { u32 n_left = frame->n_vectors, *from; ikev2_main_t *km = &ikev2_main; vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b; u16 nexts[VLIB_FRAME_SIZE], *next = nexts; ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data (); + ikev2_stats_t _stats, *stats = &_stats; int res; + clib_memset_u16 (stats, 0, sizeof (stats[0]) / sizeof (u16)); from = vlib_frame_vector_args (frame); vlib_get_buffers (vm, from, bufs, n_left); b = bufs; @@ -2805,9 +2890,9 @@ ikev2_node_internal (vlib_main_t * vm, ikev2_sa_t sa; /* temporary store for SA */ u32 rlen, slen = 0; int ip_hdr_sz = 0; - int is_req = 0, has_non_esp_marker = 0; + int is_req = 0; - if (b0->punt_reason == ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0]) + if (natt) { u8 *ptr = vlib_buffer_get_current (b0); ip40 = (ip4_header_t *) ptr; @@ -2840,12 +2925,12 @@ ikev2_node_internal (vlib_main_t * vm, rlen = b0->current_length - ip_hdr_sz - sizeof (*udp0); /* check for non-esp marker */ - if (*((u32 *) ike0) == 0) + if (natt) { + ASSERT (*((u32 *) ike0) == 0); ike0 = (ike_header_t *) ((u8 *) ike0 + sizeof (ikev2_non_esp_marker)); rlen -= sizeof (ikev2_non_esp_marker); - has_non_esp_marker = 1; } if (clib_net_to_host_u32 (ike0->length) != rlen) @@ -2869,6 +2954,8 @@ ikev2_node_internal (vlib_main_t * vm, if (ike_hdr_is_initiator (ike0)) { + sa0->stats.n_sa_init_req++; + stats->n_sa_init_req++; if (ike0->rspi == 0) { if (is_ip4) @@ -2895,7 +2982,9 @@ ikev2_node_internal (vlib_main_t * vm, goto dispatch0; } - res = ikev2_process_sa_init_req (vm, sa0, ike0, udp0, rlen); + res = ikev2_process_sa_init_req ( + vm, sa0, ike0, udp0, rlen, + vnet_buffer (b0)->sw_if_index[VLIB_RX]); if (!res) vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_MALFORMED_PACKET, @@ -2907,14 +2996,15 @@ ikev2_node_internal (vlib_main_t * vm, sa0->r_proposals = ikev2_select_proposal (sa0->i_proposals, IKEV2_PROTOCOL_IKE); - ikev2_generate_sa_init_data (sa0); + ikev2_generate_sa_init_data_and_log (sa0); } if (sa0->state == IKEV2_STATE_SA_INIT || sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE) { ike0->flags = IKEV2_HDR_FLAG_RESPONSE; - slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + 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, @@ -2962,8 +3052,11 @@ ikev2_node_internal (vlib_main_t * vm, ikev2_calc_keys (sa0); ikev2_sa_auth_init (sa0); ike0->flags = IKEV2_HDR_FLAG_INITIATOR; - slen = - ikev2_generate_message (b0, sa0, ike0, 0, udp0); + ike0->msgid = + clib_net_to_host_u32 (sai->last_init_msg_id); + sa0->last_init_msg_id = sai->last_init_msg_id + 1; + slen = ikev2_generate_message (b0, sa0, ike0, 0, + udp0, stats); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, @@ -3034,7 +3127,12 @@ ikev2_node_internal (vlib_main_t * vm, } else { - slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + sa0->stats.n_sa_auth_req++; + stats->n_sa_auth_req++; + ike0->flags = IKEV2_HDR_FLAG_RESPONSE; + sa0->last_init_msg_id = 1; + 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, @@ -3106,7 +3204,8 @@ ikev2_node_internal (vlib_main_t * vm, if (ike_hdr_is_request (ike0)) { ike0->flags = IKEV2_HDR_FLAG_RESPONSE; - slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); + 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, @@ -3166,8 +3265,11 @@ ikev2_node_internal (vlib_main_t * vm, } 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); + 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, @@ -3204,13 +3306,13 @@ ikev2_node_internal (vlib_main_t * vm, if (udp0->dst_port == clib_net_to_host_u16 (IKEV2_PORT_NATT) && ikev2_natt_active (sa0)) { - if (!has_non_esp_marker) + if (!natt) slen = ikev2_insert_non_esp_marker (ike0, slen); } } else { - if (has_non_esp_marker) + if (natt) slen += sizeof (ikev2_non_esp_marker); u16 tp = udp0->dst_port; @@ -3256,6 +3358,7 @@ ikev2_node_internal (vlib_main_t * vm, b += 1; } + ikev2_update_stats (vm, node->node_index, stats); vlib_node_increment_counter (vm, node->node_index, IKEV2_ERROR_PROCESSED, frame->n_vectors); vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors); @@ -3265,13 +3368,20 @@ ikev2_node_internal (vlib_main_t * vm, static uword ikev2_ip4 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame) { - return ikev2_node_internal (vm, node, frame, 1 /* is_ip4 */ ); + return ikev2_node_internal (vm, node, frame, 1 /* is_ip4 */, 0); +} + +static uword +ikev2_ip4_natt (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame) +{ + return ikev2_node_internal (vm, node, frame, 1 /* is_ip4 */, 1 /* natt */); } static uword 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 */ ); + return ikev2_node_internal (vm, node, frame, 0 /* is_ip4 */, 0); } /* *INDENT-OFF* */ @@ -3282,8 +3392,25 @@ VLIB_REGISTER_NODE (ikev2_node_ip4,static) = { .format_trace = format_ikev2_trace, .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(ikev2_error_strings), - .error_strings = ikev2_error_strings, + .n_errors = IKEV2_N_ERROR, + .error_counters = ikev2_error_counters, + + .n_next_nodes = IKEV2_IP4_N_NEXT, + .next_nodes = { + [IKEV2_NEXT_IP4_LOOKUP] = "ip4-lookup", + [IKEV2_NEXT_IP4_ERROR_DROP] = "error-drop", + }, +}; + +VLIB_REGISTER_NODE (ikev2_node_ip4_natt,static) = { + .function = ikev2_ip4_natt, + .name = "ikev2-ip4-natt", + .vector_size = sizeof (u32), + .format_trace = format_ikev2_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_errors = IKEV2_N_ERROR, + .error_counters = ikev2_error_counters, .n_next_nodes = IKEV2_IP4_N_NEXT, .next_nodes = { @@ -3299,8 +3426,8 @@ VLIB_REGISTER_NODE (ikev2_node_ip6,static) = { .format_trace = format_ikev2_trace, .type = VLIB_NODE_TYPE_INTERNAL, - .n_errors = ARRAY_LEN(ikev2_error_strings), - .error_strings = ikev2_error_strings, + .n_errors = IKEV2_N_ERROR, + .error_counters = ikev2_error_counters, .n_next_nodes = IKEV2_IP6_N_NEXT, .next_nodes = { @@ -3634,9 +3761,9 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm, ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); ike0->flags = 0; - ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); - sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); - len = ikev2_generate_message (b0, sa, ike0, 0, 0); + ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); + sa->last_init_msg_id += 1; + len = ikev2_generate_message (b0, sa, ike0, 0, 0, 0); if (~0 == len) return; @@ -3683,10 +3810,10 @@ ikev2_cleanup_profile_sessions (ikev2_main_t * km, ikev2_profile_t * p) u32 *del_sai = 0; /* *INDENT-OFF* */ - pool_foreach(sa, km->sais, ({ + pool_foreach (sa, km->sais) { if (pi == sa->profile_index) vec_add1 (del_sai, sa - km->sais); - })); + } /* *INDENT-ON* */ vec_foreach (sai, del_sai) @@ -3701,10 +3828,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, ({ + 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) @@ -4128,15 +4255,6 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) valid_ip = 1; } - bi0 = ikev2_get_new_ike_header_buff (vm, &b0); - if (!bi0) - { - char *errmsg = "buffer alloc failure"; - ikev2_log_error (errmsg); - return clib_error_return (0, errmsg); - } - ike0 = vlib_buffer_get_current (b0); - /* Prepare the SA and the IKE payload */ ikev2_sa_t sa; clib_memset (&sa, 0, sizeof (ikev2_sa_t)); @@ -4164,7 +4282,15 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) sa.is_tun_itf_set = 1; sa.initial_contact = 1; sa.dst_port = IKEV2_PORT; - ikev2_generate_sa_init_data (&sa); + + ikev2_generate_sa_error_t rc = ikev2_generate_sa_init_data (&sa); + if (rc != IKEV2_GENERATE_SA_INIT_OK) + { + ikev2_sa_free_all_vec (&sa); + ikev2_payload_destroy_chain (chain); + return clib_error_return (0, "%U", format_ikev2_gen_sa_error, rc); + } + ikev2_payload_add_ke (chain, sa.dh_group, sa.i_dh_data); ikev2_payload_add_nonce (chain, sa.i_nonce); @@ -4204,6 +4330,17 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) sig_hash_algo); vec_free (sig_hash_algo); + bi0 = ikev2_get_new_ike_header_buff (vm, &b0); + if (!bi0) + { + ikev2_sa_free_all_vec (&sa); + ikev2_payload_destroy_chain (chain); + char *errmsg = "buffer alloc failure"; + ikev2_log_error (errmsg); + return clib_error_return (0, errmsg); + } + ike0 = vlib_buffer_get_current (b0); + /* Buffer update and boilerplate */ len += vec_len (chain->data); ike0->nextpayload = chain->first_payload_type; @@ -4217,6 +4354,7 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) ike0->ispi = clib_host_to_net_u64 (sa.ispi); ike0->rspi = 0; ike0->msgid = 0; + sa.last_init_msg_id += 1; /* store whole IKE payload - needed for PSK auth */ vec_reset_length (sa.last_sa_init_req_packet_data); @@ -4293,9 +4431,9 @@ ikev2_delete_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, vec_resize (sa->del, 1); sa->del->protocol_id = IKEV2_PROTOCOL_ESP; sa->del->spi = csa->i_proposals->spi; - ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); - sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); - len = ikev2_generate_message (b0, sa, ike0, 0, 0); + ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); + sa->last_init_msg_id += 1; + len = ikev2_generate_message (b0, sa, ike0, 0, 0, 0); if (~0 == len) return; @@ -4325,14 +4463,14 @@ ikev2_initiate_delete_child_sa (vlib_main_t * vm, u32 ispi) if (fchild) break; /* *INDENT-OFF* */ - pool_foreach (sa, tkm->sas, ({ + pool_foreach (sa, tkm->sas) { fchild = ikev2_sa_get_child(sa, ispi, IKEV2_PROTOCOL_ESP, 1); if (fchild) { fsa = sa; break; } - })); + } /* *INDENT-ON* */ } @@ -4365,14 +4503,14 @@ ikev2_initiate_delete_ike_sa (vlib_main_t * vm, u64 ispi) if (fsa) break; /* *INDENT-OFF* */ - pool_foreach (sa, tkm->sas, ({ + pool_foreach (sa, tkm->sas) { if (sa->ispi == ispi) { fsa = sa; ftkm = tkm; break; } - })); + } /* *INDENT-ON* */ } @@ -4409,10 +4547,11 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, ike0->exchange = IKEV2_EXCHANGE_CREATE_CHILD_SA; ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); - ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); - sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); + ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); + sa->last_init_msg_id += 1; ikev2_rekey_t *rekey; + vec_reset_length (sa->rekey); vec_add2 (sa->rekey, rekey, 1); ikev2_sa_proposal_t *proposals = vec_dup (csa->i_proposals); @@ -4420,7 +4559,7 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, RAND_bytes ((u8 *) & proposals[0].spi, sizeof (proposals[0].spi)); rekey->spi = proposals[0].spi; rekey->ispi = csa->i_proposals->spi; - len = ikev2_generate_message (b0, sa, ike0, proposals, 0); + len = ikev2_generate_message (b0, sa, ike0, proposals, 0, 0); if (~0 == len) return; @@ -4447,14 +4586,14 @@ ikev2_initiate_rekey_child_sa (vlib_main_t * vm, u32 ispi) if (fchild) break; /* *INDENT-OFF* */ - pool_foreach (sa, tkm->sas, ({ + pool_foreach (sa, tkm->sas) { fchild = ikev2_sa_get_child(sa, ispi, IKEV2_PROTOCOL_ESP, 1); if (fchild) { fsa = sa; break; } - })); + } /* *INDENT-ON* */ } @@ -4489,10 +4628,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, ({ + 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) @@ -4504,10 +4643,10 @@ ikev2_sa_del (ikev2_profile_t * p, u32 sw_if_index) vec_free (sa_vec); /* *INDENT-OFF* */ - pool_foreach (sa, km->sais, ({ + 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) @@ -4528,10 +4667,10 @@ ikev2_sw_interface_add_del (vnet_main_t * vnm, u32 sw_if_index, u32 is_add) return 0; /* *INDENT-OFF* */ - pool_foreach (p, km->profiles, ({ + 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; @@ -4585,9 +4724,9 @@ ikev2_init (vlib_main_t * vm) 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"); + 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"); + "ikev2-ip4-natt"); ikev2_cli_reference (); km->log_level = IKEV2_LOG_ERROR; @@ -4691,7 +4830,10 @@ ikev2_mngr_process_child_sa (ikev2_sa_t * sa, ikev2_child_sa_t * csa, u32 *sas_in = NULL; vec_add1 (sas_in, csa->remote_sa_id); vlib_worker_thread_barrier_sync (vm); - ipsec_tun_protect_update (sw_if_index, NULL, csa->local_sa_id, sas_in); + int rv = ipsec_tun_protect_update (sw_if_index, NULL, + csa->local_sa_id, sas_in); + if (rv) + vec_free (sas_in); ipsec_sa_unlock_id (ikev2_flip_alternate_sa_bit (csa->remote_sa_id)); vlib_worker_thread_barrier_release (vm); } @@ -4757,14 +4899,14 @@ ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa) if (fchild) break; /* *INDENT-OFF* */ - pool_foreach (sa, tkm->sas, ({ + pool_foreach (sa, tkm->sas) { fchild = ikev2_sa_get_child(sa, ipsec_sa->spi, IKEV2_PROTOCOL_ESP, 1); if (fchild) { fsa = sa; break; } - })); + } /* *INDENT-ON* */ } vlib_get_combined_counter (&ipsec_sa_counters, @@ -4868,10 +5010,10 @@ ikev2_send_informational_request (ikev2_sa_t * sa) ike0->exchange = IKEV2_EXCHANGE_INFORMATIONAL; ike0->ispi = clib_host_to_net_u64 (sa->ispi); ike0->rspi = clib_host_to_net_u64 (sa->rspi); - ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id + 1); + ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); ike0->flags = 0; - sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); - len = ikev2_generate_message (b0, sa, ike0, 0, 0); + sa->last_init_msg_id += 1; + len = ikev2_generate_message (b0, sa, ike0, 0, 0, 0); if (~0 == len) return; @@ -4947,7 +5089,7 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, u32 *to_be_deleted = 0; /* *INDENT-OFF* */ - pool_foreach (sa, tkm->sas, ({ + pool_foreach (sa, tkm->sas) { ikev2_child_sa_t *c; u8 del_old_ids = 0; @@ -4967,7 +5109,7 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, if (!km->dpd_disabled && ikev2_mngr_process_responder_sas (sa)) vec_add1 (to_be_deleted, sa - tkm->sas); - })); + } /* *INDENT-ON* */ vec_foreach (sai, to_be_deleted) @@ -4988,7 +5130,12 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, p = pool_elt_at_index (km->profiles, sa->profile_index); if (p) { - ikev2_initiate_sa_init (vm, p->name); + clib_error_t *e = ikev2_initiate_sa_init (vm, p->name); + if (e) + { + ikev2_log_error ("%U", format_clib_error, e); + clib_error_free (e); + } } } } @@ -4998,9 +5145,9 @@ 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, im->sad, ({ + pool_foreach (sa, im->sad) { ikev2_mngr_process_ipsec_sa(sa); - })); + } /* *INDENT-ON* */ ikev2_process_pending_sa_init (km);