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