ant_quic/
lib.rs

1// Copyright 2024 Saorsa Labs Ltd.
2//
3// This Saorsa Network Software is licensed under the General Public License (GPL), version 3.
4// Please see the file LICENSE-GPL, or visit <http://www.gnu.org/licenses/> for the full text.
5//
6// Full details available at https://saorsalabs.com/licenses
7
8//! ant-quic: QUIC transport protocol with advanced NAT traversal for P2P networks
9#![allow(elided_lifetimes_in_paths)]
10#![allow(missing_debug_implementations)]
11//!
12//! This library provides a clean, modular implementation of QUIC-native NAT traversal
13//! using raw public keys for authentication. It is designed to be minimal, focused,
14//! and highly testable, with exceptional cross-platform support.
15//!
16//! The library is organized into the following main modules:
17//! - `transport`: Core QUIC transport functionality
18//! - `nat_traversal`: QUIC-native NAT traversal protocol
19//! - `discovery`: Platform-specific network interface discovery
20//! - `crypto`: Raw public key authentication
21//! - `trust`: Trust management with TOFU pinning and channel binding
22
23// Documentation warnings enabled - all public APIs must be documented
24#![cfg_attr(not(fuzzing), warn(missing_docs))]
25#![allow(unreachable_pub)]
26#![allow(clippy::cognitive_complexity)]
27#![allow(clippy::too_many_arguments)]
28#![allow(clippy::use_self)]
29// Dead code warnings enabled - remove unused code
30#![warn(dead_code)]
31#![allow(clippy::field_reassign_with_default)]
32#![allow(clippy::module_inception)]
33#![allow(clippy::useless_vec)]
34#![allow(private_interfaces)]
35#![allow(clippy::upper_case_acronyms)]
36#![allow(clippy::type_complexity)]
37#![allow(clippy::manual_clamp)]
38#![allow(clippy::needless_range_loop)]
39#![allow(clippy::borrowed_box)]
40#![allow(clippy::manual_strip)]
41#![allow(clippy::if_same_then_else)]
42#![allow(clippy::ptr_arg)]
43#![allow(clippy::incompatible_msrv)]
44#![allow(clippy::await_holding_lock)]
45#![allow(clippy::single_match)]
46#![allow(clippy::must_use_candidate)]
47#![allow(clippy::let_underscore_must_use)]
48#![allow(clippy::let_underscore_untyped)]
49#![allow(clippy::large_enum_variant)]
50#![allow(clippy::too_many_lines)]
51#![allow(clippy::result_large_err)]
52#![allow(clippy::enum_glob_use)]
53#![allow(clippy::match_like_matches_macro)]
54#![allow(clippy::struct_field_names)]
55#![allow(clippy::cast_precision_loss)]
56#![allow(clippy::cast_sign_loss)]
57#![allow(clippy::cast_possible_wrap)]
58#![allow(clippy::cast_possible_truncation)]
59#![allow(clippy::unnecessary_wraps)]
60#![allow(clippy::doc_markdown)]
61#![allow(clippy::module_name_repetitions)]
62#![allow(clippy::items_after_statements)]
63#![allow(clippy::missing_panics_doc)]
64#![allow(clippy::missing_errors_doc)]
65#![allow(clippy::similar_names)]
66#![allow(clippy::new_without_default)]
67#![allow(clippy::unwrap_or_default)]
68#![allow(clippy::uninlined_format_args)]
69#![allow(clippy::redundant_field_names)]
70#![allow(clippy::redundant_closure_for_method_calls)]
71#![allow(clippy::redundant_pattern_matching)]
72#![allow(clippy::option_if_let_else)]
73#![allow(clippy::trivially_copy_pass_by_ref)]
74#![allow(clippy::len_without_is_empty)]
75#![allow(clippy::explicit_auto_deref)]
76#![allow(clippy::blocks_in_conditions)]
77#![allow(clippy::collapsible_else_if)]
78#![allow(clippy::collapsible_if)]
79#![allow(clippy::unnecessary_cast)]
80#![allow(clippy::needless_bool)]
81#![allow(clippy::needless_borrow)]
82#![allow(clippy::redundant_static_lifetimes)]
83#![allow(clippy::match_ref_pats)]
84#![allow(clippy::should_implement_trait)]
85#![allow(clippy::wildcard_imports)]
86#![warn(unused_must_use)]
87#![allow(improper_ctypes)]
88#![allow(improper_ctypes_definitions)]
89#![allow(non_upper_case_globals)]
90#![allow(clippy::wrong_self_convention)]
91#![allow(clippy::vec_init_then_push)]
92#![allow(clippy::format_in_format_args)]
93#![allow(clippy::from_over_into)]
94#![allow(clippy::useless_conversion)]
95#![allow(clippy::never_loop)]
96#![allow(dropping_references)]
97#![allow(non_snake_case)]
98#![allow(clippy::unnecessary_literal_unwrap)]
99#![allow(clippy::assertions_on_constants)]
100#![allow(unused_imports)]
101
102use std::{
103    fmt,
104    net::{IpAddr, SocketAddr},
105    ops,
106};
107
108// Core modules
109mod cid_queue;
110pub mod coding;
111mod constant_time;
112mod range_set;
113pub mod transport_parameters;
114mod varint;
115
116pub use varint::{VarInt, VarIntBoundsExceeded};
117
118// Removed optional bloom module
119
120/// Bounded pending data buffer with TTL expiration
121pub mod bounded_pending_buffer;
122
123/// RTT-based path selection with hysteresis
124pub mod path_selection;
125
126/// Coordinated shutdown for endpoints
127pub mod shutdown;
128
129/// Watchable state pattern for reactive observation
130pub mod watchable;
131
132/// Fair polling for multiple transports
133pub mod fair_polling;
134
135/// Graceful transport degradation
136pub mod transport_resilience;
137
138/// Discovery trait for stream composition
139pub mod discovery_trait;
140
141/// Structured event logging for observability
142pub mod structured_events;
143
144// ============================================================================
145// SIMPLE API - Zero Configuration P2P
146// ============================================================================
147
148/// Zero-configuration P2P node - THE PRIMARY API
149///
150/// Use [`Node`] for the simplest possible P2P experience:
151/// ```rust,ignore
152/// let node = Node::new().await?;
153/// ```
154pub mod node;
155
156/// Minimal configuration for zero-config P2P nodes
157pub mod node_config;
158
159/// Consolidated node status for observability
160pub mod node_status;
161
162/// Unified events for P2P nodes
163pub mod node_event;
164
165// Core implementation modules
166/// Configuration structures and validation
167pub mod config;
168/// QUIC connection state machine and management
169pub mod connection;
170/// QUIC endpoint for accepting and initiating connections
171pub mod endpoint;
172/// QUIC frame types and encoding/decoding
173pub mod frame;
174/// QUIC packet structures and processing
175pub mod packet;
176/// Shared types and utilities
177pub mod shared;
178/// Transport error types and codes
179pub mod transport_error;
180// Simplified congestion control
181/// Network candidate discovery and management
182pub mod candidate_discovery;
183/// Connection ID generation strategies
184pub mod cid_generator;
185mod congestion;
186mod protocol_violations;
187#[cfg(test)]
188mod protocol_violations_tests;
189
190// Zero-cost tracing system
191/// High-level NAT traversal API
192pub mod nat_traversal_api;
193mod token;
194mod token_memory_cache;
195/// Zero-cost tracing and event logging system
196pub mod tracing;
197
198// Public modules with new structure
199/// Cryptographic operations and raw public key support
200pub mod crypto;
201/// Platform-specific network interface discovery
202pub mod discovery;
203/// NAT traversal protocol implementation
204pub mod nat_traversal;
205/// Transport-level protocol implementation
206pub mod transport;
207
208// Additional modules
209// v0.2: auth module removed - TLS handles peer authentication via ML-DSA-65
210/// Secure chat protocol implementation
211pub mod chat;
212// Performance optimization utilities are deprecated; remove module to eliminate dead code
213// pub mod optimization;
214
215// ============================================================================
216// P2P API
217// ============================================================================
218
219/// P2P endpoint - the primary API for ant-quic
220///
221/// This module provides the main API for P2P networking with NAT traversal,
222/// connection management, and secure communication.
223pub mod p2p_endpoint;
224
225/// P2P configuration system
226///
227/// This module provides `P2pConfig` with builder pattern support for
228/// configuring endpoints, NAT traversal, MTU, PQC, and other settings.
229pub mod unified_config;
230
231/// Real-time statistics dashboard
232pub mod stats_dashboard;
233/// Terminal user interface components
234pub mod terminal_ui;
235
236// Compliance validation framework
237/// IETF compliance validation tools
238pub mod compliance_validator;
239
240// Comprehensive logging system
241/// Structured logging and diagnostics
242pub mod logging;
243
244/// Metrics collection and export system (basic metrics always available)
245pub mod metrics;
246
247/// TURN-style relay protocol for NAT traversal fallback
248pub mod relay;
249
250/// MASQUE CONNECT-UDP Bind protocol for fully connectable P2P nodes
251pub mod masque;
252
253/// Transport trust module (TOFU, rotations, channel binding surfaces)
254pub mod trust;
255
256/// Address-validation tokens bound to (PeerId||CID||nonce)
257#[cfg(feature = "aws-lc-rs")]
258pub mod token_v2;
259
260// High-level async API modules (ported from quinn crate)
261pub mod high_level;
262
263// Re-export high-level API types for easier usage
264pub use high_level::{
265    Accept, Connecting, Connection as HighLevelConnection, Endpoint,
266    RecvStream as HighLevelRecvStream, SendStream as HighLevelSendStream,
267};
268
269// Link transport abstraction layer for overlay networks
270pub mod link_transport;
271mod link_transport_impl;
272
273// Re-export link transport types
274pub use link_transport::{
275    BoxFuture, BoxStream, Capabilities, ConnectionStats as LinkConnectionStats,
276    DisconnectReason as LinkDisconnectReason, Incoming as LinkIncoming, LinkConn, LinkError,
277    LinkEvent, LinkRecvStream, LinkResult, LinkSendStream, LinkTransport, NatHint, ProtocolId,
278};
279pub use link_transport_impl::{P2pLinkConn, P2pLinkTransport, P2pRecvStream, P2pSendStream};
280
281// Bootstrap cache for peer persistence and quality-based selection
282pub mod bootstrap_cache;
283pub use bootstrap_cache::{
284    BootstrapCache, BootstrapCacheConfig, BootstrapCacheConfigBuilder, CacheEvent, CacheStats,
285    CachedPeer, ConnectionOutcome, ConnectionStats as CacheConnectionStats,
286    NatType as CacheNatType, PeerCapabilities, PeerSource, QualityWeights, SelectionStrategy,
287};
288
289// Re-export crypto utilities for peer ID management (v0.2: Pure PQC with ML-DSA-65)
290pub use crypto::raw_public_keys::key_utils::{
291    ML_DSA_65_PUBLIC_KEY_SIZE, ML_DSA_65_SECRET_KEY_SIZE, MlDsaPublicKey, MlDsaSecretKey,
292    derive_peer_id_from_key_bytes, derive_peer_id_from_public_key, generate_ml_dsa_keypair,
293    verify_peer_id,
294};
295
296// Re-export key types for backward compatibility
297pub use candidate_discovery::{
298    CandidateDiscoveryManager, DiscoveryConfig, DiscoveryError, DiscoveryEvent, NetworkInterface,
299    ValidatedCandidate,
300};
301// v0.13.0: NatTraversalRole removed - all nodes are symmetric P2P nodes
302pub use connection::nat_traversal::{CandidateSource, CandidateState};
303pub use connection::{
304    Chunk, Chunks, ClosedStream, Connection, ConnectionError, ConnectionStats, Datagrams, Event,
305    FinishError, ReadError, ReadableError, RecvStream, SendDatagramError, SendStream, StreamEvent,
306    Streams, WriteError, Written,
307};
308pub use endpoint::{
309    AcceptError, ConnectError, ConnectionHandle, DatagramEvent, Endpoint as LowLevelEndpoint,
310    Incoming,
311};
312pub use nat_traversal_api::{
313    BootstrapNode, CandidateAddress, NatTraversalConfig, NatTraversalEndpoint, NatTraversalError,
314    NatTraversalEvent, NatTraversalStatistics, PeerId,
315};
316
317// ============================================================================
318// SIMPLE API EXPORTS - Zero Configuration P2P (RECOMMENDED)
319// ============================================================================
320
321/// Zero-configuration P2P node - THE PRIMARY API
322pub use node::{Node, NodeError};
323
324/// Minimal configuration for zero-config P2P nodes
325pub use node_config::{NodeConfig, NodeConfigBuilder};
326
327/// Consolidated node status for observability
328pub use node_status::{NatType, NodeStatus};
329
330/// Unified events for P2P nodes
331pub use node_event::{DisconnectReason as NodeDisconnectReason, NodeEvent, TraversalMethod};
332
333// ============================================================================
334// P2P API EXPORTS (for advanced use)
335// ============================================================================
336
337/// P2P endpoint - for advanced use, prefer Node for most applications
338pub use p2p_endpoint::{
339    ConnectionMetrics, DisconnectReason, EndpointError, EndpointStats, P2pEndpoint, P2pEvent,
340    PeerConnection, TraversalPhase,
341};
342
343/// P2P configuration with builder pattern
344pub use unified_config::{ConfigError, MtuConfig, NatConfig, P2pConfig, P2pConfigBuilder};
345
346pub use relay::{
347    AuthToken,
348    // MASQUE types re-exported from relay module
349    MasqueRelayClient,
350    MasqueRelayConfig,
351    MasqueRelayServer,
352    MasqueRelayStats,
353    MigrationConfig,
354    MigrationCoordinator,
355    MigrationState,
356    RelayAuthenticator,
357    RelayError,
358    RelayManager,
359    RelayManagerConfig,
360    RelayResult,
361    RelaySession,
362    RelaySessionConfig,
363    RelaySessionState,
364    RelayStatisticsCollector,
365};
366pub use shared::{ConnectionId, EcnCodepoint, EndpointEvent};
367pub use transport_error::{Code as TransportErrorCode, Error as TransportError};
368
369// #[cfg(fuzzing)]
370// pub mod fuzzing; // Module not implemented yet
371
372/// The QUIC protocol version implemented.
373///
374/// Simplified to include only the essential versions:
375/// - 0x00000001: QUIC v1 (RFC 9000)
376/// - 0xff00_001d: Draft 29
377pub const DEFAULT_SUPPORTED_VERSIONS: &[u32] = &[
378    0x00000001,  // QUIC v1 (RFC 9000)
379    0xff00_001d, // Draft 29
380];
381
382/// Whether an endpoint was the initiator of a connection
383#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
384#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
385pub enum Side {
386    /// The initiator of a connection
387    Client = 0,
388    /// The acceptor of a connection
389    Server = 1,
390}
391
392impl Side {
393    #[inline]
394    /// Shorthand for `self == Side::Client`
395    pub fn is_client(self) -> bool {
396        self == Self::Client
397    }
398
399    #[inline]
400    /// Shorthand for `self == Side::Server`
401    pub fn is_server(self) -> bool {
402        self == Self::Server
403    }
404}
405
406impl ops::Not for Side {
407    type Output = Self;
408    fn not(self) -> Self {
409        match self {
410            Self::Client => Self::Server,
411            Self::Server => Self::Client,
412        }
413    }
414}
415
416/// Whether a stream communicates data in both directions or only from the initiator
417#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
418#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
419pub enum Dir {
420    /// Data flows in both directions
421    Bi = 0,
422    /// Data flows only from the stream's initiator
423    Uni = 1,
424}
425
426impl Dir {
427    fn iter() -> impl Iterator<Item = Self> {
428        [Self::Bi, Self::Uni].iter().cloned()
429    }
430}
431
432impl fmt::Display for Dir {
433    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
434        use Dir::*;
435        f.pad(match *self {
436            Bi => "bidirectional",
437            Uni => "unidirectional",
438        })
439    }
440}
441
442/// Identifier for a stream within a particular connection
443#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
444#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
445pub struct StreamId(u64);
446
447impl fmt::Display for StreamId {
448    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
449        let initiator = match self.initiator() {
450            Side::Client => "client",
451            Side::Server => "server",
452        };
453        let dir = match self.dir() {
454            Dir::Uni => "uni",
455            Dir::Bi => "bi",
456        };
457        write!(
458            f,
459            "{} {}directional stream {}",
460            initiator,
461            dir,
462            self.index()
463        )
464    }
465}
466
467impl StreamId {
468    /// Create a new StreamId
469    pub fn new(initiator: Side, dir: Dir, index: u64) -> Self {
470        Self((index << 2) | ((dir as u64) << 1) | initiator as u64)
471    }
472    /// Which side of a connection initiated the stream
473    pub fn initiator(self) -> Side {
474        if self.0 & 0x1 == 0 {
475            Side::Client
476        } else {
477            Side::Server
478        }
479    }
480    /// Which directions data flows in
481    pub fn dir(self) -> Dir {
482        if self.0 & 0x2 == 0 { Dir::Bi } else { Dir::Uni }
483    }
484    /// Distinguishes streams of the same initiator and directionality
485    pub fn index(self) -> u64 {
486        self.0 >> 2
487    }
488}
489
490impl From<StreamId> for VarInt {
491    fn from(x: StreamId) -> Self {
492        unsafe { Self::from_u64_unchecked(x.0) }
493    }
494}
495
496impl From<VarInt> for StreamId {
497    fn from(v: VarInt) -> Self {
498        Self(v.0)
499    }
500}
501
502impl From<StreamId> for u64 {
503    fn from(x: StreamId) -> Self {
504        x.0
505    }
506}
507
508impl coding::Codec for StreamId {
509    fn decode<B: bytes::Buf>(buf: &mut B) -> coding::Result<Self> {
510        VarInt::decode(buf).map(|x| Self(x.into_inner()))
511    }
512    fn encode<B: bytes::BufMut>(&self, buf: &mut B) {
513        // StreamId values should always be valid VarInt values, but handle the error case
514        match VarInt::from_u64(self.0) {
515            Ok(varint) => varint.encode(buf),
516            Err(_) => {
517                // This should never happen for valid StreamIds, but use a safe fallback
518                VarInt::MAX.encode(buf);
519            }
520        }
521    }
522}
523
524/// An outgoing packet
525#[derive(Debug)]
526#[must_use]
527pub struct Transmit {
528    /// The socket this datagram should be sent to
529    pub destination: SocketAddr,
530    /// Explicit congestion notification bits to set on the packet
531    pub ecn: Option<EcnCodepoint>,
532    /// Amount of data written to the caller-supplied buffer
533    pub size: usize,
534    /// The segment size if this transmission contains multiple datagrams.
535    /// This is `None` if the transmit only contains a single datagram
536    pub segment_size: Option<usize>,
537    /// Optional source IP address for the datagram
538    pub src_ip: Option<IpAddr>,
539}
540
541// Deal with time
542#[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
543pub(crate) use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
544#[cfg(all(target_family = "wasm", target_os = "unknown"))]
545pub(crate) use web_time::{Duration, Instant, SystemTime, UNIX_EPOCH};
546
547//
548// Useful internal constants
549//
550
551/// The maximum number of CIDs we bother to issue per connection
552pub(crate) const LOC_CID_COUNT: u64 = 8;
553pub(crate) const RESET_TOKEN_SIZE: usize = 16;
554pub(crate) const MAX_CID_SIZE: usize = 20;
555pub(crate) const MIN_INITIAL_SIZE: u16 = 1200;
556/// <https://www.rfc-editor.org/rfc/rfc9000.html#name-datagram-size>
557pub(crate) const INITIAL_MTU: u16 = 1200;
558pub(crate) const MAX_UDP_PAYLOAD: u16 = 65527;
559pub(crate) const TIMER_GRANULARITY: Duration = Duration::from_millis(1);
560/// Maximum number of streams that can be tracked per connection
561pub(crate) const MAX_STREAM_COUNT: u64 = 1 << 60;
562
563// Internal type re-exports for crate modules
564pub use cid_generator::RandomConnectionIdGenerator;
565pub use config::{
566    AckFrequencyConfig, ClientConfig, EndpointConfig, MtuDiscoveryConfig, ServerConfig,
567    TransportConfig,
568};
569
570// Post-Quantum Cryptography (PQC) re-exports - always available
571// v0.2: Pure PQC only - HybridKem and HybridSignature removed
572pub use crypto::pqc::{MlDsa65, MlKem768, PqcConfig, PqcConfigBuilder, PqcError, PqcResult};
573pub(crate) use frame::Frame;
574pub use token::TokenStore;
575pub(crate) use token::{NoneTokenLog, ResetToken, TokenLog};
576pub(crate) use token_memory_cache::TokenMemoryCache;