2 * Copyright (c) 2020 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
18 * @brief Deterministic NAT (CGN) inside to outside translation
21 #include <vlib/vlib.h>
22 #include <vnet/vnet.h>
23 #include <vnet/ip/ip.h>
24 #include <vnet/fib/ip4_fib.h>
25 #include <vppinfra/error.h>
26 #include <vppinfra/elog.h>
28 #include <nat/det44/det44.h>
29 #include <nat/det44/det44_inlines.h>
31 #include <nat/lib/lib.h>
32 #include <nat/lib/inlines.h>
33 #include <nat/lib/nat_inlines.h>
37 DET44_IN2OUT_NEXT_LOOKUP,
38 DET44_IN2OUT_NEXT_DROP,
39 DET44_IN2OUT_NEXT_ICMP_ERROR,
41 } det44_in2out_next_t;
48 } det44_in2out_trace_t;
50 #define foreach_det44_in2out_error \
51 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
52 _(NO_TRANSLATION, "No translation") \
53 _(BAD_ICMP_TYPE, "unsupported ICMP type") \
54 _(OUT_OF_PORTS, "Out of ports") \
55 _(IN2OUT_PACKETS, "Good in2out packets processed")
59 #define _(sym,str) DET44_IN2OUT_ERROR_##sym,
60 foreach_det44_in2out_error
63 } det44_in2out_error_t;
65 static char *det44_in2out_error_strings[] = {
66 #define _(sym,string) string,
67 foreach_det44_in2out_error
72 format_det44_in2out_trace (u8 * s, va_list * args)
74 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
75 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
76 det44_in2out_trace_t *t = va_arg (*args, det44_in2out_trace_t *);
78 s = format (s, "DET44_IN2OUT: sw_if_index %d, next index %d, session %d",
79 t->sw_if_index, t->next_index, t->session_index);
84 #ifndef CLIB_MARCH_VARIANT
86 * Get address and port values to be used for ICMP packet translation
87 * and create session if needed
89 * @param[in,out] node NAT node runtime
90 * @param[in] thread_index thread index
91 * @param[in,out] b0 buffer containing packet to be translated
92 * @param[in,out] ip0 ip header
93 * @param[out] p_proto protocol used for matching
94 * @param[out] p_value address and port after NAT translation
95 * @param[out] p_dont_translate if packet should not be translated
96 * @param d optional parameter
97 * @param e optional parameter
100 icmp_match_in2out_det (vlib_node_runtime_t * node,
101 u32 thread_index, vlib_buffer_t * b0,
102 ip4_header_t * ip0, ip4_address_t * addr,
103 u16 * port, u32 * fib_index,
104 nat_protocol_t * proto, void *d, void *e,
107 det44_main_t *dm = &det44_main;
108 vlib_main_t *vm = vlib_get_main ();
109 icmp46_header_t *icmp0;
112 nat_protocol_t protocol;
113 snat_det_out_key_t key0;
115 icmp_echo_header_t *echo0, *inner_echo0 = 0;
116 ip4_header_t *inner_ip0;
118 icmp46_header_t *inner_icmp0;
119 snat_det_map_t *mp0 = 0;
120 ip4_address_t new_addr0;
122 snat_det_session_t *ses0 = 0;
123 ip4_address_t in_addr;
127 icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
128 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
129 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
130 rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
132 if (!icmp_type_is_error_message
133 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
135 protocol = NAT_PROTOCOL_ICMP;
136 in_addr = ip0->src_address;
137 in_port = vnet_buffer (b0)->ip.reass.l4_src_port;
141 /* if error message, then it's not fragmented and we can access it */
142 inner_ip0 = (ip4_header_t *) (echo0 + 1);
143 l4_header = ip4_next_header (inner_ip0);
144 protocol = ip_proto_to_nat_proto (inner_ip0->protocol);
145 in_addr = inner_ip0->dst_address;
148 case NAT_PROTOCOL_ICMP:
149 inner_icmp0 = (icmp46_header_t *) l4_header;
150 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
151 in_port = inner_echo0->identifier;
153 case NAT_PROTOCOL_UDP:
154 case NAT_PROTOCOL_TCP:
155 in_port = ((tcp_udp_header_t *) l4_header)->dst_port;
158 b0->error = node->errors[DET44_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
159 next0 = DET44_IN2OUT_NEXT_DROP;
164 mp0 = snat_det_map_by_user (&in_addr);
165 if (PREDICT_FALSE (!mp0))
167 if (PREDICT_FALSE (det44_translate (node, sw_if_index0, ip0,
168 IP_PROTOCOL_ICMP, rx_fib_index0)))
173 next0 = DET44_IN2OUT_NEXT_DROP;
174 b0->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
178 snat_det_forward (mp0, &in_addr, &new_addr0, &lo_port0);
180 key0.ext_host_addr = ip0->dst_address;
181 key0.ext_host_port = 0;
183 ses0 = snat_det_find_ses_by_in (mp0, &in_addr, in_port, key0);
184 if (PREDICT_FALSE (!ses0))
186 if (PREDICT_FALSE (det44_translate (node, sw_if_index0, ip0,
187 IP_PROTOCOL_ICMP, rx_fib_index0)))
192 if (icmp0->type != ICMP4_echo_request)
194 b0->error = node->errors[DET44_IN2OUT_ERROR_BAD_ICMP_TYPE];
195 next0 = DET44_IN2OUT_NEXT_DROP;
198 for (i0 = 0; i0 < mp0->ports_per_host; i0++)
200 key0.out_port = clib_host_to_net_u16 (lo_port0 +
203 (echo0->identifier)) %
204 mp0->ports_per_host));
206 if (snat_det_get_ses_by_out (mp0, &in_addr, key0.as_u64))
210 snat_det_ses_create (thread_index, mp0,
211 &in_addr, echo0->identifier, &key0);
214 if (PREDICT_FALSE (!ses0))
216 next0 = DET44_IN2OUT_NEXT_DROP;
217 b0->error = node->errors[DET44_IN2OUT_ERROR_OUT_OF_PORTS];
223 (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_request
224 && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
225 reass.icmp_type_or_tcp_flags)))
227 b0->error = node->errors[DET44_IN2OUT_ERROR_BAD_ICMP_TYPE];
228 next0 = DET44_IN2OUT_NEXT_DROP;
232 u32 now = (u32) vlib_time_now (vm);
234 ses0->state = DET44_SESSION_ICMP_ACTIVE;
235 ses0->expire = now + dm->timeouts.icmp;
242 *fib_index = dm->outside_fib_index;
243 *port = ses0->out.out_port;
246 *(snat_det_session_t **) d = ses0;
248 *(snat_det_map_t **) e = mp0;
253 #ifndef CLIB_MARCH_VARIANT
255 det44_icmp_in2out (vlib_buffer_t * b0,
257 icmp46_header_t * icmp0,
260 vlib_node_runtime_t * node,
261 u32 next0, u32 thread_index, void *d, void *e)
263 vlib_main_t *vm = vlib_get_main ();
264 u16 old_id0, new_id0, port, checksum0, old_checksum0, new_checksum0;
265 u32 new_addr0, old_addr0, next0_tmp, fib_index;
266 icmp_echo_header_t *echo0, *inner_echo0;
267 icmp46_header_t *inner_icmp0;
268 ip4_header_t *inner_ip0;
273 nat_protocol_t protocol;
275 echo0 = (icmp_echo_header_t *) (icmp0 + 1);
276 next0_tmp = icmp_match_in2out_det (node, thread_index, b0, ip0,
277 &addr, &port, &fib_index, &protocol,
278 d, e, &dont_translate);
281 if (next0 == DET44_IN2OUT_NEXT_DROP || dont_translate)
284 if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
287 ip_incremental_checksum_buffer (vm, b0,
289 (u8 *) vlib_buffer_get_current (b0),
290 ntohs (ip0->length) -
291 ip4_header_bytes (ip0), 0);
292 checksum0 = ~ip_csum_fold (sum0);
293 if (PREDICT_FALSE (checksum0 != 0 && checksum0 != 0xffff))
295 next0 = DET44_IN2OUT_NEXT_DROP;
300 old_addr0 = ip0->src_address.as_u32;
301 new_addr0 = ip0->src_address.as_u32 = addr.as_u32;
303 sum0 = ip0->checksum;
304 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
305 src_address /* changed member */ );
306 ip0->checksum = ip_csum_fold (sum0);
308 if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
310 if (icmp0->checksum == 0)
311 icmp0->checksum = 0xffff;
313 if (!icmp_type_is_error_message (icmp0->type))
316 if (PREDICT_FALSE (new_id0 != echo0->identifier))
318 old_id0 = echo0->identifier;
320 echo0->identifier = new_id0;
322 sum0 = icmp0->checksum;
324 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
326 icmp0->checksum = ip_csum_fold (sum0);
331 inner_ip0 = (ip4_header_t *) (echo0 + 1);
332 l4_header = ip4_next_header (inner_ip0);
334 if (!ip4_header_checksum_is_valid (inner_ip0))
336 next0 = DET44_IN2OUT_NEXT_DROP;
340 /* update inner destination IP address */
341 old_addr0 = inner_ip0->dst_address.as_u32;
342 inner_ip0->dst_address = addr;
343 new_addr0 = inner_ip0->dst_address.as_u32;
344 sum0 = icmp0->checksum;
345 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
346 dst_address /* changed member */ );
347 icmp0->checksum = ip_csum_fold (sum0);
349 /* update inner IP header checksum */
350 old_checksum0 = inner_ip0->checksum;
351 sum0 = inner_ip0->checksum;
352 sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
353 dst_address /* changed member */ );
354 inner_ip0->checksum = ip_csum_fold (sum0);
355 new_checksum0 = inner_ip0->checksum;
356 sum0 = icmp0->checksum;
358 ip_csum_update (sum0, old_checksum0, new_checksum0, ip4_header_t,
360 icmp0->checksum = ip_csum_fold (sum0);
364 case NAT_PROTOCOL_ICMP:
365 inner_icmp0 = (icmp46_header_t *) l4_header;
366 inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
368 old_id0 = inner_echo0->identifier;
370 inner_echo0->identifier = new_id0;
372 sum0 = icmp0->checksum;
374 ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
376 icmp0->checksum = ip_csum_fold (sum0);
378 case NAT_PROTOCOL_UDP:
379 case NAT_PROTOCOL_TCP:
380 old_id0 = ((tcp_udp_header_t *) l4_header)->dst_port;
382 ((tcp_udp_header_t *) l4_header)->dst_port = new_id0;
384 sum0 = icmp0->checksum;
385 sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
387 icmp0->checksum = ip_csum_fold (sum0);
395 if (vnet_buffer (b0)->sw_if_index[VLIB_TX] == ~0)
396 vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
402 VLIB_NODE_FN (det44_in2out_node) (vlib_main_t * vm,
403 vlib_node_runtime_t * node,
404 vlib_frame_t * frame)
406 u32 n_left_from, *from;
407 u32 pkts_processed = 0;
408 det44_main_t *dm = &det44_main;
409 u32 now = (u32) vlib_time_now (vm);
410 u32 thread_index = vm->thread_index;
412 from = vlib_frame_vector_args (frame);
413 n_left_from = frame->n_vectors;
415 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
416 u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
417 vlib_get_buffers (vm, from, b, n_left_from);
419 while (n_left_from >= 2)
421 vlib_buffer_t *b0, *b1;
423 u32 sw_if_index0, sw_if_index1;
424 ip4_header_t *ip0, *ip1;
425 ip_csum_t sum0, sum1;
426 ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
427 u16 old_port0, new_port0, lo_port0, i0;
428 u16 old_port1, new_port1, lo_port1, i1;
429 udp_header_t *udp0, *udp1;
430 tcp_header_t *tcp0, *tcp1;
432 snat_det_out_key_t key0, key1;
433 snat_det_map_t *mp0, *mp1;
434 snat_det_session_t *ses0 = 0, *ses1 = 0;
435 u32 rx_fib_index0, rx_fib_index1;
436 icmp46_header_t *icmp0, *icmp1;
443 /* Prefetch next iteration. */
444 if (PREDICT_TRUE (n_left_from >= 4))
446 vlib_buffer_t *p2, *p3;
451 vlib_prefetch_buffer_header (p2, LOAD);
452 vlib_prefetch_buffer_header (p3, LOAD);
454 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
455 CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, LOAD);
458 next0 = DET44_IN2OUT_NEXT_LOOKUP;
459 next1 = DET44_IN2OUT_NEXT_LOOKUP;
461 ip0 = vlib_buffer_get_current (b0);
462 udp0 = ip4_next_header (ip0);
463 tcp0 = (tcp_header_t *) udp0;
465 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
467 if (PREDICT_FALSE (ip0->ttl == 1))
469 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
470 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
471 ICMP4_time_exceeded_ttl_exceeded_in_transit,
473 next0 = DET44_IN2OUT_NEXT_ICMP_ERROR;
477 proto0 = ip_proto_to_nat_proto (ip0->protocol);
479 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
482 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
483 icmp0 = (icmp46_header_t *) udp0;
486 next0 = det44_icmp_in2out (b0, ip0, icmp0, sw_if_index0,
487 rx_fib_index0, node, next0,
488 thread_index, &ses0, &mp0);
492 mp0 = snat_det_map_by_user (&ip0->src_address);
493 if (PREDICT_FALSE (!mp0))
495 det44_log_info ("no match for internal host %U",
496 format_ip4_address, &ip0->src_address);
497 next0 = DET44_IN2OUT_NEXT_DROP;
498 b0->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
502 snat_det_forward (mp0, &ip0->src_address, &new_addr0, &lo_port0);
504 key0.ext_host_addr = ip0->dst_address;
505 key0.ext_host_port = tcp0->dst;
508 snat_det_find_ses_by_in (mp0, &ip0->src_address, tcp0->src, key0);
509 if (PREDICT_FALSE (!ses0))
511 for (i0 = 0; i0 < mp0->ports_per_host; i0++)
513 key0.out_port = clib_host_to_net_u16 (lo_port0 +
517 mp0->ports_per_host));
519 if (snat_det_get_ses_by_out
520 (mp0, &ip0->src_address, key0.as_u64))
524 snat_det_ses_create (thread_index, mp0, &ip0->src_address,
528 if (PREDICT_FALSE (!ses0))
530 /* too many sessions for user, send ICMP error packet */
531 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
532 icmp4_error_set_vnet_buffer (b0,
533 ICMP4_destination_unreachable,
534 ICMP4_destination_unreachable_destination_unreachable_host,
536 next0 = DET44_IN2OUT_NEXT_ICMP_ERROR;
541 old_port0 = udp0->src_port;
542 udp0->src_port = new_port0 = ses0->out.out_port;
544 old_addr0.as_u32 = ip0->src_address.as_u32;
545 ip0->src_address.as_u32 = new_addr0.as_u32;
546 vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->outside_fib_index;
548 sum0 = ip0->checksum;
549 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
550 ip4_header_t, src_address /* changed member */ );
551 ip0->checksum = ip_csum_fold (sum0);
553 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
555 if (tcp0->flags & TCP_FLAG_SYN)
556 ses0->state = DET44_SESSION_TCP_SYN_SENT;
557 else if (tcp0->flags & TCP_FLAG_ACK
558 && ses0->state == DET44_SESSION_TCP_SYN_SENT)
559 ses0->state = DET44_SESSION_TCP_ESTABLISHED;
560 else if (tcp0->flags & TCP_FLAG_FIN
561 && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
562 ses0->state = DET44_SESSION_TCP_FIN_WAIT;
563 else if (tcp0->flags & TCP_FLAG_ACK
564 && ses0->state == DET44_SESSION_TCP_FIN_WAIT)
565 snat_det_ses_close (mp0, ses0);
566 else if (tcp0->flags & TCP_FLAG_FIN
567 && ses0->state == DET44_SESSION_TCP_CLOSE_WAIT)
568 ses0->state = DET44_SESSION_TCP_LAST_ACK;
569 else if (tcp0->flags == 0 && ses0->state == DET44_SESSION_UNKNOWN)
570 ses0->state = DET44_SESSION_TCP_ESTABLISHED;
572 sum0 = tcp0->checksum;
573 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
575 dst_address /* changed member */ );
576 sum0 = ip_csum_update (sum0, old_port0, new_port0,
577 ip4_header_t /* cheat */ ,
578 length /* changed member */ );
579 mss_clamping (dm->mss_clamping, tcp0, &sum0);
580 tcp0->checksum = ip_csum_fold (sum0);
584 ses0->state = DET44_SESSION_UDP_ACTIVE;
586 if (PREDICT_FALSE (udp0->checksum))
588 sum0 = udp0->checksum;
590 ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
592 dst_address /* changed member */ );
594 ip_csum_update (sum0, old_port0, new_port0,
595 ip4_header_t /* cheat */ ,
596 length /* changed member */ );
597 udp0->checksum = ip_csum_fold (sum0);
603 case DET44_SESSION_UDP_ACTIVE:
604 ses0->expire = now + dm->timeouts.udp;
606 case DET44_SESSION_TCP_SYN_SENT:
607 case DET44_SESSION_TCP_FIN_WAIT:
608 case DET44_SESSION_TCP_CLOSE_WAIT:
609 case DET44_SESSION_TCP_LAST_ACK:
610 ses0->expire = now + dm->timeouts.tcp.transitory;
612 case DET44_SESSION_TCP_ESTABLISHED:
613 ses0->expire = now + dm->timeouts.tcp.established;
618 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
619 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
621 det44_in2out_trace_t *t =
622 vlib_add_trace (vm, node, b0, sizeof (*t));
623 t->sw_if_index = sw_if_index0;
624 t->next_index = next0;
625 t->session_index = ~0;
627 t->session_index = ses0 - mp0->sessions;
630 pkts_processed += next0 != DET44_IN2OUT_NEXT_DROP;
632 ip1 = vlib_buffer_get_current (b1);
633 udp1 = ip4_next_header (ip1);
634 tcp1 = (tcp_header_t *) udp1;
636 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
638 if (PREDICT_FALSE (ip1->ttl == 1))
640 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
641 icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
642 ICMP4_time_exceeded_ttl_exceeded_in_transit,
644 next1 = DET44_IN2OUT_NEXT_ICMP_ERROR;
648 proto1 = ip_proto_to_nat_proto (ip1->protocol);
650 if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
653 ip4_fib_table_get_index_for_sw_if_index (sw_if_index1);
654 icmp1 = (icmp46_header_t *) udp1;
656 next1 = det44_icmp_in2out (b1, ip1, icmp1, sw_if_index1,
657 rx_fib_index1, node, next1,
658 thread_index, &ses1, &mp1);
662 mp1 = snat_det_map_by_user (&ip1->src_address);
663 if (PREDICT_FALSE (!mp1))
665 det44_log_info ("no match for internal host %U",
666 format_ip4_address, &ip0->src_address);
667 next1 = DET44_IN2OUT_NEXT_DROP;
668 b1->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
672 snat_det_forward (mp1, &ip1->src_address, &new_addr1, &lo_port1);
674 key1.ext_host_addr = ip1->dst_address;
675 key1.ext_host_port = tcp1->dst;
678 snat_det_find_ses_by_in (mp1, &ip1->src_address, tcp1->src, key1);
679 if (PREDICT_FALSE (!ses1))
681 for (i1 = 0; i1 < mp1->ports_per_host; i1++)
683 key1.out_port = clib_host_to_net_u16 (lo_port1 +
687 mp1->ports_per_host));
689 if (snat_det_get_ses_by_out
690 (mp1, &ip1->src_address, key1.as_u64))
694 snat_det_ses_create (thread_index, mp1, &ip1->src_address,
698 if (PREDICT_FALSE (!ses1))
700 /* too many sessions for user, send ICMP error packet */
701 vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
702 icmp4_error_set_vnet_buffer (b1,
703 ICMP4_destination_unreachable,
704 ICMP4_destination_unreachable_destination_unreachable_host,
706 next1 = DET44_IN2OUT_NEXT_ICMP_ERROR;
711 old_port1 = udp1->src_port;
712 udp1->src_port = new_port1 = ses1->out.out_port;
714 old_addr1.as_u32 = ip1->src_address.as_u32;
715 ip1->src_address.as_u32 = new_addr1.as_u32;
716 vnet_buffer (b1)->sw_if_index[VLIB_TX] = dm->outside_fib_index;
718 sum1 = ip1->checksum;
719 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
720 ip4_header_t, src_address /* changed member */ );
721 ip1->checksum = ip_csum_fold (sum1);
723 if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
725 if (tcp1->flags & TCP_FLAG_SYN)
726 ses1->state = DET44_SESSION_TCP_SYN_SENT;
727 else if (tcp1->flags & TCP_FLAG_ACK
728 && ses1->state == DET44_SESSION_TCP_SYN_SENT)
729 ses1->state = DET44_SESSION_TCP_ESTABLISHED;
730 else if (tcp1->flags & TCP_FLAG_FIN
731 && ses1->state == DET44_SESSION_TCP_ESTABLISHED)
732 ses1->state = DET44_SESSION_TCP_FIN_WAIT;
733 else if (tcp1->flags & TCP_FLAG_ACK
734 && ses1->state == DET44_SESSION_TCP_FIN_WAIT)
735 snat_det_ses_close (mp1, ses1);
736 else if (tcp1->flags & TCP_FLAG_FIN
737 && ses1->state == DET44_SESSION_TCP_CLOSE_WAIT)
738 ses1->state = DET44_SESSION_TCP_LAST_ACK;
739 else if (tcp1->flags == 0 && ses1->state == DET44_SESSION_UNKNOWN)
740 ses1->state = DET44_SESSION_TCP_ESTABLISHED;
742 sum1 = tcp1->checksum;
743 sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
745 dst_address /* changed member */ );
746 sum1 = ip_csum_update (sum1, old_port1, new_port1,
747 ip4_header_t /* cheat */ ,
748 length /* changed member */ );
749 mss_clamping (dm->mss_clamping, tcp1, &sum1);
750 tcp1->checksum = ip_csum_fold (sum1);
754 ses1->state = DET44_SESSION_UDP_ACTIVE;
756 if (PREDICT_FALSE (udp1->checksum))
758 sum1 = udp1->checksum;
760 ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
762 dst_address /* changed member */ );
764 ip_csum_update (sum1, old_port1, new_port1,
765 ip4_header_t /* cheat */ ,
766 length /* changed member */ );
767 udp1->checksum = ip_csum_fold (sum1);
773 case DET44_SESSION_UDP_ACTIVE:
774 ses1->expire = now + dm->timeouts.udp;
776 case DET44_SESSION_TCP_SYN_SENT:
777 case DET44_SESSION_TCP_FIN_WAIT:
778 case DET44_SESSION_TCP_CLOSE_WAIT:
779 case DET44_SESSION_TCP_LAST_ACK:
780 ses1->expire = now + dm->timeouts.tcp.transitory;
782 case DET44_SESSION_TCP_ESTABLISHED:
783 ses1->expire = now + dm->timeouts.tcp.established;
788 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
789 && (b1->flags & VLIB_BUFFER_IS_TRACED)))
791 det44_in2out_trace_t *t =
792 vlib_add_trace (vm, node, b1, sizeof (*t));
793 t->sw_if_index = sw_if_index1;
794 t->next_index = next1;
795 t->session_index = ~0;
797 t->session_index = ses1 - mp1->sessions;
800 pkts_processed += next1 != DET44_IN2OUT_NEXT_DROP;
808 while (n_left_from > 0)
815 ip4_address_t new_addr0, old_addr0;
816 u16 old_port0, new_port0, lo_port0, i0;
820 snat_det_out_key_t key0;
822 snat_det_session_t *ses0 = 0;
824 icmp46_header_t *icmp0;
828 next0 = DET44_IN2OUT_NEXT_LOOKUP;
830 ip0 = vlib_buffer_get_current (b0);
831 udp0 = ip4_next_header (ip0);
832 tcp0 = (tcp_header_t *) udp0;
834 sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
836 if (PREDICT_FALSE (ip0->ttl == 1))
838 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
839 icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
840 ICMP4_time_exceeded_ttl_exceeded_in_transit,
842 next0 = DET44_IN2OUT_NEXT_ICMP_ERROR;
846 proto0 = ip_proto_to_nat_proto (ip0->protocol);
848 if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
851 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
852 icmp0 = (icmp46_header_t *) udp0;
854 next0 = det44_icmp_in2out (b0, ip0, icmp0, sw_if_index0,
855 rx_fib_index0, node, next0,
856 thread_index, &ses0, &mp0);
860 mp0 = snat_det_map_by_user (&ip0->src_address);
861 if (PREDICT_FALSE (!mp0))
863 det44_log_info ("no match for internal host %U",
864 format_ip4_address, &ip0->src_address);
865 next0 = DET44_IN2OUT_NEXT_DROP;
866 b0->error = node->errors[DET44_IN2OUT_ERROR_NO_TRANSLATION];
870 snat_det_forward (mp0, &ip0->src_address, &new_addr0, &lo_port0);
872 key0.ext_host_addr = ip0->dst_address;
873 key0.ext_host_port = tcp0->dst;
876 snat_det_find_ses_by_in (mp0, &ip0->src_address, tcp0->src, key0);
877 if (PREDICT_FALSE (!ses0))
879 for (i0 = 0; i0 < mp0->ports_per_host; i0++)
881 key0.out_port = clib_host_to_net_u16 (lo_port0 +
885 mp0->ports_per_host));
887 if (snat_det_get_ses_by_out
888 (mp0, &ip0->src_address, key0.as_u64))
892 snat_det_ses_create (thread_index, mp0, &ip0->src_address,
896 if (PREDICT_FALSE (!ses0))
898 /* too many sessions for user, send ICMP error packet */
899 vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
900 icmp4_error_set_vnet_buffer (b0,
901 ICMP4_destination_unreachable,
902 ICMP4_destination_unreachable_destination_unreachable_host,
904 next0 = DET44_IN2OUT_NEXT_ICMP_ERROR;
909 old_port0 = udp0->src_port;
910 udp0->src_port = new_port0 = ses0->out.out_port;
912 old_addr0.as_u32 = ip0->src_address.as_u32;
913 ip0->src_address.as_u32 = new_addr0.as_u32;
914 vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->outside_fib_index;
916 sum0 = ip0->checksum;
917 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
918 ip4_header_t, src_address /* changed member */ );
919 ip0->checksum = ip_csum_fold (sum0);
921 if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
923 if (tcp0->flags & TCP_FLAG_SYN)
924 ses0->state = DET44_SESSION_TCP_SYN_SENT;
925 else if (tcp0->flags & TCP_FLAG_ACK
926 && ses0->state == DET44_SESSION_TCP_SYN_SENT)
927 ses0->state = DET44_SESSION_TCP_ESTABLISHED;
928 else if (tcp0->flags & TCP_FLAG_FIN
929 && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
930 ses0->state = DET44_SESSION_TCP_FIN_WAIT;
931 else if (tcp0->flags & TCP_FLAG_ACK
932 && ses0->state == DET44_SESSION_TCP_FIN_WAIT)
933 snat_det_ses_close (mp0, ses0);
934 else if (tcp0->flags & TCP_FLAG_FIN
935 && ses0->state == DET44_SESSION_TCP_CLOSE_WAIT)
936 ses0->state = DET44_SESSION_TCP_LAST_ACK;
937 else if (tcp0->flags == 0 && ses0->state == DET44_SESSION_UNKNOWN)
938 ses0->state = DET44_SESSION_TCP_ESTABLISHED;
940 sum0 = tcp0->checksum;
941 sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
943 dst_address /* changed member */ );
944 sum0 = ip_csum_update (sum0, old_port0, new_port0,
945 ip4_header_t /* cheat */ ,
946 length /* changed member */ );
947 mss_clamping (dm->mss_clamping, tcp0, &sum0);
948 tcp0->checksum = ip_csum_fold (sum0);
952 ses0->state = DET44_SESSION_UDP_ACTIVE;
954 if (PREDICT_FALSE (udp0->checksum))
956 sum0 = udp0->checksum;
958 ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
960 dst_address /* changed member */ );
962 ip_csum_update (sum0, old_port0, new_port0,
963 ip4_header_t /* cheat */ ,
964 length /* changed member */ );
965 udp0->checksum = ip_csum_fold (sum0);
971 case DET44_SESSION_UDP_ACTIVE:
972 ses0->expire = now + dm->timeouts.udp;
974 case DET44_SESSION_TCP_SYN_SENT:
975 case DET44_SESSION_TCP_FIN_WAIT:
976 case DET44_SESSION_TCP_CLOSE_WAIT:
977 case DET44_SESSION_TCP_LAST_ACK:
978 ses0->expire = now + dm->timeouts.tcp.transitory;
980 case DET44_SESSION_TCP_ESTABLISHED:
981 ses0->expire = now + dm->timeouts.tcp.established;
986 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
987 && (b0->flags & VLIB_BUFFER_IS_TRACED)))
989 det44_in2out_trace_t *t =
990 vlib_add_trace (vm, node, b0, sizeof (*t));
991 t->sw_if_index = sw_if_index0;
992 t->next_index = next0;
993 t->session_index = ~0;
995 t->session_index = ses0 - mp0->sessions;
998 pkts_processed += next0 != DET44_IN2OUT_NEXT_DROP;
1005 vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1008 vlib_node_increment_counter (vm, dm->in2out_node_index,
1009 DET44_IN2OUT_ERROR_IN2OUT_PACKETS,
1011 return frame->n_vectors;
1015 VLIB_REGISTER_NODE (det44_in2out_node) = {
1016 .name = "det44-in2out",
1017 .vector_size = sizeof (u32),
1018 .format_trace = format_det44_in2out_trace,
1019 .type = VLIB_NODE_TYPE_INTERNAL,
1020 .n_errors = ARRAY_LEN(det44_in2out_error_strings),
1021 .error_strings = det44_in2out_error_strings,
1022 .runtime_data_bytes = sizeof (det44_runtime_t),
1023 .n_next_nodes = DET44_IN2OUT_N_NEXT,
1024 /* edit / add dispositions here */
1026 [DET44_IN2OUT_NEXT_DROP] = "error-drop",
1027 [DET44_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
1028 [DET44_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1034 * fd.io coding-style-patch-verification: ON
1037 * eval: (c-set-style "gnu")