Line data Source code
1 : /*
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:
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 : /**
17 : * @file
18 : * @brief Deterministic NAT (CGN) outside to inside translation
19 : */
20 :
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>
27 :
28 : #include <nat/det44/det44.h>
29 : #include <nat/det44/det44_inlines.h>
30 :
31 : #include <nat/lib/lib.h>
32 : #include <nat/lib/inlines.h>
33 : #include <nat/lib/nat_inlines.h>
34 :
35 : typedef enum
36 : {
37 : DET44_OUT2IN_NEXT_DROP,
38 : DET44_OUT2IN_NEXT_LOOKUP,
39 : DET44_OUT2IN_NEXT_ICMP_ERROR,
40 : DET44_OUT2IN_N_NEXT,
41 : } det44_out2in_next_t;
42 :
43 : typedef struct
44 : {
45 : u32 sw_if_index;
46 : u32 next_index;
47 : u32 session_index;
48 : } det44_out2in_trace_t;
49 :
50 : #define foreach_det44_out2in_error \
51 : _(UNSUPPORTED_PROTOCOL, "Unsupported protocol") \
52 : _(NO_TRANSLATION, "No translation") \
53 : _(BAD_ICMP_TYPE, "unsupported ICMP type") \
54 : _(OUT2IN_PACKETS, "Good out2in packets processed")
55 :
56 : typedef enum
57 : {
58 : #define _(sym,str) DET44_OUT2IN_ERROR_##sym,
59 : foreach_det44_out2in_error
60 : #undef _
61 : DET44_OUT2IN_N_ERROR,
62 : } det44_out2in_error_t;
63 :
64 : static char *det44_out2in_error_strings[] = {
65 : #define _(sym,string) string,
66 : foreach_det44_out2in_error
67 : #undef _
68 : };
69 :
70 : static u8 *
71 5 : format_det44_out2in_trace (u8 * s, va_list * args)
72 : {
73 5 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
74 5 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
75 5 : det44_out2in_trace_t *t = va_arg (*args, det44_out2in_trace_t *);
76 :
77 : s =
78 5 : format (s,
79 : "DET44_OUT2IN: sw_if_index %d, next index %d, session index %d",
80 : t->sw_if_index, t->next_index, t->session_index);
81 5 : return s;
82 : }
83 :
84 : #ifndef CLIB_MARCH_VARIANT
85 : /**
86 : * Get address and port values to be used for ICMP packet translation
87 : * and create session if needed
88 : *
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
98 : */
99 : u32
100 1 : icmp_match_out2in_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,
105 : u8 * dont_translate)
106 : {
107 1 : det44_main_t *dm = &det44_main;
108 : icmp46_header_t *icmp0;
109 : u32 sw_if_index0;
110 : u8 protocol;
111 : snat_det_out_key_t key0;
112 1 : u32 next0 = ~0;
113 1 : icmp_echo_header_t *echo0, *inner_echo0 = 0;
114 : ip4_header_t *inner_ip0;
115 1 : void *l4_header = 0;
116 : icmp46_header_t *inner_icmp0;
117 1 : snat_det_map_t *mp0 = 0;
118 1 : ip4_address_t new_addr0 = { {0} };
119 1 : snat_det_session_t *ses0 = 0;
120 : ip4_address_t out_addr;
121 1 : *dont_translate = 0;
122 :
123 1 : icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
124 1 : echo0 = (icmp_echo_header_t *) (icmp0 + 1);
125 1 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
126 :
127 1 : if (!icmp_type_is_error_message
128 1 : (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags))
129 : {
130 1 : protocol = NAT_PROTOCOL_ICMP;
131 1 : key0.ext_host_addr = ip0->src_address;
132 1 : key0.ext_host_port = 0;
133 1 : key0.out_port = vnet_buffer (b0)->ip.reass.l4_src_port;
134 1 : out_addr = ip0->dst_address;
135 : }
136 : else
137 : {
138 : /* if error message, then it's not fragmented and we can access it */
139 0 : inner_ip0 = (ip4_header_t *) (echo0 + 1);
140 0 : l4_header = ip4_next_header (inner_ip0);
141 0 : protocol = ip_proto_to_nat_proto (inner_ip0->protocol);
142 0 : key0.ext_host_addr = inner_ip0->dst_address;
143 0 : out_addr = inner_ip0->src_address;
144 0 : switch (protocol)
145 : {
146 0 : case NAT_PROTOCOL_ICMP:
147 0 : inner_icmp0 = (icmp46_header_t *) l4_header;
148 0 : inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
149 0 : key0.ext_host_port = 0;
150 0 : key0.out_port = inner_echo0->identifier;
151 0 : break;
152 0 : case NAT_PROTOCOL_UDP:
153 : case NAT_PROTOCOL_TCP:
154 0 : key0.ext_host_port = ((tcp_udp_header_t *) l4_header)->dst_port;
155 0 : key0.out_port = ((tcp_udp_header_t *) l4_header)->src_port;
156 0 : break;
157 0 : default:
158 0 : b0->error = node->errors[DET44_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
159 0 : next0 = DET44_OUT2IN_NEXT_DROP;
160 0 : goto out;
161 : }
162 : }
163 :
164 1 : mp0 = snat_det_map_by_out (&out_addr);
165 1 : if (PREDICT_FALSE (!mp0))
166 : {
167 : /* Don't NAT packet aimed at the intfc address */
168 0 : if (PREDICT_FALSE (!det44_is_interface_addr (node, sw_if_index0,
169 : ip0->dst_address.as_u32)))
170 : {
171 0 : *dont_translate = 1;
172 0 : goto out;
173 : }
174 0 : det44_log_info ("unknown dst address: %U",
175 : format_ip4_address, &ip0->dst_address);
176 0 : b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
177 0 : next0 = DET44_OUT2IN_NEXT_DROP;
178 :
179 0 : goto out;
180 : }
181 :
182 1 : snat_det_reverse (mp0, &ip0->dst_address,
183 1 : clib_net_to_host_u16 (key0.out_port), &new_addr0);
184 :
185 1 : ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
186 1 : if (PREDICT_FALSE (!ses0))
187 : {
188 : /* Don't NAT packet aimed at the intfc address */
189 0 : if (PREDICT_FALSE (!det44_is_interface_addr (node, sw_if_index0,
190 : ip0->dst_address.as_u32)))
191 : {
192 0 : *dont_translate = 1;
193 0 : goto out;
194 : }
195 0 : det44_log_info ("no match src %U:%d dst %U:%d for user %U",
196 : format_ip4_address, &key0.ext_host_addr,
197 : clib_net_to_host_u16 (key0.ext_host_port),
198 : format_ip4_address, &out_addr,
199 : clib_net_to_host_u16 (key0.out_port),
200 : format_ip4_address, &new_addr0);
201 0 : b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
202 0 : next0 = DET44_OUT2IN_NEXT_DROP;
203 0 : goto out;
204 : }
205 :
206 1 : if (PREDICT_FALSE
207 : (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_reply
208 : && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
209 : reass.icmp_type_or_tcp_flags)))
210 : {
211 0 : b0->error = node->errors[DET44_OUT2IN_ERROR_BAD_ICMP_TYPE];
212 0 : next0 = DET44_OUT2IN_NEXT_DROP;
213 0 : goto out;
214 : }
215 :
216 1 : goto out;
217 :
218 1 : out:
219 1 : *proto = protocol;
220 1 : if (ses0)
221 : {
222 1 : *addr = new_addr0;
223 1 : *fib_index = dm->inside_fib_index;
224 1 : *port = ses0->in_port;
225 : }
226 1 : if (d)
227 1 : *(snat_det_session_t **) d = ses0;
228 1 : if (e)
229 1 : *(snat_det_map_t **) e = mp0;
230 1 : return next0;
231 : }
232 : #endif
233 :
234 : #ifndef CLIB_MARCH_VARIANT
235 : u32
236 1 : det44_icmp_out2in (vlib_buffer_t * b0,
237 : ip4_header_t * ip0,
238 : icmp46_header_t * icmp0,
239 : u32 sw_if_index0,
240 : u32 rx_fib_index0,
241 : vlib_node_runtime_t * node,
242 : u32 next0, u32 thread_index, void *d, void *e)
243 : {
244 1 : vlib_main_t *vm = vlib_get_main ();
245 : u32 new_addr0, old_addr0, next0_tmp, fib_index;
246 : u16 old_id0, new_id0, port, checksum0;
247 : icmp_echo_header_t *echo0, *inner_echo0;
248 : icmp46_header_t *inner_icmp0;
249 : ip4_header_t *inner_ip0;
250 : ip4_address_t addr;
251 : void *l4_header;
252 : u8 dont_translate;
253 : ip_csum_t sum0;
254 : nat_protocol_t proto;
255 :
256 1 : echo0 = (icmp_echo_header_t *) (icmp0 + 1);
257 1 : next0_tmp = icmp_match_out2in_det (node, thread_index, b0, ip0,
258 : &addr, &port, &fib_index, &proto,
259 : d, e, &dont_translate);
260 1 : if (next0_tmp != ~0)
261 0 : next0 = next0_tmp;
262 1 : if (next0 == DET44_OUT2IN_NEXT_DROP || dont_translate)
263 0 : goto out;
264 :
265 1 : if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
266 : {
267 : sum0 =
268 2 : ip_incremental_checksum_buffer (vm, b0,
269 1 : (u8 *) icmp0 -
270 1 : (u8 *) vlib_buffer_get_current (b0),
271 1 : ntohs (ip0->length) -
272 1 : ip4_header_bytes (ip0), 0);
273 1 : checksum0 = ~ip_csum_fold (sum0);
274 1 : if (checksum0 != 0 && checksum0 != 0xffff)
275 : {
276 0 : next0 = DET44_OUT2IN_NEXT_DROP;
277 0 : goto out;
278 : }
279 : }
280 :
281 1 : old_addr0 = ip0->dst_address.as_u32;
282 1 : new_addr0 = ip0->dst_address.as_u32 = addr.as_u32;
283 1 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
284 :
285 1 : sum0 = ip0->checksum;
286 1 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
287 : dst_address /* changed member */ );
288 1 : ip0->checksum = ip_csum_fold (sum0);
289 :
290 :
291 1 : if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
292 : {
293 1 : if (icmp0->checksum == 0)
294 0 : icmp0->checksum = 0xffff;
295 :
296 1 : if (!icmp_type_is_error_message (icmp0->type))
297 : {
298 1 : new_id0 = port;
299 1 : if (PREDICT_FALSE (new_id0 != echo0->identifier))
300 : {
301 1 : old_id0 = echo0->identifier;
302 1 : new_id0 = port;
303 1 : echo0->identifier = new_id0;
304 :
305 1 : sum0 = icmp0->checksum;
306 : sum0 =
307 1 : ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
308 : identifier /* changed member */ );
309 1 : icmp0->checksum = ip_csum_fold (sum0);
310 : }
311 : }
312 : else
313 : {
314 0 : inner_ip0 = (ip4_header_t *) (echo0 + 1);
315 0 : l4_header = ip4_next_header (inner_ip0);
316 :
317 0 : if (!ip4_header_checksum_is_valid (inner_ip0))
318 : {
319 0 : next0 = DET44_OUT2IN_NEXT_DROP;
320 0 : goto out;
321 : }
322 :
323 0 : old_addr0 = inner_ip0->src_address.as_u32;
324 0 : inner_ip0->src_address = addr;
325 0 : new_addr0 = inner_ip0->src_address.as_u32;
326 :
327 0 : sum0 = icmp0->checksum;
328 0 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
329 : src_address /* changed member */ );
330 0 : icmp0->checksum = ip_csum_fold (sum0);
331 :
332 0 : switch (proto)
333 : {
334 0 : case NAT_PROTOCOL_ICMP:
335 0 : inner_icmp0 = (icmp46_header_t *) l4_header;
336 0 : inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
337 :
338 0 : old_id0 = inner_echo0->identifier;
339 0 : new_id0 = port;
340 0 : inner_echo0->identifier = new_id0;
341 :
342 0 : sum0 = icmp0->checksum;
343 : sum0 =
344 0 : ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
345 : identifier);
346 0 : icmp0->checksum = ip_csum_fold (sum0);
347 0 : break;
348 0 : case NAT_PROTOCOL_UDP:
349 : case NAT_PROTOCOL_TCP:
350 0 : old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
351 0 : new_id0 = port;
352 0 : ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
353 :
354 0 : sum0 = icmp0->checksum;
355 0 : sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
356 : src_port);
357 0 : icmp0->checksum = ip_csum_fold (sum0);
358 0 : break;
359 0 : default:
360 0 : ASSERT (0);
361 : }
362 : }
363 : }
364 :
365 0 : out:
366 1 : return next0;
367 : }
368 : #endif
369 :
370 2309 : VLIB_NODE_FN (det44_out2in_node) (vlib_main_t * vm,
371 : vlib_node_runtime_t * node,
372 : vlib_frame_t * frame)
373 : {
374 : u32 n_left_from, *from;
375 9 : u32 pkts_processed = 0;
376 9 : det44_main_t *dm = &det44_main;
377 9 : u32 thread_index = vm->thread_index;
378 :
379 9 : from = vlib_frame_vector_args (frame);
380 9 : n_left_from = frame->n_vectors;
381 :
382 9 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
383 9 : u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
384 9 : vlib_get_buffers (vm, from, b, n_left_from);
385 :
386 11 : while (n_left_from >= 2)
387 : {
388 : vlib_buffer_t *b0, *b1;
389 2 : u32 next0 = DET44_OUT2IN_NEXT_LOOKUP;
390 2 : u32 next1 = DET44_OUT2IN_NEXT_LOOKUP;
391 : u32 sw_if_index0, sw_if_index1;
392 : ip4_header_t *ip0, *ip1;
393 : ip_csum_t sum0, sum1;
394 : ip4_address_t new_addr0, old_addr0, new_addr1, old_addr1;
395 : u16 new_port0, old_port0, old_port1, new_port1;
396 : udp_header_t *udp0, *udp1;
397 : tcp_header_t *tcp0, *tcp1;
398 : u32 proto0, proto1;
399 : snat_det_out_key_t key0, key1;
400 : snat_det_map_t *mp0, *mp1;
401 2 : snat_det_session_t *ses0 = 0, *ses1 = 0;
402 : u32 rx_fib_index0, rx_fib_index1;
403 : icmp46_header_t *icmp0, *icmp1;
404 :
405 2 : b0 = *b;
406 2 : b++;
407 2 : b1 = *b;
408 2 : b++;
409 :
410 : /* Prefetch next iteration. */
411 2 : if (PREDICT_TRUE (n_left_from >= 4))
412 : {
413 : vlib_buffer_t *p2, *p3;
414 :
415 0 : p2 = *b;
416 0 : p3 = *(b + 1);
417 :
418 0 : vlib_prefetch_buffer_header (p2, LOAD);
419 0 : vlib_prefetch_buffer_header (p3, LOAD);
420 :
421 0 : clib_prefetch_load (p2->data);
422 0 : clib_prefetch_load (p3->data);
423 : }
424 :
425 :
426 2 : ip0 = vlib_buffer_get_current (b0);
427 2 : udp0 = ip4_next_header (ip0);
428 2 : tcp0 = (tcp_header_t *) udp0;
429 :
430 2 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
431 :
432 2 : if (PREDICT_FALSE (ip0->ttl == 1))
433 : {
434 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
435 0 : icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
436 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
437 : 0);
438 0 : next0 = DET44_OUT2IN_NEXT_ICMP_ERROR;
439 0 : goto trace0;
440 : }
441 :
442 2 : proto0 = ip_proto_to_nat_proto (ip0->protocol);
443 :
444 2 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
445 : {
446 : rx_fib_index0 =
447 0 : ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
448 0 : icmp0 = (icmp46_header_t *) udp0;
449 :
450 0 : next0 = det44_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
451 : rx_fib_index0, node, next0,
452 : thread_index, &ses0, &mp0);
453 0 : goto trace0;
454 : }
455 :
456 2 : key0.ext_host_addr = ip0->src_address;
457 2 : key0.ext_host_port = tcp0->src;
458 2 : key0.out_port = tcp0->dst;
459 :
460 2 : mp0 = snat_det_map_by_out (&ip0->dst_address);
461 2 : if (PREDICT_FALSE (!mp0))
462 : {
463 0 : det44_log_info ("unknown dst address: %U",
464 : format_ip4_address, &ip0->dst_address);
465 0 : next0 = DET44_OUT2IN_NEXT_DROP;
466 0 : b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
467 0 : goto trace0;
468 : }
469 :
470 2 : snat_det_reverse (mp0, &ip0->dst_address,
471 2 : clib_net_to_host_u16 (tcp0->dst), &new_addr0);
472 :
473 2 : ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
474 2 : if (PREDICT_FALSE (!ses0))
475 : {
476 0 : det44_log_info ("no match src %U:%d dst %U:%d for user %U",
477 : format_ip4_address, &ip0->src_address,
478 : clib_net_to_host_u16 (tcp0->src),
479 : format_ip4_address, &ip0->dst_address,
480 : clib_net_to_host_u16 (tcp0->dst),
481 : format_ip4_address, &new_addr0);
482 0 : next0 = DET44_OUT2IN_NEXT_DROP;
483 0 : b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
484 0 : goto trace0;
485 : }
486 2 : old_port0 = udp0->dst_port;
487 2 : udp0->dst_port = new_port0 = ses0->in_port;
488 :
489 2 : old_addr0 = ip0->dst_address;
490 2 : ip0->dst_address = new_addr0;
491 2 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
492 :
493 2 : sum0 = ip0->checksum;
494 2 : sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
495 : ip4_header_t, dst_address /* changed member */ );
496 2 : ip0->checksum = ip_csum_fold (sum0);
497 :
498 2 : if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
499 : {
500 2 : if (tcp0->flags & TCP_FLAG_FIN
501 0 : && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
502 0 : ses0->state = DET44_SESSION_TCP_CLOSE_WAIT;
503 2 : else if (tcp0->flags & TCP_FLAG_ACK
504 1 : && ses0->state == DET44_SESSION_TCP_LAST_ACK)
505 0 : snat_det_ses_close (mp0, ses0);
506 :
507 2 : sum0 = tcp0->checksum;
508 2 : sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
509 : ip4_header_t,
510 : dst_address /* changed member */ );
511 2 : sum0 = ip_csum_update (sum0, old_port0, new_port0,
512 : ip4_header_t /* cheat */ ,
513 : length /* changed member */ );
514 2 : tcp0->checksum = ip_csum_fold (sum0);
515 : }
516 0 : else if (udp0->checksum)
517 : {
518 0 : sum0 = udp0->checksum;
519 0 : sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
520 : ip4_header_t,
521 : dst_address /* changed member */ );
522 0 : sum0 = ip_csum_update (sum0, old_port0, new_port0,
523 : ip4_header_t /* cheat */ ,
524 : length /* changed member */ );
525 0 : udp0->checksum = ip_csum_fold (sum0);
526 : }
527 :
528 0 : trace0:
529 :
530 2 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
531 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
532 : {
533 : det44_out2in_trace_t *t =
534 2 : vlib_add_trace (vm, node, b0, sizeof (*t));
535 2 : t->sw_if_index = sw_if_index0;
536 2 : t->next_index = next0;
537 2 : t->session_index = ~0;
538 2 : if (ses0)
539 2 : t->session_index = ses0 - mp0->sessions;
540 : }
541 :
542 2 : pkts_processed += next0 != DET44_OUT2IN_NEXT_DROP;
543 :
544 2 : ip1 = vlib_buffer_get_current (b1);
545 2 : udp1 = ip4_next_header (ip1);
546 2 : tcp1 = (tcp_header_t *) udp1;
547 :
548 2 : sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
549 :
550 2 : if (PREDICT_FALSE (ip1->ttl == 1))
551 : {
552 0 : vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
553 0 : icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
554 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
555 : 0);
556 0 : next1 = DET44_OUT2IN_NEXT_ICMP_ERROR;
557 0 : goto trace1;
558 : }
559 :
560 2 : proto1 = ip_proto_to_nat_proto (ip1->protocol);
561 :
562 2 : if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
563 : {
564 : rx_fib_index1 =
565 0 : ip4_fib_table_get_index_for_sw_if_index (sw_if_index1);
566 0 : icmp1 = (icmp46_header_t *) udp1;
567 :
568 0 : next1 = det44_icmp_out2in (b1, ip1, icmp1, sw_if_index1,
569 : rx_fib_index1, node, next1,
570 : thread_index, &ses1, &mp1);
571 0 : goto trace1;
572 : }
573 :
574 2 : key1.ext_host_addr = ip1->src_address;
575 2 : key1.ext_host_port = tcp1->src;
576 2 : key1.out_port = tcp1->dst;
577 :
578 2 : mp1 = snat_det_map_by_out (&ip1->dst_address);
579 2 : if (PREDICT_FALSE (!mp1))
580 : {
581 0 : det44_log_info ("unknown dst address: %U",
582 : format_ip4_address, &ip1->dst_address);
583 0 : next1 = DET44_OUT2IN_NEXT_DROP;
584 0 : b1->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
585 0 : goto trace1;
586 : }
587 :
588 2 : snat_det_reverse (mp1, &ip1->dst_address,
589 2 : clib_net_to_host_u16 (tcp1->dst), &new_addr1);
590 :
591 2 : ses1 = snat_det_get_ses_by_out (mp1, &new_addr1, key1.as_u64);
592 2 : if (PREDICT_FALSE (!ses1))
593 : {
594 0 : det44_log_info ("no match src %U:%d dst %U:%d for user %U",
595 : format_ip4_address, &ip1->src_address,
596 : clib_net_to_host_u16 (tcp1->src),
597 : format_ip4_address, &ip1->dst_address,
598 : clib_net_to_host_u16 (tcp1->dst),
599 : format_ip4_address, &new_addr1);
600 0 : next1 = DET44_OUT2IN_NEXT_DROP;
601 0 : b1->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
602 0 : goto trace1;
603 : }
604 2 : old_port1 = udp1->dst_port;
605 2 : udp1->dst_port = new_port1 = ses1->in_port;
606 :
607 2 : old_addr1 = ip1->dst_address;
608 2 : ip1->dst_address = new_addr1;
609 2 : vnet_buffer (b1)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
610 :
611 2 : sum1 = ip1->checksum;
612 2 : sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
613 : ip4_header_t, dst_address /* changed member */ );
614 2 : ip1->checksum = ip_csum_fold (sum1);
615 :
616 2 : if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
617 : {
618 1 : if (tcp1->flags & TCP_FLAG_FIN
619 1 : && ses1->state == DET44_SESSION_TCP_ESTABLISHED)
620 0 : ses1->state = DET44_SESSION_TCP_CLOSE_WAIT;
621 1 : else if (tcp1->flags & TCP_FLAG_ACK
622 0 : && ses1->state == DET44_SESSION_TCP_LAST_ACK)
623 0 : snat_det_ses_close (mp1, ses1);
624 :
625 1 : sum1 = tcp1->checksum;
626 1 : sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
627 : ip4_header_t,
628 : dst_address /* changed member */ );
629 1 : sum1 = ip_csum_update (sum1, old_port1, new_port1,
630 : ip4_header_t /* cheat */ ,
631 : length /* changed member */ );
632 1 : tcp1->checksum = ip_csum_fold (sum1);
633 : }
634 1 : else if (udp1->checksum)
635 : {
636 1 : sum1 = udp1->checksum;
637 1 : sum1 = ip_csum_update (sum1, old_addr1.as_u32, new_addr1.as_u32,
638 : ip4_header_t,
639 : dst_address /* changed member */ );
640 1 : sum1 = ip_csum_update (sum1, old_port1, new_port1,
641 : ip4_header_t /* cheat */ ,
642 : length /* changed member */ );
643 1 : udp1->checksum = ip_csum_fold (sum1);
644 : }
645 :
646 0 : trace1:
647 :
648 2 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
649 : && (b1->flags & VLIB_BUFFER_IS_TRACED)))
650 : {
651 : det44_out2in_trace_t *t =
652 2 : vlib_add_trace (vm, node, b1, sizeof (*t));
653 2 : t->sw_if_index = sw_if_index1;
654 2 : t->next_index = next1;
655 2 : t->session_index = ~0;
656 2 : if (ses1)
657 2 : t->session_index = ses1 - mp1->sessions;
658 : }
659 :
660 2 : pkts_processed += next1 != DET44_OUT2IN_NEXT_DROP;
661 :
662 2 : n_left_from -= 2;
663 2 : next[0] = next0;
664 2 : next[1] = next1;
665 2 : next += 2;
666 : }
667 :
668 17 : while (n_left_from > 0)
669 : {
670 : vlib_buffer_t *b0;
671 8 : u32 next0 = DET44_OUT2IN_NEXT_LOOKUP;
672 : u32 sw_if_index0;
673 : ip4_header_t *ip0;
674 : ip_csum_t sum0;
675 : ip4_address_t new_addr0, old_addr0;
676 : u16 new_port0, old_port0;
677 : udp_header_t *udp0;
678 : tcp_header_t *tcp0;
679 : u32 proto0;
680 : snat_det_out_key_t key0;
681 : snat_det_map_t *mp0;
682 8 : snat_det_session_t *ses0 = 0;
683 : u32 rx_fib_index0;
684 : icmp46_header_t *icmp0;
685 :
686 8 : b0 = *b;
687 8 : b++;
688 :
689 8 : ip0 = vlib_buffer_get_current (b0);
690 8 : udp0 = ip4_next_header (ip0);
691 8 : tcp0 = (tcp_header_t *) udp0;
692 :
693 8 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
694 :
695 8 : if (PREDICT_FALSE (ip0->ttl == 1))
696 : {
697 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
698 0 : icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
699 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
700 : 0);
701 0 : next0 = DET44_OUT2IN_NEXT_ICMP_ERROR;
702 0 : goto trace00;
703 : }
704 :
705 8 : proto0 = ip_proto_to_nat_proto (ip0->protocol);
706 :
707 8 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
708 : {
709 : rx_fib_index0 =
710 1 : ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
711 1 : icmp0 = (icmp46_header_t *) udp0;
712 :
713 1 : next0 = det44_icmp_out2in (b0, ip0, icmp0, sw_if_index0,
714 : rx_fib_index0, node, next0,
715 : thread_index, &ses0, &mp0);
716 1 : goto trace00;
717 : }
718 :
719 7 : key0.ext_host_addr = ip0->src_address;
720 7 : key0.ext_host_port = tcp0->src;
721 7 : key0.out_port = tcp0->dst;
722 :
723 7 : mp0 = snat_det_map_by_out (&ip0->dst_address);
724 7 : if (PREDICT_FALSE (!mp0))
725 : {
726 0 : det44_log_info ("unknown dst address: %U",
727 : format_ip4_address, &ip0->dst_address);
728 0 : next0 = DET44_OUT2IN_NEXT_DROP;
729 0 : b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
730 0 : goto trace00;
731 : }
732 :
733 7 : snat_det_reverse (mp0, &ip0->dst_address,
734 7 : clib_net_to_host_u16 (tcp0->dst), &new_addr0);
735 :
736 7 : ses0 = snat_det_get_ses_by_out (mp0, &new_addr0, key0.as_u64);
737 7 : if (PREDICT_FALSE (!ses0))
738 : {
739 0 : det44_log_info ("no match src %U:%d dst %U:%d for user %U",
740 : format_ip4_address, &ip0->src_address,
741 : clib_net_to_host_u16 (tcp0->src),
742 : format_ip4_address, &ip0->dst_address,
743 : clib_net_to_host_u16 (tcp0->dst),
744 : format_ip4_address, &new_addr0);
745 0 : next0 = DET44_OUT2IN_NEXT_DROP;
746 0 : b0->error = node->errors[DET44_OUT2IN_ERROR_NO_TRANSLATION];
747 0 : goto trace00;
748 : }
749 7 : old_port0 = udp0->dst_port;
750 7 : udp0->dst_port = new_port0 = ses0->in_port;
751 :
752 7 : old_addr0 = ip0->dst_address;
753 7 : ip0->dst_address = new_addr0;
754 7 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = dm->inside_fib_index;
755 :
756 7 : sum0 = ip0->checksum;
757 7 : sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
758 : ip4_header_t, dst_address /* changed member */ );
759 7 : ip0->checksum = ip_csum_fold (sum0);
760 :
761 7 : if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
762 : {
763 7 : if (tcp0->flags & TCP_FLAG_FIN
764 1 : && ses0->state == DET44_SESSION_TCP_ESTABLISHED)
765 1 : ses0->state = DET44_SESSION_TCP_CLOSE_WAIT;
766 6 : else if (tcp0->flags & TCP_FLAG_ACK
767 4 : && ses0->state == DET44_SESSION_TCP_LAST_ACK)
768 1 : snat_det_ses_close (mp0, ses0);
769 :
770 7 : sum0 = tcp0->checksum;
771 7 : sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
772 : ip4_header_t,
773 : dst_address /* changed member */ );
774 7 : sum0 = ip_csum_update (sum0, old_port0, new_port0,
775 : ip4_header_t /* cheat */ ,
776 : length /* changed member */ );
777 7 : tcp0->checksum = ip_csum_fold (sum0);
778 : }
779 0 : else if (udp0->checksum)
780 : {
781 0 : sum0 = udp0->checksum;
782 0 : sum0 = ip_csum_update (sum0, old_addr0.as_u32, new_addr0.as_u32,
783 : ip4_header_t,
784 : dst_address /* changed member */ );
785 0 : sum0 = ip_csum_update (sum0, old_port0, new_port0,
786 : ip4_header_t /* cheat */ ,
787 : length /* changed member */ );
788 0 : udp0->checksum = ip_csum_fold (sum0);
789 : }
790 :
791 0 : trace00:
792 :
793 8 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
794 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
795 : {
796 : det44_out2in_trace_t *t =
797 8 : vlib_add_trace (vm, node, b0, sizeof (*t));
798 8 : t->sw_if_index = sw_if_index0;
799 8 : t->next_index = next0;
800 8 : t->session_index = ~0;
801 8 : if (ses0)
802 8 : t->session_index = ses0 - mp0->sessions;
803 : }
804 :
805 8 : pkts_processed += next0 != DET44_OUT2IN_NEXT_DROP;
806 :
807 8 : n_left_from--;
808 8 : next[0] = next0;
809 8 : next++;
810 : }
811 9 : vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
812 9 : frame->n_vectors);
813 :
814 :
815 9 : vlib_node_increment_counter (vm, dm->out2in_node_index,
816 : DET44_OUT2IN_ERROR_OUT2IN_PACKETS,
817 : pkts_processed);
818 9 : return frame->n_vectors;
819 : }
820 :
821 : /* *INDENT-OFF* */
822 161324 : VLIB_REGISTER_NODE (det44_out2in_node) = {
823 : .name = "det44-out2in",
824 : .vector_size = sizeof (u32),
825 : .format_trace = format_det44_out2in_trace,
826 : .type = VLIB_NODE_TYPE_INTERNAL,
827 : .n_errors = ARRAY_LEN(det44_out2in_error_strings),
828 : .error_strings = det44_out2in_error_strings,
829 : .runtime_data_bytes = sizeof (det44_runtime_t),
830 : .n_next_nodes = DET44_OUT2IN_N_NEXT,
831 : /* edit / add dispositions here */
832 : .next_nodes = {
833 : [DET44_OUT2IN_NEXT_DROP] = "error-drop",
834 : [DET44_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
835 : [DET44_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
836 : },
837 : };
838 : /* *INDENT-ON* */
839 :
840 : /*
841 : * fd.io coding-style-patch-verification: ON
842 : *
843 : * Local Variables:
844 : * eval: (c-set-style "gnu")
845 : * End:
846 : */
|