1
//! Define an error type for the tor-proto crate.
2
use std::sync::Arc;
3
use thiserror::Error;
4
use tor_cell::relaycell::msg::EndReason;
5
use tor_error::{ErrorKind, HasKind};
6

            
7
/// An error type for the tor-proto crate.
8
///
9
/// This type should probably be split into several.  There's more
10
/// than one kind of error that can occur while doing something with
11
/// the Tor protocol.
12
63
#[derive(Error, Debug, Clone)]
13
#[non_exhaustive]
14
pub enum Error {
15
    /// An error that occurred in the tor_bytes crate while decoding an
16
    /// object.
17
    #[error("parsing error: {0}")]
18
    BytesErr(#[from] tor_bytes::Error),
19
    /// An error that occurred from the io system when using a
20
    /// channel.
21
    #[error("io error on channel: {0}")]
22
    ChanIoErr(#[source] Arc<std::io::Error>),
23
    /// An error from the io system that occurred when trying to connect a channel.
24
    #[error("io error in handshake: {0}")]
25
    HandshakeIoErr(#[source] Arc<std::io::Error>),
26
    /// An error occurred in the cell-handling layer.
27
    #[error("cell encoding error: {0}")]
28
    CellErr(#[source] tor_cell::Error),
29
    /// We tried to produce too much output for some function.
30
    #[error("couldn't produce that much output")]
31
    InvalidOutputLength,
32
    /// We tried to encrypt a message to a hop that wasn't there.
33
    #[error("tried to encrypt to nonexistent hop")]
34
    NoSuchHop,
35
    /// The authentication information on this cell was completely wrong,
36
    /// or the cell was corrupted.
37
    #[error("bad relay cell authentication")]
38
    BadCellAuth,
39
    /// A circuit-extension handshake failed.
40
    #[error("handshake failed")]
41
    BadCircHandshake,
42
    /// Handshake protocol violation.
43
    #[error("handshake protocol violation: {0}")]
44
    HandshakeProto(String),
45
    /// Protocol violation at the channel level, other than at the handshake
46
    /// stage.
47
    #[error("channel protocol violation: {0}")]
48
    ChanProto(String),
49
    /// Protocol violation at the circuit level
50
    #[error("circuit protocol violation: {0}")]
51
    CircProto(String),
52
    /// Channel is closed.
53
    #[error("channel closed")]
54
    ChannelClosed,
55
    /// Circuit is closed.
56
    #[error("circuit closed")]
57
    CircuitClosed,
58
    /// Can't allocate any more circuit or stream IDs on a channel.
59
    #[error("too many entries in map: can't allocate ID")]
60
    IdRangeFull,
61
    /// Couldn't extend a circuit because the extending relay or the
62
    /// target relay refused our request.
63
    #[error("circuit extension handshake error: {0}")]
64
    CircRefused(&'static str),
65
    /// Tried to make or use a stream to an invalid destination address.
66
    #[error("invalid stream target address")]
67
    BadStreamAddress,
68
    /// Received an End cell from the other end of a stream.
69
    #[error("Received an End cell with reason {0}")]
70
    EndReceived(EndReason),
71
    /// Stream was already closed when we tried to use it.
72
    #[error("stream not connected")]
73
    NotConnected,
74
    /// Stream protocol violation
75
    #[error("stream protocol violation: {0}")]
76
    StreamProto(String),
77

            
78
    /// Channel does not match target
79
    #[error("channel mismatch: {0}")]
80
    ChanMismatch(String),
81
    /// There was a programming error somewhere in our code, or the calling code.
82
    #[error("Programming error: {0}")]
83
    Bug(#[from] tor_error::Bug),
84
    /// Remote DNS lookup failed.
85
    #[error("remote resolve failed: {0}")]
86
    ResolveError(String),
87
}
88

            
89
impl From<tor_cell::Error> for Error {
90
19
    fn from(err: tor_cell::Error) -> Error {
91
19
        match err {
92
19
            tor_cell::Error::ChanProto(msg) => Error::ChanProto(msg),
93
            _ => Error::CellErr(err),
94
        }
95
19
    }
96
}
97

            
98
impl From<Error> for std::io::Error {
99
    fn from(err: Error) -> std::io::Error {
100
        use std::io::ErrorKind;
101
        use Error::*;
102
        let kind = match err {
103
            ChanIoErr(e) | HandshakeIoErr(e) => match Arc::try_unwrap(e) {
104
                Ok(e) => return e,
105
                Err(arc) => return std::io::Error::new(arc.kind(), arc),
106
            },
107

            
108
            InvalidOutputLength | NoSuchHop | BadStreamAddress => ErrorKind::InvalidInput,
109

            
110
            NotConnected => ErrorKind::NotConnected,
111

            
112
            EndReceived(end_reason) => end_reason.into(),
113

            
114
            ChannelClosed | CircuitClosed => ErrorKind::ConnectionReset,
115

            
116
            BytesErr(_) | BadCellAuth | BadCircHandshake | HandshakeProto(_) | ChanProto(_)
117
            | CircProto(_) | CellErr(_) | ChanMismatch(_) | StreamProto(_) => {
118
                ErrorKind::InvalidData
119
            }
120

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

            
123
            IdRangeFull | CircRefused(_) | ResolveError(_) | Bug(_) => ErrorKind::Other,
124
        };
125
        std::io::Error::new(kind, err)
126
    }
127
}
128

            
129
impl HasKind for Error {
130
    fn kind(&self) -> ErrorKind {
131
        use tor_bytes::Error as BytesError;
132
        use Error as E;
133
        use ErrorKind as EK;
134
        match self {
135
            E::BytesErr(BytesError::Bug(e)) => e.kind(),
136
            E::BytesErr(_) => EK::TorProtocolViolation,
137
            E::ChanIoErr(_) => EK::LocalNetworkError,
138
            E::HandshakeIoErr(_) => EK::TorAccessFailed,
139
            E::CellErr(e) => e.kind(),
140
            E::InvalidOutputLength => EK::Internal,
141
            E::NoSuchHop => EK::BadApiUsage,
142
            E::BadCellAuth => EK::TorProtocolViolation,
143
            E::BadCircHandshake => EK::TorProtocolViolation,
144
            E::HandshakeProto(_) => EK::TorAccessFailed,
145
            E::ChanProto(_) => EK::TorProtocolViolation,
146
            E::CircProto(_) => EK::TorProtocolViolation,
147
            E::ChannelClosed | E::CircuitClosed => EK::CircuitCollapse,
148
            E::IdRangeFull => EK::BadApiUsage,
149
            E::CircRefused(_) => EK::CircuitRefused,
150
            E::BadStreamAddress => EK::BadApiUsage,
151
            E::EndReceived(reason) => reason.kind(),
152
            E::NotConnected => EK::BadApiUsage,
153
            E::StreamProto(_) => EK::TorProtocolViolation,
154
            E::ChanMismatch(_) => EK::RelayIdMismatch,
155
            E::ResolveError(_) => EK::RemoteHostNotFound,
156
            E::Bug(e) => e.kind(),
157
        }
158
    }
159
}
160

            
161
/// Internal type: Error return value from reactor's run_once
162
/// function: indicates an error or a shutdown.
163
#[derive(Debug)]
164
pub(crate) enum ReactorError {
165
    /// The reactor should shut down with an abnormal exit condition.
166
    Err(Error),
167
    /// The reactor should shut down without an error, since all is well.
168
    Shutdown,
169
}
170
impl From<Error> for ReactorError {
171
63
    fn from(e: Error) -> ReactorError {
172
63
        ReactorError::Err(e)
173
63
    }
174
}
175
#[cfg(test)]
176
impl ReactorError {
177
    /// Tests only: assert that this is an Error, and return it.
178
36
    pub(crate) fn unwrap_err(self) -> Error {
179
36
        match self {
180
            ReactorError::Shutdown => panic!(),
181
36
            ReactorError::Err(e) => e,
182
36
        }
183
36
    }
184
}