tor_chanmgr/
err.rs

1//! Declare error types for tor-chanmgr
2
3use std::net::SocketAddr;
4use std::sync::Arc;
5
6use futures::task::SpawnError;
7use thiserror::Error;
8
9use crate::factory::AbstractPtError;
10use tor_error::{internal, ErrorKind};
11use tor_linkspec::{BridgeAddr, ChanTarget, IntoOwnedChanTarget, LoggedChanTarget};
12use 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)
18use safelog::{BoxSensitive as BoxChanSensitive, Sensitive as ChanSensitive};
19
20use crate::transport::proxied::ProxyError;
21
22/// An error returned by a channel manager.
23#[derive(Debug, Error, Clone)]
24#[non_exhaustive]
25pub 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
135impl<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
141impl From<tor_linkspec::ByRelayIdsError> for Error {
142    fn from(_: tor_linkspec::ByRelayIdsError) -> Self {
143        Error::MissingId
144    }
145}
146
147impl From<tor_linkspec::ListByRelayIdsError> for Error {
148    fn from(_: tor_linkspec::ListByRelayIdsError) -> Self {
149        Error::MissingId
150    }
151}
152
153impl 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
181impl 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
228impl 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}