| // 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) |
| } |
| |
| // shouldSkipAfter 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 |
| } |
| } |