Skip to content

Commit

Permalink
lib, qlog: Track and Log Unknown Transport Parameters
Browse files Browse the repository at this point in the history
Track (and make available to qlog for logging) transport parameters and
their values that this implementation does not specifically recognize.
  • Loading branch information
hawkinsw committed Oct 19, 2024
1 parent 9ea2152 commit 82ec65f
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 3 deletions.
9 changes: 9 additions & 0 deletions qlog/src/events/quic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,15 @@ pub struct TransportParametersSet {
pub initial_max_streams_uni: Option<u64>,

pub preferred_address: Option<PreferredAddress>,

pub unknown_parameters: Vec<UnknownTransportParameter>,
}

#[serde_with::skip_serializing_none]
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
pub struct UnknownTransportParameter {
pub id: u64,
pub value: Vec<u8>,
}

#[serde_with::skip_serializing_none]
Expand Down
166 changes: 163 additions & 3 deletions quiche/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@
#[macro_use]
extern crate log;

use octets::BufferTooShortError;
#[cfg(feature = "qlog")]
use qlog::events::connectivity::ConnectivityEventType;
#[cfg(feature = "qlog")]
Expand Down Expand Up @@ -7984,6 +7985,95 @@ impl std::fmt::Debug for Stats {
}
}

/// QUIC Unknown Transport Parameter
///
/// A QUIC transport parameter that is not specifically recognized
/// by this implementation.
#[derive(Clone, Debug, PartialEq)]
pub struct UnknownTransportParameter {
/// ID of an unknown transport parameter
pub id: u64,
/// Original data representing the value of an unknown transport parameter
pub value: Vec<u8>,
}

#[cfg(feature = "qlog")]
impl From<UnknownTransportParameter>
for qlog::events::quic::UnknownTransportParameter
{
fn from(value: UnknownTransportParameter) -> Self {
Self {
id: value.id,
value: value.value,
}
}
}

/// Track unknown transport parameters, up to a limit.
#[derive(Clone, Debug, PartialEq)]
pub struct UnknownTransportParameters {
// The maximum number of bytes available to store the values of unknown
// transport parameters.
/// The space remaining for storing unknown transport parameters.
pub capacity: usize,
/// The unknown transport parameters.
pub parameters: Vec<UnknownTransportParameter>,
}

impl<'a> Default for UnknownTransportParameters {
fn default() -> Self {
Self {
capacity: Self::MAX_UNKNOWN_TRANSPORT_PARAM_SIZE,
parameters: vec![],
}
}
}

impl UnknownTransportParameters {
const MAX_UNKNOWN_TRANSPORT_PARAM_SIZE: usize = 256;

/// Push an unknown transport parameter into storage if there is space
/// remaining.
pub fn safe_push(&mut self, new: UnknownTransportParameter) -> Result<()> {
let new_unknown_tp_size = new.value.len();
if new_unknown_tp_size < self.capacity {
self.capacity -= new.value.len();
self.parameters.push(new);
Ok(())
} else {
Err(BufferTooShortError.into())
}
}
}

/// An Iterator over unknown transport parameters.
pub struct UnknownTransportParameterIterator<'a> {
index: usize,
parameters: &'a Vec<UnknownTransportParameter>,
}

impl<'a> IntoIterator for &'a UnknownTransportParameters {
type IntoIter = UnknownTransportParameterIterator<'a>;
type Item = &'a UnknownTransportParameter;

fn into_iter(self) -> Self::IntoIter {
UnknownTransportParameterIterator {
index: 0,
parameters: &self.parameters,
}
}
}

impl<'a> Iterator for UnknownTransportParameterIterator<'a> {
type Item = &'a UnknownTransportParameter;

fn next(&mut self) -> Option<Self::Item> {
let result = self.parameters.get(self.index);
self.index += 1;
result
}
}

