Skip to main content

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