From a73f2d6f53c224668bd6bbea1a980ee4313c794f Mon Sep 17 00:00:00 2001 From: Filip Varga Date: Tue, 25 Feb 2020 14:31:33 +0100 Subject: nat: timed out session scavenging upgrade Patch changes the behavior of session scavenging and fixes multiple nat issues. Allows proper session clearing and removes issue with lingering sessions in session db. Patch also updates and fixes CLI/API calls for better readability of session state metrics. Fixes security issue that would allow attacker to reuse timed out session in both directions (in2out/out2in). Type: improvement Signed-off-by: Filip Varga Change-Id: I78897585a2a57291fad5db6d457941aa0a0457bd --- src/plugins/nat/in2out_ed.c | 55 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 13 deletions(-) (limited to 'src/plugins/nat/in2out_ed.c') diff --git a/src/plugins/nat/in2out_ed.c b/src/plugins/nat/in2out_ed.c index 581d7b4ef60..ca737d56663 100644 --- a/src/plugins/nat/in2out_ed.c +++ b/src/plugins/nat/in2out_ed.c @@ -209,14 +209,18 @@ slow_path_ed (snat_main_t * sm, }; nat44_is_idle_session_ctx_t ctx; - nat44_session_try_cleanup (&key->l_addr, rx_fib_index, thread_index, now); + u32 cleared = 0; if (PREDICT_FALSE (nat44_maximum_sessions_exceeded (sm, thread_index))) { - b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED]; - nat_ipfix_logging_max_sessions (thread_index, sm->max_translations); - nat_elog_notice ("maximum sessions exceeded"); - return NAT_NEXT_DROP; + if (PREDICT_FALSE + (!(cleared = nat44_users_cleanup (thread_index, now)))) + { + b->error = node->errors[NAT_IN2OUT_ED_ERROR_MAX_SESSIONS_EXCEEDED]; + nat_ipfix_logging_max_sessions (thread_index, sm->max_translations); + nat_elog_notice ("maximum sessions exceeded"); + return NAT_NEXT_DROP; + } } key0.addr = key->l_addr; @@ -224,6 +228,7 @@ slow_path_ed (snat_main_t * sm, key1.protocol = key0.protocol = proto; key0.fib_index = rx_fib_index; key1.fib_index = sm->outside_fib_index; + /* First try to match static mapping by local address and port */ if (snat_static_mapping_match (sm, key0, &key1, 0, 0, 0, &lb, 0, &identity_nat)) @@ -234,9 +239,16 @@ slow_path_ed (snat_main_t * sm, sm->port_per_thread, tsm->snat_thread_index)) { - nat_elog_notice ("addresses exhausted"); - b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS]; - return NAT_NEXT_DROP; + if (cleared || !nat44_out_of_ports_cleanup (thread_index, now) || + snat_alloc_outside_address_and_port (sm->addresses, + rx_fib_index, thread_index, + &key1, sm->port_per_thread, + tsm->snat_thread_index)) + { + nat_elog_notice ("addresses exhausted"); + b->error = node->errors[NAT_IN2OUT_ED_ERROR_OUT_OF_PORTS]; + return NAT_NEXT_DROP; + } } } else @@ -246,16 +258,19 @@ slow_path_ed (snat_main_t * sm, *sessionp = s; return next; } - is_sm = 1; } - if (proto == SNAT_PROTOCOL_TCP) + if (PREDICT_TRUE (proto == SNAT_PROTOCOL_TCP)) { - if (!tcp_flags_is_init - (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags)) + if (PREDICT_FALSE + (!tcp_flags_is_init + (vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags))) { b->error = node->errors[NAT_IN2OUT_ED_ERROR_NON_SYN]; + if (!is_sm) + snat_free_outside_address_and_port (sm->addresses, + thread_index, &key1); return NAT_NEXT_DROP; } } @@ -932,9 +947,23 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm, next0 = def_slow; goto trace0; } - s0 = pool_elt_at_index (tsm->sessions, value0.value); + // drop if session expired + u64 sess_timeout_time; + sess_timeout_time = s0->last_heard + + (f64) nat44_session_get_timeout (sm, s0); + if (now >= sess_timeout_time) + { + // delete session + nat_free_session_data (sm, s0, thread_index, 0); + nat44_delete_session (sm, s0, thread_index); + + next0 = NAT_NEXT_DROP; + goto trace0; + } + // + b0->flags |= VNET_BUFFER_F_IS_NATED; if (!is_output_feature) -- cgit 1.2.3-korg