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 (always available)
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: Some(crate::crypto::pqc::PqcConfig::default()), // Enable PQC by default
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. PQC is enabled by default.
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 token log
605 ///
606 /// If the `bloom` feature is enabled (which it is by default), defaults to a bloom
607 /// token log, which is suitable for most internet applications.
608 ///
609 /// If the `bloom` feature is disabled, defaults to a none token log,
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 token store
709 ///
710 /// Defaults to a memory cache, 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}