github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/packetimpact/tests/tcp_outside_the_window_test.go (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tcp_outside_the_window_test
    16  
    17  import (
    18  	"flag"
    19  	"fmt"
    20  	"testing"
    21  	"time"
    22  
    23  	"golang.org/x/sys/unix"
    24  	"github.com/SagerNet/gvisor/pkg/tcpip/header"
    25  	"github.com/SagerNet/gvisor/pkg/tcpip/seqnum"
    26  	"github.com/SagerNet/gvisor/test/packetimpact/testbench"
    27  )
    28  
    29  func init() {
    30  	testbench.Initialize(flag.CommandLine)
    31  }
    32  
    33  // TestTCPOutsideTheWindows tests the behavior of the DUT when packets arrive
    34  // that are inside or outside the TCP window. Packets that are outside the
    35  // window should force an extra ACK, as described in RFC793 page 69:
    36  // https://tools.ietf.org/html/rfc793#page-69
    37  func TestTCPOutsideTheWindow(t *testing.T) {
    38  	for _, tt := range []struct {
    39  		description  string
    40  		tcpFlags     header.TCPFlags
    41  		payload      []testbench.Layer
    42  		seqNumOffset seqnum.Size
    43  		expectACK    bool
    44  	}{
    45  		{"SYN", header.TCPFlagSyn, nil, 0, true},
    46  		{"SYNACK", header.TCPFlagSyn | header.TCPFlagAck, nil, 0, true},
    47  		{"ACK", header.TCPFlagAck, nil, 0, false},
    48  		{"FIN", header.TCPFlagFin, nil, 0, false},
    49  		{"Data", header.TCPFlagAck, []testbench.Layer{&testbench.Payload{Bytes: []byte("abc123")}}, 0, true},
    50  
    51  		{"SYN", header.TCPFlagSyn, nil, 1, true},
    52  		{"SYNACK", header.TCPFlagSyn | header.TCPFlagAck, nil, 1, true},
    53  		{"ACK", header.TCPFlagAck, nil, 1, true},
    54  		{"FIN", header.TCPFlagFin, nil, 1, false},
    55  		{"Data", header.TCPFlagAck, []testbench.Layer{&testbench.Payload{Bytes: []byte("abc123")}}, 1, true},
    56  
    57  		{"SYN", header.TCPFlagSyn, nil, 2, true},
    58  		{"SYNACK", header.TCPFlagSyn | header.TCPFlagAck, nil, 2, true},
    59  		{"ACK", header.TCPFlagAck, nil, 2, true},
    60  		{"FIN", header.TCPFlagFin, nil, 2, false},
    61  		{"Data", header.TCPFlagAck, []testbench.Layer{&testbench.Payload{Bytes: []byte("abc123")}}, 2, true},
    62  	} {
    63  		t.Run(fmt.Sprintf("%s%d", tt.description, tt.seqNumOffset), func(t *testing.T) {
    64  			dut := testbench.NewDUT(t)
    65  			listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
    66  			defer dut.Close(t, listenFD)
    67  			conn := dut.Net.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
    68  			defer conn.Close(t)
    69  			conn.Connect(t)
    70  			acceptFD, _ := dut.Accept(t, listenFD)
    71  			defer dut.Close(t, acceptFD)
    72  
    73  			windowSize := seqnum.Size(*conn.SynAck(t).WindowSize) + tt.seqNumOffset
    74  			conn.Drain(t)
    75  			// Ignore whatever incrementing that this out-of-order packet might cause
    76  			// to the AckNum.
    77  			localSeqNum := testbench.Uint32(uint32(*conn.LocalSeqNum(t)))
    78  			conn.Send(t, testbench.TCP{
    79  				Flags:  testbench.TCPFlags(tt.tcpFlags),
    80  				SeqNum: testbench.Uint32(uint32(conn.LocalSeqNum(t).Add(windowSize))),
    81  			}, tt.payload...)
    82  			timeout := time.Second
    83  			gotACK, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck), AckNum: localSeqNum}, timeout)
    84  			if tt.expectACK && err != nil {
    85  				t.Fatalf("expected an ACK packet within %s but got none: %s", timeout, err)
    86  			}
    87  			// Data packets w/o SYN bits are always acked by Linux. Netstack ACK's data packets
    88  			// always right now. So only send a second segment and test for no ACK for packets
    89  			// with no data.
    90  			if tt.expectACK && tt.payload == nil {
    91  				// Sending another out-of-window segment immediately should not trigger
    92  				// an ACK if less than 500ms(default rate limit for out-of-window ACKs)
    93  				// has passed since the last ACK was sent.
    94  				t.Logf("sending another segment")
    95  				conn.Send(t, testbench.TCP{
    96  					Flags:  testbench.TCPFlags(tt.tcpFlags),
    97  					SeqNum: testbench.Uint32(uint32(conn.LocalSeqNum(t).Add(windowSize))),
    98  				}, tt.payload...)
    99  				timeout := 3 * time.Second
   100  				gotACK, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck), AckNum: localSeqNum}, timeout)
   101  				if err == nil {
   102  					t.Fatalf("expected no ACK packet but got one: %s", gotACK)
   103  				}
   104  			}
   105  			if !tt.expectACK && gotACK != nil {
   106  				t.Fatalf("expected no ACK packet within %s but got one: %s", timeout, gotACK)
   107  			}
   108  		})
   109  	}
   110  }
   111  
   112  // TestAckOTWSeqInClosing tests that the DUT should send an ACK with
   113  // the right ACK number when receiving a packet with OTW Seq number
   114  // in CLOSING state. https://tools.ietf.org/html/rfc793#page-69
   115  func TestAckOTWSeqInClosing(t *testing.T) {
   116  	for _, tt := range []struct {
   117  		description  string
   118  		flags        header.TCPFlags
   119  		payloads     testbench.Layers
   120  		seqNumOffset seqnum.Size
   121  		expectACK    bool
   122  	}{
   123  		{"SYN", header.TCPFlagSyn, nil, 0, true},
   124  		{"SYNACK", header.TCPFlagSyn | header.TCPFlagAck, nil, 0, true},
   125  		{"ACK", header.TCPFlagAck, nil, 0, false},
   126  		{"FINACK", header.TCPFlagFin | header.TCPFlagAck, nil, 0, false},
   127  		{"Data", header.TCPFlagAck, []testbench.Layer{&testbench.Payload{Bytes: []byte("Sample Data")}}, 0, false},
   128  
   129  		{"SYN", header.TCPFlagSyn, nil, 1, true},
   130  		{"SYNACK", header.TCPFlagSyn | header.TCPFlagAck, nil, 1, true},
   131  		{"ACK", header.TCPFlagAck, nil, 1, true},
   132  		{"FINACK", header.TCPFlagFin | header.TCPFlagAck, nil, 1, true},
   133  		{"Data", header.TCPFlagAck, []testbench.Layer{&testbench.Payload{Bytes: []byte("Sample Data")}}, 1, true},
   134  
   135  		{"SYN", header.TCPFlagSyn, nil, 2, true},
   136  		{"SYNACK", header.TCPFlagSyn | header.TCPFlagAck, nil, 2, true},
   137  		{"ACK", header.TCPFlagAck, nil, 2, true},
   138  		{"FINACK", header.TCPFlagFin | header.TCPFlagAck, nil, 2, true},
   139  		{"Data", header.TCPFlagAck, []testbench.Layer{&testbench.Payload{Bytes: []byte("Sample Data")}}, 2, true},
   140  	} {
   141  		t.Run(fmt.Sprintf("%s%d", tt.description, tt.seqNumOffset), func(t *testing.T) {
   142  			dut := testbench.NewDUT(t)
   143  			listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1)
   144  			defer dut.Close(t, listenFD)
   145  			conn := dut.Net.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort})
   146  			defer conn.Close(t)
   147  			conn.Connect(t)
   148  			acceptFD, _ := dut.Accept(t, listenFD)
   149  			defer dut.Close(t, acceptFD)
   150  
   151  			dut.Shutdown(t, acceptFD, unix.SHUT_WR)
   152  
   153  			if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagFin | header.TCPFlagAck)}, time.Second); err != nil {
   154  				t.Fatalf("expected FINACK from DUT, but got none: %s", err)
   155  			}
   156  
   157  			// Do not ack the FIN from DUT so that the TCP state on DUT is CLOSING instead of CLOSED.
   158  			seqNumForTheirFIN := testbench.Uint32(uint32(*conn.RemoteSeqNum(t)) - 1)
   159  			conn.Send(t, testbench.TCP{AckNum: seqNumForTheirFIN, Flags: testbench.TCPFlags(header.TCPFlagFin | header.TCPFlagAck)})
   160  
   161  			gotTCP, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second)
   162  			if err != nil {
   163  				t.Fatalf("expected an ACK to our FIN, but got none: %s", err)
   164  			}
   165  
   166  			windowSize := seqnum.Size(*gotTCP.WindowSize) + tt.seqNumOffset
   167  			conn.SendFrameStateless(t, conn.CreateFrame(t, testbench.Layers{&testbench.TCP{
   168  				SeqNum: testbench.Uint32(uint32(conn.LocalSeqNum(t).Add(windowSize))),
   169  				AckNum: seqNumForTheirFIN,
   170  				Flags:  testbench.TCPFlags(tt.flags),
   171  			}}, tt.payloads...))
   172  
   173  			gotACK, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second)
   174  			if tt.expectACK && err != nil {
   175  				t.Errorf("expected an ACK but got none: %s", err)
   176  			}
   177  			if !tt.expectACK && gotACK != nil {
   178  				t.Errorf("expected no ACK but got one: %s", gotACK)
   179  			}
   180  		})
   181  	}
   182  }