/// If the frame causes a recipient to generate an ACK within its /// advertised maximum acknowledgement delay. #[must_use] pubconstfn ack_eliciting(&self) -> bool {
!matches!( self, Self::Ack { .. } | Self::Padding { .. } | Self::ConnectionClose { .. }
)
}
/// If the frame can be sent in a path probe /// without initiating migration to that path. #[must_use] pubconstfn path_probing(&self) -> bool {
matches!( self, Self::Padding { .. }
| Self::NewConnectionId { .. }
| Self::PathChallenge { .. }
| Self::PathResponse { .. }
)
}
/// Converts `AckRanges` as encoded in a ACK frame (see -transport /// 19.3.1) into ranges of acked packets (end, start), inclusive of /// start and end values. /// /// # Errors /// /// Returns an error if the ranges are invalid. pubfn decode_ack_frame(
largest_acked: u64,
first_ack_range: u64,
ack_ranges: &[AckRange],
) -> Res<Vec<RangeInclusive<u64>>> { letmut acked_ranges = Vec::with_capacity(ack_ranges.len() + 1);
if largest_acked < first_ack_range { return Err(Error::FrameEncoding);
}
acked_ranges.push((largest_acked - first_ack_range)..=largest_acked); if !ack_ranges.is_empty() && largest_acked < first_ack_range + 1 { return Err(Error::FrameEncoding);
} letmut cur = if ack_ranges.is_empty() { 0
} else {
largest_acked - first_ack_range - 1
}; for r in ack_ranges { if cur < r.gap + 1 { return Err(Error::FrameEncoding);
}
cur = cur - r.gap - 1;
if cur < r.range { return Err(Error::FrameEncoding);
}
acked_ranges.push((cur - r.range)..=cur);
if cur > r.range + 1 {
cur -= r.range + 1;
} else {
cur -= r.range;
}
}
/// # Errors /// /// Returns an error if the frame cannot be decoded. #[expect(
clippy::too_many_lines,
reason = "Yeah, but it's a nice match statement."
)] pubfn decode(dec: &mut Decoder<'a>) -> Res<Self> { /// Maximum ACK Range Count in ACK Frame /// /// Given a max UDP datagram size of 64k bytes and a minimum ACK Range size of 2 /// bytes (2 QUIC varints), a single datagram can at most contain 32k ACK /// Ranges. /// /// Note that the maximum (jumbogram) Ethernet MTU of 9216 or on the /// Internet the regular Ethernet MTU of 1518 are more realistically to /// be the limiting factor. Though for simplicity the higher limit is chosen. const MAX_ACK_RANGE_COUNT: u64 = 32 * 1024;
fn decode_ack<'a>(dec: &mut Decoder<'a>, ecn: bool) -> Res<Frame<'a>> { let la = dv(dec)?; let ad = dv(dec)?; let nr = dv(dec).and_then(|nr| { if nr < MAX_ACK_RANGE_COUNT {
Ok(nr)
} else {
Err(Error::TooMuchData)
}
})?; let fa = dv(dec)?; letmut arr: Vec<AckRange> = Vec::with_capacity(usize::try_from(nr)?); for _ in0..nr { let ar = AckRange {
gap: dv(dec)?,
range: dv(dec)?,
};
arr.push(ar);
}
// Now check for the values for ACK_ECN. let ecn_count = ecn
.then(|| -> Res<ecn::Count> {
Ok(ecn::Count::new(0, dv(dec)?, dv(dec)?, dv(dec)?))
})
.transpose()?;
// Check for minimal encoding of frame type. let pos = dec.offset(); let t = dv(dec)?; // RFC 9000, Section 12.4: // // The Frame Type field uses a variable-length integer encoding [...], // with one exception. To ensure simple and efficient implementations of // frame parsing, a frame type MUST use the shortest possible encoding. if Encoder::varint_len(t) != dec.offset() - pos { return Err(Error::ProtocolViolation);
}
let t = t.try_into()?; match t {
FrameType::Padding => { // t itself + any additional `Frame::Padding`
(1 + dec.skip_while(u8::from(FrameType::Padding)))
.try_into()
.map(Self::Padding)
.map_err(|_| Error::TooMuchData)
}
FrameType::Ping => Ok(Self::Ping),
FrameType::ResetStream => Ok(Self::ResetStream {
stream_id: StreamId::from(dv(dec)?),
application_error_code: dv(dec)?,
final_size: dv(dec)?,
}),
FrameType::Ack => decode_ack(dec, false),
FrameType::AckEcn => decode_ack(dec, true),
FrameType::StopSending => Ok(Self::StopSending {
stream_id: StreamId::from(dv(dec)?),
application_error_code: dv(dec)?,
}),
FrameType::Crypto => { let offset = dv(dec)?; let data = d(dec.decode_vvec())?; if offset + u64::try_from(data.len())? > MAX_VARINT { return Err(Error::FrameEncoding);
}
Ok(Self::Crypto { offset, data })
}
FrameType::NewToken => { let token = d(dec.decode_vvec())?; if token.is_empty() { return Err(Error::FrameEncoding);
}
Ok(Self::NewToken { token })
}
FrameType::Stream
| FrameType::StreamWithFin
| FrameType::StreamWithLen
| FrameType::StreamWithLenFin
| FrameType::StreamWithOff
| FrameType::StreamWithOffFin
| FrameType::StreamWithOffLen
| FrameType::StreamWithOffLenFin => { let s = dv(dec)?; let o = if t.is_stream_with_offset() {
dv(dec)?
} else { 0
}; let fill = !t.is_stream_with_length(); let data = if fill {
qtrace!("STREAM frame, extends to the end of the packet");
dec.decode_remainder()
} else {
qtrace!("STREAM frame, with length");
d(dec.decode_vvec())?
}; if o + u64::try_from(data.len())? > MAX_VARINT { return Err(Error::FrameEncoding);
}
Ok(Self::Stream {
fin: t.is_stream_with_fin(),
stream_id: StreamId::from(s),
offset: o,
data,
fill,
})
}
FrameType::MaxData => Ok(Self::MaxData {
maximum_data: dv(dec)?,
}),
FrameType::MaxStreamData => Ok(Self::MaxStreamData {
stream_id: StreamId::from(dv(dec)?),
maximum_stream_data: dv(dec)?,
}),
FrameType::MaxStreamsBiDi | FrameType::MaxStreamsUniDi => { let m = dv(dec)?; if m > (1 << 60) { return Err(Error::StreamLimit);
}
Ok(Self::MaxStreams {
stream_type: t.try_into()?,
maximum_streams: m,
})
}
FrameType::DataBlocked => Ok(Self::DataBlocked {
data_limit: dv(dec)?,
}),
FrameType::StreamDataBlocked => Ok(Self::StreamDataBlocked {
stream_id: dv(dec)?.into(),
stream_data_limit: dv(dec)?,
}),
FrameType::StreamsBlockedBiDi | FrameType::StreamsBlockedUniDi => {
Ok(Self::StreamsBlocked {
stream_type: t.try_into()?,
stream_limit: dv(dec)?,
})
}
FrameType::NewConnectionId => { let sequence_number = dv(dec)?; let retire_prior = dv(dec)?; let connection_id = d(dec.decode_vec(1))?; if connection_id.len() > ConnectionId::MAX_LEN { return Err(Error::FrameEncoding);
} let stateless_reset_token = Srt::try_from(dec)?;
Ok(Self::NewConnectionId {
sequence_number,
retire_prior,
connection_id,
stateless_reset_token,
})
}
FrameType::RetireConnectionId => Ok(Self::RetireConnectionId {
sequence_number: dv(dec)?,
}),
FrameType::PathChallenge => { let data = d(dec.decode(8))?; letmut datav: [u8; 8] = [0; 8];
datav.copy_from_slice(data);
Ok(Self::PathChallenge { data: datav })
}
FrameType::PathResponse => { let data = d(dec.decode(8))?; letmut datav: [u8; 8] = [0; 8];
datav.copy_from_slice(data);
Ok(Self::PathResponse { data: datav })
}
FrameType::ConnectionCloseTransport | FrameType::ConnectionCloseApplication => { let (error_code, frame_type) = if t == FrameType::ConnectionCloseTransport {
(CloseError::Transport(dv(dec)?), dv(dec)?)
} else {
(CloseError::Application(dv(dec)?), 0)
}; // We can tolerate this copy for now. let reason_phrase = String::from_utf8_lossy(d(dec.decode_vvec())?).into_owned();
Ok(Self::ConnectionClose {
error_code,
frame_type,
reason_phrase,
})
}
FrameType::HandshakeDone => Ok(Self::HandshakeDone),
FrameType::AckFrequency => { let seqno = dv(dec)?; let tolerance = dv(dec)?; if tolerance == 0 { return Err(Error::FrameEncoding);
} let delay = dv(dec)?; let ignore_order = match d(dec.decode_uint::<u8>())? { 0 => false, 1 => true,
_ => return Err(Error::FrameEncoding),
};
Ok(Self::AckFrequency {
seqno,
tolerance,
delay,
ignore_order,
})
}
FrameType::Datagram | FrameType::DatagramWithLen => { let fill = t == FrameType::Datagram; let data = if fill {
qtrace!("DATAGRAM frame, extends to the end of the packet");
dec.decode_remainder()
} else {
qtrace!("DATAGRAM frame, with length");
d(dec.decode_vvec())?
};
Ok(Self::Datagram { data, fill })
}
}
}
}
/// Extension trait for [`Encoder`] that automates writing to fuzzing corpus. pubtrait FrameEncoder { /// Encode a frame with the given type and encoding closure. /// /// This method: /// 1. Encodes the frame type as a varint /// 2. Calls the provided closure to encode the frame-specific data /// 3. When fuzzing corpus collection is enabled, saves the frame to the corpus /// /// # Example /// ```ignore /// builder.encode_frame(FrameType::NewToken, |b| { /// b.encode_vvec(&token); /// }); /// ``` fn encode_frame<T, F>(&mutself, frame_type: T, encode_fn: F) -> &style='color:red'>mutSelf where
T: Into<u64>,
F: FnOnce(&mutSelf);
}
let f = Frame::Ack {
largest_acknowledged: 0x1234,
ack_delay: 0x1235,
first_ack_range: 0x1236,
ack_ranges: ar.clone(),
ecn_count: None,
};
just_dec(&f, "025234523502523601020304");
// Try to parse ACK_ECN without ECN values let enc = Encoder::from_hex("035234523502523601020304"); letmut dec = enc.as_decoder();
assert_eq!(Frame::decode(&mut dec).unwrap_err(), Error::NoMoreData);
// Try to parse ACK_ECN with ECN values let ecn_count = Some(Count::new(0, 1, 2, 3)); let fe = Frame::Ack {
largest_acknowledged: 0x1234,
ack_delay: 0x1235,
first_ack_range: 0x1236,
ack_ranges: ar,
ecn_count,
}; let enc = Encoder::from_hex("035234523502523601020304010203"); letmut dec = enc.as_decoder();
assert_eq!(Frame::decode(&mut dec).unwrap(), fe);
}
#[test] fn reset_stream() { let f = Frame::ResetStream {
stream_id: StreamId::from(0x1234),
application_error_code: 0x77,
final_size: 0x3456,
};
just_dec(&f, "04523440777456");
}
#[test] fn stop_sending() { let f = Frame::StopSending {
stream_id: StreamId::from(63),
application_error_code: 0x77,
};
just_dec(&f, "053F4077");
}
#[test] fn crypto() { let f = Frame::Crypto {
offset: 1,
data: &[1, 2, 3],
};
just_dec(&f, "060103010203");
}
#[test] fn new_token() { let f = Frame::NewToken {
token: &[0x12, 0x34, 0x56],
};
#[test] fn stream() { // First, just set the length bit. let f = Frame::Stream {
fin: false,
stream_id: StreamId::from(5),
offset: 0,
data: &[1, 2, 3],
fill: false,
};
just_dec(&f, "0a0503010203");
// Now with offset != 0 and FIN let f = Frame::Stream {
fin: true,
stream_id: StreamId::from(5),
offset: 1,
data: &[1, 2, 3],
fill: false,
};
just_dec(&f, "0f050103010203");
// Now to fill the packet. let f = Frame::Stream {
fin: true,
stream_id: StreamId::from(5),
offset: 0,
data: &[1, 2, 3],
fill: true,
};
just_dec(&f, "0905010203");
}
#[test] fn max_data() { let f = Frame::MaxData {
maximum_data: 0x1234,
};
just_dec(&f, "105234");
}
#[test] fn max_stream_data() { let f = Frame::MaxStreamData {
stream_id: StreamId::from(5),
maximum_stream_data: 0x1234,
};
#[test] fn ack_frequency_ignore_error_error() { let enc = Encoder::from_hex("40af0a0547d003"); // ignore_order of 3
assert_eq!(
Frame::decode(&mut enc.as_decoder()).unwrap_err(),
Error::FrameEncoding
);
}
/// Hopefully this test is eventually redundant. #[test] fn ack_frequency_zero_packets() { let enc = Encoder::from_hex("40af0a000101"); // packets of 0
assert_eq!(
Frame::decode(&mut enc.as_decoder()).unwrap_err(),
Error::FrameEncoding
);
}
#[test] fn datagram() { // Without the length bit. let f = Frame::Datagram {
data: &[1, 2, 3],
fill: true,
};
just_dec(&f, "30010203");
// With the length bit. let f = Frame::Datagram {
data: &[1, 2, 3],
fill: false,
};
just_dec(&f, "3103010203");
}
#[test] fn frame_decode_enforces_bound_on_ack_range() { letmut e = Encoder::default();
e.encode_varint(FrameType::Ack);
e.encode_varint(0u64); // largest acknowledged
e.encode_varint(0u64); // ACK delay
e.encode_varint(u32::MAX); // ACK range count = huge, but maybe available for allocation
#[test] #[should_panic(expected = "Failed to decode frame")] fn invalid_frame_type_len() { let f = Frame::Datagram {
data: &[1, 2, 3],
fill: true,
};
just_dec(&f, "4030010203");
}
/// See bug in <https://github.com/mozilla/neqo/issues/2838>. #[test] fn padding_frame_u16_overflow() { letmut e = Encoder::default();
e.encode_varint(FrameType::Padding); // `Frame::Padding` uses u16 to store length. Try to overflow length.
e.pad_to(u16::MAX as usize + 1, 0);
assert_eq!(Frame::decode(&mut e.as_decoder()), Err(Error::TooMuchData));
}
/// `is_allowed`: `NewToken` and app-close are only allowed in Short packets. #[test] fn is_allowed_new_token_and_app_close() { let new_token = Frame::NewToken { token: &[1, 2] };
assert!(new_token.is_allowed(packet::Type::Short));
assert!(!new_token.is_allowed(packet::Type::ZeroRtt));
assert!(!new_token.is_allowed(packet::Type::Handshake));
/// `decode_ack_frame` rejects invalid range configurations. #[test] fn decode_ack_frame_boundaries() { // largest_acked < first_ack_range is always invalid.
assert!(Frame::decode_ack_frame(3, 4, &[]).is_err());
// largest_acked == first_ack_range with additional ranges: no room for a gap.
assert!(Frame::decode_ack_frame(4, 4, &[AckRange { gap: 0, range: 0 }]).is_err());
// After the first range (5..=5), cur = 0, which is less than gap+1=1.
assert!(Frame::decode_ack_frame(5, 4, &[AckRange { gap: 0, range: 0 }]).is_err());
// With one extra unit of room (largest - first = 2), cur starts at 1 — enough.
assert!(Frame::decode_ack_frame(5, 3, &[AckRange { gap: 0, range: 0 }]).is_ok());
}
/// `decode_ack_frame` correctly advances `cur` by `gap + 1` and produces exact ranges. #[test] fn decode_ack_frame_gap_arithmetic() { // gap=1 skips 2 packet numbers (gap+1=2): cur goes 5→3 after the gap. let result = Frame::decode_ack_frame(10, 4, &[AckRange { gap: 1, range: 0 }]);
assert_eq!(result.unwrap(), vec![6..=10, 3..=3]);
/// ACK with too many ranges is rejected; just below the limit passes the range count check. #[test] fn decode_ack_too_many_ranges() { let enc = encode_ack_header(32768); let result = Frame::decode(&mut enc.as_decoder());
assert_eq!(result.unwrap_err(), Error::TooMuchData);
let enc = encode_ack_header(32767); let result = Frame::decode(&mut enc.as_decoder());
assert_ne!(result.unwrap_err(), Error::TooMuchData);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.