github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/packetimpact/tests/tcp_paws_mechanism_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_paws_mechanism_test 16 17 import ( 18 "encoding/hex" 19 "flag" 20 "testing" 21 "time" 22 23 "golang.org/x/sys/unix" 24 "github.com/SagerNet/gvisor/pkg/tcpip/header" 25 "github.com/SagerNet/gvisor/test/packetimpact/testbench" 26 ) 27 28 func init() { 29 testbench.Initialize(flag.CommandLine) 30 } 31 32 func TestPAWSMechanism(t *testing.T) { 33 dut := testbench.NewDUT(t) 34 listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1) 35 defer dut.Close(t, listenFD) 36 conn := dut.Net.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort}) 37 defer conn.Close(t) 38 39 options := make([]byte, header.TCPOptionTSLength) 40 header.EncodeTSOption(currentTS(), 0, options) 41 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn), Options: options}) 42 synAck, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn | header.TCPFlagAck)}, time.Second) 43 if err != nil { 44 t.Fatalf("didn't get synack during handshake: %s", err) 45 } 46 parsedSynOpts := header.ParseSynOptions(synAck.Options, true) 47 if !parsedSynOpts.TS { 48 t.Fatalf("expected TSOpt from DUT, options we got:\n%s", hex.Dump(synAck.Options)) 49 } 50 tsecr := parsedSynOpts.TSVal 51 header.EncodeTSOption(currentTS(), tsecr, options) 52 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck), Options: options}) 53 acceptFD, _ := dut.Accept(t, listenFD) 54 defer dut.Close(t, acceptFD) 55 56 sampleData := []byte("Sample Data") 57 sentTSVal := currentTS() 58 header.EncodeTSOption(sentTSVal, tsecr, options) 59 // 3ms here is chosen arbitrarily to make sure we have increasing timestamps 60 // every time we send one, it should not cause any flakiness because timestamps 61 // only need to be non-decreasing. 62 time.Sleep(3 * time.Millisecond) 63 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck), Options: options}, &testbench.Payload{Bytes: sampleData}) 64 65 gotTCP, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second) 66 if err != nil { 67 t.Fatalf("expected an ACK but got none: %s", err) 68 } 69 70 parsedOpts := header.ParseTCPOptions(gotTCP.Options) 71 if !parsedOpts.TS { 72 t.Fatalf("expected TS option in response, options we got:\n%s", hex.Dump(gotTCP.Options)) 73 } 74 if parsedOpts.TSVal < tsecr { 75 t.Fatalf("TSVal should be non-decreasing, but %d < %d", parsedOpts.TSVal, tsecr) 76 } 77 if parsedOpts.TSEcr != sentTSVal { 78 t.Fatalf("TSEcr should match our sent TSVal, %d != %d", parsedOpts.TSEcr, sentTSVal) 79 } 80 tsecr = parsedOpts.TSVal 81 lastAckNum := gotTCP.AckNum 82 83 badTSVal := sentTSVal - 100 84 header.EncodeTSOption(badTSVal, tsecr, options) 85 // 3ms here is chosen arbitrarily and this time.Sleep() should not cause flakiness 86 // due to the exact same reasoning discussed above. 87 time.Sleep(3 * time.Millisecond) 88 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck), Options: options}, &testbench.Payload{Bytes: sampleData}) 89 90 gotTCP, err = conn.Expect(t, testbench.TCP{AckNum: lastAckNum, Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second) 91 if err != nil { 92 t.Fatalf("expected segment with AckNum %d but got none: %s", lastAckNum, err) 93 } 94 parsedOpts = header.ParseTCPOptions(gotTCP.Options) 95 if !parsedOpts.TS { 96 t.Fatalf("expected TS option in response, options we got:\n%s", hex.Dump(gotTCP.Options)) 97 } 98 if parsedOpts.TSVal < tsecr { 99 t.Fatalf("TSVal should be non-decreasing, but %d < %d", parsedOpts.TSVal, tsecr) 100 } 101 if parsedOpts.TSEcr != sentTSVal { 102 t.Fatalf("TSEcr should match our sent TSVal, %d != %d", parsedOpts.TSEcr, sentTSVal) 103 } 104 } 105 106 func currentTS() uint32 { 107 return uint32(time.Now().UnixNano() / 1e6) 108 }