057b26158fa655ae4cdc72dcba33aa4e76b6a543
[vpp.git] / src / plugins / nat / nat_det_in2out.c
1 /*
2  * Copyright (c) 2018 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:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15 /**
16  * @file
17  * @brief Deterministic/CGN NAT44 inside to outside network translation
18  */
19
20 #include <vlib/vlib.h>
21 #include <vnet/vnet.h>
22 #include <vnet/ip/ip.h>
23 #include <vnet/fib/ip4_fib.h>
24 #include <vppinfra/error.h>
25 #include <vppinfra/elog.h>
26 #include <nat/nat.h>
27 #include <nat/nat_det.h>
28 #include <nat/nat_inlines.h>
29
30 typedef struct
31 {
32   u32 sw_if_index;
33   u32 next_index;
34   u32 session_index;
35 } nat_det_in2out_trace_t;
36
37 typedef enum
38 {
39   NAT_DET_IN2OUT_NEXT_LOOKUP,
40   NAT_DET_IN2OUT_NEXT_DROP,
41   NAT_DET_IN2OUT_NEXT_ICMP_ERROR,
42   NAT_DET_IN2OUT_N_NEXT,
43 } nat_det_in2out_next_t;
44
45 #define foreach_nat_det_in2out_error                    \
46 _(UNSUPPORTED_PROTOCOL, "Unsupported protocol")         \
47 _(NO_TRANSLATION, "No translation")                     \
48 _(BAD_ICMP_TYPE, "unsupported ICMP type")               \
49 _(OUT_OF_PORTS, "Out of ports")                         \
50 _(IN2OUT_PACKETS, "Good in2out packets processed")
51
52 typedef enum
53 {
54 #define _(sym,str) NAT_DET_IN2OUT_ERROR_##sym,
55   foreach_nat_det_in2out_error
56 #undef _
57     NAT_DET_IN2OUT_N_ERROR,
58 } nat_det_in2out_error_t;
59
60 static char *nat_det_in2out_error_strings[] = {
61 #define _(sym,string) string,
62   foreach_nat_det_in2out_error
63 #undef _
64 };
65
66 static u8 *
67 format_nat_det_in2out_trace (u8 * s, va_list * args)
68 {
69   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
70   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
71   nat_det_in2out_trace_t *t = va_arg (*args, nat_det_in2out_trace_t *);
72
73   s = format (s, "NAT_DET_IN2OUT: sw_if_index %d, next index %d, session %d",
74               t->sw_if_index, t->next_index, t->session_index);
75
76   return s;
77 }
78
79 #ifndef CLIB_MARCH_VARIANT
80 /**
81  * Get address and port values to be used for ICMP packet translation
82  * and create session if needed
83  *
84  * @param[in,out] sm             NAT main
85  * @param[in,out] node           NAT node runtime
86  * @param[in] thread_index       thread index
87  * @param[in,out] b0             buffer containing packet to be translated
88  * @param[in,out] ip0            ip header
89  * @param[out] p_proto           protocol used for matching
90  * @param[out] p_value           address and port after NAT translation
91  * @param[out] p_dont_translate  if packet should not be translated
92  * @param d                      optional parameter
93  * @param e                      optional parameter
94  */
95 u32
96 icmp_match_in2out_det (snat_main_t * sm, vlib_node_runtime_t * node,
97                        u32 thread_index, vlib_buffer_t * b0,
98                        ip4_header_t * ip0, u8 * p_proto,
99                        snat_session_key_t * p_value, u8 * p_dont_translate,
100                        void *d, void *e)
101 {
102   icmp46_header_t *icmp0;
103   u32 sw_if_index0;
104   u32 rx_fib_index0;
105   u8 protocol;
106   snat_det_out_key_t key0;
107   u8 dont_translate = 0;
108   u32 next0 = ~0;
109   icmp_echo_header_t *echo0, *inner_echo0 = 0;
110   ip4_header_t *inner_ip0;
111   void *l4_header = 0;
112   icmp46_header_t *inner_icmp0;
113   snat_det_map_t *dm0 = 0;
114   ip4_address_t new_addr0;
115   u16 lo_port0, i0;
116   snat_det_session_t *ses0 = 0;
117   ip4_address_t in_addr;
118   u16 in_port;
119
120   icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
121   echo0 = (icmp_echo_header_t *) (icmp0 + 1);
122   sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
123   rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
124
125   if (!icmp_type_is_error_message
126       (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
127     {
128       protocol = SNAT_PROTOCOL_ICMP;
129       in_addr = ip0->src_address;
130       in_port = vnet_buffer (b0)->ip.reass.l4_src_port;
131     }
132   else
133     {
134       /* if error message, then it's not fragmented and we can access it */
135       inner_ip0 = (ip4_header_t *) (echo0 + 1);
136       l4_header = ip4_next_header (inner_ip0);
137       protocol = ip_proto_to_snat_proto (inner_ip0->protocol);
138       in_addr = inner_ip0->dst_address;
139       switch (protocol)
140         {
141         case SNAT_PROTOCOL_ICMP:
142           inner_icmp0 = (icmp46_header_t *) l4_header;
143           inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
144           in_port = inner_echo0->identifier;
145           break;
146         case SNAT_PROTOCOL_UDP:
147         case SNAT_PROTOCOL_TCP:
148           in_port = ((tcp_udp_header_t *) l4_header)->dst_port;
149           break;
150         default:
151           b0->error = node->errors[NAT_DET_IN2OUT_ERROR_UNSUPPORTED_PROTOCOL];
152           next0 = NAT_DET_IN2OUT_NEXT_DROP;
153           goto out;
154         }
155     }
156
157   dm0 = snat_det_map_by_user (sm, &in_addr);
158   if (PREDICT_FALSE (!dm0))
159     {
160       nat_log_info ("no match for internal host %U",
161                     format_ip4_address, &in_addr);
162       if (PREDICT_FALSE (snat_not_translate_fast (sm, node, sw_if_index0, ip0,
163                                                   IP_PROTOCOL_ICMP,
164                                                   rx_fib_index0)))
165         {
166           dont_translate = 1;
167           goto out;
168         }
169       next0 = NAT_DET_IN2OUT_NEXT_DROP;
170       b0->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
171       goto out;
172     }
173
174   snat_det_forward (dm0, &in_addr, &new_addr0, &lo_port0);
175
176   key0.ext_host_addr = ip0->dst_address;
177   key0.ext_host_port = 0;
178
179   ses0 = snat_det_find_ses_by_in (dm0, &in_addr, in_port, key0);
180   if (PREDICT_FALSE (!ses0))
181     {
182       if (PREDICT_FALSE (snat_not_translate_fast (sm, node, sw_if_index0, ip0,
183                                                   IP_PROTOCOL_ICMP,
184                                                   rx_fib_index0)))
185         {
186           dont_translate = 1;
187           goto out;
188         }
189       if (icmp0->type != ICMP4_echo_request)
190         {
191           b0->error = node->errors[NAT_DET_IN2OUT_ERROR_BAD_ICMP_TYPE];
192           next0 = NAT_DET_IN2OUT_NEXT_DROP;
193           goto out;
194         }
195       for (i0 = 0; i0 < dm0->ports_per_host; i0++)
196         {
197           key0.out_port = clib_host_to_net_u16 (lo_port0 +
198                                                 ((i0 +
199                                                   clib_net_to_host_u16
200                                                   (echo0->identifier)) %
201                                                  dm0->ports_per_host));
202
203           if (snat_det_get_ses_by_out (dm0, &in_addr, key0.as_u64))
204             continue;
205
206           ses0 =
207             snat_det_ses_create (thread_index, dm0,
208                                  &in_addr, echo0->identifier, &key0);
209           break;
210         }
211       if (PREDICT_FALSE (!ses0))
212         {
213           next0 = NAT_DET_IN2OUT_NEXT_DROP;
214           b0->error = node->errors[NAT_DET_IN2OUT_ERROR_OUT_OF_PORTS];
215           goto out;
216         }
217     }
218
219   if (PREDICT_FALSE
220       (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_request
221        && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
222                                        reass.icmp_type_or_tcp_flags)))
223     {
224       b0->error = node->errors[NAT_DET_IN2OUT_ERROR_BAD_ICMP_TYPE];
225       next0 = NAT_DET_IN2OUT_NEXT_DROP;
226       goto out;
227     }
228
229   u32 now = (u32) vlib_time_now (sm->vlib_main);
230
231   ses0->state = SNAT_SESSION_ICMP_ACTIVE;
232   ses0->expire = now + sm->icmp_timeout;
233
234 out:
235   *p_proto = protocol;
236   if (ses0)
237     {
238       p_value->addr = new_addr0;
239       p_value->fib_index = sm->outside_fib_index;
240       p_value->port = ses0->out.out_port;
241     }
242   *p_dont_translate = dont_translate;
243   if (d)
244     *(snat_det_session_t **) d = ses0;
245   if (e)
246     *(snat_det_map_t **) e = dm0;
247   return next0;
248 }
249 #endif
250
251 VLIB_NODE_FN (snat_det_in2out_node) (vlib_main_t * vm,
252                                      vlib_node_runtime_t * node,
253                                      vlib_frame_t * frame)
254 {
255   u32 n_left_from, *from, *to_next;
256   nat_det_in2out_next_t next_index;
257   u32 pkts_processed = 0;
258   snat_main_t *sm = &snat_main;
259   u32 now = (u32) vlib_time_now (vm);
260   u32 thread_index = vm->thread_index;
261
262   from = vlib_frame_vector_args (frame);
263   n_left_from = frame->n_vectors;
264   next_index = node->cached_next_index;
265
266   while (n_left_from > 0)
267     {
268       u32 n_left_to_next;
269
270       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
271
272       while (n_left_from >= 4 && n_left_to_next >= 2)
273         {
274           u32 bi0, bi1;
275           vlib_buffer_t *b0, *b1;
276           u32 next0, next1;
277           u32 sw_if_index0, sw_if_index1;
278           ip4_header_t *ip0, *ip1;
279           ip_csum_t sum0, sum1;
280           ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
281           u16 old_port0, new_port0, lo_port0, i0;
282           u16 old_port1, new_port1, lo_port1, i1;
283           udp_header_t *udp0, *udp1;
284           tcp_header_t *tcp0, *tcp1;
285           u32 proto0, proto1;
286           snat_det_out_key_t key0, key1;
287           snat_det_map_t *dm0, *dm1;
288           snat_det_session_t *ses0 = 0, *ses1 = 0;
289           u32 rx_fib_index0, rx_fib_index1;
290           icmp46_header_t *icmp0, *icmp1;
291
292           /* Prefetch next iteration. */
293           {
294             vlib_buffer_t *p2, *p3;
295
296             p2 = vlib_get_buffer (vm, from[2]);
297             p3 = vlib_get_buffer (vm, from[3]);
298
299             vlib_prefetch_buffer_header (p2, LOAD);
300             vlib_prefetch_buffer_header (p3, LOAD);
301
302             CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
303             CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
304           }
305
306           /* speculatively enqueue b0 and b1 to the current next frame */
307           to_next[0] = bi0 = from[0];
308           to_next[1] = bi1 = from[1];
309           from += 2;
310           to_next += 2;
311           n_left_from -= 2;
312           n_left_to_next -= 2;
313
314           b0 = vlib_get_buffer (vm, bi0);
315           b1 = vlib_get_buffer (vm, bi1);
316
317           next0 = NAT_DET_IN2OUT_NEXT_LOOKUP;
318           next1 = NAT_DET_IN2OUT_NEXT_LOOKUP;
319
320           ip0 = vlib_buffer_get_current (b0);
321           udp0 = ip4_next_header (ip0);
322           tcp0 = (tcp_header_t *) udp0;
323
324           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
325
326           if (PREDICT_FALSE (ip0->ttl == 1))
327             {
328               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
329               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
330                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
331                                            0);
332               next0 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
333               goto trace0;
334             }
335
336           proto0 = ip_proto_to_snat_proto (ip0->protocol);
337
338           if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
339             {
340               rx_fib_index0 =
341                 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
342               icmp0 = (icmp46_header_t *) udp0;
343
344               next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0,
345                                    rx_fib_index0, node, next0, thread_index,
346                                    &ses0, &dm0);
347               goto trace0;
348             }
349
350           dm0 = snat_det_map_by_user (sm, &ip0->src_address);
351           if (PREDICT_FALSE (!dm0))
352             {
353               nat_log_info ("no match for internal host %U",
354                             format_ip4_address, &ip0->src_address);
355               next0 = NAT_DET_IN2OUT_NEXT_DROP;
356               b0->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
357               goto trace0;
358             }
359
360           snat_det_forward (dm0, &ip0->src_address, &new_addr0, &lo_port0);
361
362           key0.ext_host_addr = ip0->dst_address;
363           key0.ext_host_port = tcp0->dst;
364
365           ses0 =
366             snat_det_find_ses_by_in (dm0, &ip0->src_address, tcp0->src, key0);
367           if (PREDICT_FALSE (!ses0))
368             {
369               for (i0 = 0; i0 < dm0->ports_per_host; i0++)
370                 {
371                   key0.out_port = clib_host_to_net_u16 (lo_port0 +
372                                                         ((i0 +
373                                                           clib_net_to_host_u16
374                                                           (tcp0->src)) %
375                                                          dm0->
376                                                          ports_per_host));
377
378                   if (snat_det_get_ses_by_out
379                       (dm0, &ip0->src_address, key0.as_u64))
380                     continue;
381
382                   ses0 =
383                     snat_det_ses_create (thread_index, dm0, &ip0->src_address,
384                                          tcp0->src, &key0);
385                   break;
386                 }
387               if (PREDICT_FALSE (!ses0))
388                 {
389                   /* too many sessions for user, send ICMP error packet */
390                   vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
391                   icmp4_error_set_vnet_buffer (b0,
392                                                ICMP4_destination_unreachable,
393                                                ICMP4_destination_unreachable_destination_unreachable_host,
394                                                0);
395                   next0 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
396                   goto trace0;
397                 }
398             }
399
400           old_port0 = udp0->src_port;
401           udp0->src_port = new_port0 = ses0->out.out_port;
402
403           old_addr0.as_u32 = ip0->src_address.as_u32;
404           ip0->src_address.as_u32 = new_addr0.as_u32;
405           vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
406
407           sum0 = ip0->checksum;
408           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
409                                  ip4_header_t,
410                                  src_address /* changed member */ );
411           ip0->checksum = ip_csum_fold (sum0);
412
413           if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
414             {
415               if (tcp0->flags & TCP_FLAG_SYN)
416                 ses0->state = SNAT_SESSION_TCP_SYN_SENT;
417               else if (tcp0->flags & TCP_FLAG_ACK
418                        && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
419                 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
420               else if (tcp0->flags & TCP_FLAG_FIN
421                        && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
422                 ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
423               else if (tcp0->flags & TCP_FLAG_ACK
424                        && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
425                 snat_det_ses_close (dm0, ses0);
426               else if (tcp0->flags & TCP_FLAG_FIN
427                        && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
428                 ses0->state = SNAT_SESSION_TCP_LAST_ACK;
429               else if (tcp0->flags == 0
430                        && ses0->state == SNAT_SESSION_UNKNOWN)
431                 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
432
433               sum0 = tcp0->checksum;
434               sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
435                                      ip4_header_t,
436                                      dst_address /* changed member */ );
437               sum0 = ip_csum_update (sum0, old_port0, new_port0,
438                                      ip4_header_t /* cheat */ ,
439                                      length /* changed member */ );
440               mss_clamping (sm, tcp0, &sum0);
441               tcp0->checksum = ip_csum_fold (sum0);
442             }
443           else
444             {
445               ses0->state = SNAT_SESSION_UDP_ACTIVE;
446
447               if (PREDICT_FALSE (udp0->checksum))
448                 {
449                   sum0 = udp0->checksum;
450                   sum0 =
451                     ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
452                                     ip4_header_t,
453                                     dst_address /* changed member */ );
454                   sum0 =
455                     ip_csum_update (sum0, old_port0, new_port0,
456                                     ip4_header_t /* cheat */ ,
457                                     length /* changed member */ );
458                   udp0->checksum = ip_csum_fold (sum0);
459                 }
460             }
461
462           switch (ses0->state)
463             {
464             case SNAT_SESSION_UDP_ACTIVE:
465               ses0->expire = now + sm->udp_timeout;
466               break;
467             case SNAT_SESSION_TCP_SYN_SENT:
468             case SNAT_SESSION_TCP_FIN_WAIT:
469             case SNAT_SESSION_TCP_CLOSE_WAIT:
470             case SNAT_SESSION_TCP_LAST_ACK:
471               ses0->expire = now + sm->tcp_transitory_timeout;
472               break;
473             case SNAT_SESSION_TCP_ESTABLISHED:
474               ses0->expire = now + sm->tcp_established_timeout;
475               break;
476             }
477
478         trace0:
479           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
480                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
481             {
482               nat_det_in2out_trace_t *t =
483                 vlib_add_trace (vm, node, b0, sizeof (*t));
484               t->sw_if_index = sw_if_index0;
485               t->next_index = next0;
486               t->session_index = ~0;
487               if (ses0)
488                 t->session_index = ses0 - dm0->sessions;
489             }
490
491           pkts_processed += next0 != NAT_DET_IN2OUT_NEXT_DROP;
492
493           ip1 = vlib_buffer_get_current (b1);
494           udp1 = ip4_next_header (ip1);
495           tcp1 = (tcp_header_t *) udp1;
496
497           sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
498
499           if (PREDICT_FALSE (ip1->ttl == 1))
500             {
501               vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
502               icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
503                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
504                                            0);
505               next1 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
506               goto trace1;
507             }
508
509           proto1 = ip_proto_to_snat_proto (ip1->protocol);
510
511           if (PREDICT_FALSE (proto1 == SNAT_PROTOCOL_ICMP))
512             {
513               rx_fib_index1 =
514                 ip4_fib_table_get_index_for_sw_if_index (sw_if_index1);
515               icmp1 = (icmp46_header_t *) udp1;
516
517               next1 = icmp_in2out (sm, b1, ip1, icmp1, sw_if_index1,
518                                    rx_fib_index1, node, next1, thread_index,
519                                    &ses1, &dm1);
520               goto trace1;
521             }
522
523           dm1 = snat_det_map_by_user (sm, &ip1->src_address);
524           if (PREDICT_FALSE (!dm1))
525             {
526               nat_log_info ("no match for internal host %U",
527                             format_ip4_address, &ip0->src_address);
528               next1 = NAT_DET_IN2OUT_NEXT_DROP;
529               b1->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
530               goto trace1;
531             }
532
533           snat_det_forward (dm1, &ip1->src_address, &new_addr1, &lo_port1);
534
535           key1.ext_host_addr = ip1->dst_address;
536           key1.ext_host_port = tcp1->dst;
537
538           ses1 =
539             snat_det_find_ses_by_in (dm1, &ip1->src_address, tcp1->src, key1);
540           if (PREDICT_FALSE (!ses1))
541             {
542               for (i1 = 0; i1 < dm1->ports_per_host; i1++)
543                 {
544                   key1.out_port = clib_host_to_net_u16 (lo_port1 +
545                                                         ((i1 +
546                                                           clib_net_to_host_u16
547                                                           (tcp1->src)) %
548                                                          dm1->
549                                                          ports_per_host));
550
551                   if (snat_det_get_ses_by_out
552                       (dm1, &ip1->src_address, key1.as_u64))
553                     continue;
554
555                   ses1 =
556                     snat_det_ses_create (thread_index, dm1, &ip1->src_address,
557                                          tcp1->src, &key1);
558                   break;
559                 }
560               if (PREDICT_FALSE (!ses1))
561                 {
562                   /* too many sessions for user, send ICMP error packet */
563                   vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
564                   icmp4_error_set_vnet_buffer (b1,
565                                                ICMP4_destination_unreachable,
566                                                ICMP4_destination_unreachable_destination_unreachable_host,
567                                                0);
568                   next1 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
569                   goto trace1;
570                 }
571             }
572
573           old_port1 = udp1->src_port;
574           udp1->src_port = new_port1 = ses1->out.out_port;
575
576           old_addr1.as_u32 = ip1->src_address.as_u32;
577           ip1->src_address.as_u32 = new_addr1.as_u32;
578           vnet_buffer (b1)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
579
580           sum1 = ip1->checksum;
581           sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
582                                  ip4_header_t,
583                                  src_address /* changed member */ );
584           ip1->checksum = ip_csum_fold (sum1);
585
586           if (PREDICT_TRUE (proto1 == SNAT_PROTOCOL_TCP))
587             {
588               if (tcp1->flags & TCP_FLAG_SYN)
589                 ses1->state = SNAT_SESSION_TCP_SYN_SENT;
590               else if (tcp1->flags & TCP_FLAG_ACK
591                        && ses1->state == SNAT_SESSION_TCP_SYN_SENT)
592                 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
593               else if (tcp1->flags & TCP_FLAG_FIN
594                        && ses1->state == SNAT_SESSION_TCP_ESTABLISHED)
595                 ses1->state = SNAT_SESSION_TCP_FIN_WAIT;
596               else if (tcp1->flags & TCP_FLAG_ACK
597                        && ses1->state == SNAT_SESSION_TCP_FIN_WAIT)
598                 snat_det_ses_close (dm1, ses1);
599               else if (tcp1->flags & TCP_FLAG_FIN
600                        && ses1->state == SNAT_SESSION_TCP_CLOSE_WAIT)
601                 ses1->state = SNAT_SESSION_TCP_LAST_ACK;
602               else if (tcp1->flags == 0
603                        && ses1->state == SNAT_SESSION_UNKNOWN)
604                 ses1->state = SNAT_SESSION_TCP_ESTABLISHED;
605
606               sum1 = tcp1->checksum;
607               sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
608                                      ip4_header_t,
609                                      dst_address /* changed member */ );
610               sum1 = ip_csum_update (sum1, old_port1, new_port1,
611                                      ip4_header_t /* cheat */ ,
612                                      length /* changed member */ );
613               mss_clamping (sm, tcp1, &sum1);
614               tcp1->checksum = ip_csum_fold (sum1);
615             }
616           else
617             {
618               ses1->state = SNAT_SESSION_UDP_ACTIVE;
619
620               if (PREDICT_FALSE (udp1->checksum))
621                 {
622                   sum1 = udp1->checksum;
623                   sum1 =
624                     ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
625                                     ip4_header_t,
626                                     dst_address /* changed member */ );
627                   sum1 =
628                     ip_csum_update (sum1, old_port1, new_port1,
629                                     ip4_header_t /* cheat */ ,
630                                     length /* changed member */ );
631                   udp1->checksum = ip_csum_fold (sum1);
632                 }
633             }
634
635           switch (ses1->state)
636             {
637             case SNAT_SESSION_UDP_ACTIVE:
638               ses1->expire = now + sm->udp_timeout;
639               break;
640             case SNAT_SESSION_TCP_SYN_SENT:
641             case SNAT_SESSION_TCP_FIN_WAIT:
642             case SNAT_SESSION_TCP_CLOSE_WAIT:
643             case SNAT_SESSION_TCP_LAST_ACK:
644               ses1->expire = now + sm->tcp_transitory_timeout;
645               break;
646             case SNAT_SESSION_TCP_ESTABLISHED:
647               ses1->expire = now + sm->tcp_established_timeout;
648               break;
649             }
650
651         trace1:
652           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
653                              && (b1->flags & VLIB_BUFFER_IS_TRACED)))
654             {
655               nat_det_in2out_trace_t *t =
656                 vlib_add_trace (vm, node, b1, sizeof (*t));
657               t->sw_if_index = sw_if_index1;
658               t->next_index = next1;
659               t->session_index = ~0;
660               if (ses1)
661                 t->session_index = ses1 - dm1->sessions;
662             }
663
664           pkts_processed += next1 != NAT_DET_IN2OUT_NEXT_DROP;
665
666           /* verify speculative enqueues, maybe switch current next frame */
667           vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
668                                            to_next, n_left_to_next,
669                                            bi0, bi1, next0, next1);
670         }
671
672       while (n_left_from > 0 && n_left_to_next > 0)
673         {
674           u32 bi0;
675           vlib_buffer_t *b0;
676           u32 next0;
677           u32 sw_if_index0;
678           ip4_header_t *ip0;
679           ip_csum_t sum0;
680           ip4_address_t new_addr0, old_addr0;
681           u16 old_port0, new_port0, lo_port0, i0;
682           udp_header_t *udp0;
683           tcp_header_t *tcp0;
684           u32 proto0;
685           snat_det_out_key_t key0;
686           snat_det_map_t *dm0;
687           snat_det_session_t *ses0 = 0;
688           u32 rx_fib_index0;
689           icmp46_header_t *icmp0;
690
691           /* speculatively enqueue b0 to the current next frame */
692           bi0 = from[0];
693           to_next[0] = bi0;
694           from += 1;
695           to_next += 1;
696           n_left_from -= 1;
697           n_left_to_next -= 1;
698
699           b0 = vlib_get_buffer (vm, bi0);
700           next0 = NAT_DET_IN2OUT_NEXT_LOOKUP;
701
702           ip0 = vlib_buffer_get_current (b0);
703           udp0 = ip4_next_header (ip0);
704           tcp0 = (tcp_header_t *) udp0;
705
706           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
707
708           if (PREDICT_FALSE (ip0->ttl == 1))
709             {
710               vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
711               icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
712                                            ICMP4_time_exceeded_ttl_exceeded_in_transit,
713                                            0);
714               next0 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
715               goto trace00;
716             }
717
718           proto0 = ip_proto_to_snat_proto (ip0->protocol);
719
720           if (PREDICT_FALSE (proto0 == SNAT_PROTOCOL_ICMP))
721             {
722               rx_fib_index0 =
723                 ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
724               icmp0 = (icmp46_header_t *) udp0;
725
726               next0 = icmp_in2out (sm, b0, ip0, icmp0, sw_if_index0,
727                                    rx_fib_index0, node, next0, thread_index,
728                                    &ses0, &dm0);
729               goto trace00;
730             }
731
732           dm0 = snat_det_map_by_user (sm, &ip0->src_address);
733           if (PREDICT_FALSE (!dm0))
734             {
735               nat_log_info ("no match for internal host %U",
736                             format_ip4_address, &ip0->src_address);
737               next0 = NAT_DET_IN2OUT_NEXT_DROP;
738               b0->error = node->errors[NAT_DET_IN2OUT_ERROR_NO_TRANSLATION];
739               goto trace00;
740             }
741
742           snat_det_forward (dm0, &ip0->src_address, &new_addr0, &lo_port0);
743
744           key0.ext_host_addr = ip0->dst_address;
745           key0.ext_host_port = tcp0->dst;
746
747           ses0 =
748             snat_det_find_ses_by_in (dm0, &ip0->src_address, tcp0->src, key0);
749           if (PREDICT_FALSE (!ses0))
750             {
751               for (i0 = 0; i0 < dm0->ports_per_host; i0++)
752                 {
753                   key0.out_port = clib_host_to_net_u16 (lo_port0 +
754                                                         ((i0 +
755                                                           clib_net_to_host_u16
756                                                           (tcp0->src)) %
757                                                          dm0->
758                                                          ports_per_host));
759
760                   if (snat_det_get_ses_by_out
761                       (dm0, &ip0->src_address, key0.as_u64))
762                     continue;
763
764                   ses0 =
765                     snat_det_ses_create (thread_index, dm0, &ip0->src_address,
766                                          tcp0->src, &key0);
767                   break;
768                 }
769               if (PREDICT_FALSE (!ses0))
770                 {
771                   /* too many sessions for user, send ICMP error packet */
772                   vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
773                   icmp4_error_set_vnet_buffer (b0,
774                                                ICMP4_destination_unreachable,
775                                                ICMP4_destination_unreachable_destination_unreachable_host,
776                                                0);
777                   next0 = NAT_DET_IN2OUT_NEXT_ICMP_ERROR;
778                   goto trace00;
779                 }
780             }
781
782           old_port0 = udp0->src_port;
783           udp0->src_port = new_port0 = ses0->out.out_port;
784
785           old_addr0.as_u32 = ip0->src_address.as_u32;
786           ip0->src_address.as_u32 = new_addr0.as_u32;
787           vnet_buffer (b0)->sw_if_index[VLIB_TX] = sm->outside_fib_index;
788
789           sum0 = ip0->checksum;
790           sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
791                                  ip4_header_t,
792                                  src_address /* changed member */ );
793           ip0->checksum = ip_csum_fold (sum0);
794
795           if (PREDICT_TRUE (proto0 == SNAT_PROTOCOL_TCP))
796             {
797               if (tcp0->flags & TCP_FLAG_SYN)
798                 ses0->state = SNAT_SESSION_TCP_SYN_SENT;
799               else if (tcp0->flags & TCP_FLAG_ACK
800                        && ses0->state == SNAT_SESSION_TCP_SYN_SENT)
801                 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
802               else if (tcp0->flags & TCP_FLAG_FIN
803                        && ses0->state == SNAT_SESSION_TCP_ESTABLISHED)
804                 ses0->state = SNAT_SESSION_TCP_FIN_WAIT;
805               else if (tcp0->flags & TCP_FLAG_ACK
806                        && ses0->state == SNAT_SESSION_TCP_FIN_WAIT)
807                 snat_det_ses_close (dm0, ses0);
808               else if (tcp0->flags & TCP_FLAG_FIN
809                        && ses0->state == SNAT_SESSION_TCP_CLOSE_WAIT)
810                 ses0->state = SNAT_SESSION_TCP_LAST_ACK;
811               else if (tcp0->flags == 0
812                        && ses0->state == SNAT_SESSION_UNKNOWN)
813                 ses0->state = SNAT_SESSION_TCP_ESTABLISHED;
814
815               sum0 = tcp0->checksum;
816               sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
817                                      ip4_header_t,
818                                      dst_address /* changed member */ );
819               sum0 = ip_csum_update (sum0, old_port0, new_port0,
820                                      ip4_header_t /* cheat */ ,
821                                      length /* changed member */ );
822               mss_clamping (sm, tcp0, &sum0);
823               tcp0->checksum = ip_csum_fold (sum0);
824             }
825           else
826             {
827               ses0->state = SNAT_SESSION_UDP_ACTIVE;
828
829               if (PREDICT_FALSE (udp0->checksum))
830                 {
831                   sum0 = udp0->checksum;
832                   sum0 =
833                     ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
834                                     ip4_header_t,
835                                     dst_address /* changed member */ );
836                   sum0 =
837                     ip_csum_update (sum0, old_port0, new_port0,
838                                     ip4_header_t /* cheat */ ,
839                                     length /* changed member */ );
840                   udp0->checksum = ip_csum_fold (sum0);
841                 }
842             }
843
844           switch (ses0->state)
845             {
846             case SNAT_SESSION_UDP_ACTIVE:
847               ses0->expire = now + sm->udp_timeout;
848               break;
849             case SNAT_SESSION_TCP_SYN_SENT:
850             case SNAT_SESSION_TCP_FIN_WAIT:
851             case SNAT_SESSION_TCP_CLOSE_WAIT:
852             case SNAT_SESSION_TCP_LAST_ACK:
853               ses0->expire = now + sm->tcp_transitory_timeout;
854               break;
855             case SNAT_SESSION_TCP_ESTABLISHED:
856               ses0->expire = now + sm->tcp_established_timeout;
857               break;
858             }
859
860         trace00:
861           if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
862                              && (b0->flags & VLIB_BUFFER_IS_TRACED)))
863             {
864               nat_det_in2out_trace_t *t =
865                 vlib_add_trace (vm, node, b0, sizeof (*t));
866               t->sw_if_index = sw_if_index0;
867               t->next_index = next0;
868               t->session_index = ~0;
869               if (ses0)
870                 t->session_index = ses0 - dm0->sessions;
871             }
872
873           pkts_processed += next0 != NAT_DET_IN2OUT_NEXT_DROP;
874
875           /* verify speculative enqueue, maybe switch current next frame */
876           vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
877                                            to_next, n_left_to_next,
878                                            bi0, next0);
879         }
880
881       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
882     }
883
884   vlib_node_increment_counter (vm, sm->det_in2out_node_index,
885                                NAT_DET_IN2OUT_ERROR_IN2OUT_PACKETS,
886                                pkts_processed);
887   return frame->n_vectors;
888 }
889
890 /* *INDENT-OFF* */
891 VLIB_REGISTER_NODE (snat_det_in2out_node) = {
892   .name = "nat44-det-in2out",
893   .vector_size = sizeof (u32),
894   .format_trace = format_nat_det_in2out_trace,
895   .type = VLIB_NODE_TYPE_INTERNAL,
896   .n_errors = ARRAY_LEN(nat_det_in2out_error_strings),
897   .error_strings = nat_det_in2out_error_strings,
898   .n_next_nodes = NAT_DET_IN2OUT_N_NEXT,
899   /* edit / add dispositions here */
900   .next_nodes = {
901     [NAT_DET_IN2OUT_NEXT_DROP] = "error-drop",
902     [NAT_DET_IN2OUT_NEXT_LOOKUP] = "ip4-lookup",
903     [NAT_DET_IN2OUT_NEXT_ICMP_ERROR] = "ip4-icmp-error",
904   },
905 };
906 /* *INDENT-ON* */
907
908 /*
909  * fd.io coding-style-patch-verification: ON
910  *
911  * Local Variables:
912  * eval: (c-set-style "gnu")
913  * End:
914  */