mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-03-22 09:41:59 +00:00
Part of a small yak shave for #3817 The `atomicwrites` lib uses the atomic rename trick and does correct fsyncs for us, so if we lose power while rewriting or reverting `/etc/resolv.conf`, it should always be in a recoverable state. (Unless the hard drive lies about fsync, but then it's beyond our control.) --------- Signed-off-by: Reactor Scram <ReactorScram@users.noreply.github.com>
225 lines
7.8 KiB
Rust
225 lines
7.8 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,
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|