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