nat: tweak rfc7857 tcp connection tracking
The RFC7857 state machine introduced in 56c492a is a trade-off. It tries to retain sessions as much as possible and also offers some protection against spurious RST by re-establishing sessions if data is received after the RST. From experience in the wild, this algorithm is a little too liberal, as it leaves too many spurious established sessions in the session table. E.g. a oberserved pattern is: client server <- FIN, ACK ACK -> ACK -> RST, ACK -> With the current state machine this would leave the session in established state. These proposed changes do: - require 3-way handshake to establish session. (current requires only to see SYNs from both sides) - RST will move session to transitory without recovery if data is sent after - Only a single FIN is needed to move to transitory Fixes: 56c492aa0502751de2dd9d890096a82c5f04776d Type: fix Signed-off-by: Ole Troan <ot@cisco.com> Change-Id: I92e593e00b2efe48d04997642d85bd59e0eaa2ea Signed-off-by: Ole Troan <ot@cisco.com>
This commit is contained in:
@ -2456,8 +2456,6 @@ nat44_plugin_enable (nat44_config_t c)
|
||||
|
||||
nat44_ed_db_init (sm->max_translations_per_thread, sm->translation_buckets);
|
||||
|
||||
nat44_ed_init_tcp_state_stable (sm);
|
||||
|
||||
nat_affinity_enable ();
|
||||
|
||||
nat_reset_timeouts (&sm->timeouts);
|
||||
|
@ -123,14 +123,10 @@ typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NAT44_ED_TCP_FLAG_NONE = 0,
|
||||
NAT44_ED_TCP_FLAG_FIN,
|
||||
NAT44_ED_TCP_FLAG_FIN = 0,
|
||||
NAT44_ED_TCP_FLAG_SYN,
|
||||
NAT44_ED_TCP_FLAG_SYNFIN,
|
||||
NAT44_ED_TCP_FLAG_RST,
|
||||
NAT44_ED_TCP_FLAG_FINRST,
|
||||
NAT44_ED_TCP_FLAG_SYNRST,
|
||||
NAT44_ED_TCP_FLAG_SYNFINRST,
|
||||
NAT44_ED_TCP_FLAG_ACK,
|
||||
NAT44_ED_TCP_N_FLAG,
|
||||
} nat44_ed_tcp_flag_e;
|
||||
|
||||
@ -145,15 +141,8 @@ typedef enum
|
||||
typedef enum
|
||||
{
|
||||
NAT44_ED_TCP_STATE_CLOSED = 0,
|
||||
NAT44_ED_TCP_STATE_SYN_I2O,
|
||||
NAT44_ED_TCP_STATE_SYN_O2I,
|
||||
NAT44_ED_TCP_STATE_ESTABLISHED,
|
||||
NAT44_ED_TCP_STATE_FIN_I2O,
|
||||
NAT44_ED_TCP_STATE_FIN_O2I,
|
||||
NAT44_ED_TCP_STATE_RST_TRANS,
|
||||
NAT44_ED_TCP_STATE_FIN_TRANS,
|
||||
NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O,
|
||||
NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I,
|
||||
NAT44_ED_TCP_STATE_CLOSING,
|
||||
NAT44_ED_TCP_N_STATE,
|
||||
} nat44_ed_tcp_state_e;
|
||||
|
||||
@ -336,6 +325,7 @@ typedef CLIB_PACKED(struct
|
||||
u16 ext_host_nat_port;
|
||||
|
||||
/* TCP session state */
|
||||
u8 tcp_flags[NAT44_ED_N_DIR];
|
||||
nat44_ed_tcp_state_e tcp_state;
|
||||
|
||||
/* per vrf sessions index */
|
||||
|
@ -303,34 +303,11 @@ format_nat44_ed_tcp_state (u8 *s, va_list *args)
|
||||
case NAT44_ED_TCP_STATE_CLOSED:
|
||||
s = format (s, "closed");
|
||||
break;
|
||||
case NAT44_ED_TCP_STATE_SYN_I2O:
|
||||
s = format (s, "SYN seen in in2out direction");
|
||||
break;
|
||||
case NAT44_ED_TCP_STATE_SYN_O2I:
|
||||
s = format (s, "SYN seen in out2in direction");
|
||||
break;
|
||||
case NAT44_ED_TCP_STATE_ESTABLISHED:
|
||||
s = format (s, "SYN seen in both directions/established");
|
||||
s = format (s, "established");
|
||||
break;
|
||||
case NAT44_ED_TCP_STATE_FIN_I2O:
|
||||
s = format (s, "FIN seen in in2out direction");
|
||||
break;
|
||||
case NAT44_ED_TCP_STATE_FIN_O2I:
|
||||
s = format (s, "FIN seen in out2in direction");
|
||||
break;
|
||||
case NAT44_ED_TCP_STATE_RST_TRANS:
|
||||
s = format (s, "RST seen/transitory timeout");
|
||||
break;
|
||||
case NAT44_ED_TCP_STATE_FIN_TRANS:
|
||||
s = format (s, "FIN seen in both directions/transitory timeout");
|
||||
break;
|
||||
case NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_O2I:
|
||||
s = format (s, "FIN seen in both directions/transitory timeout/session "
|
||||
"reopening in out2in direction");
|
||||
break;
|
||||
case NAT44_ED_TCP_STATE_FIN_REOPEN_SYN_I2O:
|
||||
s = format (s, "FIN seen in both directions/transitory timeout/session "
|
||||
"reopening in in2out direction");
|
||||
case NAT44_ED_TCP_STATE_CLOSING:
|
||||
s = format (s, "closing");
|
||||
break;
|
||||
case NAT44_ED_TCP_N_STATE:
|
||||
s = format (s, "BUG! unexpected N_STATE! BUG!");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2609,8 +2609,8 @@ class TestNAT44EDMW(TestNAT44ED):
|
||||
self.tcp_external_port)
|
||||
|
||||
# Wait at least the transitory time, the session is in established
|
||||
# state anyway. RST followed by a data packet should keep it
|
||||
# established.
|
||||
# state anyway. RST followed by a data packet should move it to
|
||||
# transitory state.
|
||||
self.virtual_sleep(6)
|
||||
p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
|
||||
IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
|
||||
@ -2624,15 +2624,6 @@ class TestNAT44EDMW(TestNAT44ED):
|
||||
flags="P"))
|
||||
self.send_and_expect(self.pg0, p, self.pg1)
|
||||
|
||||
# State is established, session should be still open after 6 seconds
|
||||
self.virtual_sleep(6)
|
||||
|
||||
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="R"))
|
||||
self.send_and_expect(self.pg0, p, self.pg1)
|
||||
|
||||
# State is transitory, session should be closed after 6 seconds
|
||||
self.virtual_sleep(6)
|
||||
|
||||
@ -3135,9 +3126,16 @@ class TestNAT44EDMW(TestNAT44ED):
|
||||
# SYN out2in
|
||||
p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
|
||||
IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
|
||||
TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
|
||||
TCP(sport=self.tcp_external_port, dport=self.tcp_port_out,
|
||||
flags='SA'))
|
||||
self.send_and_expect(self.pg1, p, self.pg0)
|
||||
|
||||
p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_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"))
|
||||
self.send_and_expect(self.pg0, p, self.pg1)
|
||||
|
||||
# FIN in2out
|
||||
p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
|
||||
IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
|
||||
@ -3152,17 +3150,8 @@ class TestNAT44EDMW(TestNAT44ED):
|
||||
flags="F"))
|
||||
self.send_and_expect(self.pg1, p, self.pg0)
|
||||
|
||||
# SYN in2out
|
||||
p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) /
|
||||
IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4) /
|
||||
TCP(sport=self.tcp_port_in, dport=self.tcp_external_port))
|
||||
self.send_and_expect(self.pg0, p, self.pg1)
|
||||
|
||||
# SYN out2in
|
||||
p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) /
|
||||
IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
|
||||
TCP(sport=self.tcp_external_port, dport=self.tcp_port_out))
|
||||
self.send_and_expect(self.pg1, p, self.pg0)
|
||||
self.init_tcp_session(self.pg0, self.pg1, self.tcp_port_in,
|
||||
self.tcp_external_port)
|
||||
|
||||
# 2 records should be produced - first one del & add
|
||||
capture = self.pg3.get_capture(2)
|
||||
@ -3746,9 +3735,16 @@ class TestNAT44EDMW(TestNAT44ED):
|
||||
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=in_port, dport=ext_port,
|
||||
flags="S", seq=101, ack=301))
|
||||
flags="SA", seq=101, ack=301))
|
||||
self.send_and_expect(self.pg0, p, self.pg1)
|
||||
|
||||
# send ACK packet out -> in
|
||||
p = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) /
|
||||
IP(src=self.pg1.remote_ip4, dst=self.nat_addr) /
|
||||
TCP(sport=ext_port, dport=out_port,
|
||||
flags="A", seq=300, ack=101))
|
||||
self.send_and_expect(self.pg1, p, self.pg0)
|
||||
|
||||
self.virtual_sleep(3)
|
||||
# send ACK packet in -> out - should be forwarded and session alive
|
||||
p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) /
|
||||
|
Reference in New Issue
Block a user