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/nat44_cli.c | 195 +++++++++++++++++++++++++++++--------------- 1 file changed, 128 insertions(+), 67 deletions(-) (limited to 'src/plugins/nat/nat44_cli.c') diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c index 11e87092ae7..45e00693676 100644 --- a/src/plugins/nat/nat44_cli.c +++ b/src/plugins/nat/nat44_cli.c @@ -122,9 +122,7 @@ nat44_session_cleanup_command_fn (vlib_main_t * vm, vlib_cli_command_t * cmd) { clib_error_t *error = 0; - - nat44_force_session_cleanup (); - + nat44_force_users_cleanup (); return error; } @@ -645,56 +643,26 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, { snat_main_per_thread_data_t *tsm; snat_main_t *sm = &snat_main; - snat_address_t *a; snat_session_t *s; - u32 free_ports, free_ports_addr; - if (sm->deterministic) + if (sm->deterministic || !sm->endpoint_dependent) return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR); - if (sm->endpoint_dependent) - vlib_cli_output (vm, "mode: endpoint-depenent"); - - // print timeouts - vlib_cli_output (vm, "icmp timeout: %u", sm->icmp_timeout); - vlib_cli_output (vm, "udp timeout: %u", sm->udp_timeout); - - vlib_cli_output (vm, "tcp established timeout: %u", - sm->tcp_established_timeout); - vlib_cli_output (vm, "tcp transitory timeout: %u", - sm->tcp_transitory_timeout); - // print session configuration values vlib_cli_output (vm, "max translations: %u", sm->max_translations); vlib_cli_output (vm, "max translations per user: %u", sm->max_translations_per_user); - // do we need also twice-nat addresses ?? - if (vec_len (sm->addresses)) - { - free_ports = 0; - /* *INDENT-OFF* */ - vec_foreach (a, sm->addresses) - { - free_ports_addr = sm->port_per_thread; - - #define _(N, i, n, s) \ - free_ports_addr -= a->busy_##n##_ports; - foreach_snat_protocol - #undef _ + u32 count = 0; - vlib_cli_output (vm, "addr: %U free ports: %u out of: %u", - format_ip4_address, &a->addr, free_ports_addr, sm->port_per_thread); + u64 now = vlib_time_now (sm->vlib_main); + u64 sess_timeout_time; - free_ports += free_ports_addr; - } - /* *INDENT-ON* */ - vlib_cli_output (vm, "free ports overall: %u out of: %u", - free_ports, - vec_len (sm->addresses) * sm->port_per_thread); - } + u32 udp_sessions = 0; + u32 tcp_sessions = 0; + u32 icmp_sessions = 0; - u32 count = 0; + u32 timed_out = 0; u32 transitory = 0; u32 established = 0; @@ -703,14 +671,44 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, /* *INDENT-OFF* */ vec_foreach (tsm, sm->per_thread_data) { - count += vec_len (tsm->sessions); pool_foreach (s, tsm->sessions, ({ - if (s->state) - transitory++; - else - established++; + sess_timeout_time = s->last_heard + + (f64) nat44_session_get_timeout (sm, s); + if (now >= sess_timeout_time) + timed_out++; + + switch (s->in2out.protocol) + { + case SNAT_PROTOCOL_ICMP: + icmp_sessions++; + break; + case SNAT_PROTOCOL_TCP: + tcp_sessions++; + if (s->state) + transitory++; + else + established++; + break; + case SNAT_PROTOCOL_UDP: + default: + udp_sessions++; + break; + } })); + count += pool_elts (tsm->sessions); + + vlib_cli_output (vm, "tid[%u] session scavenging cleared: %u", + tsm->thread_index, tsm->cleared); + vlib_cli_output (vm, "tid[%u] session scavenging cleanup runs: %u", + tsm->thread_index, tsm->cleanup_runs); + + if (now < tsm->cleanup_timeout) + vlib_cli_output (vm, "tid[%u] session scavenging next run in: %f", + tsm->thread_index, tsm->cleanup_timeout - now); + else + vlib_cli_output (vm, "tid[%u] session scavenging next run in: 0", + tsm->thread_index); } /* *INDENT-ON* */ } @@ -720,17 +718,51 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, /* *INDENT-OFF* */ pool_foreach (s, tsm->sessions, ({ - if (s->state) - transitory++; - else - established++; + sess_timeout_time = s->last_heard + + (f64) nat44_session_get_timeout (sm, s); + if (now >= sess_timeout_time) + timed_out++; + + switch (s->in2out.protocol) + { + case SNAT_PROTOCOL_ICMP: + icmp_sessions++; + break; + case SNAT_PROTOCOL_TCP: + tcp_sessions++; + if (s->state) + transitory++; + else + established++; + break; + case SNAT_PROTOCOL_UDP: + default: + udp_sessions++; + break; + } })); /* *INDENT-ON* */ - count = vec_len (tsm->sessions); + count = pool_elts (tsm->sessions); + + vlib_cli_output (vm, "tid[0] session scavenging cleared: %u", + tsm->cleared); + vlib_cli_output (vm, "tid[0] session scavenging cleanup runs: %u", + tsm->cleanup_runs); + + if (now < tsm->cleanup_timeout) + vlib_cli_output (vm, "tid[0] session scavenging next run in: %f", + tsm->cleanup_timeout - now); + else + vlib_cli_output (vm, "tid[0] session scavenging next run in: 0"); } - vlib_cli_output (vm, "established sessions: %u", established); - vlib_cli_output (vm, "transitory sessions: %u", transitory); - vlib_cli_output (vm, "sessions: %u", count); + + vlib_cli_output (vm, "total timed out sessions: %u", timed_out); + vlib_cli_output (vm, "total sessions: %u", count); + vlib_cli_output (vm, "total tcp sessions: %u", tcp_sessions); + vlib_cli_output (vm, "total tcp established sessions: %u", established); + vlib_cli_output (vm, "total tcp transitory sessions: %u", transitory); + vlib_cli_output (vm, "total udp sessions: %u", udp_sessions); + vlib_cli_output (vm, "total icmp sessions: %u", icmp_sessions); return 0; } @@ -1439,20 +1471,38 @@ static clib_error_t * nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - int verbose = 0; + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = 0; snat_main_t *sm = &snat_main; snat_main_per_thread_data_t *tsm; + + int detail = 0, metrics = 0; snat_user_t *u; int i = 0; if (sm->deterministic) return clib_error_return (0, UNSUPPORTED_IN_DET_MODE_STR); - if (unformat (input, "detail")) - verbose = 1; + if (!unformat_user (input, unformat_line_input, line_input)) + goto print; - vlib_cli_output (vm, "NAT44 sessions:"); + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "detail")) + detail = 1; + else if (unformat (line_input, "metrics")) + metrics = 1; + else + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + break; + } + } + unformat_free (line_input); +print: + vlib_cli_output (vm, "NAT44 sessions:"); /* *INDENT-OFF* */ vec_foreach_index (i, sm->per_thread_data) { @@ -1461,14 +1511,24 @@ nat44_show_sessions_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_output (vm, "-------- thread %d %s: %d sessions --------\n", i, vlib_worker_threads[i].name, pool_elts (tsm->sessions)); - pool_foreach (u, tsm->users, - ({ - vlib_cli_output (vm, " %U", format_snat_user, tsm, u, verbose); - })); + if (metrics) + { + u64 now = vlib_time_now (sm->vlib_main); + pool_foreach (u, tsm->users, + ({ + vlib_cli_output (vm, " %U", format_snat_user_v2, tsm, u, now); + })); + } + else + { + pool_foreach (u, tsm->users, + ({ + vlib_cli_output (vm, " %U", format_snat_user, tsm, u, detail); + })); + } } /* *INDENT-ON* */ - - return 0; + return error; } static clib_error_t * @@ -1896,10 +1956,9 @@ set_timeout_command_fn (vlib_main_t * vm, goto done; } } - done: unformat_free (line_input); - + sm->min_timeout = nat44_minimal_timeout (sm); return error; } @@ -1910,6 +1969,8 @@ nat_show_timeouts_command_fn (vlib_main_t * vm, { snat_main_t *sm = &snat_main; + // fix text + vlib_cli_output (vm, "min session cleanup timeout: %dsec", sm->min_timeout); vlib_cli_output (vm, "udp timeout: %dsec", sm->udp_timeout); vlib_cli_output (vm, "tcp-established timeout: %dsec", sm->tcp_established_timeout); @@ -2535,7 +2596,7 @@ VLIB_CLI_COMMAND (nat44_show_interface_address_command, static) = { ?*/ VLIB_CLI_COMMAND (nat44_show_sessions_command, static) = { .path = "show nat44 sessions", - .short_help = "show nat44 sessions [detail]", + .short_help = "show nat44 sessions [detail|metrics]", .function = nat44_show_sessions_command_fn, }; -- cgit 1.2.3-korg