ant_quic/config/
mod.rs

1use std::{
2    fmt,
3    net::{SocketAddrV4, SocketAddrV6},
4    num::TryFromIntError,
5    sync::Arc,
6};
7
8#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
9use rustls::client::WebPkiServerVerifier;
10#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
11use rustls::pki_types::{CertificateDer, PrivateKeyDer};
12use thiserror::Error;
13
14#[cfg(feature = "bloom")]
15use crate::NoneTokenLog;
16#[cfg(not(feature = "bloom"))]
17use crate::NoneTokenLog;
18#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
19use crate::crypto::rustls::{QuicServerConfig, configured_provider};
20use crate::{
21    DEFAULT_SUPPORTED_VERSIONS, Duration, MAX_CID_SIZE, RandomConnectionIdGenerator, SystemTime,
22    TokenLog, TokenMemoryCache, TokenStore, VarInt, VarIntBoundsExceeded,
23    cid_generator::{ConnectionIdGenerator, HashedConnectionIdGenerator},
24    crypto::{self, HandshakeTokenKey, HmacKey},
25    shared::ConnectionId,
26};
27
28mod transport;
29pub use transport::{AckFrequencyConfig, IdleTimeout, MtuDiscoveryConfig, TransportConfig};
30
31/// Configuration for QUIC Address Discovery extension
32#[derive(Debug, Clone)]
33pub struct AddressDiscoveryConfig {
34    /// Whether address discovery is enabled
35    pub enabled: bool,
36    /// Maximum observation rate (frames per second)
37    pub max_observation_rate: u8,
38    /// Whether to observe all paths or just active ones
39    pub observe_all_paths: bool,
40}
41
42impl Default for AddressDiscoveryConfig {
43    fn default() -> Self {
44        Self {
45            enabled: true, // Enabled by default as requested
46            max_observation_rate: 10, // Reasonable default rate
47            observe_all_paths: false, // Only observe active paths by default
48        }
49    }
50}
51
52pub mod timeouts;
53
54// Production-ready configuration validation
55pub(crate) mod validation;
56
57/// Global configuration for the endpoint, affecting all connections
58///
59/// Default values should be suitable for most internet applications.
60#[derive(Clone)]
61pub struct EndpointConfig {
62    pub(crate) reset_key: Arc<dyn HmacKey>,
63    pub(crate) max_udp_payload_size: VarInt,
64    /// CID generator factory
65    ///
66    /// Create a cid generator for local cid in Endpoint struct
67    pub(crate) connection_id_generator_factory:
68        Arc<dyn Fn() -> Box<dyn ConnectionIdGenerator> + Send + Sync>,
69    pub(crate) supported_versions: Vec<u32>,
70    pub(crate) grease_quic_bit: bool,
71    /// Minimum interval between outgoing stateless reset packets
72    pub(crate) min_reset_interval: Duration,
73    /// Optional seed to be used internally for random number generation
74    pub(crate) rng_seed: Option<[u8; 32]>,
75    /// Address discovery configuration
76    pub(crate) address_discovery_config: AddressDiscoveryConfig,
77}
78
79impl EndpointConfig {
80    /// Create a default config with a particular `reset_key`
81    pub fn new(reset_key: Arc<dyn HmacKey>) -> Self {
82        let cid_factory =
83            || -> Box<dyn ConnectionIdGenerator> { Box::<HashedConnectionIdGenerator>::default() };
84        Self {
85            reset_key,
86            max_udp_payload_size: (1500u32 - 28).into(), // Ethernet MTU minus IP + UDP headers
87            connection_id_generator_factory: Arc::new(cid_factory),
88            supported_versions: DEFAULT_SUPPORTED_VERSIONS.to_vec(),
89            grease_quic_bit: true,
90            min_reset_interval: Duration::from_millis(20),
91            rng_seed: None,
92            address_discovery_config: AddressDiscoveryConfig::default(),
93        }
94    }
95
96    /// Supply a custom connection ID generator factory
97    ///
98    /// Called once by each `Endpoint` constructed from this configuration to obtain the CID
99    /// generator which will be used to generate the CIDs used for incoming packets on all
100    /// connections involving that  `Endpoint`. A custom CID generator allows applications to embed
101    /// information in local connection IDs, e.g. to support stateless packet-level load balancers.
102    ///
103    /// Defaults to [`HashedConnectionIdGenerator`].
104    pub fn cid_generator<F: Fn() -> Box<dyn ConnectionIdGenerator> + Send + Sync + 'static>(
105        &mut self,
106        factory: F,
107    ) -> &mut Self {
108        self.connection_id_generator_factory = Arc::new(factory);
109        self
110    }
111
112    /// Private key used to send authenticated connection resets to peers who were
113    /// communicating with a previous instance of this endpoint.
114    pub fn reset_key(&mut self, key: Arc<dyn HmacKey>) -> &mut Self {
115        self.reset_key = key;
116        self
117    }
118
119    /// Maximum UDP payload size accepted from peers (excluding UDP and IP overhead).
120    ///
121    /// Must be greater or equal than 1200.
122    ///
123    /// Defaults to 1472, which is the largest UDP payload that can be transmitted in the typical
124    /// 1500 byte Ethernet MTU. Deployments on links with larger MTUs (e.g. loopback or Ethernet
125    /// with jumbo frames) can raise this to improve performance at the cost of a linear increase in
126    /// datagram receive buffer size.
127    pub fn max_udp_payload_size(&mut self, value: u16) -> Result<&mut Self, ConfigError> {
128        if !(1200..=65_527).contains(&value) {
129            return Err(ConfigError::OutOfBounds);
130        }
131
132        self.max_udp_payload_size = value.into();
133        Ok(self)
134    }
135
136    /// Get the current value of [`max_udp_payload_size`](Self::max_udp_payload_size)
137    //
138    // While most parameters don't need to be readable, this must be exposed to allow higher-level
139    // layers, e.g. the `quinn` crate, to determine how large a receive buffer to allocate to
140    // support an externally-defined `EndpointConfig`.
141    //
142    // While `get_` accessors are typically unidiomatic in Rust, we favor concision for setters,
143    // which will be used far more heavily.
144    pub fn get_max_udp_payload_size(&self) -> u64 {
145        self.max_udp_payload_size.into()
146    }
147
148    /// Override supported QUIC versions
149    pub fn supported_versions(&mut self, supported_versions: Vec<u32>) -> &mut Self {
150        self.supported_versions = supported_versions;
151        self
152    }
153
154    /// Whether to accept QUIC packets containing any value for the fixed bit
155    ///
156    /// Enabled by default. Helps protect against protocol ossification and makes traffic less
157    /// identifiable to observers. Disable if helping observers identify this traffic as QUIC is
158    /// desired.
159    pub fn grease_quic_bit(&mut self, value: bool) -> &mut Self {
160        self.grease_quic_bit = value;
161        self
162    }
163
164    /// Minimum interval between outgoing stateless reset packets
165    ///
166    /// Defaults to 20ms. Limits the impact of attacks which flood an endpoint with garbage packets,
167    /// e.g. [ISAKMP/IKE amplification]. Larger values provide a stronger defense, but may delay
168    /// detection of some error conditions by clients. Using a [`ConnectionIdGenerator`] with a low
169    /// rate of false positives in [`validate`](ConnectionIdGenerator::validate) reduces the risk
170    /// incurred by a small minimum reset interval.
171    ///
172    /// [ISAKMP/IKE
173    /// amplification]: https://bughunters.google.com/blog/5960150648750080/preventing-cross-service-udp-loops-in-quic#isakmp-ike-amplification-vs-quic
174    pub fn min_reset_interval(&mut self, value: Duration) -> &mut Self {
175        self.min_reset_interval = value;
176        self
177    }
178
179    /// Optional seed to be used internally for random number generation
180    ///
181    /// By default, quinn will initialize an endpoint's rng using a platform entropy source.
182    /// However, you can seed the rng yourself through this method (e.g. if you need to run quinn
183    /// deterministically or if you are using quinn in an environment that doesn't have a source of
184    /// entropy available).
185    pub fn rng_seed(&mut self, seed: Option<[u8; 32]>) -> &mut Self {
186        self.rng_seed = seed;
187        self
188    }
189    
190    /// Check if address discovery is enabled
191    /// 
192    /// Checks environment variables first, then falls back to configuration
193    pub fn address_discovery_enabled(&self) -> bool {
194        // Check environment variable override
195        if let Ok(val) = std::env::var("ANT_QUIC_ADDRESS_DISCOVERY_ENABLED") {
196            return val.to_lowercase() == "true" || val == "1";
197        }
198        self.address_discovery_config.enabled
199    }
200    
201    /// Set whether address discovery is enabled
202    pub fn set_address_discovery_enabled(&mut self, enabled: bool) -> &mut Self {
203        self.address_discovery_config.enabled = enabled;
204        self
205    }
206    
207    /// Get the maximum observation rate
208    /// 
209    /// Checks environment variables first, then falls back to configuration
210    pub fn max_observation_rate(&self) -> u8 {
211        // Check environment variable override
212        if let Ok(val) = std::env::var("ANT_QUIC_MAX_OBSERVATION_RATE") {
213            if let Ok(rate) = val.parse::<u8>() {
214                return rate.min(63); // Cap at protocol maximum
215            }
216        }
217        self.address_discovery_config.max_observation_rate
218    }
219    
220    /// Set the maximum observation rate (0-63 per second)
221    pub fn set_max_observation_rate(&mut self, rate: u8) -> &mut Self {
222        self.address_discovery_config.max_observation_rate = rate.min(63);
223        self
224    }
225    
226    /// Check if all paths should be observed
227    pub fn observe_all_paths(&self) -> bool {
228        self.address_discovery_config.observe_all_paths
229    }
230    
231    /// Set whether to observe all paths or just active ones
232    pub fn set_observe_all_paths(&mut self, observe_all: bool) -> &mut Self {
233        self.address_discovery_config.observe_all_paths = observe_all;
234        self
235    }
236    
237    /// Builder method for enabling address discovery
238    pub fn address_discovery(mut self, enabled: bool) -> Self {
239        self.address_discovery_config.enabled = enabled;
240        self
241    }
242    
243    /// Builder method for setting observation rate
244    pub fn observation_rate(mut self, rate: u8) -> Self {
245        self.address_discovery_config.max_observation_rate = rate.min(63);
246        self
247    }
248    
249    /// Builder method for observing all paths
250    pub fn with_observe_all_paths(mut self, observe_all: bool) -> Self {
251        self.address_discovery_config.observe_all_paths = observe_all;
252        self
253    }
254    
255    /// Check if address discovery feature is available
256    /// 
257    /// Always returns true as address discovery is a core feature
258    pub fn address_discovery_available(&self) -> bool {
259        true
260    }
261}
262
263impl fmt::Debug for EndpointConfig {
264    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
265        fmt.debug_struct("EndpointConfig")
266            // reset_key not debug
267            .field("max_udp_payload_size", &self.max_udp_payload_size)
268            // cid_generator_factory not debug
269            .field("supported_versions", &self.supported_versions)
270            .field("grease_quic_bit", &self.grease_quic_bit)
271            .field("rng_seed", &self.rng_seed)
272            .field("address_discovery_config", &self.address_discovery_config)
273            .finish_non_exhaustive()
274    }
275}
276
277#[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
278impl Default for EndpointConfig {
279    fn default() -> Self {
280        #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]
281        use aws_lc_rs::hmac;
282        use rand::RngCore;
283        #[cfg(feature = "ring")]
284        use ring::hmac;
285
286        let mut reset_key = [0; 64];
287        rand::thread_rng().fill_bytes(&mut reset_key);
288
289        Self::new(Arc::new(hmac::Key::new(hmac::HMAC_SHA256, &reset_key)))
290    }
291}
292
293/// Parameters governing incoming connections
294///
295/// Default values should be suitable for most internet applications.
296#[derive(Clone)]
297pub struct ServerConfig {
298    /// Transport configuration to use for incoming connections
299    pub transport: Arc<TransportConfig>,
300
301    /// TLS configuration used for incoming connections
302    ///
303    /// Must be set to use TLS 1.3 only.
304    pub crypto: Arc<dyn crypto::ServerConfig>,
305
306    /// Configuration for sending and handling validation tokens
307    pub validation_token: ValidationTokenConfig,
308
309    /// Used to generate one-time AEAD keys to protect handshake tokens
310    pub(crate) token_key: Arc<dyn HandshakeTokenKey>,
311
312    /// Duration after a retry token was issued for which it's considered valid
313    pub(crate) retry_token_lifetime: Duration,
314
315    /// Whether to allow clients to migrate to new addresses
316    ///
317    /// Improves behavior for clients that move between different internet connections or suffer NAT
318    /// rebinding. Enabled by default.
319    pub(crate) migration: bool,
320
321    pub(crate) preferred_address_v4: Option<SocketAddrV4>,
322    pub(crate) preferred_address_v6: Option<SocketAddrV6>,
323
324    pub(crate) max_incoming: usize,
325    pub(crate) incoming_buffer_size: u64,
326    pub(crate) incoming_buffer_size_total: u64,
327
328    pub(crate) time_source: Arc<dyn TimeSource>,
329}
330
331impl ServerConfig {
332    /// Create a default config with a particular handshake token key
333    pub fn new(
334        crypto: Arc<dyn crypto::ServerConfig>,
335        token_key: Arc<dyn HandshakeTokenKey>,
336    ) -> Self {
337        Self {
338            transport: Arc::new(TransportConfig::default()),
339            crypto,
340
341            token_key,
342            retry_token_lifetime: Duration::from_secs(15),
343
344            migration: true,
345
346            validation_token: ValidationTokenConfig::default(),
347
348            preferred_address_v4: None,
349            preferred_address_v6: None,
350
351            max_incoming: 1 << 16,
352            incoming_buffer_size: 10 << 20,
353            incoming_buffer_size_total: 100 << 20,
354
355            time_source: Arc::new(StdSystemTime),
356        }
357    }
358
359    /// Set a custom [`TransportConfig`]
360    pub fn transport_config(&mut self, transport: Arc<TransportConfig>) -> &mut Self {
361        self.transport = transport;
362        self
363    }
364
365    /// Set a custom [`ValidationTokenConfig`]
366    pub fn validation_token_config(
367        &mut self,
368        validation_token: ValidationTokenConfig,
369    ) -> &mut Self {
370        self.validation_token = validation_token;
371        self
372    }
373
374    /// Private key used to authenticate data included in handshake tokens
375    pub fn token_key(&mut self, value: Arc<dyn HandshakeTokenKey>) -> &mut Self {
376        self.token_key = value;
377        self
378    }
379
380    /// Duration after a retry token was issued for which it's considered valid
381    ///
382    /// Defaults to 15 seconds.
383    pub fn retry_token_lifetime(&mut self, value: Duration) -> &mut Self {
384        self.retry_token_lifetime = value;
385        self
386    }
387
388    /// Whether to allow clients to migrate to new addresses
389    ///
390    /// Improves behavior for clients that move between different internet connections or suffer NAT
391    /// rebinding. Enabled by default.
392    pub fn migration(&mut self, value: bool) -> &mut Self {
393        self.migration = value;
394        self
395    }
396
397    /// The preferred IPv4 address that will be communicated to clients during handshaking
398    ///
399    /// If the client is able to reach this address, it will switch to it.
400    pub fn preferred_address_v4(&mut self, address: Option<SocketAddrV4>) -> &mut Self {
401        self.preferred_address_v4 = address;
402        self
403    }
404
405    /// The preferred IPv6 address that will be communicated to clients during handshaking
406    ///
407    /// If the client is able to reach this address, it will switch to it.
408    pub fn preferred_address_v6(&mut self, address: Option<SocketAddrV6>) -> &mut Self {
409        self.preferred_address_v6 = address;
410        self
411    }
412
413    /// Maximum number of [`Incoming`][crate::Incoming] to allow to exist at a time
414    ///
415    /// An [`Incoming`][crate::Incoming] comes into existence when an incoming connection attempt
416    /// is received and stops existing when the application either accepts it or otherwise disposes
417    /// of it. While this limit is reached, new incoming connection attempts are immediately
418    /// refused. Larger values have greater worst-case memory consumption, but accommodate greater
419    /// application latency in handling incoming connection attempts.
420    ///
421    /// The default value is set to 65536. With a typical Ethernet MTU of 1500 bytes, this limits
422    /// memory consumption from this to under 100 MiB--a generous amount that still prevents memory
423    /// exhaustion in most contexts.
424    pub fn max_incoming(&mut self, max_incoming: usize) -> &mut Self {
425        self.max_incoming = max_incoming;
426        self
427    }
428
429    /// Maximum number of received bytes to buffer for each [`Incoming`][crate::Incoming]
430    ///
431    /// An [`Incoming`][crate::Incoming] comes into existence when an incoming connection attempt
432    /// is received and stops existing when the application either accepts it or otherwise disposes
433    /// of it. This limit governs only packets received within that period, and does not include
434    /// the first packet. Packets received in excess of this limit are dropped, which may cause
435    /// 0-RTT or handshake data to have to be retransmitted.
436    ///
437    /// The default value is set to 10 MiB--an amount such that in most situations a client would
438    /// not transmit that much 0-RTT data faster than the server handles the corresponding
439    /// [`Incoming`][crate::Incoming].
440    pub fn incoming_buffer_size(&mut self, incoming_buffer_size: u64) -> &mut Self {
441        self.incoming_buffer_size = incoming_buffer_size;
442        self
443    }
444
445    /// Maximum number of received bytes to buffer for all [`Incoming`][crate::Incoming]
446    /// collectively
447    ///
448    /// An [`Incoming`][crate::Incoming] comes into existence when an incoming connection attempt
449    /// is received and stops existing when the application either accepts it or otherwise disposes
450    /// of it. This limit governs only packets received within that period, and does not include
451    /// the first packet. Packets received in excess of this limit are dropped, which may cause
452    /// 0-RTT or handshake data to have to be retransmitted.
453    ///
454    /// The default value is set to 100 MiB--a generous amount that still prevents memory
455    /// exhaustion in most contexts.
456    pub fn incoming_buffer_size_total(&mut self, incoming_buffer_size_total: u64) -> &mut Self {
457        self.incoming_buffer_size_total = incoming_buffer_size_total;
458        self
459    }
460
461    /// Object to get current [`SystemTime`]
462    ///
463    /// This exists to allow system time to be mocked in tests, or wherever else desired.
464    ///
465    /// Defaults to [`StdSystemTime`], which simply calls [`SystemTime::now()`](SystemTime::now).
466    pub fn time_source(&mut self, time_source: Arc<dyn TimeSource>) -> &mut Self {
467        self.time_source = time_source;
468        self
469    }
470
471    pub(crate) fn has_preferred_address(&self) -> bool {
472        self.preferred_address_v4.is_some() || self.preferred_address_v6.is_some()
473    }
474}
475
476#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
477impl ServerConfig {
478    /// Create a server config with the given certificate chain to be presented to clients
479    ///
480    /// Uses a randomized handshake token key.
481    pub fn with_single_cert(
482        cert_chain: Vec<CertificateDer<'static>>,
483        key: PrivateKeyDer<'static>,
484    ) -> Result<Self, rustls::Error> {
485        Ok(Self::with_crypto(Arc::new(QuicServerConfig::new(
486            cert_chain, key,
487        )?)))
488    }
489}
490
491#[cfg(any(feature = "aws-lc-rs", feature = "ring"))]
492impl ServerConfig {
493    /// Create a server config with the given [`crypto::ServerConfig`]
494    ///
495    /// Uses a randomized handshake token key.
496    pub fn with_crypto(crypto: Arc<dyn crypto::ServerConfig>) -> Self {
497        #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]
498        use aws_lc_rs::hkdf;
499        use rand::RngCore;
500        #[cfg(feature = "ring")]
501        use ring::hkdf;
502
503        let rng = &mut rand::thread_rng();
504        let mut master_key = [0u8; 64];
505        rng.fill_bytes(&mut master_key);
506        let master_key = hkdf::Salt::new(hkdf::HKDF_SHA256, &[]).extract(&master_key);
507
508        Self::new(crypto, Arc::new(master_key))
509    }
510}
511
512impl fmt::Debug for ServerConfig {
513    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
514        fmt.debug_struct("ServerConfig")
515            .field("transport", &self.transport)
516            // crypto not debug
517            // token not debug
518            .field("retry_token_lifetime", &self.retry_token_lifetime)
519            .field("validation_token", &self.validation_token)
520            .field("migration", &self.migration)
521            .field("preferred_address_v4", &self.preferred_address_v4)
522            .field("preferred_address_v6", &self.preferred_address_v6)
523            .field("max_incoming", &self.max_incoming)
524            .field("incoming_buffer_size", &self.incoming_buffer_size)
525            .field(
526                "incoming_buffer_size_total",
527                &self.incoming_buffer_size_total,
528            )
529            // system_time_clock not debug
530            .finish_non_exhaustive()
531    }
532}
533
534/// Configuration for sending and handling validation tokens in incoming connections
535///
536/// Default values should be suitable for most internet applications.
537///
538/// ## QUIC Tokens
539///
540/// The QUIC protocol defines a concept of "[address validation][1]". Essentially, one side of a
541/// QUIC connection may appear to be receiving QUIC packets from a particular remote UDP address,
542/// but it will only consider that remote address "validated" once it has convincing evidence that
543/// the address is not being [spoofed][2].
544///
545/// Validation is important primarily because of QUIC's "anti-amplification limit." This limit
546/// prevents a QUIC server from sending a client more than three times the number of bytes it has
547/// received from the client on a given address until that address is validated. This is designed
548/// to mitigate the ability of attackers to use QUIC-based servers as reflectors in [amplification
549/// attacks][3].
550///
551/// A path may become validated in several ways. The server is always considered validated by the
552/// client. The client usually begins in an unvalidated state upon first connecting or migrating,
553/// but then becomes validated through various mechanisms that usually take one network round trip.
554/// However, in some cases, a client which has previously attempted to connect to a server may have
555/// been given a one-time use cryptographically secured "token" that it can send in a subsequent
556/// connection attempt to be validated immediately.
557///
558/// There are two ways these tokens can originate:
559///
560/// - If the server responds to an incoming connection with `retry`, a "retry token" is minted and
561///   sent to the client, which the client immediately uses to attempt to connect again. Retry
562///   tokens operate on short timescales, such as 15 seconds.
563/// - If a client's path within an active connection is validated, the server may send the client
564///   one or more "validation tokens," which the client may store for use in later connections to
565///   the same server. Validation tokens may be valid for much longer lifetimes than retry token.
566///
567/// The usage of validation tokens is most impactful in situations where 0-RTT data is also being
568/// used--in particular, in situations where the server sends the client more than three times more
569/// 0.5-RTT data than it has received 0-RTT data. Since the successful completion of a connection
570/// handshake implicitly causes the client's address to be validated, transmission of 0.5-RTT data
571/// is the main situation where a server might be sending application data to an address that could
572/// be validated by token usage earlier than it would become validated without token usage.
573///
574/// [1]: https://www.rfc-editor.org/rfc/rfc9000.html#section-8
575/// [2]: https://en.wikipedia.org/wiki/IP_address_spoofing
576/// [3]: https://en.wikipedia.org/wiki/Denial-of-service_attack#Amplification
577///
578/// These tokens should not be confused with "stateless reset tokens," which are similarly named
579/// but entirely unrelated.
580#[derive(Clone)]
581pub struct ValidationTokenConfig {
582    pub(crate) lifetime: Duration,
583    pub(crate) log: Arc<dyn TokenLog>,
584    pub(crate) sent: u32,
585}
586
587impl ValidationTokenConfig {
588    /// Duration after an address validation token was issued for which it's considered valid
589    ///
590    /// This refers only to tokens sent in NEW_TOKEN frames, in contrast to retry tokens.
591    ///
592    /// Defaults to 2 weeks.
593    pub fn lifetime(&mut self, value: Duration) -> &mut Self {
594        self.lifetime = value;
595        self
596    }
597
598    #[allow(rustdoc::redundant_explicit_links)] // which links are redundant depends on features
599    /// Set a custom [`TokenLog`]
600    ///
601    /// If the `bloom` feature is enabled (which it is by default), defaults to a default
602    /// [`BloomTokenLog`][crate::BloomTokenLog], which is suitable for most internet applications.
603    ///
604    /// If the `bloom` feature is disabled, defaults to [`NoneTokenLog`][crate::NoneTokenLog],
605    /// which makes the server ignore all address validation tokens (that is, tokens originating
606    /// from NEW_TOKEN frames--retry tokens are not affected).
607    pub fn log(&mut self, log: Arc<dyn TokenLog>) -> &mut Self {
608        self.log = log;
609        self
610    }
611
612    /// Number of address validation tokens sent to a client when its path is validated
613    ///
614    /// This refers only to tokens sent in NEW_TOKEN frames, in contrast to retry tokens.
615    ///
616    /// If the `bloom` feature is enabled (which it is by default), defaults to 2. Otherwise,
617    /// defaults to 0.
618    pub fn sent(&mut self, value: u32) -> &mut Self {
619        self.sent = value;
620        self
621    }
622}
623
624impl Default for ValidationTokenConfig {
625    fn default() -> Self {
626        let log = Arc::new(NoneTokenLog);
627        Self {
628            lifetime: Duration::from_secs(2 * 7 * 24 * 60 * 60),
629            log,
630            sent: if cfg!(feature = "bloom") { 2 } else { 0 },
631        }
632    }
633}
634
635impl fmt::Debug for ValidationTokenConfig {
636    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
637        fmt.debug_struct("ServerValidationTokenConfig")
638            .field("lifetime", &self.lifetime)
639            // log not debug
640            .field("sent", &self.sent)
641            .finish_non_exhaustive()
642    }
643}
644
645/// Configuration for outgoing connections
646///
647/// Default values should be suitable for most internet applications.
648#[derive(Clone)]
649#[non_exhaustive]
650pub struct ClientConfig {
651    /// Transport configuration to use
652    pub(crate) transport: Arc<TransportConfig>,
653
654    /// Cryptographic configuration to use
655    pub(crate) crypto: Arc<dyn crypto::ClientConfig>,
656
657    /// Validation token store to use
658    pub(crate) token_store: Arc<dyn TokenStore>,
659
660    /// Provider that populates the destination connection ID of Initial Packets
661    pub(crate) initial_dst_cid_provider: Arc<dyn Fn() -> ConnectionId + Send + Sync>,
662
663    /// QUIC protocol version to use
664    pub(crate) version: u32,
665}
666
667impl ClientConfig {
668    /// Create a default config with a particular cryptographic config
669    pub fn new(crypto: Arc<dyn crypto::ClientConfig>) -> Self {
670        Self {
671            transport: Default::default(),
672            crypto,
673            token_store: Arc::new(TokenMemoryCache::default()),
674            initial_dst_cid_provider: Arc::new(|| {
675                RandomConnectionIdGenerator::new(MAX_CID_SIZE).generate_cid()
676            }),
677            version: 1,
678        }
679    }
680
681    /// Configure how to populate the destination CID of the initial packet when attempting to
682    /// establish a new connection
683    ///
684    /// By default, it's populated with random bytes with reasonable length, so unless you have
685    /// a good reason, you do not need to change it.
686    ///
687    /// When prefer to override the default, please note that the generated connection ID MUST be
688    /// at least 8 bytes long and unpredictable, as per section 7.2 of RFC 9000.
689    pub fn initial_dst_cid_provider(
690        &mut self,
691        initial_dst_cid_provider: Arc<dyn Fn() -> ConnectionId + Send + Sync>,
692    ) -> &mut Self {
693        self.initial_dst_cid_provider = initial_dst_cid_provider;
694        self
695    }
696
697    /// Set a custom [`TransportConfig`]
698    pub fn transport_config(&mut self, transport: Arc<TransportConfig>) -> &mut Self {
699        self.transport = transport;
700        self
701    }
702
703    /// Set a custom [`TokenStore`]
704    ///
705    /// Defaults to [`TokenMemoryCache`], which is suitable for most internet applications.
706    pub fn token_store(&mut self, store: Arc<dyn TokenStore>) -> &mut Self {
707        self.token_store = store;
708        self
709    }
710
711    /// Set the QUIC version to use
712    pub fn version(&mut self, version: u32) -> &mut Self {
713        self.version = version;
714        self
715    }
716}
717
718#[cfg(any(feature = "rustls-aws-lc-rs", feature = "rustls-ring"))]
719impl ClientConfig {
720    /// Create a client configuration that trusts the platform's native roots
721    #[deprecated(since = "0.11.13", note = "use `try_with_platform_verifier()` instead")]
722    #[cfg(feature = "platform-verifier")]
723    pub fn with_platform_verifier() -> Self {
724        Self::try_with_platform_verifier().expect("use try_with_platform_verifier() instead")
725    }
726
727    /// Create a client configuration that trusts the platform's native roots
728    #[cfg(feature = "platform-verifier")]
729    pub fn try_with_platform_verifier() -> Result<Self, rustls::Error> {
730        Ok(Self::new(Arc::new(
731            crypto::rustls::QuicClientConfig::with_platform_verifier()?,
732        )))
733    }
734
735    /// Create a client configuration that trusts specified trust anchors
736    pub fn with_root_certificates(
737        roots: Arc<rustls::RootCertStore>,
738    ) -> Result<Self, rustls::client::VerifierBuilderError> {
739        Ok(Self::new(Arc::new(crypto::rustls::QuicClientConfig::new(
740            WebPkiServerVerifier::builder_with_provider(roots, configured_provider()).build()?,
741        ))))
742    }
743}
744
745impl fmt::Debug for ClientConfig {
746    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
747        fmt.debug_struct("ClientConfig")
748            .field("transport", &self.transport)
749            // crypto not debug
750            // token_store not debug
751            .field("version", &self.version)
752            .finish_non_exhaustive()
753    }
754}
755
756/// Errors in the configuration of an endpoint
757#[derive(Debug, Error, Clone, PartialEq, Eq)]
758#[non_exhaustive]
759pub enum ConfigError {
760    /// Value exceeds supported bounds
761    #[error("value exceeds supported bounds")]
762    OutOfBounds,
763}
764
765impl From<TryFromIntError> for ConfigError {
766    fn from(_: TryFromIntError) -> Self {
767        Self::OutOfBounds
768    }
769}
770
771impl From<VarIntBoundsExceeded> for ConfigError {
772    fn from(_: VarIntBoundsExceeded) -> Self {
773        Self::OutOfBounds
774    }
775}
776
777/// Object to get current [`SystemTime`]
778///
779/// This exists to allow system time to be mocked in tests, or wherever else desired.
780pub trait TimeSource: Send + Sync {
781    /// Get [`SystemTime::now()`](SystemTime::now) or the mocked equivalent
782    fn now(&self) -> SystemTime;
783}
784
785/// Default implementation of [`TimeSource`]
786///
787/// Implements `now` by calling [`SystemTime::now()`](SystemTime::now).
788pub struct StdSystemTime;
789
790impl TimeSource for StdSystemTime {
791    fn now(&self) -> SystemTime {
792        SystemTime::now()
793    }
794}