Skip to content

Commit

Permalink
quinn-rs#2057: Write transport parameters in random order.
Browse files Browse the repository at this point in the history
  • Loading branch information
mstyura committed Nov 27, 2024
1 parent d658b53 commit 8078b6f
Showing 1 changed file with 128 additions and 60 deletions.
188 changes: 128 additions & 60 deletions quinn-proto/src/transport_parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::{
};

use bytes::{Buf, BufMut};
use rand::{Rng as _, RngCore};
use rand::{seq::SliceRandom as _, Rng as _, RngCore};
use thiserror::Error;

use crate::{
Expand Down Expand Up @@ -104,6 +104,9 @@ macro_rules! make_struct {
/// of transport parameter extensions.
/// When present, it is included during serialization but ignored during deserialization.
pub(crate) grease_transport_parameter: Option<ReservedTransportParameter>,

/// The order in which transport parameters are serialized
pub(crate) write_order: Option<[u8; TransportParameterId::SUPPORTED.len()]>,
}

// We deliberately don't implement the `Default` trait, since that would be public, and
Expand All @@ -126,6 +129,7 @@ macro_rules! make_struct {
stateless_reset_token: None,
preferred_address: None,
grease_transport_parameter: None,
write_order: None,
}
}
}
Expand Down Expand Up @@ -168,6 +172,11 @@ impl TransportParameters {
VarInt::from_u64(u64::try_from(TIMER_GRANULARITY.as_micros()).unwrap()).unwrap(),
),
grease_transport_parameter: Some(ReservedTransportParameter::random(rng)),
write_order: Some({
let mut order = std::array::from_fn(|i| i as u8);
order.shuffle(rng);
order
}),
..Self::default()
}
}
Expand Down Expand Up @@ -295,68 +304,100 @@ impl From<UnexpectedEnd> for Error {
impl TransportParameters {
/// Encode `TransportParameters` into buffer
pub fn write<W: BufMut>(&self, w: &mut W) {
macro_rules! write_params {
{$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
$(
if self.$name.0 != $default {
w.write_var(TransportParameterId::$id as u64);
w.write(VarInt::try_from(self.$name.size()).unwrap());
w.write(self.$name);
for idx in self
.write_order
.as_ref()
.unwrap_or(&std::array::from_fn(|i| i as u8))
{
let id = TransportParameterId::SUPPORTED[*idx as usize];
match id {
TransportParameterId::ReservedTransportParameter => {
if let Some(param) = self.grease_transport_parameter {
param.write(w);
}
)*
}
}
apply_params!(write_params);

if let Some(param) = self.grease_transport_parameter {
param.write(w);
}

if let Some(ref x) = self.stateless_reset_token {
w.write_var(0x02);
w.write_var(16);
w.put_slice(x);
}

if self.disable_active_migration {
w.write_var(0x0c);
w.write_var(0);
}

if let Some(x) = self.max_datagram_frame_size {
w.write_var(0x20);
w.write_var(x.size() as u64);
w.write(x);
}

if let Some(ref x) = self.preferred_address {
w.write_var(0x000d);
w.write_var(x.wire_size() as u64);
x.write(w);
}

for &(tag, cid) in &[
(0x00, &self.original_dst_cid),
(0x0f, &self.initial_src_cid),
(0x10, &self.retry_src_cid),
] {
if let Some(ref cid) = *cid {
w.write_var(tag);
w.write_var(cid.len() as u64);
w.put_slice(cid);
}
TransportParameterId::StatelessResetToken => {
if let Some(ref x) = self.stateless_reset_token {
w.write_var(id as u64);
w.write_var(16);
w.put_slice(x);
}
}
TransportParameterId::DisableActiveMigration => {
if self.disable_active_migration {
w.write_var(id as u64);
w.write_var(0);
}
}
TransportParameterId::MaxDatagramFrameSize => {
if let Some(x) = self.max_datagram_frame_size {
w.write_var(id as u64);
w.write_var(x.size() as u64);
w.write(x);
}
}
TransportParameterId::PreferredAddress => {
if let Some(ref x) = self.preferred_address {
w.write_var(id as u64);
w.write_var(x.wire_size() as u64);
x.write(w);
}
}
TransportParameterId::OriginalDestinationConnectionId => {
if let Some(ref cid) = self.original_dst_cid {
w.write_var(id as u64);
w.write_var(cid.len() as u64);
w.put_slice(cid);
}
}
TransportParameterId::InitialSourceConnectionId => {
if let Some(ref cid) = self.initial_src_cid {
w.write_var(id as u64);
w.write_var(cid.len() as u64);
w.put_slice(cid);
}
}
TransportParameterId::RetrySourceConnectionId => {
if let Some(ref cid) = self.retry_src_cid {
w.write_var(id as u64);
w.write_var(cid.len() as u64);
w.put_slice(cid);
}
}
TransportParameterId::GreaseQuicBit => {
if self.grease_quic_bit {
w.write_var(id as u64);
w.write_var(0);
}
}
TransportParameterId::MinAckDelayDraft07 => {
if let Some(x) = self.min_ack_delay {
w.write_var(id as u64);
w.write_var(x.size() as u64);
w.write(x);
}
}
id => {
macro_rules! write_params {
{$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
match id {
$(TransportParameterId::$id => {
if self.$name.0 != $default {
w.write_var(id as u64);
w.write(VarInt::try_from(self.$name.size()).unwrap());
w.write(self.$name);
}
})*,
_ => {
unimplemented!("Missing implementation of write for transport parameter with code {id:?}");
}
}
}
}
apply_params!(write_params);
}
}
}

if self.grease_quic_bit {
w.write_var(0x2ab2);
w.write_var(0);
}

if let Some(x) = self.min_ack_delay {
w.write_var(0xff04de1b);
w.write_var(x.size() as u64);
w.write(x);
}
}

/// Decode `TransportParameters` from buffer
Expand Down Expand Up @@ -593,6 +634,33 @@ pub(crate) enum TransportParameterId {
MinAckDelayDraft07 = 0xFF04DE1B,
}

impl TransportParameterId {
/// Array with all supported transport parameter IDs
const SUPPORTED: [TransportParameterId; 21] = [
TransportParameterId::MaxIdleTimeout,
TransportParameterId::MaxUdpPayloadSize,
TransportParameterId::InitialMaxData,
TransportParameterId::InitialMaxStreamDataBidiLocal,
TransportParameterId::InitialMaxStreamDataBidiRemote,
TransportParameterId::InitialMaxStreamDataUni,
TransportParameterId::InitialMaxStreamsBidi,
TransportParameterId::InitialMaxStreamsUni,
TransportParameterId::AckDelayExponent,
TransportParameterId::MaxAckDelay,
TransportParameterId::ActiveConnectionIdLimit,
TransportParameterId::ReservedTransportParameter,
TransportParameterId::StatelessResetToken,
TransportParameterId::DisableActiveMigration,
TransportParameterId::MaxDatagramFrameSize,
TransportParameterId::PreferredAddress,
TransportParameterId::OriginalDestinationConnectionId,
TransportParameterId::InitialSourceConnectionId,
TransportParameterId::RetrySourceConnectionId,
TransportParameterId::GreaseQuicBit,
TransportParameterId::MinAckDelayDraft07,
];
}

impl std::cmp::PartialEq<u64> for TransportParameterId {
fn eq(&self, other: &u64) -> bool {
*other == (*self as u64)
Expand Down

0 comments on commit 8078b6f

Please sign in to comment.