Test handling segments on completed but not yet accepted TCP connections

This change does not introduce any new features, or modify existing ones.

This change tests handling TCP segments right away for connections that were
completed from a listening endpoint.

PiperOrigin-RevId: 282986457
This commit is contained in:
Ghanan Gowripalan
2019-11-28 17:15:07 -08:00
committed by gVisor bot
parent 684f757a22
commit 10bbcf97d2
2 changed files with 127 additions and 1 deletions
+121 -1
View File
@@ -792,6 +792,82 @@ func TestSendRstOnListenerRxSynAckV6(t *testing.T) {
checker.SeqNum(200)))
}
// TestTCPAckBeforeAcceptV4 tests that once the 3-way handshake is complete,
// peers can send data and expect a response within a reasonable ammount of time
// without calling Accept on the listening endpoint first.
//
// This test uses IPv4.
func TestTCPAckBeforeAcceptV4(t *testing.T) {
c := context.New(t, defaultMTU)
defer c.Cleanup()
c.Create(-1)
if err := c.EP.Bind(tcpip.FullAddress{Port: context.StackPort}); err != nil {
t.Fatal("Bind failed:", err)
}
if err := c.EP.Listen(10); err != nil {
t.Fatal("Listen failed:", err)
}
irs, iss := executeHandshake(t, c, context.TestPort, false /* synCookiesInUse */)
// Send data before accepting the connection.
c.SendPacket([]byte{1, 2, 3, 4}, &context.Headers{
SrcPort: context.TestPort,
DstPort: context.StackPort,
Flags: header.TCPFlagAck,
SeqNum: irs + 1,
AckNum: iss + 1,
})
// Receive ACK for the data we sent.
checker.IPv4(t, c.GetPacket(), checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagAck),
checker.SeqNum(uint32(iss+1)),
checker.AckNum(uint32(irs+5))))
}
// TestTCPAckBeforeAcceptV6 tests that once the 3-way handshake is complete,
// peers can send data and expect a response within a reasonable ammount of time
// without calling Accept on the listening endpoint first.
//
// This test uses IPv6.
func TestTCPAckBeforeAcceptV6(t *testing.T) {
c := context.New(t, defaultMTU)
defer c.Cleanup()
c.CreateV6Endpoint(true)
if err := c.EP.Bind(tcpip.FullAddress{Port: context.StackPort}); err != nil {
t.Fatal("Bind failed:", err)
}
if err := c.EP.Listen(10); err != nil {
t.Fatal("Listen failed:", err)
}
irs, iss := executeV6Handshake(t, c, context.TestPort, false /* synCookiesInUse */)
// Send data before accepting the connection.
c.SendV6Packet([]byte{1, 2, 3, 4}, &context.Headers{
SrcPort: context.TestPort,
DstPort: context.StackPort,
Flags: header.TCPFlagAck,
SeqNum: irs + 1,
AckNum: iss + 1,
})
// Receive ACK for the data we sent.
checker.IPv6(t, c.GetV6Packet(), checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPFlags(header.TCPFlagAck),
checker.SeqNum(uint32(iss+1)),
checker.AckNum(uint32(irs+5))))
}
func TestSendRstOnListenerRxAckV4(t *testing.T) {
c := context.New(t, defaultMTU)
defer c.Cleanup()
@@ -4303,7 +4379,7 @@ func executeHandshake(t *testing.T, c *context.Context, srcPort uint16, synCooki
RcvWnd: 30000,
})
// Receive the SYN-ACK reply.w
// Receive the SYN-ACK reply.
b := c.GetPacket()
tcp := header.TCP(header.IPv4(b).Payload())
iss = seqnum.Value(tcp.SequenceNumber())
@@ -4336,6 +4412,50 @@ func executeHandshake(t *testing.T, c *context.Context, srcPort uint16, synCooki
return irs, iss
}
func executeV6Handshake(t *testing.T, c *context.Context, srcPort uint16, synCookieInUse bool) (irs, iss seqnum.Value) {
// Send a SYN request.
irs = seqnum.Value(789)
c.SendV6Packet(nil, &context.Headers{
SrcPort: srcPort,
DstPort: context.StackPort,
Flags: header.TCPFlagSyn,
SeqNum: irs,
RcvWnd: 30000,
})
// Receive the SYN-ACK reply.
b := c.GetV6Packet()
tcp := header.TCP(header.IPv6(b).Payload())
iss = seqnum.Value(tcp.SequenceNumber())
tcpCheckers := []checker.TransportChecker{
checker.SrcPort(context.StackPort),
checker.DstPort(srcPort),
checker.TCPFlags(header.TCPFlagAck | header.TCPFlagSyn),
checker.AckNum(uint32(irs) + 1),
}
if synCookieInUse {
// When cookies are in use window scaling is disabled.
tcpCheckers = append(tcpCheckers, checker.TCPSynOptions(header.TCPSynOptions{
WS: -1,
MSS: c.MSSWithoutOptionsV6(),
}))
}
checker.IPv6(t, b, checker.TCP(tcpCheckers...))
// Send ACK.
c.SendV6Packet(nil, &context.Headers{
SrcPort: srcPort,
DstPort: context.StackPort,
Flags: header.TCPFlagAck,
SeqNum: irs + 1,
AckNum: iss + 1,
RcvWnd: 30000,
})
return irs, iss
}
// TestListenBacklogFull tests that netstack does not complete handshakes if the
// listen backlog for the endpoint is full.
func TestListenBacklogFull(t *testing.T) {
@@ -1089,3 +1089,9 @@ func (c *Context) SetGSOEnabled(enable bool) {
func (c *Context) MSSWithoutOptions() uint16 {
return uint16(c.linkEP.MTU() - header.IPv4MinimumSize - header.TCPMinimumSize)
}
// MSSWithoutOptionsV6 returns the value for the MSS used by the stack when no
// options are in use for IPv6 packets.
func (c *Context) MSSWithoutOptionsV6() uint16 {
return uint16(c.linkEP.MTU() - header.IPv6MinimumSize - header.TCPMinimumSize)
}