1
//! Types to implement the SOCKS handshake.
2

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

            
7
use tor_bytes::{EncodeResult, Error as BytesError};
8
use tor_bytes::{Reader, Writer};
9
use tor_error::internal;
10

            
11
use derive_deftly::Deftly;
12

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

            
15
/// The Proxy (responder) side of an ongoing SOCKS handshake.
16
///
17
/// Create you have one of these with [`SocksProxyHandshake::new()`],
18
/// and then use [`Handshake::step`](crate::Handshake::step) to drive it.
19
///
20
/// Eventually you will hopefully obtain a [`SocksRequest`],
21
/// on which you should call [`.reply()`](SocksRequest::reply),
22
/// and send the resulting data to the peer.
23
#[derive(Clone, Debug, Deftly)]
24
#[derive_deftly(Handshake)]
25
pub struct SocksProxyHandshake {
26
    /// Current state of the handshake. Each completed message
27
    /// advances the state.
28
    state: State,
29
    /// SOCKS5 authentication that has been received (but not yet put
30
    /// in a SocksRequest object.)
31
    socks5_auth: Option<SocksAuth>,
32
    /// Completed SOCKS handshake.
33
    #[deftly(handshake(output))]
34
    handshake: Option<SocksRequest>,
35
}
36

            
37
/// Possible state for a Socks connection.
38
///
39
/// Each completed message advances the state.
40
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
41
enum State {
42
    /// Starting state: no messages have been handled yet.
43
    Initial,
44
    /// SOCKS5: we've negotiated Username/Password authentication, and
45
    /// are waiting for the client to send it.
46
    Socks5Username,
47
    /// SOCKS5: we've finished the authentication (if any), and
48
    /// we're waiting for the actual request.
49
    Socks5Wait,
50
    /// Ending (successful) state: the client has sent all its messages.
51
    ///
52
    /// (Note that we still need to send a reply.)
53
    Done,
54
    /// Ending (failed) state: the handshake has failed and cannot continue.
55
    Failed,
56
}
57

            
58
impl HandshakeImpl for SocksProxyHandshake {
59
962
    fn handshake_impl(&mut self, input: &mut Reader<'_>) -> Result<ImplNextStep> {
60
962
        match (self.state, input.peek(1)?[0]) {
61
362
            (State::Initial, 4) => self.s4(input),
62
76
            (State::Initial, 5) => self.s5_initial(input),
63
4
            (State::Initial, v) => Err(Error::BadProtocol(v)),
64
80
            (State::Socks5Username, 1) => self.s5_uname(input),
65
320
            (State::Socks5Wait, 5) => self.s5(input),
66
2
            (State::Done, _) => Err(Error::AlreadyFinished(internal!(
67
2
                "called handshake() after handshaking was done"
68
2
            ))),
69
2
            (State::Failed, _) => Err(Error::AlreadyFinished(internal!(
70
2
                "called handshake() after handshaking failed"
71
2
            ))),
72
2
            (_, _) => Err(Error::Syntax),
73
        }
74
962
    }
75
}
76

            
77
impl SocksProxyHandshake {
78
    /// Construct a new SocksProxyHandshake in its initial state
79
70
    pub fn new() -> Self {
80
70
        SocksProxyHandshake {
81
70
            state: State::Initial,
82
70
            socks5_auth: None,
83
70
            handshake: None,
84
70
        }
85
70
    }
86

            
87
    /// Complete a socks4 or socks4a handshake.
88
362
    fn s4(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
89
362
        let version = r.take_u8()?.try_into()?;
90
362
        if version != SocksVersion::V4 {
91
            return Err(internal!("called s4 on wrong type {:?}", version).into());
92
362
        }
93

            
94
362
        let cmd: SocksCmd = r.take_u8()?.into();
95
346
        let port = r.take_u16()?;
96
318
        let ip = r.take_u32()?;
97
266
        let username: Vec<u8> = r.take_until(0)?.into();
98
178
        let auth = if username.is_empty() {
99
166
            SocksAuth::NoAuth
100
        } else {
101
12
            SocksAuth::Socks4(username)
102
        };
103

            
104
178
        let addr = if ip != 0 && (ip >> 8) == 0 {
105
            // Socks4a; a hostname is given.
106
164
            let hostname = r.take_until(0)?;
107
12
            let hostname = std::str::from_utf8(hostname)
108
12
                .map_err(|_| Error::Syntax)?
109
12
                .to_string();
110
12
            let hostname = hostname
111
12
                .try_into()
112
12
                .map_err(|_| BytesError::InvalidMessage("hostname too long".into()))?;
113
12
            SocksAddr::Hostname(hostname)
114
        } else {
115
14
            let ip4: std::net::Ipv4Addr = ip.into();
116
14
            SocksAddr::Ip(ip4.into())
117
        };
118

            
119
26
        let request = SocksRequest::new(version, cmd, addr, port, auth)?;
120

            
121
26
        self.state = State::Done;
122
26
        self.handshake = Some(request);
123

            
124
26
        Ok(ImplNextStep::Finished)
125
362
    }
126

            
127
    /// Socks5: initial handshake to negotiate authentication method.
128
76
    fn s5_initial(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
129
        use super::{NO_AUTHENTICATION, USERNAME_PASSWORD};
130
76
        let version: SocksVersion = r.take_u8()?.try_into()?;
131
76
        if version != SocksVersion::V5 {
132
            return Err(internal!("called on wrong handshake type {:?}", version).into());
133
76
        }
134

            
135
76
        let nmethods = r.take_u8()?;
136
60
        let methods = r.take(nmethods as usize)?;
137

            
138
        // Prefer username/password, then none.
139
38
        let (next, reply) = if methods.contains(&USERNAME_PASSWORD) {
140
14
            (State::Socks5Username, [5, USERNAME_PASSWORD])
141
24
        } else if methods.contains(&NO_AUTHENTICATION) {
142
22
            self.socks5_auth = Some(SocksAuth::NoAuth);
143
22
            (State::Socks5Wait, [5, NO_AUTHENTICATION])
144
        } else {
145
            // In theory we should reply with "NO ACCEPTABLE METHODS".
146
2
            return Err(Error::NotImplemented("authentication methods".into()));
147
        };
148

            
149
36
        self.state = next;
150
36
        Ok(ImplNextStep::Reply {
151
36
            reply: reply.into(),
152
36
        })
153
76
    }
154

            
155
    /// Socks5: second step for username/password authentication.
156
80
    fn s5_uname(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
157
80
        let ver = r.take_u8()?;
158
80
        if ver != 1 {
159
            return Err(Error::NotImplemented(
160
                format!("username/password version {}", ver).into(),
161
            ));
162
80
        }
163

            
164
80
        let ulen = r.take_u8()?;
165
72
        let username = r.take(ulen as usize)?;
166
40
        let plen = r.take_u8()?;
167
32
        let passwd = r.take(plen as usize)?;
168

            
169
12
        self.socks5_auth = Some(SocksAuth::Username(username.into(), passwd.into()));
170
12
        self.state = State::Socks5Wait;
171
12
        Ok(ImplNextStep::Reply { reply: vec![1, 0] })
172
80
    }
173

            
174
    /// Socks5: final step, to receive client's request.
175
320
    fn s5(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
176
320
        let version: SocksVersion = r.take_u8()?.try_into()?;
177
320
        if version != SocksVersion::V5 {
178
            return Err(
179
                internal!("called s5 on non socks5 handshake with type {:?}", version).into(),
180
            );
181
320
        }
182
320
        let cmd = r.take_u8()?.into();
183
304
        let _ignore = r.take_u8()?;
184
288
        let addr = r.extract()?;
185
56
        let port = r.take_u16()?;
186

            
187
28
        let auth = self
188
28
            .socks5_auth
189
28
            .take()
190
28
            .ok_or_else(|| internal!("called s5 without negotiating auth"))?;
191

            
192
28
        let request = SocksRequest::new(version, cmd, addr, port, auth)?;
193

            
194
28
        self.state = State::Done;
195
28
        self.handshake = Some(request);
196

            
197
28
        Ok(ImplNextStep::Finished)
198
320
    }
199

            
200
    /// Return true if this handshake is finished.
201
4
    pub fn finished(&self) -> bool {
202
4
        self.state == State::Done
203
4
    }
204

            
205
    /// Consume this handshake's state; if it finished successfully,
206
    /// return a SocksRequest.
207
20
    pub fn into_request(self) -> Option<SocksRequest> {
208
20
        self.handshake
209
20
    }
210
}
211

            
212
impl Default for SocksProxyHandshake {
213
2
    fn default() -> Self {
214
2
        Self::new()
215
2
    }
216
}
217

            
218
impl SocksRequest {
219
    /// Format a reply to this request, indicating success or failure.
220
    ///
221
    /// Note that an address should be provided only when the request
222
    /// was for a RESOLVE.
223
52
    pub fn reply(&self, status: SocksStatus, addr: Option<&SocksAddr>) -> EncodeResult<Vec<u8>> {
224
52
        match self.version() {
225
24
            SocksVersion::V4 => self.s4(status, addr),
226
28
            SocksVersion::V5 => self.s5(status, addr),
227
        }
228
52
    }
229

            
230
    /// Format a SOCKS4 reply.
231
24
    fn s4(&self, status: SocksStatus, addr: Option<&SocksAddr>) -> EncodeResult<Vec<u8>> {
232
24
        let mut w = Vec::new();
233
24
        w.write_u8(0);
234
24
        w.write_u8(status.into_socks4_status());
235
2
        match addr {
236
2
            Some(SocksAddr::Ip(IpAddr::V4(ip))) => {
237
2
                w.write_u16(self.port());
238
2
                w.write(ip)?;
239
            }
240
22
            _ => {
241
22
                w.write_u16(0);
242
22
                w.write_u32(0);
243
22
            }
244
        }
245
24
        Ok(w)
246
24
    }
247

            
248
    /// Format a SOCKS5 reply.
249
28
    fn s5(&self, status: SocksStatus, addr: Option<&SocksAddr>) -> EncodeResult<Vec<u8>> {
250
28
        let mut w = Vec::new();
251
28
        w.write_u8(5);
252
28
        w.write_u8(status.into());
253
28
        w.write_u8(0); // reserved.
254
28
        if let Some(a) = addr {
255
4
            w.write(a)?;
256
4
            w.write_u16(self.port());
257
        } else {
258
            // When no address is given in the reply, we send back an UNSPECIFIED address.
259
            // We try to match the _requested_ address family, if it's an IP family.
260
            //
261
            // (Tor doesn't need to support SOCKS BIND; if we wanted to support that,
262
            // we'd provide the address in the `addr` argument.)
263
24
            match self.addr() {
264
                SocksAddr::Ip(IpAddr::V6(_)) => {
265
12
                    w.write(&SocksAddr::Ip(Ipv6Addr::UNSPECIFIED.into()))?;
266
                }
267
                SocksAddr::Ip(IpAddr::V4(_)) | SocksAddr::Hostname(_) => {
268
12
                    w.write(&SocksAddr::Ip(Ipv4Addr::UNSPECIFIED.into()))?;
269
                }
270
            }
271
24
            w.write_u16(0);
272
        }
273
28
        Ok(w)
274
28
    }
275
}
276

            
277
#[cfg(test)]
278
mod test {
279
    // @@ begin test lint list maintained by maint/add_warning @@
280
    #![allow(clippy::bool_assert_comparison)]
281
    #![allow(clippy::clone_on_copy)]
282
    #![allow(clippy::dbg_macro)]
283
    #![allow(clippy::mixed_attributes_style)]
284
    #![allow(clippy::print_stderr)]
285
    #![allow(clippy::print_stdout)]
286
    #![allow(clippy::single_char_pattern)]
287
    #![allow(clippy::unwrap_used)]
288
    #![allow(clippy::unchecked_time_subtraction)]
289
    #![allow(clippy::useless_vec)]
290
    #![allow(clippy::needless_pass_by_value)]
291
    #![allow(clippy::string_slice)] // See arti#2571
292
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
293
    use super::*;
294
    use crate::{Handshake as _, Truncated};
295
    use hex_literal::hex;
296

            
297
    #[test]
298
    fn socks4_good() {
299
        let mut h = SocksProxyHandshake::default();
300
        let a = h
301
            .handshake_for_tests(&hex!("04 01 0050 CB007107 00")[..])
302
            .unwrap()
303
            .unwrap();
304
        assert!(a.finished);
305
        assert!(h.finished());
306
        assert_eq!(a.drain, 9);
307
        assert!(a.reply.is_empty()); // no reply -- waiting to see how it goes
308

            
309
        let req = h.into_request().unwrap();
310
        assert_eq!(req.port(), 80);
311
        assert_eq!(req.addr().to_string(), "203.0.113.7");
312
        assert_eq!(req.command(), SocksCmd::CONNECT);
313

            
314
        assert_eq!(
315
            req.reply(
316
                SocksStatus::GENERAL_FAILURE,
317
                Some(&SocksAddr::Ip("127.0.0.1".parse().unwrap()))
318
            )
319
            .unwrap(),
320
            hex!("00 5B 0050 7f000001")
321
        );
322
    }
323

            
324
    #[test]
325
    fn socks4a_good() {
326
        let mut h = SocksProxyHandshake::new();
327
        let msg = hex!(
328
            "04 01 01BB 00000001 73776f72646669736800
329
                        7777772e6578616d706c652e636f6d00 99"
330
        );
331
        let a = h.handshake_for_tests(&msg[..]).unwrap().unwrap();
332
        assert!(a.finished);
333
        assert!(h.finished());
334
        assert_eq!(a.drain, msg.len() - 1);
335
        assert!(a.reply.is_empty()); // no reply -- waiting to see how it goes
336

            
337
        let req = h.into_request().unwrap();
338
        assert_eq!(req.port(), 443);
339
        assert_eq!(req.addr().to_string(), "www.example.com");
340
        assert_eq!(req.auth(), &SocksAuth::Socks4(b"swordfish".to_vec()));
341
        assert_eq!(req.command(), SocksCmd::CONNECT);
342

            
343
        assert_eq!(
344
            req.reply(SocksStatus::SUCCEEDED, None).unwrap(),
345
            hex!("00 5A 0000 00000000")
346
        );
347
    }
348

            
349
    #[test]
350
    fn socks5_init_noauth() {
351
        let mut h = SocksProxyHandshake::new();
352
        let a = h
353
            .handshake_for_tests(&hex!("05 01 00")[..])
354
            .unwrap()
355
            .unwrap();
356
        assert!(!a.finished);
357
        assert_eq!(a.drain, 3);
358
        assert_eq!(a.reply, &[5, 0]);
359
        assert_eq!(h.state, State::Socks5Wait);
360
    }
361

            
362
    #[test]
363
    fn socks5_init_username() {
364
        let mut h = SocksProxyHandshake::new();
365
        let a = h
366
            .handshake_for_tests(&hex!("05 04 00023031")[..])
367
            .unwrap()
368
            .unwrap();
369
        assert!(!a.finished);
370
        assert_eq!(a.drain, 6);
371
        assert_eq!(a.reply, &[5, 2]);
372
        assert_eq!(h.state, State::Socks5Username);
373
    }
374

            
375
    #[test]
376
    fn socks5_init_nothing_works() {
377
        let mut h = SocksProxyHandshake::new();
378
        let a = h.handshake_for_tests(&hex!("05 02 9988")[..]);
379
        assert!(matches!(a, Ok(Err(Error::NotImplemented(_)))));
380
    }
381

            
382
    #[test]
383
    fn socks5_username_ok() {
384
        let mut h = SocksProxyHandshake::new();
385
        let _a = h.handshake_for_tests(&hex!("05 02 9902")).unwrap().unwrap();
386
        let a = h
387
            .handshake_for_tests(&hex!("01 08 5761677374616666 09 24776f726466693568"))
388
            .unwrap()
389
            .unwrap();
390
        assert_eq!(a.drain, 20);
391
        assert_eq!(a.reply, &[1, 0]);
392
        assert_eq!(h.state, State::Socks5Wait);
393
        assert_eq!(
394
            h.socks5_auth.unwrap(),
395
            // _Horse Feathers_, 1932
396
            SocksAuth::Username(b"Wagstaff".to_vec(), b"$wordfi5h".to_vec())
397
        );
398
    }
399

            
400
    #[test]
401
    fn socks5_request_ok_ipv4() {
402
        let mut h = SocksProxyHandshake::new();
403
        let _a = h.handshake_for_tests(&hex!("05 01 00")).unwrap().unwrap();
404
        let a = h
405
            .handshake_for_tests(&hex!("05 01 00 01 7f000007 1f90"))
406
            .unwrap()
407
            .unwrap();
408
        assert_eq!(a.drain, 10);
409
        assert!(a.finished);
410
        assert!(a.reply.is_empty());
411
        assert_eq!(h.state, State::Done);
412

            
413
        let req = h.into_request().unwrap();
414
        assert_eq!(req.version(), SocksVersion::V5);
415
        assert_eq!(req.command(), SocksCmd::CONNECT);
416
        assert_eq!(req.addr().to_string(), "127.0.0.7");
417
        assert_eq!(req.port(), 8080);
418
        assert_eq!(req.auth(), &SocksAuth::NoAuth);
419

            
420
        assert_eq!(
421
            req.reply(
422
                SocksStatus::HOST_UNREACHABLE,
423
                Some(&SocksAddr::Hostname(
424
                    "foo.example.com".to_string().try_into().unwrap()
425
                ))
426
            )
427
            .unwrap(),
428
            hex!("05 04 00 03 0f 666f6f2e6578616d706c652e636f6d 1f90")
429
        );
430
    }
431

            
432
    #[test]
433
    fn socks5_request_ok_ipv6() {
434
        let mut h = SocksProxyHandshake::new();
435
        let _a = h.handshake_for_tests(&hex!("05 01 00")).unwrap().unwrap();
436
        let a = h
437
            .handshake_for_tests(&hex!(
438
                "05 01 00 04 f000 0000 0000 0000 0000 0000 0000 ff11 1f90"
439
            ))
440
            .unwrap()
441
            .unwrap();
442
        assert_eq!(a.drain, 22);
443
        assert!(a.finished);
444
        assert!(a.reply.is_empty());
445
        assert_eq!(h.state, State::Done);
446

            
447
        let req = h.into_request().unwrap();
448
        assert_eq!(req.version(), SocksVersion::V5);
449
        assert_eq!(req.command(), SocksCmd::CONNECT);
450
        assert_eq!(req.addr().to_string(), "f000::ff11");
451
        assert_eq!(req.port(), 8080);
452
        assert_eq!(req.auth(), &SocksAuth::NoAuth);
453

            
454
        assert_eq!(
455
            req.reply(SocksStatus::GENERAL_FAILURE, Some(req.addr()))
456
                .unwrap(),
457
            hex!("05 01 00 04 f000 0000 0000 0000 0000 0000 0000 ff11 1f90")
458
        );
459
    }
460

            
461
    #[test]
462
    fn socks5_request_ok_hostname() {
463
        let mut h = SocksProxyHandshake::new();
464
        let _a = h.handshake_for_tests(&hex!("05 01 00")).unwrap().unwrap();
465
        let a = h
466
            .handshake_for_tests(&hex!("05 01 00 03 0f 666f6f2e6578616d706c652e636f6d 1f90"))
467
            .unwrap()
468
            .unwrap();
469
        assert_eq!(a.drain, 22);
470
        assert!(a.finished);
471
        assert!(a.reply.is_empty());
472
        assert_eq!(h.state, State::Done);
473

            
474
        let req = h.into_request().unwrap();
475
        assert_eq!(req.version(), SocksVersion::V5);
476
        assert_eq!(req.command(), SocksCmd::CONNECT);
477
        assert_eq!(req.addr().to_string(), "foo.example.com");
478
        assert_eq!(req.port(), 8080);
479
        assert_eq!(req.auth(), &SocksAuth::NoAuth);
480

            
481
        assert_eq!(
482
            req.reply(SocksStatus::SUCCEEDED, None).unwrap(),
483
            hex!("05 00 00 01 00000000 0000")
484
        );
485
    }
486

            
487
    #[test]
488
    fn socks5_request_ok_ipv6_addr_none() {
489
        // socks5 request using IPv6 address type and addr is none
490
        let mut h = SocksProxyHandshake::new();
491
        let _a = h.handshake_for_tests(&hex!("05 01 00")).unwrap().unwrap();
492
        // handshake for tests-> Result<Option<HandshakeResult>>
493
        let a = h
494
            .handshake_for_tests(&hex!(
495
                "05 01 00 04 f000 0000 0000 0000 0000 0000 0000 ff11 1f90"
496
            ))
497
            .unwrap()
498
            .unwrap();
499

            
500
        assert_eq!(a.drain, 22);
501
        assert!(a.finished);
502
        assert!(a.reply.is_empty());
503
        assert_eq!(h.state, State::Done);
504

            
505
        let req = h.into_request().unwrap();
506
        assert_eq!(req.version(), SocksVersion::V5);
507
        assert_eq!(req.command(), SocksCmd::CONNECT);
508
        assert_eq!(req.addr().to_string(), "f000::ff11");
509
        assert_eq!(req.port(), 8080);
510
        assert_eq!(req.auth(), &SocksAuth::NoAuth);
511

            
512
        assert_eq!(
513
            req.reply(SocksStatus::GENERAL_FAILURE, None).unwrap(),
514
            hex!("05 01 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00")
515
        );
516
    }
517

            
518
    #[test]
519
    fn empty_handshake() {
520
        let r = SocksProxyHandshake::new().handshake_for_tests(&[]);
521
        assert!(matches!(r, Err(Truncated { .. })));
522
    }
523

            
524
    #[test]
525
    fn bad_version() {
526
        let mut h = SocksProxyHandshake::new();
527
        let r = h.handshake_for_tests(&hex!("06 01 00"));
528
        assert!(matches!(r, Ok(Err(Error::BadProtocol(6)))));
529

            
530
        let mut h = SocksProxyHandshake::new();
531
        let _a = h.handshake_for_tests(&hex!("05 01 00")).unwrap();
532
        let r = h.handshake_for_tests(&hex!("06 01 00"));
533
        assert!(r.unwrap().is_err());
534
    }
535

            
536
    #[test]
537
    fn fused_result() {
538
        let good_socks4a = &hex!("04 01 0050 CB007107 00")[..];
539

            
540
        // Can't try again after failure.
541
        let mut h = SocksProxyHandshake::new();
542
        let r = h.handshake_for_tests(&hex!("06 01 00"));
543
        assert!(r.unwrap().is_err());
544
        let r = h.handshake_for_tests(good_socks4a);
545
        assert!(matches!(r, Ok(Err(Error::AlreadyFinished(_)))));
546

            
547
        // Can't try again after success
548
        let mut h = SocksProxyHandshake::new();
549
        let r = h.handshake_for_tests(good_socks4a);
550
        assert!(r.is_ok());
551
        let r = h.handshake_for_tests(good_socks4a);
552
        assert!(matches!(r, Ok(Err(Error::AlreadyFinished(_)))));
553
    }
554
}