1
//! Define an error type for the tor-proto crate.
2
use safelog::Sensitive;
3
use std::{sync::Arc, time::Duration};
4
use thiserror::Error;
5
use tor_cell::relaycell::{StreamId, msg::EndReason};
6
use tor_error::{Bug, ErrorKind, HasKind};
7
use tor_linkspec::RelayIdType;
8

            
9
use crate::HopNum;
10
use 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]
19
pub 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
    /// An error occurred while trying to decode a link specifier.
69
    #[error("Error while parsing {object}")]
70
    #[cfg(feature = "relay")]
71
    LinkspecDecodeErr {
72
        /// The object we were trying to decode.
73
        object: &'static str,
74
        /// The error that occurred.
75
        #[source]
76
        err: tor_linkspec::decode::ChanTargetDecodeError,
77
    },
78
    /// We found a problem with one of the certificates in the channel
79
    /// handshake.
80
    #[error("Problem with certificate on handshake")]
81
    HandshakeCertErr(#[source] tor_cert::CertError),
82
    /// We tried to produce too much output for a key derivation function.
83
    #[error("Tried to extract too many bytes from a KDF")]
84
    InvalidKDFOutputLength,
85
    /// We tried to encrypt a message to a hop that wasn't there.
86
    #[error("Tried to encrypt a cell for a nonexistent hop")]
87
    NoSuchHop,
88
    /// The authentication information on this cell was completely wrong,
89
    /// or the cell was corrupted.
90
    #[error("Bad relay cell authentication")]
91
    BadCellAuth,
92
    /// A circuit-extension handshake failed due to a mismatched authentication
93
    /// value.
94
    #[error("Circuit-extension handshake authentication failed")]
95
    BadCircHandshakeAuth,
96
    /// Handshake protocol violation.
97
    #[error("Handshake protocol violation: {0}")]
98
    HandshakeProto(String),
99
    /// Handshake broken, maybe due to clock skew.
100
    ///
101
    /// (If the problem can't be due to clock skew, we return HandshakeProto
102
    /// instead.)
103
    #[error("Handshake failed due to expired certificates (possible clock skew)")]
104
    HandshakeCertsExpired {
105
        /// For how long has the circuit been expired?
106
        expired_by: Duration,
107
    },
108
    /// Protocol violation at the channel level, other than at the handshake
109
    /// stage.
110
    #[error("Channel protocol violation: {0}")]
111
    ChanProto(String),
112
    /// Protocol violation at the circuit level
113
    #[error("Circuit protocol violation: {0}")]
114
    CircProto(String),
115
    /// Channel is closed, or became closed while we were trying to do some
116
    /// operation.
117
    #[error("Channel closed")]
118
    ChannelClosed(#[from] ChannelClosed),
119
    /// Circuit is closed, or became closed while we were trying to so some
120
    /// operation.
121
    #[error("Circuit closed")]
122
    CircuitClosed,
123
    /// Can't allocate any more circuit or stream IDs on a channel.
124
    #[error("Too many entries in map: can't allocate ID")]
125
    IdRangeFull,
126
    /// Received a stream request with a stream ID that is already in use for another stream.
127
    #[error("Stream ID {0} is already in use")]
128
    IdUnavailable(StreamId),
129
    /// Received a cell with a stream ID of zero.
130
    #[error("Received a cell with a stream ID of zero")]
131
    StreamIdZero,
132
    /// Received a cell on a closed or non-existent stream.
133
    #[error(
134
        "Received a cell from {} on a closed or non-existent stream {}. \
135
         Either they are violating the protocol, or we are expiring streams too aggressively",
136
        src,
137
        streamid
138
    )]
139
    UnknownStream {
140
        /// The hop the cell originated from.
141
        src: Sensitive<PathEntry>,
142
        /// The stream ID of the cell.
143
        streamid: StreamId,
144
    },
145
    /// Couldn't extend a circuit because the extending relay or the
146
    /// target relay refused our request.
147
    #[error("Circuit extension refused: {0}")]
