tor_proto/util/
err.rs

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