X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fplugins%2Fnat%2Fout2in.c;h=4589c48aef6463deadcb86a5d81474f7c3a266f5;hb=204591d1bd754f6086edcf8b27a95beab929a78f;hp=b5464e0ad410a6d66361370537d4c1cff7c67643;hpb=b932d26ea48ba8aa7677dc3b6ffd5d4729176c8f;p=vpp.git diff --git a/src/plugins/nat/out2in.c b/src/plugins/nat/out2in.c index b5464e0ad41..4589c48aef6 100755 --- a/src/plugins/nat/out2in.c +++ b/src/plugins/nat/out2in.c @@ -264,6 +264,90 @@ snat_out2in_error_t icmp_get_key(ip4_header_t *ip0, return -1; /* success */ } +static_always_inline int +icmp_get_ed_key(ip4_header_t *ip0, nat_ed_ses_key_t *p_key0) +{ + icmp46_header_t *icmp0; + nat_ed_ses_key_t key0; + icmp_echo_header_t *echo0, *inner_echo0 = 0; + ip4_header_t *inner_ip0; + void *l4_header = 0; + icmp46_header_t *inner_icmp0; + + icmp0 = (icmp46_header_t *) ip4_next_header (ip0); + echo0 = (icmp_echo_header_t *)(icmp0+1); + + if (!icmp_is_error_message (icmp0)) + { + key0.proto = IP_PROTOCOL_ICMP; + key0.l_addr = ip0->dst_address; + key0.r_addr = ip0->src_address; + key0.l_port = key0.r_port = echo0->identifier; + } + else + { + inner_ip0 = (ip4_header_t *)(echo0+1); + l4_header = ip4_next_header (inner_ip0); + key0.proto = inner_ip0->protocol; + key0.l_addr = inner_ip0->src_address; + key0.r_addr = inner_ip0->dst_address; + switch (ip_proto_to_snat_proto (inner_ip0->protocol)) + { + case SNAT_PROTOCOL_ICMP: + inner_icmp0 = (icmp46_header_t*)l4_header; + inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1); + key0.l_port = key0.r_port = inner_echo0->identifier; + break; + case SNAT_PROTOCOL_UDP: + case SNAT_PROTOCOL_TCP: + key0.l_port = ((tcp_udp_header_t*)l4_header)->src_port; + key0.r_port = ((tcp_udp_header_t*)l4_header)->dst_port; + break; + default: + return -1; + } + } + *p_key0 = key0; + return 0; +} + +static void +create_bypass_for_fwd(snat_main_t * sm, ip4_header_t * ip) +{ + nat_ed_ses_key_t key; + clib_bihash_kv_16_8_t kv; + udp_header_t *udp; + + if (ip->protocol == IP_PROTOCOL_ICMP) + { + if (icmp_get_ed_key (ip, &key)) + return; + } + else if (ip->protocol == IP_PROTOCOL_UDP || ip->protocol == IP_PROTOCOL_TCP) + { + udp = ip4_next_header(ip); + key.r_addr = ip->src_address; + key.l_addr = ip->dst_address; + key.proto = ip->protocol; + key.l_port = udp->dst_port; + key.r_port = udp->src_port; + } + else + { + key.r_addr = ip->src_address; + key.l_addr = ip->dst_address; + key.proto = ip->protocol; + key.l_port = key.r_port = 0; + } + key.fib_index = 0; + kv.key[0] = key.as_u64[0]; + kv.key[1] = key.as_u64[1]; + kv.value = ~0ULL; + + if (clib_bihash_add_del_16_8 (&sm->in2out_ed, &kv, 1)) + clib_warning ("in2out_ed key add failed"); +} + /** * Get address and port values to be used for ICMP packet translation * and create session if needed @@ -320,16 +404,25 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, destination address and port in packet */ if (snat_static_mapping_match(sm, key0, &sm0, 1, &is_addr_only, 0)) { - /* Don't NAT packet aimed at the intfc address */ - if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0, - ip0->dst_address.as_u32))) + if (!sm->forwarding_enabled) + { + /* Don't NAT packet aimed at the intfc address */ + if (PREDICT_FALSE(is_interface_addr(sm, node, sw_if_index0, + ip0->dst_address.as_u32))) + { + dont_translate = 1; + goto out; + } + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto out; + } + else { + create_bypass_for_fwd(sm, ip0); dont_translate = 1; goto out; } - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - next0 = SNAT_OUT2IN_NEXT_DROP; - goto out; } if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply && @@ -361,8 +454,34 @@ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, goto out; } - s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, - value0.value); + if (PREDICT_FALSE (value0.value == ~0ULL)) + { + nat_ed_ses_key_t key; + clib_bihash_kv_16_8_t s_kv, s_value; + + key.as_u64[0] = 0; + key.as_u64[1] = 0; + if (icmp_get_ed_key (ip0, &key)) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto out; + } + key.fib_index = rx_fib_index0; + s_kv.key[0] = key.as_u64[0]; + s_kv.key[1] = key.as_u64[1]; + if (!clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value)) + s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, + s_value.value); + else + { + next0 = SNAT_OUT2IN_NEXT_DROP; + goto out; + } + } + else + s0 = pool_elt_at_index (sm->per_thread_data[thread_index].sessions, + value0.value); } out: @@ -1017,16 +1136,28 @@ snat_out2in_node_fn (vlib_main_t * vm, destination address and port in packet */ if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0)) { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - /* - * Send DHCP packets to the ipv4 stack, or we won't - * be able to use dhcp client on the outside interface - */ - if (proto0 != SNAT_PROTOCOL_UDP - || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) - next0 = SNAT_OUT2IN_NEXT_DROP; - goto trace0; + if (!sm->forwarding_enabled) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + /* + * Send DHCP packets to the ipv4 stack, or we won't + * be able to use dhcp client on the outside interface + */ + if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP + || (udp0->dst_port + != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) + next0 = SNAT_OUT2IN_NEXT_DROP; + else + vnet_feature_next + (vnet_buffer (b0)->sw_if_index[VLIB_RX], + &next0, b0); + goto trace0; + } + else + { + create_bypass_for_fwd(sm, ip0); + goto trace0; + } } /* Create session initiated by host from external network */ @@ -1175,16 +1306,28 @@ snat_out2in_node_fn (vlib_main_t * vm, destination address and port in packet */ if (snat_static_mapping_match(sm, key1, &sm1, 1, 0, 0)) { - b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - /* - * Send DHCP packets to the ipv4 stack, or we won't - * be able to use dhcp client on the outside interface - */ - if (proto1 != SNAT_PROTOCOL_UDP - || (udp1->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) - next1 = SNAT_OUT2IN_NEXT_DROP; - goto trace1; + if (!sm->forwarding_enabled) + { + b1->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + /* + * Send DHCP packets to the ipv4 stack, or we won't + * be able to use dhcp client on the outside interface + */ + if (PREDICT_TRUE (proto1 != SNAT_PROTOCOL_UDP + || (udp1->dst_port + != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) + next1 = SNAT_OUT2IN_NEXT_DROP; + else + vnet_feature_next + (vnet_buffer (b1)->sw_if_index[VLIB_RX], + &next1, b1); + goto trace1; + } + else + { + create_bypass_for_fwd(sm, ip1); + goto trace1; + } } /* Create session initiated by host from external network */ @@ -1369,17 +1512,28 @@ snat_out2in_node_fn (vlib_main_t * vm, destination address and port in packet */ if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0)) { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - /* - * Send DHCP packets to the ipv4 stack, or we won't - * be able to use dhcp client on the outside interface - */ - if (proto0 != SNAT_PROTOCOL_UDP - || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) - - next0 = SNAT_OUT2IN_NEXT_DROP; - goto trace00; + if (!sm->forwarding_enabled) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + /* + * Send DHCP packets to the ipv4 stack, or we won't + * be able to use dhcp client on the outside interface + */ + if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP + || (udp0->dst_port + != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) + next0 = SNAT_OUT2IN_NEXT_DROP; + else + vnet_feature_next + (vnet_buffer (b0)->sw_if_index[VLIB_RX], + &next0, b0); + goto trace00; + } + else + { + create_bypass_for_fwd(sm, ip0); + goto trace00; + } } /* Create session initiated by host from external network */ @@ -1605,17 +1759,28 @@ nat44_out2in_reass_node_fn (vlib_main_t * vm, destination address and port in packet */ if (snat_static_mapping_match(sm, key0, &sm0, 1, 0, 0)) { - b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; - /* - * Send DHCP packets to the ipv4 stack, or we won't - * be able to use dhcp client on the outside interface - */ - if (proto0 != SNAT_PROTOCOL_UDP - || (udp0->dst_port - != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client))) - - next0 = SNAT_OUT2IN_NEXT_DROP; - goto trace0; + if (!sm->forwarding_enabled) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + /* + * Send DHCP packets to the ipv4 stack, or we won't + * be able to use dhcp client on the outside interface + */ + if (PREDICT_TRUE (proto0 != SNAT_PROTOCOL_UDP + || (udp0->dst_port + != clib_host_to_net_u16(UDP_DST_PORT_dhcp_to_client)))) + next0 = SNAT_OUT2IN_NEXT_DROP; + else + vnet_feature_next + (vnet_buffer (b0)->sw_if_index[VLIB_RX], + &next0, b0); + goto trace0; + } + else + { + create_bypass_for_fwd(sm, ip0); + goto trace0; + } } /* Create session initiated by host from external network */