1use std::{
10 convert::TryFrom,
11 net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6},
12};
13
14use bytes::{Buf, BufMut};
15use rand::{Rng as _, RngCore, 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, 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) nat_traversal: Option<NatTraversalConfig>,
96
97 pub(crate) original_dst_cid: Option<ConnectionId>,
101 pub(crate) retry_src_cid: Option<ConnectionId>,
104 pub(crate) stateless_reset_token: Option<ResetToken>,
106 pub(crate) preferred_address: Option<PreferredAddress>,
108 pub(crate) grease_transport_parameter: Option<ReservedTransportParameter>,
112
113 pub(crate) write_order: Option<[u8; TransportParameterId::SUPPORTED.len()]>,
118 }
119
120 impl TransportParameters {
124 pub(crate) fn default() -> Self {
126 Self {
127 $($name: VarInt::from_u32($default),)*
128
129 disable_active_migration: false,
130 max_datagram_frame_size: None,
131 initial_src_cid: None,
132 grease_quic_bit: false,
133 min_ack_delay: None,
134 nat_traversal: None,
135
136 original_dst_cid: None,
137 retry_src_cid: None,
138 stateless_reset_token: None,
139 preferred_address: None,
140 grease_transport_parameter: None,
141 write_order: None,
142 }
143 }
144 }
145 }
146}
147
148apply_params!(make_struct);
149
150impl TransportParameters {
151 pub(crate) fn new(
152 config: &TransportConfig,
153 endpoint_config: &EndpointConfig,
154 cid_gen: &dyn ConnectionIdGenerator,
155 initial_src_cid: ConnectionId,
156 server_config: Option<&ServerConfig>,
157 rng: &mut impl RngCore,
158 ) -> Self {
159 Self {
160 initial_src_cid: Some(initial_src_cid),
161 initial_max_streams_bidi: config.max_concurrent_bidi_streams,
162 initial_max_streams_uni: config.max_concurrent_uni_streams,
163 initial_max_data: config.receive_window,
164 initial_max_stream_data_bidi_local: config.stream_receive_window,
165 initial_max_stream_data_bidi_remote: config.stream_receive_window,
166 initial_max_stream_data_uni: config.stream_receive_window,
167 max_udp_payload_size: endpoint_config.max_udp_payload_size,
168 max_idle_timeout: config.max_idle_timeout.unwrap_or(VarInt(0)),
169 disable_active_migration: server_config.is_some_and(|c| !c.migration),
170 active_connection_id_limit: if cid_gen.cid_len() == 0 {
171 2 } else {
173 CidQueue::LEN as u32
174 }
175 .into(),
176 max_datagram_frame_size: config
177 .datagram_receive_buffer_size
178 .map(|x| (x.min(u16::MAX.into()) as u16).into()),
179 grease_quic_bit: endpoint_config.grease_quic_bit,
180 min_ack_delay: Some(
181 VarInt::from_u64(u64::try_from(TIMER_GRANULARITY.as_micros()).unwrap()).unwrap(),
182 ),
183 grease_transport_parameter: Some(ReservedTransportParameter::random(rng)),
184 write_order: Some({
185 let mut order = std::array::from_fn(|i| i as u8);
186 order.shuffle(rng);
187 order
188 }),
189 nat_traversal: config.nat_traversal_config.clone(),
190 ..Self::default()
191 }
192 }
193
194 pub(crate) fn validate_resumption_from(&self, cached: &Self) -> Result<(), TransportError> {
197 if cached.active_connection_id_limit > self.active_connection_id_limit
198 || cached.initial_max_data > self.initial_max_data
199 || cached.initial_max_stream_data_bidi_local > self.initial_max_stream_data_bidi_local
200 || cached.initial_max_stream_data_bidi_remote > self.initial_max_stream_data_bidi_remote
201 || cached.initial_max_stream_data_uni > self.initial_max_stream_data_uni
202 || cached.initial_max_streams_bidi > self.initial_max_streams_bidi
203 || cached.initial_max_streams_uni > self.initial_max_streams_uni
204 || cached.max_datagram_frame_size > self.max_datagram_frame_size
205 || cached.grease_quic_bit && !self.grease_quic_bit
206 {
207 return Err(TransportError::PROTOCOL_VIOLATION(
208 "0-RTT accepted with incompatible transport parameters",
209 ));
210 }
211 Ok(())
212 }
213
214 pub(crate) fn issue_cids_limit(&self) -> u64 {
219 self.active_connection_id_limit.0.min(LOC_CID_COUNT)
220 }
221
222 pub fn nat_traversal_config(&self) -> Option<&NatTraversalConfig> {
227 self.nat_traversal.as_ref()
228 }
229}
230
231#[derive(Debug, Clone, Eq, PartialEq)]
236pub struct NatTraversalConfig {
237 pub(crate) role: NatTraversalRole,
239 pub(crate) max_candidates: VarInt,
241 pub(crate) coordination_timeout: VarInt,
243 pub(crate) max_concurrent_attempts: VarInt,
245 pub(crate) peer_id: Option<[u8; 32]>,
247}
248
249impl NatTraversalConfig {
253
254 pub fn new(
259 role: NatTraversalRole,
260 max_candidates: VarInt,
261 coordination_timeout: VarInt,
262 max_concurrent_attempts: VarInt,
263 peer_id: Option<[u8; 32]>,
264 ) -> Self {
265 Self {
266 role,
267 max_candidates,
268 coordination_timeout,
269 max_concurrent_attempts,
270 peer_id,
271 }
272 }
273
274 pub fn role(&self) -> NatTraversalRole {
276 self.role
277 }
278
279 pub fn max_candidates(&self) -> VarInt {
281 self.max_candidates
282 }
283
284 pub fn coordination_timeout(&self) -> VarInt {
286 self.coordination_timeout
287 }
288
289 pub fn max_concurrent_attempts(&self) -> VarInt {
291 self.max_concurrent_attempts
292 }
293
294 pub fn peer_id(&self) -> Option<[u8; 32]> {
296 self.peer_id
297 }
298
299 pub fn validate(&self) -> Result<(), Error> {
301 if self.max_candidates.0 == 0 || self.max_candidates.0 > 100 {
303 return Err(Error::IllegalValue);
304 }
305
306 if self.coordination_timeout.0 < 1000 || self.coordination_timeout.0 > 60000 {
308 return Err(Error::IllegalValue);
309 }
310
311 if self.max_concurrent_attempts.0 == 0 || self.max_concurrent_attempts.0 > 10 {
313 return Err(Error::IllegalValue);
314 }
315
316 Ok(())
317 }
318}
319
320impl Default for NatTraversalConfig {
321 fn default() -> Self {
322 Self {
323 role: NatTraversalRole::Client,
324 max_candidates: VarInt::from_u32(8),
325 coordination_timeout: VarInt::from_u32(10000), max_concurrent_attempts: VarInt::from_u32(3),
327 peer_id: None,
328 }
329 }
330}
331
332#[derive(Debug, Copy, Clone, Eq, PartialEq)]
334pub enum NatTraversalRole {
335 Client,
337 Server {
339 can_relay: bool,
341 },
342 Bootstrap,
344}
345
346#[derive(Debug, Copy, Clone, Eq, PartialEq)]
350pub(crate) struct PreferredAddress {
351 pub(crate) address_v4: Option<SocketAddrV4>,
352 pub(crate) address_v6: Option<SocketAddrV6>,
353 pub(crate) connection_id: ConnectionId,
354 pub(crate) stateless_reset_token: ResetToken,
355}
356
357impl PreferredAddress {
358 fn wire_size(&self) -> u16 {
359 4 + 2 + 16 + 2 + 1 + self.connection_id.len() as u16 + 16
360 }
361
362 fn write<W: BufMut>(&self, w: &mut W) {
363 w.write(self.address_v4.map_or(Ipv4Addr::UNSPECIFIED, |x| *x.ip()));
364 w.write::<u16>(self.address_v4.map_or(0, |x| x.port()));
365 w.write(self.address_v6.map_or(Ipv6Addr::UNSPECIFIED, |x| *x.ip()));
366 w.write::<u16>(self.address_v6.map_or(0, |x| x.port()));
367 w.write::<u8>(self.connection_id.len() as u8);
368 w.put_slice(&self.connection_id);
369 w.put_slice(&self.stateless_reset_token);
370 }
371
372 fn read<R: Buf>(r: &mut R) -> Result<Self, Error> {
373 let ip_v4 = r.get::<Ipv4Addr>()?;
374 let port_v4 = r.get::<u16>()?;
375 let ip_v6 = r.get::<Ipv6Addr>()?;
376 let port_v6 = r.get::<u16>()?;
377 let cid_len = r.get::<u8>()?;
378 if r.remaining() < cid_len as usize || cid_len > MAX_CID_SIZE as u8 {
379 return Err(Error::Malformed);
380 }
381 let mut stage = [0; MAX_CID_SIZE];
382 r.copy_to_slice(&mut stage[0..cid_len as usize]);
383 let cid = ConnectionId::new(&stage[0..cid_len as usize]);
384 if r.remaining() < 16 {
385 return Err(Error::Malformed);
386 }
387 let mut token = [0; RESET_TOKEN_SIZE];
388 r.copy_to_slice(&mut token);
389 let address_v4 = if ip_v4.is_unspecified() && port_v4 == 0 {
390 None
391 } else {
392 Some(SocketAddrV4::new(ip_v4, port_v4))
393 };
394 let address_v6 = if ip_v6.is_unspecified() && port_v6 == 0 {
395 None
396 } else {
397 Some(SocketAddrV6::new(ip_v6, port_v6, 0, 0))
398 };
399 if address_v4.is_none() && address_v6.is_none() {
400 return Err(Error::IllegalValue);
401 }
402 Ok(Self {
403 address_v4,
404 address_v6,
405 connection_id: cid,
406 stateless_reset_token: token.into(),
407 })
408 }
409}
410
411#[derive(Debug, Copy, Clone, Eq, PartialEq, Error)]
413pub enum Error {
414 #[error("parameter had illegal value")]
416 IllegalValue,
417 #[error("parameters were malformed")]
419 Malformed,
420}
421
422impl From<Error> for TransportError {
423 fn from(e: Error) -> Self {
424 match e {
425 Error::IllegalValue => Self::TRANSPORT_PARAMETER_ERROR("illegal value"),
426 Error::Malformed => Self::TRANSPORT_PARAMETER_ERROR("malformed"),
427 }
428 }
429}
430
431impl From<UnexpectedEnd> for Error {
432 fn from(_: UnexpectedEnd) -> Self {
433 Self::Malformed
434 }
435}
436
437impl TransportParameters {
438 pub fn write<W: BufMut>(&self, w: &mut W) {
440 for idx in self
441 .write_order
442 .as_ref()
443 .unwrap_or(&std::array::from_fn(|i| i as u8))
444 {
445 let id = TransportParameterId::SUPPORTED[*idx as usize];
446 match id {
447 TransportParameterId::ReservedTransportParameter => {
448 if let Some(param) = self.grease_transport_parameter {
449 param.write(w);
450 }
451 }
452 TransportParameterId::StatelessResetToken => {
453 if let Some(ref x) = self.stateless_reset_token {
454 w.write_var(id as u64);
455 w.write_var(16);
456 w.put_slice(x);
457 }
458 }
459 TransportParameterId::DisableActiveMigration => {
460 if self.disable_active_migration {
461 w.write_var(id as u64);
462 w.write_var(0);
463 }
464 }
465 TransportParameterId::MaxDatagramFrameSize => {
466 if let Some(x) = self.max_datagram_frame_size {
467 w.write_var(id as u64);
468 w.write_var(x.size() as u64);
469 w.write(x);
470 }
471 }
472 TransportParameterId::PreferredAddress => {
473 if let Some(ref x) = self.preferred_address {
474 w.write_var(id as u64);
475 w.write_var(x.wire_size() as u64);
476 x.write(w);
477 }
478 }
479 TransportParameterId::OriginalDestinationConnectionId => {
480 if let Some(ref cid) = self.original_dst_cid {
481 w.write_var(id as u64);
482 w.write_var(cid.len() as u64);
483 w.put_slice(cid);
484 }
485 }
486 TransportParameterId::InitialSourceConnectionId => {
487 if let Some(ref cid) = self.initial_src_cid {
488 w.write_var(id as u64);
489 w.write_var(cid.len() as u64);
490 w.put_slice(cid);
491 }
492 }
493 TransportParameterId::RetrySourceConnectionId => {
494 if let Some(ref cid) = self.retry_src_cid {
495 w.write_var(id as u64);
496 w.write_var(cid.len() as u64);
497 w.put_slice(cid);
498 }
499 }
500 TransportParameterId::GreaseQuicBit => {
501 if self.grease_quic_bit {
502 w.write_var(id as u64);
503 w.write_var(0);
504 }
505 }
506 TransportParameterId::MinAckDelayDraft07 => {
507 if let Some(x) = self.min_ack_delay {
508 w.write_var(id as u64);
509 w.write_var(x.size() as u64);
510 w.write(x);
511 }
512 }
513 TransportParameterId::NatTraversal => {
514 if let Some(ref config) = self.nat_traversal {
515 match config.role {
519 NatTraversalRole::Client => {
520 w.write_var(id as u64);
522 w.write_var(0); }
524 NatTraversalRole::Server { can_relay: _ } => {
525 w.write_var(id as u64);
527 w.write_var(1); let limit = config.max_concurrent_attempts.0.min(255) as u8;
530 w.put_u8(limit);
531 }
532 NatTraversalRole::Bootstrap => {
533 w.write_var(id as u64);
535 w.write_var(1); let limit = config.max_concurrent_attempts.0.min(255) as u8;
537 w.put_u8(limit);
538 }
539 }
540 }
541 }
542 id => {
543 macro_rules! write_params {
544 {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
545 match id {
546 $(TransportParameterId::$id => {
547 if self.$name.0 != $default {
548 w.write_var(id as u64);
549 w.write(VarInt::try_from(self.$name.size()).unwrap());
550 w.write(self.$name);
551 }
552 })*,
553 _ => {
554 panic!("Unsupported transport parameter reached write implementation: {id:?}");
557 }
558 }
559 }
560 }
561 apply_params!(write_params);
562 }
563 }
564 }
565 }
566
567 pub fn read<R: Buf>(side: Side, r: &mut R) -> Result<Self, Error> {
569 let mut params = Self::default();
571
572 macro_rules! param_state {
574 {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {{
575 struct ParamState {
576 $($name: bool,)*
577 }
578
579 ParamState {
580 $($name: false,)*
581 }
582 }}
583 }
584 let mut got = apply_params!(param_state);
585
586 while r.has_remaining() {
587 let id = r.get_var()?;
588 let len = r.get_var()?;
589 if (r.remaining() as u64) < len {
590 return Err(Error::Malformed);
591 }
592 let len = len as usize;
593 let Ok(id) = TransportParameterId::try_from(id) else {
594 r.advance(len);
596 continue;
597 };
598
599 match id {
600 TransportParameterId::OriginalDestinationConnectionId => {
601 decode_cid(len, &mut params.original_dst_cid, r)?
602 }
603 TransportParameterId::StatelessResetToken => {
604 if len != 16 || params.stateless_reset_token.is_some() {
605 return Err(Error::Malformed);
606 }
607 let mut tok = [0; RESET_TOKEN_SIZE];
608 r.copy_to_slice(&mut tok);
609 params.stateless_reset_token = Some(tok.into());
610 }
611 TransportParameterId::DisableActiveMigration => {
612 if len != 0 || params.disable_active_migration {
613 return Err(Error::Malformed);
614 }
615 params.disable_active_migration = true;
616 }
617 TransportParameterId::PreferredAddress => {
618 if params.preferred_address.is_some() {
619 return Err(Error::Malformed);
620 }
621 params.preferred_address = Some(PreferredAddress::read(&mut r.take(len))?);
622 }
623 TransportParameterId::InitialSourceConnectionId => {
624 decode_cid(len, &mut params.initial_src_cid, r)?
625 }
626 TransportParameterId::RetrySourceConnectionId => {
627 decode_cid(len, &mut params.retry_src_cid, r)?
628 }
629 TransportParameterId::MaxDatagramFrameSize => {
630 if len > 8 || params.max_datagram_frame_size.is_some() {
631 return Err(Error::Malformed);
632 }
633 params.max_datagram_frame_size = Some(r.get().unwrap());
634 }
635 TransportParameterId::GreaseQuicBit => match len {
636 0 => params.grease_quic_bit = true,
637 _ => return Err(Error::Malformed),
638 },
639 TransportParameterId::MinAckDelayDraft07 => {
640 params.min_ack_delay = Some(r.get().unwrap())
641 }
642 TransportParameterId::NatTraversal => {
643 if params.nat_traversal.is_some() {
644 return Err(Error::Malformed);
645 }
646 match (side, len) {
650 (Side::Server, 0) => {
651 params.nat_traversal = Some(NatTraversalConfig {
653 role: NatTraversalRole::Client,
654 max_candidates: VarInt::from_u32(8), coordination_timeout: VarInt::from_u32(10000), max_concurrent_attempts: VarInt::from_u32(3), peer_id: None,
658 });
659 }
660 (Side::Client, 1) => {
661 let limit = r.get::<u8>()?;
663 params.nat_traversal = Some(NatTraversalConfig {
664 role: NatTraversalRole::Server { can_relay: false }, max_candidates: VarInt::from_u32(8), coordination_timeout: VarInt::from_u32(10000), max_concurrent_attempts: VarInt::from_u32(limit as u32),
668 peer_id: None,
669 });
670 }
671 _ => {
672 return Err(Error::Malformed);
674 }
675 }
676 }
677 _ => {
678 macro_rules! parse {
679 {$($(#[$doc:meta])* $name:ident ($id:ident) = $default:expr,)*} => {
680 match id {
681 $(TransportParameterId::$id => {
682 let value = r.get::<VarInt>()?;
683 if len != value.size() || got.$name { return Err(Error::Malformed); }
684 params.$name = value.into();
685 got.$name = true;
686 })*
687 _ => r.advance(len),
688 }
689 }
690 }
691 apply_params!(parse);
692 }
693 }
694 }
695
696 if params.ack_delay_exponent.0 > 20
700 || params.max_ack_delay.0 >= 1 << 14
702 || params.active_connection_id_limit.0 < 2
704 || params.max_udp_payload_size.0 < 1200
706 || params.initial_max_streams_bidi.0 > MAX_STREAM_COUNT
708 || params.initial_max_streams_uni.0 > MAX_STREAM_COUNT
709 || params.min_ack_delay.is_some_and(|min_ack_delay| {
711 min_ack_delay.0 > params.max_ack_delay.0 * 1_000
713 })
714 || (side.is_server()
716 && (params.original_dst_cid.is_some()
717 || params.preferred_address.is_some()
718 || params.retry_src_cid.is_some()
719 || params.stateless_reset_token.is_some()))
720 || params
722 .preferred_address.is_some_and(|x| x.connection_id.is_empty())
723 {
724 return Err(Error::IllegalValue);
725 }
726
727 if let Some(ref nat_config) = params.nat_traversal {
729 if let Err(_) = nat_config.validate() {
731 return Err(Error::IllegalValue);
732 }
733
734 match nat_config.role {
736 NatTraversalRole::Server { .. } | NatTraversalRole::Bootstrap => {
737 if side.is_server() {
739 return Err(Error::IllegalValue);
740 }
741 }
742 NatTraversalRole::Client => {
743 if side.is_client() {
745 return Err(Error::IllegalValue);
746 }
747 }
748 }
749 }
750
751 Ok(params)
752 }
753}
754
755#[derive(Debug, Copy, Clone, Eq, PartialEq)]
764pub(crate) struct ReservedTransportParameter {
765 id: VarInt,
767
768 payload: [u8; Self::MAX_PAYLOAD_LEN],
770
771 payload_len: usize,
773}
774
775impl ReservedTransportParameter {
776 fn random(rng: &mut impl RngCore) -> Self {
782 let id = Self::generate_reserved_id(rng);
783
784 let payload_len = rng.gen_range(0..Self::MAX_PAYLOAD_LEN);
785
786 let payload = {
787 let mut slice = [0u8; Self::MAX_PAYLOAD_LEN];
788 rng.fill_bytes(&mut slice[..payload_len]);
789 slice
790 };
791
792 Self {
793 id,
794 payload,
795 payload_len,
796 }
797 }
798
799 fn write(&self, w: &mut impl BufMut) {
800 w.write_var(self.id.0);
801 w.write_var(self.payload_len as u64);
802 w.put_slice(&self.payload[..self.payload_len]);
803 }
804
805 fn generate_reserved_id(rng: &mut impl RngCore) -> VarInt {
810 let id = {
811 let rand = rng.gen_range(0u64..(1 << 62) - 27);
812 let n = rand / 31;
813 31 * n + 27
814 };
815 debug_assert!(
816 id % 31 == 27,
817 "generated id does not have the form of 31 * N + 27"
818 );
819 VarInt::from_u64(id).expect(
820 "generated id does fit into range of allowed transport parameter IDs: [0; 2^62)",
821 )
822 }
823
824 const MAX_PAYLOAD_LEN: usize = 16;
828}
829
830#[repr(u64)]
831#[derive(Debug, Clone, Copy, PartialEq, Eq)]
832pub(crate) enum TransportParameterId {
833 OriginalDestinationConnectionId = 0x00,
835 MaxIdleTimeout = 0x01,
836 StatelessResetToken = 0x02,
837 MaxUdpPayloadSize = 0x03,
838 InitialMaxData = 0x04,
839 InitialMaxStreamDataBidiLocal = 0x05,
840 InitialMaxStreamDataBidiRemote = 0x06,
841 InitialMaxStreamDataUni = 0x07,
842 InitialMaxStreamsBidi = 0x08,
843 InitialMaxStreamsUni = 0x09,
844 AckDelayExponent = 0x0A,
845 MaxAckDelay = 0x0B,
846 DisableActiveMigration = 0x0C,
847 PreferredAddress = 0x0D,
848 ActiveConnectionIdLimit = 0x0E,
849 InitialSourceConnectionId = 0x0F,
850 RetrySourceConnectionId = 0x10,
851
852 ReservedTransportParameter = 0x1B,
854
855 MaxDatagramFrameSize = 0x20,
857
858 GreaseQuicBit = 0x2AB2,
860
861 MinAckDelayDraft07 = 0xFF04DE1B,
863
864 NatTraversal = 0x3d7e9f0bca12fea6,
867}
868
869impl TransportParameterId {
870 const SUPPORTED: [Self; 22] = [
872 Self::MaxIdleTimeout,
873 Self::MaxUdpPayloadSize,
874 Self::InitialMaxData,
875 Self::InitialMaxStreamDataBidiLocal,
876 Self::InitialMaxStreamDataBidiRemote,
877 Self::InitialMaxStreamDataUni,
878 Self::InitialMaxStreamsBidi,
879 Self::InitialMaxStreamsUni,
880 Self::AckDelayExponent,
881 Self::MaxAckDelay,
882 Self::ActiveConnectionIdLimit,
883 Self::ReservedTransportParameter,
884 Self::StatelessResetToken,
885 Self::DisableActiveMigration,
886 Self::MaxDatagramFrameSize,
887 Self::PreferredAddress,
888 Self::OriginalDestinationConnectionId,
889 Self::InitialSourceConnectionId,
890 Self::RetrySourceConnectionId,
891 Self::GreaseQuicBit,
892 Self::MinAckDelayDraft07,
893 Self::NatTraversal,
894 ];
895}
896
897impl std::cmp::PartialEq<u64> for TransportParameterId {
898 fn eq(&self, other: &u64) -> bool {
899 *other == (*self as u64)
900 }
901}
902
903impl TryFrom<u64> for TransportParameterId {
904 type Error = ();
905
906 fn try_from(value: u64) -> Result<Self, Self::Error> {
907 let param = match value {
908 id if Self::MaxIdleTimeout == id => Self::MaxIdleTimeout,
909 id if Self::MaxUdpPayloadSize == id => Self::MaxUdpPayloadSize,
910 id if Self::InitialMaxData == id => Self::InitialMaxData,
911 id if Self::InitialMaxStreamDataBidiLocal == id => Self::InitialMaxStreamDataBidiLocal,
912 id if Self::InitialMaxStreamDataBidiRemote == id => {
913 Self::InitialMaxStreamDataBidiRemote
914 }
915 id if Self::InitialMaxStreamDataUni == id => Self::InitialMaxStreamDataUni,
916 id if Self::InitialMaxStreamsBidi == id => Self::InitialMaxStreamsBidi,
917 id if Self::InitialMaxStreamsUni == id => Self::InitialMaxStreamsUni,
918 id if Self::AckDelayExponent == id => Self::AckDelayExponent,
919 id if Self::MaxAckDelay == id => Self::MaxAckDelay,
920 id if Self::ActiveConnectionIdLimit == id => Self::ActiveConnectionIdLimit,
921 id if Self::ReservedTransportParameter == id => Self::ReservedTransportParameter,
922 id if Self::StatelessResetToken == id => Self::StatelessResetToken,
923 id if Self::DisableActiveMigration == id => Self::DisableActiveMigration,
924 id if Self::MaxDatagramFrameSize == id => Self::MaxDatagramFrameSize,
925 id if Self::PreferredAddress == id => Self::PreferredAddress,
926 id if Self::OriginalDestinationConnectionId == id => {
927 Self::OriginalDestinationConnectionId
928 }
929 id if Self::InitialSourceConnectionId == id => Self::InitialSourceConnectionId,
930 id if Self::RetrySourceConnectionId == id => Self::RetrySourceConnectionId,
931 id if Self::GreaseQuicBit == id => Self::GreaseQuicBit,
932 id if Self::MinAckDelayDraft07 == id => Self::MinAckDelayDraft07,
933 id if Self::NatTraversal == id => Self::NatTraversal,
934 _ => return Err(()),
935 };
936 Ok(param)
937 }
938}
939
940fn decode_cid(len: usize, value: &mut Option<ConnectionId>, r: &mut impl Buf) -> Result<(), Error> {
941 if len > MAX_CID_SIZE || value.is_some() || r.remaining() < len {
942 return Err(Error::Malformed);
943 }
944
945 *value = Some(ConnectionId::from_buf(r, len));
946 Ok(())
947}
948
949#[cfg(test)]
950mod test {
951 use super::*;
952
953 #[test]
954 fn test_nat_traversal_transport_parameter_encoding_decoding() {
955 let client_config = NatTraversalConfig {
959 role: NatTraversalRole::Client,
960 max_candidates: VarInt::from_u32(8),
961 coordination_timeout: VarInt::from_u32(5000),
962 max_concurrent_attempts: VarInt::from_u32(3),
963 peer_id: None,
964 };
965
966 let mut client_params = TransportParameters::default();
967 client_params.nat_traversal = Some(client_config);
968
969 let mut encoded = Vec::new();
970 client_params.write(&mut encoded);
971
972 let server_decoded = TransportParameters::read(Side::Server, &mut encoded.as_slice())
974 .expect("Failed to decode client transport parameters");
975
976 assert!(server_decoded.nat_traversal.is_some());
978 let server_view = server_decoded.nat_traversal.unwrap();
979 assert!(matches!(server_view.role, NatTraversalRole::Client));
980
981 let server_config = NatTraversalConfig {
983 role: NatTraversalRole::Server { can_relay: false },
984 max_candidates: VarInt::from_u32(16),
985 coordination_timeout: VarInt::from_u32(10000),
986 max_concurrent_attempts: VarInt::from_u32(5),
987 peer_id: None,
988 };
989
990 let mut server_params = TransportParameters::default();
991 server_params.nat_traversal = Some(server_config);
992
993 let mut encoded = Vec::new();
994 server_params.write(&mut encoded);
995
996 let client_decoded = TransportParameters::read(Side::Client, &mut encoded.as_slice())
998 .expect("Failed to decode server transport parameters");
999
1000 assert!(client_decoded.nat_traversal.is_some());
1002 let client_view = client_decoded.nat_traversal.unwrap();
1003 assert!(matches!(client_view.role, NatTraversalRole::Server { .. }));
1004 assert_eq!(client_view.max_concurrent_attempts, VarInt::from_u32(5));
1005 }
1006
1007 #[test]
1008 fn test_nat_traversal_parameter_without_peer_id() {
1009 let config = NatTraversalConfig {
1011 role: NatTraversalRole::Client,
1012 max_candidates: VarInt::from_u32(4),
1013 coordination_timeout: VarInt::from_u32(3000),
1014 max_concurrent_attempts: VarInt::from_u32(2),
1015 peer_id: None,
1016 };
1017
1018 let mut params = TransportParameters::default();
1019 params.nat_traversal = Some(config);
1020
1021 let mut encoded = Vec::new();
1022 params.write(&mut encoded);
1023
1024 let decoded_params = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1026 .expect("Failed to decode transport parameters");
1027
1028 let decoded_config = decoded_params.nat_traversal
1029 .expect("NAT traversal config should be present");
1030
1031 assert_eq!(decoded_config.role, NatTraversalRole::Client);
1032 assert!(decoded_config.peer_id.is_none());
1033
1034 let server_config = NatTraversalConfig {
1036 role: NatTraversalRole::Server { can_relay: true },
1037 max_candidates: VarInt::from_u32(8),
1038 coordination_timeout: VarInt::from_u32(5000),
1039 max_concurrent_attempts: VarInt::from_u32(4),
1040 peer_id: None,
1041 };
1042
1043 let mut server_params = TransportParameters::default();
1044 server_params.nat_traversal = Some(server_config);
1045
1046 let mut server_encoded = Vec::new();
1047 server_params.write(&mut server_encoded);
1048
1049 let decoded_server_params = TransportParameters::read(Side::Client, &mut server_encoded.as_slice())
1051 .expect("Failed to decode server transport parameters");
1052
1053 let decoded_server_config = decoded_server_params.nat_traversal
1054 .expect("Server NAT traversal config should be present");
1055
1056 match decoded_server_config.role {
1057 NatTraversalRole::Server { can_relay } => {
1058 assert!(!can_relay);
1060 },
1061 _ => panic!("Expected server role"),
1062 }
1063 assert_eq!(decoded_server_config.max_concurrent_attempts, VarInt::from_u32(4));
1064 }
1065
1066 #[test]
1067 fn test_transport_parameters_without_nat_traversal() {
1068 let mut params = TransportParameters::default();
1070 params.nat_traversal = None;
1071
1072 let mut encoded = Vec::new();
1073 params.write(&mut encoded);
1074
1075 let decoded_params = TransportParameters::read(Side::Client, &mut encoded.as_slice())
1076 .expect("Failed to decode transport parameters");
1077
1078 assert!(decoded_params.nat_traversal.is_none());
1079 }
1080
1081 #[test]
1082 fn test_nat_traversal_draft_compliant_encoding() {
1083 let client_config = NatTraversalConfig {
1087 role: NatTraversalRole::Client,
1088 max_candidates: VarInt::from_u32(8),
1089 coordination_timeout: VarInt::from_u32(10000),
1090 max_concurrent_attempts: VarInt::from_u32(3),
1091 peer_id: None,
1092 };
1093
1094 let mut client_params = TransportParameters::default();
1095 client_params.nat_traversal = Some(client_config);
1096
1097 let mut encoded = Vec::new();
1098 client_params.write(&mut encoded);
1099
1100 use bytes::Buf;
1103 let mut cursor = &encoded[..];
1104 while cursor.has_remaining() {
1105 let id = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1106 let len = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1107 if id.0 == 0x3d7e9f0bca12fea6 {
1108 assert_eq!(len.0, 0, "Client should send empty value");
1110 break;
1111 }
1112 cursor.advance(len.0 as usize);
1114 }
1115
1116 let server_config = NatTraversalConfig {
1118 role: NatTraversalRole::Server { can_relay: true },
1119 max_candidates: VarInt::from_u32(16),
1120 coordination_timeout: VarInt::from_u32(10000),
1121 max_concurrent_attempts: VarInt::from_u32(5),
1122 peer_id: None,
1123 };
1124
1125 let mut server_params = TransportParameters::default();
1126 server_params.nat_traversal = Some(server_config);
1127
1128 let mut encoded = Vec::new();
1129 server_params.write(&mut encoded);
1130
1131 let mut cursor = &encoded[..];
1133 while cursor.has_remaining() {
1134 let id = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1135 let len = VarInt::from_u64(cursor.get_var().unwrap()).unwrap();
1136 if id.0 == 0x3d7e9f0bca12fea6 {
1137 assert_eq!(len.0, 1, "Server should send 1-byte value");
1139 let limit = cursor.chunk()[0];
1140 assert_eq!(limit, 5, "Server should send concurrency limit");
1141 break;
1142 }
1143 cursor.advance(len.0 as usize);
1145 }
1146 }
1147
1148 #[test]
1149 fn test_nat_traversal_draft_compliant_decoding() {
1150 use bytes::BufMut;
1151
1152 let mut buf = Vec::new();
1154 buf.write_var(0x3d7e9f0bca12fea6); buf.write_var(0); let params = TransportParameters::read(Side::Server, &mut buf.as_slice())
1158 .expect("Failed to decode transport parameters");
1159
1160 let config = params.nat_traversal.expect("NAT traversal should be present");
1161 assert_eq!(config.role, NatTraversalRole::Client);
1162 assert_eq!(config.max_candidates, VarInt::from_u32(8)); assert_eq!(config.coordination_timeout, VarInt::from_u32(10000)); assert_eq!(config.max_concurrent_attempts, VarInt::from_u32(3)); let mut buf = Vec::new();
1168 buf.write_var(0x3d7e9f0bca12fea6); buf.write_var(1); buf.put_u8(7); let params = TransportParameters::read(Side::Client, &mut buf.as_slice())
1173 .expect("Failed to decode transport parameters");
1174
1175 let config = params.nat_traversal.expect("NAT traversal should be present");
1176 match config.role {
1177 NatTraversalRole::Server { can_relay } => {
1178 assert!(!can_relay); }
1180 _ => panic!("Expected Server role"),
1181 }
1182 assert_eq!(config.max_concurrent_attempts, VarInt::from_u32(7));
1183
1184 let mut buf = Vec::new();
1186 buf.write_var(0x3d7e9f0bca12fea6); buf.write_var(2); buf.put_u8(7);
1189 buf.put_u8(8);
1190
1191 let result = TransportParameters::read(Side::Client, &mut buf.as_slice());
1192 assert!(result.is_err(), "Should fail with invalid length");
1193 }
1194
1195 #[test]
1196 fn test_nat_traversal_parameter_id() {
1197 assert_eq!(TransportParameterId::NatTraversal as u64, 0x3d7e9f0bca12fea6);
1199 }
1200
1201 #[test]
1202 fn test_nat_traversal_config_validation() {
1203 let valid_config = NatTraversalConfig {
1205 role: NatTraversalRole::Client,
1206 max_candidates: VarInt::from_u32(8),
1207 coordination_timeout: VarInt::from_u32(5000),
1208 max_concurrent_attempts: VarInt::from_u32(3),
1209 peer_id: None,
1210 };
1211 assert!(valid_config.validate().is_ok());
1212
1213 let invalid_config = NatTraversalConfig {
1215 max_candidates: VarInt::from_u32(0),
1216 ..valid_config
1217 };
1218 assert!(invalid_config.validate().is_err());
1219
1220 let invalid_config = NatTraversalConfig {
1222 max_candidates: VarInt::from_u32(101),
1223 ..valid_config
1224 };
1225 assert!(invalid_config.validate().is_err());
1226
1227 let invalid_config = NatTraversalConfig {
1229 coordination_timeout: VarInt::from_u32(500),
1230 ..valid_config
1231 };
1232 assert!(invalid_config.validate().is_err());
1233
1234 let invalid_config = NatTraversalConfig {
1236 coordination_timeout: VarInt::from_u32(70000),
1237 ..valid_config
1238 };
1239 assert!(invalid_config.validate().is_err());
1240
1241 let invalid_config = NatTraversalConfig {
1243 max_concurrent_attempts: VarInt::from_u32(0),
1244 ..valid_config
1245 };
1246 assert!(invalid_config.validate().is_err());
1247
1248 let invalid_config = NatTraversalConfig {
1250 max_concurrent_attempts: VarInt::from_u32(11),
1251 ..valid_config
1252 };
1253 assert!(invalid_config.validate().is_err());
1254 }
1255
1256 #[test]
1257 fn test_nat_traversal_role_validation() {
1258 use bytes::BufMut;
1259
1260 let mut buf = Vec::new();
1262 buf.write_var(0x3d7e9f0bca12fea6); buf.write_var(0); let result = TransportParameters::read(Side::Client, &mut buf.as_slice());
1267 assert!(result.is_err(), "Client should not accept client role from peer");
1268
1269 let result = TransportParameters::read(Side::Server, &mut buf.as_slice());
1271 assert!(result.is_ok(), "Server should accept client role from peer");
1272
1273 let mut buf = Vec::new();
1275 buf.write_var(0x3d7e9f0bca12fea6); buf.write_var(1); buf.put_u8(5); let result = TransportParameters::read(Side::Server, &mut buf.as_slice());
1281 assert!(result.is_err(), "Server should not accept server role from peer");
1282
1283 let result = TransportParameters::read(Side::Client, &mut buf.as_slice());
1285 assert!(result.is_ok(), "Client should accept server role from peer");
1286 }
1287
1288 #[test]
1289 fn test_nat_traversal_parameter_combinations() {
1290 let nat_config = NatTraversalConfig {
1292 role: NatTraversalRole::Client,
1293 max_candidates: VarInt::from_u32(10),
1294 coordination_timeout: VarInt::from_u32(8000),
1295 max_concurrent_attempts: VarInt::from_u32(4),
1296 peer_id: Some([42u8; 32]),
1297 };
1298
1299 let mut params = TransportParameters::default();
1300 params.nat_traversal = Some(nat_config);
1301 params.max_idle_timeout = VarInt::from_u32(30000);
1302 params.initial_max_data = VarInt::from_u32(1048576);
1303 params.grease_quic_bit = true;
1304
1305 let mut encoded = Vec::new();
1307 params.write(&mut encoded);
1308 assert!(!encoded.is_empty());
1309
1310 let decoded = TransportParameters::read(Side::Server, &mut encoded.as_slice())
1312 .expect("Should decode successfully");
1313
1314 let decoded_config = decoded.nat_traversal.expect("NAT traversal should be present");
1316 assert_eq!(decoded_config.role, NatTraversalRole::Client);
1317 assert_eq!(decoded_config.max_candidates, VarInt::from_u32(8)); assert_eq!(decoded.max_idle_timeout, VarInt::from_u32(30000));
1321 assert_eq!(decoded.initial_max_data, VarInt::from_u32(1048576));
1322 assert!(decoded.grease_quic_bit);
1323 }
1324
1325 #[test]
1326 fn test_nat_traversal_default_config() {
1327 let default_config = NatTraversalConfig::default();
1328
1329 assert_eq!(default_config.role, NatTraversalRole::Client);
1330 assert_eq!(default_config.max_candidates, VarInt::from_u32(8));
1331 assert_eq!(default_config.coordination_timeout, VarInt::from_u32(10000));
1332 assert_eq!(default_config.max_concurrent_attempts, VarInt::from_u32(3));
1333 assert!(default_config.peer_id.is_none());
1334
1335 assert!(default_config.validate().is_ok());
1337 }
1338
1339 #[test]
1340 fn test_nat_traversal_endpoint_role_negotiation() {
1341 let client_config = NatTraversalConfig {
1345 role: NatTraversalRole::Client,
1346 max_candidates: VarInt::from_u32(12),
1347 coordination_timeout: VarInt::from_u32(7000),
1348 max_concurrent_attempts: VarInt::from_u32(5),
1349 peer_id: None,
1350 };
1351
1352 let mut client_params = TransportParameters::default();
1353 client_params.nat_traversal = Some(client_config);
1354
1355 let mut client_encoded = Vec::new();
1357 client_params.write(&mut client_encoded);
1358
1359 let server_received = TransportParameters::read(Side::Server, &mut client_encoded.as_slice())
1361 .expect("Server should decode client params");
1362
1363 let server_view = server_received.nat_traversal.expect("NAT traversal should be present");
1365 assert_eq!(server_view.role, NatTraversalRole::Client);
1366
1367 let server_config = NatTraversalConfig {
1369 role: NatTraversalRole::Server { can_relay: true },
1370 max_candidates: VarInt::from_u32(16),
1371 coordination_timeout: VarInt::from_u32(12000),
1372 max_concurrent_attempts: VarInt::from_u32(8),
1373 peer_id: Some([123u8; 32]),
1374 };
1375
1376 let mut server_params = TransportParameters::default();
1377 server_params.nat_traversal = Some(server_config);
1378
1379 let mut server_encoded = Vec::new();
1381 server_params.write(&mut server_encoded);
1382
1383 let client_received = TransportParameters::read(Side::Client, &mut server_encoded.as_slice())
1385 .expect("Client should decode server params");
1386
1387 let client_view = client_received.nat_traversal.expect("NAT traversal should be present");
1389 match client_view.role {
1390 NatTraversalRole::Server { can_relay } => {
1391 assert!(!can_relay); }
1393 _ => panic!("Expected server role"),
1394 }
1395 assert_eq!(client_view.max_concurrent_attempts, VarInt::from_u32(8));
1396 }
1397
1398 #[test]
1399 fn coding() {
1400 let mut buf = Vec::new();
1401 let params = TransportParameters {
1402 initial_src_cid: Some(ConnectionId::new(&[])),
1403 original_dst_cid: Some(ConnectionId::new(&[])),
1404 initial_max_streams_bidi: 16u32.into(),
1405 initial_max_streams_uni: 16u32.into(),
1406 ack_delay_exponent: 2u32.into(),
1407 max_udp_payload_size: 1200u32.into(),
1408 preferred_address: Some(PreferredAddress {
1409 address_v4: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 42)),
1410 address_v6: Some(SocketAddrV6::new(Ipv6Addr::LOCALHOST, 24, 0, 0)),
1411 connection_id: ConnectionId::new(&[0x42]),
1412 stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
1413 }),
1414 grease_quic_bit: true,
1415 min_ack_delay: Some(2_000u32.into()),
1416 ..TransportParameters::default()
1417 };
1418 params.write(&mut buf);
1419 assert_eq!(
1420 TransportParameters::read(Side::Client, &mut buf.as_slice()).unwrap(),
1421 params
1422 );
1423 }
1424
1425 #[test]
1426 fn reserved_transport_parameter_generate_reserved_id() {
1427 use rand::rngs::mock::StepRng;
1428 let mut rngs = [
1429 StepRng::new(0, 1),
1430 StepRng::new(1, 1),
1431 StepRng::new(27, 1),
1432 StepRng::new(31, 1),
1433 StepRng::new(u32::MAX as u64, 1),
1434 StepRng::new(u32::MAX as u64 - 1, 1),
1435 StepRng::new(u32::MAX as u64 + 1, 1),
1436 StepRng::new(u32::MAX as u64 - 27, 1),
1437 StepRng::new(u32::MAX as u64 + 27, 1),
1438 StepRng::new(u32::MAX as u64 - 31, 1),
1439 StepRng::new(u32::MAX as u64 + 31, 1),
1440 StepRng::new(u64::MAX, 1),
1441 StepRng::new(u64::MAX - 1, 1),
1442 StepRng::new(u64::MAX - 27, 1),
1443 StepRng::new(u64::MAX - 31, 1),
1444 StepRng::new(1 << 62, 1),
1445 StepRng::new((1 << 62) - 1, 1),
1446 StepRng::new((1 << 62) + 1, 1),
1447 StepRng::new((1 << 62) - 27, 1),
1448 StepRng::new((1 << 62) + 27, 1),
1449 StepRng::new((1 << 62) - 31, 1),
1450 StepRng::new((1 << 62) + 31, 1),
1451 ];
1452 for rng in &mut rngs {
1453 let id = ReservedTransportParameter::generate_reserved_id(rng);
1454 assert!(id.0 % 31 == 27)
1455 }
1456 }
1457
1458 #[test]
1459 fn reserved_transport_parameter_ignored_when_read() {
1460 let mut buf = Vec::new();
1461 let reserved_parameter = ReservedTransportParameter::random(&mut rand::thread_rng());
1462 assert!(reserved_parameter.payload_len < ReservedTransportParameter::MAX_PAYLOAD_LEN);
1463 assert!(reserved_parameter.id.0 % 31 == 27);
1464
1465 reserved_parameter.write(&mut buf);
1466 assert!(!buf.is_empty());
1467 let read_params = TransportParameters::read(Side::Server, &mut buf.as_slice()).unwrap();
1468 assert_eq!(read_params, TransportParameters::default());
1469 }
1470
1471 #[test]
1472 fn read_semantic_validation() {
1473 #[allow(clippy::type_complexity)]
1474 let illegal_params_builders: Vec<Box<dyn FnMut(&mut TransportParameters)>> = vec![
1475 Box::new(|t| {
1476 let min_ack_delay = t.max_ack_delay.0 * 1_000 + 1;
1478 t.min_ack_delay = Some(VarInt::from_u64(min_ack_delay).unwrap())
1479 }),
1480 Box::new(|t| {
1481 t.preferred_address = Some(PreferredAddress {
1484 address_v4: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 42)),
1485 address_v6: None,
1486 connection_id: ConnectionId::new(&[]),
1487 stateless_reset_token: [0xab; RESET_TOKEN_SIZE].into(),
1488 })
1489 }),
1490 ];
1491
1492 for mut builder in illegal_params_builders {
1493 let mut buf = Vec::new();
1494 let mut params = TransportParameters::default();
1495 builder(&mut params);
1496 params.write(&mut buf);
1497
1498 assert_eq!(
1499 TransportParameters::read(Side::Server, &mut buf.as_slice()),
1500 Err(Error::IllegalValue)
1501 );
1502 }
1503 }
1504
1505 #[test]
1506 fn resumption_params_validation() {
1507 let high_limit = TransportParameters {
1508 initial_max_streams_uni: 32u32.into(),
1509 ..TransportParameters::default()
1510 };
1511 let low_limit = TransportParameters {
1512 initial_max_streams_uni: 16u32.into(),
1513 ..TransportParameters::default()
1514 };
1515 high_limit.validate_resumption_from(&low_limit).unwrap();
1516 low_limit.validate_resumption_from(&high_limit).unwrap_err();
1517 }
1518}