diff options
author | Juraj Sloboda <jsloboda@cisco.com> | 2017-04-03 08:43:58 +0200 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2017-04-11 20:38:20 +0000 |
commit | 7a1bde061a919af42645e3bc09206b98fbfde9d9 (patch) | |
tree | c552d142eabbcce376928fb8ab67345083d2ccd5 /src/plugins/snat | |
parent | 9f171f5e20d4f30316626987a3dc66c9730e6d73 (diff) |
Add ICMP support for deterministic NAT
Change-Id: I9a6bcb7d173a2c13d89784e7ff8a6e42dcee201f
Signed-off-by: Juraj Sloboda <jsloboda@cisco.com>
Diffstat (limited to 'src/plugins/snat')
-rw-r--r-- | src/plugins/snat/in2out.c | 214 | ||||
-rw-r--r-- | src/plugins/snat/out2in.c | 205 | ||||
-rw-r--r-- | src/plugins/snat/snat.c | 2 | ||||
-rw-r--r-- | src/plugins/snat/snat.h | 19 |
4 files changed, 414 insertions, 26 deletions
diff --git a/src/plugins/snat/in2out.c b/src/plugins/snat/in2out.c index f5443762336..89054a01b64 100644 --- a/src/plugins/snat/in2out.c +++ b/src/plugins/snat/in2out.c @@ -472,11 +472,12 @@ snat_in2out_error_t icmp_get_key(ip4_header_t *ip0, * @param[out] p_value address and port after NAT translation * @param[out] p_dont_translate if packet should not be translated * @param d optional parameter + * @param e optional parameter */ u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, snat_session_key_t *p_value, - u8 *p_dont_translate, void *d) + u8 *p_dont_translate, void *d, void *e) { ip4_header_t *ip0; icmp46_header_t *icmp0; @@ -559,11 +560,12 @@ out: * @param[out] p_value address and port after NAT translation * @param[out] p_dont_translate if packet should not be translated * @param d optional parameter + * @param e optional parameter */ u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, snat_session_key_t *p_value, - u8 *p_dont_translate, void *d) + u8 *p_dont_translate, void *d, void *e) { ip4_header_t *ip0; icmp46_header_t *icmp0; @@ -637,7 +639,8 @@ static inline u32 icmp_in2out (snat_main_t *sm, vlib_node_runtime_t * node, u32 next0, u32 thread_index, - void *d) + void *d, + void *e) { snat_session_key_t sm0; u8 protocol; @@ -655,7 +658,7 @@ static inline u32 icmp_in2out (snat_main_t *sm, echo0 = (icmp_echo_header_t *)(icmp0+1); next0_tmp = sm->icmp_match_in2out_cb(sm, node, thread_index, b0, - &protocol, &sm0, &dont_translate, d); + &protocol, &sm0, &dont_translate, d, e); if (next0_tmp != ~0) next0 = next0_tmp; if (next0 == SNAT_IN2OUT_NEXT_DROP || dont_translate) @@ -864,7 +867,7 @@ static inline u32 icmp_in2out_slow_path (snat_main_t *sm, snat_session_t ** p_s0) { next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, thread_index, p_s0); + next0, thread_index, p_s0, 0); snat_session_t * s0 = *p_s0; if (PREDICT_TRUE(next0 != SNAT_IN2OUT_NEXT_DROP && s0)) { @@ -1508,6 +1511,7 @@ snat_det_in2out_node_fn (vlib_main_t * vm, u32 pkts_processed = 0; snat_main_t * sm = &snat_main; u32 now = (u32) vlib_time_now (vm); + u32 thread_index = os_get_cpu_number (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -1537,6 +1541,8 @@ snat_det_in2out_node_fn (vlib_main_t * vm, snat_det_out_key_t key0, key1; snat_det_map_t * dm0, * dm1; snat_det_session_t * ses0 = 0, * ses1 = 0; + u32 rx_fib_index0, rx_fib_index1; + icmp46_header_t * icmp0, * icmp1; /* Prefetch next iteration. */ { @@ -1582,6 +1588,19 @@ snat_det_in2out_node_fn (vlib_main_t * vm, goto trace0; } + proto0 = ip_proto_to_snat_proto (ip0->protocol); + + if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP)) + { + rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); + icmp0 = (icmp46_header_t *) udp0; + + next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, + rx_fib_index0, node, next0, thread_index, + &ses0, &dm0); + goto trace0; + } + dm0 = snat_det_map_by_user(sm, &ip0->src_address); if (PREDICT_FALSE(!dm0)) { @@ -1619,7 +1638,6 @@ snat_det_in2out_node_fn (vlib_main_t * vm, } new_port0 = ses0->out.out_port; - proto0 = ip_proto_to_snat_proto (ip0->protocol); old_addr0.as_u32 = ip0->src_address.as_u32; ip0->src_address.as_u32 = new_addr0.as_u32; @@ -1714,6 +1732,19 @@ snat_det_in2out_node_fn (vlib_main_t * vm, goto trace1; } + proto1 = ip_proto_to_snat_proto (ip1->protocol); + + if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP)) + { + rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1); + icmp1 = (icmp46_header_t *) udp1; + + next1 = icmp_in2out(sm, b1, ip1, icmp1, sw_if_index1, + rx_fib_index1, node, next1, thread_index, + &ses1, &dm1); + goto trace1; + } + dm1 = snat_det_map_by_user(sm, &ip1->src_address); if (PREDICT_FALSE(!dm1)) { @@ -1751,7 +1782,6 @@ snat_det_in2out_node_fn (vlib_main_t * vm, } new_port1 = ses1->out.out_port; - proto1 = ip_proto_to_snat_proto (ip1->protocol); old_addr1.as_u32 = ip1->src_address.as_u32; ip1->src_address.as_u32 = new_addr1.as_u32; @@ -1852,6 +1882,8 @@ snat_det_in2out_node_fn (vlib_main_t * vm, snat_det_out_key_t key0; snat_det_map_t * dm0; snat_det_session_t * ses0 = 0; + u32 rx_fib_index0; + icmp46_header_t * icmp0; /* speculatively enqueue b0 to the current next frame */ bi0 = from[0]; @@ -1880,6 +1912,19 @@ snat_det_in2out_node_fn (vlib_main_t * vm, goto trace00; } + proto0 = ip_proto_to_snat_proto (ip0->protocol); + + if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP)) + { + rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); + icmp0 = (icmp46_header_t *) udp0; + + next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, + rx_fib_index0, node, next0, thread_index, + &ses0, &dm0); + goto trace00; + } + dm0 = snat_det_map_by_user(sm, &ip0->src_address); if (PREDICT_FALSE(!dm0)) { @@ -1917,7 +1962,6 @@ snat_det_in2out_node_fn (vlib_main_t * vm, } new_port0 = ses0->out.out_port; - proto0 = ip_proto_to_snat_proto (ip0->protocol); old_addr0.as_u32 = ip0->src_address.as_u32; ip0->src_address.as_u32 = new_addr0.as_u32; @@ -2035,6 +2079,158 @@ VLIB_REGISTER_NODE (snat_det_in2out_node) = { VLIB_NODE_FUNCTION_MULTIARCH (snat_det_in2out_node, snat_det_in2out_node_fn); +/** + * Get address and port values to be used for packet SNAT translation + * and create session if needed + * + * @param[in,out] sm SNAT main + * @param[in,out] node SNAT node runtime + * @param[in] thread_index thread index + * @param[in,out] b0 buffer containing packet to be translated + * @param[out] p_proto protocol used for matching + * @param[out] p_value address and port after NAT translation + * @param[out] p_dont_translate if packet should not be translated + * @param d optional parameter + * @param e optional parameter + */ +u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node, + u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, + snat_session_key_t *p_value, + u8 *p_dont_translate, void *d, void *e) +{ + ip4_header_t *ip0; + icmp46_header_t *icmp0; + u32 sw_if_index0; + u32 rx_fib_index0; + u8 protocol; + snat_det_out_key_t key0; + u8 dont_translate = 0; + u32 next0 = ~0; + icmp_echo_header_t *echo0, *inner_echo0 = 0; + ip4_header_t *inner_ip0; + void *l4_header = 0; + icmp46_header_t *inner_icmp0; + snat_det_map_t * dm0 = 0; + ip4_address_t new_addr0; + u16 lo_port0, i0; + snat_det_session_t * ses0 = 0; + ip4_address_t in_addr; + u16 in_port; + + ip0 = vlib_buffer_get_current (b0); + icmp0 = (icmp46_header_t *) ip4_next_header (ip0); + echo0 = (icmp_echo_header_t *)(icmp0+1); + sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0); + + if (!icmp_is_error_message (icmp0)) + { + protocol = SNAT_PROTOCOL_ICMP; + in_addr = ip0->src_address; + in_port = echo0->identifier; + } + else + { + inner_ip0 = (ip4_header_t *)(echo0+1); + l4_header = ip4_next_header (inner_ip0); + protocol = ip_proto_to_snat_proto (inner_ip0->protocol); + in_addr = inner_ip0->dst_address; + switch (protocol) + { + case SNAT_PROTOCOL_ICMP: + inner_icmp0 = (icmp46_header_t*)l4_header; + inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1); + in_port = inner_echo0->identifier; + break; + case SNAT_PROTOCOL_UDP: + case SNAT_PROTOCOL_TCP: + in_port = ((tcp_udp_header_t*)l4_header)->dst_port; + break; + default: + b0->error = node->errors[SNAT_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL]; + next0 = SNAT_IN2OUT_NEXT_DROP; + goto out; + } + } + + dm0 = snat_det_map_by_user(sm, &in_addr); + if (PREDICT_FALSE(!dm0)) + { + clib_warning("no match for internal host %U", + format_ip4_address, &in_addr); + if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0, + IP_PROTOCOL_ICMP, rx_fib_index0))) + { + dont_translate = 1; + goto out; + } + next0 = SNAT_IN2OUT_NEXT_DROP; + b0->error = node->errors[SNAT_IN2OUT_ERROR_NO_TRANSLATION]; + goto out; + } + + snat_det_forward(dm0, &in_addr, &new_addr0, &lo_port0); + + ses0 = snat_det_find_ses_by_in(dm0, &in_addr, in_port); + if (PREDICT_FALSE(!ses0)) + { + if (PREDICT_FALSE(snat_not_translate_fast(sm, node, sw_if_index0, ip0, + IP_PROTOCOL_ICMP, rx_fib_index0))) + { + dont_translate = 1; + goto out; + } + if (icmp0->type != ICMP4_echo_request) + { + b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE]; + next0 = SNAT_IN2OUT_NEXT_DROP; + goto out; + } + key0.ext_host_addr = ip0->dst_address; + key0.ext_host_port = 0; + for (i0 = 0; i0 < dm0->ports_per_host; i0++) + { + key0.out_port = clib_host_to_net_u16 (lo_port0 + + ((i0 + clib_net_to_host_u16 (echo0->identifier)) % dm0->ports_per_host)); + + if (snat_det_get_ses_by_out (dm0, &in_addr, key0.as_u64)) + continue; + + ses0 = snat_det_ses_create(dm0, &in_addr, echo0->identifier, &key0); + break; + } + if (PREDICT_FALSE(!ses0)) + { + next0 = SNAT_IN2OUT_NEXT_DROP; + b0->error = node->errors[SNAT_IN2OUT_ERROR_OUT_OF_PORTS]; + goto out; + } + } + + if (PREDICT_FALSE(icmp0->type != ICMP4_echo_request && + !icmp_is_error_message (icmp0))) + { + b0->error = node->errors[SNAT_IN2OUT_ERROR_BAD_ICMP_TYPE]; + next0 = SNAT_IN2OUT_NEXT_DROP; + goto out; + } + +out: + *p_proto = protocol; + if (ses0) + { + p_value->addr = new_addr0; + p_value->fib_index = sm->outside_fib_index; + p_value->port = ses0->out.out_port; + } + *p_dont_translate = dont_translate; + if (d) + *(snat_det_session_t**)d = ses0; + if (e) + *(snat_det_map_t**)e = dm0; + return next0; +} + /**********************/ /*** worker handoff ***/ /**********************/ @@ -2276,7 +2472,7 @@ snat_in2out_fast_static_map_fn (vlib_main_t * vm, if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) { next0 = icmp_in2out(sm, b0, ip0, icmp0, sw_if_index0, - rx_fib_index0, node, next0, ~0, 0); + rx_fib_index0, node, next0, ~0, 0, 0); goto trace0; } diff --git a/src/plugins/snat/out2in.c b/src/plugins/snat/out2in.c index 447605bab48..f9f8defa90f 100644 --- a/src/plugins/snat/out2in.c +++ b/src/plugins/snat/out2in.c @@ -283,11 +283,12 @@ snat_out2in_error_t icmp_get_key(ip4_header_t *ip0, * @param[out] p_value address and port after NAT translation * @param[out] p_dont_translate if packet should not be translated * @param d optional parameter + * @param e optional parameter */ u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, snat_session_key_t *p_value, - u8 *p_dont_translate, void *d) + u8 *p_dont_translate, void *d, void *e) { ip4_header_t *ip0; icmp46_header_t *icmp0; @@ -384,11 +385,12 @@ out: * @param[out] p_value address and port after NAT translation * @param[out] p_dont_translate if packet should not be translated * @param d optional parameter + * @param e optional parameter */ u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, snat_session_key_t *p_value, - u8 *p_dont_translate, void *d) + u8 *p_dont_translate, void *d, void *e) { ip4_header_t *ip0; icmp46_header_t *icmp0; @@ -455,7 +457,8 @@ static inline u32 icmp_out2in (snat_main_t *sm, vlib_node_runtime_t * node, u32 next0, u32 thread_index, - void *d) + void *d, + void *e) { snat_session_key_t sm0; u8 protocol; @@ -473,7 +476,7 @@ static inline u32 icmp_out2in (snat_main_t *sm, echo0 = (icmp_echo_header_t *)(icmp0+1); next0_tmp = sm->icmp_match_out2in_cb(sm, node, thread_index, b0, - &protocol, &sm0, &dont_translate, d); + &protocol, &sm0, &dont_translate, d, e); if (next0_tmp != ~0) next0 = next0_tmp; if (next0 == SNAT_OUT2IN_NEXT_DROP || dont_translate) @@ -580,7 +583,7 @@ static inline u32 icmp_out2in_slow_path (snat_main_t *sm, snat_session_t ** p_s0) { next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, - next0, thread_index, p_s0); + next0, thread_index, p_s0, 0); snat_session_t * s0 = *p_s0; if (PREDICT_TRUE(next0 != SNAT_OUT2IN_NEXT_DROP && s0)) { @@ -1160,6 +1163,7 @@ snat_det_out2in_node_fn (vlib_main_t * vm, snat_out2in_next_t next_index; u32 pkts_processed = 0; snat_main_t * sm = &snat_main; + u32 thread_index = os_get_cpu_number (); from = vlib_frame_vector_args (frame); n_left_from = frame->n_vectors; @@ -1189,6 +1193,8 @@ snat_det_out2in_node_fn (vlib_main_t * vm, snat_det_out_key_t key0, key1; snat_det_map_t * dm0, * dm1; snat_det_session_t * ses0 = 0, * ses1 = 0; + u32 rx_fib_index0, rx_fib_index1; + icmp46_header_t * icmp0, * icmp1; /* Prefetch next iteration. */ { @@ -1231,6 +1237,19 @@ snat_det_out2in_node_fn (vlib_main_t * vm, goto trace0; } + proto0 = ip_proto_to_snat_proto (ip0->protocol); + + if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP)) + { + rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); + icmp0 = (icmp46_header_t *) udp0; + + next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, + rx_fib_index0, node, next0, thread_index, + &ses0, &dm0); + goto trace0; + } + key0.ext_host_addr = ip0->src_address; key0.ext_host_port = tcp0->src; key0.out_port = tcp0->dst; @@ -1263,8 +1282,6 @@ snat_det_out2in_node_fn (vlib_main_t * vm, } new_port0 = ses0->in_port; - proto0 = ip_proto_to_snat_proto (ip0->protocol); - old_addr0 = ip0->dst_address; ip0->dst_address = new_addr0; vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index; @@ -1336,6 +1353,19 @@ snat_det_out2in_node_fn (vlib_main_t * vm, goto trace1; } + proto1 = ip_proto_to_snat_proto (ip1->protocol); + + if (PREDICT_FALSE(proto1 == SNAT_PROTOCOL_ICMP)) + { + rx_fib_index1 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index1); + icmp1 = (icmp46_header_t *) udp1; + + next1 = icmp_out2in(sm, b1, ip1, icmp1, sw_if_index1, + rx_fib_index1, node, next1, thread_index, + &ses1, &dm1); + goto trace1; + } + key1.ext_host_addr = ip1->src_address; key1.ext_host_port = tcp1->src; key1.out_port = tcp1->dst; @@ -1368,8 +1398,6 @@ snat_det_out2in_node_fn (vlib_main_t * vm, } new_port1 = ses1->in_port; - proto1 = ip_proto_to_snat_proto (ip1->protocol); - old_addr1 = ip1->dst_address; ip1->dst_address = new_addr1; vnet_buffer(b1)->sw_if_index[VLIB_TX] = sm->inside_fib_index; @@ -1445,6 +1473,8 @@ snat_det_out2in_node_fn (vlib_main_t * vm, snat_det_out_key_t key0; snat_det_map_t * dm0; snat_det_session_t * ses0 = 0; + u32 rx_fib_index0; + icmp46_header_t * icmp0; /* speculatively enqueue b0 to the current next frame */ bi0 = from[0]; @@ -1472,6 +1502,19 @@ snat_det_out2in_node_fn (vlib_main_t * vm, goto trace00; } + proto0 = ip_proto_to_snat_proto (ip0->protocol); + + if (PREDICT_FALSE(proto0 == SNAT_PROTOCOL_ICMP)) + { + rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index(sw_if_index0); + icmp0 = (icmp46_header_t *) udp0; + + next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, + rx_fib_index0, node, next0, thread_index, + &ses0, &dm0); + goto trace00; + } + key0.ext_host_addr = ip0->src_address; key0.ext_host_port = tcp0->src; key0.out_port = tcp0->dst; @@ -1504,8 +1547,6 @@ snat_det_out2in_node_fn (vlib_main_t * vm, } new_port0 = ses0->in_port; - proto0 = ip_proto_to_snat_proto (ip0->protocol); - old_addr0 = ip0->dst_address; ip0->dst_address = new_addr0; vnet_buffer(b0)->sw_if_index[VLIB_TX] = sm->inside_fib_index; @@ -1597,6 +1638,146 @@ VLIB_REGISTER_NODE (snat_det_out2in_node) = { }; VLIB_NODE_FUNCTION_MULTIARCH (snat_det_out2in_node, snat_det_out2in_node_fn); +/** + * Get address and port values to be used for packet SNAT translation + * and create session if needed + * + * @param[in,out] sm SNAT main + * @param[in,out] node SNAT node runtime + * @param[in] thread_index thread index + * @param[in,out] b0 buffer containing packet to be translated + * @param[out] p_proto protocol used for matching + * @param[out] p_value address and port after NAT translation + * @param[out] p_dont_translate if packet should not be translated + * @param d optional parameter + * @param e optional parameter + */ +u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, + u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, + snat_session_key_t *p_value, + u8 *p_dont_translate, void *d, void *e) +{ + ip4_header_t *ip0; + icmp46_header_t *icmp0; + u32 sw_if_index0; + u8 protocol; + snat_det_out_key_t key0; + u8 dont_translate = 0; + u32 next0 = ~0; + icmp_echo_header_t *echo0, *inner_echo0 = 0; + ip4_header_t *inner_ip0; + void *l4_header = 0; + icmp46_header_t *inner_icmp0; + snat_det_map_t * dm0 = 0; + ip4_address_t new_addr0 = {{0}}; + snat_det_session_t * ses0 = 0; + ip4_address_t out_addr; + + ip0 = vlib_buffer_get_current (b0); + icmp0 = (icmp46_header_t *) ip4_next_header (ip0); + echo0 = (icmp_echo_header_t *)(icmp0+1); + sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_RX]; + + if (!icmp_is_error_message (icmp0)) + { + protocol = SNAT_PROTOCOL_ICMP; + key0.ext_host_addr = ip0->src_address; + key0.ext_host_port = 0; + key0.out_port = echo0->identifier; + out_addr = ip0->dst_address; + } + else + { + inner_ip0 = (ip4_header_t *)(echo0+1); + l4_header = ip4_next_header (inner_ip0); + protocol = ip_proto_to_snat_proto (inner_ip0->protocol); + key0.ext_host_addr = inner_ip0->dst_address; + out_addr = inner_ip0->src_address; + switch (protocol) + { + case SNAT_PROTOCOL_ICMP: + inner_icmp0 = (icmp46_header_t*)l4_header; + inner_echo0 = (icmp_echo_header_t *)(inner_icmp0+1); + key0.ext_host_port = 0; + key0.out_port = inner_echo0->identifier; + break; + case SNAT_PROTOCOL_UDP: + case SNAT_PROTOCOL_TCP: + key0.ext_host_port = ((tcp_udp_header_t*)l4_header)->dst_port; + key0.out_port = ((tcp_udp_header_t*)l4_header)->src_port; + break; + default: + b0->error = node->errors[SNAT_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto out; + } + } + + dm0 = snat_det_map_by_out(sm, &out_addr); + if (PREDICT_FALSE(!dm0)) + { + /* 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; + } + clib_warning("unknown dst address: %U", + format_ip4_address, &ip0->dst_address); + goto out; + } + + snat_det_reverse(dm0, &ip0->dst_address, + clib_net_to_host_u16(key0.out_port), &new_addr0); + + ses0 = snat_det_get_ses_by_out (dm0, &new_addr0, key0.as_u64); + if (PREDICT_FALSE(!ses0)) + { + /* 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; + } + clib_warning("no match src %U:%d dst %U:%d for user %U", + format_ip4_address, &key0.ext_host_addr, + clib_net_to_host_u16 (key0.ext_host_port), + format_ip4_address, &out_addr, + clib_net_to_host_u16 (key0.out_port), + format_ip4_address, &new_addr0); + b0->error = node->errors[SNAT_OUT2IN_ERROR_NO_TRANSLATION]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto out; + } + + if (PREDICT_FALSE(icmp0->type != ICMP4_echo_reply && + !icmp_is_error_message (icmp0))) + { + b0->error = node->errors[SNAT_OUT2IN_ERROR_BAD_ICMP_TYPE]; + next0 = SNAT_OUT2IN_NEXT_DROP; + goto out; + } + + goto out; + +out: + *p_proto = protocol; + if (ses0) + { + p_value->addr = new_addr0; + p_value->fib_index = sm->inside_fib_index; + p_value->port = ses0->in_port; + } + *p_dont_translate = dont_translate; + if (d) + *(snat_det_session_t**)d = ses0; + if (e) + *(snat_det_map_t**)e = dm0; + return next0; +} + /**********************/ /*** worker handoff ***/ /**********************/ @@ -1836,7 +2017,7 @@ snat_out2in_fast_node_fn (vlib_main_t * vm, if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP)) { next0 = icmp_out2in(sm, b0, ip0, icmp0, sw_if_index0, - rx_fib_index0, node, next0, ~0, 0); + rx_fib_index0, node, next0, ~0, 0, 0); goto trace00; } diff --git a/src/plugins/snat/snat.c b/src/plugins/snat/snat.c index 70b6a6e285e..65d26b3cda2 100644 --- a/src/plugins/snat/snat.c +++ b/src/plugins/snat/snat.c @@ -2549,6 +2549,8 @@ snat_config (vlib_main_t * vm, unformat_input_t * input) { sm->in2out_node_index = snat_det_in2out_node.index; sm->out2in_node_index = snat_det_out2in_node.index; + sm->icmp_match_in2out_cb = icmp_match_in2out_det; + sm->icmp_match_out2in_cb = icmp_match_out2in_det; } else { diff --git a/src/plugins/snat/snat.h b/src/plugins/snat/snat.h index 92b2f7eae80..49b6e374968 100644 --- a/src/plugins/snat/snat.h +++ b/src/plugins/snat/snat.h @@ -226,7 +226,8 @@ typedef u32 snat_icmp_match_function_t (struct snat_main_s *sm, u8 *p_proto, snat_session_key_t *p_value, u8 *p_dont_translate, - void *d); + void *d, + void *e); typedef u32 (snat_get_worker_function_t) (ip4_header_t * ip, u32 rx_fib_index); @@ -404,19 +405,27 @@ typedef struct { u32 icmp_match_in2out_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, snat_session_key_t *p_value, - u8 *p_dont_translate, void *d); + u8 *p_dont_translate, void *d, void *e); u32 icmp_match_in2out_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, snat_session_key_t *p_value, - u8 *p_dont_translate, void *d); + u8 *p_dont_translate, void *d, void *e); +u32 icmp_match_in2out_det(snat_main_t *sm, vlib_node_runtime_t *node, + u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, + snat_session_key_t *p_value, + u8 *p_dont_translate, void *d, void *e); u32 icmp_match_out2in_fast(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, snat_session_key_t *p_value, - u8 *p_dont_translate, void *d); + u8 *p_dont_translate, void *d, void *e); u32 icmp_match_out2in_slow(snat_main_t *sm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, snat_session_key_t *p_value, - u8 *p_dont_translate, void *d); + u8 *p_dont_translate, void *d, void *e); +u32 icmp_match_out2in_det(snat_main_t *sm, vlib_node_runtime_t *node, + u32 thread_index, vlib_buffer_t *b0, u8 *p_proto, + snat_session_key_t *p_value, + u8 *p_dont_translate, void *d, void *e); static_always_inline u8 icmp_is_error_message (icmp46_header_t * icmp) |