Skip to main content

tailscale/
error.rs

1use std::fmt;
2
3use crate::netstack::Error as NetstackError;
4
5/// Errors that may occur while interacting with a device.
6#[derive(Debug, thiserror::Error, Clone, Copy, Eq, PartialEq)]
7pub enum Error {
8    /// An operation timed-out.
9    ///
10    /// This error can often be handled by retrying.
11    #[error("operation timed-out")]
12    Timeout,
13
14    /// A connection was reset.
15    ///
16    /// This error can often be handled by retrying.
17    #[error("connection reset")]
18    ConnectionReset,
19
20    /// An error reading or parsing the key file.
21    #[error("an error reading or parsing the key file")]
22    KeyFileRead,
23
24    /// An error writing out the key file.
25    #[error("an error writing out the key file")]
26    KeyFileWrite,
27
28    /// The environment variable `TS_RS_EXPERIMENT` was not set.
29    ///
30    /// The end-user must set `TS_RS_EXPERIMENT=this_is_unstable_software` to acknowledge that tailscale-rs
31    /// is early-days experimental software containing bugs, unvalidated cryptography, and no stability
32    /// or compatibility guarantees.
33    #[error("the environment variable `{}` was not set", crate::ENV_MAGIC_VAR)]
34    UnstableEnvVar,
35
36    /// An error occurred which can not be anticipated or handled by a library user.
37    ///
38    /// This is likely due to a bug in our code or a rare and unexpected error.
39    ///
40    /// [`InternalErrorKind`] is intended to be informational (might be used to improve error reporting
41    /// in logs or to the end-user), rather then inspected during handling.
42    #[error("internal error ({0})")]
43    Internal(InternalErrorKind),
44}
45
46/// Informational detail on the kind of internal error.
47#[non_exhaustive]
48#[derive(Debug, Clone, Copy, Eq, PartialEq)]
49pub enum InternalErrorKind {
50    /// Invalid socket state.
51    InvalidSocketState,
52    /// Response type mismatched to request type.
53    InternalResponseMismatch,
54    /// Channel closed.
55    InternalChannelClosed,
56    /// Handle to invalid TCP listener.
57    BadListenerHandle,
58    /// Handle to invalid socket.
59    BadSocketHandle,
60    /// Bad request.
61    BadRequest,
62    /// Buffer is full, cannot read in packet.
63    BufferFull,
64    /// Actor missing or shutdown.
65    Actor,
66    /// The operation is not supported while running in TUN transport mode, or
67    /// TUN mode was requested but is unavailable (no device, or the `tun`
68    /// feature is disabled in this build).
69    UnsupportedInTunMode,
70    /// The requested resource (e.g. a Taildrop file) does not exist.
71    NotFound,
72    /// The resource already exists (e.g. a Taildrop transfer for the same file is in progress).
73    AlreadyExists,
74    /// An underlying I/O error (e.g. a Taildrop filesystem operation failed).
75    Io,
76}
77
78impl fmt::Display for InternalErrorKind {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        match self {
81            InternalErrorKind::InvalidSocketState => write!(f, "invalid socket state"),
82            InternalErrorKind::InternalResponseMismatch => {
83                write!(f, "response type mismatched to request type")
84            }
85            InternalErrorKind::InternalChannelClosed => write!(f, "channel closed"),
86            InternalErrorKind::BadListenerHandle => write!(f, "handle to invalid TCP listener"),
87            InternalErrorKind::BadSocketHandle => write!(f, "handle to invalid socket"),
88            InternalErrorKind::BadRequest => write!(f, "bad request"),
89            InternalErrorKind::BufferFull => write!(f, "buffer full"),
90            InternalErrorKind::Actor => write!(f, "actor missing or shutdown"),
91            InternalErrorKind::UnsupportedInTunMode => {
92                write!(f, "operation unsupported in TUN transport mode")
93            }
94            InternalErrorKind::NotFound => write!(f, "resource not found"),
95            InternalErrorKind::AlreadyExists => write!(f, "resource already exists"),
96            InternalErrorKind::Io => write!(f, "I/O error"),
97        }
98    }
99}
100
101impl From<crate::netstack::InternalErrorKind> for InternalErrorKind {
102    fn from(e: crate::netstack::InternalErrorKind) -> Self {
103        match e {
104            crate::netstack::InternalErrorKind::InvalidSocketState => {
105                InternalErrorKind::InvalidSocketState
106            }
107            crate::netstack::InternalErrorKind::InternalResponseMismatch => {
108                InternalErrorKind::InternalResponseMismatch
109            }
110            crate::netstack::InternalErrorKind::InternalChannelClosed => {
111                InternalErrorKind::InternalChannelClosed
112            }
113            crate::netstack::InternalErrorKind::BadListenerHandle => {
114                InternalErrorKind::BadListenerHandle
115            }
116            crate::netstack::InternalErrorKind::BadSocketHandle => {
117                InternalErrorKind::BadSocketHandle
118            }
119            crate::netstack::InternalErrorKind::BufferFull => InternalErrorKind::BufferFull,
120            _ => unreachable!(),
121        }
122    }
123}
124
125impl From<ts_runtime::Error> for Error {
126    fn from(value: ts_runtime::Error) -> Self {
127        match value.kind {
128            ts_runtime::ErrorKind::Timeout => Error::Timeout,
129            ts_runtime::ErrorKind::ActorGone
130            | ts_runtime::ErrorKind::MailboxFull
131            | ts_runtime::ErrorKind::ReplyErr => Error::Internal(InternalErrorKind::Actor),
132            // TUN transport mode: a netstack-only operation, or TUN requested but unavailable
133            // (no device / `tun` feature off).
134            ts_runtime::ErrorKind::UnsupportedInTunMode | ts_runtime::ErrorKind::TunUnavailable => {
135                Error::Internal(InternalErrorKind::UnsupportedInTunMode)
136            }
137        }
138    }
139}
140
141impl From<NetstackError> for Error {
142    fn from(value: NetstackError) -> Self {
143        match value {
144            NetstackError::Internal(k) => Error::Internal(k.into()),
145            NetstackError::ConnectionReset => Error::ConnectionReset,
146            NetstackError::BadRequest(_) => Error::Internal(InternalErrorKind::BadRequest),
147        }
148    }
149}