//! HTTPS/H3 mimicry configuration (project §7, "outer = mimicry"). //! //! The outer QUIC/TLS layer is meant to look like ordinary browser HTTP/3 traffic so a passive //! observer sees what appears to be a connection to a CDN, not a VPN. That disguise is *not* the //! security boundary — see the crate docs and [`crate::quic::AcceptAnyServerCert`]; the real mutual //! authentication happens in the inner Aura proto handshake. This module just centralizes the //! browser-flavored knobs (ALPN, a default SNI, transport tuning) so they are set consistently. use std::time::Duration; /// ALPN protocol identifiers advertised on the outer TLS handshake. /// /// `h3` (RFC 9114) and `h3-29` (a still-seen draft) are exactly what Chrome offers for HTTP/3, so /// advertising them makes the ClientHello/ServerHello ALPN extension indistinguishable from a real /// browser's. Both client and server must agree, so they share this list. pub const ALPN_H3: &[&[u8]] = &[b"h3", b"h3-29"]; /// A plausible default SNI to present when the caller does not specify one. /// /// Picking a generic CDN-looking hostname keeps the Server Name Indication from screaming "VPN". /// Callers should normally pass their own camouflage hostname to [`crate::AuraClient::connect`]; /// this is only a fallback. pub const DEFAULT_SNI: &str = "cdn.example.com"; /// Return the ALPN list as owned `Vec>`, the shape rustls' `alpn_protocols` field wants. #[must_use] pub fn alpn_protocols() -> Vec> { ALPN_H3.iter().map(|p| p.to_vec()).collect() } /// Chrome-like QUIC transport timing/flow-control knobs (project §7.1). /// /// These values mirror what a Chromium HTTP/3 connection uses closely enough that the resulting /// idle-timeout / keep-alive / flow-control behavior is unremarkable on the wire: /// /// * `max_idle_timeout` ~ 30s — Chrome's default idle timeout. /// * `keep_alive_interval` ~ 15s — half the idle timeout, so an otherwise-quiet tunnel stays up. /// * `max_concurrent_bidi_streams` = 100 — a browser-ish concurrency ceiling. /// * receive windows ~ 10 MB — generous stream/connection flow-control windows so bulk transfer is /// not throttled (and matches a browser doing large downloads). /// /// Returned by value so callers wrap it in `Arc` and hand it to both the client and server /// `quinn::*Config` (keeping the two ends symmetric, which also aids the disguise). #[must_use] pub fn chrome_quic_transport_config() -> quinn::TransportConfig { /// ~10 MB flow-control window (stream and connection level). const RECV_WINDOW: u32 = 10 * 1024 * 1024; let mut tc = quinn::TransportConfig::default(); // 30s idle timeout. `IdleTimeout::try_from(Duration)` only fails for absurdly large durations; // 30s is always representable, so the expect is unreachable in practice. let idle = quinn::IdleTimeout::try_from(Duration::from_secs(30)) .expect("30s is a valid QUIC idle timeout"); tc.max_idle_timeout(Some(idle)); tc.keep_alive_interval(Some(Duration::from_secs(15))); tc.max_concurrent_bidi_streams(100u32.into()); // Keep uni-streams modest; the Aura tunnel only uses one bidi stream, but a browser-like profile // still permits a handful of unidirectional streams (e.g. H3 control/QPACK streams). tc.max_concurrent_uni_streams(100u32.into()); tc.stream_receive_window(RECV_WINDOW.into()); tc.receive_window((RECV_WINDOW * 2).into()); tc.send_window(u64::from(RECV_WINDOW) * 2); tc } #[cfg(test)] mod tests { use super::*; #[test] fn alpn_is_h3() { assert_eq!(ALPN_H3, &[b"h3".as_slice(), b"h3-29".as_slice()]); let owned = alpn_protocols(); assert_eq!(owned, vec![b"h3".to_vec(), b"h3-29".to_vec()]); } #[test] fn transport_config_builds() { // §7.1: must construct without panicking (the IdleTimeout conversion is the only fallible // step, and 30s is always valid). let _tc = chrome_quic_transport_config(); } }