mirror of
https://github.com/golang/net.git
synced 2026-04-01 02:47:08 +09:00
Including mismatched function names/struct names, repeated words, typos, etc. Change-Id: Ia576274bce6e6fbfe4d2fca6dcd6d31bf00936fb Reviewed-on: https://go-review.googlesource.com/c/net/+/683875 Auto-Submit: Sean Liao <sean@liao.dev> Reviewed-by: Mark Freeman <markfreeman@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> Reviewed-by: Sean Liao <sean@liao.dev>
63 lines
2.3 KiB
Go
63 lines
2.3 KiB
Go
// Copyright 2025 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package quic
|
|
|
|
// skipState is state for optimistic ACK defenses.
|
|
//
|
|
// An endpoint performs an optimistic ACK attack by sending acknowledgements for packets
|
|
// which it has not received, potentially convincing the sender's congestion controller to
|
|
// send at rates beyond what the network supports.
|
|
//
|
|
// We defend against this by periodically skipping packet numbers.
|
|
// Receiving an ACK for an unsent packet number is a PROTOCOL_VIOLATION error.
|
|
//
|
|
// We only skip packet numbers in the Application Data number space.
|
|
// The total data sent in the Initial/Handshake spaces should generally fit into
|
|
// the initial congestion window.
|
|
//
|
|
// https://www.rfc-editor.org/rfc/rfc9000.html#section-21.4
|
|
type skipState struct {
|
|
// skip is the next packet number (in the Application Data space) we should skip.
|
|
skip packetNumber
|
|
|
|
// maxSkip is the maximum number of packets to send before skipping another number.
|
|
// Increases over time.
|
|
maxSkip int64
|
|
}
|
|
|
|
func (ss *skipState) init(c *Conn) {
|
|
ss.maxSkip = 256 // skip our first packet number within this range
|
|
ss.updateNumberSkip(c)
|
|
}
|
|
|
|
// shouldSkip returns whether we should skip the given packet number.
|
|
func (ss *skipState) shouldSkip(num packetNumber) bool {
|
|
return ss.skip == num
|
|
}
|
|
|
|
// updateNumberSkip schedules a packet to be skipped after skipping lastSkipped.
|
|
func (ss *skipState) updateNumberSkip(c *Conn) {
|
|
// Send at least this many packets before skipping.
|
|
// Limits the impact of skipping a little,
|
|
// plus allows most tests to ignore skipping.
|
|
const minSkip = 64
|
|
|
|
skip := minSkip + c.prng.Int64N(ss.maxSkip-minSkip)
|
|
ss.skip += packetNumber(skip)
|
|
|
|
// Double the size of the skip each time until we reach 128k.
|
|
// The idea here is that an attacker needs to correctly ack ~N packets in order
|
|
// to send an optimistic ack for another ~N packets.
|
|
// Skipping packet numbers comes with a small cost (it causes the receiver to
|
|
// send an immediate ACK rather than the usual delayed ACK), so we increase the
|
|
// time between skips as a connection's lifetime grows.
|
|
//
|
|
// The 128k cap is arbitrary, chosen so that we skip a packet number
|
|
// about once a second when sending full-size datagrams at 1Gbps.
|
|
if ss.maxSkip < 128*1024 {
|
|
ss.maxSkip *= 2
|
|
}
|
|
}
|