netstack: zero window probes must have a payload

Note that this implements Linux-like behavior that differs from RFC 9293
3.8.6.1. We do not send the next byte in the stream as a probe. We instead use
a previously ACKed sequence number with a junk payload that the receiver must
respond to.

Fixes #10243.

PiperOrigin-RevId: 622966365
This commit is contained in:
Kevin Krakauer
2024-04-08 15:24:00 -07:00
committed by gVisor bot
parent e23b5a711a
commit 91a283f8fa
2 changed files with 18 additions and 4 deletions
+17 -3
View File
@@ -20,6 +20,7 @@ import (
"sort"
"time"
"gvisor.dev/gvisor/pkg/buffer"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/header"
@@ -904,12 +905,25 @@ func (s *sender) maybeSendSegment(seg *segment, limit int, end seqnum.Value) (se
return true
}
// zeroProbeJunk is data sent during zero window probes. Its value is
// irrelevant; since the sequence number has already been acknowledged it will
// be discarded. It's only here to avoid allocating.
var zeroProbeJunk = []byte{0}
// +checklocks:s.ep.mu
func (s *sender) sendZeroWindowProbe() {
s.unackZeroWindowProbes++
// Send a zero window probe with sequence number pointing to
// the last acknowledged byte.
s.sendEmptySegment(header.TCPFlagAck, s.SndUna-1)
// Send a zero window probe with sequence number pointing to the last
// acknowledged byte. Note that, like Linux, this isn't quite what RFC
// 9293 3.8.6.1 describes: we don't send the next byte in the stream,
// we re-send an ACKed byte to goad the receiver into responding.
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
Payload: buffer.MakeWithData(zeroProbeJunk),
})
defer pkt.DecRef()
s.sendSegmentFromPacketBuffer(pkt, header.TCPFlagAck, s.SndUna-1)
// Rearm the timer to continue probing.
s.resendTimer.enable(s.RTO)
}
+1 -1
View File
@@ -2914,7 +2914,7 @@ func TestZeroWindowSend(t *testing.T) {
defer b.Release()
iss := seqnum.Value(context.TestInitialSequenceNumber).Add(1)
checker.IPv4(t, b,
checker.PayloadLen(header.TCPMinimumSize),
checker.PayloadLen(header.TCPMinimumSize+1),
checker.TCP(
checker.DstPort(context.TestPort),
checker.TCPSeqNum(uint32(c.IRS)),