gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/packetimpact/tests/tcp_synsent_reset_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_synsent_reset_test 16 17 import ( 18 "flag" 19 "testing" 20 "time" 21 22 "golang.org/x/sys/unix" 23 "gvisor.dev/gvisor/pkg/abi/linux" 24 "gvisor.dev/gvisor/pkg/tcpip/header" 25 "gvisor.dev/gvisor/test/packetimpact/testbench" 26 ) 27 28 func init() { 29 testbench.Initialize(flag.CommandLine) 30 } 31 32 // dutSynSentState sets up the dut connection in SYN-SENT state. 33 func dutSynSentState(t *testing.T) (*testbench.DUT, *testbench.TCPIPv4, int32, uint16, uint16) { 34 t.Helper() 35 36 dut := testbench.NewDUT(t) 37 38 clientFD, clientPort := dut.CreateBoundSocket(t, unix.SOCK_STREAM|unix.SOCK_NONBLOCK, unix.IPPROTO_TCP, dut.Net.RemoteIPv4) 39 port := uint16(9001) 40 conn := dut.Net.NewTCPIPv4(t, testbench.TCP{SrcPort: &port, DstPort: &clientPort}, testbench.TCP{SrcPort: &clientPort, DstPort: &port}) 41 42 sa := unix.SockaddrInet4{Port: int(port)} 43 copy(sa.Addr[:], dut.Net.LocalIPv4) 44 // Bring the dut to SYN-SENT state with a non-blocking connect. 45 dut.Connect(t, clientFD, &sa) 46 if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn)}, nil, time.Second); err != nil { 47 t.Fatalf("expected SYN\n") 48 } 49 50 return &dut, &conn, clientFD, port, clientPort 51 } 52 53 // TestTCPSynSentReset tests RFC793, p67: SYN-SENT to CLOSED transition. 54 func TestTCPSynSentReset(t *testing.T) { 55 dut, conn, fd, _, _ := dutSynSentState(t) 56 defer conn.Close(t) 57 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagRst | header.TCPFlagAck)}) 58 // Expect the connection to have closed. 59 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}) 60 if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagRst)}, nil, time.Second); err != nil { 61 t.Fatalf("expected a TCP RST") 62 } 63 info := dut.GetSockOptTCPInfo(t, fd) 64 if got, want := uint32(info.State), linux.TCP_CLOSE; got != want { 65 t.Fatalf("got %d want %d", got, want) 66 } 67 } 68 69 // TestTCPSynSentRcvdReset tests RFC793, p70, SYN-SENT to SYN-RCVD to CLOSED 70 // transitions. 71 func TestTCPSynSentRcvdReset(t *testing.T) { 72 dut, c, fd, remotePort, clientPort := dutSynSentState(t) 73 defer c.Close(t) 74 75 conn := dut.Net.NewTCPIPv4(t, testbench.TCP{SrcPort: &remotePort, DstPort: &clientPort}, testbench.TCP{SrcPort: &clientPort, DstPort: &remotePort}) 76 defer conn.Close(t) 77 // Initiate new SYN connection with the same port pair 78 // (simultaneous open case), expect the dut connection to move to 79 // SYN-RCVD state 80 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn)}) 81 if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn | header.TCPFlagAck)}, nil, time.Second); err != nil { 82 t.Fatalf("expected SYN-ACK %s\n", err) 83 } 84 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagRst)}) 85 // Expect the connection to have transitioned SYN-RCVD to CLOSED. 86 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}) 87 if _, err := conn.ExpectData(t, &testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagRst)}, nil, time.Second); err != nil { 88 t.Fatalf("expected a TCP RST") 89 } 90 info := dut.GetSockOptTCPInfo(t, fd) 91 if got, want := uint32(info.State), linux.TCP_CLOSE; got != want { 92 t.Fatalf("got %d want %d", got, want) 93 } 94 }