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>
diff --git a/test/test_nat44_ed.py b/test/test_nat44_ed.py
index f172dab..21eebb2 100644
--- a/test/test_nat44_ed.py
+++ b/test/test_nat44_ed.py
@@ -2609,8 +2609,8 @@
                               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 @@
                  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 @@
         # 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 @@
                  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 @@
         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) /