github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/packetimpact/tests/tcp_unacc_seq_ack_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_unacc_seq_ack_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 func TestEstablishedUnaccSeqAck(t *testing.T) { 34 for _, tt := range []struct { 35 description string 36 makeTestingTCP func(t *testing.T, conn *testbench.TCPIPv4, seqNumOffset, windowSize seqnum.Size) testbench.TCP 37 seqNumOffset seqnum.Size 38 expectAck bool 39 restoreSeq bool 40 }{ 41 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 0, expectAck: true, restoreSeq: true}, 42 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 1, expectAck: true, restoreSeq: true}, 43 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 2, expectAck: true, restoreSeq: true}, 44 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 0, expectAck: true, restoreSeq: false}, 45 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 1, expectAck: false, restoreSeq: true}, 46 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 2, expectAck: false, restoreSeq: true}, 47 } { 48 t.Run(fmt.Sprintf("%s:offset=%d", tt.description, tt.seqNumOffset), func(t *testing.T) { 49 dut := testbench.NewDUT(t) 50 listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1 /*backlog*/) 51 defer dut.Close(t, listenFD) 52 conn := dut.Net.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort}) 53 defer conn.Close(t) 54 55 conn.Connect(t) 56 dut.Accept(t, listenFD) 57 58 sampleData := []byte("Sample Data") 59 samplePayload := &testbench.Payload{Bytes: sampleData} 60 61 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck | header.TCPFlagPsh)}, samplePayload) 62 gotTCP, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second) 63 if err != nil { 64 t.Fatalf("expected ack %s", err) 65 } 66 windowSize := seqnum.Size(*gotTCP.WindowSize) 67 68 origSeq := *conn.LocalSeqNum(t) 69 // Send a segment with OTW Seq / unacc ACK. 70 conn.Send(t, tt.makeTestingTCP(t, &conn, tt.seqNumOffset, windowSize), samplePayload) 71 if tt.restoreSeq { 72 // Restore the local sequence number to ensure that the incoming 73 // ACK matches the TCP layer state. 74 *conn.LocalSeqNum(t) = origSeq 75 } 76 gotAck, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second) 77 if tt.expectAck && err != nil { 78 t.Fatalf("expected an ack but got none: %s", err) 79 } 80 if err == nil && !tt.expectAck && gotAck != nil { 81 t.Fatalf("expected no ack but got one: %s", gotAck) 82 } 83 }) 84 } 85 } 86 87 func TestPassiveCloseUnaccSeqAck(t *testing.T) { 88 for _, tt := range []struct { 89 description string 90 makeTestingTCP func(t *testing.T, conn *testbench.TCPIPv4, seqNumOffset, windowSize seqnum.Size) testbench.TCP 91 seqNumOffset seqnum.Size 92 expectAck bool 93 }{ 94 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 0, expectAck: false}, 95 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 1, expectAck: true}, 96 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 2, expectAck: true}, 97 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 0, expectAck: false}, 98 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 1, expectAck: true}, 99 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 2, expectAck: true}, 100 } { 101 t.Run(fmt.Sprintf("%s:offset=%d", tt.description, tt.seqNumOffset), func(t *testing.T) { 102 dut := testbench.NewDUT(t) 103 listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1 /*backlog*/) 104 defer dut.Close(t, listenFD) 105 conn := dut.Net.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort}) 106 defer conn.Close(t) 107 108 conn.Connect(t) 109 acceptFD, _ := dut.Accept(t, listenFD) 110 111 // Send a FIN to DUT to intiate the passive close. 112 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck | header.TCPFlagFin)}) 113 gotTCP, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second) 114 if err != nil { 115 t.Fatalf("expected an ACK for our fin and DUT should enter CLOSE_WAIT: %s", err) 116 } 117 windowSize := seqnum.Size(*gotTCP.WindowSize) 118 119 sampleData := []byte("Sample Data") 120 samplePayload := &testbench.Payload{Bytes: sampleData} 121 122 // Send a segment with OTW Seq / unacc ACK. 123 conn.Send(t, tt.makeTestingTCP(t, &conn, tt.seqNumOffset, windowSize), samplePayload) 124 gotAck, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second) 125 if tt.expectAck && err != nil { 126 t.Errorf("expected an ack but got none: %s", err) 127 } 128 if err == nil && !tt.expectAck && gotAck != nil { 129 t.Errorf("expected no ack but got one: %s", gotAck) 130 } 131 132 // Now let's verify DUT is indeed in CLOSE_WAIT 133 dut.Close(t, acceptFD) 134 if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck | header.TCPFlagFin)}, time.Second); err != nil { 135 t.Fatalf("expected DUT to send a FIN: %s", err) 136 } 137 // Ack the FIN from DUT 138 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}) 139 // Send some extra data to DUT 140 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, samplePayload) 141 if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagRst)}, time.Second); err != nil { 142 t.Fatalf("expected DUT to send an RST: %s", err) 143 } 144 }) 145 } 146 } 147 148 func TestActiveCloseUnaccpSeqAck(t *testing.T) { 149 for _, tt := range []struct { 150 description string 151 makeTestingTCP func(t *testing.T, conn *testbench.TCPIPv4, seqNumOffset, windowSize seqnum.Size) testbench.TCP 152 seqNumOffset seqnum.Size 153 restoreSeq bool 154 }{ 155 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 0, restoreSeq: true}, 156 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 1, restoreSeq: true}, 157 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 2, restoreSeq: true}, 158 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 0, restoreSeq: false}, 159 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 1, restoreSeq: true}, 160 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 2, restoreSeq: true}, 161 } { 162 t.Run(fmt.Sprintf("%s:offset=%d", tt.description, tt.seqNumOffset), func(t *testing.T) { 163 dut := testbench.NewDUT(t) 164 listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1 /*backlog*/) 165 defer dut.Close(t, listenFD) 166 conn := dut.Net.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort}) 167 defer conn.Close(t) 168 169 conn.Connect(t) 170 acceptFD, _ := dut.Accept(t, listenFD) 171 172 // Trigger active close. 173 dut.Shutdown(t, acceptFD, unix.SHUT_WR) 174 175 // Get to FIN_WAIT2 176 gotTCP, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagFin | header.TCPFlagAck)}, time.Second) 177 if err != nil { 178 t.Fatalf("expected a FIN: %s", err) 179 } 180 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}) 181 182 sendUnaccSeqAck := func(state string) { 183 t.Helper() 184 sampleData := []byte("Sample Data") 185 samplePayload := &testbench.Payload{Bytes: sampleData} 186 187 origSeq := *conn.LocalSeqNum(t) 188 // Send a segment with OTW Seq / unacc ACK. 189 conn.Send(t, tt.makeTestingTCP(t, &conn, tt.seqNumOffset, seqnum.Size(*gotTCP.WindowSize)), samplePayload) 190 if tt.restoreSeq { 191 // Restore the local sequence number to ensure that the 192 // incoming ACK matches the TCP layer state. 193 *conn.LocalSeqNum(t) = origSeq 194 } 195 if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second); err != nil { 196 t.Errorf("expected an ack in %s state, but got none: %s", state, err) 197 } 198 } 199 200 sendUnaccSeqAck("FIN_WAIT2") 201 202 // Send a FIN to DUT to get to TIME_WAIT 203 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagFin | header.TCPFlagAck)}) 204 if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second); err != nil { 205 t.Fatalf("expected an ACK for our fin and DUT should enter TIME_WAIT: %s", err) 206 } 207 208 sendUnaccSeqAck("TIME_WAIT") 209 }) 210 } 211 } 212 213 func TestSimultaneousCloseUnaccSeqAck(t *testing.T) { 214 for _, tt := range []struct { 215 description string 216 makeTestingTCP func(t *testing.T, conn *testbench.TCPIPv4, seqNumOffset, windowSize seqnum.Size) testbench.TCP 217 seqNumOffset seqnum.Size 218 expectAck bool 219 }{ 220 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 0, expectAck: false}, 221 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 1, expectAck: true}, 222 {description: "OTWSeq", makeTestingTCP: testbench.GenerateOTWSeqSegment, seqNumOffset: 2, expectAck: true}, 223 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 0, expectAck: false}, 224 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 1, expectAck: true}, 225 {description: "UnaccAck", makeTestingTCP: testbench.GenerateUnaccACKSegment, seqNumOffset: 2, expectAck: true}, 226 } { 227 t.Run(fmt.Sprintf("%s:offset=%d", tt.description, tt.seqNumOffset), func(t *testing.T) { 228 dut := testbench.NewDUT(t) 229 listenFD, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1 /*backlog*/) 230 defer dut.Close(t, listenFD) 231 conn := dut.Net.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort}) 232 defer conn.Close(t) 233 234 conn.Connect(t) 235 acceptFD, _ := dut.Accept(t, listenFD) 236 237 // Trigger active close. 238 dut.Shutdown(t, acceptFD, unix.SHUT_WR) 239 240 if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagFin | header.TCPFlagAck)}, time.Second); err != nil { 241 t.Fatalf("expected a FIN: %s", err) 242 } 243 // Do not ack the FIN from DUT so that we get to CLOSING. 244 seqNumForTheirFIN := testbench.Uint32(uint32(*conn.RemoteSeqNum(t)) - 1) 245 conn.Send(t, testbench.TCP{AckNum: seqNumForTheirFIN, Flags: testbench.TCPFlags(header.TCPFlagFin | header.TCPFlagAck)}) 246 247 gotTCP, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second) 248 if err != nil { 249 t.Errorf("expected an ACK to our FIN, but got none: %s", err) 250 } 251 252 sampleData := []byte("Sample Data") 253 samplePayload := &testbench.Payload{Bytes: sampleData} 254 255 origSeq := uint32(*conn.LocalSeqNum(t)) 256 // Send a segment with OTW Seq / unacc ACK. 257 tcp := tt.makeTestingTCP(t, &conn, tt.seqNumOffset, seqnum.Size(*gotTCP.WindowSize)) 258 if tt.description == "OTWSeq" { 259 // If we generate an OTW Seq segment, make sure we don't acknowledge their FIN so that 260 // we stay in CLOSING. 261 tcp.AckNum = seqNumForTheirFIN 262 } 263 conn.Send(t, tcp, samplePayload) 264 265 got, err := conn.Expect(t, testbench.TCP{AckNum: testbench.Uint32(origSeq), Flags: testbench.TCPFlags(header.TCPFlagAck)}, time.Second) 266 if tt.expectAck && err != nil { 267 t.Errorf("expected an ack in CLOSING state, but got none: %s", err) 268 } 269 if !tt.expectAck && got != nil { 270 t.Errorf("expected no ack in CLOSING state, but got one: %s", got) 271 } 272 }) 273 } 274 }