tcp: fix port reuse with multiple listeners 54/30554/8
authorFlorin Coras <fcoras@cisco.com>
Tue, 29 Dec 2020 17:42:58 +0000 (09:42 -0800)
committerDave Barach <openvpp@barachs.net>
Fri, 5 Feb 2021 20:50:11 +0000 (20:50 +0000)
The check in listen state that the listener is not valid is not enough
if the time wait session's index overlaps an actual listener's index.
Thanks wanghanlin@corp.netease.com for the report!

Type: fix

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: I3dff0cb134940a8265ff908faa607c67dba5e56b

src/vnet/tcp/tcp_inlines.h
src/vnet/tcp/tcp_input.c

index 25bf738..4576267 100644 (file)
@@ -310,7 +310,6 @@ tcp_input_lookup_buffer (vlib_buffer_t * b, u8 thread_index, u32 * error,
   vnet_buffer (b)->tcp.data_len = n_data_bytes;
   vnet_buffer (b)->tcp.seq_end = vnet_buffer (b)->tcp.seq_number
     + n_data_bytes;
-  vnet_buffer (b)->tcp.flags = 0;
 
   *error = result ? TCP_ERROR_NONE + result : *error;
 
index a159d85..f5d17ea 100644 (file)
@@ -2561,14 +2561,19 @@ tcp46_listen_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
 
       b = vlib_get_buffer (vm, bi);
 
-      lc = tcp_listener_get (vnet_buffer (b)->tcp.connection_index);
-      if (PREDICT_FALSE (lc == 0))
+      /* Flags initialized with connection state after lookup */
+      if (vnet_buffer (b)->tcp.flags == TCP_STATE_LISTEN)
+       {
+         lc = tcp_listener_get (vnet_buffer (b)->tcp.connection_index);
+       }
+      else
        {
          tcp_connection_t *tc;
          tc = tcp_connection_get (vnet_buffer (b)->tcp.connection_index,
                                   thread_index);
          if (tc->state != TCP_STATE_TIME_WAIT)
            {
+             lc = 0;
              error = TCP_ERROR_CREATE_EXISTS;
              goto done;
            }
@@ -2802,6 +2807,10 @@ tcp_input_dispatch_buffer (tcp_main_t * tm, tcp_connection_t * tc,
   error = tm->dispatch_table[tc->state][flags].error;
   tc->segs_in += 1;
 
+  /* Track connection state when packet was received. It helps
+   * @ref tcp46_listen_inline detect port reuse */
+  vnet_buffer (b)->tcp.flags = tc->state;
+
   if (PREDICT_FALSE (error != TCP_ERROR_NONE))
     {
       b->error = error_node->errors[error];