From 1c2ac860ed9a80dac539af6408d70f7dfd2c238e Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Tue, 10 Mar 2020 12:32:54 +0100 Subject: nat: transitory timeout for TCP CLOSED state Wait transitory timeout seconds before moving internal state of TCP session to CLOSED state per RFC 7857. This patch implements this functionality for endpoint-dependent NAT. Type: improvement Signed-off-by: Klement Sekera Change-Id: I4491d831cd9edf63fae520a516cdbe590bac85db --- src/plugins/nat/in2out_ed.c | 46 ++++++-- src/plugins/nat/nat.c | 3 +- src/plugins/nat/nat.h | 12 +- src/plugins/nat/nat44/inlines.h | 8 +- src/plugins/nat/nat44_cli.c | 42 ++++++- src/plugins/nat/nat_det_in2out.c | 4 +- src/plugins/nat/nat_inlines.h | 37 +++--- src/plugins/nat/out2in_ed.c | 46 ++++++-- src/plugins/nat/test/test_nat.py | 249 ++++++++++++++++++++++++++++----------- 9 files changed, 329 insertions(+), 118 deletions(-) (limited to 'src/plugins/nat') diff --git a/src/plugins/nat/in2out_ed.c b/src/plugins/nat/in2out_ed.c index 4e7432d8228..4be76372a49 100644 --- a/src/plugins/nat/in2out_ed.c +++ b/src/plugins/nat/in2out_ed.c @@ -455,7 +455,8 @@ nat_not_translate_output_feature_fwd (snat_main_t * sm, ip4_header_t * ip, { if (ip->protocol == IP_PROTOCOL_TCP) { - if (nat44_set_tcp_session_state_i2o (sm, s, b, thread_index)) + if (nat44_set_tcp_session_state_i2o + (sm, now, s, b, thread_index)) return 1; } /* Accounting */ @@ -850,6 +851,7 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm, snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets = 0, def_slow; + u32 tcp_closed_drops = 0; def_slow = is_output_feature ? NAT_NEXT_IN2OUT_ED_OUTPUT_SLOW_PATH : NAT_NEXT_IN2OUT_ED_SLOW_PATH; @@ -953,6 +955,23 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm, } s0 = pool_elt_at_index (tsm->sessions, value0.value); + if (s0->tcp_close_timestamp) + { + if (now >= s0->tcp_close_timestamp) + { + // session is closed, go slow path + next0 = def_slow; + } + else + { + // session in transitory timeout, drop + ++tcp_closed_drops; + b0->error = node->errors[NAT_IN2OUT_ED_ERROR_TCP_CLOSED]; + next0 = NAT_NEXT_DROP; + } + goto trace0; + } + // drop if session expired u64 sess_timeout_time; sess_timeout_time = s0->last_heard + @@ -967,7 +986,6 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm, next0 = NAT_NEXT_DROP; goto trace0; } - // b0->flags |= VNET_BUFFER_F_IS_NATED; @@ -1017,7 +1035,8 @@ nat44_ed_in2out_fast_path_node_fn_inline (vlib_main_t * vm, tcp0->checksum = ip_csum_fold (sum0); } tcp_packets++; - if (nat44_set_tcp_session_state_i2o (sm, s0, b0, thread_index)) + if (nat44_set_tcp_session_state_i2o + (sm, now, s0, b0, thread_index)) goto trace0; } else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment @@ -1216,9 +1235,20 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm, vnet_buffer (b0)->ip.reass.l4_src_port, vnet_buffer (b0)->ip.reass.l4_dst_port); - if (clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0)) + if (!clib_bihash_search_16_8 (&tsm->in2out_ed, &kv0, &value0)) { + s0 = pool_elt_at_index (tsm->sessions, value0.value); + if (s0->tcp_close_timestamp && now >= s0->tcp_close_timestamp) + { + nat_free_session_data (sm, s0, thread_index, 0); + nat44_delete_session (sm, s0, thread_index); + s0 = NULL; + } + } + + if (!s0) + { if (is_output_feature) { if (PREDICT_FALSE @@ -1260,11 +1290,6 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm, goto trace0; } - else - { - s0 = pool_elt_at_index (tsm->sessions, value0.value); - } - b0->flags |= VNET_BUFFER_F_IS_NATED; @@ -1314,7 +1339,8 @@ nat44_ed_in2out_slow_path_node_fn_inline (vlib_main_t * vm, tcp0->checksum = ip_csum_fold (sum0); } tcp_packets++; - if (nat44_set_tcp_session_state_i2o (sm, s0, b0, thread_index)) + if (nat44_set_tcp_session_state_i2o + (sm, now, s0, b0, thread_index)) goto trace0; } else if (!vnet_buffer (b0)->ip.reass.is_non_first_fragment diff --git a/src/plugins/nat/nat.c b/src/plugins/nat/nat.c index 1f63237fb45..ffa94a1fd94 100755 --- a/src/plugins/nat/nat.c +++ b/src/plugins/nat/nat.c @@ -619,7 +619,8 @@ nat_ed_session_alloc (snat_main_t * sm, snat_user_t * u, u32 thread_index, s = pool_elt_at_index (tsm->sessions, oldest_elt->value); sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s); - if (now >= sess_timeout_time) + if (now >= sess_timeout_time || + (s->tcp_close_timestamp && now >= s->tcp_close_timestamp)) { // reuse old session clib_dlist_addtail (tsm->list_pool, diff --git a/src/plugins/nat/nat.h b/src/plugins/nat/nat.h index 8df3b9a9cd3..83611016e34 100644 --- a/src/plugins/nat/nat.h +++ b/src/plugins/nat/nat.h @@ -228,6 +228,7 @@ _(MAX_FRAG, "maximum fragments per reassembly exceeded")\ _(CANNOT_CREATE_USER, "cannot create NAT user") \ _(NON_SYN, "non-SYN packet try to create session") \ _(TCP_PACKETS, "TCP packets") \ +_(TCP_CLOSED, "drops due to TCP in transitory timeout") \ _(UDP_PACKETS, "UDP packets") \ _(ICMP_PACKETS, "ICMP packets") \ _(OTHER_PACKETS, "other protocol packets") \ @@ -258,6 +259,7 @@ _(MAX_FRAG, "maximum fragments per reassembly exceeded")\ _(CANNOT_CREATE_USER, "cannot create NAT user") \ _(NON_SYN, "non-SYN packet try to create session") \ _(TCP_PACKETS, "TCP packets") \ +_(TCP_CLOSED, "drops due to TCP in transitory timeout") \ _(UDP_PACKETS, "UDP packets") \ _(ICMP_PACKETS, "ICMP packets") \ _(OTHER_PACKETS, "other protocol packets") \ @@ -341,6 +343,7 @@ typedef CLIB_PACKED(struct u8 state; u32 i2o_fin_seq; u32 o2i_fin_seq; + u32 tcp_close_timestamp; /* user index */ u32 user_index; @@ -746,23 +749,14 @@ extern vlib_node_registration_t nat_pre_out2in_node; extern vlib_node_registration_t snat_in2out_node; extern vlib_node_registration_t snat_in2out_output_node; extern vlib_node_registration_t snat_out2in_node; -extern vlib_node_registration_t snat_in2out_fast_node; -extern vlib_node_registration_t snat_out2in_fast_node; extern vlib_node_registration_t snat_in2out_worker_handoff_node; extern vlib_node_registration_t snat_in2out_output_worker_handoff_node; extern vlib_node_registration_t snat_out2in_worker_handoff_node; extern vlib_node_registration_t snat_det_in2out_node; extern vlib_node_registration_t snat_det_out2in_node; -extern vlib_node_registration_t snat_hairpin_dst_node; -extern vlib_node_registration_t snat_hairpin_src_node; extern vlib_node_registration_t nat44_ed_in2out_node; extern vlib_node_registration_t nat44_ed_in2out_output_node; extern vlib_node_registration_t nat44_ed_out2in_node; -extern vlib_node_registration_t nat44_ed_hairpin_dst_node; -extern vlib_node_registration_t nat44_ed_hairpin_src_node; -extern vlib_node_registration_t nat44_ed_in2out_worker_handoff_node; -extern vlib_node_registration_t nat44_ed_in2out_output_worker_handoff_node; -extern vlib_node_registration_t nat44_ed_out2in_worker_handoff_node; extern fib_source_t nat_fib_src_hi; extern fib_source_t nat_fib_src_low; diff --git a/src/plugins/nat/nat44/inlines.h b/src/plugins/nat/nat44/inlines.h index 7cc24750423..fcaf57383ef 100644 --- a/src/plugins/nat/nat44/inlines.h +++ b/src/plugins/nat/nat44/inlines.h @@ -61,7 +61,7 @@ nat44_session_reuse_old (snat_main_t * sm, snat_user_t * u, s->ext_host_port = 0; s->ext_host_nat_addr.as_u32 = 0; s->ext_host_nat_port = 0; - // + s->tcp_close_timestamp = 0; s->ha_last_refreshed = now; return s; } @@ -193,6 +193,12 @@ nat44_user_session_cleanup (snat_user_t * u, u32 thread_index, f64 now) sess_timeout_time = s->last_heard + (f64) nat44_session_get_timeout (sm, s); + if (s->tcp_close_timestamp) + { + sess_timeout_time = + clib_min (sess_timeout_time, s->tcp_close_timestamp); + } + if (now < sess_timeout_time) continue; diff --git a/src/plugins/nat/nat44_cli.c b/src/plugins/nat/nat44_cli.c index 45e00693676..cdf94a8dc9d 100644 --- a/src/plugins/nat/nat44_cli.c +++ b/src/plugins/nat/nat44_cli.c @@ -664,6 +664,8 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, u32 timed_out = 0; u32 transitory = 0; + u32 transitory_wait_closed = 0; + u32 transitory_closed = 0; u32 established = 0; if (sm->num_workers > 1) @@ -686,7 +688,23 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, case SNAT_PROTOCOL_TCP: tcp_sessions++; if (s->state) - transitory++; + { + if (s->tcp_close_timestamp) + { + if (now >= s->tcp_close_timestamp) + { + ++transitory_closed; + } + else + { + ++transitory_wait_closed; + } + } + else + { + transitory++; + } + } else established++; break; @@ -731,7 +749,23 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, case SNAT_PROTOCOL_TCP: tcp_sessions++; if (s->state) - transitory++; + { + if (s->tcp_close_timestamp) + { + if (now >= s->tcp_close_timestamp) + { + ++transitory_closed; + } + else + { + ++transitory_wait_closed; + } + } + else + { + transitory++; + } + } else established++; break; @@ -761,6 +795,10 @@ nat44_show_summary_command_fn (vlib_main_t * vm, unformat_input_t * input, 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 tcp transitory (WAIT-CLOSED) sessions: %u", + transitory_wait_closed); + vlib_cli_output (vm, "total tcp transitory (CLOSED) sessions: %u", + transitory_closed); vlib_cli_output (vm, "total udp sessions: %u", udp_sessions); vlib_cli_output (vm, "total icmp sessions: %u", icmp_sessions); return 0; diff --git a/src/plugins/nat/nat_det_in2out.c b/src/plugins/nat/nat_det_in2out.c index 384a1eb54b9..22b76373731 100644 --- a/src/plugins/nat/nat_det_in2out.c +++ b/src/plugins/nat/nat_det_in2out.c @@ -95,8 +95,8 @@ u32 icmp_match_in2out_det (snat_main_t * sm, vlib_node_runtime_t * node, u32 thread_index, vlib_buffer_t * b0, ip4_header_t * ip0, u8 * p_proto, - snat_session_key_t * p_value, - u8 * p_dont_translate, void *d, void *e) + snat_session_key_t * p_value, u8 * p_dont_translate, + void *d, void *e) { icmp46_header_t *icmp0; u32 sw_if_index0; diff --git a/src/plugins/nat/nat_inlines.h b/src/plugins/nat/nat_inlines.h index f693032a685..bdcfd39dfb7 100644 --- a/src/plugins/nat/nat_inlines.h +++ b/src/plugins/nat/nat_inlines.h @@ -322,8 +322,9 @@ nat44_delete_session (snat_main_t * sm, snat_session_t * ses, @return 1 if session was closed, otherwise 0 */ always_inline int -nat44_set_tcp_session_state_i2o (snat_main_t * sm, snat_session_t * ses, - vlib_buffer_t * b, u32 thread_index) +nat44_set_tcp_session_state_i2o (snat_main_t * sm, f64 now, + snat_session_t * ses, vlib_buffer_t * b, + u32 thread_index) { u8 tcp_flags = vnet_buffer (b)->ip.reass.icmp_type_or_tcp_flags; u32 tcp_ack_number = vnet_buffer (b)->ip.reass.tcp_ack_number; @@ -345,22 +346,22 @@ nat44_set_tcp_session_state_i2o (snat_main_t * sm, snat_session_t * ses, if ((tcp_flags & TCP_FLAG_ACK) && (ses->state & NAT44_SES_O2I_FIN)) { if (clib_net_to_host_u32 (tcp_ack_number) > ses->o2i_fin_seq) - ses->state |= NAT44_SES_O2I_FIN_ACK; - } - if (nat44_is_ses_closed (ses) - && !(ses->flags & SNAT_SESSION_FLAG_OUTPUT_FEATURE)) - { - nat_free_session_data (sm, ses, thread_index, 0); - nat44_delete_session (sm, ses, thread_index); - return 1; + { + ses->state |= NAT44_SES_O2I_FIN_ACK; + if (nat44_is_ses_closed (ses)) + { // if session is now closed, save the timestamp + ses->tcp_close_timestamp = now + sm->tcp_transitory_timeout; + } + } } return 0; } always_inline int -nat44_set_tcp_session_state_o2i (snat_main_t * sm, snat_session_t * ses, - u8 tcp_flags, u32 tcp_ack_number, - u32 tcp_seq_number, u32 thread_index) +nat44_set_tcp_session_state_o2i (snat_main_t * sm, f64 now, + snat_session_t * ses, u8 tcp_flags, + u32 tcp_ack_number, u32 tcp_seq_number, + u32 thread_index) { if ((ses->state == 0) && (tcp_flags & TCP_FLAG_RST)) ses->state = NAT44_SES_RST; @@ -380,12 +381,10 @@ nat44_set_tcp_session_state_o2i (snat_main_t * sm, snat_session_t * ses, { if (clib_net_to_host_u32 (tcp_ack_number) > ses->i2o_fin_seq) ses->state |= NAT44_SES_I2O_FIN_ACK; - } - if (nat44_is_ses_closed (ses)) - { - nat_free_session_data (sm, ses, thread_index, 0); - nat44_delete_session (sm, ses, thread_index); - return 1; + if (nat44_is_ses_closed (ses)) + { // if session is now closed, save the timestamp + ses->tcp_close_timestamp = now + sm->tcp_transitory_timeout; + } } return 0; } diff --git a/src/plugins/nat/out2in_ed.c b/src/plugins/nat/out2in_ed.c index fbb7d069dbb..69436145a67 100644 --- a/src/plugins/nat/out2in_ed.c +++ b/src/plugins/nat/out2in_ed.c @@ -414,7 +414,8 @@ create_bypass_for_fwd (snat_main_t * sm, vlib_buffer_t * b, ip4_header_t * ip, { tcp_header_t *tcp = ip4_next_header (ip); if (nat44_set_tcp_session_state_o2i - (sm, s, tcp->flags, tcp->ack_number, tcp->seq_number, thread_index)) + (sm, now, s, tcp->flags, tcp->ack_number, tcp->seq_number, + thread_index)) return; } @@ -682,6 +683,7 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, snat_main_per_thread_data_t *tsm = &sm->per_thread_data[thread_index]; u32 tcp_packets = 0, udp_packets = 0, icmp_packets = 0, other_packets = 0, fragments = 0; + u32 tcp_closed_drops = 0; stats_node_index = sm->ed_out2in_node_index; @@ -766,6 +768,23 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, } s0 = pool_elt_at_index (tsm->sessions, value0.value); + if (s0->tcp_close_timestamp) + { + if (now >= s0->tcp_close_timestamp) + { + // session is closed, go slow path + next0 = NAT_NEXT_OUT2IN_ED_SLOW_PATH; + } + else + { + // session in transitory timeout, drop + b0->error = node->errors[NAT_OUT2IN_ED_ERROR_TCP_CLOSED]; + ++tcp_closed_drops; + next0 = NAT_NEXT_DROP; + } + goto trace0; + } + // drop if session expired u64 sess_timeout_time; sess_timeout_time = s0->last_heard + @@ -827,7 +846,8 @@ nat44_ed_out2in_fast_path_node_fn_inline (vlib_main_t * vm, } tcp_packets++; if (nat44_set_tcp_session_state_o2i - (sm, s0, vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags, + (sm, now, s0, + vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags, vnet_buffer (b0)->ip.reass.tcp_ack_number, vnet_buffer (b0)->ip.reass.tcp_seq_number, thread_index)) goto trace0; @@ -1029,7 +1049,20 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, vnet_buffer (b0)->ip.reass.l4_dst_port, vnet_buffer (b0)->ip.reass.l4_src_port); - if (clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0)) + s0 = NULL; + if (!clib_bihash_search_16_8 (&tsm->out2in_ed, &kv0, &value0)) + { + s0 = pool_elt_at_index (tsm->sessions, value0.value); + + if (s0->tcp_close_timestamp && now >= s0->tcp_close_timestamp) + { + nat_free_session_data (sm, s0, thread_index, 0); + nat44_delete_session (sm, s0, thread_index); + s0 = NULL; + } + } + + if (!s0) { /* Try to match static mapping by external address and port, destination address and port in packet */ @@ -1108,10 +1141,6 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, goto trace0; } } - else - { - s0 = pool_elt_at_index (tsm->sessions, value0.value); - } old_addr0 = ip0->dst_address.as_u32; new_addr0 = ip0->dst_address.as_u32 = s0->in2out.addr.as_u32; @@ -1158,7 +1187,8 @@ nat44_ed_out2in_slow_path_node_fn_inline (vlib_main_t * vm, } tcp_packets++; if (nat44_set_tcp_session_state_o2i - (sm, s0, vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags, + (sm, now, s0, + vnet_buffer (b0)->ip.reass.icmp_type_or_tcp_flags, vnet_buffer (b0)->ip.reass.tcp_ack_number, vnet_buffer (b0)->ip.reass.tcp_seq_number, thread_index)) goto trace0; diff --git a/src/plugins/nat/test/test_nat.py b/src/plugins/nat/test/test_nat.py index a38cdc9f4fb..d5d41288c42 100644 --- a/src/plugins/nat/test/test_nat.py +++ b/src/plugins/nat/test/test_nat.py @@ -1155,12 +1155,8 @@ class MethodHolder(VppTestCase): self.port_in = random.randint(1025, 65535) # in2out - pkts = self.create_stream_frag(self.pg0, - self.pg1.remote_ip4, - self.port_in, - 20, - data, - proto) + pkts = self.create_stream_frag(self.pg0, self.pg1.remote_ip4, + self.port_in, 20, data, proto) self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -1197,13 +1193,8 @@ class MethodHolder(VppTestCase): else: sport = p[layer].id dport = 0 - pkts = self.create_stream_frag(self.pg1, - dst_addr, - sport, - dport, - data, - proto, - echo_reply=True) + pkts = self.create_stream_frag(self.pg1, dst_addr, sport, dport, data, + proto, echo_reply=True) self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -1229,12 +1220,9 @@ class MethodHolder(VppTestCase): for i in range(2): # out2in - pkts = self.create_stream_frag(self.pg0, - self.server_out_addr, - self.port_in, - self.server_out_port, - data, - proto) + pkts = self.create_stream_frag(self.pg0, self.server_out_addr, + self.port_in, self.server_out_port, + data, proto) self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() @@ -1251,19 +1239,12 @@ class MethodHolder(VppTestCase): # in2out if proto != IP_PROTOS.icmp: - pkts = self.create_stream_frag(self.pg1, - self.pg0.remote_ip4, + pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4, self.server_in_port, - p[layer].sport, - data, - proto) + p[layer].sport, data, proto) else: - pkts = self.create_stream_frag(self.pg1, - self.pg0.remote_ip4, - p[layer].id, - 0, - data, - proto, + pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4, + p[layer].id, 0, data, proto, echo_reply=True) self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) @@ -1319,12 +1300,8 @@ class MethodHolder(VppTestCase): for i in range(2): # in2out - pkts = self.create_stream_frag(self.pg0, - self.pg1.remote_ip4, - self.port_in, - 20, - data, - proto) + pkts = self.create_stream_frag(self.pg0, self.pg1.remote_ip4, + self.port_in, 20, data, proto) pkts.reverse() self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) @@ -1362,13 +1339,8 @@ class MethodHolder(VppTestCase): else: sport = p[layer].id dport = 0 - pkts = self.create_stream_frag(self.pg1, - dst_addr, - sport, - dport, - data, - proto, - echo_reply=True) + pkts = self.create_stream_frag(self.pg1, dst_addr, sport, dport, + data, proto, echo_reply=True) pkts.reverse() self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) @@ -1395,12 +1367,9 @@ class MethodHolder(VppTestCase): for i in range(2): # out2in - pkts = self.create_stream_frag(self.pg0, - self.server_out_addr, - self.port_in, - self.server_out_port, - data, - proto) + pkts = self.create_stream_frag(self.pg0, self.server_out_addr, + self.port_in, self.server_out_port, + data, proto) pkts.reverse() self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) @@ -1419,19 +1388,12 @@ class MethodHolder(VppTestCase): # in2out if proto != IP_PROTOS.icmp: - pkts = self.create_stream_frag(self.pg1, - self.pg0.remote_ip4, + pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4, self.server_in_port, - p[layer].sport, - data, - proto) + p[layer].sport, data, proto) else: - pkts = self.create_stream_frag(self.pg1, - self.pg0.remote_ip4, - p[layer].id, - 0, - data, - proto, + pkts = self.create_stream_frag(self.pg1, self.pg0.remote_ip4, + p[layer].id, 0, data, proto, echo_reply=True) pkts.reverse() self.pg1.add_stream(pkts) @@ -4425,6 +4387,11 @@ class TestNAT44EndpointDependent(MethodHolder): cls.pg8.config_ip4() cls.pg8.resolve_arp() + def setUp(self): + super(TestNAT44EndpointDependent, self).setUp() + self.vapi.nat_set_timeouts( + udp=300, tcp_established=7440, tcp_transitory=240, icmp=60) + @classmethod def tearDownClass(cls): super(TestNAT44EndpointDependent, cls).tearDownClass() @@ -5979,6 +5946,9 @@ class TestNAT44EndpointDependent(MethodHolder): sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0) start_sessnum = len(sessions) + self.vapi.nat_set_timeouts(udp=300, tcp_established=7440, + tcp_transitory=2, icmp=5) + self.initiate_tcp_session(self.pg0, self.pg1) # FIN packet in -> out @@ -6022,8 +5992,55 @@ class TestNAT44EndpointDependent(MethodHolder): self.pg_start() self.pg1.get_capture(1) - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, - 0) + sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0) + self.assertEqual(len(sessions) - start_sessnum, 1) + + stats = self.statistics.get_counter( + '/err/nat44-ed-out2in/drops due to TCP in transitory timeout') + out2in_drops = stats[0] + stats = self.statistics.get_counter( + '/err/nat44-ed-in2out/drops due to TCP in transitory timeout') + in2out_drops = stats[0] + + # extra FIN packet out -> in - this should be dropped + p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / + IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / + TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, + flags="FA", seq=300, ack=101)) + + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg0.assert_nothing_captured() + + # extra ACK packet in -> out - this should be dropped + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, + flags="A", seq=101, ack=301)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg1.assert_nothing_captured() + + stats = self.statistics.get_counter( + '/err/nat44-ed-out2in/drops due to TCP in transitory timeout') + self.assertEqual(stats[0] - out2in_drops, 1) + stats = self.statistics.get_counter( + '/err/nat44-ed-in2out/drops due to TCP in transitory timeout') + self.assertEqual(stats[0] - in2out_drops, 1) + + self.sleep(3) + # extra ACK packet in -> out - this will cause session to be wiped + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, + flags="A", seq=101, ack=301)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg1.assert_nothing_captured() + sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0) self.assertEqual(len(sessions) - start_sessnum, 0) def test_tcp_session_close_out(self): @@ -6048,6 +6065,9 @@ class TestNAT44EndpointDependent(MethodHolder): sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0) start_sessnum = len(sessions) + self.vapi.nat_set_timeouts(udp=300, tcp_established=7440, + tcp_transitory=2, icmp=5) + self.initiate_tcp_session(self.pg0, self.pg1) # FIN packet out -> in @@ -6081,8 +6101,55 @@ class TestNAT44EndpointDependent(MethodHolder): self.pg_start() self.pg0.get_capture(1) - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, - 0) + sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0) + self.assertEqual(len(sessions) - start_sessnum, 1) + + stats = self.statistics.get_counter( + '/err/nat44-ed-out2in/drops due to TCP in transitory timeout') + out2in_drops = stats[0] + stats = self.statistics.get_counter( + '/err/nat44-ed-in2out/drops due to TCP in transitory timeout') + in2out_drops = stats[0] + + # extra FIN packet out -> in - this should be dropped + p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / + IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / + TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, + flags="FA", seq=300, ack=101)) + + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg0.assert_nothing_captured() + + # extra ACK packet in -> out - this should be dropped + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, + flags="A", seq=101, ack=301)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg1.assert_nothing_captured() + + stats = self.statistics.get_counter( + '/err/nat44-ed-out2in/drops due to TCP in transitory timeout') + self.assertEqual(stats[0] - out2in_drops, 1) + stats = self.statistics.get_counter( + '/err/nat44-ed-in2out/drops due to TCP in transitory timeout') + self.assertEqual(stats[0] - in2out_drops, 1) + + self.sleep(3) + # extra ACK packet in -> out - this will cause session to be wiped + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, + flags="A", seq=101, ack=301)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg1.assert_nothing_captured() + sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0) self.assertEqual(len(sessions) - start_sessnum, 0) def test_tcp_session_close_simultaneous(self): @@ -6107,6 +6174,9 @@ class TestNAT44EndpointDependent(MethodHolder): sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0) start_sessnum = len(sessions) + self.vapi.nat_set_timeouts(udp=300, tcp_established=7440, + tcp_transitory=2, icmp=5) + self.initiate_tcp_session(self.pg0, self.pg1) # FIN packet in -> out @@ -6149,8 +6219,55 @@ class TestNAT44EndpointDependent(MethodHolder): self.pg_start() self.pg0.get_capture(1) - sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, - 0) + sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0) + self.assertEqual(len(sessions) - start_sessnum, 1) + + stats = self.statistics.get_counter( + '/err/nat44-ed-out2in/drops due to TCP in transitory timeout') + out2in_drops = stats[0] + stats = self.statistics.get_counter( + '/err/nat44-ed-in2out/drops due to TCP in transitory timeout') + in2out_drops = stats[0] + + # extra FIN packet out -> in - this should be dropped + p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / + IP(src=self.pg1.remote_ip4, dst=self.nat_addr) / + TCP(sport=self.tcp_external_port, dport=self.tcp_port_out, + flags="FA", seq=300, ack=101)) + + self.pg1.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg0.assert_nothing_captured() + + # extra ACK packet in -> out - this should be dropped + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, + flags="A", seq=101, ack=301)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg1.assert_nothing_captured() + + stats = self.statistics.get_counter( + '/err/nat44-ed-out2in/drops due to TCP in transitory timeout') + self.assertEqual(stats[0] - out2in_drops, 1) + stats = self.statistics.get_counter( + '/err/nat44-ed-in2out/drops due to TCP in transitory timeout') + self.assertEqual(stats[0] - in2out_drops, 1) + + self.sleep(3) + # extra ACK packet in -> out - this will cause session to be wiped + p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / + IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) / + TCP(sport=self.tcp_port_in, dport=self.tcp_external_port, + flags="A", seq=101, ack=301)) + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + self.pg1.assert_nothing_captured() + sessions = self.vapi.nat44_user_session_dump(self.pg0.remote_ip4, 0) self.assertEqual(len(sessions) - start_sessnum, 0) def test_one_armed_nat44_static(self): -- cgit 1.2.3-korg