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