X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fikev2%2Fikev2.c;h=336f896bc06bfb897e08e4dcd89e29b2842df6ca;hb=e1ab06c14deaff5cc0870f7ec76f36613ffcc2d3;hp=4b318605df355d65943236ed23097b2272c78a33;hpb=6960da528443ea40b1cdab323c76f978f7b16a8b;p=vpp.git diff --git a/src/plugins/ikev2/ikev2.c b/src/plugins/ikev2/ikev2.c index 4b318605df3..336f896bc06 100644 --- a/src/plugins/ikev2/ikev2.c +++ b/src/plugins/ikev2/ikev2.c @@ -61,6 +61,37 @@ format_ikev2_trace (u8 * s, va_list * args) return s; } +#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 +{ + 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 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; +} + #define foreach_ikev2_error \ _(PROCESSED, "IKEv2 packets processed") \ _(IKE_SA_INIT_RETRANSMIT, "IKE_SA_INIT retransmit ") \ @@ -105,7 +136,7 @@ typedef u32 ikev2_non_esp_marker; static_always_inline u16 ikev2_get_port (ikev2_sa_t * sa) { - return sa->natt ? IKEV2_PORT_NATT : IKEV2_PORT; + return ikev2_natt_active (sa) ? IKEV2_PORT_NATT : IKEV2_PORT; } static_always_inline int @@ -357,16 +388,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 +410,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 +435,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,6 +457,7 @@ 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; sa->i_id.data = _(sai->i_id.data); sa->r_id.data = _(sai->r_id.data); sa->i_auth.method = sai->i_auth.method; @@ -434,6 +465,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; @@ -640,7 +672,7 @@ ikev2_compute_nat_sha1 (u64 ispi, u64 rspi, ip_address_t * ia, u16 port) clib_memcpy_fast (&buf[8], &rspi, sizeof (rspi)); clib_memcpy_fast (&buf[8 + 8], ip_addr_bytes (ia), ip_address_size (ia)); clib_memcpy_fast (&buf[8 + 8 + ip_address_size (ia)], &port, sizeof (port)); - SHA1 (buf, sizeof (buf), res); + SHA1 (buf, 2 * sizeof (ispi) + sizeof (port) + ip_address_size (ia), res); return res; } @@ -743,7 +775,8 @@ ikev2_process_sa_init_req (vlib_main_t * vm, udp->src_port); if (clib_memcmp (src_sha, n->data, vec_len (src_sha))) { - sa->natt = 1; + if (sa->natt_state == IKEV2_NATT_ENABLED) + sa->natt_state = IKEV2_NATT_ACTIVE; ikev2_elog_uint (IKEV2_LOG_DEBUG, "ispi %lx initiator" " behind NAT", sa->ispi); } @@ -756,7 +789,8 @@ ikev2_process_sa_init_req (vlib_main_t * vm, udp->dst_port); if (clib_memcmp (dst_sha, n->data, vec_len (dst_sha))) { - sa->natt = 1; + if (sa->natt_state == IKEV2_NATT_ENABLED) + sa->natt_state = IKEV2_NATT_ACTIVE; ikev2_elog_uint (IKEV2_LOG_DEBUG, "ispi %lx responder" " (self) behind NAT", sa->ispi); } @@ -869,7 +903,8 @@ ikev2_process_sa_init_resp (vlib_main_t * vm, udp->dst_port); if (clib_memcmp (dst_sha, n->data, vec_len (dst_sha))) { - sa->natt = 1; + if (sa->natt_state == IKEV2_NATT_ENABLED) + sa->natt_state = IKEV2_NATT_ACTIVE; ikev2_elog_uint (IKEV2_LOG_DEBUG, "ispi %lx initiator" " (self) behind NAT", sa->ispi); } @@ -1404,9 +1439,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); @@ -1442,17 +1480,22 @@ ikev2_process_create_child_sa_req (vlib_main_t * vm, rekey->tsi = tsi; rekey->tsr = tsr; /* update Ni */ - vec_free (sa->i_nonce); + 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); - vec_free (n); } + else + goto cleanup_and_exit; + vec_free (n); return 1; cleanup_and_exit: vec_free (n); + vec_free (proposal); + vec_free (tsr); + vec_free (tsi); return 0; } @@ -1806,7 +1849,6 @@ 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; if (~0 == a->sw_if_index) { @@ -1851,21 +1893,39 @@ 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, 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, 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, 0, a->salt_local, &a->local_ip, + &a->remote_ip, TUNNEL_ENCAP_DECAP_FLAG_NONE, + IP_DSCP_CS0, NULL, a->src_port, a->dst_port); + 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), 0, + a->salt_remote, &a->remote_ip, + &a->local_ip, TUNNEL_ENCAP_DECAP_FLAG_NONE, + IP_DSCP_CS0, NULL, + a->ipsec_over_udp_port, a->ipsec_over_udp_port); + 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 @@ -1915,7 +1975,7 @@ ikev2_create_tunnel_interface (vlib_main_t * vm, a.flags |= IPSEC_SA_FLAG_IS_TUNNEL; a.flags |= IPSEC_SA_FLAG_UDP_ENCAP; } - if (sa->natt) + if (ikev2_natt_active (sa)) a.flags |= IPSEC_SA_FLAG_UDP_ENCAP; a.is_rekey = is_rekey; @@ -2041,7 +2101,8 @@ ikev2_create_tunnel_interface (vlib_main_t * vm, a.salt_remote = child->salt_ei; a.salt_local = child->salt_er; } - a.dst_port = sa->natt ? sa->dst_port : sa->ipsec_over_udp_port; + a.dst_port = + ikev2_natt_active (sa) ? sa->dst_port : sa->ipsec_over_udp_port; a.src_port = sa->ipsec_over_udp_port; } @@ -2352,7 +2413,7 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, { if (sa->del[0].protocol_id == IKEV2_PROTOCOL_IKE) { - if (sa->is_initiator) + if (ike_hdr_is_request (ike)) ikev2_payload_add_delete (chain, sa->del); /* The response to a request that deletes the IKE SA is an empty @@ -2446,16 +2507,9 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa, ike->version = IKE_VERSION_2; ike->nextpayload = IKEV2_PAYLOAD_SK; tlen = sizeof (*ike); - if (sa->is_initiator) - { - ike->flags = IKEV2_HDR_FLAG_INITIATOR; - sa->last_init_msg_id = clib_net_to_host_u32 (ike->msgid); - } - else - { - ike->flags = IKEV2_HDR_FLAG_RESPONSE; - } + if (sa->is_initiator) + ike->flags |= IKEV2_HDR_FLAG_INITIATOR; if (ike->exchange == IKEV2_EXCHANGE_SA_INIT) { @@ -2638,6 +2692,9 @@ ikev2_retransmit_sa_init (ike_header_t * ike, ip_address_t iaddr, static u32 ikev2_retransmit_resp (ikev2_sa_t * sa, ike_header_t * ike) { + if (ike_hdr_is_response (ike)) + return 0; + u32 msg_id = clib_net_to_host_u32 (ike->msgid); /* new req */ @@ -2734,11 +2791,9 @@ 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 *src, - const void *dst, const int af, const int is_initiator) +ikev2_set_ip_address (ikev2_sa_t * sa, const void *iaddr, + const void *raddr, const int af) { - const void *raddr = is_initiator ? src : dst; - const void *iaddr = is_initiator ? dst : src; ip_address_set (&sa->raddr, raddr, af); ip_address_set (&sa->iaddr, iaddr, af); } @@ -2763,6 +2818,20 @@ 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_always_inline uword ikev2_node_internal (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, @@ -2794,7 +2863,13 @@ ikev2_node_internal (vlib_main_t * vm, int ip_hdr_sz = 0; int is_req = 0, has_non_esp_marker = 0; - if (b0->punt_reason == ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0]) + ASSERT (0 == b0->punt_reason + || (is_ip4 + && b0->punt_reason == + ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0])); + + if (is_ip4 + && b0->punt_reason == ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0]) { u8 *ptr = vlib_buffer_get_current (b0); ip40 = (ip4_header_t *) ptr; @@ -2854,19 +2929,16 @@ ikev2_node_internal (vlib_main_t * vm, sa0 = &sa; clib_memset (sa0, 0, sizeof (*sa0)); - u8 is_initiator = ike0->flags & IKEV2_HDR_FLAG_INITIATOR; - if (is_initiator) + if (ike_hdr_is_initiator (ike0)) { if (ike0->rspi == 0) { if (is_ip4) - ikev2_set_ip_address (sa0, &ip40->dst_address, - &ip40->src_address, AF_IP4, - is_initiator); + ikev2_set_ip_address (sa0, &ip40->src_address, + &ip40->dst_address, AF_IP4); else - ikev2_set_ip_address (sa0, &ip60->dst_address, - &ip60->src_address, AF_IP6, - is_initiator); + ikev2_set_ip_address (sa0, &ip60->src_address, + &ip60->dst_address, AF_IP6); sa0->dst_port = clib_net_to_host_u16 (udp0->src_port); @@ -2897,12 +2969,13 @@ 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); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, @@ -2927,13 +3000,11 @@ ikev2_node_internal (vlib_main_t * vm, else //received sa_init without initiator flag { if (is_ip4) - ikev2_set_ip_address (sa0, &ip40->src_address, - &ip40->dst_address, AF_IP4, - is_initiator); + ikev2_set_ip_address (sa0, &ip40->dst_address, + &ip40->src_address, AF_IP4); else - ikev2_set_ip_address (sa0, &ip60->src_address, - &ip60->dst_address, AF_IP6, - is_initiator); + ikev2_set_ip_address (sa0, &ip60->dst_address, + &ip60->src_address, AF_IP6); ikev2_process_sa_init_resp (vm, sa0, ike0, udp0, rlen); @@ -2952,6 +3023,10 @@ ikev2_node_internal (vlib_main_t * vm, ikev2_complete_sa_data (sa0, sai); ikev2_calc_keys (sa0); ikev2_sa_auth_init (sa0); + ike0->flags = IKEV2_HDR_FLAG_INITIATOR; + 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); if (~0 == slen) @@ -3024,6 +3099,7 @@ ikev2_node_internal (vlib_main_t * vm, } else { + ike0->flags = IKEV2_HDR_FLAG_RESPONSE; slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, @@ -3093,9 +3169,9 @@ ikev2_node_internal (vlib_main_t * vm, } } } - if (!(ike0->flags & IKEV2_HDR_FLAG_RESPONSE)) + if (ike_hdr_is_request (ike0)) { - ike0->flags |= IKEV2_HDR_FLAG_RESPONSE; + ike0->flags = IKEV2_HDR_FLAG_RESPONSE; slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, @@ -3150,12 +3226,13 @@ ikev2_node_internal (vlib_main_t * vm, ikev2_create_tunnel_interface (vm, sa0, child, p[0], child - sa0->childs, 1); } - if (sa0->is_initiator) + if (ike_hdr_is_response (ike0)) { vec_free (sa0->rekey); } else { + ike0->flags = IKEV2_HDR_FLAG_RESPONSE; slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0); if (~0 == slen) vlib_node_increment_counter (vm, node->node_index, @@ -3191,7 +3268,7 @@ ikev2_node_internal (vlib_main_t * vm, clib_net_to_host_u16 (ikev2_get_port (sa0)); if (udp0->dst_port == clib_net_to_host_u16 (IKEV2_PORT_NATT) - && sa0->natt) + && ikev2_natt_active (sa0)) { if (!has_non_esp_marker) slen = ikev2_insert_non_esp_marker (ike0, slen); @@ -3622,14 +3699,14 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm, 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); - sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); + ike0->flags = 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); if (~0 == len) return; - if (sa->natt) + if (ikev2_natt_active (sa)) len = ikev2_insert_non_esp_marker (ike0, len); if (sa->is_initiator) @@ -4117,15 +4194,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)); @@ -4147,11 +4215,21 @@ ikev2_initiate_sa_init (vlib_main_t * vm, u8 * name) sa.state = IKEV2_STATE_SA_INIT; sa.tun_itf = p->tun_itf; sa.udp_encap = p->udp_encap; + if (p->natt_disabled) + sa.natt_state = IKEV2_NATT_DISABLED; sa.ipsec_over_udp_port = p->ipsec_over_udp_port; 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); @@ -4191,6 +4269,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; @@ -4204,6 +4293,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); @@ -4276,16 +4366,17 @@ ikev2_delete_child_sa_internal (vlib_main_t * vm, 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->flags = 0; 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); + 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); if (~0 == len) return; - if (sa->natt) + if (ikev2_natt_active (sa)) len = ikev2_insert_non_esp_marker (ike0, len); ikev2_send_ike (vm, &sa->iaddr, &sa->raddr, bi0, len, ikev2_get_port (sa), sa->dst_port, sa->sw_if_index); @@ -4395,10 +4486,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); @@ -4410,7 +4502,7 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa, if (~0 == len) return; - if (sa->natt) + if (ikev2_natt_active (sa)) len = ikev2_insert_non_esp_marker (ike0, len); ikev2_send_ike (vm, &sa->iaddr, &sa->raddr, bi0, len, ikev2_get_port (sa), ikev2_get_port (sa), sa->sw_if_index); @@ -4677,7 +4769,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); } @@ -4713,6 +4808,17 @@ ikev2_set_liveness_params (u32 period, u32 max_retries) return 0; } +clib_error_t * +ikev2_profile_natt_disable (u8 * name) +{ + ikev2_profile_t *p = ikev2_profile_index_by_name (name); + if (!p) + return clib_error_return (0, "unknown profile %v", name); + + p->natt_disabled = 1; + return 0; +} + static void ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa) { @@ -4757,33 +4863,12 @@ ikev2_mngr_process_ipsec_sa (ipsec_sa_t * ipsec_sa) } } -static ike_payload_header_t * -ikev2_find_ike_payload (ike_header_t * ike, u32 payload_type) -{ - int p = 0; - ike_payload_header_t *ikep; - u32 payload = ike->nextpayload; - - while (payload != IKEV2_PAYLOAD_NONE) - { - ikep = (ike_payload_header_t *) & ike->payload[p]; - if (payload == payload_type) - return ikep; - - u16 plen = clib_net_to_host_u16 (ikep->length); - payload = ikep->nextpayload; - p += plen; - } - return 0; -} - static void ikev2_process_pending_sa_init_one (ikev2_main_t * km, ikev2_sa_t * sa) { ikev2_profile_t *p; u32 bi0; - u8 *nat_sha; - ike_payload_header_t *ph; + u8 *nat_sha, *np; if (ip_address_is_zero (&sa->iaddr)) { @@ -4794,20 +4879,20 @@ ikev2_process_pending_sa_init_one (ikev2_main_t * km, ikev2_sa_t * sa) return; /* update NAT detection payload */ - ph = - ikev2_find_ike_payload ((ike_header_t *) - sa->last_sa_init_req_packet_data, - IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP); - if (!ph) - return; - - nat_sha = - ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi), - clib_host_to_net_u64 (sa->rspi), - &sa->iaddr, - clib_host_to_net_u16 (IKEV2_PORT)); - clib_memcpy_fast (ph->payload, nat_sha, vec_len (nat_sha)); - vec_free (nat_sha); + np = + ikev2_find_ike_notify_payload + ((ike_header_t *) sa->last_sa_init_req_packet_data, + IKEV2_NOTIFY_MSG_NAT_DETECTION_SOURCE_IP); + if (np) + { + nat_sha = + ikev2_compute_nat_sha1 (clib_host_to_net_u64 (sa->ispi), + clib_host_to_net_u64 (sa->rspi), + &sa->iaddr, + clib_host_to_net_u16 (IKEV2_PORT)); + clib_memcpy_fast (np, nat_sha, vec_len (nat_sha)); + vec_free (nat_sha); + } } if (vlib_buffer_alloc (km->vlib_main, &bi0, 1) != 1) @@ -4864,13 +4949,14 @@ 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); - sa->last_init_msg_id = clib_net_to_host_u32 (ike0->msgid); + ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id); + ike0->flags = 0; + sa->last_init_msg_id += 1; len = ikev2_generate_message (b0, sa, ike0, 0, 0); if (~0 == len) return; - if (sa->natt) + if (ikev2_natt_active (sa)) len = ikev2_insert_non_esp_marker (ike0, len); if (sa->is_initiator) @@ -4889,6 +4975,13 @@ ikev2_send_informational_request (ikev2_sa_t * sa) sa->sw_if_index); } +void +ikev2_disable_dpd (void) +{ + ikev2_main_t *km = &ikev2_main; + km->dpd_disabled = 1; +} + static_always_inline int ikev2_mngr_process_responder_sas (ikev2_sa_t * sa) { @@ -4924,8 +5017,7 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, while (1) { - u8 req_sent = 0; - vlib_process_wait_for_event_or_clock (vm, 1); + vlib_process_wait_for_event_or_clock (vm, 2); vlib_process_get_events (vm, NULL); /* process ike child sas */ @@ -4952,11 +5044,9 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, sa->old_id_expiration -= 1; vec_foreach (c, sa->childs) - { - req_sent |= ikev2_mngr_process_child_sa(sa, c, del_old_ids); - } + ikev2_mngr_process_child_sa(sa, c, del_old_ids); - if (ikev2_mngr_process_responder_sas (sa)) + if (!km->dpd_disabled && ikev2_mngr_process_responder_sas (sa)) vec_add1 (to_be_deleted, sa - tkm->sas); })); /* *INDENT-ON* */ @@ -4979,7 +5069,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); + } } } } @@ -4995,14 +5090,6 @@ ikev2_mngr_process_fn (vlib_main_t * vm, vlib_node_runtime_t * rt, /* *INDENT-ON* */ ikev2_process_pending_sa_init (km); - - if (req_sent) - { - vlib_process_wait_for_event_or_clock (vm, 5); - vlib_process_get_events (vm, NULL); - req_sent = 0; - } - } return 0; }