1use std::{
10 convert::TryFrom,
11 net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6},
12};
13
14use bytes::{Buf, BufMut};
15use rand::{Rng, RngExt, seq::SliceRandom as _};
16use thiserror::Error;
17
18use crate::{
19 LOC_CID_COUNT, MAX_CID_SIZE, MAX_STREAM_COUNT, RESET_TOKEN_SIZE, ResetToken, Side,
20 TIMER_GRANULARITY, TransportError, VarInt,
21 cid_generator::ConnectionIdGenerator,
22 cid_queue::CidQueue,
23 coding::{BufExt, BufMutExt, UnexpectedEnd},
24 config::{EndpointConfig, ServerConfig, TransportConfig},
25 shared::ConnectionId,
26};
27
28macro_rules! apply_params {
34 ($macro:ident) => {
35 $macro! {
36 max_idle_timeout(MaxIdleTimeout) = 0,
39 max_udp_payload_size(MaxUdpPayloadSize) = 65527,
41
42 initial_max_data(InitialMaxData) = 0,
44 initial_max_stream_data_bidi_local(InitialMaxStreamDataBidiLocal) = 0,
46 initial_max_stream_data_bidi_remote(InitialMaxStreamDataBidiRemote) = 0,
48 initial_max_stream_data_uni(InitialMaxStreamDataUni) = 0,
50
51 initial_max_streams_bidi(InitialMaxStreamsBidi) = 0,
53 initial_max_streams_uni(InitialMaxStreamsUni) = 0,
55
56 ack_delay_exponent(AckDelayExponent) = 3,
58 max_ack_delay(MaxAckDelay) = 25,
61 active_connection_id_limit(ActiveConnectionIdLimit) = 2,
63 }
64 };
65}
66
67macro_rules! make_struct {
68 {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
69 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
71 pub struct TransportParameters {
72 $($(#[$doc])* pub(crate) $name : VarInt,)*
73
74 pub(crate) disable_active_migration: bool,
76 pub(crate) max_datagram_frame_size: Option<VarInt>,
78 pub(crate) initial_src_cid: Option<ConnectionId>,
81 pub(crate) grease_quic_bit: bool,
84
85 pub(crate) min_ack_delay: Option<VarInt>,
91
92 pub(crate) original_dst_cid: Option<ConnectionId>,
96 pub(crate) retry_src_cid: Option<ConnectionId>,
99 pub(crate) stateless_reset_token: Option<ResetToken>,
101 pub(crate) preferred_address: Option<PreferredAddress>,
103 pub(crate) grease_transport_parameter: Option<ReservedTransportParameter>,
107
108 pub(crate) write_order: Option<[u8; TransportParameterId::SUPPORTED.len()]>,
113 }
114
115 impl TransportParameters {
119 pub(crate) fn default() -> Self {
121 Self {
122 $($name: VarInt::from_u32($default),)*
123
124 disable_active_migration: false,
125 max_datagram_frame_size: None,
126 initial_src_cid: None,
127 grease_quic_bit: false,
128 min_ack_delay: None,
129
130 original_dst_cid: None,
131 retry_src_cid: None,
132 stateless_reset_token: None,
133 preferred_address: None,
134 grease_transport_parameter: None,
135 write_order: None,
136 }
137 }
138 }
139 }
140}
141
142apply_params!(make_struct);
143
144impl TransportParameters {
145 pub(crate) fn new(
146 config: &TransportConfig,
147 endpoint_config: &EndpointConfig,
148 cid_gen: &dyn ConnectionIdGenerator,
149 initial_src_cid: ConnectionId,
150 server_config: Option<&ServerConfig>,
151 rng: &mut impl Rng,
152 ) -> Self {
153 Self {
154 initial_src_cid: Some(initial_src_cid),
155 initial_max_streams_bidi: config.max_concurrent_bidi_streams,
156 initial_max_streams_uni: config.max_concurrent_uni_streams,
157 initial_max_data: config.receive_window,
158 initial_max_stream_data_bidi_local: config.stream_receive_window,
159 initial_max_stream_data_bidi_remote: config.stream_receive_window,
160 initial_max_stream_data_uni: config.stream_receive_window,
161 max_udp_payload_size: endpoint_config.max_udp_payload_size,
162 max_idle_timeout: config.max_idle_timeout.unwrap_or(VarInt(0)),
163 disable_active_migration: server_config.is_some_and(|c| !c.migration),
164 active_connection_id_limit: if cid_gen.cid_len() == 0 {
165 2 } else {
167 CidQueue::LEN as u32
168 }
169 .into(),
170 max_datagram_frame_size: config
171 .datagram_receive_buffer_size
172 .map(|x| (x.min(u16::MAX.into()) as u16).into()),
173 grease_quic_bit: endpoint_config.grease_quic_bit,
174 min_ack_delay: Some(
175 VarInt::from_u64(u64::try_from(TIMER_GRANULARITY.as_micros()).unwrap()).unwrap(),
176 ),
177 grease_transport_parameter: Some(ReservedTransportParameter::random(rng)),
178 write_order: Some({
179 let mut order = std::array::from_fn(|i| i as u8);
180 order.shuffle(rng);
181 order
182 }),
183 ..Self::default()
184 }
185 }
186
187 pub(crate) fn validate_resumption_from(&self, cached: &Self) -> Result<(), TransportError> {
190 if cached.active_connection_id_limit > self.active_connection_id_limit
191 || cached.initial_max_data > self.initial_max_data
192 || cached.initial_max_stream_data_bidi_local > self.initial_max_stream_data_bidi_local
193 || cached.initial_max_stream_data_bidi_remote > self.initial_max_stream_data_bidi_remote
194 || cached.initial_max_stream_data_uni > self.initial_max_stream_data_uni
195 || cached.initial_max_streams_bidi > self.initial_max_streams_bidi
196 || cached.initial_max_streams_uni > self.initial_max_streams_uni
197 || cached.max_datagram_frame_size > self.max_datagram_frame_size
198 || cached.grease_quic_bit && !self.grease_quic_bit
199 {
200 return Err(TransportError::PROTOCOL_VIOLATION(
201 "0-RTT accepted with incompatible transport parameters",
202 ));
203 }
204 Ok(())
205 }
206
207 pub(crate) fn issue_cids_limit(&self) -> u64 {
212 self.active_connection_id_limit.0.min(LOC_CID_COUNT)
213 }
214}
215
216#[derive(Debug, Copy, Clone, Eq, PartialEq)]
220pub(crate) struct PreferredAddress {
221 pub(crate) address_v4: Option<SocketAddrV4>,
222 pub(crate) address_v6: Option<SocketAddrV6>,
223 pub(crate) connection_id: ConnectionId,
224 pub(crate) stateless_reset_token: ResetToken,
225}
226
227impl PreferredAddress {
228 fn wire_size(&self) -> u16 {
229 4 + 2 + 16 + 2 + 1 + self.connection_id.len() as u16 + 16
230 }
231
232 fn write<W: BufMut>(&self, w: &mut W) {
233 w.write(self.address_v4.map_or(Ipv4Addr::UNSPECIFIED, |x| *x.ip()));
234 w.write::<u16>(self.address_v4.map_or(0, |x| x.port()));
235 w.write(self.address_v6.map_or(Ipv6Addr::UNSPECIFIED, |x| *x.ip()));
236 w.write::<u16>(self.address_v6.map_or(0, |x| x.port()));
237 w.write::<u8>(self.connection_id.len() as u8);
238 w.put_slice(&self.connection_id);
239 w.put_slice(&self.stateless_reset_token);
240 }
241
242 fn read<R: Buf>(r: &mut R) -> Result<Self, Error> {
243 let ip_v4 = r.get::<Ipv4Addr>()?;
244 let port_v4 = r.get::<u16>()?;
245 let ip_v6 = r.get::<Ipv6Addr>()?;
246 let port_v6 = r.get::<u16>()?;
247 let cid_len = r.get::<u8>()?;
248 if r.remaining() < cid_len as usize || cid_len > MAX_CID_SIZE as u8 {
249 return Err(Error::Malformed);
250 }
251 let mut stage = [0; MAX_CID_SIZE];
252 r.copy_to_slice(&mut stage[0..cid_len as usize]);
253 let cid = ConnectionId::new(&stage[0..cid_len as usize]);
254 if r.remaining() < 16 {
255 return Err(Error::Malformed);
256 }
257 let mut token = [0; RESET_TOKEN_SIZE];
258 r.copy_to_slice(&mut token);
259 let address_v4 = if ip_v4.is_unspecified() && port_v4 == 0 {
260 None
261 } else {
262 Some(SocketAddrV4::new(ip_v4, port_v4))
263 };
264 let address_v6 = if ip_v6.is_unspecified() && port_v6 == 0 {
265 None
266 } else {
267 Some(SocketAddrV6::new(ip_v6, port_v6, 0, 0))
268 };
269 if address_v4.is_none() && address_v6.is_none() {
270 return Err(Error::IllegalValue);
271 }
272 Ok(Self {
273 address_v4,
274 address_v6,
275 connection_id: cid,
276 stateless_reset_token: token.into(),
277 })
278 }
279}
280
281#[derive(Debug, Copy, Clone, Eq, PartialEq, Error)]
283pub enum Error {
284 #[error("parameter had illegal value")]
286 IllegalValue,
287 #[error("parameters were malformed")]
289 Malformed,
290}
291
292impl From<Error> for TransportError {
293 fn from(e: Error) -> Self {
294 match e {
295 Error::IllegalValue => Self::TRANSPORT_PARAMETER_ERROR("illegal value"),
296 Error::Malformed => Self::TRANSPORT_PARAMETER_ERROR("malformed"),
297 }
298 }
299}
300
301impl From<UnexpectedEnd> for Error {
302 fn from(_: UnexpectedEnd) -> Self {
303 Self::Malformed
304 }
305}
306
307impl TransportParameters {
308 pub fn write<W: BufMut>(&self, w: &mut W) {
310 for idx in self
311 .write_order
312 .as_ref()
313 .unwrap_or(&std::array::from_fn(|i| i as u8))
314 {
315 let id = TransportParameterId::SUPPORTED[*idx as usize];
316 match id {
317 TransportParameterId::ReservedTransportParameter => {
318 if let Some(param) = self.grease_transport_parameter {
319 param.write(w);
320 }
321 }
322 TransportParameterId::StatelessResetToken => {
323 if let Some(ref x) = self.stateless_reset_token {
324 w.write_var(id as u64);
325 w.write_var(16);
326 w.put_slice(x);
327 }
328 }
329 TransportParameterId::DisableActiveMigration => {
330 if self.disable_active_migration {
331 w.write_var(id as u64);
332 w.write_var(0);
333 }
334 }
335 TransportParameterId::MaxDatagramFrameSize => {
336 if let Some(x) = self.max_datagram_frame_size {
337 w.write_var(id as u64);
338 w.write_var(x.size() as u64);
339 w.write(x);
340 }
341 }
342 TransportParameterId::PreferredAddress => {
343 if let Some(ref x) = self.preferred_address {
344 w.write_var(id as u64);
345 w.write_var(x.wire_size() as u64);
346 x.write(w);
347 }
348 }
349 TransportParameterId::OriginalDestinationConnectionId => {
350 if let Some(ref cid) = self.original_dst_cid {
351 w.write_var(id as u64);
352 w.write_var(cid.len() as u64);
353 w.put_slice(cid);
354 }
355 }
356 TransportParameterId::InitialSourceConnectionId => {
357 if let Some(ref cid) = self.initial_src_cid {
358 w.write_var(id as u64);
359 w.write_var(cid.len() as u64);
360 w.put_slice(cid);
361 }
362 }
363 TransportParameterId::RetrySourceConnectionId => {
364 if let Some(ref cid) = self.retry_src_cid {
365 w.write_var(id as u64);
366 w.write_var(cid.len() as u64);
367 w.put_slice(cid);
368 }
369 }
370 TransportParameterId::GreaseQuicBit => {
371 if self.grease_quic_bit {
372 w.write_var(id as u64);
373 w.write_var(0);
374 }
375 }
376 TransportParameterId::MinAckDelayDraft07 => {
377 if let Some(x) = self.min_ack_delay {
378 w.write_var(id as u64);
379 w.write_var(x.size() as u64);
380 w.write(x);
381 }
382 }
383 id => {
384 macro_rules! write_params {
385 {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
386 match id {
387 $(TransportParameterId::$id => {
388 if self.$name.0 != $default {
389 w.write_var(id as u64);
390 w.write(VarInt::try_from(self.$name.size()).unwrap());
391 w.write(self.$name);
392 }
393 })*,
394 _ => {
395 unimplemented!("Missing implementation of write for transport parameter with code {id:?}");
396 }
397 }
398 }
399 }
400 apply_params!(write_params);
401 }
402 }
403 }
404 }
405
406 pub fn read<R: Buf>(side: Side, r: &mut R) -> Result<Self, Error> {
408 let mut params = Self::default();
410
411 macro_rules! param_state {
413 {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {{
414 struct ParamState {
415 $($name: bool,)*
416 }
417
418 ParamState {
419 $($name: false,)*
420 }
421 }}
422 }
423 let mut got = apply_params!(param_state);
424
425 while r.has_remaining() {
426 let id = r.get_var()?;
427 let len = r.get_var()?;
428 if (r.remaining() as u64) < len {
429 return Err(Error::Malformed);
430 }
431 let len = len as usize;
432 let Ok(id) = TransportParameterId::try_from(id) else {
433 r.advance(len);
435 continue;
436 };
437
438 let remaining_before = r.remaining();
439
440 match id {
441 TransportParameterId::OriginalDestinationConnectionId => {
442 decode_cid(len, &mut params.original_dst_cid, r)?
443 }
444 TransportParameterId::StatelessResetToken => {
445 if len != 16 || params.stateless_reset_token.is_some() {
446 return Err(Error::Malformed);
447 }
448 let mut tok = [0; RESET_TOKEN_SIZE];
449 r.copy_to_slice(&mut tok);
450 params.stateless_reset_token = Some(tok.into());
451 }
452 TransportParameterId::DisableActiveMigration => {
453 if len != 0 || params.disable_active_migration {
454 return Err(Error::Malformed);
455 }
456 params.disable_active_migration = true;
457 }
458 TransportParameterId::PreferredAddress => {
459 if params.preferred_address.is_some() {
460 return Err(Error::Malformed);
461 }
462 params.preferred_address = Some(PreferredAddress::read(&mut r.take(len))?);
463 }
464 TransportParameterId::InitialSourceConnectionId => {
465 decode_cid(len, &mut params.initial_src_cid, r)?
466 }
467 TransportParameterId::RetrySourceConnectionId => {
468 decode_cid(len, &mut params.retry_src_cid, r)?
469 }
470 TransportParameterId::MaxDatagramFrameSize => {
471 if len > 8 || params.max_datagram_frame_size.is_some() {
472 return Err(Error::Malformed);
473 }
474 params.max_datagram_frame_size = Some(r.get()?);
475 }
476 TransportParameterId::GreaseQuicBit => match len {
477 0 => params.grease_quic_bit = true,
478 _ => return Err(Error::Malformed),
479 },
480 TransportParameterId::MinAckDelayDraft07 => params.min_ack_delay = Some(r.get()?),
481 _ => {
482 macro_rules! parse {
483 {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
484 match id {
485 $(TransportParameterId::$id => {
486 let value = r.get::<VarInt>()?;
487 if len != value.size() || got.$name { return Err(Error::Malformed); }
488 params.$name = value.into();
489 got.$name = true;
490 })*
491 _ => r.advance(len),
492 }
493 }
494 }
495 apply_params!(parse);
496 }
497 }
498
499 if remaining_before - r.remaining() != len {
500 return Err(Error::Malformed);
501 }
502 }
503
504 if params.ack_delay_exponent.0 > 20
508 || params.max_ack_delay.0 >= 1 << 14
510 || params.active_connection_id_limit.0 < 2
512 || params.max_udp_payload_size.0 < 1200
514 || params.initial_max_streams_bidi.0 > MAX_STREAM_COUNT
516 || params.initial_max_streams_uni.0 > MAX_STREAM_COUNT
517 || params.min_ack_delay.is_some_and(|min_ack_delay| {
519 min_ack_delay.0 > params.max_ack_delay.0 * 1_000
521 })
522 || (side.is_server()
524 && (params.original_dst_cid.is_some()
525 || params.preferred_address.is_some()
526 || params.retry_src_cid.is_some()
527 || params.stateless_reset_token.is_some()))
528 || params
530 .preferred_address.is_some_and(|x| x.connection_id.is_empty())
531 {
532 return Err(Error::IllegalValue);
533 }
534
535 Ok(params)
536 }
537}
538
539#[derive(Debug, Copy, Clone, Eq, PartialEq)]
548pub(crate) struct ReservedTransportParameter {
549 id: VarInt,
551
552 payload: [u8; Self::MAX_PAYLOAD_LEN],
554
555 payload_len: usize,
557}
558
559impl ReservedTransportParameter {
560 fn random(rng: &mut impl Rng) -> Self {
566 let id = Self::generate_reserved_id(rng);
567
568 let payload_len = rng.random_range(0..Self::MAX_PAYLOAD_LEN);
569
570 let payload = {
571 let mut slice = [0u8; Self::MAX_PAYLOAD_LEN];
572 rng.fill_bytes(&mut slice[..payload_len]);
573 slice
574 };
575
576 Self {
577 id,
578 payload,
579 payload_len,
580 }
581 }
582
583 fn write(&self, w: &mut impl BufMut) {
584 w.write_var(self.id.0);
585 w.write_var(self.payload_len as u64);
586 w.put_slice(&self.payload[..self.payload_len]);
587 }
588
589 fn generate_reserved_id(rng: &mut impl Rng) -> VarInt {
594 let id = {
595 let rand = rng.random_range(0u64..(1 << 62) - 27);
596 let n = rand / 31;
597 31 * n + 27
598 };
599 debug_assert!(
600 id % 31 == 27,
601 "generated id does not have the form of 31 * N + 27"
602 );
603 VarInt::from_u64(id).expect(
604 "generated id does fit into range of allowed transport parameter IDs: [0; 2^62)",
605 )
606 }
607
608 const MAX_PAYLOAD_LEN: usize = 16;
612}
613
614#[repr(u64)]
615#[derive(Debug, Clone, Copy, PartialEq, Eq)]
616pub(crate) enum TransportParameterId {
617 OriginalDestinationConnectionId = 0x00,
619 MaxIdleTimeout = 0x01,
620 StatelessResetToken = 0x02,
621 MaxUdpPayloadSize = 0x03,
622 InitialMaxData = 0x04,
623 InitialMaxStreamDataBidiLocal = 0x05,
624 InitialMaxStreamDataBidiRemote = 0x06,
625 InitialMaxStreamDataUni = 0x07,
626 InitialMaxStreamsBidi = 0x08,
627 InitialMaxStreamsUni = 0x09,
628 AckDelayExponent = 0x0A,
629 MaxAckDelay = 0x0B,
630 DisableActiveMigration = 0x0C,
631 PreferredAddress = 0x0D,
632 ActiveConnectionIdLimit = 0x0E,
633 InitialSourceConnectionId = 0x0F,
634 RetrySourceConnectionId = 0x10,
635
636 ReservedTransportParameter = 0x1B,
638
639 MaxDatagramFrameSize = 0x20,
641
642 GreaseQuicBit = 0x2AB2,
644
645 MinAckDelayDraft07 = 0xFF04DE1B,
647}
648
649impl TransportParameterId {
650 const SUPPORTED: [Self; 21] = [
652 Self::MaxIdleTimeout,
653 Self::MaxUdpPayloadSize,
654 Self::InitialMaxData,
655 Self::InitialMaxStreamDataBidiLocal,
656 Self::InitialMaxStreamDataBidiRemote,
657 Self::InitialMaxStreamDataUni,
658 Self::InitialMaxStreamsBidi,
659 Self::InitialMaxStreamsUni,
660 Self::AckDelayExponent,
661 Self::MaxAckDelay,
662 Self::ActiveConnectionIdLimit,
663 Self::ReservedTransportParameter,
664 Self::StatelessResetToken,
665 Self::DisableActiveMigration,
666 Self::MaxDatagramFrameSize,
667 Self::PreferredAddress,
668 Self::OriginalDestinationConnectionId,
669 Self::InitialSourceConnectionId,
670 Self::RetrySourceConnectionId,
671 Self::GreaseQuicBit,
672 Self::MinAckDelayDraft07,
673 ];
674}
675
676impl std::cmp::PartialEq<u64> for TransportParameterId {
677 fn eq(&self, other: &u64) -> bool {
678 *other == (*self as u64)
679 }
680}
681
682impl TryFrom<u64> for TransportParameterId {
683 type Error = ();
684
685 fn try_from(value: u64) -> Result<Self, Self::Error> {
686 let param = match value {
687 id if Self::MaxIdleTimeout == id => Self::MaxIdleTimeout,
688 id if Self::MaxUdpPayloadSize == id => Self::MaxUdpPayloadSize,
689 id if Self::InitialMaxData == id => Self::InitialMaxData,
690 id if Self::InitialMaxStreamDataBidiLocal == id => Self::InitialMaxStreamDataBidiLocal,
691 id if Self::InitialMaxStreamDataBidiRemote == id => {
692 Self::InitialMaxStreamDataBidiRemote
693 }
694 id if Self::InitialMaxStreamDataUni == id => Self::InitialMaxStreamDataUni,
695 id if Self::InitialMaxStreamsBidi == id => Self::InitialMaxStreamsBidi,
696 id if Self::InitialMaxStreamsUni == id => Self::InitialMaxStreamsUni,
697 id if Self::AckDelayExponent == id => Self::AckDelayExponent,
698 id if Self::MaxAckDelay == id => Self::MaxAckDelay,
699 id if Self::ActiveConnectionIdLimit == id => Self::ActiveConnectionIdLimit,
700 id if Self::ReservedTransportParameter == id => Self::ReservedTransportParameter,
701 id if Self::StatelessResetToken == id => Self::StatelessResetToken,
702 id if Self::DisableActiveMigration == id => Self::DisableActiveMigration,
703 id if Self::MaxDatagramFrameSize == id => Self::MaxDatagramFrameSize,
704 id if Self::PreferredAddress == id => Self::PreferredAddress,
705 id if Self::OriginalDestinationConnectionId == id => {
706 Self::OriginalDestinationConnectionId
707 }
708 id if Self::InitialSourceConnectionId == id => Self::InitialSourceConnectionId,
709 id if Self::RetrySourceConnectionId == id => Self::RetrySourceConnectionId,
710 id if Self::GreaseQuicBit == id => Self::GreaseQuicBit,
711 id if Self::MinAckDelayDraft07 == id => Self::MinAckDelayDraft07,
712 _ => return Err(()),
713 };
714 Ok(param)
715 }
716}
717
718fn decode_cid(len: usize, value: &mut Option<ConnectionId>, r: &mut impl Buf) -> Result<(), Error> {
719 if len > MAX_CID_SIZE || value.is_some() || r.remaining() < len {
720 return Err(Error::Malformed);
721 }
722
723 *value = Some(ConnectionId::from_buf(r, len));
724 Ok(())
725}
726
727#[cfg(test)]
728mod test {
729 use std::convert::Infallible;
730
731 use rand::TryRng;
732
733 use super::*;
734
735 #[test]
736 fn coding() {
737 let mut buf = Vec::new();
738 let params = TransportParameters {
739 initial_src_cid: Some(ConnectionId::new(&[])),
740 original_dst_cid: Some(ConnectionId::new(&[])),
741 initial_max_streams_bidi: 16u32.into(),
742 initial_max_streams_uni: 16u32.into(),
743 ack_delay_exponent: 2u32.into(),
744 max_udp_payload_size: 1200u32.into(),
745 preferred_address: Some(PreferredAddress {
746 address_v4: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 42)),
747 address_v6: Some(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 24, 0, 0)),
748 connection_id: ConnectionId::new(&[0x42]),
749 stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
750 }),
751 grease_quic_bit: true,
752 min_ack_delay: Some(2_000u32.into()),
753 ..TransportParameters::default()
754 };
755 params.write(&mut buf);
756 assert_eq!(
757 TransportParameters::read(Side::Client, &mut buf.as_slice()).unwrap(),
758 params
759 );
760 }
761
762 #[test]
763 fn reserved_transport_parameter_generate_reserved_id() {
764 let mut rngs = [
765 StepRng(0),
766 StepRng(1),
767 StepRng(27),
768 StepRng(31),
769 StepRng(u32::MAX as u64),
770 StepRng(u32::MAX as u64 - 1),
771 StepRng(u32::MAX as u64 + 1),
772 StepRng(u32::MAX as u64 - 27),
773 StepRng(u32::MAX as u64 + 27),
774 StepRng(u32::MAX as u64 - 31),
775 StepRng(u32::MAX as u64 + 31),
776 StepRng(u64::MAX),
777 StepRng(u64::MAX - 1),
778 StepRng(u64::MAX - 27),
779 StepRng(u64::MAX - 31),
780 StepRng(1 << 62),
781 StepRng((1 << 62) - 1),
782 StepRng((1 << 62) + 1),
783 StepRng((1 << 62) - 27),
784 StepRng((1 << 62) + 27),
785 StepRng((1 << 62) - 31),
786 StepRng((1 << 62) + 31),
787 ];
788 for rng in &mut rngs {
789 let id = ReservedTransportParameter::generate_reserved_id(rng);
790 assert!(id.0 % 31 == 27)
791 }
792 }
793
794 struct StepRng(u64);
795
796 impl TryRng for StepRng {
797 type Error = Infallible;
798
799 #[inline]
800 fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
801 Ok(self.next_u64() as u32)
802 }
803
804 #[inline]
805 fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
806 let res = self.0;
807 self.0 = self.0.wrapping_add(1);
808 Ok(res)
809 }
810
811 fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
812 let mut left = dst;
813 while left.len() >= 8 {
814 let (l, r) = left.split_at_mut(8);
815 left = r;
816 l.copy_from_slice(&self.next_u64().to_le_bytes());
817 }
818 let n = left.len();
819 if n > 0 {
820 left.copy_from_slice(&self.next_u32().to_le_bytes()[..n]);
821 }
822
823 Ok(())
824 }
825 }
826
827 #[test]
828 fn reserved_transport_parameter_ignored_when_read() {
829 let mut buf = Vec::new();
830 let reserved_parameter = ReservedTransportParameter::random(&mut rand::rng());
831 assert!(reserved_parameter.payload_len < ReservedTransportParameter::MAX_PAYLOAD_LEN);
832 assert!(reserved_parameter.id.0 % 31 == 27);
833
834 reserved_parameter.write(&mut buf);
835 assert!(!buf.is_empty());
836 let read_params = TransportParameters::read(Side::Server, &mut buf.as_slice()).unwrap();
837 assert_eq!(read_params, TransportParameters::default());
838 }
839
840 #[test]
841 fn read_semantic_validation() {
842 #[allow(clippy::type_complexity)]
843 let illegal_params_builders: Vec<Box<dyn FnMut(&mut TransportParameters)>> = vec![
844 Box::new(|t| {
845 let min_ack_delay = t.max_ack_delay.0 * 1_000 + 1;
847 t.min_ack_delay = Some(VarInt::from_u64(min_ack_delay).unwrap())
848 }),
849 Box::new(|t| {
850 t.preferred_address = Some(PreferredAddress {
853 address_v4: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 42)),
854 address_v6: None,
855 connection_id: ConnectionId::new(&[]),
856 stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
857 })
858 }),
859 ];
860
861 for mut builder in illegal_params_builders {
862 let mut buf = Vec::new();
863 let mut params = TransportParameters::default();
864 builder(&mut params);
865 params.write(&mut buf);
866
867 assert_eq!(
868 TransportParameters::read(Side::Server, &mut buf.as_slice()),
869 Err(Error::IllegalValue)
870 );
871 }
872 }
873
874 #[test]
875 fn read_length_mismatch() {
876 let mut buf = Vec::new();
879 buf.write_var(TransportParameterId::MaxDatagramFrameSize as u64);
880 buf.write_var(3);
881 buf.write(VarInt::from_u32(0));
882 buf.write_var(TransportParameterId::DisableActiveMigration as u64);
883 buf.write_var(0);
884 assert_eq!(
885 TransportParameters::read(Side::Server, &mut buf.as_slice()),
886 Err(Error::Malformed)
887 );
888 }
889
890 #[test]
891 fn read_min_ack_delay_length_mismatch() {
892 let mut buf = Vec::new();
895 buf.write_var(TransportParameterId::MinAckDelayDraft07 as u64);
896 buf.write_var(0);
897 buf.write_var(TransportParameterId::InitialMaxData as u64);
898 buf.write_var(1);
899 buf.write(VarInt::from_u32(7));
900 assert_eq!(
901 TransportParameters::read(Side::Server, &mut buf.as_slice()),
902 Err(Error::Malformed)
903 );
904 }
905
906 #[test]
907 fn read_preferred_address_length_mismatch() {
908 let address = PreferredAddress {
911 address_v4: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 42)),
912 address_v6: None,
913 connection_id: ConnectionId::new(&[0x42]),
914 stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
915 };
916 let mut value = Vec::new();
917 address.write(&mut value);
918 value.write_var(TransportParameterId::DisableActiveMigration as u64);
919 value.write_var(0);
920 let mut buf = Vec::new();
921 buf.write_var(TransportParameterId::PreferredAddress as u64);
922 buf.write_var(value.len() as u64);
923 buf.extend_from_slice(&value);
924 assert_eq!(
925 TransportParameters::read(Side::Client, &mut buf.as_slice()),
926 Err(Error::Malformed)
927 );
928 }
929
930 #[test]
931 fn resumption_params_validation() {
932 let high_limit = TransportParameters {
933 initial_max_streams_uni: 32u32.into(),
934 ..TransportParameters::default()
935 };
936 let low_limit = TransportParameters {
937 initial_max_streams_uni: 16u32.into(),
938 ..TransportParameters::default()
939 };
940 high_limit.validate_resumption_from(&low_limit).unwrap();
941 low_limit.validate_resumption_from(&high_limit).unwrap_err();
942 }
943}