148
    CircRefused(&'static str),
149
    /// Tried to make or use a stream to an invalid destination address.
150
    #[error("Invalid stream target address")]
151
    BadStreamAddress,
152
    /// Received an End cell from the other end of a stream.
153
    #[error("Received an END cell with reason {0}")]
154
    EndReceived(EndReason),
155
    /// Stream was already closed when we tried to use it.
156
    #[error("Stream not connected")]
157
    NotConnected,
158
    /// Stream protocol violation
159
    #[error("Stream protocol violation: {0}")]
160
    StreamProto(String),
161

            
162
    /// Excessive data received from a circuit hop.
163
    #[error("Received too many inbound cells")]
164
    ExcessInboundCells,
165
    /// Tried to send too many cells to a circuit hop.
166
    #[error("Tried to send too many outbound cells")]
167
    ExcessOutboundCells,
168

            
169
    /// Received unexpected or excessive inbound circuit
170
    #[error("Received unexpected or excessive circuit padding from {}", _1.display())]
171
    ExcessPadding(#[source] ExcessPadding, HopNum),
172

            
173
    /// Channel does not match target
174
    #[error("Peer identity mismatch: {0}")]
175
    ChanMismatch(String),
176
    /// There was a programming error somewhere in our code, or the calling code.
177
    #[error("Programming error")]
178
    Bug(#[from] tor_error::Bug),
179
    /// Remote DNS lookup failed.
180
    #[error("Remote resolve failed")]
181
    ResolveError(#[source] ResolveError),
182
    /// We tried to do something with a that we couldn't, because of an identity key type
183
    /// that the relay doesn't have.
184
    #[error("Relay has no {0} identity")]
185
    MissingId(RelayIdType),
186
    /// Memory quota error
187
    #[error("memory quota error")]
188
    Memquota(#[from] tor_memquota::Error),
189
    /// An unsupported authentication type value. This is raised during the relay <-> relay channel
190
    /// handshake if the authentication presented from the other side is unsupported.
191
    #[cfg(feature = "relay")]
192
    #[error("Authentication type {0} is unsupported")]
193
    UnsupportedAuth(u16),
194
}
195

            
196
/// Error which indicates that the channel was closed.
197
#[derive(Error, Debug, Clone)]
198
#[error("Channel closed")]
199
pub struct ChannelClosed;
200

            
201
impl HasKind for ChannelClosed {
202
4
    fn kind(&self) -> ErrorKind {
203
4
        ErrorKind::CircuitCollapse
204
4
    }
205
}
206

            
207
/// Details about an error received while resolving a domain
208
#[derive(Error, Debug, Clone)]
209
#[non_exhaustive]
210
pub enum ResolveError {
211
    /// A transient error which can be retried
212
    #[error("Received retriable transient error")]
213
    Transient,
214
    /// A non transient error, which shouldn't be retried
215
    #[error("Received non-retriable error")]
216
    Nontransient,
217
    /// Could not parse the response properly
218
    #[error("Received unrecognized result")]
219
    Unrecognized,
220
}
221

            
222
impl Error {
223
    /// Create an error from a tor_cell error that has occurred while trying to
224
    /// encode or create something of type `object`
225
    pub(crate) fn from_cell_enc(err: tor_cell::Error, object: &'static str) -> Error {
226
        Error::CellEncodeErr { object, err }
227
    }
228

            
229
    /// Create an error for a tor_bytes error that occurred while parsing
230
    /// something of type `object`.
231
12
    pub(crate) fn from_bytes_err(err: tor_bytes::Error, object: &'static str) -> Error {
232
12
        Error::BytesErr { err, object }
233
12
    }
234

            
235
    /// Create an error for a tor_bytes error that occurred while encoding
236
    /// something of type `object`.
237
    pub(crate) fn from_bytes_enc(err: tor_bytes::EncodeError, object: &'static str) -> Error {
238
        Error::EncodeErr { err, object }
239
    }
240
}
241

            
242
impl From<std::io::Error> for Error {
243
    fn from(err: std::io::Error) -> Self {
244
        Self::ChanIoErr(Arc::new(err))
245
    }
246
}
247

            
248
impl From<Error> for std::io::Error {
249
    fn from(err: Error) -> std::io::Error {
250
        use Error::*;
251
        use std::io::ErrorKind;
252
        let kind = match err {
253
            ChanIoErr(e) | HandshakeIoErr(e) => match Arc::try_unwrap(e) {
254
                Ok(e) => return e,
255
                Err(arc) => return std::io::Error::new(arc.kind(), arc),
256
            },
257

            
258
            InvalidKDFOutputLength | NoSuchHop | BadStreamAddress => ErrorKind::InvalidInput,
259

            
260
            NotConnected => ErrorKind::NotConnected,
261

            
262
            EndReceived(end_reason) => end_reason.into(),
263

            
264
            CircuitClosed => ErrorKind::ConnectionReset,
265

            
266
            Memquota { .. } => ErrorKind::OutOfMemory,
267

            
268
            BytesErr { .. }
269
            | BadCellAuth
270
            | BadCircHandshakeAuth
271
            | HandshakeProto(_)
272
            | HandshakeCertErr(_)
273
            | ChanProto(_)
274
            | HandshakeCertsExpired { .. }
275
            | ChannelClosed(_)
276
            | CircProto(_)
277
            | CellDecodeErr { .. }
278
            | CellEncodeErr { .. }
279
            | EncodeErr { .. }
280
            | ChanMismatch(_)
281
            | StreamProto(_)
282
            | MissingId(_)
283
            | IdUnavailable(_)
284
            | StreamIdZero
285
            | UnknownStream { .. }
286
            | ExcessInboundCells
287
            | ExcessOutboundCells
288
            | ExcessPadding(_, _) => ErrorKind::InvalidData,
289

            
290
            #[cfg(feature = "relay")]
291
            LinkspecDecodeErr { .. } => ErrorKind::InvalidData,
292
            #[cfg(feature = "relay")]
293
            UnsupportedAuth(_) => ErrorKind::Unsupported,
294

            
295
            Bug(ref e) if e.kind() == tor_error::ErrorKind::BadApiUsage => ErrorKind::InvalidData,
296

            
297
            IdRangeFull | CircRefused(_) | ResolveError(_) | Bug(_) => ErrorKind::Other,
298
        };
299
        std::io::Error::new(kind, err)
300
    }
301
}
302

            
303
impl HasKind for Error {
304
260
    fn kind(&self) -> ErrorKind {
305
        use Error as E;
306
        use ErrorKind as EK;
307
        use tor_bytes::Error as BytesError;
308
12
        match self {
309
            E::BytesErr {
310
                err: BytesError::Bug(e),
311
                ..
312
            } => e.kind(),
313
12
            E::BytesErr { .. } => EK::TorProtocolViolation,
314
            E::ChanIoErr(_) => EK::LocalNetworkError,
315
            E::HandshakeIoErr(_) => EK::TorAccessFailed,
316
            E::HandshakeCertErr(_) => EK::TorProtocolViolation,
317
            E::CellEncodeErr { err, .. } => err.kind(),
318
136
            E::CellDecodeErr { err, .. } => err.kind(),
319
            #[cfg(feature = "relay")]
320
            E::LinkspecDecodeErr { .. } => EK::TorProtocolViolation,
321
            E::EncodeErr { .. } => EK::BadApiUsage,
322
            E::InvalidKDFOutputLength => EK::Internal,
323
            E::NoSuchHop => EK::BadApiUsage,
324
            E::BadCellAuth => EK::TorProtocolViolation,
325
12
            E::BadCircHandshakeAuth => EK::TorProtocolViolation,
326
            E::HandshakeProto(_) => EK::TorAccessFailed,
327
            E::HandshakeCertsExpired { .. } => EK::ClockSkew,
328
12
            E::ChanProto(_) => EK::TorProtocolViolation,
329
80
            E::CircProto(_) => EK::TorProtocolViolation,
330
4
            E::ChannelClosed(e) => e.kind(),
331
            E::CircuitClosed => EK::CircuitCollapse,
332
            E::IdRangeFull => EK::BadApiUsage,
333
            E::CircRefused(_) => EK::CircuitRefused,
334
            E::BadStreamAddress => EK::BadApiUsage,
335
            E::EndReceived(reason) => reason.kind(),
336
            E::NotConnected => EK::BadApiUsage,
337
            E::StreamProto(_) => EK::TorProtocolViolation,
338
            E::ChanMismatch(_) => EK::RelayIdMismatch,
339
            E::ResolveError(ResolveError::Nontransient) => EK::RemoteHostNotFound,
340
            E::ResolveError(ResolveError::Transient) => EK::RemoteHostResolutionFailed,
341
            E::ResolveError(ResolveError::Unrecognized) => EK::RemoteHostResolutionFailed,
342
            E::MissingId(_) => EK::BadApiUsage,
343
            E::IdUnavailable(_) => EK::BadApiUsage,
344
            E::StreamIdZero => EK::BadApiUsage,
345
4
            E::UnknownStream { .. } => EK::TorProtocolViolation,
346
            E::ExcessInboundCells => EK::TorProtocolViolation,
347
            E::ExcessOutboundCells => EK::Internal,
348
            E::ExcessPadding(_, _) => EK::TorProtocolViolation,
349
            E::Memquota(err) => err.kind(),
350
            E::Bug(e) => e.kind(),
351
            #[cfg(feature = "relay")]
352
            E::UnsupportedAuth(_) => EK::RemoteProtocolViolation,
353
        }
354
260
    }
355
}
356

            
357
/// Internal type: Error return value from reactor's run_once
358
/// function: indicates an error or a shutdown.
359
#[derive(Debug)]
360
pub(crate) enum ReactorError {
361
    /// The reactor should shut down with an abnormal exit condition.
362
    Err(Error),
363
    /// The reactor should shut down without an error, since all is well.
364
    Shutdown,
365
}
366

            
367
impl From<Error> for ReactorError {
368
332
    fn from(e: Error) -> ReactorError {
369
332
        ReactorError::Err(e)
370
332
    }
371
}
372

            
373
impl From<ChannelClosed> for ReactorError {
374
    fn from(e: ChannelClosed) -> ReactorError {
375
        ReactorError::Err(e.into())
376
    }
377
}
378

            
379
impl From<Bug> for ReactorError {
380
    fn from(e: Bug) -> ReactorError {
381
        ReactorError::Err(e.into())
382
    }
383
}
384

            
385
#[cfg(test)]
386
impl ReactorError {
387
    /// Tests only: assert that this is an Error, and return it.
388
72
    pub(crate) fn unwrap_err(self) -> Error {
389
72
        match self {
390
            ReactorError::Shutdown => panic!(),
391
72
            ReactorError::Err(e) => e,
392
        }
393
72
    }
394
}
395

            
396
/// An error type for client-side conflux handshakes.
397
#[derive(Debug)]
398
#[cfg(feature = "conflux")]
399
#[allow(unused)] // TODO(conflux): remove
400
pub(crate) enum ConfluxHandshakeError {
401
    /// Timeout while waiting for CONFLUX_LINKED response.
402
    Timeout,
403
    /// An error that occurred while sending the CONFLUX_LINK message.
404
    Link(Error),
405
    /// The channel was closed.
406
    ChannelClosed,
407
}
408

            
409
/// An error returned when we receive excessive or unexpected padding.
410
#[derive(Debug, Clone, Error)]
411
#[non_exhaustive]
412
pub enum ExcessPadding {
413
    /// We received circuit padding when we hadn't negotiated a padding framework.
414
    #[error("Padding received when not negotiated with given hop")]
415
    NoPaddingNegotiated,
416
    /// We received more padding than our negotiated framework permits.
417
    #[error("Received padding in excess of negotiated framework's limit")]
418
    PaddingExceedsLimit,
419
}