1
//! Declare error types for tor-chanmgr
2

            
3
use std::net::SocketAddr;
4
use std::sync::Arc;
5

            
6
use futures::task::SpawnError;
7
use thiserror::Error;
8

            
9
use crate::factory::AbstractPtError;
10
use tor_error::{internal, ErrorKind};
11
use tor_linkspec::{BridgeAddr, ChanTarget, IntoOwnedChanTarget, LoggedChanTarget};
12
use tor_proto::ClockSkew;
13

            
14
// We use "ChanSensitive" for values which are sensitive because they relate to
15
// channel-layer trouble, rather than circuit-layer or higher.  This will let us find these later:
16
// if we want to change `LoggedChanTarget` to `Redacted` (say), we should change these too.
17
// (`Redacted` like https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/882)
18
use safelog::{BoxSensitive as BoxChanSensitive, Sensitive as ChanSensitive};
19

            
20
use crate::transport::proxied::ProxyError;
21

            
22
/// An error returned by a channel manager.
23
#[derive(Debug, Error, Clone)]
24
#[non_exhaustive]
25
pub enum Error {
26
    /// A ChanTarget was given for which no channel could be built.
27
    #[error("Bug: Target was unusable")]
28
    UnusableTarget(#[source] tor_error::Bug),
29

            
30
    /// We were waiting on a pending channel, but it didn't succeed.
31
    #[error("Pending channel for {peer} failed to launch")]
32
    PendingFailed {
33
        /// Who we were talking to
34
        peer: LoggedChanTarget,
35
    },
36

            
37
    /// It took too long for us to establish this connection.
38
    #[error("Channel for {peer} timed out")]
39
    ChanTimeout {
40
        /// Who we were trying to talk to
41
        peer: LoggedChanTarget,
42
    },
43

            
44
    /// A protocol error while making a channel
45
    #[error("Protocol error while opening a channel with {peer}")]
46
    Proto {
47
        /// The underlying error
48
        #[source]
49
        source: tor_proto::Error,
50
        /// Who we were trying to talk to
51
        peer: LoggedChanTarget,
52
        /// An authenticated ClockSkew (if available) that we received from the
53
        /// peer.
54
        clock_skew: Option<ClockSkew>,
55
    },
56

            
57
    /// Network IO error or TLS error
58
    #[error("Network IO error, or TLS error, in {action}, talking to {peer:?}")]
59
    Io {
60
        /// Who we were talking to
61
        peer: Option<BoxChanSensitive<BridgeAddr>>,
62

            
63
        /// What we were doing
64
        action: &'static str,
65

            
66
        /// What happened.  Might be some TLS library error wrapped up in io::Error
67
        #[source]
68
        source: Arc<std::io::Error>,
69
    },
70

            
71
    /// Failed to build a channel, after trying multiple addresses.
72
    #[error("Channel build failed: [(address, error)] = {addresses:?}")]
73
    ChannelBuild {
74
        /// The list of addresses we tried to connect to, coupled with
75
        /// the error we encountered connecting to each one.
76
        addresses: Vec<(ChanSensitive<SocketAddr>, Arc<std::io::Error>)>,
77
    },
78

            
79
    /// Unable to spawn task
80
    #[error("unable to spawn {spawning}")]
81
    Spawn {
82
        /// What we were trying to spawn.
83
        spawning: &'static str,
84
        /// What happened when we tried to spawn it.
85
        #[source]
86
        cause: Arc<SpawnError>,
87
    },
88

            
89
    /// A relay did not have the set of identity keys that we expected.
90
    ///
91
    /// (Currently, `tor-chanmgr` only works on relays that have at least
92
    /// one recognized identity key.)
93
    #[error("Could not identify relay by identity key")]
94
    MissingId,
95

            
96
    /// A successful relay channel had one of the identity keys we wanted,
97
    /// but not the other(s).
98
    ///
99
    /// This means that (assuming the relay is well behaved), we will not
100
    /// find the ID combination we want.
101
    #[error("Relay identity keys were only a partial match for what we wanted.")]
102
    IdentityConflict,
103

            
104
    /// Tried to connect via a transport that we don't support.
105
    #[error("No plugin available for the transport {0}")]
106
    NoSuchTransport(tor_linkspec::TransportId),
107

            
108
    /// An attempt to open a channel failed because it was cancelled or
109
    /// superseded by another request or configuration change.
110
    #[error("Channel request cancelled or superseded")]
111
    RequestCancelled,
112

            
113
    /// We tried to create a channel through a proxy, and encountered an error.
114
    #[error("Problem while connecting to Tor via a proxy")]
115
    Proxy(#[from] ProxyError),
116

            
117
    /// An error occurred in a pluggable transport manager.
118
    ///
119
    /// We can't know the type, because any pluggable transport manager implementing
120
    /// `AbstractPtMgr` can be used.
121
    /// However, if you're using Arti in the standard configuration, this will be
122
    /// `tor-ptmgr`'s `PtError`.
123
    #[error("Pluggable transport error: {0}")]
124
    Pt(#[source] Arc<dyn AbstractPtError>),
125

            
126
    /// Memory quota error
127
    #[error("memory quota error")]
128
    Memquota(#[from] tor_memquota::Error),
129

            
130
    /// An internal error of some kind that should never occur.
131
    #[error("Internal error")]
132
    Internal(#[from] tor_error::Bug),
133
}
134

            
135
impl<T> From<std::sync::PoisonError<T>> for Error {
136
    fn from(_: std::sync::PoisonError<T>) -> Error {
137
        Error::Internal(internal!("Thread failed while holding lock"))
138
    }
139
}
140

            
141
impl From<tor_linkspec::ByRelayIdsError> for Error {
142
    fn from(_: tor_linkspec::ByRelayIdsError) -> Self {
143
        Error::MissingId
144
    }
145
}
146

            
147
impl From<tor_linkspec::ListByRelayIdsError> for Error {
148
    fn from(_: tor_linkspec::ListByRelayIdsError) -> Self {
149
        Error::MissingId
150
    }
151
}
152

            
153
impl tor_error::HasKind for Error {
154
    fn kind(&self) -> ErrorKind {
155
        use tor_proto::Error as ProtoErr;
156
        use Error as E;
157
        use ErrorKind as EK;
158
        match self {
159
            E::ChanTimeout { .. }
160
            | E::Io { .. }
161
            | E::Proto {
162
                source: ProtoErr::ChanIoErr(_),
163
                ..
164
            } => EK::TorAccessFailed,
165
            E::Spawn { cause, .. } => cause.kind(),
166
            E::Proto { source, .. } => source.kind(),
167
            E::PendingFailed { .. } => EK::TorAccessFailed,
168
            E::NoSuchTransport(_) => EK::InvalidConfig,
169
            E::UnusableTarget(_) | E::Internal(_) => EK::Internal,
170
            E::MissingId => EK::BadApiUsage,
171
            E::IdentityConflict => EK::TorAccessFailed,
172
            E::ChannelBuild { .. } => EK::TorAccessFailed,
173
            E::RequestCancelled => EK::TransientFailure,
174
            E::Proxy(e) => e.kind(),
175
            E::Memquota(e) => e.kind(),
176
            E::Pt(e) => e.kind(),
177
        }
178
    }
179
}
180

            
181
impl tor_error::HasRetryTime for Error {
182
    fn retry_time(&self) -> tor_error::RetryTime {
183
        use tor_error::RetryTime as RT;
184
        use Error as E;
185
        match self {
186
            // We can retry this action immediately; there was already a time delay.
187
            E::ChanTimeout { .. } => RT::Immediate,
188

            
189
            // These are worth retrying in a little while.
190
            //
191
            // TODO: Someday we might want to distinguish among different kinds of IO
192
            // errors.
193
            E::PendingFailed { .. } | E::Proto { .. } | E::Io { .. } => RT::AfterWaiting,
194

            
195
            // Delegate.
196
            E::Proxy(e) => e.retry_time(),
197
            E::Pt(e) => e.retry_time(),
198

            
199
            // This error reflects multiple attempts, but every failure is an IO
200
            // error, so we can also retry this after a delay.
201
            //
202
            // TODO: Someday we might want to distinguish among different kinds
203
            // of IO errors.
204
            E::ChannelBuild { .. } => RT::AfterWaiting,
205

            
206
            // This one can't succeed: if the ChanTarget have addresses to begin with,
207
            // it won't have addresses in the future.
208
            E::UnusableTarget(_) => RT::Never,
209

            
210
            // This can't succeed until the relay is reconfigured.
211
            E::IdentityConflict => RT::Never,
212

            
213
            // This one can't succeed until the bridge, or our set of
214
            // transports, is reconfigured.
215
            E::NoSuchTransport(_) => RT::Never,
216

            
217
            E::RequestCancelled => RT::Immediate,
218

            
219
            // Hopefully the problem will pass!
220
            E::Memquota { .. } => RT::AfterWaiting,
221

            
222
            // These aren't recoverable at all.
223
            E::Spawn { .. } | E::MissingId | E::Internal(_) => RT::Never,
224
        }
225
    }
226
}
227

            
228
impl Error {
229
    /// Construct a new `Error` from a `SpawnError`.
230
    pub(crate) fn from_spawn(spawning: &'static str, err: SpawnError) -> Error {
231
        Error::Spawn {
232
            spawning,
233
            cause: Arc::new(err),
234
        }
235
    }
236

            
237
    /// Construct a new `Error` from a `tor_proto::Error`, with no additional
238
    /// clock skew information.
239
    ///
240
    /// This is not an `Into` implementation because we don't want to call it
241
    /// accidentally when we actually do have clock skew information.
242
    pub(crate) fn from_proto_no_skew<T: ChanTarget + ?Sized>(
243
        source: tor_proto::Error,
244
        peer: &T,
245
    ) -> Self {
246
        Error::Proto {
247
            source,
248
            peer: peer.to_logged(),
249
            clock_skew: None,
250
        }
251
    }
252

            
253
    /// Return the clock skew information from this error (or from an internal
254
    /// error).
255
    ///
256
    /// Only returns the clock skew information if it is authenticated.
257
    pub fn clock_skew(&self) -> Option<ClockSkew> {
258
        match self {
259
            Error::Proto { clock_skew, .. } => *clock_skew,
260
            _ => None,
261
        }
262
    }
263
}