parent
5eb522193c
commit
b0a1bbd3e2
|
@ -299,6 +299,15 @@ func (h *handshake) synRcvdState(s *segment) *tcpip.Error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RFC 793, Section 3.9, page 69, states that in the SYN-RCVD state, a
|
||||
// sequence number outside of the window causes an ACK with the proper seq
|
||||
// number and "After sending the acknowledgment, drop the unacceptable
|
||||
// segment and return."
|
||||
if !s.sequenceNumber.InWindow(h.ackNum, h.rcvWnd) {
|
||||
h.ep.sendRaw(buffer.VectorisedView{}, header.TCPFlagAck, h.iss+1, h.ackNum, h.rcvWnd)
|
||||
return nil
|
||||
}
|
||||
|
||||
if s.flagIsSet(header.TCPFlagSyn) && s.sequenceNumber != h.ackNum-1 {
|
||||
// We received two SYN segments with different sequence
|
||||
// numbers, so we reset this and restart the whole
|
||||
|
|
|
@ -4673,7 +4673,7 @@ func TestListenSynRcvdQueueFull(t *testing.T) {
|
|||
SrcPort: context.TestPort,
|
||||
DstPort: context.StackPort,
|
||||
Flags: header.TCPFlagSyn,
|
||||
SeqNum: seqnum.Value(789),
|
||||
SeqNum: irs,
|
||||
RcvWnd: 30000,
|
||||
})
|
||||
|
||||
|
@ -4825,6 +4825,125 @@ func TestListenBacklogFullSynCookieInUse(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSynRcvdBadSeqNumber(t *testing.T) {
|
||||
c := context.New(t, defaultMTU)
|
||||
defer c.Cleanup()
|
||||
|
||||
// Create TCP endpoint.
|
||||
var err *tcpip.Error
|
||||
c.EP, err = c.Stack().NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, &c.WQ)
|
||||
if err != nil {
|
||||
t.Fatalf("NewEndpoint failed: %s", err)
|
||||
}
|
||||
|
||||
// Bind to wildcard.
|
||||
if err := c.EP.Bind(tcpip.FullAddress{Port: context.StackPort}); err != nil {
|
||||
t.Fatalf("Bind failed: %s", err)
|
||||
}
|
||||
|
||||
// Start listening.
|
||||
if err := c.EP.Listen(10); err != nil {
|
||||
t.Fatalf("Listen failed: %s", err)
|
||||
}
|
||||
|
||||
// Send a SYN to get a SYN-ACK. This should put the ep into SYN-RCVD state
|
||||
irs := seqnum.Value(789)
|
||||
c.SendPacket(nil, &context.Headers{
|
||||
SrcPort: context.TestPort,
|
||||
DstPort: context.StackPort,
|
||||
Flags: header.TCPFlagSyn,
|
||||
SeqNum: irs,
|
||||
RcvWnd: 30000,
|
||||
})
|
||||
|
||||
// Receive the SYN-ACK reply.
|
||||
b := c.GetPacket()
|
||||
tcpHdr := header.TCP(header.IPv4(b).Payload())
|
||||
iss := seqnum.Value(tcpHdr.SequenceNumber())
|
||||
tcpCheckers := []checker.TransportChecker{
|
||||
checker.SrcPort(context.StackPort),
|
||||
checker.DstPort(context.TestPort),
|
||||
checker.TCPFlags(header.TCPFlagAck | header.TCPFlagSyn),
|
||||
checker.AckNum(uint32(irs) + 1),
|
||||
}
|
||||
checker.IPv4(t, b, checker.TCP(tcpCheckers...))
|
||||
|
||||
// Now send a packet with an out-of-window sequence number
|
||||
largeSeqnum := irs + seqnum.Value(tcpHdr.WindowSize()) + 1
|
||||
c.SendPacket(nil, &context.Headers{
|
||||
SrcPort: context.TestPort,
|
||||
DstPort: context.StackPort,
|
||||
Flags: header.TCPFlagAck,
|
||||
SeqNum: largeSeqnum,
|
||||
AckNum: iss + 1,
|
||||
RcvWnd: 30000,
|
||||
})
|
||||
|
||||
// Should receive an ACK with the expected SEQ number
|
||||
b = c.GetPacket()
|
||||
tcpCheckers = []checker.TransportChecker{
|
||||
checker.SrcPort(context.StackPort),
|
||||
checker.DstPort(context.TestPort),
|
||||
checker.TCPFlags(header.TCPFlagAck),
|
||||
checker.AckNum(uint32(irs) + 1),
|
||||
checker.SeqNum(uint32(iss + 1)),
|
||||
}
|
||||
checker.IPv4(t, b, checker.TCP(tcpCheckers...))
|
||||
|
||||
// Now that the socket replied appropriately with the ACK,
|
||||
// complete the connection to test that the large SEQ num
|
||||
// did not change the state from SYN-RCVD.
|
||||
|
||||
// Send ACK to move to ESTABLISHED state.
|
||||
c.SendPacket(nil, &context.Headers{
|
||||
SrcPort: context.TestPort,
|
||||
DstPort: context.StackPort,
|
||||
Flags: header.TCPFlagAck,
|
||||
SeqNum: irs + 1,
|
||||
AckNum: iss + 1,
|
||||
RcvWnd: 30000,
|
||||
})
|
||||
|
||||
newEP, _, err := c.EP.Accept()
|
||||
|
||||
if err != nil && err != tcpip.ErrWouldBlock {
|
||||
t.Fatalf("Accept failed: %s", err)
|
||||
}
|
||||
|
||||
if err == tcpip.ErrWouldBlock {
|
||||
// Try to accept the connections in the backlog.
|
||||
we, ch := waiter.NewChannelEntry(nil)
|
||||
c.WQ.EventRegister(&we, waiter.EventIn)
|
||||
defer c.WQ.EventUnregister(&we)
|
||||
|
||||
// Wait for connection to be established.
|
||||
select {
|
||||
case <-ch:
|
||||
newEP, _, err = c.EP.Accept()
|
||||
if err != nil {
|
||||
t.Fatalf("Accept failed: %s", err)
|
||||
}
|
||||
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatalf("Timed out waiting for accept")
|
||||
}
|
||||
}
|
||||
|
||||
// Now verify that the TCP socket is usable and in a connected state.
|
||||
data := "Don't panic"
|
||||
_, _, err = newEP.Write(tcpip.SlicePayload(buffer.NewViewFromBytes([]byte(data))), tcpip.WriteOptions{})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Write failed: %s", err)
|
||||
}
|
||||
|
||||
pkt := c.GetPacket()
|
||||
tcpHdr = header.TCP(header.IPv4(pkt).Payload())
|
||||
if string(tcpHdr.Payload()) != data {
|
||||
t.Fatalf("Unexpected data: got %s, want %s", string(tcpHdr.Payload()), data)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPassiveConnectionAttemptIncrement(t *testing.T) {
|
||||
c := context.New(t, defaultMTU)
|
||||
defer c.Cleanup()
|
||||
|
|
Loading…
Reference in New Issue