use std::fmt;
pub const MAX_SACK_RANGES: usize = 32;
const MIN_WIRE_LEN: usize = 14;
const FIXED_HDR_LEN: usize = 10;
const CONTINUATION_BYTES: usize = 8;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Sack {
pub largest_acked: u32,
pub ack_delay_us: u32,
ranges: Vec<(u32, u32)>,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum SackError {
Truncated,
TooManyRanges,
Malformed,
}
impl fmt::Display for SackError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Truncated => write!(f, "SACK payload too short for the declared range count"),
Self::TooManyRanges => write!(
f,
"SACK range_count exceeds the anti-DoS limit of {MAX_SACK_RANGES}"
),
Self::Malformed => write!(
f,
"SACK encoding is malformed (zero ranges, adjacent ranges, underflow, or overlapping ranges)"
),
}
}
}
impl std::error::Error for SackError {}
impl Sack {
pub fn from_received(received: &[u32], ack_delay_us: u32) -> Option<Sack> {
if received.is_empty() {
return None;
}
let mut seqs: Vec<u32> = received.to_vec();
seqs.sort_unstable();
let mut asc_ranges: Vec<(u32, u32)> = Vec::new();
for seq in seqs {
match asc_ranges.last_mut() {
Some(last) if seq <= last.1.saturating_add(1) => {
if seq > last.1 {
last.1 = seq;
}
}
_ => asc_ranges.push((seq, seq)),
}
}
Self::from_ascending_coalesced(asc_ranges, ack_delay_us)
}
pub fn from_inclusive_ranges(mut ranges: Vec<(u32, u32)>, ack_delay_us: u32) -> Option<Sack> {
if ranges.is_empty() {
return None;
}
ranges.sort_unstable_by_key(|&(lo, _)| lo);
let mut asc: Vec<(u32, u32)> = Vec::with_capacity(ranges.len());
for (lo, hi) in ranges {
match asc.last_mut() {
Some(last) if lo <= last.1.saturating_add(1) => {
if hi > last.1 {
last.1 = hi;
}
}
_ => asc.push((lo, hi)),
}
}
Self::from_ascending_coalesced(asc, ack_delay_us)
}
fn from_ascending_coalesced(
mut asc_ranges: Vec<(u32, u32)>,
ack_delay_us: u32,
) -> Option<Sack> {
if asc_ranges.is_empty() {
return None;
}
asc_ranges.reverse();
asc_ranges.truncate(MAX_SACK_RANGES);
let largest_acked = asc_ranges[0].1;
Some(Sack {
largest_acked,
ack_delay_us,
ranges: asc_ranges,
})
}
pub fn ranges(&self) -> &[(u32, u32)] {
&self.ranges
}
pub fn to_wire(&self) -> Vec<u8> {
let range_count = self.ranges.len();
let capacity = FIXED_HDR_LEN + 4 + CONTINUATION_BYTES * range_count.saturating_sub(1);
let mut buf = Vec::with_capacity(capacity);
buf.extend_from_slice(&self.largest_acked.to_be_bytes());
buf.extend_from_slice(&self.ack_delay_us.to_be_bytes());
#[allow(clippy::cast_possible_truncation)]
let range_count_wire = (range_count.min(u16::MAX as usize)) as u16;
buf.extend_from_slice(&range_count_wire.to_be_bytes());
let (first_low, first_high) = self.ranges[0];
let first_len: u32 = first_high - first_low;
buf.extend_from_slice(&first_len.to_be_bytes());
let mut prev_low = first_low;
for &(low, high) in &self.ranges[1..] {
let gap: u32 = prev_low.saturating_sub(1).saturating_sub(high);
buf.extend_from_slice(&gap.to_be_bytes());
let len: u32 = high - low;
buf.extend_from_slice(&len.to_be_bytes());
prev_low = low;
}
buf
}
pub fn from_wire(buf: &[u8]) -> Result<Sack, SackError> {
if buf.len() < MIN_WIRE_LEN {
return Err(SackError::Truncated);
}
let largest_acked = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]);
let ack_delay_us = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]);
let range_count = u16::from_be_bytes([buf[8], buf[9]]) as usize;
if range_count == 0 {
return Err(SackError::Malformed);
}
if range_count > MAX_SACK_RANGES {
return Err(SackError::TooManyRanges);
}
let needed = FIXED_HDR_LEN
.checked_add(4)
.and_then(|n| n.checked_add(CONTINUATION_BYTES * (range_count - 1)))
.ok_or(SackError::Truncated)?;
if buf.len() < needed {
return Err(SackError::Truncated);
}
let first_len = u32::from_be_bytes([buf[10], buf[11], buf[12], buf[13]]);
let first_high = largest_acked;
let first_low = largest_acked
.checked_sub(first_len)
.ok_or(SackError::Malformed)?;
let mut ranges: Vec<(u32, u32)> = Vec::with_capacity(range_count);
ranges.push((first_low, first_high));
let mut prev_low = first_low;
let mut pos = 14usize; for _ in 1..range_count {
let gap = u32::from_be_bytes([buf[pos], buf[pos + 1], buf[pos + 2], buf[pos + 3]]);
let len = u32::from_be_bytes([buf[pos + 4], buf[pos + 5], buf[pos + 6], buf[pos + 7]]);
pos += 8;
if gap == 0 {
return Err(SackError::Malformed);
}
let below_prev = prev_low.checked_sub(1).ok_or(SackError::Malformed)?;
let high = below_prev.checked_sub(gap).ok_or(SackError::Malformed)?;
let low = high.checked_sub(len).ok_or(SackError::Malformed)?;
if low > high {
return Err(SackError::Malformed);
}
ranges.push((low, high));
prev_low = low;
}
Ok(Sack {
largest_acked,
ack_delay_us,
ranges,
})
}
pub fn acks(&self, seq: u32) -> bool {
for &(low, high) in &self.ranges {
if seq >= low && seq <= high {
return true;
}
}
false
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn coalesces_to_descending_ranges() {
let sack = Sack::from_received(&[5, 6, 7, 10, 11, 3], 0).unwrap();
assert_eq!(sack.largest_acked, 11);
assert_eq!(sack.ranges(), &[(10, 11), (5, 7), (3, 3)]);
}
#[test]
fn from_received_empty_returns_none() {
assert!(Sack::from_received(&[], 42).is_none());
}
#[test]
fn from_received_single_seq() {
let sack = Sack::from_received(&[7], 100).unwrap();
assert_eq!(sack.largest_acked, 7);
assert_eq!(sack.ranges(), &[(7, 7)]);
}
#[test]
fn from_received_contiguous() {
let input: Vec<u32> = (0..=9).collect();
let sack = Sack::from_received(&input, 0).unwrap();
assert_eq!(sack.largest_acked, 9);
assert_eq!(sack.ranges(), &[(0, 9)]);
}
#[test]
fn from_received_duplicate_seqs_coalesced() {
let sack = Sack::from_received(&[3, 3, 3, 5, 5], 0).unwrap();
assert_eq!(sack.ranges(), &[(5, 5), (3, 3)]);
}
#[test]
fn from_received_caps_ranges_to_max_and_stays_decodable() {
let seqs: Vec<u32> = (0u32..40).map(|i| i * 2).collect();
let sack = Sack::from_received(&seqs, 0).expect("non-empty");
assert!(
sack.ranges().len() <= MAX_SACK_RANGES,
"generated SACK must be capped to MAX_SACK_RANGES, got {}",
sack.ranges().len()
);
assert_eq!(sack.largest_acked, 78);
assert_eq!(sack.ranges().len(), MAX_SACK_RANGES);
assert_eq!(sack.ranges()[0], (78, 78));
assert_eq!(sack.ranges()[MAX_SACK_RANGES - 1], (16, 16));
let wire = sack.to_wire();
let decoded = Sack::from_wire(&wire).expect("a capped SACK must decode at the peer");
assert_eq!(decoded, sack);
}
#[test]
fn from_inclusive_ranges_caps_and_keeps_highest() {
let asc: Vec<(u32, u32)> = (0u32..40).map(|i| (i * 2, i * 2)).collect();
let sack = Sack::from_inclusive_ranges(asc, 7).expect("non-empty");
assert_eq!(sack.ack_delay_us, 7);
assert_eq!(sack.ranges().len(), MAX_SACK_RANGES);
assert_eq!(sack.largest_acked, 78);
assert_eq!(sack.ranges()[0], (78, 78));
assert_eq!(Sack::from_wire(&sack.to_wire()).expect("decode"), sack);
}
#[test]
fn from_inclusive_ranges_coalesces_and_orders() {
let sack = Sack::from_inclusive_ranges(vec![(6, 7), (0, 1), (4, 5)], 0).expect("non-empty");
assert_eq!(sack.ranges(), &[(4, 7), (0, 1)]);
assert_eq!(sack.largest_acked, 7);
assert_eq!(Sack::from_wire(&sack.to_wire()).expect("decode"), sack);
}
#[test]
fn from_inclusive_ranges_empty_is_none() {
assert!(Sack::from_inclusive_ranges(Vec::new(), 0).is_none());
}
#[test]
fn roundtrip_multi_gap() {
let sack =
Sack::from_received(&[20, 21, 22, 23, 24, 25, 10, 11, 12, 13, 1, 2, 3], 1234).unwrap();
assert_eq!(sack.ranges(), &[(20, 25), (10, 13), (1, 3)]);
let wire = sack.to_wire();
let decoded = Sack::from_wire(&wire).expect("should decode");
assert_eq!(decoded, sack);
}
#[test]
fn roundtrip_single_contiguous() {
let sack = Sack::from_received(&(0u32..=9).collect::<Vec<_>>(), 0).unwrap();
assert_eq!(sack.ranges(), &[(0, 9)]);
let wire = sack.to_wire();
let decoded = Sack::from_wire(&wire).expect("roundtrip single");
assert_eq!(decoded, sack);
}
#[test]
fn roundtrip_degenerate_single_seq() {
let sack = Sack::from_received(&[42], 999).unwrap();
assert_eq!(sack.largest_acked, 42);
let wire = sack.to_wire();
let decoded = Sack::from_wire(&wire).expect("roundtrip single seq");
assert_eq!(decoded, sack);
}
#[test]
fn roundtrip_from_received_coalesced() {
let input = [5u32, 6, 7, 10, 11, 3];
let sack = Sack::from_received(&input, 500).unwrap();
let wire = sack.to_wire();
let decoded = Sack::from_wire(&wire).expect("from_received roundtrip");
assert_eq!(decoded, sack);
}
#[test]
fn roundtrip_preserves_ack_delay() {
let sack = Sack::from_received(&[1, 2, 3], 0xDEAD_BEEF).unwrap();
let wire = sack.to_wire();
let decoded = Sack::from_wire(&wire).expect("roundtrip ack_delay");
assert_eq!(decoded.ack_delay_us, 0xDEAD_BEEF);
}
#[test]
fn roundtrip_large_span_exceeds_u16() {
let seqs: Vec<u32> = (0u32..=100_000).collect();
let sack = Sack::from_received(&seqs, 0).unwrap();
assert_eq!(sack.largest_acked, 100_000);
assert_eq!(sack.ranges(), &[(0, 100_000)]);
let wire = sack.to_wire();
let decoded = Sack::from_wire(&wire).expect("large span must round-trip");
assert_eq!(decoded, sack);
let first_len_wire = u32::from_be_bytes([wire[10], wire[11], wire[12], wire[13]]);
assert_eq!(first_len_wire, 100_000u32);
}
#[test]
fn roundtrip_large_gap_exceeds_u16() {
let sack = Sack::from_received(&[200_000u32, 0], 0).unwrap();
assert_eq!(sack.ranges(), &[(200_000, 200_000), (0, 0)]);
let wire = sack.to_wire();
let decoded = Sack::from_wire(&wire).expect("large gap must round-trip");
assert_eq!(decoded, sack);
let gap_wire = u32::from_be_bytes([wire[14], wire[15], wire[16], wire[17]]);
assert_eq!(gap_wire, 199_999u32);
}
#[test]
fn decode_gap_zero_is_malformed() {
let mut buf = vec![0u8; 22]; buf[0..4].copy_from_slice(&10u32.to_be_bytes()); buf[4..8].copy_from_slice(&0u32.to_be_bytes()); buf[8..10].copy_from_slice(&2u16.to_be_bytes()); buf[10..14].copy_from_slice(&0u32.to_be_bytes()); buf[14..18].copy_from_slice(&0u32.to_be_bytes()); buf[18..22].copy_from_slice(&0u32.to_be_bytes()); assert!(
matches!(Sack::from_wire(&buf), Err(SackError::Malformed)),
"gap == 0 must be rejected as Malformed"
);
}
#[test]
fn acks_correctness_across_gaps() {
let sack = Sack::from_received(&[5, 6, 7, 10, 11, 3], 0).unwrap();
for seq in [3u32, 5, 6, 7, 10, 11] {
assert!(sack.acks(seq), "expected seq {seq} to be ACKed");
}
for seq in [0u32, 1, 2, 4, 8, 9, 12, 100] {
assert!(!sack.acks(seq), "expected seq {seq} to NOT be ACKed");
}
}
#[test]
fn acks_single_seq() {
let sack = Sack::from_received(&[99], 0).unwrap();
assert!(sack.acks(99));
assert!(!sack.acks(98));
assert!(!sack.acks(100));
}
#[test]
fn decode_truncated_too_short() {
let buf = [0u8; 13];
assert!(
matches!(Sack::from_wire(&buf), Err(SackError::Truncated)),
"expected Truncated for 13-byte buffer"
);
}
#[test]
fn decode_truncated_claimed_ranges_exceed_buffer() {
let mut buf = vec![0u8; 14];
buf[0..4].copy_from_slice(&10u32.to_be_bytes());
buf[4..8].copy_from_slice(&0u32.to_be_bytes());
buf[8..10].copy_from_slice(&2u16.to_be_bytes());
buf[10..14].copy_from_slice(&0u32.to_be_bytes());
assert!(
matches!(Sack::from_wire(&buf), Err(SackError::Truncated)),
"expected Truncated when buffer too small for claimed ranges"
);
}
#[test]
fn decode_too_many_ranges() {
let bad_count = (MAX_SACK_RANGES + 1) as u16;
let needed = FIXED_HDR_LEN + 4 + CONTINUATION_BYTES * MAX_SACK_RANGES; let mut buf = vec![0u8; needed + CONTINUATION_BYTES]; buf[0..4].copy_from_slice(&u32::MAX.to_be_bytes());
buf[4..8].copy_from_slice(&0u32.to_be_bytes());
buf[8..10].copy_from_slice(&bad_count.to_be_bytes());
assert!(
matches!(Sack::from_wire(&buf), Err(SackError::TooManyRanges)),
"expected TooManyRanges for range_count = MAX+1"
);
}
#[test]
fn decode_zero_range_count_is_malformed() {
let mut buf = vec![0u8; 14];
buf[8..10].copy_from_slice(&0u16.to_be_bytes()); assert!(
matches!(Sack::from_wire(&buf), Err(SackError::Malformed)),
"expected Malformed for range_count == 0"
);
}
#[test]
fn decode_first_len_underflow_is_malformed() {
let mut buf = vec![0u8; 14];
buf[0..4].copy_from_slice(&3u32.to_be_bytes()); buf[4..8].copy_from_slice(&0u32.to_be_bytes());
buf[8..10].copy_from_slice(&1u16.to_be_bytes()); buf[10..14].copy_from_slice(&5u32.to_be_bytes()); assert!(
matches!(Sack::from_wire(&buf), Err(SackError::Malformed)),
"expected Malformed when first_len underflows"
);
}
#[test]
fn decode_continuation_gap_underflow_is_malformed() {
let mut buf = vec![0u8; 22]; buf[0..4].copy_from_slice(&5u32.to_be_bytes()); buf[4..8].copy_from_slice(&0u32.to_be_bytes());
buf[8..10].copy_from_slice(&2u16.to_be_bytes()); buf[10..14].copy_from_slice(&0u32.to_be_bytes()); buf[14..18].copy_from_slice(&10u32.to_be_bytes()); buf[18..22].copy_from_slice(&0u32.to_be_bytes()); assert!(
matches!(Sack::from_wire(&buf), Err(SackError::Malformed)),
"expected Malformed when continuation gap underflows"
);
}
#[test]
fn wire_size_1_range() {
let sack = Sack::from_received(&[5], 0).unwrap();
assert_eq!(sack.to_wire().len(), 14);
}
#[test]
fn wire_size_2_ranges() {
let sack = Sack::from_received(&[8, 9, 10, 3, 4, 5], 0).unwrap();
assert_eq!(sack.ranges(), &[(8, 10), (3, 5)]);
assert_eq!(sack.to_wire().len(), 22);
}
#[test]
fn wire_size_n_ranges() {
let mut seqs: Vec<u32> = Vec::new();
for i in 0u32..5 {
for s in (i * 20)..(i * 20 + 10) {
seqs.push(s);
}
}
let sack = Sack::from_received(&seqs, 0).unwrap();
let n = sack.ranges().len();
assert_eq!(n, 5);
assert_eq!(sack.to_wire().len(), 10 + 4 + 8 * (n - 1));
}
#[test]
fn sack_error_display_is_non_empty() {
for e in [
SackError::Truncated,
SackError::TooManyRanges,
SackError::Malformed,
] {
let s = e.to_string();
assert!(!s.is_empty(), "Display must not be empty for {e:?}");
}
}
#[test]
fn sack_error_is_std_error() {
let e: &dyn std::error::Error = &SackError::Truncated;
assert!(e.source().is_none());
}
}