github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/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/google/netstack/tcpip" 25 "github.com/google/netstack/tcpip/buffer" 26 "github.com/google/netstack/tcpip/checker" 27 "github.com/google/netstack/tcpip/header" 28 "github.com/google/netstack/tcpip/link/channel" 29 "github.com/google/netstack/tcpip/link/sniffer" 30 "github.com/google/netstack/tcpip/network/ipv4" 31 "github.com/google/netstack/tcpip/network/ipv6" 32 "github.com/google/netstack/tcpip/seqnum" 33 "github.com/google/netstack/tcpip/stack" 34 "github.com/google/netstack/tcpip/transport/tcp" 35 "github.com/google/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 240 hdr := p.Pkt.Header.View() 241 b := append(hdr[:len(hdr):len(hdr)], p.Pkt.Data.ToView()...) 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 268 hdr := p.Pkt.Header.View() 269 b := append(hdr[:len(hdr):len(hdr)], p.Pkt.Data.ToView()...) 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.InjectInbound(ipv4.ProtocolNumber, tcpip.PacketBuffer{ 306 Data: buf.ToVectorisedView(), 307 }) 308 } 309 310 // BuildSegment builds a TCP segment based on the given Headers and payload. 311 func (c *Context) BuildSegment(payload []byte, h *Headers) buffer.VectorisedView { 312 return c.BuildSegmentWithAddrs(payload, h, TestAddr, StackAddr) 313 } 314 315 // BuildSegmentWithAddrs builds a TCP segment based on the given Headers, 316 // payload and source and destination IPv4 addresses. 317 func (c *Context) BuildSegmentWithAddrs(payload []byte, h *Headers, src, dst tcpip.Address) buffer.VectorisedView { 318 // Allocate a buffer for data and headers. 319 buf := buffer.NewView(header.TCPMinimumSize + header.IPv4MinimumSize + len(h.TCPOpts) + len(payload)) 320 copy(buf[len(buf)-len(payload):], payload) 321 copy(buf[len(buf)-len(payload)-len(h.TCPOpts):], h.TCPOpts) 322 323 // Initialize the IP header. 324 ip := header.IPv4(buf) 325 ip.Encode(&header.IPv4Fields{ 326 IHL: header.IPv4MinimumSize, 327 TotalLength: uint16(len(buf)), 328 TTL: 65, 329 Protocol: uint8(tcp.ProtocolNumber), 330 SrcAddr: src, 331 DstAddr: dst, 332 }) 333 ip.SetChecksum(^ip.CalculateChecksum()) 334 335 // Initialize the TCP header. 336 t := header.TCP(buf[header.IPv4MinimumSize:]) 337 t.Encode(&header.TCPFields{ 338 SrcPort: h.SrcPort, 339 DstPort: h.DstPort, 340 SeqNum: uint32(h.SeqNum), 341 AckNum: uint32(h.AckNum), 342 DataOffset: uint8(header.TCPMinimumSize + len(h.TCPOpts)), 343 Flags: uint8(h.Flags), 344 WindowSize: uint16(h.RcvWnd), 345 }) 346 347 // Calculate the TCP pseudo-header checksum. 348 xsum := header.PseudoHeaderChecksum(tcp.ProtocolNumber, src, dst, uint16(len(t))) 349 350 // Calculate the TCP checksum and set it. 351 xsum = header.Checksum(payload, xsum) 352 t.SetChecksum(^t.CalculateChecksum(xsum)) 353 354 // Inject packet. 355 return buf.ToVectorisedView() 356 } 357 358 // SendSegment sends a TCP segment that has already been built and written to a 359 // buffer.VectorisedView. 360 func (c *Context) SendSegment(s buffer.VectorisedView) { 361 c.linkEP.InjectInbound(ipv4.ProtocolNumber, tcpip.PacketBuffer{ 362 Data: s, 363 }) 364 } 365 366 // SendPacket builds and sends a TCP segment(with the provided payload & TCP 367 // headers) in an IPv4 packet via the link layer endpoint. 368 func (c *Context) SendPacket(payload []byte, h *Headers) { 369 c.linkEP.InjectInbound(ipv4.ProtocolNumber, tcpip.PacketBuffer{ 370 Data: c.BuildSegment(payload, h), 371 }) 372 } 373 374 // SendPacketWithAddrs builds and sends a TCP segment(with the provided payload 375 // & TCPheaders) in an IPv4 packet via the link layer endpoint using the 376 // provided source and destination IPv4 addresses. 377 func (c *Context) SendPacketWithAddrs(payload []byte, h *Headers, src, dst tcpip.Address) { 378 c.linkEP.InjectInbound(ipv4.ProtocolNumber, tcpip.PacketBuffer{ 379 Data: c.BuildSegmentWithAddrs(payload, h, src, dst), 380 }) 381 } 382 383 // SendAck sends an ACK packet. 384 func (c *Context) SendAck(seq seqnum.Value, bytesReceived int) { 385 c.SendAckWithSACK(seq, bytesReceived, nil) 386 } 387 388 // SendAckWithSACK sends an ACK packet which includes the sackBlocks specified. 389 func (c *Context) SendAckWithSACK(seq seqnum.Value, bytesReceived int, sackBlocks []header.SACKBlock) { 390 options := make([]byte, 40) 391 offset := 0 392 if len(sackBlocks) > 0 { 393 offset += header.EncodeNOP(options[offset:]) 394 offset += header.EncodeNOP(options[offset:]) 395 offset += header.EncodeSACKBlocks(sackBlocks, options[offset:]) 396 } 397 398 c.SendPacket(nil, &Headers{ 399 SrcPort: TestPort, 400 DstPort: c.Port, 401 Flags: header.TCPFlagAck, 402 SeqNum: seq, 403 AckNum: c.IRS.Add(1 + seqnum.Size(bytesReceived)), 404 RcvWnd: 30000, 405 TCPOpts: options[:offset], 406 }) 407 } 408 409 // ReceiveAndCheckPacket reads a packet from the link layer endpoint and 410 // verifies that the packet packet payload of packet matches the slice 411 // of data indicated by offset & size. 412 func (c *Context) ReceiveAndCheckPacket(data []byte, offset, size int) { 413 c.ReceiveAndCheckPacketWithOptions(data, offset, size, 0) 414 } 415 416 // ReceiveAndCheckPacketWithOptions reads a packet from the link layer endpoint 417 // and verifies that the packet packet payload of packet matches the slice of 418 // data indicated by offset & size and skips optlen bytes in addition to the IP 419 // TCP headers when comparing the data. 420 func (c *Context) ReceiveAndCheckPacketWithOptions(data []byte, offset, size, optlen int) { 421 b := c.GetPacket() 422 checker.IPv4(c.t, b, 423 checker.PayloadLen(size+header.TCPMinimumSize+optlen), 424 checker.TCP( 425 checker.DstPort(TestPort), 426 checker.SeqNum(uint32(c.IRS.Add(seqnum.Size(1+offset)))), 427 checker.AckNum(uint32(seqnum.Value(testInitialSequenceNumber).Add(1))), 428 checker.TCPFlagsMatch(header.TCPFlagAck, ^uint8(header.TCPFlagPsh)), 429 ), 430 ) 431 432 pdata := data[offset:][:size] 433 if p := b[header.IPv4MinimumSize+header.TCPMinimumSize+optlen:]; bytes.Compare(pdata, p) != 0 { 434 c.t.Fatalf("Data is different: expected %v, got %v", pdata, p) 435 } 436 } 437 438 // ReceiveNonBlockingAndCheckPacket reads a packet from the link layer endpoint 439 // and verifies that the packet packet payload of packet matches the slice of 440 // data indicated by offset & size. It returns true if a packet was received and 441 // processed. 442 func (c *Context) ReceiveNonBlockingAndCheckPacket(data []byte, offset, size int) bool { 443 b := c.GetPacketNonBlocking() 444 if b == nil { 445 return false 446 } 447 checker.IPv4(c.t, b, 448 checker.PayloadLen(size+header.TCPMinimumSize), 449 checker.TCP( 450 checker.DstPort(TestPort), 451 checker.SeqNum(uint32(c.IRS.Add(seqnum.Size(1+offset)))), 452 checker.AckNum(uint32(seqnum.Value(testInitialSequenceNumber).Add(1))), 453 checker.TCPFlagsMatch(header.TCPFlagAck, ^uint8(header.TCPFlagPsh)), 454 ), 455 ) 456 457 pdata := data[offset:][:size] 458 if p := b[header.IPv4MinimumSize+header.TCPMinimumSize:]; bytes.Compare(pdata, p) != 0 { 459 c.t.Fatalf("Data is different: expected %v, got %v", pdata, p) 460 } 461 return true 462 } 463 464 // CreateV6Endpoint creates and initializes c.ep as a IPv6 Endpoint. If v6Only 465 // is true then it sets the IP_V6ONLY option on the socket to make it a IPv6 466 // only endpoint instead of a default dual stack socket. 467 func (c *Context) CreateV6Endpoint(v6only bool) { 468 var err *tcpip.Error 469 c.EP, err = c.s.NewEndpoint(tcp.ProtocolNumber, ipv6.ProtocolNumber, &c.WQ) 470 if err != nil { 471 c.t.Fatalf("NewEndpoint failed: %v", err) 472 } 473 474 var v tcpip.V6OnlyOption 475 if v6only { 476 v = 1 477 } 478 if err := c.EP.SetSockOpt(v); err != nil { 479 c.t.Fatalf("SetSockOpt failed failed: %v", err) 480 } 481 } 482 483 // GetV6Packet reads a single packet from the link layer endpoint of the context 484 // and asserts that it is an IPv6 Packet with the expected src/dest addresses. 485 func (c *Context) GetV6Packet() []byte { 486 select { 487 case p := <-c.linkEP.C: 488 if p.Proto != ipv6.ProtocolNumber { 489 c.t.Fatalf("Bad network protocol: got %v, wanted %v", p.Proto, ipv6.ProtocolNumber) 490 } 491 b := make([]byte, p.Pkt.Header.UsedLength()+p.Pkt.Data.Size()) 492 copy(b, p.Pkt.Header.View()) 493 copy(b[p.Pkt.Header.UsedLength():], p.Pkt.Data.ToView()) 494 495 checker.IPv6(c.t, b, checker.SrcAddr(StackV6Addr), checker.DstAddr(TestV6Addr)) 496 return b 497 498 case <-time.After(2 * time.Second): 499 c.t.Fatalf("Packet wasn't written out") 500 } 501 502 return nil 503 } 504 505 // SendV6Packet builds and sends an IPv6 Packet via the link layer endpoint of 506 // the context. 507 func (c *Context) SendV6Packet(payload []byte, h *Headers) { 508 c.SendV6PacketWithAddrs(payload, h, TestV6Addr, StackV6Addr) 509 } 510 511 // SendV6PacketWithAddrs builds and sends an IPv6 Packet via the link layer 512 // endpoint of the context using the provided source and destination IPv6 513 // addresses. 514 func (c *Context) SendV6PacketWithAddrs(payload []byte, h *Headers, src, dst tcpip.Address) { 515 // Allocate a buffer for data and headers. 516 buf := buffer.NewView(header.TCPMinimumSize + header.IPv6MinimumSize + len(payload)) 517 copy(buf[len(buf)-len(payload):], payload) 518 519 // Initialize the IP header. 520 ip := header.IPv6(buf) 521 ip.Encode(&header.IPv6Fields{ 522 PayloadLength: uint16(header.TCPMinimumSize + len(payload)), 523 NextHeader: uint8(tcp.ProtocolNumber), 524 HopLimit: 65, 525 SrcAddr: src, 526 DstAddr: dst, 527 }) 528 529 // Initialize the TCP header. 530 t := header.TCP(buf[header.IPv6MinimumSize:]) 531 t.Encode(&header.TCPFields{ 532 SrcPort: h.SrcPort, 533 DstPort: h.DstPort, 534 SeqNum: uint32(h.SeqNum), 535 AckNum: uint32(h.AckNum), 536 DataOffset: header.TCPMinimumSize, 537 Flags: uint8(h.Flags), 538 WindowSize: uint16(h.RcvWnd), 539 }) 540 541 // Calculate the TCP pseudo-header checksum. 542 xsum := header.PseudoHeaderChecksum(tcp.ProtocolNumber, src, dst, uint16(len(t))) 543 544 // Calculate the TCP checksum and set it. 545 xsum = header.Checksum(payload, xsum) 546 t.SetChecksum(^t.CalculateChecksum(xsum)) 547 548 // Inject packet. 549 c.linkEP.InjectInbound(ipv6.ProtocolNumber, tcpip.PacketBuffer{ 550 Data: buf.ToVectorisedView(), 551 }) 552 } 553 554 // CreateConnected creates a connected TCP endpoint. 555 func (c *Context) CreateConnected(iss seqnum.Value, rcvWnd seqnum.Size, epRcvBuf int) { 556 c.CreateConnectedWithRawOptions(iss, rcvWnd, epRcvBuf, nil) 557 } 558 559 // Connect performs the 3-way handshake for c.EP with the provided Initial 560 // Sequence Number (iss) and receive window(rcvWnd) and any options if 561 // specified. 562 // 563 // It also sets the receive buffer for the endpoint to the specified 564 // value in epRcvBuf. 565 // 566 // PreCondition: c.EP must already be created. 567 func (c *Context) Connect(iss seqnum.Value, rcvWnd seqnum.Size, options []byte) { 568 // Start connection attempt. 569 waitEntry, notifyCh := waiter.NewChannelEntry(nil) 570 c.WQ.EventRegister(&waitEntry, waiter.EventOut) 571 defer c.WQ.EventUnregister(&waitEntry) 572 573 if err := c.EP.Connect(tcpip.FullAddress{Addr: TestAddr, Port: TestPort}); err != tcpip.ErrConnectStarted { 574 c.t.Fatalf("Unexpected return value from Connect: %v", err) 575 } 576 577 // Receive SYN packet. 578 b := c.GetPacket() 579 checker.IPv4(c.t, b, 580 checker.TCP( 581 checker.DstPort(TestPort), 582 checker.TCPFlags(header.TCPFlagSyn), 583 ), 584 ) 585 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateSynSent; got != want { 586 c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) 587 } 588 589 tcpHdr := header.TCP(header.IPv4(b).Payload()) 590 c.IRS = seqnum.Value(tcpHdr.SequenceNumber()) 591 592 c.SendPacket(nil, &Headers{ 593 SrcPort: tcpHdr.DestinationPort(), 594 DstPort: tcpHdr.SourcePort(), 595 Flags: header.TCPFlagSyn | header.TCPFlagAck, 596 SeqNum: iss, 597 AckNum: c.IRS.Add(1), 598 RcvWnd: rcvWnd, 599 TCPOpts: options, 600 }) 601 602 // Receive ACK packet. 603 checker.IPv4(c.t, c.GetPacket(), 604 checker.TCP( 605 checker.DstPort(TestPort), 606 checker.TCPFlags(header.TCPFlagAck), 607 checker.SeqNum(uint32(c.IRS)+1), 608 checker.AckNum(uint32(iss)+1), 609 ), 610 ) 611 612 // Wait for connection to be established. 613 select { 614 case <-notifyCh: 615 if err := c.EP.GetSockOpt(tcpip.ErrorOption{}); err != nil { 616 c.t.Fatalf("Unexpected error when connecting: %v", err) 617 } 618 case <-time.After(1 * time.Second): 619 c.t.Fatalf("Timed out waiting for connection") 620 } 621 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateEstablished; got != want { 622 c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) 623 } 624 625 c.Port = tcpHdr.SourcePort() 626 } 627 628 // Create creates a TCP endpoint. 629 func (c *Context) Create(epRcvBuf int) { 630 // Create TCP endpoint. 631 var err *tcpip.Error 632 c.EP, err = c.s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &c.WQ) 633 if err != nil { 634 c.t.Fatalf("NewEndpoint failed: %v", err) 635 } 636 637 if epRcvBuf != -1 { 638 if err := c.EP.SetSockOptInt(tcpip.ReceiveBufferSizeOption, epRcvBuf); err != nil { 639 c.t.Fatalf("SetSockOpt failed failed: %v", err) 640 } 641 } 642 } 643 644 // CreateConnectedWithRawOptions creates a connected TCP endpoint and sends 645 // the specified option bytes as the Option field in the initial SYN packet. 646 // 647 // It also sets the receive buffer for the endpoint to the specified 648 // value in epRcvBuf. 649 func (c *Context) CreateConnectedWithRawOptions(iss seqnum.Value, rcvWnd seqnum.Size, epRcvBuf int, options []byte) { 650 c.Create(epRcvBuf) 651 c.Connect(iss, rcvWnd, options) 652 } 653 654 // RawEndpoint is just a small wrapper around a TCP endpoint's state to make 655 // sending data and ACK packets easy while being able to manipulate the sequence 656 // numbers and timestamp values as needed. 657 type RawEndpoint struct { 658 C *Context 659 SrcPort uint16 660 DstPort uint16 661 Flags int 662 NextSeqNum seqnum.Value 663 AckNum seqnum.Value 664 WndSize seqnum.Size 665 RecentTS uint32 // Stores the latest timestamp to echo back. 666 TSVal uint32 // TSVal stores the last timestamp sent by this endpoint. 667 668 // SackPermitted is true if SACKPermitted option was negotiated for this endpoint. 669 SACKPermitted bool 670 } 671 672 // SendPacketWithTS embeds the provided tsVal in the Timestamp option 673 // for the packet to be sent out. 674 func (r *RawEndpoint) SendPacketWithTS(payload []byte, tsVal uint32) { 675 r.TSVal = tsVal 676 tsOpt := [12]byte{header.TCPOptionNOP, header.TCPOptionNOP} 677 header.EncodeTSOption(r.TSVal, r.RecentTS, tsOpt[2:]) 678 r.SendPacket(payload, tsOpt[:]) 679 } 680 681 // SendPacket is a small wrapper function to build and send packets. 682 func (r *RawEndpoint) SendPacket(payload []byte, opts []byte) { 683 packetHeaders := &Headers{ 684 SrcPort: r.SrcPort, 685 DstPort: r.DstPort, 686 Flags: r.Flags, 687 SeqNum: r.NextSeqNum, 688 AckNum: r.AckNum, 689 RcvWnd: r.WndSize, 690 TCPOpts: opts, 691 } 692 r.C.SendPacket(payload, packetHeaders) 693 r.NextSeqNum = r.NextSeqNum.Add(seqnum.Size(len(payload))) 694 } 695 696 // VerifyACKWithTS verifies that the tsEcr field in the ack matches the provided 697 // tsVal. 698 func (r *RawEndpoint) VerifyACKWithTS(tsVal uint32) { 699 // Read ACK and verify that tsEcr of ACK packet is [1,2,3,4] 700 ackPacket := r.C.GetPacket() 701 checker.IPv4(r.C.t, ackPacket, 702 checker.TCP( 703 checker.DstPort(r.SrcPort), 704 checker.TCPFlags(header.TCPFlagAck), 705 checker.SeqNum(uint32(r.AckNum)), 706 checker.AckNum(uint32(r.NextSeqNum)), 707 checker.TCPTimestampChecker(true, 0, tsVal), 708 ), 709 ) 710 // Store the parsed TSVal from the ack as recentTS. 711 tcpSeg := header.TCP(header.IPv4(ackPacket).Payload()) 712 opts := tcpSeg.ParsedOptions() 713 r.RecentTS = opts.TSVal 714 } 715 716 // VerifyACKRcvWnd verifies that the window advertised by the incoming ACK 717 // matches the provided rcvWnd. 718 func (r *RawEndpoint) VerifyACKRcvWnd(rcvWnd uint16) { 719 ackPacket := r.C.GetPacket() 720 checker.IPv4(r.C.t, ackPacket, 721 checker.TCP( 722 checker.DstPort(r.SrcPort), 723 checker.TCPFlags(header.TCPFlagAck), 724 checker.SeqNum(uint32(r.AckNum)), 725 checker.AckNum(uint32(r.NextSeqNum)), 726 checker.Window(rcvWnd), 727 ), 728 ) 729 } 730 731 // VerifyACKNoSACK verifies that the ACK does not contain a SACK block. 732 func (r *RawEndpoint) VerifyACKNoSACK() { 733 r.VerifyACKHasSACK(nil) 734 } 735 736 // VerifyACKHasSACK verifies that the ACK contains the specified SACKBlocks. 737 func (r *RawEndpoint) VerifyACKHasSACK(sackBlocks []header.SACKBlock) { 738 // Read ACK and verify that the TCP options in the segment do 739 // not contain a SACK block. 740 ackPacket := r.C.GetPacket() 741 checker.IPv4(r.C.t, ackPacket, 742 checker.TCP( 743 checker.DstPort(r.SrcPort), 744 checker.TCPFlags(header.TCPFlagAck), 745 checker.SeqNum(uint32(r.AckNum)), 746 checker.AckNum(uint32(r.NextSeqNum)), 747 checker.TCPSACKBlockChecker(sackBlocks), 748 ), 749 ) 750 } 751 752 // CreateConnectedWithOptions creates and connects c.ep with the specified TCP 753 // options enabled and returns a RawEndpoint which represents the other end of 754 // the connection. 755 // 756 // It also verifies where required(eg.Timestamp) that the ACK to the SYN-ACK 757 // does not carry an option that was not requested. 758 func (c *Context) CreateConnectedWithOptions(wantOptions header.TCPSynOptions) *RawEndpoint { 759 var err *tcpip.Error 760 c.EP, err = c.s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &c.WQ) 761 if err != nil { 762 c.t.Fatalf("c.s.NewEndpoint(tcp, ipv4...) = %v", err) 763 } 764 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateInitial; got != want { 765 c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) 766 } 767 768 // Start connection attempt. 769 waitEntry, notifyCh := waiter.NewChannelEntry(nil) 770 c.WQ.EventRegister(&waitEntry, waiter.EventOut) 771 defer c.WQ.EventUnregister(&waitEntry) 772 773 testFullAddr := tcpip.FullAddress{Addr: TestAddr, Port: TestPort} 774 err = c.EP.Connect(testFullAddr) 775 if err != tcpip.ErrConnectStarted { 776 c.t.Fatalf("c.ep.Connect(%v) = %v", testFullAddr, err) 777 } 778 // Receive SYN packet. 779 b := c.GetPacket() 780 // Validate that the syn has the timestamp option and a valid 781 // TS value. 782 mss := uint16(c.linkEP.MTU() - header.IPv4MinimumSize - header.TCPMinimumSize) 783 784 checker.IPv4(c.t, b, 785 checker.TCP( 786 checker.DstPort(TestPort), 787 checker.TCPFlags(header.TCPFlagSyn), 788 checker.TCPSynOptions(header.TCPSynOptions{ 789 MSS: mss, 790 TS: true, 791 WS: int(c.WindowScale), 792 SACKPermitted: c.SACKEnabled(), 793 }), 794 ), 795 ) 796 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateSynSent; got != want { 797 c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) 798 } 799 800 tcpSeg := header.TCP(header.IPv4(b).Payload()) 801 synOptions := header.ParseSynOptions(tcpSeg.Options(), false) 802 803 // Build options w/ tsVal to be sent in the SYN-ACK. 804 synAckOptions := make([]byte, header.TCPOptionsMaximumSize) 805 offset := 0 806 if wantOptions.WS != -1 { 807 offset += header.EncodeWSOption(wantOptions.WS, synAckOptions[offset:]) 808 } 809 if wantOptions.TS { 810 offset += header.EncodeTSOption(wantOptions.TSVal, synOptions.TSVal, synAckOptions[offset:]) 811 } 812 if wantOptions.SACKPermitted { 813 offset += header.EncodeSACKPermittedOption(synAckOptions[offset:]) 814 } 815 816 offset += header.AddTCPOptionPadding(synAckOptions, offset) 817 818 // Build SYN-ACK. 819 c.IRS = seqnum.Value(tcpSeg.SequenceNumber()) 820 iss := seqnum.Value(testInitialSequenceNumber) 821 c.SendPacket(nil, &Headers{ 822 SrcPort: tcpSeg.DestinationPort(), 823 DstPort: tcpSeg.SourcePort(), 824 Flags: header.TCPFlagSyn | header.TCPFlagAck, 825 SeqNum: iss, 826 AckNum: c.IRS.Add(1), 827 RcvWnd: 30000, 828 TCPOpts: synAckOptions[:offset], 829 }) 830 831 // Read ACK. 832 ackPacket := c.GetPacket() 833 834 // Verify TCP header fields. 835 tcpCheckers := []checker.TransportChecker{ 836 checker.DstPort(TestPort), 837 checker.TCPFlags(header.TCPFlagAck), 838 checker.SeqNum(uint32(c.IRS) + 1), 839 checker.AckNum(uint32(iss) + 1), 840 } 841 842 // Verify that tsEcr of ACK packet is wantOptions.TSVal if the 843 // timestamp option was enabled, if not then we verify that 844 // there is no timestamp in the ACK packet. 845 if wantOptions.TS { 846 tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(true, 0, wantOptions.TSVal)) 847 } else { 848 tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(false, 0, 0)) 849 } 850 851 checker.IPv4(c.t, ackPacket, checker.TCP(tcpCheckers...)) 852 853 ackSeg := header.TCP(header.IPv4(ackPacket).Payload()) 854 ackOptions := ackSeg.ParsedOptions() 855 856 // Wait for connection to be established. 857 select { 858 case <-notifyCh: 859 err = c.EP.GetSockOpt(tcpip.ErrorOption{}) 860 if err != nil { 861 c.t.Fatalf("Unexpected error when connecting: %v", err) 862 } 863 case <-time.After(1 * time.Second): 864 c.t.Fatalf("Timed out waiting for connection") 865 } 866 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateEstablished; got != want { 867 c.t.Fatalf("Unexpected endpoint state: want %v, got %v", want, got) 868 } 869 870 // Store the source port in use by the endpoint. 871 c.Port = tcpSeg.SourcePort() 872 873 // Mark in context that timestamp option is enabled for this endpoint. 874 c.TimeStampEnabled = true 875 876 return &RawEndpoint{ 877 C: c, 878 SrcPort: tcpSeg.DestinationPort(), 879 DstPort: tcpSeg.SourcePort(), 880 Flags: header.TCPFlagAck | header.TCPFlagPsh, 881 NextSeqNum: iss + 1, 882 AckNum: c.IRS.Add(1), 883 WndSize: 30000, 884 RecentTS: ackOptions.TSVal, 885 TSVal: wantOptions.TSVal, 886 SACKPermitted: wantOptions.SACKPermitted, 887 } 888 } 889 890 // AcceptWithOptions initializes a listening endpoint and connects to it with the 891 // provided options enabled. It also verifies that the SYN-ACK has the expected 892 // values for the provided options. 893 // 894 // The function returns a RawEndpoint representing the other end of the accepted 895 // endpoint. 896 func (c *Context) AcceptWithOptions(wndScale int, synOptions header.TCPSynOptions) *RawEndpoint { 897 // Create EP and start listening. 898 wq := &waiter.Queue{} 899 ep, err := c.s.NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, wq) 900 if err != nil { 901 c.t.Fatalf("NewEndpoint failed: %v", err) 902 } 903 defer ep.Close() 904 905 if err := ep.Bind(tcpip.FullAddress{Port: StackPort}); err != nil { 906 c.t.Fatalf("Bind failed: %v", err) 907 } 908 if got, want := tcp.EndpointState(ep.State()), tcp.StateBound; got != want { 909 c.t.Errorf("Unexpected endpoint state: want %v, got %v", want, got) 910 } 911 912 if err := ep.Listen(10); err != nil { 913 c.t.Fatalf("Listen failed: %v", err) 914 } 915 if got, want := tcp.EndpointState(ep.State()), tcp.StateListen; got != want { 916 c.t.Errorf("Unexpected endpoint state: want %v, got %v", want, got) 917 } 918 919 rep := c.PassiveConnectWithOptions(100, wndScale, synOptions) 920 921 // Try to accept the connection. 922 we, ch := waiter.NewChannelEntry(nil) 923 wq.EventRegister(&we, waiter.EventIn) 924 defer wq.EventUnregister(&we) 925 926 c.EP, _, err = ep.Accept() 927 if err == tcpip.ErrWouldBlock { 928 // Wait for connection to be established. 929 select { 930 case <-ch: 931 c.EP, _, err = ep.Accept() 932 if err != nil { 933 c.t.Fatalf("Accept failed: %v", err) 934 } 935 936 case <-time.After(1 * time.Second): 937 c.t.Fatalf("Timed out waiting for accept") 938 } 939 } 940 if got, want := tcp.EndpointState(c.EP.State()), tcp.StateEstablished; got != want { 941 c.t.Errorf("Unexpected endpoint state: want %v, got %v", want, got) 942 } 943 944 return rep 945 } 946 947 // PassiveConnect just disables WindowScaling and delegates the call to 948 // PassiveConnectWithOptions. 949 func (c *Context) PassiveConnect(maxPayload, wndScale int, synOptions header.TCPSynOptions) { 950 synOptions.WS = -1 951 c.PassiveConnectWithOptions(maxPayload, wndScale, synOptions) 952 } 953 954 // PassiveConnectWithOptions initiates a new connection (with the specified TCP 955 // options enabled) to the port on which the Context.ep is listening for new 956 // connections. It also validates that the SYN-ACK has the expected values for 957 // the enabled options. 958 // 959 // NOTE: MSS is not a negotiated option and it can be asymmetric 960 // in each direction. This function uses the maxPayload to set the MSS to be 961 // sent to the peer on a connect and validates that the MSS in the SYN-ACK 962 // response is equal to the MTU - (tcphdr len + iphdr len). 963 // 964 // wndScale is the expected window scale in the SYN-ACK and synOptions.WS is the 965 // value of the window scaling option to be sent in the SYN. If synOptions.WS > 966 // 0 then we send the WindowScale option. 967 func (c *Context) PassiveConnectWithOptions(maxPayload, wndScale int, synOptions header.TCPSynOptions) *RawEndpoint { 968 opts := make([]byte, header.TCPOptionsMaximumSize) 969 offset := 0 970 offset += header.EncodeMSSOption(uint32(maxPayload), opts) 971 972 if synOptions.WS >= 0 { 973 offset += header.EncodeWSOption(3, opts[offset:]) 974 } 975 if synOptions.TS { 976 offset += header.EncodeTSOption(synOptions.TSVal, synOptions.TSEcr, opts[offset:]) 977 } 978 979 if synOptions.SACKPermitted { 980 offset += header.EncodeSACKPermittedOption(opts[offset:]) 981 } 982 983 paddingToAdd := 4 - offset%4 984 // Now add any padding bytes that might be required to quad align the 985 // options. 986 for i := offset; i < offset+paddingToAdd; i++ { 987 opts[i] = header.TCPOptionNOP 988 } 989 offset += paddingToAdd 990 991 // Send a SYN request. 992 iss := seqnum.Value(testInitialSequenceNumber) 993 c.SendPacket(nil, &Headers{ 994 SrcPort: TestPort, 995 DstPort: StackPort, 996 Flags: header.TCPFlagSyn, 997 SeqNum: iss, 998 RcvWnd: 30000, 999 TCPOpts: opts[:offset], 1000 }) 1001 1002 // Receive the SYN-ACK reply. Make sure MSS and other expected options 1003 // are present. 1004 b := c.GetPacket() 1005 tcp := header.TCP(header.IPv4(b).Payload()) 1006 c.IRS = seqnum.Value(tcp.SequenceNumber()) 1007 1008 tcpCheckers := []checker.TransportChecker{ 1009 checker.SrcPort(StackPort), 1010 checker.DstPort(TestPort), 1011 checker.TCPFlags(header.TCPFlagAck | header.TCPFlagSyn), 1012 checker.AckNum(uint32(iss) + 1), 1013 checker.TCPSynOptions(header.TCPSynOptions{MSS: synOptions.MSS, WS: wndScale, SACKPermitted: synOptions.SACKPermitted && c.SACKEnabled()}), 1014 } 1015 1016 // If TS option was enabled in the original SYN then add a checker to 1017 // validate the Timestamp option in the SYN-ACK. 1018 if synOptions.TS { 1019 tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(synOptions.TS, 0, synOptions.TSVal)) 1020 } else { 1021 tcpCheckers = append(tcpCheckers, checker.TCPTimestampChecker(false, 0, 0)) 1022 } 1023 1024 checker.IPv4(c.t, b, checker.TCP(tcpCheckers...)) 1025 rcvWnd := seqnum.Size(30000) 1026 ackHeaders := &Headers{ 1027 SrcPort: TestPort, 1028 DstPort: StackPort, 1029 Flags: header.TCPFlagAck, 1030 SeqNum: iss + 1, 1031 AckNum: c.IRS + 1, 1032 RcvWnd: rcvWnd, 1033 } 1034 1035 // If WS was expected to be in effect then scale the advertised window 1036 // correspondingly. 1037 if synOptions.WS > 0 { 1038 ackHeaders.RcvWnd = rcvWnd >> byte(synOptions.WS) 1039 } 1040 1041 parsedOpts := tcp.ParsedOptions() 1042 if synOptions.TS { 1043 // Echo the tsVal back to the peer in the tsEcr field of the 1044 // timestamp option. 1045 // Increment TSVal by 1 from the value sent in the SYN and echo 1046 // the TSVal in the SYN-ACK in the TSEcr field. 1047 opts := [12]byte{header.TCPOptionNOP, header.TCPOptionNOP} 1048 header.EncodeTSOption(synOptions.TSVal+1, parsedOpts.TSVal, opts[2:]) 1049 ackHeaders.TCPOpts = opts[:] 1050 } 1051 1052 // Send ACK. 1053 c.SendPacket(nil, ackHeaders) 1054 1055 c.Port = StackPort 1056 1057 return &RawEndpoint{ 1058 C: c, 1059 SrcPort: TestPort, 1060 DstPort: StackPort, 1061 Flags: header.TCPFlagPsh | header.TCPFlagAck, 1062 NextSeqNum: iss + 1, 1063 AckNum: c.IRS + 1, 1064 WndSize: rcvWnd, 1065 SACKPermitted: synOptions.SACKPermitted && c.SACKEnabled(), 1066 RecentTS: parsedOpts.TSVal, 1067 TSVal: synOptions.TSVal + 1, 1068 } 1069 } 1070 1071 // SACKEnabled returns true if the TCP Protocol option SACKEnabled is set to true 1072 // for the Stack in the context. 1073 func (c *Context) SACKEnabled() bool { 1074 var v tcp.SACKEnabled 1075 if err := c.Stack().TransportProtocolOption(tcp.ProtocolNumber, &v); err != nil { 1076 // Stack doesn't support SACK. So just return. 1077 return false 1078 } 1079 return bool(v) 1080 } 1081 1082 // SetGSOEnabled enables or disables generic segmentation offload. 1083 func (c *Context) SetGSOEnabled(enable bool) { 1084 c.linkEP.GSO = enable 1085 } 1086 1087 // MSSWithoutOptions returns the value for the MSS used by the stack when no 1088 // options are in use. 1089 func (c *Context) MSSWithoutOptions() uint16 { 1090 return uint16(c.linkEP.MTU() - header.IPv4MinimumSize - header.TCPMinimumSize) 1091 }