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