//! Error module. use base64::{DecodeError, DecodeSliceError}; use boringtun::noise::errors::WireGuardError; use thiserror::Error; /// Unified Result type to use across connlib. pub type Result = std::result::Result; /// Unified error type to use across connlib. #[derive(Error, Debug)] pub enum ConnlibError { /// Standard IO error. #[error(transparent)] Io(#[from] std::io::Error), /// Standard IO error. #[error("Failed to roll over log file: {0}")] LogFileRollError(std::io::Error), /// Error while decoding a base64 value. #[error("There was an error while decoding a base64 value: {0}")] Base64DecodeError(#[from] DecodeError), /// Error while decoding a base64 value from a slice. #[error("There was an error while decoding a base64 value: {0}")] Base64DecodeSliceError(#[from] DecodeSliceError), /// Request error for websocket connection. #[error("Error forming request: {0}")] RequestError(#[from] tokio_tungstenite::tungstenite::http::Error), /// Websocket heartbeat timedout #[error("Websocket heartbeat timedout")] WebsocketTimeout(#[from] tokio_stream::Elapsed), /// Error during websocket connection. #[error("Portal connection error: {0}")] PortalConnectionError(#[from] tokio_tungstenite::tungstenite::error::Error), /// Provided string was not formatted as a URL. #[error("Badly formatted URI")] UriError, /// Provided an unsupported uri string. #[error("Unsupported URI scheme: Must be http://, https://, ws:// or wss://")] UriScheme, /// Serde's serialize error. #[error(transparent)] SerializeError(#[from] serde_json::Error), /// Webrtc error #[error("ICE-related error: {0}")] IceError(#[from] webrtc::Error), /// Webrtc error regarding data channel. #[error("ICE-data error: {0}")] IceDataError(#[from] webrtc::data::Error), /// Error while sending through an async channelchannel. #[error("Error sending message through an async channel")] SendChannelError, /// Error when trying to establish connection between peers. #[error("Error while establishing connection between peers")] ConnectionEstablishError, /// Error related to wireguard protocol. #[error("Wireguard error")] WireguardError(WireGuardError), /// Expected an initialized runtime but there was none. #[error("Expected runtime to be initialized")] NoRuntime, /// Tried to access a resource which didn't exists. #[error("Tried to access an undefined resource")] UnknownResource, /// One of the stored resources isn't a valid CIDR/DNS. #[error("Invalid resource")] InvalidResource, /// Error regarding our own control protocol. #[error("Control plane protocol error. Unexpected messages or message order.")] ControlProtocolError, /// Error when reading system's interface #[error("Error while reading system's interface")] IfaceRead(std::io::Error), #[error("`on_set_interface_config` failed: {0}")] OnSetInterfaceConfigFailed(String), #[error("`on_tunnel_ready` failed: {0}")] OnTunnelReadyFailed(String), #[error("`on_add_route` failed: {0}")] OnAddRouteFailed(String), #[error("`on_remove_route` failed: {0}")] OnRemoveRouteFailed(String), #[error("`on_update_resources` failed: {0}")] OnUpdateResourcesFailed(String), #[error("`get_system_default_resolvers` failed: {0}")] GetSystemDefaultResolverFailed(String), /// Glob for errors without a type. #[error("Other error: {0}")] Other(&'static str), /// Invalid tunnel name #[error("Invalid tunnel name")] InvalidTunnelName, #[cfg(target_os = "linux")] #[error(transparent)] NetlinkError(rtnetlink::Error), /// Io translation of netlink error /// The IO version is easier to interpret /// We maintain a different variant from the standard IO for this to keep more context #[error("IO netlink error: {0}")] NetlinkErrorIo(std::io::Error), /// No iface found #[error("No iface found")] NoIface, /// Expected file descriptor and none was found #[error("No filedescriptor")] NoFd, /// No MTU found #[error("No MTU found")] NoMtu, /// A panic occurred. #[error("Panicked: {0}")] Panic(String), /// A panic occurred with a non-string payload. #[error("Panicked with a non-string payload")] PanicNonStringPayload, /// Received connection details that might be stale #[error("Unexpected connection details")] UnexpectedConnectionDetails, /// Invalid phoenix channel reference #[error("Invalid phoenix channel reply reference")] InvalidReference, /// Invalid packet format #[error("Received badly formatted packet")] BadPacket, /// Tunnel is under load #[error("Under load")] UnderLoad, /// Invalid source address for peer #[error("Invalid source address")] InvalidSource, /// Invalid destination for packet #[error("Invalid dest address")] InvalidDst, /// Any parse error #[error("parse error")] ParseError, /// DNS lookup error #[error("Error with the DNS fallback lookup")] DNSFallback(#[from] hickory_resolver::error::ResolveError), #[error("Error with the DNS fallback lookup")] DNSFallbackKind(#[from] hickory_resolver::error::ResolveErrorKind), #[error("DNS proto error")] DnsProtoError(#[from] hickory_resolver::proto::error::ProtoError), /// Connection is still being stablished, retry later #[error("Pending connection")] PendingConnection, #[error(transparent)] Uuid(#[from] uuid::Error), #[cfg(target_os = "windows")] #[error(transparent)] Wintun(#[from] wintun::Error), #[error("Token has expired")] TokenExpired, #[error("Too many concurrent gateway connection requests")] TooManyConnectionRequests, } impl ConnlibError { pub fn is_http_client_error(&self) -> bool { matches!( self, Self::PortalConnectionError(tokio_tungstenite::tungstenite::error::Error::Http(e)) if e.status().is_client_error() ) } /// Whether this error is fatal to the underlying connection. pub fn is_fatal_connection_error(&self) -> bool { if let Self::WireguardError(e) = self { return matches!( e, WireGuardError::ConnectionExpired | WireGuardError::NoCurrentSession ); } if let Self::IceDataError(e) = self { return matches!( e, webrtc::data::Error::ErrStreamClosed | webrtc::data::Error::Sctp(webrtc::sctp::Error::ErrStreamClosed) ); } false } } #[cfg(target_os = "linux")] impl From for ConnlibError { fn from(err: rtnetlink::Error) -> Self { match err { rtnetlink::Error::NetlinkError(err) => Self::NetlinkErrorIo(err.to_io()), err => Self::NetlinkError(err), } } } impl From for ConnlibError { fn from(e: WireGuardError) -> Self { ConnlibError::WireguardError(e) } } impl From<&'static str> for ConnlibError { fn from(e: &'static str) -> Self { ConnlibError::Other(e) } } impl From> for ConnlibError { fn from(_: tokio::sync::mpsc::error::SendError) -> Self { ConnlibError::SendChannelError } } impl From for ConnlibError { fn from(_: futures::channel::mpsc::SendError) -> Self { ConnlibError::SendChannelError } }