tcp: accept rst that fail paws
[vpp.git] / src / vnet / tcp / tcp_input.c
index d1736e9..4406d68 100644 (file)
@@ -245,7 +245,7 @@ tcp_options_parse (tcp_header_t * th, tcp_options_t * to, u8 is_syn)
 always_inline int
 tcp_segment_check_paws (tcp_connection_t * tc)
 {
-  return tcp_opts_tstamp (&tc->rcv_opts) && tc->tsval_recent
+  return tcp_opts_tstamp (&tc->rcv_opts)
     && timestamp_lt (tc->rcv_opts.tsval, tc->tsval_recent);
 }
 
@@ -307,8 +307,6 @@ tcp_segment_validate (tcp_worker_ctx_t * wrk, tcp_connection_t * tc0,
   if (PREDICT_FALSE (tcp_segment_check_paws (tc0)))
     {
       *error0 = TCP_ERROR_PAWS;
-      if (CLIB_DEBUG > 2)
-       clib_warning ("paws failed\n%U", format_tcp_connection, tc0, 2);
       TCP_EVT_DBG (TCP_EVT_PAWS_FAIL, tc0, vnet_buffer (b0)->tcp.seq_number,
                   vnet_buffer (b0)->tcp.seq_end);
 
@@ -317,20 +315,19 @@ tcp_segment_validate (tcp_worker_ctx_t * wrk, tcp_connection_t * tc0,
       if (timestamp_lt (tc0->tsval_recent_age + TCP_PAWS_IDLE,
                        tcp_time_now_w_thread (tc0->c_thread_index)))
        {
-         /* Age isn't reset until we get a valid tsval (bsd inspired) */
-         tc0->tsval_recent = 0;
-         clib_warning ("paws failed - really old segment. REALLY?");
+         tc0->tsval_recent = tc0->rcv_opts.tsval;
+         clib_warning ("paws failed: 24-day old segment");
        }
-      else
+      /* Drop after ack if not rst. Resets can fail paws check as per
+       * RFC 7323 sec. 5.2: When an <RST> segment is received, it MUST NOT
+       * be subjected to the PAWS check by verifying an acceptable value in
+       * SEG.TSval */
+      else if (!tcp_rst (th0))
        {
-         /* Drop after ack if not rst */
-         if (!tcp_rst (th0))
-           {
-             tcp_program_ack (wrk, tc0);
-             TCP_EVT_DBG (TCP_EVT_DUPACK_SENT, tc0, vnet_buffer (b0)->tcp);
-           }
+         tcp_program_ack (wrk, tc0);
+         TCP_EVT_DBG (TCP_EVT_DUPACK_SENT, tc0, vnet_buffer (b0)->tcp);
+         goto error;
        }
-      goto error;
     }
 
   /* 1st: check sequence number */
@@ -546,6 +543,12 @@ tcp_handle_postponed_dequeues (tcp_worker_ctx_t * wrk)
       tc->burst_acked = 0;
       tcp_validate_txf_size (tc, tc->snd_una_max - tc->snd_una);
 
+      if (PREDICT_FALSE (tc->flags & TCP_CONN_PSH_PENDING))
+       {
+         if (seq_leq (tc->psh_seq, tc->snd_una))
+           tc->flags &= ~TCP_CONN_PSH_PENDING;
+       }
+
       /* If everything has been acked, stop retransmit timer
        * otherwise update. */
       tcp_retransmit_timer_update (tc);
@@ -908,7 +911,9 @@ tcp_rcv_sacks (tcp_connection_t * tc, u32 ack)
     {
       if (seq_lt (blk->start, blk->end)
          && seq_gt (blk->start, tc->snd_una)
-         && seq_gt (blk->start, ack) && seq_leq (blk->end, tc->snd_una_max))
+         && seq_gt (blk->start, ack)
+         && seq_lt (blk->start, tc->snd_una_max)
+         && seq_leq (blk->end, tc->snd_una_max))
        {
          blk++;
          continue;
@@ -2475,6 +2480,8 @@ tcp46_syn_sent_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
 
       if (tcp_opts_wscale (&new_tc0->rcv_opts))
        new_tc0->snd_wscale = new_tc0->rcv_opts.wscale;
+      else
+       new_tc0->rcv_wscale = 0;
 
       new_tc0->snd_wnd = clib_net_to_host_u16 (tcp0->window)
        << new_tc0->snd_wscale;
@@ -2719,6 +2726,14 @@ tcp46_rcv_process_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
              goto drop;
            }
 
+         /* Make sure the ack is exactly right */
+         if (tc0->rcv_nxt != vnet_buffer (b0)->tcp.seq_number || is_fin0)
+           {
+             error0 = TCP_ERROR_SEGMENT_INVALID;
+             tcp_send_reset_w_pkt (tc0, b0, is_ip4);
+             goto drop;
+           }
+
          /* Update rtt and rto */
          tcp_estimate_initial_rtt (tc0);