gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/transport/tcpconntrack/tcp_conntrack_test.go (about) 1 // Copyright 2018 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 tcpconntrack_test 16 17 import ( 18 "os" 19 "testing" 20 21 "gvisor.dev/gvisor/pkg/refs" 22 "gvisor.dev/gvisor/pkg/tcpip/header" 23 "gvisor.dev/gvisor/pkg/tcpip/transport/tcpconntrack" 24 ) 25 26 // connected creates a connection tracker TCB and sets it to a connected state 27 // by performing a 3-way handshake. 28 func connected(t *testing.T, iss, irs uint32, isw, irw uint16) *tcpconntrack.TCB { 29 // Send SYN. 30 tcp := make(header.TCP, header.TCPMinimumSize) 31 tcp.Encode(&header.TCPFields{ 32 SeqNum: iss, 33 AckNum: 0, 34 DataOffset: header.TCPMinimumSize, 35 Flags: header.TCPFlagSyn, 36 WindowSize: irw, 37 }) 38 39 tcb := tcpconntrack.TCB{} 40 tcb.Init(tcp, dataLen(tcp)) 41 42 // Receive SYN-ACK. 43 tcp.Encode(&header.TCPFields{ 44 SeqNum: irs, 45 AckNum: iss + 1, 46 DataOffset: header.TCPMinimumSize, 47 Flags: header.TCPFlagSyn | header.TCPFlagAck, 48 WindowSize: isw, 49 }) 50 51 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 52 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 53 } 54 55 // Send ACK. 56 tcp.Encode(&header.TCPFields{ 57 SeqNum: iss + 1, 58 AckNum: irs + 1, 59 DataOffset: header.TCPMinimumSize, 60 Flags: header.TCPFlagAck, 61 WindowSize: irw, 62 }) 63 64 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 65 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 66 } 67 68 return &tcb 69 } 70 71 func TestConnectionRefused(t *testing.T) { 72 // Send SYN. 73 tcp := make(header.TCP, header.TCPMinimumSize) 74 tcp.Encode(&header.TCPFields{ 75 SeqNum: 1234, 76 AckNum: 0, 77 DataOffset: header.TCPMinimumSize, 78 Flags: header.TCPFlagSyn, 79 WindowSize: 30000, 80 }) 81 82 tcb := tcpconntrack.TCB{} 83 tcb.Init(tcp, dataLen(tcp)) 84 85 // Receive RST. 86 tcp.Encode(&header.TCPFields{ 87 SeqNum: 789, 88 AckNum: 1235, 89 DataOffset: header.TCPMinimumSize, 90 Flags: header.TCPFlagRst | header.TCPFlagAck, 91 WindowSize: 50000, 92 }) 93 94 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultReset { 95 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultReset) 96 } 97 } 98 99 func TestConnectionRefusedInSynRcvd(t *testing.T) { 100 // Send SYN. 101 tcp := make(header.TCP, header.TCPMinimumSize) 102 tcp.Encode(&header.TCPFields{ 103 SeqNum: 1234, 104 AckNum: 0, 105 DataOffset: header.TCPMinimumSize, 106 Flags: header.TCPFlagSyn, 107 WindowSize: 30000, 108 }) 109 110 tcb := tcpconntrack.TCB{} 111 tcb.Init(tcp, dataLen(tcp)) 112 113 // Receive SYN. 114 tcp.Encode(&header.TCPFields{ 115 SeqNum: 789, 116 AckNum: 0, 117 DataOffset: header.TCPMinimumSize, 118 Flags: header.TCPFlagSyn, 119 WindowSize: 50000, 120 }) 121 122 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 123 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 124 } 125 126 // Receive RST with no ACK. 127 tcp.Encode(&header.TCPFields{ 128 SeqNum: 790, 129 AckNum: 0, 130 DataOffset: header.TCPMinimumSize, 131 Flags: header.TCPFlagRst, 132 WindowSize: 50000, 133 }) 134 135 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultReset { 136 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultReset) 137 } 138 } 139 140 func TestConnectionResetInSynRcvd(t *testing.T) { 141 // Send SYN. 142 tcp := make(header.TCP, header.TCPMinimumSize) 143 tcp.Encode(&header.TCPFields{ 144 SeqNum: 1234, 145 AckNum: 0, 146 DataOffset: header.TCPMinimumSize, 147 Flags: header.TCPFlagSyn, 148 WindowSize: 30000, 149 }) 150 151 tcb := tcpconntrack.TCB{} 152 tcb.Init(tcp, dataLen(tcp)) 153 154 // Receive SYN. 155 tcp.Encode(&header.TCPFields{ 156 SeqNum: 789, 157 AckNum: 0, 158 DataOffset: header.TCPMinimumSize, 159 Flags: header.TCPFlagSyn, 160 WindowSize: 50000, 161 }) 162 163 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 164 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 165 } 166 167 // Send RST with no ACK. 168 tcp.Encode(&header.TCPFields{ 169 SeqNum: 1235, 170 AckNum: 0, 171 DataOffset: header.TCPMinimumSize, 172 Flags: header.TCPFlagRst, 173 }) 174 175 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultReset { 176 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultReset) 177 } 178 } 179 180 func TestRetransmitOnSynSent(t *testing.T) { 181 // Send initial SYN. 182 tcp := make(header.TCP, header.TCPMinimumSize) 183 tcp.Encode(&header.TCPFields{ 184 SeqNum: 1234, 185 AckNum: 0, 186 DataOffset: header.TCPMinimumSize, 187 Flags: header.TCPFlagSyn, 188 WindowSize: 30000, 189 }) 190 191 tcb := tcpconntrack.TCB{} 192 tcb.Init(tcp, dataLen(tcp)) 193 194 // Retransmit the same SYN. 195 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultConnecting { 196 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultConnecting) 197 } 198 } 199 200 func TestRetransmitOnSynRcvd(t *testing.T) { 201 // Send initial SYN. 202 tcp := make(header.TCP, header.TCPMinimumSize) 203 tcp.Encode(&header.TCPFields{ 204 SeqNum: 1234, 205 AckNum: 0, 206 DataOffset: header.TCPMinimumSize, 207 Flags: header.TCPFlagSyn, 208 WindowSize: 30000, 209 }) 210 211 tcb := tcpconntrack.TCB{} 212 tcb.Init(tcp, dataLen(tcp)) 213 214 // Receive SYN. This will cause the state to go to SYN-RCVD. 215 tcp.Encode(&header.TCPFields{ 216 SeqNum: 789, 217 AckNum: 0, 218 DataOffset: header.TCPMinimumSize, 219 Flags: header.TCPFlagSyn, 220 WindowSize: 50000, 221 }) 222 223 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 224 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 225 } 226 227 // Retransmit the original SYN. 228 tcp.Encode(&header.TCPFields{ 229 SeqNum: 1234, 230 AckNum: 0, 231 DataOffset: header.TCPMinimumSize, 232 Flags: header.TCPFlagSyn, 233 WindowSize: 30000, 234 }) 235 236 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 237 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 238 } 239 240 // Transmit a SYN-ACK. 241 tcp.Encode(&header.TCPFields{ 242 SeqNum: 1234, 243 AckNum: 790, 244 DataOffset: header.TCPMinimumSize, 245 Flags: header.TCPFlagSyn | header.TCPFlagAck, 246 WindowSize: 30000, 247 }) 248 249 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 250 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 251 } 252 } 253 254 func TestClosedByOriginator(t *testing.T) { 255 tcb := connected(t, 1234, 789, 30000, 50000) 256 257 // Send FIN. 258 tcp := make(header.TCP, header.TCPMinimumSize) 259 tcp.Encode(&header.TCPFields{ 260 SeqNum: 1235, 261 AckNum: 790, 262 DataOffset: header.TCPMinimumSize, 263 Flags: header.TCPFlagAck | header.TCPFlagFin, 264 WindowSize: 30000, 265 }) 266 267 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 268 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 269 } 270 271 // Receive FIN/ACK. 272 tcp.Encode(&header.TCPFields{ 273 SeqNum: 790, 274 AckNum: 1236, 275 DataOffset: header.TCPMinimumSize, 276 Flags: header.TCPFlagAck | header.TCPFlagFin, 277 WindowSize: 50000, 278 }) 279 280 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 281 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 282 } 283 284 // Send ACK. 285 tcp.Encode(&header.TCPFields{ 286 SeqNum: 1236, 287 AckNum: 791, 288 DataOffset: header.TCPMinimumSize, 289 Flags: header.TCPFlagAck, 290 WindowSize: 30000, 291 }) 292 293 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultClosedByOriginator { 294 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultClosedByOriginator) 295 } 296 } 297 298 func TestClosedByResponder(t *testing.T) { 299 tcb := connected(t, 1234, 789, 30000, 50000) 300 301 // Receive FIN. 302 tcp := make(header.TCP, header.TCPMinimumSize) 303 tcp.Encode(&header.TCPFields{ 304 SeqNum: 790, 305 AckNum: 1235, 306 DataOffset: header.TCPMinimumSize, 307 Flags: header.TCPFlagAck | header.TCPFlagFin, 308 WindowSize: 50000, 309 }) 310 311 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 312 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 313 } 314 315 // Send FIN/ACK. 316 tcp.Encode(&header.TCPFields{ 317 SeqNum: 1235, 318 AckNum: 791, 319 DataOffset: header.TCPMinimumSize, 320 Flags: header.TCPFlagAck | header.TCPFlagFin, 321 WindowSize: 30000, 322 }) 323 324 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 325 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 326 } 327 328 // Receive ACK. 329 tcp.Encode(&header.TCPFields{ 330 SeqNum: 791, 331 AckNum: 1236, 332 DataOffset: header.TCPMinimumSize, 333 Flags: header.TCPFlagAck, 334 WindowSize: 50000, 335 }) 336 337 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultClosedByResponder { 338 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultClosedByResponder) 339 } 340 } 341 342 func TestSendAndReceiveDataClosedByOriginator(t *testing.T) { 343 sseq := uint32(1234) 344 rseq := uint32(789) 345 tcb := connected(t, sseq, rseq, 30000, 50000) 346 sseq++ 347 rseq++ 348 349 // Send some data. 350 tcp := make(header.TCP, header.TCPMinimumSize+1024) 351 352 for i := uint32(0); i < 10; i++ { 353 // Send some data. 354 tcp.Encode(&header.TCPFields{ 355 SeqNum: sseq, 356 AckNum: rseq, 357 DataOffset: header.TCPMinimumSize, 358 Flags: header.TCPFlagAck, 359 WindowSize: 30000, 360 }) 361 sseq += uint32(dataLen(tcp)) - header.TCPMinimumSize 362 363 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 364 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 365 } 366 367 // Receive ack for data. 368 tcp.Encode(&header.TCPFields{ 369 SeqNum: rseq, 370 AckNum: sseq, 371 DataOffset: header.TCPMinimumSize, 372 Flags: header.TCPFlagAck, 373 WindowSize: 50000, 374 }) 375 376 if r := tcb.UpdateStateReply(tcp[:header.TCPMinimumSize], dataLen(tcp)); r != tcpconntrack.ResultAlive { 377 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 378 } 379 } 380 381 for i := uint32(0); i < 10; i++ { 382 // Receive some data. 383 tcp.Encode(&header.TCPFields{ 384 SeqNum: rseq, 385 AckNum: sseq, 386 DataOffset: header.TCPMinimumSize, 387 Flags: header.TCPFlagAck, 388 WindowSize: 50000, 389 }) 390 rseq += uint32(dataLen(tcp)) 391 392 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 393 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 394 } 395 396 // Send ack for data. 397 tcp.Encode(&header.TCPFields{ 398 SeqNum: sseq, 399 AckNum: rseq, 400 DataOffset: header.TCPMinimumSize, 401 Flags: header.TCPFlagAck, 402 WindowSize: 30000, 403 }) 404 405 if r := tcb.UpdateStateOriginal(tcp[:header.TCPMinimumSize], dataLen(tcp)); r != tcpconntrack.ResultAlive { 406 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 407 } 408 } 409 410 // Send FIN. 411 tcp = tcp[:header.TCPMinimumSize] 412 tcp.Encode(&header.TCPFields{ 413 SeqNum: sseq, 414 AckNum: rseq, 415 DataOffset: header.TCPMinimumSize, 416 Flags: header.TCPFlagAck | header.TCPFlagFin, 417 WindowSize: 30000, 418 }) 419 sseq++ 420 421 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 422 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 423 } 424 425 // Receive FIN/ACK. 426 tcp.Encode(&header.TCPFields{ 427 SeqNum: rseq, 428 AckNum: sseq, 429 DataOffset: header.TCPMinimumSize, 430 Flags: header.TCPFlagAck | header.TCPFlagFin, 431 WindowSize: 50000, 432 }) 433 rseq++ 434 435 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 436 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 437 } 438 439 // Send ACK. 440 tcp.Encode(&header.TCPFields{ 441 SeqNum: sseq, 442 AckNum: rseq, 443 DataOffset: header.TCPMinimumSize, 444 Flags: header.TCPFlagAck, 445 WindowSize: 30000, 446 }) 447 448 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultClosedByOriginator { 449 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultClosedByOriginator) 450 } 451 } 452 453 func TestIgnoreBadResetOnSynSent(t *testing.T) { 454 // Send SYN. 455 tcp := make(header.TCP, header.TCPMinimumSize) 456 tcp.Encode(&header.TCPFields{ 457 SeqNum: 1234, 458 AckNum: 0, 459 DataOffset: header.TCPMinimumSize, 460 Flags: header.TCPFlagSyn, 461 WindowSize: 30000, 462 }) 463 464 tcb := tcpconntrack.TCB{} 465 tcb.Init(tcp, dataLen(tcp)) 466 467 // Receive a RST with a bad ACK, it should not cause the connection to 468 // be reset. 469 acks := []uint32{1234, 1236, 1000, 5000} 470 flags := []header.TCPFlags{header.TCPFlagRst, header.TCPFlagRst | header.TCPFlagAck} 471 for _, a := range acks { 472 for _, f := range flags { 473 tcp.Encode(&header.TCPFields{ 474 SeqNum: 789, 475 AckNum: a, 476 DataOffset: header.TCPMinimumSize, 477 Flags: f, 478 WindowSize: 50000, 479 }) 480 481 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultConnecting { 482 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 483 } 484 } 485 } 486 487 // Complete the handshake. 488 // Receive SYN-ACK. 489 tcp.Encode(&header.TCPFields{ 490 SeqNum: 789, 491 AckNum: 1235, 492 DataOffset: header.TCPMinimumSize, 493 Flags: header.TCPFlagSyn | header.TCPFlagAck, 494 WindowSize: 50000, 495 }) 496 497 if r := tcb.UpdateStateReply(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 498 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 499 } 500 501 // Send ACK. 502 tcp.Encode(&header.TCPFields{ 503 SeqNum: 1235, 504 AckNum: 790, 505 DataOffset: header.TCPMinimumSize, 506 Flags: header.TCPFlagAck, 507 WindowSize: 30000, 508 }) 509 510 if r := tcb.UpdateStateOriginal(tcp, dataLen(tcp)); r != tcpconntrack.ResultAlive { 511 t.Fatalf("Bad result: got %v, want %v", r, tcpconntrack.ResultAlive) 512 } 513 } 514 515 // dataLen returns the length of the TCP payload assuming that both the header 516 // and payload are in tcp. 517 func dataLen(tcp header.TCP) int { 518 return len(tcp) - int(tcp.DataOffset()) 519 } 520 521 func TestMain(m *testing.M) { 522 refs.SetLeakMode(refs.LeaksPanic) 523 code := m.Run() 524 refs.DoLeakCheck() 525 os.Exit(code) 526 }