From f1cf88fb9fd249e12cb3ca4aa5e7fd59952bb9fe Mon Sep 17 00:00:00 2001 From: conectado Date: Tue, 23 May 2023 21:20:48 -0300 Subject: [PATCH] add docs --- clients/apple/src/lib.rs | 1 + libs/client/src/control.rs | 1 + libs/client/src/lib.rs | 8 ++++-- libs/common/src/control.rs | 15 ++++++++++- libs/common/src/error.rs | 1 + libs/common/src/error_type.rs | 1 + libs/common/src/lib.rs | 2 -- libs/common/src/messages.rs | 35 ++++++++++++++++++++++-- libs/common/src/session.rs | 37 ++++++++++++++++++++++++++ libs/gateway/src/lib.rs | 8 ++++-- libs/tunnel/src/control_protocol.rs | 41 +++++++++++++++++++++++++++++ libs/tunnel/src/lib.rs | 25 +++++++++++++++++- 12 files changed, 165 insertions(+), 10 deletions(-) diff --git a/clients/apple/src/lib.rs b/clients/apple/src/lib.rs index 9404e1c..24580bd 100644 --- a/clients/apple/src/lib.rs +++ b/clients/apple/src/lib.rs @@ -72,6 +72,7 @@ impl From for ffi::TunnelAddresses { } } +/// This is used by the apple client to interact with our code. pub struct WrappedSession { session: Session, } diff --git a/libs/client/src/control.rs b/libs/client/src/control.rs index e2889be..62bb7a8 100644 --- a/libs/client/src/control.rs +++ b/libs/client/src/control.rs @@ -28,6 +28,7 @@ impl ControlSignal for ControlSignaler { } } +/// Implementation of [ControlSession] for clients. pub struct ControlPlane { tunnel: Arc>, control_signaler: ControlSignaler, diff --git a/libs/client/src/lib.rs b/libs/client/src/lib.rs index c75c655..4df8006 100644 --- a/libs/client/src/lib.rs +++ b/libs/client/src/lib.rs @@ -1,3 +1,4 @@ +//! Main connlib library for clients. use control::ControlPlane; use messages::EgressMessages; use messages::IngressMessages; @@ -5,10 +6,13 @@ use messages::IngressMessages; mod control; mod messages; -// IPv6 Min MTU = 1280 -const VIRTUAL_IFACE_MTU: u16 = 1280; +const VIRTUAL_IFACE_MTU: u16 = 1420; +/// Session type for clients. +/// +/// For more information see libs_common docs on [Session][libs_common::Session]. pub type Session = libs_common::Session, IngressMessages, EgressMessages>; + pub use libs_common::{ error::SwiftConnlibError, error_type::{ErrorType, SwiftErrorType}, diff --git a/libs/common/src/control.rs b/libs/common/src/control.rs index c5a33e8..8430230 100644 --- a/libs/common/src/control.rs +++ b/libs/common/src/control.rs @@ -1,4 +1,4 @@ -//! Control protocol related module +//! Control protocol related module. //! //! This modules contains the logic for handling in and out messages through the control plane. //! Handling of the message itself can be found in the other lib crates. @@ -186,11 +186,21 @@ impl PhoenixMessage { #[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone)] struct Empty {} +/// You can use this sender to send messages through a `PhoenixChannel`. +/// +/// Messages won't be sent unless [PhoenixChannel::start] is running, internally +/// this sends messages through a future channel that are forwrarded then in [PhoenixChannel] event loop pub struct PhoenixSender { sender: Sender, } impl PhoenixSender { + /// Sends a message upstream to a connected [PhoenixChannel]. + /// + /// # Parameters + /// - topic: Phoenix topic + /// - event: Phoenix event + /// - payload: Message's payload pub async fn send( &mut self, topic: impl Into, @@ -202,10 +212,13 @@ impl PhoenixSender { Ok(()) } + /// Join a phoenix topic, meaning that after this method is invoked [PhoenixChannel] will + /// recieve messages from that topic, given that upstream accepts you into the given topic. pub async fn join_topic(&mut self, topic: impl Into) -> Result<()> { self.send(topic, "phx_join", Empty {}).await } + /// Closes the [PhoenixChannel] pub async fn close(&mut self) -> Result<()> { self.sender.send(Message::Close(None)).await?; self.sender.close().await?; diff --git a/libs/common/src/error.rs b/libs/common/src/error.rs index a944265..3ff0b9c 100644 --- a/libs/common/src/error.rs +++ b/libs/common/src/error.rs @@ -1,3 +1,4 @@ +//! Error module. use base64::{DecodeError, DecodeSliceError}; use boringtun::noise::errors::WireGuardError; use macros::SwiftEnum; diff --git a/libs/common/src/error_type.rs b/libs/common/src/error_type.rs index 98555f4..7f411c8 100644 --- a/libs/common/src/error_type.rs +++ b/libs/common/src/error_type.rs @@ -1,3 +1,4 @@ +//! Module that contains the Error-Type that hints how to handle an error to upper layers. use macros::SwiftEnum; /// This indicates whether the produced error is something recoverable or fatal. /// Fata/Recoverable only indicates how to handle the error for the client. diff --git a/libs/common/src/lib.rs b/libs/common/src/lib.rs index cf31f7e..2d4c0fe 100644 --- a/libs/common/src/lib.rs +++ b/libs/common/src/lib.rs @@ -3,9 +3,7 @@ //! This includes types provided by external crates, i.e. [boringtun] to make sure that //! we are using the same version across our own crates. -/// Erorrs module. pub mod error; -/// Error types that hints how to handle an error for upper-layer libraries. pub mod error_type; mod session; diff --git a/libs/common/src/messages.rs b/libs/common/src/messages.rs index 8334d50..5e60c06 100644 --- a/libs/common/src/messages.rs +++ b/libs/common/src/messages.rs @@ -1,3 +1,4 @@ +//! Message types that are used by both the gateway and client. use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use serde::{Deserialize, Serialize}; @@ -8,37 +9,67 @@ mod key; pub use key::Key; -// Sending Public key + Token in the query parameters when opening websocket - +/// General type for handling portal's id (UUID v4) pub type Id = Uuid; +/// Represents a wireguard peer. #[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone)] pub struct Peer { + /// Keepalive: How often to send a keep alive message. pub persistent_keepalive: Option, + /// Peer's public key. pub public_key: Key, + /// Peer's Ipv4 (only 1 ipv4 per peer for now and mandatory). pub ipv4: Ipv4Addr, + /// Peer's Ipv6 (only 1 ipv6 per peer for now and mandatory). pub ipv6: Ipv6Addr, + /// Preshared key for the given peer. pub preshared_key: Key, } +/// Represent a connection request from a client to a given resource. +/// +/// While this is a client-only message it's hosted in common since the tunnel +/// make use of this message type. #[derive(Debug, Deserialize, Serialize, Clone)] pub struct RequestConnection { + /// Resource id the request is for. pub resource_id: Id, + /// The preshared key the client generated for the connection that it is trying to establish. pub client_preshared_key: Key, + /// Client's local RTC Session Description that the client will use for this connection. pub client_rtc_sdp: RTCSessionDescription, } +/// Description of a resource from a client's perspective. #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] pub struct ResourceDescription { + /// Resource's id. pub id: Id, + /// Internal resource's domain name if any. pub dns_name: Option, + /// Resource's ipv4 mapping. + /// + /// Note that this is not the actual ipv4 for the resource not even wireguard's ipv4 for the resource. + /// This is just the mapping we use internally between a resource and its ip for intercepting packets. pub ipv4: Ipv4Addr, + /// Resource's ipv6 mapping. + /// + /// Note that this is not the actual ipv6 for the resource not even wireguard's ipv6 for the resource. + /// This is just the mapping we use internally between a resource and its ip for intercepting packets. pub ipv6: Ipv6Addr, } +/// Represents a wireguard interface configuration. +/// +/// Note that the ips are /32 for ipv4 and /128 for ipv6. +/// This is done to minimize collisions and we update the routing table manually. #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] pub struct Interface { + /// Interface's Ipv4. pub ipv4: Ipv4Addr, + /// Interface's Ipv6. pub ipv6: Ipv6Addr, + /// DNS that will be used to query for DNS that aren't within our resource list. pub upstream_dns: Vec, } diff --git a/libs/common/src/session.rs b/libs/common/src/session.rs index ad6ebc8..a19a930 100644 --- a/libs/common/src/session.rs +++ b/libs/common/src/session.rs @@ -14,34 +14,53 @@ use url::Url; use crate::{control::PhoenixChannel, error_type::ErrorType, Error, Result}; +// TODO: Not the most tidy trait for a control-plane. +/// Trait that represents a control-plane. #[async_trait] pub trait ControlSession { + /// Start control-plane with the given private-key in the background. async fn start(private_key: StaticSecret) -> Result<(Sender, Receiver)>; + /// Either "gateway" or "client" used to ge the control-plane URL. fn mode() -> &'static str; } // TODO: Currently I'm using Session for both gateway and clients // however, gateway could use the runtime directly and could make things easier // so revisit this. +/// A session is the entry-point for connlib, mantains the runtime and the tunnel. +/// +/// A session is created using [Session::connect], then to stop a session we use [Session::disconnect]. pub struct Session { runtime: Option, _phantom: PhantomData<(T, U, V)>, } +/// Resource list that will be displayed to the users. pub struct ResourceList { pub resources: Vec, } +/// Tunnel addresses to be surfaced to the client apps. pub struct TunnelAddresses { + /// IPv4 Address. pub address4: Ipv4Addr, + /// IPv6 Address. pub address6: Ipv6Addr, } // Evaluate doing this not static +/// Traits that will be used by connlib to callback the client upper layers. pub trait Callbacks { + /// Called when there's a change in the resource list. fn on_update_resources(resource_list: ResourceList); + /// Called when the tunnel address is set. fn on_set_tunnel_adresses(tunnel_addresses: TunnelAddresses); + /// Called when there's an error. + /// + /// # Parameters + /// - `error`: The actual error that happened. + /// - `error_type`: Wether the error should terminate the session or not. fn on_error(error: &Error, error_type: ErrorType); } @@ -63,6 +82,8 @@ where U: for<'de> serde::Deserialize<'de> + std::fmt::Debug + Send + 'static, V: serde::Serialize + Send + 'static, { + /// Block on waiting for ctrl+c to terminate the runtime. + /// (Used for the gateways). pub fn wait_for_ctrl_c(&mut self) -> Result<()> { self.runtime .as_ref() @@ -73,6 +94,16 @@ where }) } + /// Starts a session in the background. + /// + /// This will: + /// 1. Create and start a tokio runtime + /// 2. Connect to the control plane to the portal + /// 3. Start the tunnel in the background and forward control plane messages to it. + /// + /// The generic parameter `C` should implement all the handlers and that's how errors will be surfaced. + /// + /// On a fatal error you should call `[Session::disconnect]` and start a new one. pub fn connect(portal_url: impl TryInto, token: String) -> Result { // TODO: We could use tokio::runtime::current() to get the current runtime // which could work with swif-rust that already runs a runtime. But IDK if that will work @@ -145,6 +176,10 @@ where }) } + /// Cleanup a [Session]. + /// + /// For now this just drops the runtime, which should drop all pending tasks. + /// Further cleanup should be done here. (Otherwise we can just drop [Session]). pub fn disconnect(&mut self) -> bool { // 1. Close the websocket connection // 2. Free the device handle (UNIX) @@ -161,10 +196,12 @@ where true } + /// TODO pub fn bump_sockets(&self) -> bool { true } + /// TODO pub fn disable_some_roaming_for_broken_mobile_semantics(&self) -> bool { true } diff --git a/libs/gateway/src/lib.rs b/libs/gateway/src/lib.rs index 3746f80..3ad7fb4 100644 --- a/libs/gateway/src/lib.rs +++ b/libs/gateway/src/lib.rs @@ -1,3 +1,4 @@ +//! Main connlib library for gateway. use control::ControlPlane; use messages::EgressMessages; use messages::IngressMessages; @@ -5,8 +6,11 @@ use messages::IngressMessages; mod control; mod messages; -// IPv6 Min MTU = 1280 -const VIRTUAL_IFACE_MTU: u16 = 1280; +const VIRTUAL_IFACE_MTU: u16 = 1420; +/// Session type for gateway. +/// +/// For more information see libs_common docs on [Session][libs_common::Session]. pub type Session = libs_common::Session, IngressMessages, EgressMessages>; + pub use libs_common::{error_type::ErrorType, Callbacks, Error, ResourceList, TunnelAddresses}; diff --git a/libs/tunnel/src/control_protocol.rs b/libs/tunnel/src/control_protocol.rs index e0473c2..53f7b3e 100644 --- a/libs/tunnel/src/control_protocol.rs +++ b/libs/tunnel/src/control_protocol.rs @@ -107,6 +107,20 @@ where )); } + /// Initiate an ice connection request. + /// + /// Given a resource id and a list of relay creates a [RequestConnection] + /// and prepares the tunnel to handle the connection once initiated. + /// + /// # Note + /// This function blocks until all ICE candidates are gathered so it might block for a long time. + /// + /// # Parameters + /// - `resource_id`: Id of the resource we are going to request the connection to. + /// - `relays`: The list of relays used for that connection. + /// + /// # Returns + /// A [RequestConnection] that should be sent to the gateway through the control-plane. #[tracing::instrument(level = "trace", skip(self))] pub async fn request_connection( self: &Arc, @@ -180,6 +194,14 @@ where }) } + /// Called when a response to [Tunnel::request_connection] is ready. + /// + /// Once this is called if everything goes fine a new tunnel should be started between the 2 peers. + /// + /// # Parameters + /// - `resource_id`: Id of the resource that responded. + /// - `rtc_sdp`: Remote SDP. + /// - `gateway_public_key`: Public key of the gateway that is handling that resource for this connection. #[tracing::instrument(level = "trace", skip(self))] pub async fn recieved_offer_response( self: &Arc, @@ -200,6 +222,24 @@ where Ok(()) } + /// Accept a connection request from a client. + /// + /// Sets a connection to a remote SDP, creates the local SDP + /// and returns it. + /// + /// # Note + /// + /// This function blocks until it gathers all the ICE candidates + /// so it might block for a long time. + /// + /// # Parameters + /// - `sdp_session`: Remote session description. + /// - `peer`: Configuration for the remote peer. + /// - `relays`: List of relays to use with this connection. + /// - `client_id`: UUID of the remote client. + /// + /// # Returns + /// An [RTCSessionDescription] of the local sdp, with candidates gathered. pub async fn set_peer_connection_request( self: &Arc, sdp_session: RTCSessionDescription, @@ -254,6 +294,7 @@ where Ok(local_desc) } + /// Clean up a connection to a resource. pub fn cleanup_connection(&self, resource_id: Id) { self.awaiting_connection.lock().remove(&resource_id); self.peer_connections.lock().remove(&resource_id); diff --git a/libs/tunnel/src/lib.rs b/libs/tunnel/src/lib.rs index af92aed..41e7deb 100644 --- a/libs/tunnel/src/lib.rs +++ b/libs/tunnel/src/lib.rs @@ -1,3 +1,7 @@ +//! Connlib tunnel implementation. +//! +//! This is both the wireguard and ICE implementation that should work in tandem. +//! [Tunnel] is the main entry-point for this crate. use libs_common::{ boringtun::{ noise::{ @@ -73,6 +77,8 @@ enum ResourceKind { Addr(T), } +/// Represent's the tunnel actual peer's config +/// Obtained from libs_common's Peer #[derive(Clone)] pub struct PeerConfig { pub(crate) persistent_keepalive: Option, @@ -94,12 +100,19 @@ impl From for PeerConfig { } } +/// Trait used for out-going signals to control plane that are **required** to be made from inside the tunnel. +/// +/// Generally, we try to return from the functions here rather than using this callback. #[async_trait] pub trait ControlSignal { + /// Signals to the control plane an intent to initiate a connecti to the given resource. + /// + /// Used when a packet is found to a resource we have no connection stablished but is within the list of resources available for the client. async fn signal_connection_to(&self, resource: &ResourceDescription) -> Result<()>; } -// why even have the mut keyword? +/// Tunnel is a wireguard state machine that uses webrtc's ICE channels instead of UDP sockets +/// to communicate between peers. pub struct Tunnel { next_index: Mutex, iface_device: Mutex, @@ -123,6 +136,11 @@ where C: Send + Sync + 'static, CB: Send + Sync + 'static, { + /// Creates a new tunnel. + /// + /// # Parameters + /// - `private_key`: wireguard's private key. + /// - `control_signaler`: this is used to send SDP from the tunnel to the control plane. #[tracing::instrument(level = "trace", skip(private_key, control_signaler))] pub async fn new(private_key: StaticSecret, control_signaler: C) -> Result { let public_key = (&private_key).into(); @@ -172,6 +190,10 @@ where }) } + /// Adds a the given resource to the tunnel. + /// + /// Once added, when a packet for the resource is intercepted a new data channel will be created + /// and packets will be wrapped with wireguard and sent through it. #[tracing::instrument(level = "trace", skip(self))] pub fn add_resource(&self, resource_description: ResourceDescription) { let mut resources = self.resources.write(); @@ -183,6 +205,7 @@ where ); } + /// Sets the interface configuration and starts background tasks. #[tracing::instrument(level = "trace", skip(self))] pub async fn set_interface(self: &Arc, config: &InterfaceConfig) -> Result<()> { {