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
481
    fn handshake_impl(&mut self, input: &mut Reader<'_>) -> Result<ImplNextStep> {
60
481
        match (self.state, input.peek(1)?[0]) {
61
181
            (State::Initial, 4) => self.s4(input),
62
38
            (State::Initial, 5) => self.s5_initial(input),
63
2
            (State::Initial, v) => Err(Error::BadProtocol(v)),
64
40
            (State::Socks5Username, 1) => self.s5_uname(input),
65
160
            (State::Socks5Wait, 5) => self.s5(input),
66
1
            (State::Done, _) => Err(Error::AlreadyFinished(internal!(
67
1
                "called handshake() after handshaking was done"
68
1
            ))),
69
1
            (State::Failed, _) => Err(Error::AlreadyFinished(internal!(
70
1
                "called handshake() after handshaking failed"
71
1
            ))),
72
1
            (_, _) => Err(Error::Syntax),
73
        }
74
481
    }
75
}
76

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

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

            
94
181
        let cmd: SocksCmd = r.take_u8()?.into();
95
173
        let port = r.take_u16()?;
96
159
        let ip = r.take_u32()?;
97
133
        let username: Vec<u8> = r.take_until(0)?.into();
98
89
        let auth = if username.is_empty() {
99
83
            SocksAuth::NoAuth
100
        } else {
101
6
            SocksAuth::Socks4(username)
102
        };
103

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

            
119
13
        let request = SocksRequest::new(SocksVersion::V4, cmd, addr, port, auth)?;
120

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

            
124
13
        Ok(ImplNextStep::Finished)
125
181
    }
126

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

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

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

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

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

            
164
40
        let ulen = r.take_u8()?;
165
36
        let username = r.take(ulen as usize)?;
166
20
        let plen = r.take_u8()?;
167
16
        let passwd = r.take(plen as usize)?;
168

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

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

            
189
14
        let auth = self
190
14
            .socks5_auth
191
14
            .take()
192
14
            .ok_or_else(|| internal!("called s5 without negotiating auth"))?;
193

            
194
14
        let request = SocksRequest::new(SocksVersion::V5, cmd, addr, port, auth)?;
195

            
196
14
        self.state = State::Done;
197
14
        self.handshake = Some(request);
198

            
199
14
        Ok(ImplNextStep::Finished)
200
160
    }
201

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

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

            
214
impl Default for SocksProxyHandshake {
215
1
    fn default() -> Self {
216
1
        Self::new()
217
1
    }
218
}
219

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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