Files
firezone/rust/connlib/shared/src/error.rs
Thomas Eizinger 407d20d817 refactor(connlib): use phoenix-channel crate for clients (#3682)
Depends-On: #4048.
Depends-On: #4015.

Resolves: #2158.

---------

Co-authored-by: conectado <gabrielalejandro7@gmail.com>
2024-03-12 08:10:56 +00:00

228 lines
7.9 KiB
Rust

//! Error module.
use base64::{DecodeError, DecodeSliceError};
use boringtun::noise::errors::WireGuardError;
use thiserror::Error;
use tokio::task::JoinError;
/// Unified Result type to use across connlib.
pub type Result<T> = std::result::Result<T, ConnlibError>;
/// 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),
/// 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),
#[error("`protect_file_descriptor` failed: {0}")]
ProtectFileDescriptorFailed(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(Option<String>),
/// 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("Windows error: {0}")]
WindowsError(#[from] windows::core::Error),
#[cfg(target_os = "windows")]
#[error(transparent)]
Wintun(#[from] wintun::Error),
#[cfg(target_os = "windows")]
#[error("Can't compute path for wintun.dll")]
WintunDllPath,
#[cfg(target_os = "windows")]
#[error("Can't find AppData/Local folder")]
CantFindLocalAppDataFolder,
#[error("Token has expired")]
TokenExpired,
#[error("Too many concurrent gateway connection requests")]
TooManyConnectionRequests,
#[error("Channel connection closed by portal")]
ClosedByPortal,
#[error(transparent)]
JoinError(#[from] JoinError),
#[cfg(target_os = "linux")]
#[error("Error while rewriting `/etc/resolv.conf`: {0}")]
ResolvConf(#[from] crate::linux::etc_resolv_conf::Error),
#[error(transparent)]
Snownet(#[from] snownet::Error),
#[error("Detected non-allowed packet in channel")]
UnallowedPacket,
#[error("No available ipv4 socket")]
NoIpv4,
#[error("No available ipv6 socket")]
NoIpv6,
// Error variants for `systemd-resolved` DNS control
#[error("Failed to control system DNS with `resolvectl`")]
ResolvectlFailed,
#[error("connection to the portal failed")]
PortalConnectionFailed,
}
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()
)
}
}
#[cfg(target_os = "linux")]
impl From<rtnetlink::Error> 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<WireGuardError> 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<T> From<tokio::sync::mpsc::error::SendError<T>> for ConnlibError {
fn from(_: tokio::sync::mpsc::error::SendError<T>) -> Self {
ConnlibError::SendChannelError
}
}
impl From<futures::channel::mpsc::SendError> for ConnlibError {
fn from(_: futures::channel::mpsc::SendError) -> Self {
ConnlibError::SendChannelError
}
}