Line data Source code
1 : /*
2 : * Copyright (c) 2016 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 NAT44 EI outside to inside network translation
18 : */
19 :
20 : #include <vlib/vlib.h>
21 :
22 : #include <vnet/vnet.h>
23 : #include <vnet/ip/ip.h>
24 : #include <vnet/ethernet/ethernet.h>
25 : #include <vnet/udp/udp_local.h>
26 : #include <vnet/fib/ip4_fib.h>
27 :
28 : #include <vppinfra/hash.h>
29 : #include <vppinfra/error.h>
30 :
31 : #include <nat/lib/log.h>
32 : #include <nat/lib/nat_syslog.h>
33 : #include <nat/lib/ipfix_logging.h>
34 : #include <nat/nat44-ei/nat44_ei_inlines.h>
35 : #include <nat/nat44-ei/nat44_ei.h>
36 :
37 : typedef struct
38 : {
39 : u32 sw_if_index;
40 : u32 next_index;
41 : u32 session_index;
42 : } nat44_ei_out2in_trace_t;
43 :
44 : /* packet trace format function */
45 : static u8 *
46 55 : format_nat44_ei_out2in_trace (u8 *s, va_list *args)
47 : {
48 55 : CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
49 55 : CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
50 55 : nat44_ei_out2in_trace_t *t = va_arg (*args, nat44_ei_out2in_trace_t *);
51 :
52 : s =
53 55 : format (s,
54 : "NAT44_OUT2IN: sw_if_index %d, next index %d, session index %d",
55 : t->sw_if_index, t->next_index, t->session_index);
56 55 : return s;
57 : }
58 :
59 : #define foreach_nat44_ei_out2in_error \
60 : _ (UNSUPPORTED_PROTOCOL, "unsupported protocol") \
61 : _ (OUT_OF_PORTS, "out of ports") \
62 : _ (BAD_ICMP_TYPE, "unsupported ICMP type") \
63 : _ (NO_TRANSLATION, "no translation") \
64 : _ (MAX_SESSIONS_EXCEEDED, "maximum sessions exceeded") \
65 : _ (CANNOT_CREATE_USER, "cannot create NAT user")
66 :
67 : typedef enum
68 : {
69 : #define _(sym, str) NAT44_EI_OUT2IN_ERROR_##sym,
70 : foreach_nat44_ei_out2in_error
71 : #undef _
72 : NAT44_EI_OUT2IN_N_ERROR,
73 : } nat44_ei_out2in_error_t;
74 :
75 : static char *nat44_ei_out2in_error_strings[] = {
76 : #define _(sym,string) string,
77 : foreach_nat44_ei_out2in_error
78 : #undef _
79 : };
80 :
81 : typedef enum
82 : {
83 : NAT44_EI_OUT2IN_NEXT_DROP,
84 : NAT44_EI_OUT2IN_NEXT_LOOKUP,
85 : NAT44_EI_OUT2IN_NEXT_ICMP_ERROR,
86 : NAT44_EI_OUT2IN_N_NEXT,
87 : } nat44_ei_out2in_next_t;
88 :
89 : #ifndef CLIB_MARCH_VARIANT
90 : int
91 49 : nat44_o2i_is_idle_session_cb (clib_bihash_kv_8_8_t * kv, void *arg)
92 : {
93 49 : nat44_ei_main_t *nm = &nat44_ei_main;
94 49 : nat44_ei_is_idle_session_ctx_t *ctx = arg;
95 : nat44_ei_session_t *s;
96 : u64 sess_timeout_time;
97 49 : nat44_ei_main_per_thread_data_t *tnm =
98 49 : vec_elt_at_index (nm->per_thread_data, ctx->thread_index);
99 : clib_bihash_kv_8_8_t s_kv;
100 :
101 49 : if (ctx->thread_index != nat_value_get_thread_index (kv))
102 : {
103 0 : return 0;
104 : }
105 :
106 49 : s = pool_elt_at_index (tnm->sessions, nat_value_get_session_index (kv));
107 98 : sess_timeout_time = s->last_heard + (f64) nat_session_get_timeout (
108 49 : &nm->timeouts, s->nat_proto, s->state);
109 49 : if (ctx->now >= sess_timeout_time)
110 : {
111 0 : init_nat_i2o_k (&s_kv, s);
112 0 : if (clib_bihash_add_del_8_8 (&nm->in2out, &s_kv, 0))
113 0 : nat_elog_warn (nm, "out2in key del failed");
114 :
115 0 : nat_ipfix_logging_nat44_ses_delete (
116 : ctx->thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
117 0 : nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
118 : s->in2out.fib_index);
119 :
120 0 : nat_syslog_nat44_apmdel (s->user_index, s->in2out.fib_index,
121 0 : &s->in2out.addr, s->in2out.port,
122 0 : &s->out2in.addr, s->out2in.port, s->nat_proto);
123 :
124 0 : nat_ha_sdel (&s->out2in.addr, s->out2in.port, &s->ext_host_addr,
125 0 : s->ext_host_port, s->nat_proto, s->out2in.fib_index,
126 : ctx->thread_index);
127 :
128 0 : if (!nat44_ei_is_session_static (s))
129 0 : nat44_ei_free_outside_address_and_port (
130 0 : nm->addresses, ctx->thread_index, &s->out2in.addr, s->out2in.port,
131 : s->nat_proto);
132 :
133 0 : nat44_ei_delete_session (nm, s, ctx->thread_index);
134 0 : return 1;
135 : }
136 :
137 49 : return 0;
138 : }
139 : #endif
140 :
141 : /**
142 : * @brief Create session for static mapping.
143 : *
144 : * Create NAT session initiated by host from external network with static
145 : * mapping.
146 : *
147 : * @param nm NAT main.
148 : * @param b0 Vlib buffer.
149 : * @param in2out In2out NAT44 session key.
150 : * @param out2in Out2in NAT44 session key.
151 : * @param node Vlib node.
152 : *
153 : * @returns NAT44_EI session if successfully created otherwise 0.
154 : */
155 : static inline nat44_ei_session_t *
156 17 : create_session_for_static_mapping (
157 : nat44_ei_main_t *nm, vlib_buffer_t *b0, ip4_address_t i2o_addr, u16 i2o_port,
158 : u32 i2o_fib_index, ip4_address_t o2i_addr, u16 o2i_port, u32 o2i_fib_index,
159 : nat_protocol_t proto, vlib_node_runtime_t *node, u32 thread_index, f64 now)
160 : {
161 : nat44_ei_user_t *u;
162 : nat44_ei_session_t *s;
163 : clib_bihash_kv_8_8_t kv0;
164 : ip4_header_t *ip0;
165 : udp_header_t *udp0;
166 : nat44_ei_is_idle_session_ctx_t ctx0;
167 :
168 17 : if (PREDICT_FALSE (nat44_ei_maximum_sessions_exceeded (nm, thread_index)))
169 : {
170 0 : b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_MAX_SESSIONS_EXCEEDED];
171 0 : nat_elog_notice (nm, "maximum sessions exceeded");
172 0 : return 0;
173 : }
174 :
175 17 : ip0 = vlib_buffer_get_current (b0);
176 17 : udp0 = ip4_next_header (ip0);
177 :
178 17 : u = nat44_ei_user_get_or_create (nm, &i2o_addr, i2o_fib_index, thread_index);
179 17 : if (!u)
180 : {
181 0 : b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_CANNOT_CREATE_USER];
182 0 : return 0;
183 : }
184 :
185 17 : s = nat44_ei_session_alloc_or_recycle (nm, u, thread_index, now);
186 17 : if (!s)
187 : {
188 0 : nat44_ei_delete_user_with_no_session (nm, u, thread_index);
189 0 : nat_elog_warn (nm, "create NAT session failed");
190 0 : return 0;
191 : }
192 :
193 17 : s->flags |= NAT44_EI_SESSION_FLAG_STATIC_MAPPING;
194 17 : s->ext_host_addr.as_u32 = ip0->src_address.as_u32;
195 17 : s->ext_host_port = udp0->src_port;
196 17 : nat44_ei_user_session_increment (nm, u, 1 /* static */);
197 17 : s->in2out.addr = i2o_addr;
198 17 : s->in2out.port = i2o_port;
199 17 : s->in2out.fib_index = i2o_fib_index;
200 17 : s->out2in.addr = o2i_addr;
201 17 : s->out2in.port = o2i_port;
202 17 : s->out2in.fib_index = o2i_fib_index;
203 17 : s->nat_proto = proto;
204 :
205 : /* Add to translation hashes */
206 17 : ctx0.now = now;
207 17 : ctx0.thread_index = thread_index;
208 17 : init_nat_i2o_kv (&kv0, s, thread_index,
209 17 : s - nm->per_thread_data[thread_index].sessions);
210 17 : if (clib_bihash_add_or_overwrite_stale_8_8 (
211 : &nm->in2out, &kv0, nat44_i2o_is_idle_session_cb, &ctx0))
212 0 : nat_elog_notice (nm, "in2out key add failed");
213 :
214 17 : init_nat_o2i_kv (&kv0, s, thread_index,
215 17 : s - nm->per_thread_data[thread_index].sessions);
216 17 : if (clib_bihash_add_or_overwrite_stale_8_8 (
217 : &nm->out2in, &kv0, nat44_o2i_is_idle_session_cb, &ctx0))
218 0 : nat_elog_notice (nm, "out2in key add failed");
219 :
220 : /* log NAT event */
221 17 : nat_ipfix_logging_nat44_ses_create (
222 : thread_index, s->in2out.addr.as_u32, s->out2in.addr.as_u32,
223 17 : nat_proto_to_ip_proto (s->nat_proto), s->in2out.port, s->out2in.port,
224 : s->in2out.fib_index);
225 :
226 17 : nat_syslog_nat44_apmadd (s->user_index, s->in2out.fib_index,
227 17 : &s->in2out.addr, s->in2out.port, &s->out2in.addr,
228 17 : s->out2in.port, s->nat_proto);
229 :
230 17 : nat_ha_sadd (&s->in2out.addr, s->in2out.port, &s->out2in.addr,
231 17 : s->out2in.port, &s->ext_host_addr, s->ext_host_port,
232 17 : &s->ext_host_nat_addr, s->ext_host_nat_port,
233 17 : s->nat_proto, s->in2out.fib_index, s->flags, thread_index, 0);
234 :
235 17 : return s;
236 : }
237 :
238 : #ifndef CLIB_MARCH_VARIANT
239 : static_always_inline nat44_ei_out2in_error_t
240 37 : icmp_get_key (vlib_buffer_t *b, ip4_header_t *ip0, ip4_address_t *addr,
241 : u16 *port, nat_protocol_t *nat_proto)
242 : {
243 : icmp46_header_t *icmp0;
244 37 : icmp_echo_header_t *echo0, *inner_echo0 = 0;
245 : ip4_header_t *inner_ip0;
246 37 : void *l4_header = 0;
247 : icmp46_header_t *inner_icmp0;
248 :
249 37 : icmp0 = (icmp46_header_t *) ip4_next_header (ip0);
250 37 : echo0 = (icmp_echo_header_t *) (icmp0 + 1);
251 :
252 37 : if (!icmp_type_is_error_message
253 37 : (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))
254 : {
255 33 : *nat_proto = NAT_PROTOCOL_ICMP;
256 33 : *addr = ip0->dst_address;
257 33 : *port = vnet_buffer (b)->ip.reass.l4_src_port;
258 : }
259 : else
260 : {
261 4 : inner_ip0 = (ip4_header_t *) (echo0 + 1);
262 4 : l4_header = ip4_next_header (inner_ip0);
263 4 : *nat_proto = ip_proto_to_nat_proto (inner_ip0->protocol);
264 4 : *addr = inner_ip0->src_address;
265 4 : switch (*nat_proto)
266 : {
267 1 : case NAT_PROTOCOL_ICMP:
268 1 : inner_icmp0 = (icmp46_header_t *) l4_header;
269 1 : inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
270 1 : *port = inner_echo0->identifier;
271 1 : break;
272 3 : case NAT_PROTOCOL_UDP:
273 : case NAT_PROTOCOL_TCP:
274 3 : *port = ((tcp_udp_header_t *) l4_header)->src_port;
275 3 : break;
276 0 : default:
277 0 : return NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL;
278 : }
279 : }
280 37 : return -1; /* success */
281 : }
282 :
283 : /**
284 : * Get address and port values to be used for ICMP packet translation
285 : * and create session if needed
286 : *
287 : * @param[in,out] nm NAT main
288 : * @param[in,out] node NAT node runtime
289 : * @param[in] thread_index thread index
290 : * @param[in,out] b0 buffer containing packet to be translated
291 : * @param[in,out] ip0 ip header
292 : * @param[out] p_proto protocol used for matching
293 : * @param[out] p_value address and port after NAT translation
294 : * @param[out] p_dont_translate if packet should not be translated
295 : * @param d optional parameter
296 : * @param e optional parameter
297 : */
298 : u32
299 37 : nat44_ei_icmp_match_out2in_slow (vlib_node_runtime_t *node, u32 thread_index,
300 : vlib_buffer_t *b0, ip4_header_t *ip0,
301 : ip4_address_t *addr, u16 *port,
302 : u32 *fib_index, nat_protocol_t *proto,
303 : nat44_ei_session_t **p_s0, u8 *dont_translate)
304 : {
305 37 : nat44_ei_main_t *nm = &nat44_ei_main;
306 37 : nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
307 : u32 sw_if_index0;
308 37 : nat44_ei_session_t *s0 = 0;
309 : clib_bihash_kv_8_8_t kv0, value0;
310 : u8 is_addr_only;
311 37 : u32 next0 = ~0;
312 : int err;
313 : u8 identity_nat;
314 37 : vlib_main_t *vm = vlib_get_main ();
315 37 : *dont_translate = 0;
316 :
317 37 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
318 37 : *fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
319 :
320 37 : *proto = 0;
321 :
322 37 : err = icmp_get_key (b0, ip0, addr, port, proto);
323 37 : if (err != -1)
324 : {
325 0 : b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
326 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
327 0 : goto out;
328 : }
329 :
330 : ip4_address_t mapping_addr;
331 : u16 mapping_port;
332 : u32 mapping_fib_index;
333 :
334 37 : init_nat_k (&kv0, *addr, *port, *fib_index, *proto);
335 37 : if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
336 : {
337 : /* Try to match static mapping by external address and port,
338 : destination address and port in packet */
339 8 : if (nat44_ei_static_mapping_match (
340 8 : *addr, *port, *fib_index, *proto, &mapping_addr, &mapping_port,
341 : &mapping_fib_index, 1, &is_addr_only, &identity_nat))
342 : {
343 2 : if (!nm->forwarding_enabled)
344 : {
345 : /* Don't NAT packet aimed at the intfc address */
346 1 : if (PREDICT_FALSE (nat44_ei_is_interface_addr (
347 : nm->ip4_main, node, sw_if_index0,
348 : ip0->dst_address.as_u32)))
349 : {
350 1 : *dont_translate = 1;
351 1 : goto out;
352 : }
353 0 : b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
354 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
355 0 : goto out;
356 : }
357 : else
358 : {
359 1 : *dont_translate = 1;
360 1 : goto out;
361 : }
362 : }
363 :
364 6 : if (PREDICT_FALSE
365 : (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
366 : ICMP4_echo_reply
367 : && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
368 : ICMP4_echo_request || !is_addr_only)))
369 : {
370 0 : b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
371 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
372 0 : goto out;
373 : }
374 :
375 6 : if (PREDICT_FALSE (identity_nat))
376 : {
377 0 : *dont_translate = 1;
378 0 : goto out;
379 : }
380 : /* Create session initiated by host from external network */
381 6 : s0 = create_session_for_static_mapping (
382 6 : nm, b0, mapping_addr, mapping_port, mapping_fib_index, *addr, *port,
383 : *fib_index, *proto, node, thread_index, vlib_time_now (vm));
384 :
385 6 : if (!s0)
386 : {
387 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
388 0 : goto out;
389 : }
390 : }
391 : else
392 : {
393 29 : if (PREDICT_FALSE
394 : (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
395 : ICMP4_echo_reply
396 : && vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
397 : ICMP4_echo_request
398 : && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
399 : reass.icmp_type_or_tcp_flags)))
400 : {
401 0 : b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
402 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
403 0 : goto out;
404 : }
405 :
406 29 : s0 = pool_elt_at_index (tnm->sessions,
407 : nat_value_get_session_index (&value0));
408 : }
409 :
410 37 : out:
411 37 : if (s0)
412 : {
413 35 : *addr = s0->in2out.addr;
414 35 : *port = s0->in2out.port;
415 35 : *fib_index = s0->in2out.fib_index;
416 : }
417 37 : if (p_s0)
418 37 : *p_s0 = s0;
419 37 : return next0;
420 : }
421 : #endif
422 :
423 : #ifndef CLIB_MARCH_VARIANT
424 : u32
425 0 : nat44_ei_icmp_match_out2in_fast (vlib_node_runtime_t *node, u32 thread_index,
426 : vlib_buffer_t *b0, ip4_header_t *ip0,
427 : ip4_address_t *mapping_addr,
428 : u16 *mapping_port, u32 *mapping_fib_index,
429 : nat_protocol_t *proto,
430 : nat44_ei_session_t **p_s0, u8 *dont_translate)
431 : {
432 0 : nat44_ei_main_t *nm = &nat44_ei_main;
433 : u32 sw_if_index0;
434 : u32 rx_fib_index0;
435 : u8 is_addr_only;
436 0 : u32 next0 = ~0;
437 : int err;
438 : ip4_address_t addr;
439 : u16 port;
440 0 : *dont_translate = 0;
441 :
442 0 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
443 0 : rx_fib_index0 = ip4_fib_table_get_index_for_sw_if_index (sw_if_index0);
444 :
445 0 : err = icmp_get_key (b0, ip0, &addr, &port, proto);
446 0 : if (err != -1)
447 : {
448 0 : b0->error = node->errors[err];
449 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
450 0 : goto out;
451 : }
452 0 : if (nat44_ei_static_mapping_match (addr, port, rx_fib_index0, *proto,
453 : mapping_addr, mapping_port,
454 : mapping_fib_index, 1, &is_addr_only, 0))
455 : {
456 : /* Don't NAT packet aimed at the intfc address */
457 0 : if (nat44_ei_is_interface_addr (nm->ip4_main, node, sw_if_index0,
458 : ip0->dst_address.as_u32))
459 : {
460 0 : *dont_translate = 1;
461 0 : goto out;
462 : }
463 0 : b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
464 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
465 0 : goto out;
466 : }
467 :
468 0 : if (PREDICT_FALSE
469 : (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags != ICMP4_echo_reply
470 : && (vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags !=
471 : ICMP4_echo_request || !is_addr_only)
472 : && !icmp_type_is_error_message (vnet_buffer (b0)->ip.
473 : reass.icmp_type_or_tcp_flags)))
474 : {
475 0 : b0->error = node->errors[NAT44_EI_OUT2IN_ERROR_BAD_ICMP_TYPE];
476 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
477 0 : goto out;
478 : }
479 :
480 0 : out:
481 0 : return next0;
482 : }
483 : #endif
484 :
485 : u32 nat44_ei_icmp_out2in (vlib_buffer_t *b0, ip4_header_t *ip0,
486 : icmp46_header_t *icmp0, u32 sw_if_index0,
487 : u32 rx_fib_index0, vlib_node_runtime_t *node,
488 : u32 next0, u32 thread_index,
489 : nat44_ei_session_t **p_s0);
490 :
491 : #ifndef CLIB_MARCH_VARIANT
492 : u32
493 37 : nat44_ei_icmp_out2in (vlib_buffer_t *b0, ip4_header_t *ip0,
494 : icmp46_header_t *icmp0, u32 sw_if_index0,
495 : u32 rx_fib_index0, vlib_node_runtime_t *node, u32 next0,
496 : u32 thread_index, nat44_ei_session_t **p_s0)
497 : {
498 37 : nat44_ei_main_t *nm = &nat44_ei_main;
499 37 : icmp_echo_header_t *echo0, *inner_echo0 = 0;
500 37 : ip4_header_t *inner_ip0 = 0;
501 37 : void *l4_header = 0;
502 : icmp46_header_t *inner_icmp0;
503 : u8 dont_translate;
504 : u32 new_addr0, old_addr0;
505 : u16 old_id0, new_id0;
506 : ip_csum_t sum0;
507 : u16 checksum0;
508 : u32 next0_tmp;
509 37 : vlib_main_t *vm = vlib_get_main ();
510 : ip4_address_t addr;
511 : u16 port;
512 : u32 fib_index;
513 : nat_protocol_t proto;
514 :
515 37 : echo0 = (icmp_echo_header_t *) (icmp0 + 1);
516 :
517 37 : if (PREDICT_TRUE (nm->pat))
518 : {
519 37 : next0_tmp = nat44_ei_icmp_match_out2in_slow (
520 : node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
521 : &dont_translate);
522 : }
523 : else
524 : {
525 0 : next0_tmp = nat44_ei_icmp_match_out2in_fast (
526 : node, thread_index, b0, ip0, &addr, &port, &fib_index, &proto, p_s0,
527 : &dont_translate);
528 : }
529 :
530 37 : if (next0_tmp != ~0)
531 0 : next0 = next0_tmp;
532 37 : if (next0 == NAT44_EI_OUT2IN_NEXT_DROP || dont_translate)
533 2 : goto out;
534 :
535 35 : if (PREDICT_TRUE (!ip4_is_fragment (ip0)))
536 : {
537 : sum0 =
538 52 : ip_incremental_checksum_buffer (vm, b0,
539 26 : (u8 *) icmp0 -
540 26 : (u8 *) vlib_buffer_get_current (b0),
541 26 : ntohs (ip0->length) -
542 26 : ip4_header_bytes (ip0), 0);
543 26 : checksum0 = ~ip_csum_fold (sum0);
544 26 : if (checksum0 != 0 && checksum0 != 0xffff)
545 : {
546 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
547 0 : goto out;
548 : }
549 : }
550 :
551 35 : old_addr0 = ip0->dst_address.as_u32;
552 35 : new_addr0 = ip0->dst_address.as_u32 = addr.as_u32;
553 35 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = fib_index;
554 :
555 35 : sum0 = ip0->checksum;
556 35 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
557 : dst_address /* changed member */ );
558 35 : ip0->checksum = ip_csum_fold (sum0);
559 :
560 :
561 35 : if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
562 : {
563 29 : if (icmp0->checksum == 0)
564 0 : icmp0->checksum = 0xffff;
565 :
566 29 : if (!icmp_type_is_error_message (icmp0->type))
567 : {
568 25 : new_id0 = port;
569 25 : if (PREDICT_FALSE (new_id0 != echo0->identifier))
570 : {
571 19 : old_id0 = echo0->identifier;
572 19 : new_id0 = port;
573 19 : echo0->identifier = new_id0;
574 :
575 19 : sum0 = icmp0->checksum;
576 : sum0 =
577 19 : ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
578 : identifier /* changed member */ );
579 19 : icmp0->checksum = ip_csum_fold (sum0);
580 : }
581 : }
582 : else
583 : {
584 4 : inner_ip0 = (ip4_header_t *) (echo0 + 1);
585 4 : l4_header = ip4_next_header (inner_ip0);
586 :
587 4 : if (!ip4_header_checksum_is_valid (inner_ip0))
588 : {
589 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
590 0 : goto out;
591 : }
592 :
593 4 : old_addr0 = inner_ip0->src_address.as_u32;
594 4 : inner_ip0->src_address = addr;
595 4 : new_addr0 = inner_ip0->src_address.as_u32;
596 :
597 4 : sum0 = icmp0->checksum;
598 4 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t,
599 : src_address /* changed member */ );
600 4 : icmp0->checksum = ip_csum_fold (sum0);
601 :
602 4 : switch (proto)
603 : {
604 1 : case NAT_PROTOCOL_ICMP:
605 1 : inner_icmp0 = (icmp46_header_t *) l4_header;
606 1 : inner_echo0 = (icmp_echo_header_t *) (inner_icmp0 + 1);
607 :
608 1 : old_id0 = inner_echo0->identifier;
609 1 : new_id0 = port;
610 1 : inner_echo0->identifier = new_id0;
611 :
612 1 : sum0 = icmp0->checksum;
613 : sum0 =
614 1 : ip_csum_update (sum0, old_id0, new_id0, icmp_echo_header_t,
615 : identifier);
616 1 : icmp0->checksum = ip_csum_fold (sum0);
617 1 : break;
618 3 : case NAT_PROTOCOL_UDP:
619 : case NAT_PROTOCOL_TCP:
620 3 : old_id0 = ((tcp_udp_header_t *) l4_header)->src_port;
621 3 : new_id0 = port;
622 3 : ((tcp_udp_header_t *) l4_header)->src_port = new_id0;
623 :
624 3 : sum0 = icmp0->checksum;
625 3 : sum0 = ip_csum_update (sum0, old_id0, new_id0, tcp_udp_header_t,
626 : src_port);
627 3 : icmp0->checksum = ip_csum_fold (sum0);
628 3 : break;
629 0 : default:
630 0 : ASSERT (0);
631 : }
632 : }
633 : }
634 :
635 6 : out:
636 37 : return next0;
637 : }
638 : #endif
639 :
640 : static inline u32
641 37 : nat44_ei_icmp_out2in_slow_path (nat44_ei_main_t *nm, vlib_buffer_t *b0,
642 : ip4_header_t *ip0, icmp46_header_t *icmp0,
643 : u32 sw_if_index0, u32 rx_fib_index0,
644 : vlib_node_runtime_t *node, u32 next0, f64 now,
645 : u32 thread_index, nat44_ei_session_t **p_s0)
646 : {
647 37 : vlib_main_t *vm = vlib_get_main ();
648 :
649 37 : next0 = nat44_ei_icmp_out2in (b0, ip0, icmp0, sw_if_index0, rx_fib_index0,
650 : node, next0, thread_index, p_s0);
651 37 : nat44_ei_session_t *s0 = *p_s0;
652 37 : if (PREDICT_TRUE (next0 != NAT44_EI_OUT2IN_NEXT_DROP && s0))
653 : {
654 : /* Accounting */
655 35 : nat44_ei_session_update_counters (
656 : s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
657 : /* Per-user LRU list maintenance */
658 35 : nat44_ei_session_update_lru (nm, s0, thread_index);
659 : }
660 37 : return next0;
661 : }
662 :
663 : static int
664 1 : nat_out2in_sm_unknown_proto (nat44_ei_main_t *nm, vlib_buffer_t *b,
665 : ip4_header_t *ip, u32 rx_fib_index)
666 : {
667 : clib_bihash_kv_8_8_t kv, value;
668 : nat44_ei_static_mapping_t *m;
669 : u32 old_addr, new_addr;
670 : ip_csum_t sum;
671 :
672 1 : init_nat_k (&kv, ip->dst_address, 0, 0, 0);
673 1 : if (clib_bihash_search_8_8 (&nm->static_mapping_by_external, &kv, &value))
674 0 : return 1;
675 :
676 1 : m = pool_elt_at_index (nm->static_mappings, value.value);
677 :
678 1 : old_addr = ip->dst_address.as_u32;
679 1 : new_addr = ip->dst_address.as_u32 = m->local_addr.as_u32;
680 1 : sum = ip->checksum;
681 1 : sum = ip_csum_update (sum, old_addr, new_addr, ip4_header_t, dst_address);
682 1 : ip->checksum = ip_csum_fold (sum);
683 :
684 1 : vnet_buffer (b)->sw_if_index[VLIB_TX] = m->fib_index;
685 1 : return 0;
686 : }
687 :
688 2342 : VLIB_NODE_FN (nat44_ei_out2in_node)
689 : (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
690 : {
691 : u32 n_left_from, *from;
692 42 : nat44_ei_main_t *nm = &nat44_ei_main;
693 42 : f64 now = vlib_time_now (vm);
694 42 : u32 thread_index = vm->thread_index;
695 42 : nat44_ei_main_per_thread_data_t *tnm = &nm->per_thread_data[thread_index];
696 :
697 42 : from = vlib_frame_vector_args (frame);
698 42 : n_left_from = frame->n_vectors;
699 :
700 42 : vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs;
701 42 : u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
702 42 : vlib_get_buffers (vm, from, b, n_left_from);
703 :
704 100 : while (n_left_from >= 2)
705 : {
706 : vlib_buffer_t *b0, *b1;
707 58 : u32 next0 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
708 58 : u32 next1 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
709 : u32 sw_if_index0, sw_if_index1;
710 : ip4_header_t *ip0, *ip1;
711 : ip_csum_t sum0, sum1;
712 : u32 new_addr0, old_addr0;
713 : u16 new_port0, old_port0;
714 : u32 new_addr1, old_addr1;
715 : u16 new_port1, old_port1;
716 : udp_header_t *udp0, *udp1;
717 : tcp_header_t *tcp0, *tcp1;
718 : icmp46_header_t *icmp0, *icmp1;
719 : u32 rx_fib_index0, rx_fib_index1;
720 : u32 proto0, proto1;
721 58 : nat44_ei_session_t *s0 = 0, *s1 = 0;
722 : clib_bihash_kv_8_8_t kv0, kv1, value0, value1;
723 : u8 identity_nat0, identity_nat1;
724 : ip4_address_t sm_addr0, sm_addr1;
725 : u16 sm_port0, sm_port1;
726 : u32 sm_fib_index0, sm_fib_index1;
727 :
728 58 : b0 = *b;
729 58 : b++;
730 58 : b1 = *b;
731 58 : b++;
732 :
733 : /* Prefetch next iteration. */
734 58 : if (PREDICT_TRUE (n_left_from >= 4))
735 : {
736 : vlib_buffer_t *p2, *p3;
737 :
738 24 : p2 = *b;
739 24 : p3 = *(b + 1);
740 :
741 24 : vlib_prefetch_buffer_header (p2, LOAD);
742 24 : vlib_prefetch_buffer_header (p3, LOAD);
743 :
744 24 : clib_prefetch_load (p2->data);
745 24 : clib_prefetch_load (p3->data);
746 : }
747 :
748 58 : vnet_buffer (b0)->snat.flags = 0;
749 58 : vnet_buffer (b1)->snat.flags = 0;
750 :
751 58 : ip0 = vlib_buffer_get_current (b0);
752 58 : udp0 = ip4_next_header (ip0);
753 58 : tcp0 = (tcp_header_t *) udp0;
754 58 : icmp0 = (icmp46_header_t *) udp0;
755 :
756 58 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
757 58 : rx_fib_index0 =
758 58 : vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
759 :
760 58 : if (PREDICT_FALSE (ip0->ttl == 1))
761 : {
762 2 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
763 2 : icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
764 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
765 : 0);
766 2 : next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
767 2 : goto trace0;
768 : }
769 :
770 56 : proto0 = ip_proto_to_nat_proto (ip0->protocol);
771 :
772 56 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
773 : {
774 0 : if (nat_out2in_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
775 : {
776 0 : if (!nm->forwarding_enabled)
777 : {
778 0 : b0->error =
779 0 : node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
780 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
781 : }
782 : }
783 0 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
784 : thread_index, sw_if_index0, 1);
785 :
786 0 : goto trace0;
787 : }
788 :
789 56 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
790 : {
791 5 : next0 = nat44_ei_icmp_out2in_slow_path (
792 : nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0, now,
793 : thread_index, &s0);
794 5 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
795 : thread_index, sw_if_index0, 1);
796 5 : goto trace0;
797 : }
798 :
799 51 : init_nat_k (&kv0, ip0->dst_address,
800 51 : vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
801 : proto0);
802 51 : if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
803 : {
804 : /* Try to match static mapping by external address and port,
805 : destination address and port in packet */
806 14 : if (nat44_ei_static_mapping_match (
807 14 : ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port,
808 : rx_fib_index0, proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1,
809 : 0, &identity_nat0))
810 : {
811 : /*
812 : * Send DHCP packets to the ipv4 stack, or we won't
813 : * be able to use dhcp client on the outside interface
814 : */
815 4 : if (PREDICT_FALSE
816 : (proto0 == NAT_PROTOCOL_UDP
817 : && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
818 : clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
819 : {
820 0 : vnet_feature_next (&next0, b0);
821 0 : goto trace0;
822 : }
823 :
824 4 : if (!nm->forwarding_enabled)
825 : {
826 1 : b0->error =
827 1 : node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
828 1 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
829 : }
830 4 : goto trace0;
831 : }
832 :
833 10 : if (PREDICT_FALSE (identity_nat0))
834 0 : goto trace0;
835 :
836 : /* Create session initiated by host from external network */
837 20 : s0 = create_session_for_static_mapping (
838 : nm, b0, sm_addr0, sm_port0, sm_fib_index0, ip0->dst_address,
839 10 : vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0,
840 : node, thread_index, now);
841 10 : if (!s0)
842 : {
843 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
844 0 : goto trace0;
845 : }
846 : }
847 : else
848 37 : s0 = pool_elt_at_index (tnm->sessions,
849 : nat_value_get_session_index (&value0));
850 :
851 47 : old_addr0 = ip0->dst_address.as_u32;
852 47 : ip0->dst_address = s0->in2out.addr;
853 47 : new_addr0 = ip0->dst_address.as_u32;
854 47 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
855 :
856 47 : sum0 = ip0->checksum;
857 47 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
858 : ip4_header_t, dst_address /* changed member */ );
859 47 : ip0->checksum = ip_csum_fold (sum0);
860 :
861 47 : if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
862 : {
863 23 : if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
864 : {
865 21 : old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
866 21 : new_port0 = udp0->dst_port = s0->in2out.port;
867 21 : sum0 = tcp0->checksum;
868 21 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
869 : ip4_header_t,
870 : dst_address /* changed member */ );
871 :
872 21 : sum0 = ip_csum_update (sum0, old_port0, new_port0,
873 : ip4_header_t /* cheat */ ,
874 : length /* changed member */ );
875 21 : tcp0->checksum = ip_csum_fold (sum0);
876 : }
877 23 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
878 : thread_index, sw_if_index0, 1);
879 : }
880 : else
881 : {
882 24 : if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
883 : {
884 22 : old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
885 22 : new_port0 = udp0->dst_port = s0->in2out.port;
886 22 : if (PREDICT_FALSE (udp0->checksum))
887 : {
888 22 : sum0 = udp0->checksum;
889 22 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
890 : );
891 : sum0 =
892 22 : ip_csum_update (sum0, old_port0, new_port0,
893 : ip4_header_t /* cheat */ ,
894 : length /* changed member */ );
895 22 : udp0->checksum = ip_csum_fold (sum0);
896 : }
897 : }
898 24 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
899 : thread_index, sw_if_index0, 1);
900 : }
901 :
902 : /* Accounting */
903 47 : nat44_ei_session_update_counters (
904 : s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
905 : /* Per-user LRU list maintenance */
906 47 : nat44_ei_session_update_lru (nm, s0, thread_index);
907 58 : trace0:
908 :
909 58 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
910 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
911 : {
912 : nat44_ei_out2in_trace_t *t =
913 58 : vlib_add_trace (vm, node, b0, sizeof (*t));
914 58 : t->sw_if_index = sw_if_index0;
915 58 : t->next_index = next0;
916 58 : t->session_index = ~0;
917 58 : if (s0)
918 52 : t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
919 : }
920 :
921 58 : if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
922 : {
923 1 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
924 : thread_index, sw_if_index0, 1);
925 : }
926 :
927 :
928 58 : ip1 = vlib_buffer_get_current (b1);
929 58 : udp1 = ip4_next_header (ip1);
930 58 : tcp1 = (tcp_header_t *) udp1;
931 58 : icmp1 = (icmp46_header_t *) udp1;
932 :
933 58 : sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
934 58 : rx_fib_index1 =
935 58 : vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index1);
936 :
937 58 : if (PREDICT_FALSE (ip1->ttl == 1))
938 : {
939 2 : vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0;
940 2 : icmp4_error_set_vnet_buffer (b1, ICMP4_time_exceeded,
941 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
942 : 0);
943 2 : next1 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
944 2 : goto trace1;
945 : }
946 :
947 56 : proto1 = ip_proto_to_nat_proto (ip1->protocol);
948 :
949 56 : if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_OTHER))
950 : {
951 0 : if (nat_out2in_sm_unknown_proto (nm, b1, ip1, rx_fib_index1))
952 : {
953 0 : if (!nm->forwarding_enabled)
954 : {
955 0 : b1->error =
956 0 : node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
957 0 : next1 = NAT44_EI_OUT2IN_NEXT_DROP;
958 : }
959 : }
960 0 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
961 : thread_index, sw_if_index1, 1);
962 0 : goto trace1;
963 : }
964 :
965 56 : if (PREDICT_FALSE (proto1 == NAT_PROTOCOL_ICMP))
966 : {
967 27 : next1 = nat44_ei_icmp_out2in_slow_path (
968 : nm, b1, ip1, icmp1, sw_if_index1, rx_fib_index1, node, next1, now,
969 : thread_index, &s1);
970 27 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
971 : thread_index, sw_if_index1, 1);
972 27 : goto trace1;
973 : }
974 :
975 29 : init_nat_k (&kv1, ip1->dst_address,
976 29 : vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1,
977 : proto1);
978 29 : if (clib_bihash_search_8_8 (&nm->out2in, &kv1, &value1))
979 : {
980 : /* Try to match static mapping by external address and port,
981 : destination address and port in packet */
982 3 : if (nat44_ei_static_mapping_match (
983 3 : ip1->dst_address, vnet_buffer (b1)->ip.reass.l4_dst_port,
984 : rx_fib_index1, proto1, &sm_addr1, &sm_port1, &sm_fib_index1, 1,
985 : 0, &identity_nat1))
986 : {
987 : /*
988 : * Send DHCP packets to the ipv4 stack, or we won't
989 : * be able to use dhcp client on the outside interface
990 : */
991 3 : if (PREDICT_FALSE
992 : (proto1 == NAT_PROTOCOL_UDP
993 : && (vnet_buffer (b1)->ip.reass.l4_dst_port ==
994 : clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
995 : {
996 0 : vnet_feature_next (&next1, b1);
997 0 : goto trace1;
998 : }
999 :
1000 3 : if (!nm->forwarding_enabled)
1001 : {
1002 1 : b1->error =
1003 1 : node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
1004 1 : next1 = NAT44_EI_OUT2IN_NEXT_DROP;
1005 : }
1006 3 : goto trace1;
1007 : }
1008 :
1009 0 : if (PREDICT_FALSE (identity_nat1))
1010 0 : goto trace1;
1011 :
1012 : /* Create session initiated by host from external network */
1013 0 : s1 = create_session_for_static_mapping (
1014 : nm, b1, sm_addr1, sm_port1, sm_fib_index1, ip1->dst_address,
1015 0 : vnet_buffer (b1)->ip.reass.l4_dst_port, rx_fib_index1, proto1,
1016 : node, thread_index, now);
1017 0 : if (!s1)
1018 : {
1019 0 : next1 = NAT44_EI_OUT2IN_NEXT_DROP;
1020 0 : goto trace1;
1021 : }
1022 : }
1023 : else
1024 26 : s1 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1025 : nat_value_get_session_index (&value1));
1026 :
1027 26 : old_addr1 = ip1->dst_address.as_u32;
1028 26 : ip1->dst_address = s1->in2out.addr;
1029 26 : new_addr1 = ip1->dst_address.as_u32;
1030 26 : vnet_buffer (b1)->sw_if_index[VLIB_TX] = s1->in2out.fib_index;
1031 :
1032 26 : sum1 = ip1->checksum;
1033 26 : sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1034 : ip4_header_t, dst_address /* changed member */ );
1035 26 : ip1->checksum = ip_csum_fold (sum1);
1036 :
1037 26 : if (PREDICT_TRUE (proto1 == NAT_PROTOCOL_TCP))
1038 : {
1039 23 : if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1040 : {
1041 20 : old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
1042 20 : new_port1 = udp1->dst_port = s1->in2out.port;
1043 :
1044 20 : sum1 = tcp1->checksum;
1045 20 : sum1 = ip_csum_update (sum1, old_addr1, new_addr1,
1046 : ip4_header_t,
1047 : dst_address /* changed member */ );
1048 :
1049 20 : sum1 = ip_csum_update (sum1, old_port1, new_port1,
1050 : ip4_header_t /* cheat */ ,
1051 : length /* changed member */ );
1052 20 : tcp1->checksum = ip_csum_fold (sum1);
1053 : }
1054 23 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
1055 : thread_index, sw_if_index1, 1);
1056 : }
1057 : else
1058 : {
1059 3 : if (!vnet_buffer (b1)->ip.reass.is_non_first_fragment)
1060 : {
1061 0 : old_port1 = vnet_buffer (b1)->ip.reass.l4_dst_port;
1062 0 : new_port1 = udp1->dst_port = s1->in2out.port;
1063 0 : if (PREDICT_FALSE (udp1->checksum))
1064 : {
1065 :
1066 0 : sum1 = udp1->checksum;
1067 : sum1 =
1068 0 : ip_csum_update (sum1, old_addr1, new_addr1,
1069 : ip4_header_t,
1070 : dst_address /* changed member */ );
1071 : sum1 =
1072 0 : ip_csum_update (sum1, old_port1, new_port1,
1073 : ip4_header_t /* cheat */ ,
1074 : length /* changed member */ );
1075 0 : udp1->checksum = ip_csum_fold (sum1);
1076 : }
1077 : }
1078 3 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
1079 : thread_index, sw_if_index1, 1);
1080 : }
1081 :
1082 : /* Accounting */
1083 26 : nat44_ei_session_update_counters (
1084 : s1, now, vlib_buffer_length_in_chain (vm, b1), thread_index);
1085 : /* Per-user LRU list maintenance */
1086 26 : nat44_ei_session_update_lru (nm, s1, thread_index);
1087 58 : trace1:
1088 :
1089 58 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1090 : && (b1->flags & VLIB_BUFFER_IS_TRACED)))
1091 : {
1092 : nat44_ei_out2in_trace_t *t =
1093 58 : vlib_add_trace (vm, node, b1, sizeof (*t));
1094 58 : t->sw_if_index = sw_if_index1;
1095 58 : t->next_index = next1;
1096 58 : t->session_index = ~0;
1097 58 : if (s1)
1098 52 : t->session_index = s1 - nm->per_thread_data[thread_index].sessions;
1099 : }
1100 :
1101 58 : if (next1 == NAT44_EI_OUT2IN_NEXT_DROP)
1102 : {
1103 1 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
1104 : thread_index, sw_if_index1, 1);
1105 : }
1106 :
1107 58 : n_left_from -= 2;
1108 58 : next[0] = next0;
1109 58 : next[1] = next1;
1110 58 : next += 2;
1111 : }
1112 :
1113 60 : while (n_left_from > 0)
1114 : {
1115 : vlib_buffer_t *b0;
1116 18 : u32 next0 = NAT44_EI_OUT2IN_NEXT_LOOKUP;
1117 : u32 sw_if_index0;
1118 : ip4_header_t *ip0;
1119 : ip_csum_t sum0;
1120 : u32 new_addr0, old_addr0;
1121 : u16 new_port0, old_port0;
1122 : udp_header_t *udp0;
1123 : tcp_header_t *tcp0;
1124 : icmp46_header_t *icmp0;
1125 : u32 rx_fib_index0;
1126 : u32 proto0;
1127 18 : nat44_ei_session_t *s0 = 0;
1128 : clib_bihash_kv_8_8_t kv0, value0;
1129 : u8 identity_nat0;
1130 : ip4_address_t sm_addr0;
1131 : u16 sm_port0;
1132 : u32 sm_fib_index0;
1133 :
1134 18 : b0 = *b;
1135 18 : ++b;
1136 :
1137 18 : vnet_buffer (b0)->snat.flags = 0;
1138 :
1139 18 : ip0 = vlib_buffer_get_current (b0);
1140 18 : udp0 = ip4_next_header (ip0);
1141 18 : tcp0 = (tcp_header_t *) udp0;
1142 18 : icmp0 = (icmp46_header_t *) udp0;
1143 :
1144 18 : sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
1145 18 : rx_fib_index0 =
1146 18 : vec_elt (nm->ip4_main->fib_index_by_sw_if_index, sw_if_index0);
1147 :
1148 18 : proto0 = ip_proto_to_nat_proto (ip0->protocol);
1149 :
1150 18 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_OTHER))
1151 : {
1152 1 : if (nat_out2in_sm_unknown_proto (nm, b0, ip0, rx_fib_index0))
1153 : {
1154 0 : if (!nm->forwarding_enabled)
1155 : {
1156 0 : b0->error =
1157 0 : node->errors[NAT44_EI_OUT2IN_ERROR_UNSUPPORTED_PROTOCOL];
1158 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
1159 : }
1160 : }
1161 1 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.other,
1162 : thread_index, sw_if_index0, 1);
1163 1 : goto trace00;
1164 : }
1165 :
1166 17 : if (PREDICT_FALSE (ip0->ttl == 1))
1167 : {
1168 0 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1169 0 : icmp4_error_set_vnet_buffer (b0, ICMP4_time_exceeded,
1170 : ICMP4_time_exceeded_ttl_exceeded_in_transit,
1171 : 0);
1172 0 : next0 = NAT44_EI_OUT2IN_NEXT_ICMP_ERROR;
1173 0 : goto trace00;
1174 : }
1175 :
1176 17 : if (PREDICT_FALSE (proto0 == NAT_PROTOCOL_ICMP))
1177 : {
1178 5 : next0 = nat44_ei_icmp_out2in_slow_path (
1179 : nm, b0, ip0, icmp0, sw_if_index0, rx_fib_index0, node, next0, now,
1180 : thread_index, &s0);
1181 5 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.icmp,
1182 : thread_index, sw_if_index0, 1);
1183 5 : goto trace00;
1184 : }
1185 :
1186 12 : init_nat_k (&kv0, ip0->dst_address,
1187 12 : vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0,
1188 : proto0);
1189 :
1190 12 : if (clib_bihash_search_8_8 (&nm->out2in, &kv0, &value0))
1191 : {
1192 : /* Try to match static mapping by external address and port,
1193 : destination address and port in packet */
1194 3 : if (nat44_ei_static_mapping_match (
1195 3 : ip0->dst_address, vnet_buffer (b0)->ip.reass.l4_dst_port,
1196 : rx_fib_index0, proto0, &sm_addr0, &sm_port0, &sm_fib_index0, 1,
1197 : 0, &identity_nat0))
1198 : {
1199 : /*
1200 : * Send DHCP packets to the ipv4 stack, or we won't
1201 : * be able to use dhcp client on the outside interface
1202 : */
1203 1 : if (PREDICT_FALSE
1204 : (proto0 == NAT_PROTOCOL_UDP
1205 : && (vnet_buffer (b0)->ip.reass.l4_dst_port ==
1206 : clib_host_to_net_u16 (UDP_DST_PORT_dhcp_to_client))))
1207 : {
1208 0 : vnet_feature_next (&next0, b0);
1209 0 : goto trace00;
1210 : }
1211 :
1212 1 : if (!nm->forwarding_enabled)
1213 : {
1214 0 : b0->error =
1215 0 : node->errors[NAT44_EI_OUT2IN_ERROR_NO_TRANSLATION];
1216 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
1217 : }
1218 1 : goto trace00;
1219 : }
1220 :
1221 2 : if (PREDICT_FALSE (identity_nat0))
1222 1 : goto trace00;
1223 :
1224 : /* Create session initiated by host from external network */
1225 2 : s0 = create_session_for_static_mapping (
1226 : nm, b0, sm_addr0, sm_port0, sm_fib_index0, ip0->dst_address,
1227 1 : vnet_buffer (b0)->ip.reass.l4_dst_port, rx_fib_index0, proto0,
1228 : node, thread_index, now);
1229 1 : if (!s0)
1230 : {
1231 0 : next0 = NAT44_EI_OUT2IN_NEXT_DROP;
1232 0 : goto trace00;
1233 : }
1234 : }
1235 : else
1236 9 : s0 = pool_elt_at_index (nm->per_thread_data[thread_index].sessions,
1237 : nat_value_get_session_index (&value0));
1238 :
1239 10 : old_addr0 = ip0->dst_address.as_u32;
1240 10 : ip0->dst_address = s0->in2out.addr;
1241 10 : new_addr0 = ip0->dst_address.as_u32;
1242 10 : vnet_buffer (b0)->sw_if_index[VLIB_TX] = s0->in2out.fib_index;
1243 :
1244 10 : sum0 = ip0->checksum;
1245 10 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1246 : ip4_header_t, dst_address /* changed member */ );
1247 10 : ip0->checksum = ip_csum_fold (sum0);
1248 :
1249 10 : if (PREDICT_TRUE (proto0 == NAT_PROTOCOL_TCP))
1250 : {
1251 7 : if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1252 : {
1253 6 : old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1254 6 : new_port0 = udp0->dst_port = s0->in2out.port;
1255 :
1256 6 : sum0 = tcp0->checksum;
1257 6 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0,
1258 : ip4_header_t,
1259 : dst_address /* changed member */ );
1260 :
1261 6 : sum0 = ip_csum_update (sum0, old_port0, new_port0,
1262 : ip4_header_t /* cheat */ ,
1263 : length /* changed member */ );
1264 6 : tcp0->checksum = ip_csum_fold (sum0);
1265 : }
1266 7 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.tcp,
1267 : thread_index, sw_if_index0, 1);
1268 : }
1269 : else
1270 : {
1271 3 : if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment)
1272 : {
1273 2 : old_port0 = vnet_buffer (b0)->ip.reass.l4_dst_port;
1274 2 : new_port0 = udp0->dst_port = s0->in2out.port;
1275 2 : if (PREDICT_FALSE (udp0->checksum))
1276 : {
1277 2 : sum0 = udp0->checksum;
1278 2 : sum0 = ip_csum_update (sum0, old_addr0, new_addr0, ip4_header_t, dst_address /* changed member */
1279 : );
1280 : sum0 =
1281 2 : ip_csum_update (sum0, old_port0, new_port0,
1282 : ip4_header_t /* cheat */ ,
1283 : length /* changed member */ );
1284 2 : udp0->checksum = ip_csum_fold (sum0);
1285 : }
1286 : }
1287 3 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.udp,
1288 : thread_index, sw_if_index0, 1);
1289 : }
1290 :
1291 : /* Accounting */
1292 10 : nat44_ei_session_update_counters (
1293 : s0, now, vlib_buffer_length_in_chain (vm, b0), thread_index);
1294 : /* Per-user LRU list maintenance */
1295 10 : nat44_ei_session_update_lru (nm, s0, thread_index);
1296 18 : trace00:
1297 :
1298 18 : if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)
1299 : && (b0->flags & VLIB_BUFFER_IS_TRACED)))
1300 : {
1301 : nat44_ei_out2in_trace_t *t =
1302 18 : vlib_add_trace (vm, node, b0, sizeof (*t));
1303 18 : t->sw_if_index = sw_if_index0;
1304 18 : t->next_index = next0;
1305 18 : t->session_index = ~0;
1306 18 : if (s0)
1307 14 : t->session_index = s0 - nm->per_thread_data[thread_index].sessions;
1308 : }
1309 :
1310 18 : if (next0 == NAT44_EI_OUT2IN_NEXT_DROP)
1311 : {
1312 0 : vlib_increment_simple_counter (&nm->counters.slowpath.out2in.drops,
1313 : thread_index, sw_if_index0, 1);
1314 : }
1315 :
1316 18 : n_left_from--;
1317 18 : next[0] = next0;
1318 18 : next++;
1319 : }
1320 :
1321 42 : vlib_buffer_enqueue_to_next (vm, node, from, (u16 *) nexts,
1322 42 : frame->n_vectors);
1323 :
1324 42 : return frame->n_vectors;
1325 : }
1326 :
1327 72026 : VLIB_REGISTER_NODE (nat44_ei_out2in_node) = {
1328 : .name = "nat44-ei-out2in",
1329 : .vector_size = sizeof (u32),
1330 : .format_trace = format_nat44_ei_out2in_trace,
1331 : .type = VLIB_NODE_TYPE_INTERNAL,
1332 :
1333 : .n_errors = ARRAY_LEN(nat44_ei_out2in_error_strings),
1334 : .error_strings = nat44_ei_out2in_error_strings,
1335 :
1336 : .runtime_data_bytes = sizeof (nat44_ei_runtime_t),
1337 :
1338 : .n_next_nodes = NAT44_EI_OUT2IN_N_NEXT,
1339 :
1340 : /* edit / add dispositions here */
1341 : .next_nodes = {
1342 : [NAT44_EI_OUT2IN_NEXT_DROP] = "error-drop",
1343 : [NAT44_EI_OUT2IN_NEXT_LOOKUP] = "ip4-lookup",
1344 : [NAT44_EI_OUT2IN_NEXT_ICMP_ERROR] = "ip4-icmp-error",
1345 : },
1346 : };
1347 :
1348 : /*
1349 : * fd.io coding-style-patch-verification: ON
1350 : *
1351 : * Local Variables:
1352 : * eval: (c-set-style "gnu")
1353 : * End:
1354 : */
|