/// QUIC Transport Parameters
#[derive(Clone, Debug, PartialEq)]
pub struct TransportParams {
Expand Down Expand Up @@ -8023,7 +8113,9 @@ pub struct TransportParams {
pub retry_source_connection_id: Option<ConnectionId<'static>>,
/// DATAGRAM frame extension parameter, if any.
pub max_datagram_frame_size: Option<u64>,
// pub preferred_address: ...,
/// Unknown peer transport parameters and values, if any.
pub unknown_params: UnknownTransportParameters, /* pub preferred_address:
* ..., */
}

impl Default for TransportParams {
Expand All @@ -8046,6 +8138,7 @@ impl Default for TransportParams {
initial_source_connection_id: None,
retry_source_connection_id: None,
max_datagram_frame_size: None,
unknown_params: Default::default(),
}
}
}
Expand Down Expand Up @@ -8196,8 +8289,15 @@ impl TransportParams {
tp.max_datagram_frame_size = Some(val.get_varint()?);
},

// Ignore unknown parameters.
_ => (),
// Track unknown transport parameters specially.
unknown_tp_id => {
tp.unknown_params
.safe_push(UnknownTransportParameter {
id: unknown_tp_id,
value: val.to_vec(),
})
.unwrap();
},
}
}

Expand Down Expand Up @@ -8410,6 +8510,12 @@ impl TransportParams {
initial_max_streams_uni: Some(self.initial_max_streams_uni),

preferred_address: None,

unknown_parameters: self.unknown_params
.into_iter()
.cloned()
.map(Into::<qlog::events::quic::UnknownTransportParameter>::into)
.collect(),
},
)
}
Expand Down Expand Up @@ -8952,6 +9058,7 @@ mod tests {
initial_source_connection_id: Some(b"woot woot".to_vec().into()),
retry_source_connection_id: Some(b"retry".to_vec().into()),
max_datagram_frame_size: Some(32),
unknown_params: Default::default(),
};

let mut raw_params = [42; 256];
Expand Down Expand Up @@ -8982,6 +9089,7 @@ mod tests {
initial_source_connection_id: Some(b"woot woot".to_vec().into()),
retry_source_connection_id: None,
max_datagram_frame_size: Some(32),
unknown_params: Default::default(),
};

let mut raw_params = [42; 256];
Expand Down Expand Up @@ -9029,6 +9137,58 @@ mod tests {
);
}

#[test]
fn transport_params_unknown_max_space_respected() {
let mut unknown_params: UnknownTransportParameters = Default::default();

let massive_unknown_param = UnknownTransportParameter {
id: 5,
value: vec![0xau8; 280],
};
let big_unknown_param = UnknownTransportParameter {
id: 5,
value: vec![0xau8; 240],
};
let little_unknown_param = UnknownTransportParameter {
id: 6,
value: vec![0xau8; 15],
};

assert!(unknown_params.safe_push(massive_unknown_param).is_err());
assert!(
unknown_params.capacity ==
UnknownTransportParameters::MAX_UNKNOWN_TRANSPORT_PARAM_SIZE
);

unknown_params.safe_push(big_unknown_param).unwrap();
assert!(unknown_params.capacity == 16);

unknown_params
.safe_push(little_unknown_param.clone())
.unwrap();
assert!(unknown_params.capacity == 1);

assert!(unknown_params.safe_push(little_unknown_param).is_err());

let mut unknown_params_iter = unknown_params.into_iter();

let unknown_params_first = unknown_params_iter
.next()
.expect("Should have a 0th element.");
assert!(
unknown_params_first.id == 5 &&
unknown_params_first.value == vec![0xau8; 240]
);

let unknown_params_second = unknown_params_iter
.next()
.expect("Should have a 1th element.");
assert!(
unknown_params_second.id == 6 &&
unknown_params_second.value == vec![0xau8; 15]
);
}

#[test]
fn unknown_version() {
let mut config = Config::new(0xbabababa).unwrap();
Expand Down

0 comments on commit 82ec65f

Please sign in to comment.