1
//! Define an error type for the tor-proto crate.
2

            
3
use futures::task::SpawnError;
4
use safelog::Sensitive;
5
use std::{sync::Arc, time::Duration};
6
use thiserror::Error;
7
use tor_cell::relaycell::{StreamId, msg::EndReason};
8
use tor_error::{Bug, ErrorKind, HasKind};
9
use tor_linkspec::RelayIdType;
10

            
11
use crate::HopNum;
12
use 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]
21
pub 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")]
215
pub struct ChannelClosed;
216

            
217
impl HasKind for ChannelClosed {
218
2
    fn kind(&self) -> ErrorKind {
219
2
        ErrorKind::CircuitCollapse
220
2
    }
221
}
222

            
223
/// Details about an error received while resolving a domain
224
#[derive(Error, Debug, Clone)]
225
#[non_exhaustive]
226
pub 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

            
238
impl 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
12
    pub(crate) fn from_bytes_err(err: tor_bytes::Error, object: &'static str) -> Error {
248
12
        Error::BytesErr { err, object }
249
12
    }
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

            
258
impl From<std::io::Error> for Error {
259
    fn from(err: std::io::Error) -> Self {
260
        Self::ChanIoErr(Arc::new(err))
261
    }
262
}
263

            
264
impl 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

            
321
impl HasKind for Error {
322
306
    fn kind(&self) -> ErrorKind {
323
        use Error as E;
324
        use ErrorKind as EK;
325
        use tor_bytes::Error as BytesError;
326
12
        match self {
327
            E::BytesErr {
328
                err: BytesError::Bug(e),
329
                ..
330
            } => e.kind(),
331
12
            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
164
            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
12
            E::BadCircHandshakeAuth => EK::TorProtocolViolation,
344
            E::HandshakeProto(_) => EK::TorAccessFailed,
345
            E::HandshakeCertsExpired { .. } => EK::ClockSkew,
346
12
            E::ChanProto(_) => EK::TorProtocolViolation,
347
96
            E::CircProto(_) => EK::TorProtocolViolation,
348
2
            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
4
            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
4
            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
306
    }
374
}
375

            
376
/// Internal type: Error return value from reactor's run_once
377
/// function: indicates an error or a shutdown.
378
#[derive(Debug)]
379
pub(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

            
386
impl From<Error> for ReactorError {
387
378
    fn from(e: Error) -> ReactorError {
388
378
        ReactorError::Err(e)
389
378
    }
390
}
391

            
392
impl From<ChannelClosed> for ReactorError {
393
    fn from(e: ChannelClosed) -> ReactorError {
394
        ReactorError::Err(e.into())
395
    }
396
}
397

            
398
impl From<Bug> for ReactorError {
399
    fn from(e: Bug) -> ReactorError {
400
        ReactorError::Err(e.into())
401
    }
402
}
403

            
404
#[cfg(test)]
405
impl ReactorError {
406
    /// Tests only: assert that this is an Error, and return it.
407
72
    pub(crate) fn unwrap_err(self) -> Error {
408
72
        match self {
409
            ReactorError::Shutdown => panic!(),
410
72
            ReactorError::Err(e) => e,
411
        }
412
72
    }
413
}
414

            
415
/// An error type for client-side conflux handshakes.
416
#[derive(Debug)]
417
#[cfg(feature = "conflux")]
418
#[allow(unused)] // TODO(conflux): remove
419
pub(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]
431
pub 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
}