Skip to main content

tor_proto/util/
err.rs

1//! Define an error type for the tor-proto crate.
2
3use futures::task::SpawnError;
4use safelog::Sensitive;
5use std::{sync::Arc, time::Duration};
6use thiserror::Error;
7use tor_cell::relaycell::{StreamId, msg::EndReason};
8use tor_error::{Bug, ErrorKind, HasKind};
9use tor_linkspec::RelayIdType;
10
11use crate::HopNum;
12use crate::client::circuit::PathEntry;
13
14/// An error type for the tor-proto crate.
15///
16/// This type should probably be split into several.  There's more
17/// than one kind of error that can occur while doing something with
18/// the Tor protocol.
19#[derive(Error, Debug, Clone)]
20#[non_exhaustive]
21pub enum Error {
22    /// An error that occurred in the tor_bytes crate while decoding an
23    /// object.
24    #[error("Unable to parse {object}")]
25    BytesErr {
26        /// What we were trying to parse.
27        object: &'static str,
28        /// The error that occurred while parsing it.
29        #[source]
30        err: tor_bytes::Error,
31    },
32    /// An error that occurred from the io system when using a
33    /// channel.
34    #[error("IO error on channel with peer")]
35    ChanIoErr(#[source] Arc<std::io::Error>),
36    /// An error from the io system that occurred when trying to connect a channel.
37    #[error("IO error while handshaking with peer")]
38    HandshakeIoErr(#[source] Arc<std::io::Error>),
39    /// An error occurred while trying to create or encode a cell.
40    #[error("Unable to generate or encode {object}")]
41    CellEncodeErr {
42        /// The object we were trying to create or encode.
43        object: &'static str,
44        /// The error that occurred.
45        #[source]
46        err: tor_cell::Error,
47    },
48    /// An error occurred while trying to decode or parse a cell.
49    #[error("Error while parsing {object}")]
50    CellDecodeErr {
51        /// The object we were trying to decode.
52        object: &'static str,
53        /// The error that occurred.
54        #[source]
55        err: tor_cell::Error,
56    },
57    /// An error occurred while trying to create or encode some non-cell
58    /// message.
59    ///
60    /// This is likely the result of a bug: either in this crate, or the code
61    /// that provided the input.
62    #[error("Problem while encoding {object}")]
63    EncodeErr {
64        /// What we were trying to create or encode.
65        object: &'static str,
66        /// The error that occurred.
67        #[source]
68        err: tor_bytes::EncodeError,
69    },
70    /// An error occurred while trying to decode a link specifier.
71    #[error("Error while parsing {object}")]
72    #[cfg(feature = "relay")]
73    LinkspecDecodeErr {
74        /// The object we were trying to decode.
75        object: &'static str,
76        /// The error that occurred.
77        #[source]
78        err: tor_linkspec::decode::ChanTargetDecodeError,
79    },
80    /// We found a problem with one of the certificates in the channel
81    /// handshake.
82    #[error("Problem with certificate on handshake")]
83    HandshakeCertErr(#[source] tor_cert::CertError),
84    /// We tried to produce too much output for a key derivation function.
85    #[error("Tried to extract too many bytes from a KDF")]
86    InvalidKDFOutputLength,
87    /// We tried to encrypt a message to a hop that wasn't there.
88    #[error("Tried to encrypt a cell for a nonexistent hop")]
89    NoSuchHop,
90    /// The authentication information on this cell was completely wrong,
91    /// or the cell was corrupted.
92    #[error("Bad relay cell authentication")]
93    BadCellAuth,
94    /// A circuit-extension handshake failed due to a mismatched authentication
95    /// value.
96    #[error("Circuit-extension handshake authentication failed")]
97    BadCircHandshakeAuth,
98    /// Handshake protocol violation.
99    #[error("Handshake protocol violation: {0}")]
100    HandshakeProto(String),
101    /// Handshake broken, maybe due to clock skew.
102    ///
103    /// (If the problem can't be due to clock skew, we return HandshakeProto
104    /// instead.)
105    #[error("Handshake failed due to expired certificates (possible clock skew)")]
106    HandshakeCertsExpired {
107        /// For how long has the circuit been expired?
108        expired_by: Duration,
109    },
110    /// Protocol violation at the channel level, other than at the handshake
111    /// stage.
112    #[error("Channel protocol violation: {0}")]
113    ChanProto(String),
114    /// Protocol violation at the circuit level
115    #[error("Circuit protocol violation: {0}")]
116    CircProto(String),
117    /// Channel is closed, or became closed while we were trying to do some
118    /// operation.
119    #[error("Channel closed")]
120    ChannelClosed(#[from] ChannelClosed),
121    /// Circuit is closed, or became closed while we were trying to so some
122    /// operation.
123    #[error("Circuit closed")]
124    CircuitClosed,
125    /// Can't allocate any more circuit or stream IDs on a channel.
126    #[error("Too many entries in map: can't allocate ID")]
127    IdRangeFull,
128    /// Received a stream request with a stream ID that is already in use for another stream.
129    #[error("Stream ID {0} is already in use")]
130    IdUnavailable(StreamId),
131    /// Received a cell with a stream ID of zero.
132    #[error("Received a cell with a stream ID of zero")]
133    StreamIdZero,
134    /// Received a cell on a closed or non-existent stream.
135    #[error(
136        "Received a cell from {} on a closed or non-existent stream {}. \
137         Either they are violating the protocol, or we are expiring streams too aggressively",
138        src,
139        streamid
140    )]
141    UnknownStream {
142        /// The hop the cell originated from.
143        src: Sensitive<PathEntry>,
144        /// The stream ID of the cell.
145        streamid: StreamId,
146    },
147    /// Couldn't extend a circuit because the extending relay or the
148    /// target relay refused our request.
149    #[error("Circuit extension refused: {0}")]
150    CircRefused(&'static str),
151    /// Tried to make or use a stream to an invalid destination address.
152    #[error("Invalid stream target address")]
153    BadStreamAddress,
154    /// Received an End cell from the other end of a stream.
155    #[error("Received an END cell with reason {0}")]
156    EndReceived(EndReason),
157    /// Stream was already closed when we tried to use it.
158    #[error("Stream not connected")]
159    NotConnected,
160    /// Stream protocol violation
161    #[error("Stream protocol violation: {0}")]
162    StreamProto(String),
163
164    /// Excessive data received from a circuit hop.
165    #[error("Received too many inbound cells")]
166    ExcessInboundCells,
167    /// Tried to send too many cells to a circuit hop.
168    #[error("Tried to send too many outbound cells")]
169    ExcessOutboundCells,
170
171    /// Received unexpected or excessive inbound circuit
172    #[error("Received unexpected or excessive circuit padding from {}", _1.display())]
173    ExcessPadding(#[source] ExcessPadding, HopNum),
174
175    /// Channel does not match target
176    #[error("Peer identity mismatch: {0}")]
177    ChanMismatch(String),
178    /// There was a programming error somewhere in our code, or the calling code.
179    #[error("Programming error")]
180    Bug(#[from] tor_error::Bug),
181    /// Remote DNS lookup failed.
182    #[error("Remote resolve failed")]
183    ResolveError(#[source] ResolveError),
184    /// We tried to do something with a that we couldn't, because of an identity key type
185    /// that the relay doesn't have.
186    #[error("Relay has no {0} identity")]
187    MissingId(RelayIdType),
188    /// Memory quota error
189    #[error("memory quota error")]
190    Memquota(#[from] tor_memquota::Error),
191
192    /// Unable to spawn task
193    //
194    // TODO lots of our Errors have a variant exactly like this.
195    // Maybe we should make a struct tor_error::SpawnError.
196    #[error("Unable to spawn {spawning}")]
197    Spawn {
198        /// What we were trying to spawn.
199        spawning: &'static str,
200        /// What happened when we tried to spawn it.
201        #[source]
202        cause: Arc<SpawnError>,
203    },
204
205    /// An unsupported authentication type value. This is raised during the relay <-> relay channel
206    /// handshake if the authentication presented from the other side is unsupported.
207    #[cfg(feature = "relay")]
208    #[error("Authentication type {0} is unsupported")]
209    UnsupportedAuth(u16),
210}
211
212/// Error which indicates that the channel was closed.
213#[derive(Error, Debug, Clone)]
214#[error("Channel closed")]
215pub struct ChannelClosed;
216
217impl HasKind for ChannelClosed {
218    fn kind(&self) -> ErrorKind {
219        ErrorKind::CircuitCollapse
220    }
221}
222
223/// Details about an error received while resolving a domain
224#[derive(Error, Debug, Clone)]
225#[non_exhaustive]
226pub enum ResolveError {
227    /// A transient error which can be retried
228    #[error("Received retriable transient error")]
229    Transient,
230    /// A non transient error, which shouldn't be retried
231    #[error("Received non-retriable error")]
232    Nontransient,
233    /// Could not parse the response properly
234    #[error("Received unrecognized result")]
235    Unrecognized,
236}
237
238impl Error {
239    /// Create an error from a tor_cell error that has occurred while trying to
240    /// encode or create something of type `object`
241    pub(crate) fn from_cell_enc(err: tor_cell::Error, object: &'static str) -> Error {
242        Error::CellEncodeErr { object, err }
243    }
244
245    /// Create an error for a tor_bytes error that occurred while parsing
246    /// something of type `object`.
247    pub(crate) fn from_bytes_err(err: tor_bytes::Error, object: &'static str) -> Error {
248        Error::BytesErr { err, object }
249    }
250
251    /// Create an error for a tor_bytes error that occurred while encoding
252    /// something of type `object`.
253    pub(crate) fn from_bytes_enc(err: tor_bytes::EncodeError, object: &'static str) -> Error {
254        Error::EncodeErr { err, object }
255    }
256}
257
258impl From<std::io::Error> for Error {
259    fn from(err: std::io::Error) -> Self {
260        Self::ChanIoErr(Arc::new(err))
261    }
262}
263
264impl From<Error> for std::io::Error {
265    fn from(err: Error) -> std::io::Error {
266        use Error::*;
267        use std::io::ErrorKind;
268        let kind = match err {
269            ChanIoErr(e) | HandshakeIoErr(e) => match Arc::try_unwrap(e) {
270                Ok(e) => return e,
271                Err(arc) => return std::io::Error::new(arc.kind(), arc),
272            },
273
274            InvalidKDFOutputLength | NoSuchHop | BadStreamAddress => ErrorKind::InvalidInput,
275
276            NotConnected => ErrorKind::NotConnected,
277
278            EndReceived(end_reason) => end_reason.into(),
279
280            CircuitClosed => ErrorKind::ConnectionReset,
281
282            Memquota { .. } => ErrorKind::OutOfMemory,
283
284            BytesErr { .. }
285            | BadCellAuth
286            | BadCircHandshakeAuth
287            | HandshakeProto(_)
288            | HandshakeCertErr(_)
289            | ChanProto(_)
290            | HandshakeCertsExpired { .. }
291            | ChannelClosed(_)
292            | CircProto(_)
293            | CellDecodeErr { .. }
294            | CellEncodeErr { .. }
295            | EncodeErr { .. }
296            | ChanMismatch(_)
297            | StreamProto(_)
298            | MissingId(_)
299            | IdUnavailable(_)
300            | StreamIdZero
301            | UnknownStream { .. }
302            | ExcessInboundCells
303            | ExcessOutboundCells
304            | ExcessPadding(_, _) => ErrorKind::InvalidData,
305
306            #[cfg(feature = "relay")]
307            LinkspecDecodeErr { .. } => ErrorKind::InvalidData,
308            #[cfg(feature = "relay")]
309            UnsupportedAuth(_) => ErrorKind::Unsupported,
310
311            Bug(ref e) if e.kind() == tor_error::ErrorKind::BadApiUsage => ErrorKind::InvalidData,
312
313            IdRangeFull | CircRefused(_) | ResolveError(_) | Spawn { .. } | Bug(_) => {
314                ErrorKind::Other
315            }
316        };
317        std::io::Error::new(kind, err)
318    }
319}
320
321impl HasKind for Error {
322    fn kind(&self) -> ErrorKind {
323        use Error as E;
324        use ErrorKind as EK;
325        use tor_bytes::Error as BytesError;
326        match self {
327            E::BytesErr {
328                err: BytesError::Bug(e),
329                ..
330            } => e.kind(),
331            E::BytesErr { .. } => EK::TorProtocolViolation,
332            E::ChanIoErr(_) => EK::LocalNetworkError,
333            E::HandshakeIoErr(_) => EK::TorAccessFailed,
334            E::HandshakeCertErr(_) => EK::TorProtocolViolation,
335            E::CellEncodeErr { err, .. } => err.kind(),
336            E::CellDecodeErr { err, .. } => err.kind(),
337            #[cfg(feature = "relay")]
338            E::LinkspecDecodeErr { .. } => EK::TorProtocolViolation,
339            E::EncodeErr { .. } => EK::BadApiUsage,
340            E::InvalidKDFOutputLength => EK::Internal,
341            E::NoSuchHop => EK::BadApiUsage,
342            E::BadCellAuth => EK::TorProtocolViolation,
343            E::BadCircHandshakeAuth => EK::TorProtocolViolation,
344            E::HandshakeProto(_) => EK::TorAccessFailed,
345            E::HandshakeCertsExpired { .. } => EK::ClockSkew,
346            E::ChanProto(_) => EK::TorProtocolViolation,
347            E::CircProto(_) => EK::TorProtocolViolation,
348            E::ChannelClosed(e) => e.kind(),
349            E::CircuitClosed => EK::CircuitCollapse,
350            E::IdRangeFull => EK::BadApiUsage,
351            E::CircRefused(_) => EK::CircuitRefused,
352            E::BadStreamAddress => EK::BadApiUsage,
353            E::EndReceived(reason) => reason.kind(),
354            E::NotConnected => EK::BadApiUsage,
355            E::StreamProto(_) => EK::TorProtocolViolation,
356            E::ChanMismatch(_) => EK::RelayIdMismatch,
357            E::ResolveError(ResolveError::Nontransient) => EK::RemoteHostNotFound,
358            E::ResolveError(ResolveError::Transient) => EK::RemoteHostResolutionFailed,
359            E::ResolveError(ResolveError::Unrecognized) => EK::RemoteHostResolutionFailed,
360            E::MissingId(_) => EK::BadApiUsage,
361            E::IdUnavailable(_) => EK::BadApiUsage,
362            E::StreamIdZero => EK::BadApiUsage,
363            E::UnknownStream { .. } => EK::TorProtocolViolation,
364            E::ExcessInboundCells => EK::TorProtocolViolation,
365            E::ExcessOutboundCells => EK::Internal,
366            E::ExcessPadding(_, _) => EK::TorProtocolViolation,
367            E::Memquota(err) => err.kind(),
368            E::Spawn { cause, .. } => cause.kind(),
369            E::Bug(e) => e.kind(),
370            #[cfg(feature = "relay")]
371            E::UnsupportedAuth(_) => EK::RemoteProtocolViolation,
372        }
373    }
374}
375
376/// Internal type: Error return value from reactor's run_once
377/// function: indicates an error or a shutdown.
378#[derive(Debug)]
379pub(crate) enum ReactorError {
380    /// The reactor should shut down with an abnormal exit condition.
381    Err(Error),
382    /// The reactor should shut down without an error, since all is well.
383    Shutdown,
384}
385
386impl From<Error> for ReactorError {
387    fn from(e: Error) -> ReactorError {
388        ReactorError::Err(e)
389    }
390}
391
392impl From<ChannelClosed> for ReactorError {
393    fn from(e: ChannelClosed) -> ReactorError {
394        ReactorError::Err(e.into())
395    }
396}
397
398impl From<Bug> for ReactorError {
399    fn from(e: Bug) -> ReactorError {
400        ReactorError::Err(e.into())
401    }
402}
403
404#[cfg(test)]
405impl ReactorError {
406    /// Tests only: assert that this is an Error, and return it.
407    pub(crate) fn unwrap_err(self) -> Error {
408        match self {
409            ReactorError::Shutdown => panic!(),
410            ReactorError::Err(e) => e,
411        }
412    }
413}
414
415/// An error type for client-side conflux handshakes.
416#[derive(Debug)]
417#[cfg(feature = "conflux")]
418#[allow(unused)] // TODO(conflux): remove
419pub(crate) enum ConfluxHandshakeError {
420    /// Timeout while waiting for CONFLUX_LINKED response.
421    Timeout,
422    /// An error that occurred while sending the CONFLUX_LINK message.
423    Link(Error),
424    /// The channel was closed.
425    ChannelClosed,
426}
427
428/// An error returned when we receive excessive or unexpected padding.
429#[derive(Debug, Clone, Error)]
430#[non_exhaustive]
431pub enum ExcessPadding {
432    /// We received circuit padding when we hadn't negotiated a padding framework.
433    #[error("Padding received when not negotiated with given hop")]
434    NoPaddingNegotiated,
435    /// We received more padding than our negotiated framework permits.
436    #[error("Received padding in excess of negotiated framework's limit")]
437    PaddingExceedsLimit,
438}