tor_proto/util/
err.rs

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