github.com/flowerwrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/transport/tcp/testing/context/context.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 context provides a test context for use in tcp tests. It also 16 // provides helper methods to assert/check certain behaviours. 17 package context 18 19 import ( 20 "bytes" 21 "testing" 22 "time" 23 24 "github.com/FlowerWrong/netstack/tcpip" 25 "github.com/FlowerWrong/netstack/tcpip/buffer" 26 "github.com/FlowerWrong/netstack/tcpip/checker" 27 "github.com/FlowerWrong/netstack/tcpip/header" 28 "github.com/FlowerWrong/netstack/tcpip/link/channel" 29 "github.com/FlowerWrong/netstack/tcpip/link/sniffer" 30 "github.com/FlowerWrong/netstack/tcpip/network/ipv4" 31 "github.com/FlowerWrong/netstack/tcpip/network/ipv6" 32 "github.com/FlowerWrong/netstack/tcpip/seqnum" 33 "github.com/FlowerWrong/netstack/tcpip/stack" 34 "github.com/FlowerWrong/netstack/tcpip/transport/tcp" 35 "github.com/FlowerWrong/netstack/waiter" 36 ) 37 38 const ( 39 // StackAddr is the IPv4 address assigned to the stack. 40 StackAddr = "\x0a\x00\x00\x01" 41 42 // StackPort is used as the listening port in tests for passive 43 // connects. 44 StackPort = 1234 45 46 // TestAddr is the source address for packets sent to the stack via the 47 // link layer endpoint. 48 TestAddr = "\x0a\x00\x00\x02" 49 50 // TestPort is the TCP port used for packets sent to the stack 51 // via the link layer endpoint. 52 TestPort = 4096 53 54 // StackV6Addr is the IPv6 address assigned to the stack. 55 StackV6Addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" 56 57 // TestV6Addr is the source address for packets sent to the stack via 58 // the link layer endpoint. 59 TestV6Addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" 60 61 // StackV4MappedAddr is StackAddr as a mapped v6 address. 62 StackV4MappedAddr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + StackAddr 63 64 // TestV4MappedAddr is TestAddr as a mapped v6 address. 65 TestV4MappedAddr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff" + TestAddr 66 67 // V4MappedWildcardAddr is the mapped v6 representation of 0.0.0.0. 68 V4MappedWildcardAddr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00" 69 70 // testInitialSequenceNumber is the initial sequence number sent in packets that 71 // are sent in response to a SYN or in the initial SYN sent to the stack. 72 testInitialSequenceNumber = 789 73 ) 74 75 // Headers is used to represent the TCP header fields when building a 76 // new packet. 77 type Headers struct { 78 // SrcPort holds the src port value to be used in the packet. 79 SrcPort uint16 80 81 // DstPort holds the destination port value to be used in the packet. 82 DstPort uint16 83 84 // SeqNum is the value of the sequence number field in the TCP header. 85 SeqNum seqnum.Value 86 87 // AckNum represents the acknowledgement number field in the TCP header. 88 AckNum seqnum.Value 89 90 // Flags are the TCP flags in the TCP header. 91 Flags int 92 93 // RcvWnd is the window to be advertised in the ReceiveWindow field of 94 // the TCP header. 95 RcvWnd seqnum.Size 96 97 // TCPOpts holds the options to be sent in the option field of the TCP 98 // header. 99 TCPOpts []byte 100 } 101 102 // Context provides an initialized Network stack and a link layer endpoint 103 // for use in TCP tests. 104 type Context struct { 105 t *testing.T 106 linkEP *channel.Endpoint 107 s *stack.Stack 108 109 // IRS holds the initial sequence number in the SYN sent by endpoint in 110 // case of an active connect or the sequence number sent by the endpoint 111 // in the SYN-ACK sent in response to a SYN when listening in passive 112 // mode. 113 IRS seqnum.Value 114 115 // Port holds the port bound by EP below in case of an active connect or 116 // the listening port number in case of a passive connect. 117 Port uint16 118 119 // EP is the test endpoint in the stack owned by this context. This endpoint 120 // is used in various tests to either initiate an active connect or is used 121 // as a passive listening endpoint to accept inbound connections. 122 EP tcpip.Endpoint 123 124 // Wq is the wait queue associated with EP and is used to block for events 125 // on EP. 126 WQ waiter.Queue 127 128 // TimeStampEnabled is true if ep is connected with the timestamp option 129 // enabled. 130 TimeStampEnabled bool 131 132 // WindowScale is the expected window scale in SYN packets sent by 133 // the stack. 134 WindowScale uint8 135 } 136 137 // New allocates and initializes a test context containing a new 138 // stack and a link-layer endpoint. 139 func New(t *testing.T, mtu uint32) *Context { 140 s := stack.New(stack.Options{ 141 NetworkProtocols: []stack.NetworkProtocol{ipv4.NewProtocol(), ipv6.NewProtocol()}, 142 TransportProtocols: []stack.TransportProtocol{tcp.NewProtocol()}, 143 }) 144 145 // Allow minimum send/receive buffer sizes to be 1 during tests. 146 if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SendBufferSizeOption{1, tcp.DefaultSendBufferSize, 10 * tcp.DefaultSendBufferSize}); err != nil { 147 t.Fatalf("SetTransportProtocolOption failed: %v", err) 148 } 149 150 if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.ReceiveBufferSizeOption{1, tcp.DefaultReceiveBufferSize, 10 * tcp.DefaultReceiveBufferSize}); err != nil { 151 t.Fatalf("SetTransportProtocolOption failed: %v", err) 152 } 153 154 // Some of the congestion control tests send up to 640 packets, we so 155 // set the channel size to 1000. 156 ep := channel.New(1000, mtu, "") 157 wep := stack.LinkEndpoint(ep) 158 if testing.Verbose() { 159 wep = sniffer.New(ep) 160 } 161 if err := s.CreateNamedNIC(1, "nic1", wep); err != nil { 162 t.Fatalf("CreateNIC failed: %v", err) 163 } 164 wep2 := stack.LinkEndpoint(channel.New(1000, mtu, "")) 165 if testing.Verbose() { 166 wep2 = sniffer.New(channel.New(1000, mtu, "")) 167 } 168 if err := s.CreateNamedNIC(2, "nic2", wep2); err != nil { 169 t.Fatalf("CreateNIC failed: %v", err) 170 } 171 172 if err := s.AddAddress(1, ipv4.ProtocolNumber, StackAddr); err != nil { 173 t.Fatalf("AddAddress failed: %v", err) 174 } 175 176 if err := s.AddAddress(1, ipv6.ProtocolNumber, StackV6Addr); err != nil { 177 t.Fatalf("AddAddress failed: %v", err) 178 } 179 180 s.SetRouteTable([]tcpip.Route{ 181 { 182 Destination: header.IPv4EmptySubnet, 183 NIC: 1, 184 }, 185 { 186 Destination: header.IPv6EmptySubnet, 187 NIC: 1, 188 }, 189 }) 190 191 return &Context{ 192 t: t, 193 s: s, 194 linkEP: ep, 195 WindowScale: uint8(tcp.FindWndScale(tcp.DefaultReceiveBufferSize)), 196 } 197 } 198 199 // Cleanup closes the context endpoint if required. 200 func (c *Context) Cleanup() { 201 if c.EP != nil { 202 c.EP.Close() 203 } 204 } 205 206 // Stack returns a reference to the stack in the Context. 207 func (c *Context) Stack() *stack.Stack { 208 return c.s 209 } 210 211 // CheckNoPacketTimeout verifies that no packet is received during the time 212 // specified by wait. 213 func (c *Context) CheckNoPacketTimeout(errMsg string, wait time.Duration) { 214 c.t.Helper() 215 216 select { 217 case <-c.linkEP.C: 218 c.t.Fatal(errMsg) 219 220 case <-time.After(wait): 221 } 222 } 223 224 // CheckNoPacket verifies that no packet is received for 1 second. 225 func (c *Context) CheckNoPacket(errMsg string) { 226 c.CheckNoPacketTimeout(errMsg, 1*time.Second) 227 } 228 229 // GetPacket reads a packet from the link layer endpoint and verifies 230 // that it is an IPv4 packet with the expected source and destination 231 // addresses. It will fail with an error if no packet is received for 232 // 2 seconds. 233 func (c *Context) GetPacket() []byte { 234 select { 235 case p := <-c.linkEP.C: 236 if p.Proto != ipv4.ProtocolNumber { 237 c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv4.ProtocolNumber) 238 } 239 b := make([]byte, len(p.Header)+len(p.Payload)) 240 copy(b, p.Header) 241 copy(b[len(p.Header):], p.Payload) 242 243 if p.GSO != nil && p.GSO.L3HdrLen != header.IPv4MinimumSize { 244 c.t.Errorf("L3HdrLen %v (expected %v)", p.GSO.L3HdrLen, header.IPv4MinimumSize) 245 } 246 247 checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr)) 248 return b 249 250 case <-time.After(2 * time.Second): 251 c.t.Fatalf("Packet wasn't written out") 252 } 253 254 return nil 255 } 256 257 // GetPacketNonBlocking reads a packet from the link layer endpoint 258 // and verifies that it is an IPv4 packet with the expected source 259 // and destination address. If no packet is available it will return 260 // nil immediately. 261 func (c *Context) GetPacketNonBlocking() []byte { 262 select { 263 case p := <-c.linkEP.C: 264 if p.Proto != ipv4.ProtocolNumber { 265 c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv4.ProtocolNumber) 266 } 267 b := make([]byte, len(p.Header)+len(p.Payload)) 268 copy(b, p.Header) 269 copy(b[len(p.Header):], p.Payload) 270 271 checker.IPv4(c.t, b, checker.SrcAddr(StackAddr), checker.DstAddr(TestAddr)) 272 return b 273 default: 274 return nil 275 } 276 } 277 278 // SendICMPPacket builds and sends an ICMPv4 packet via the link layer endpoint. 279 func (c *Context) SendICMPPacket(typ header.ICMPv4Type, code uint8, p1, p2 []byte, maxTotalSize int) { 280 // Allocate a buffer data and headers. 281 buf := buffer.NewView(header.IPv4MinimumSize + header.ICMPv4PayloadOffset + len(p2)) 282 if len(buf) > maxTotalSize { 283 buf = buf[:maxTotalSize] 284 } 285 286 ip := header.IPv4(buf) 287 ip.Encode(&header.IPv4Fields{ 288 IHL: header.IPv4MinimumSize, 289 TotalLength: uint16(len(buf)), 290 TTL: 65, 291 Protocol: uint8(header.ICMPv4ProtocolNumber), 292 SrcAddr: TestAddr, 293 DstAddr: StackAddr, 294 }) 295 ip.SetChecksum(^ip.CalculateChecksum()) 296 297 icmp := header.ICMPv4(buf[header.IPv4MinimumSize:]) 298 icmp.SetType(typ) 299 icmp.SetCode(code) 300 const icmpv4VariableHeaderOffset = 4 301 copy(icmp[icmpv4VariableHeaderOffset:], p1) 302 copy(icmp[header.ICMPv4PayloadOffset:], p2) 303 304 // Inject packet. 305 c.linkEP.Inject(ipv4.ProtocolNumber, buf.ToVectorisedView()) 306 } 307 308 // BuildSegment builds a TCP segment based on the given Headers and payload. 309 func (c *Context) BuildSegment(payload []byte, h *Headers) buffer.VectorisedView { 310 // Allocate a buffer for data and headers. 311 buf := buffer.NewView(header.TCPMinimumSize + header.IPv4MinimumSize + len(h.TCPOpts) + len(payload)) 312 copy(buf[len(buf)-len(payload):], payload) 313 copy(buf[len(buf)-len(payload)-len(h.TCPOpts):], h.TCPOpts) 314 315 // Initialize the IP header. 316 ip := header.IPv4(buf) 317 ip.Encode(&header.IPv4Fields{ 318 IHL: header.IPv4MinimumSize, 319 TotalLength: uint16(len(buf)), 320 TTL: 65, 321 Protocol: uint8(tcp.ProtocolNumber), 322 SrcAddr: TestAddr, 323 DstAddr: StackAddr, 324 }) 325 ip.SetChecksum(^ip.CalculateChecksum()) 326 327 // Initialize the TCP header. 328 t := header.TCP(buf[header.IPv4MinimumSize:]) 329 t.Encode(&header.TCPFields{ 330 SrcPort: h.SrcPort, 331 DstPort: h.DstPort, 332 SeqNum: uint32(h.SeqNum), 333 AckNum: uint32(h.AckNum), 334 DataOffset: uint8(header.TCPMinimumSize + len(h.TCPOpts)), 335 Flags: uint8(h.Flags), 336 WindowSize: uint16(h.RcvWnd), 337 }) 338 339 // Calculate the TCP pseudo-header checksum. 340 xsum := header.PseudoHeaderChecksum(tcp.ProtocolNumber, TestAddr, StackAddr, uint16(len(t))) 341 342 // Calculate the TCP checksum and set it. 343 xsum = header.Checksum(payload, xsum) 344 t.SetChecksum(^t.CalculateChecksum(xsum)) 345 346 // Inject packet. 347 return buf.ToVectorisedView() 348 } 349 350 // SendSegment sends a TCP segment that has already been built and written to a 351 // buffer.VectorisedView. 352 func (c *Context) SendSegment(s buffer.VectorisedView) { 353 c.linkEP.Inject(ipv4.ProtocolNumber, s) 354 } 355 356 // SendPacket builds and sends a TCP segment(with the provided payload & TCP 357 // headers) in an IPv4 packet via the link layer endpoint. 358 func (c *Context) SendPacket(payload []byte, h *Headers) { 359 c.linkEP.Inject(ipv4.ProtocolNumber, c.BuildSegment(payload, h)) 360 } 361 362 // SendAck sends an ACK packet. 363 func (c *Context) SendAck(seq seqnum.Value, bytesReceived int) { 364 c.SendAckWithSACK(seq, bytesReceived, nil) 365 } 366 367 // SendAckWithSACK sends an ACK packet which includes the sackBlocks specified. 368 func (c *Context) SendAckWithSACK(seq seqnum.Value, bytesReceived int, sackBlocks []header.SACKBlock) { 369 options := make([]byte, 40) 370 offset := 0 371 if len(sackBlocks) > 0 { 372 offset += header.EncodeNOP(options[offset:]) 373 offset += header.EncodeNOP(options[offset:]) 374 offset += header.EncodeSACKBlocks(sackBlocks, options[offset:]) 375 } 376 377 c.SendPacket(nil, &Headers{ 378 SrcPort: TestPort, 379 DstPort: c.Port, 380 Flags: header.TCPFlagAck, 381 SeqNum: seq, 382 AckNum: c.IRS.Add(1 + seqnum.Size(bytesReceived)), 383 RcvWnd: 30000, 384 TCPOpts: options[:offset], 385 }) 386 } 387 388 // ReceiveAndCheckPacket reads a packet from the link layer endpoint and 389 // verifies that the packet packet payload of packet matches the slice 390 // of data indicated by offset & size. 391 func (c *Context) ReceiveAndCheckPacket(data []byte, offset, size int) { 392 c.ReceiveAndCheckPacketWithOptions(data, offset, size, 0) 393 } 394 395 // ReceiveAndCheckPacketWithOptions reads a packet from the link layer endpoint 396 // and verifies that the packet packet payload of packet matches the slice of 397 // data indicated by offset & size and skips optlen bytes in addition to the IP 398 // TCP headers when comparing the data. 399 func (c *Context) ReceiveAndCheckPacketWithOptions(data []byte, offset, size, optlen int) { 400 b := c.GetPacket() 401 checker.IPv4(c.t, b, 402 checker.PayloadLen(size+header.TCPMinimumSize+optlen), 403 checker.TCP( 404 checker.DstPort(TestPort), 405 checker.SeqNum(uint32(c.IRS.Add(seqnum.Size(1+offset)))), 406 checker.AckNum(uint32(seqnum.Value(testInitialSequenceNumber).Add(1))), 407 checker.TCPFlagsMatch(header.TCPFlagAck, ^uint8(header.TCPFlagPsh)), 408 ), 409 ) 410 411 pdata := data[offset:][:size] 412 if p := b[header.IPv4MinimumSize+header.TCPMinimumSize+optlen:]; bytes.Compare(pdata, p) != 0 { 413 c.t.Fatalf("Data is different: expected %v, got %v", pdata, p) 414 } 415 } 416 417 // ReceiveNonBlockingAndCheckPacket reads a packet from the link layer endpoint 418 // and verifies that the packet packet payload of packet matches the slice of 419 // data indicated by offset & size. It returns true if a packet was received and 420 // processed. 421 func (c *Context) ReceiveNonBlockingAndCheckPacket(data []byte, offset, size int) bool { 422 b := c.GetPacketNonBlocking() 423 if b == nil { 424 return false 425 } 426 checker.IPv4(c.t, b, 427 checker.PayloadLen(size+header.TCPMinimumSize), 428 checker.TCP( 429 checker.DstPort(TestPort), 430 checker.SeqNum(uint32(c.IRS.Add(seqnum.Size(1+offset)))), 431 checker.AckNum(uint32(seqnum.Value(testInitialSequenceNumber).Add(1))), 432 checker.TCPFlagsMatch(header.TCPFlagAck, ^uint8(header.TCPFlagPsh)), 433 ), 434 ) 435 436 pdata := data[offset:][:size] 437 if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; bytes.Compare(pdata, p) != 0 { 438 c.t.Fatalf("Data is different: expected %v, got %v", pdata, p) 439 } 440 return true 441 } 442 443 // CreateV6Endpoint creates and initializes c.ep as a IPv6 Endpoint. If v6Only 444 // is true then it sets the IP_V6ONLY option on the socket to make it a IPv6 445 // only endpoint instead of a default dual stack socket. 446 func (c *Context) CreateV6Endpoint(v6only bool) { 447 var err *tcpip.Error 448 c.EP, err = c.s.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &c.WQ) 449 if err != nil { 450 c.t.Fatalf("NewEndpoint failed: %v", err) 451 } 452 453 var v tcpip.V6OnlyOption 454 if v6only { 455 v = 1 456 } 457 if err := c.EP.SetSockOpt(v); err != nil { 458 c.t.Fatalf("SetSockOpt failed failed: %v", err) 459 } 460 } 461 462 // GetV6Packet reads a single packet from the link layer endpoint of the context 463 // and asserts that it is an IPv6 Packet with the expected src/dest addresses. 464 func (c *Context) GetV6Packet() []byte { 465 select { 466 case p := <-c.linkEP.C: 467 if p.Proto != ipv6.ProtocolNumber { 468 c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv6.ProtocolNumber) 469 } 470 b := make([]byte, len(p.Header)+len(p.Payload)) 471 copy(b, p.Header) 472 copy(b[len(p.Header):], p.Payload) 473 474 checker.IPv6(c.t, b, checker.SrcAddr(StackV6Addr), checker.DstAddr(TestV6Addr)) 475 return b 476 477 case <-time.After(2 * time.Second): 478 c.t.Fatalf("Packet wasn't written out") 479 } 480 481 return nil 482 } 483 484 // SendV6Packet builds and sends an IPv6 Packet via the link layer endpoint of 485 // the context. 486 func (c *Context) SendV6Packet(payload []byte, h *Headers) { 487 // Allocate a buffer for data and headers. 488 buf := buffer.NewView(header.TCPMinimumSize + header.IPv6MinimumSize + len(payload)) 489 copy(buf[len(buf)-len(payload):], payload) 490 491 // Initialize the IP header. 492 ip := header.IPv6(buf) 493 ip.Encode(&header.IPv6Fields{ 494 PayloadLength: uint16(header.TCPMinimumSize + len(payload)), 495 NextHeader: uint8(tcp.ProtocolNumber), 496 HopLimit: 65, 497 SrcAddr: TestV6Addr, 498 DstAddr: StackV6Addr, 499 }) 500 501 // Initialize the TCP header. 502 t := header.TCP(buf[header.IPv6MinimumSize:]) 503 t.Encode(&header.TCPFields{ 504 SrcPort: h.SrcPort, 505 DstPort: h.DstPort, 506 SeqNum: uint32(h.SeqNum), 507 AckNum: uint32(h.AckNum), 508 DataOffset: header.TCPMinimumSize, 509 Flags: uint8(h.Flags), 510 WindowSize: uint16(h.RcvWnd), 511 }) 512 513 // Calculate the TCP pseudo-header checksum. 514 xsum := header.PseudoHeaderChecksum(tcp.ProtocolNumber, TestV6Addr, StackV6Addr, uint16(len(t))) 515 516 // Calculate the TCP checksum and set it. 517 xsum = header.Checksum(payload, xsum) 518 t.SetChecksum(^t.CalculateChecksum(xsum)) 519 520 // Inject packet. 521 c.linkEP.Inject(ipv6.ProtocolNumber, buf.ToVectorisedView()) 522 } 523 524 // CreateConnected creates a connected TCP endpoint. 525 func (c *Context) CreateConnected(iss seqnum.Value, rcvWnd seqnum.Size, epRcvBuf int) { 526 c.CreateConnectedWithRawOptions(iss, rcvWnd, epRcvBuf, nil) 527 } 528 529 // Connect performs the 3-way handshake for c.EP with the provided Initial 530 // Sequence Number (iss) and receive window(rcvWnd) and any options if 531 // specified. 532 // 533 // It also sets the receive buffer for the endpoint to the specified 534 // value in epRcvBuf. 535 // 536 // PreCondition: c.EP must already be created. 537 func (c *Context) Connect(iss seqnum.Value, rcvWnd seqnum.Size, options []byte) { 538 // Start connection attempt. 539 waitEntry, notifyCh := waiter.NewChannelEntry(nil) 540 c.WQ.EventRegister(&waitEntry, waiter.EventOut) 541 defer c.WQ.EventUnregister(&waitEntry) 542 543 if err := c.EP.Connect(tcpip.FullAddress{Addr: TestAddr, Port: TestPort}); err != tcpip.ErrConnectStarted { 544 c.t.Fatalf("Unexpected return value from Connect: %v", err) 545 } 546 547 // Receive SYN packet. 548 b := c.GetPacket() 549 checker.IPv4(c.t, b, 550 checker.TCP( 551 checker.DstPort(TestPort), 552 checker.TCPFlags(header.TCPFlagSyn), 553 ), 554 ) 555 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateSynSent; got != want { 556 c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) 557 } 558 559 tcpHdr := header.TCP(header.IPv4(b).Payload()) 560 c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) 561 562 c.SendPacket(nil, &Headers{ 563 SrcPort: tcpHdr.DestinationPort(), 564 DstPort: tcpHdr.SourcePort(), 565 Flags: header.TCPFlagSyn | header.TCPFlagAck, 566 SeqNum: iss, 567 AckNum: c.IRS.Add(1), 568 RcvWnd: rcvWnd, 569 TCPOpts: options, 570 }) 571 572 // Receive ACK packet. 573 checker.IPv4(c.t, c.GetPacket(), 574 checker.TCP( 575 checker.DstPort(TestPort), 576 checker.TCPFlags(header.TCPFlagAck), 577 checker.SeqNum(uint32(c.IRS)+1), 578 checker.AckNum(uint32(iss)+1), 579 ), 580 ) 581 582 // Wait for connection to be established. 583 select { 584 case <-notifyCh: 585 if err := c.EP.GetSockOpt(tcpip.ErrorOption{}); err != nil { 586 c.t.Fatalf("Unexpected error when connecting: %v", err) 587 } 588 case <-time.After(1 * time.Second): 589 c.t.Fatalf("Timed out waiting for connection") 590 } 591 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateEstablished; got != want { 592 c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) 593 } 594 595 c.Port = tcpHdr.SourcePort() 596 } 597 598 // Create creates a TCP endpoint. 599 func (c *Context) Create(epRcvBuf int) { 600 // Create TCP endpoint. 601 var err *tcpip.Error 602 c.EP, err = c.s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &c.WQ) 603 if err != nil { 604 c.t.Fatalf("NewEndpoint failed: %v", err) 605 } 606 607 if epRcvBuf != -1 { 608 if err := c.EP.SetSockOptInt(tcpip.ReceiveBufferSizeOption, epRcvBuf); err != nil { 609 c.t.Fatalf("SetSockOpt failed failed: %v", err) 610 } 611 } 612 } 613 614 // CreateConnectedWithRawOptions creates a connected TCP endpoint and sends 615 // the specified option bytes as the Option field in the initial SYN packet. 616 // 617 // It also sets the receive buffer for the endpoint to the specified 618 // value in epRcvBuf. 619 func (c *Context) CreateConnectedWithRawOptions(iss seqnum.Value, rcvWnd seqnum.Size, epRcvBuf int, options []byte) { 620 c.Create(epRcvBuf) 621 c.Connect(iss, rcvWnd, options) 622 } 623 624 // RawEndpoint is just a small wrapper around a TCP endpoint's state to make 625 // sending data and ACK packets easy while being able to manipulate the sequence 626 // numbers and timestamp values as needed. 627 type RawEndpoint struct { 628 C *Context 629 SrcPort uint16 630 DstPort uint16 631 Flags int 632 NextSeqNum seqnum.Value 633 AckNum seqnum.Value 634 WndSize seqnum.Size 635 RecentTS uint32 // Stores the latest timestamp to echo back. 636 TSVal uint32 // TSVal stores the last timestamp sent by this endpoint. 637 638 // SackPermitted is true if SACKPermitted option was negotiated for this endpoint. 639 SACKPermitted bool 640 } 641 642 // SendPacketWithTS embeds the provided tsVal in the Timestamp option 643 // for the packet to be sent out. 644 func (r *RawEndpoint) SendPacketWithTS(payload []byte, tsVal uint32) { 645 r.TSVal = tsVal 646 tsOpt := [12]byte{header.TCPOptionNOP, header.TCPOptionNOP} 647 header.EncodeTSOption(r.TSVal, r.RecentTS, tsOpt[2:]) 648 r.SendPacket(payload, tsOpt[:]) 649 } 650 651 // SendPacket is a small wrapper function to build and send packets. 652 func (r *RawEndpoint) SendPacket(payload []byte, opts []byte) { 653 packetHeaders := &Headers{ 654 SrcPort: r.SrcPort, 655 DstPort: r.DstPort, 656 Flags: r.Flags, 657 SeqNum: r.NextSeqNum, 658 AckNum: r.AckNum, 659 RcvWnd: r.WndSize, 660 TCPOpts: opts, 661 } 662 r.C.SendPacket(payload, packetHeaders) 663 r.NextSeqNum = r.NextSeqNum.Add(seqnum.Size(len(payload))) 664 } 665 666 // VerifyACKWithTS verifies that the tsEcr field in the ack matches the provided 667 // tsVal. 668 func (r *RawEndpoint) VerifyACKWithTS(tsVal uint32) { 669 // Read ACK and verify that tsEcr of ACK packet is [1,2,3,4] 670 ackPacket := r.C.GetPacket() 671 checker.IPv4(r.C.t, ackPacket, 672 checker.TCP( 673 checker.DstPort(r.SrcPort), 674 checker.TCPFlags(header.TCPFlagAck), 675 checker.SeqNum(uint32(r.AckNum)), 676 checker.AckNum(uint32(r.NextSeqNum)), 677 checker.TCPTimestampChecker(true, 0, tsVal), 678 ), 679 ) 680 // Store the parsed TSVal from the ack as recentTS. 681 tcpSeg := header.TCP(header.IPv4(ackPacket).Payload()) 682 opts := tcpSeg.ParsedOptions() 683 r.RecentTS = opts.TSVal 684 } 685 686 // VerifyACKRcvWnd verifies that the window advertised by the incoming ACK 687 // matches the provided rcvWnd. 688 func (r *RawEndpoint) VerifyACKRcvWnd(rcvWnd uint16) { 689 ackPacket := r.C.GetPacket() 690 checker.IPv4(r.C.t, ackPacket, 691 checker.TCP( 692 checker.DstPort(r.SrcPort), 693 checker.TCPFlags(header.TCPFlagAck), 694 checker.SeqNum(uint32(r.AckNum)), 695 checker.AckNum(uint32(r.NextSeqNum)), 696 checker.Window(rcvWnd), 697 ), 698 ) 699 } 700 701 // VerifyACKNoSACK verifies that the ACK does not contain a SACK block. 702 func (r *RawEndpoint) VerifyACKNoSACK() { 703 r.VerifyACKHasSACK(nil) 704 } 705 706 // VerifyACKHasSACK verifies that the ACK contains the specified SACKBlocks. 707 func (r *RawEndpoint) VerifyACKHasSACK(sackBlocks []header.SACKBlock) { 708 // Read ACK and verify that the TCP options in the segment do 709 // not contain a SACK block. 710 ackPacket := r.C.GetPacket() 711 checker.IPv4(r.C.t, ackPacket, 712 checker.TCP( 713 checker.DstPort(r.SrcPort), 714 checker.TCPFlags(header.TCPFlagAck), 715 checker.SeqNum(uint32(r.AckNum)), 716 checker.AckNum(uint32(r.NextSeqNum)), 717 checker.TCPSACKBlockChecker(sackBlocks), 718 ), 719 ) 720 } 721 722 // CreateConnectedWithOptions creates and connects c.ep with the specified TCP 723 // options enabled and returns a RawEndpoint which represents the other end of 724 // the connection. 725 // 726 // It also verifies where required(eg.Timestamp) that the ACK to the SYN-ACK 727 // does not carry an option that was not requested. 728 func (c *Context) CreateConnectedWithOptions(wantOptions header.TCPSynOptions) *RawEndpoint { 729 var err *tcpip.Error 730 c.EP, err = c.s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &c.WQ) 731 if err != nil { 732 c.t.Fatalf("c.s.NewEndpoint(tcp, ipv4...) = %v", err) 733 } 734 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateInitial; got != want { 735 c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) 736 } 737 738 // Start connection attempt. 739 waitEntry, notifyCh := waiter.NewChannelEntry(nil) 740 c.WQ.EventRegister(&waitEntry, waiter.EventOut) 741 defer c.WQ.EventUnregister(&waitEntry) 742 743 testFullAddr := tcpip.FullAddress{Addr: TestAddr, Port: TestPort} 744 err = c.EP.Connect(testFullAddr) 745 if err != tcpip.ErrConnectStarted { 746 c.t.Fatalf("c.ep.Connect(%v) = %v", testFullAddr, err) 747 } 748 // Receive SYN packet. 749 b := c.GetPacket() 750 // Validate that the syn has the timestamp option and a valid 751 // TS value. 752 mss := uint16(c.linkEP.MTU() - header.IPv4MinimumSize - header.TCPMinimumSize) 753 754 checker.IPv4(c.t, b, 755 checker.TCP( 756 checker.DstPort(TestPort), 757 checker.TCPFlags(header.TCPFlagSyn), 758 checker.TCPSynOptions(header.TCPSynOptions{ 759 MSS: mss, 760 TS: true, 761 WS: int(c.WindowScale), 762 SACKPermitted: c.SACKEnabled(), 763 }), 764 ), 765 ) 766 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateSynSent; got != want { 767 c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) 768 } 769 770 tcpSeg := header.TCP(header.IPv4(b).Payload()) 771 synOptions := header.ParseSynOptions(tcpSeg.Options(), false) 772 773 // Build options w/ tsVal to be sent in the SYN-ACK. 774 synAckOptions := make([]byte, header.TCPOptionsMaximumSize) 775 offset := 0 776 if wantOptions.WS != -1 { 777 offset += header.EncodeWSOption(wantOptions.WS, synAckOptions[offset:]) 778 } 779 if wantOptions.TS { 780 offset += header.EncodeTSOption(wantOptions.TSVal, synOptions.TSVal, synAckOptions[offset:]) 781 } 782 if wantOptions.SACKPermitted { 783 offset += header.EncodeSACKPermittedOption(synAckOptions[offset:]) 784 } 785 786 offset += header.AddTCPOptionPadding(synAckOptions, offset) 787 788 // Build SYN-ACK. 789 c.IRS = seqnum.Value(tcpSeg.SequenceNumber()) 790 iss := seqnum.Value(testInitialSequenceNumber) 791 c.SendPacket(nil, &Headers{ 792 SrcPort: tcpSeg.DestinationPort(), 793 DstPort: tcpSeg.SourcePort(), 794 Flags: header.TCPFlagSyn | header.TCPFlagAck, 795 SeqNum: iss, 796 AckNum: c.IRS.Add(1), 797 RcvWnd: 30000, 798 TCPOpts: synAckOptions[:offset], 799 }) 800 801 // Read ACK. 802 ackPacket := c.GetPacket() 803 804 // Verify TCP header fields. 805 tcpCheckers := []checker.TransportChecker{ 806 checker.DstPort(TestPort), 807 checker.TCPFlags(header.TCPFlagAck), 808 checker.SeqNum(uint32(c.IRS) + 1), 809 checker.AckNum(uint32(iss) + 1), 810 } 811 812 // Verify that tsEcr of ACK packet is wantOptions.TSVal if the 813 // timestamp option was enabled, if not then we verify that 814 // there is no timestamp in the ACK packet. 815 if wantOptions.TS { 816 tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(true, 0, wantOptions.TSVal)) 817 } else { 818 tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(false, 0, 0)) 819 } 820 821 checker.IPv4(c.t, ackPacket, checker.TCP(tcpCheckers...)) 822 823 ackSeg := header.TCP(header.IPv4(ackPacket).Payload()) 824 ackOptions := ackSeg.ParsedOptions() 825 826 // Wait for connection to be established. 827 select { 828 case <-notifyCh: 829 err = c.EP.GetSockOpt(tcpip.ErrorOption{}) 830 if err != nil { 831 c.t.Fatalf("Unexpected error when connecting: %v", err) 832 } 833 case <-time.After(1 * time.Second): 834 c.t.Fatalf("Timed out waiting for connection") 835 } 836 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateEstablished; got != want { 837 c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) 838 } 839 840 // Store the source port in use by the endpoint. 841 c.Port = tcpSeg.SourcePort() 842 843 // Mark in context that timestamp option is enabled for this endpoint. 844 c.TimeStampEnabled = true 845 846 return &RawEndpoint{ 847 C: c, 848 SrcPort: tcpSeg.DestinationPort(), 849 DstPort: tcpSeg.SourcePort(), 850 Flags: header.TCPFlagAck | header.TCPFlagPsh, 851 NextSeqNum: iss + 1, 852 AckNum: c.IRS.Add(1), 853 WndSize: 30000, 854 RecentTS: ackOptions.TSVal, 855 TSVal: wantOptions.TSVal, 856 SACKPermitted: wantOptions.SACKPermitted, 857 } 858 } 859 860 // AcceptWithOptions initializes a listening endpoint and connects to it with the 861 // provided options enabled. It also verifies that the SYN-ACK has the expected 862 // values for the provided options. 863 // 864 // The function returns a RawEndpoint representing the other end of the accepted 865 // endpoint. 866 func (c *Context) AcceptWithOptions(wndScale int, synOptions header.TCPSynOptions) *RawEndpoint { 867 // Create EP and start listening. 868 wq := &waiter.Queue{} 869 ep, err := c.s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, wq) 870 if err != nil { 871 c.t.Fatalf("NewEndpoint failed: %v", err) 872 } 873 defer ep.Close() 874 875 if err := ep.Bind(tcpip.FullAddress{Port: StackPort}); err != nil { 876 c.t.Fatalf("Bind failed: %v", err) 877 } 878 if got, want := tcp.EndpointState(ep.State()), tcp.StateBound; got != want { 879 c.t.Errorf("Unexpected endpoint state: want %v, got %v", want, got) 880 } 881 882 if err := ep.Listen(10); err != nil { 883 c.t.Fatalf("Listen failed: %v", err) 884 } 885 if got, want := tcp.EndpointState(ep.State()), tcp.StateListen; got != want { 886 c.t.Errorf("Unexpected endpoint state: want %v, got %v", want, got) 887 } 888 889 rep := c.PassiveConnectWithOptions(100, wndScale, synOptions) 890 891 // Try to accept the connection. 892 we, ch := waiter.NewChannelEntry(nil) 893 wq.EventRegister(&we, waiter.EventIn) 894 defer wq.EventUnregister(&we) 895 896 c.EP, _, err = ep.Accept() 897 if err == tcpip.ErrWouldBlock { 898 // Wait for connection to be established. 899 select { 900 case <-ch: 901 c.EP, _, err = ep.Accept() 902 if err != nil { 903 c.t.Fatalf("Accept failed: %v", err) 904 } 905 906 case <-time.After(1 * time.Second): 907 c.t.Fatalf("Timed out waiting for accept") 908 } 909 } 910 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateEstablished; got != want { 911 c.t.Errorf("Unexpected endpoint state: want %v, got %v", want, got) 912 } 913 914 return rep 915 } 916 917 // PassiveConnect just disables WindowScaling and delegates the call to 918 // PassiveConnectWithOptions. 919 func (c *Context) PassiveConnect(maxPayload, wndScale int, synOptions header.TCPSynOptions) { 920 synOptions.WS = -1 921 c.PassiveConnectWithOptions(maxPayload, wndScale, synOptions) 922 } 923 924 // PassiveConnectWithOptions initiates a new connection (with the specified TCP 925 // options enabled) to the port on which the Context.ep is listening for new 926 // connections. It also validates that the SYN-ACK has the expected values for 927 // the enabled options. 928 // 929 // NOTE: MSS is not a negotiated option and it can be asymmetric 930 // in each direction. This function uses the maxPayload to set the MSS to be 931 // sent to the peer on a connect and validates that the MSS in the SYN-ACK 932 // response is equal to the MTU - (tcphdr len + iphdr len). 933 // 934 // wndScale is the expected window scale in the SYN-ACK and synOptions.WS is the 935 // value of the window scaling option to be sent in the SYN. If synOptions.WS > 936 // 0 then we send the WindowScale option. 937 func (c *Context) PassiveConnectWithOptions(maxPayload, wndScale int, synOptions header.TCPSynOptions) *RawEndpoint { 938 opts := make([]byte, header.TCPOptionsMaximumSize) 939 offset := 0 940 offset += header.EncodeMSSOption(uint32(maxPayload), opts) 941 942 if synOptions.WS >= 0 { 943 offset += header.EncodeWSOption(3, opts[offset:]) 944 } 945 if synOptions.TS { 946 offset += header.EncodeTSOption(synOptions.TSVal, synOptions.TSEcr, opts[offset:]) 947 } 948 949 if synOptions.SACKPermitted { 950 offset += header.EncodeSACKPermittedOption(opts[offset:]) 951 } 952 953 paddingToAdd := 4 - offset%4 954 // Now add any padding bytes that might be required to quad align the 955 // options. 956 for i := offset; i < offset+paddingToAdd; i++ { 957 opts[i] = header.TCPOptionNOP 958 } 959 offset += paddingToAdd 960 961 // Send a SYN request. 962 iss := seqnum.Value(testInitialSequenceNumber) 963 c.SendPacket(nil, &Headers{ 964 SrcPort: TestPort, 965 DstPort: StackPort, 966 Flags: header.TCPFlagSyn, 967 SeqNum: iss, 968 RcvWnd: 30000, 969 TCPOpts: opts[:offset], 970 }) 971 972 // Receive the SYN-ACK reply. Make sure MSS and other expected options 973 // are present. 974 b := c.GetPacket() 975 tcp := header.TCP(header.IPv4(b).Payload()) 976 c.IRS = seqnum.Value(tcp.SequenceNumber()) 977 978 tcpCheckers := []checker.TransportChecker{ 979 checker.SrcPort(StackPort), 980 checker.DstPort(TestPort), 981 checker.TCPFlags(header.TCPFlagAck | header.TCPFlagSyn), 982 checker.AckNum(uint32(iss) + 1), 983 checker.TCPSynOptions(header.TCPSynOptions{MSS: synOptions.MSS, WS: wndScale, SACKPermitted: synOptions.SACKPermitted && c.SACKEnabled()}), 984 } 985 986 // If TS option was enabled in the original SYN then add a checker to 987 // validate the Timestamp option in the SYN-ACK. 988 if synOptions.TS { 989 tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(synOptions.TS, 0, synOptions.TSVal)) 990 } else { 991 tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(false, 0, 0)) 992 } 993 994 checker.IPv4(c.t, b, checker.TCP(tcpCheckers...)) 995 rcvWnd := seqnum.Size(30000) 996 ackHeaders := &Headers{ 997 SrcPort: TestPort, 998 DstPort: StackPort, 999 Flags: header.TCPFlagAck, 1000 SeqNum: iss + 1, 1001 AckNum: c.IRS + 1, 1002 RcvWnd: rcvWnd, 1003 } 1004 1005 // If WS was expected to be in effect then scale the advertised window 1006 // correspondingly. 1007 if synOptions.WS > 0 { 1008 ackHeaders.RcvWnd = rcvWnd >> byte(synOptions.WS) 1009 } 1010 1011 parsedOpts := tcp.ParsedOptions() 1012 if synOptions.TS { 1013 // Echo the tsVal back to the peer in the tsEcr field of the 1014 // timestamp option. 1015 // Increment TSVal by 1 from the value sent in the SYN and echo 1016 // the TSVal in the SYN-ACK in the TSEcr field. 1017 opts := [12]byte{header.TCPOptionNOP, header.TCPOptionNOP} 1018 header.EncodeTSOption(synOptions.TSVal+1, parsedOpts.TSVal, opts[2:]) 1019 ackHeaders.TCPOpts = opts[:] 1020 } 1021 1022 // Send ACK. 1023 c.SendPacket(nil, ackHeaders) 1024 1025 c.Port = StackPort 1026 1027 return &RawEndpoint{ 1028 C: c, 1029 SrcPort: TestPort, 1030 DstPort: StackPort, 1031 Flags: header.TCPFlagPsh | header.TCPFlagAck, 1032 NextSeqNum: iss + 1, 1033 AckNum: c.IRS + 1, 1034 WndSize: rcvWnd, 1035 SACKPermitted: synOptions.SACKPermitted && c.SACKEnabled(), 1036 RecentTS: parsedOpts.TSVal, 1037 TSVal: synOptions.TSVal + 1, 1038 } 1039 } 1040 1041 // SACKEnabled returns true if the TCP Protocol option SACKEnabled is set to true 1042 // for the Stack in the context. 1043 func (c *Context) SACKEnabled() bool { 1044 var v tcp.SACKEnabled 1045 if err := c.Stack().TransportProtocolOption(tcp.ProtocolNumber, &v); err != nil { 1046 // Stack doesn't support SACK. So just return. 1047 return false 1048 } 1049 return bool(v) 1050 } 1051 1052 // SetGSOEnabled enables or disables generic segmentation offload. 1053 func (c *Context) SetGSOEnabled(enable bool) { 1054 c.linkEP.GSO = enable 1055 } 1056 1057 // MSSWithoutOptions returns the value for the MSS used by the stack when no 1058 // options are in use. 1059 func (c *Context) MSSWithoutOptions() uint16 { 1060 return uint16(c.linkEP.MTU() - header.IPv4MinimumSize - header.TCPMinimumSize) 1061 }