1
//! Implementation for a SOCKS client handshake.
2

            
3
use super::framework::{HandshakeImpl, ImplNextStep};
4
use super::{NO_AUTHENTICATION, USERNAME_PASSWORD};
5
use crate::msg::{SocksAddr, SocksAuth, SocksReply, SocksRequest, SocksStatus, SocksVersion};
6
use crate::{Error, Result};
7

            
8
use tor_bytes::{Reader, Writer};
9
use tor_error::{internal, into_internal};
10

            
11
use derive_deftly::Deftly;
12

            
13
use std::net::{IpAddr, Ipv4Addr};
14

            
15
/// The client (initiator) side of a SOCKS handshake.
16
///
17
/// Create you have one of these with [`SocksClientHandshake::new()`],
18
/// and then use [`Handshake::step`](crate::Handshake::step) to drive it.
19
#[derive(Clone, Debug, Deftly)]
20
#[derive_deftly(Handshake)]
21
pub struct SocksClientHandshake {
22
    /// The request that we are currently trying to negotiate with the proxy.
23
    request: SocksRequest,
24
    /// Our current state in negotiating that request.
25
    state: State,
26
    /// If present, the return message that we received from the proxy.
27
    #[deftly(handshake(output))]
28
    reply: Option<SocksReply>,
29
}
30

            
31
/// An internal state for a `SocksClientHandshake`.
32
#[derive(Clone, Debug)]
33
enum State {
34
    /// We have sent nothing yet.
35
    Initial,
36
    /// We have sent a SOCKS4 request, and are waiting for a response.
37
    Socks4Wait,
38
    /// We have sent a SOCKS5 init message, and are waiting to hear what kind
39
    /// of authentication to use.
40
    Socks5AuthWait,
41
    /// We have sent a SOCKS5 username/password, and are waiting to hear whether
42
    /// it's accepted.
43
    Socks5UsernameWait,
44
    /// We have sent a SOCKS5 request, and are waiting for a response.
45
    Socks5Wait,
46
    /// We have received the final reply from the proxy.  This reply may be
47
    /// successful or unsuccessful, depending on the value of
48
    /// `SocksClientHandshake::status`.
49
    Done,
50
    /// The handshake has failed and no further progress can be made.
51
    Failed,
52
}
53

            
54
impl HandshakeImpl for SocksClientHandshake {
55
1064
    fn handshake_impl(&mut self, input: &mut Reader<'_>) -> Result<ImplNextStep> {
56
        use State::*;
57
1064
        match self.state {
58
48
            Initial => match self.request.version() {
59
24
                SocksVersion::V4 => self.send_v4(),
60
24
                SocksVersion::V5 => self.send_v5_initial(),
61
            },
62
420
            Socks4Wait => self.handle_v4(input),
63
104
            Socks5AuthWait => self.handle_v5_auth(input),
64
86
            Socks5UsernameWait => self.handle_v5_username_ack(input),
65
406
            Socks5Wait => self.handle_v5_final(input),
66
            Done => Err(Error::AlreadyFinished(internal!(
67
                "called handshake() after handshaking succeeded"
68
            ))),
69
            Failed => Err(Error::AlreadyFinished(internal!(
70
                "called handshake() after handshaking failed"
71
            ))),
72
        }
73
1064
    }
74
}
75

            
76
impl SocksClientHandshake {
77
    /// Construct a new [`SocksClientHandshake`] that will attempt to negotiate
78
    /// with a peer using `request`.
79
48
    pub fn new(request: SocksRequest) -> Self {
80
48
        SocksClientHandshake {
81
48
            request,
82
48
            state: State::Initial,
83
48
            reply: None,
84
48
        }
85
48
    }
86

            
87
    /// Consume this handshake's state; if it finished successfully,
88
    /// return the [`SocksReply`] that we got from the proxy..
89
16
    pub fn into_reply(self) -> Option<SocksReply> {
90
16
        self.reply
91
16
    }
92

            
93
    /// Send the client side of the socks 4 handshake.
94
24
    fn send_v4(&mut self) -> Result<ImplNextStep> {
95
24
        let mut msg = Vec::new();
96

            
97
24
        msg.write_u8(4);
98
24
        msg.write_u8(self.request.command().into());
99
24
        msg.write_u16(self.request.port());
100

            
101
24
        let use_v4a = match self.request.addr() {
102
12
            SocksAddr::Ip(IpAddr::V4(ipv4)) => {
103
12
                msg.write_u32((*ipv4).into());
104
12
                false
105
            }
106
            _ => {
107
12
                msg.write_u32(1);
108
12
                true
109
            }
110
        };
111

            
112
24
        match self.request.auth() {
113
12
            SocksAuth::NoAuth => msg.write_u8(0),
114
12
            SocksAuth::Socks4(s) => {
115
12
                msg.write_all(s);
116
12
                msg.write_u8(0);
117
12
            }
118
            SocksAuth::Username(_, _) => {
119
                return Err(internal!("tried to send socks5 auth over socks4.").into());
120
            }
121
        }
122

            
123
24
        if use_v4a {
124
12
            // We are using socks4a, so we need to send the address now.
125
12
            msg.write_all(self.request.addr().to_string().as_bytes());
126
12
            msg.write_u8(0);
127
12
        }
128

            
129
24
        self.state = State::Socks4Wait;
130
24
        Ok(ImplNextStep::Reply { reply: msg })
131
24
    }
132

            
133
    /// Handle a SOCKSv4 response.
134
420
    fn handle_v4(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
135
420
        let ver = r.take_u8()?;
136
120
        if ver != 0 {
137
            return Err(Error::Syntax);
138
120
        }
139
120
        let status = r.take_u8()?;
140
104
        let port = r.take_u16()?;
141
76
        let ip: Ipv4Addr = r.extract()?;
142

            
143
24
        self.state = State::Done;
144
24
        self.reply = Some(SocksReply::new(
145
24
            SocksStatus::from_socks4_status(status),
146
24
            SocksAddr::Ip(ip.into()),
147
24
            port,
148
24
        ));
149

            
150
24
        Ok(ImplNextStep::Finished)
151
420
    }
152

            
153
    /// Send our initial socks5 message (which negotiates our authentication methods).
154
24
    fn send_v5_initial(&mut self) -> Result<ImplNextStep> {
155
24
        let mut msg = Vec::new();
156
24
        msg.write_u8(5);
157
24
        match self.request.auth() {
158
12
            SocksAuth::NoAuth => {
159
12
                msg.write_u8(1); // 1 method.
160
12
                msg.write_u8(NO_AUTHENTICATION);
161
12
            }
162
            SocksAuth::Socks4(_) => return Err(internal!("Mismatched authentication type").into()),
163
12
            SocksAuth::Username(_, _) => {
164
12
                msg.write_u8(2); // 2 methods.
165
12
                msg.write_u8(USERNAME_PASSWORD);
166
12
                msg.write_u8(NO_AUTHENTICATION);
167
12
            }
168
        }
169

            
170
24
        self.state = State::Socks5AuthWait;
171
24
        Ok(ImplNextStep::Reply { reply: msg })
172
24
    }
173

            
174
    /// Try to handle a socks5 reply telling us what authentication method to
175
    /// use, and reply as appropriate.
176
104
    fn handle_v5_auth(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
177
104
        let ver = r.take_u8()?;
178
40
        if ver != 5 {
179
            return Err(Error::Syntax);
180
40
        }
181
40
        let auth = r.take_u8()?;
182
24
        let (msg, next_state) = match auth {
183
12
            USERNAME_PASSWORD => (self.generate_v5_username_auth()?, State::Socks5UsernameWait),
184
12
            NO_AUTHENTICATION => (self.generate_v5_command()?, State::Socks5Wait),
185
            other => {
186
                return Err(Error::NotImplemented(
187
                    format!("authentication type {}", other).into(),
188
                ));
189
            }
190
        };
191

            
192
24
        self.state = next_state;
193
24
        Ok(ImplNextStep::Reply { reply: msg })
194
104
    }
195

            
196
    /// Return a message to perform username/password authentication.
197
12
    fn generate_v5_username_auth(&self) -> Result<Vec<u8>> {
198
12
        if let SocksAuth::Username(username, pass) = self.request.auth() {
199
12
            let mut msg = Vec::new();
200

            
201
12
            msg.write_u8(1); // version
202
12
            let mut n = msg.write_nested_u8len();
203
12
            n.write_all(username);
204
12
            n.finish().map_err(into_internal!("id too long"))?;
205

            
206
12
            let mut n = msg.write_nested_u8len();
207
12
            n.write_all(pass);
208
12
            n.finish().map_err(into_internal!("password too long"))?;
209

            
210
12
            Ok(msg)
211
        } else {
212
            // Can't perform this authentication when it wasn't what we asked for.
213
            Err(Error::Syntax)
214
        }
215
12
    }
216

            
217
    /// Try to handle a reply from the socks5 proxy to acknowledge our
218
    /// username/password authentication, and reply as appropriate.
219
86
    fn handle_v5_username_ack(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
220
86
        let ver = r.take_u8()?;
221
20
        if ver != 1 {
222
            return Err(Error::Syntax);
223
20
        }
224
20
        let result = r.take_u8()?;
225
12
        if result != 0 {
226
            return Err(Error::AuthRejected);
227
12
        }
228

            
229
12
        self.state = State::Socks5Wait;
230
        Ok(ImplNextStep::Reply {
231
12
            reply: self.generate_v5_command()?,
232
        })
233
86
    }
234

            
235
    /// Return a message to encode our final socks5 request.
236
    ///
237
    /// (This can be done either in response getting an ACK for our
238
    /// authentication, or in response to being told that we don't need to
239
    /// authenticate.)
240
24
    fn generate_v5_command(&self) -> Result<Vec<u8>> {
241
24
        let mut msg = Vec::new();
242
24
        msg.write_u8(5); // version
243
24
        msg.write_u8(self.request.command().into());
244
24
        msg.write_u8(0); // reserved.
245
24
        msg.write(self.request.addr())
246
24
            .map_err(into_internal!("Can't encode address"))?;
247
24
        msg.write_u16(self.request.port());
248

            
249
24
        Ok(msg)
250
24
    }
251

            
252
    /// Handle a final socks5 reply.
253
406
    fn handle_v5_final(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
254
406
        let ver = r.take_u8()?;
255
152
        if ver != 5 {
256
            return Err(Error::Syntax);
257
152
        }
258
152
        let status: SocksStatus = r.take_u8()?.into();
259
136
        let _reserved = r.take_u8()?;
260
120
        let addr: SocksAddr = r.extract()?;
261
52
        let port = r.take_u16()?;
262

            
263
24
        self.state = State::Done;
264
24
        self.reply = Some(SocksReply::new(status, addr, port));
265
24
        Ok(ImplNextStep::Finished)
266
406
    }
267
}
268

            
269
#[cfg(test)]
270
mod test {
271
    // @@ begin test lint list maintained by maint/add_warning @@
272
    #![allow(clippy::bool_assert_comparison)]
273
    #![allow(clippy::clone_on_copy)]
274
    #![allow(clippy::dbg_macro)]
275
    #![allow(clippy::mixed_attributes_style)]
276
    #![allow(clippy::print_stderr)]
277
    #![allow(clippy::print_stdout)]
278
    #![allow(clippy::single_char_pattern)]
279
    #![allow(clippy::unwrap_used)]
280
    #![allow(clippy::unchecked_time_subtraction)]
281
    #![allow(clippy::useless_vec)]
282
    #![allow(clippy::needless_pass_by_value)]
283
    #![allow(clippy::string_slice)] // See arti#2571
284
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
285

            
286
    use super::*;
287
    use crate::{Handshake as _, msg::SocksCmd};
288
    use hex_literal::hex;
289

            
290
    #[test]
291
    fn socks4_ok() {
292
        let r = SocksRequest::new(
293
            SocksVersion::V4,
294
            SocksCmd::CONNECT,
295
            SocksAddr::Ip("192.0.2.15".parse().unwrap()),
296
            443,
297
            SocksAuth::NoAuth,
298
        )
299
        .unwrap();
300
        let mut hs = SocksClientHandshake::new(r);
301
        let action = hs.handshake_for_tests(&[]).unwrap().unwrap();
302
        assert_eq!(action.drain, 0);
303
        assert_eq!(action.reply, hex!("04 01 01BB C000020F 00"));
304
        assert_eq!(action.finished, false);
305

            
306
        let action = hs
307
            .handshake_for_tests(&hex!("00 5A 01BB C000020F"))
308
            .unwrap()
309
            .unwrap();
310
        assert_eq!(action.drain, 8);
311
        assert!(action.reply.is_empty());
312
        assert_eq!(action.finished, true);
313

            
314
        let reply = hs.into_reply().unwrap();
315
        assert_eq!(reply.status(), SocksStatus::SUCCEEDED);
316
        assert_eq!(reply.port(), 443);
317
        assert_eq!(reply.addr().to_string(), "192.0.2.15");
318
    }
319

            
320
    #[test]
321
    fn socks4a_ok() {
322
        let r = SocksRequest::new(
323
            SocksVersion::V4,
324
            SocksCmd::CONNECT,
325
            SocksAddr::Hostname("www.torproject.org".to_string().try_into().unwrap()),
326
            443,
327
            SocksAuth::Socks4(b"hello".to_vec()),
328
        )
329
        .unwrap();
330
        let mut hs = SocksClientHandshake::new(r);
331
        let action = hs.handshake_for_tests(&[]).unwrap().unwrap();
332
        assert_eq!(action.drain, 0);
333
        assert_eq!(
334
            action.reply,
335
            hex!("04 01 01BB 00000001 68656c6c6f00 7777772e746f7270726f6a6563742e6f726700")
336
        );
337
        assert_eq!(action.finished, false);
338

            
339
        let action = hs
340
            .handshake_for_tests(&hex!("00 5A 01BB C0000215"))
341
            .unwrap()
342
            .unwrap();
343
        assert_eq!(action.drain, 8);
344
        assert!(action.reply.is_empty());
345
        assert_eq!(action.finished, true);
346

            
347
        let reply = hs.into_reply().unwrap();
348
        assert_eq!(reply.status(), SocksStatus::SUCCEEDED);
349
        assert_eq!(reply.port(), 443);
350
        assert_eq!(reply.addr().to_string(), "192.0.2.21");
351
    }
352

            
353
    #[test]
354
    fn socks5_with_no_auth() {
355
        let r = SocksRequest::new(
356
            SocksVersion::V5,
357
            SocksCmd::CONNECT,
358
            SocksAddr::Hostname("www.torproject.org".to_string().try_into().unwrap()),
359
            443,
360
            SocksAuth::NoAuth,
361
        )
362
        .unwrap();
363

            
364
        // client begins by proposing authentication types.
365
        let mut hs = SocksClientHandshake::new(r);
366
        let action = hs.handshake_for_tests(&[]).unwrap().unwrap();
367
        assert_eq!(action.drain, 0);
368
        assert_eq!(action.reply, hex!("05 01 00"));
369
        assert_eq!(action.finished, false);
370

            
371
        // proxy chooses noauth; client replies with its handshake.
372
        let action = hs.handshake_for_tests(&hex!("0500")).unwrap().unwrap();
373
        assert_eq!(action.drain, 2);
374
        assert_eq!(
375
            action.reply,
376
            hex!("05 01 00 03 12 7777772e746f7270726f6a6563742e6f7267 01BB")
377
        );
378
        assert_eq!(action.finished, false);
379

            
380
        // Proxy says "okay, you're connected."
381
        // Client is done.
382
        let action = hs
383
            .handshake_for_tests(&hex!("05 00 00 01 C0000215 01BB"))
384
            .unwrap()
385
            .unwrap();
386
        assert_eq!(action.drain, 10);
387
        assert!(action.reply.is_empty());
388
        assert_eq!(action.finished, true);
389

            
390
        let reply = hs.into_reply().unwrap();
391
        assert_eq!(reply.status(), SocksStatus::SUCCEEDED);
392
        assert_eq!(reply.port(), 443);
393
        assert_eq!(reply.addr().to_string(), "192.0.2.21");
394
    }
395

            
396
    #[test]
397
    fn socks5_with_auth_ok() {
398
        let r = SocksRequest::new(
399
            SocksVersion::V5,
400
            SocksCmd::CONNECT,
401
            SocksAddr::Hostname("www.torproject.org".to_string().try_into().unwrap()),
402
            443,
403
            SocksAuth::Username(b"hello".to_vec(), b"world".to_vec()),
404
        )
405
        .unwrap();
406

            
407
        // client begins by proposing authentication types.
408
        let mut hs = SocksClientHandshake::new(r);
409
        let action = hs.handshake_for_tests(&[]).unwrap().unwrap();
410
        assert_eq!(action.drain, 0);
411
        assert_eq!(action.reply, hex!("05 02 0200"));
412
        assert_eq!(action.finished, false);
413

            
414
        // proxy chooses username/password; client replies with "hello"/"world"
415
        let action = hs.handshake_for_tests(&hex!("0502")).unwrap().unwrap();
416
        assert_eq!(action.drain, 2);
417
        assert_eq!(action.reply, hex!("01 05 68656c6c6f 05 776f726c64"));
418
        assert_eq!(action.finished, false);
419

            
420
        // Proxy says "yeah, that's good authentication, go ahead."
421
        // Client says what it actually wants.
422
        let action = hs.handshake_for_tests(&hex!("0100")).unwrap().unwrap();
423
        assert_eq!(action.drain, 2);
424
        assert_eq!(
425
            action.reply,
426
            hex!("05 01 00 03 12 7777772e746f7270726f6a6563742e6f7267 01BB")
427
        );
428
        assert_eq!(action.finished, false);
429

            
430
        // Proxy says "okay, you're connected."
431
        // Client is done.
432
        let action = hs
433
            .handshake_for_tests(&hex!("05 00 00 01 C0000215 01BB"))
434
            .unwrap()
435
            .unwrap();
436
        assert_eq!(action.drain, 10);
437
        assert!(action.reply.is_empty());
438
        assert_eq!(action.finished, true);
439

            
440
        let reply = hs.into_reply().unwrap();
441
        assert_eq!(reply.status(), SocksStatus::SUCCEEDED);
442
        assert_eq!(reply.port(), 443);
443
        assert_eq!(reply.addr().to_string(), "192.0.2.21");
444
    }
445
}