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