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;
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
958
    fn handshake_impl(&mut self, input: &mut Reader<'_>) -> Result<ImplNextStep> {
60
958
        match (self.state, input.peek(1)?[0]) {
61
362
            (State::Initial, 4) => self.s4(input),
62
74
            (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
318
            (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
958
    }
75
}
76

            
77
impl SocksProxyHandshake {
78
    /// Construct a new SocksProxyHandshake in its initial state
79
68
    pub fn new() -> Self {
80
68
        SocksProxyHandshake {
81
68
            state: State::Initial,
82
68
            socks5_auth: None,
83
68
            handshake: None,
84
68
        }
85
68
    }
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
26

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

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

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

            
138
        // Prefer username/password, then none.
139
36
        let (next, reply) = if methods.contains(&USERNAME_PASSWORD) {
140
14
            (State::Socks5Username, [5, USERNAME_PASSWORD])
141
22
        } else if methods.contains(&NO_AUTHENTICATION) {
142
20
            self.socks5_auth = Some(SocksAuth::NoAuth);
143
20
            (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
34
        self.state = next;
150
34
        Ok(ImplNextStep::Reply {
151
34
            reply: reply.into(),
152
34
        })
153
74
    }
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
318
    fn s5(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
176
318
        let version: SocksVersion = r.take_u8()?.try_into()?;
177
318
        if version != SocksVersion::V5 {
178
            return Err(
179
                internal!("called s5 on non socks5 handshake with type {:?}", version).into(),
180
            );
181
318
        }
182
318
        let cmd = r.take_u8()?.into();
183
302
        let _ignore = r.take_u8()?;
184
286
        let addr = r.extract()?;
185
54
        let port = r.take_u16()?;
186

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

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

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

            
197
26
        Ok(ImplNextStep::Finished)
198
318
    }
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
18
    pub fn into_request(self) -> Option<SocksRequest> {
208
18
        self.handshake
209
18
    }
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
50
    pub fn reply(&self, status: SocksStatus, addr: Option<&SocksAddr>) -> EncodeResult<Vec<u8>> {
224
50
        match self.version() {
225
24
            SocksVersion::V4 => self.s4(status, addr),
226
26
            SocksVersion::V5 => self.s5(status, addr),
227
        }
228
50
    }
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
26
    fn s5(&self, status: SocksStatus, addr: Option<&SocksAddr>) -> EncodeResult<Vec<u8>> {
250
26
        let mut w = Vec::new();
251
26
        w.write_u8(5);
252
26
        w.write_u8(status.into());
253
26
        w.write_u8(0); // reserved.
254
26
        if let Some(a) = addr {
255
4
            w.write(a)?;
256
4
            w.write_u16(self.port());
257
        } else {
258
            // TODO: sometimes I think we want to answer with ::, not 0.0.0.0
259
22
            w.write(&SocksAddr::Ip(std::net::Ipv4Addr::UNSPECIFIED.into()))?;
260
22
            w.write_u16(0);
261
        }
262
26
        Ok(w)
263
26
    }
264
}
265

            
266
#[cfg(test)]
267
mod test {
268
    // @@ begin test lint list maintained by maint/add_warning @@
269
    #![allow(clippy::bool_assert_comparison)]
270
    #![allow(clippy::clone_on_copy)]
271
    #![allow(clippy::dbg_macro)]
272
    #![allow(clippy::mixed_attributes_style)]
273
    #![allow(clippy::print_stderr)]
274
    #![allow(clippy::print_stdout)]
275
    #![allow(clippy::single_char_pattern)]
276
    #![allow(clippy::unwrap_used)]
277
    #![allow(clippy::unchecked_duration_subtraction)]
278
    #![allow(clippy::useless_vec)]
279
    #![allow(clippy::needless_pass_by_value)]
280
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
281
    use super::*;
282
    use crate::{Handshake as _, Truncated};
283
    use hex_literal::hex;
284

            
285
    #[test]
286
    fn socks4_good() {
287
        let mut h = SocksProxyHandshake::default();
288
        let a = h
289
            .handshake_for_tests(&hex!("04 01 0050 CB007107 00")[..])
290
            .unwrap()
291
            .unwrap();
292
        assert!(a.finished);
293
        assert!(h.finished());
294
        assert_eq!(a.drain, 9);
295
        assert!(a.reply.is_empty()); // no reply -- waiting to see how it goes
296

            
297
        let req = h.into_request().unwrap();
298
        assert_eq!(req.port(), 80);
299
        assert_eq!(req.addr().to_string(), "203.0.113.7");
300
        assert_eq!(req.command(), SocksCmd::CONNECT);
301

            
302
        assert_eq!(
303
            req.reply(
304
                SocksStatus::GENERAL_FAILURE,
305
                Some(&SocksAddr::Ip("127.0.0.1".parse().unwrap()))
306
            )
307
            .unwrap(),
308
            hex!("00 5B 0050 7f000001")
309
        );
310
    }
311

            
312
    #[test]
313
    fn socks4a_good() {
314
        let mut h = SocksProxyHandshake::new();
315
        let msg = hex!(
316
            "04 01 01BB 00000001 73776f72646669736800
317
                        7777772e6578616d706c652e636f6d00 99"
318
        );
319
        let a = h.handshake_for_tests(&msg[..]).unwrap().unwrap();
320
        assert!(a.finished);
321
        assert!(h.finished());
322
        assert_eq!(a.drain, msg.len() - 1);
323
        assert!(a.reply.is_empty()); // no reply -- waiting to see how it goes
324

            
325
        let req = h.into_request().unwrap();
326
        assert_eq!(req.port(), 443);
327
        assert_eq!(req.addr().to_string(), "www.example.com");
328
        assert_eq!(req.auth(), &SocksAuth::Socks4(b"swordfish".to_vec()));
329
        assert_eq!(req.command(), SocksCmd::CONNECT);
330

            
331
        assert_eq!(
332
            req.reply(SocksStatus::SUCCEEDED, None).unwrap(),
333
            hex!("00 5A 0000 00000000")
334
        );
335
    }
336

            
337
    #[test]
338
    fn socks5_init_noauth() {
339
        let mut h = SocksProxyHandshake::new();
340
        let a = h
341
            .handshake_for_tests(&hex!("05 01 00")[..])
342
            .unwrap()
343
            .unwrap();
344
        assert!(!a.finished);
345
        assert_eq!(a.drain, 3);
346
        assert_eq!(a.reply, &[5, 0]);
347
        assert_eq!(h.state, State::Socks5Wait);
348
    }
349

            
350
    #[test]
351
    fn socks5_init_username() {
352
        let mut h = SocksProxyHandshake::new();
353
        let a = h
354
            .handshake_for_tests(&hex!("05 04 00023031")[..])
355
            .unwrap()
356
            .unwrap();
357
        assert!(!a.finished);
358
        assert_eq!(a.drain, 6);
359
        assert_eq!(a.reply, &[5, 2]);
360
        assert_eq!(h.state, State::Socks5Username);
361
    }
362

            
363
    #[test]
364
    fn socks5_init_nothing_works() {
365
        let mut h = SocksProxyHandshake::new();
366
        let a = h.handshake_for_tests(&hex!("05 02 9988")[..]);
367
        assert!(matches!(a, Ok(Err(Error::NotImplemented(_)))));
368
    }
369

            
370
    #[test]
371
    fn socks5_username_ok() {
372
        let mut h = SocksProxyHandshake::new();
373
        let _a = h.handshake_for_tests(&hex!("05 02 9902")).unwrap().unwrap();
374
        let a = h
375
            .handshake_for_tests(&hex!("01 08 5761677374616666 09 24776f726466693568"))
376
            .unwrap()
377
            .unwrap();
378
        assert_eq!(a.drain, 20);
379
        assert_eq!(a.reply, &[1, 0]);
380
        assert_eq!(h.state, State::Socks5Wait);
381
        assert_eq!(
382
            h.socks5_auth.unwrap(),
383
            // _Horse Feathers_, 1932
384
            SocksAuth::Username(b"Wagstaff".to_vec(), b"$wordfi5h".to_vec())
385
        );
386
    }
387

            
388
    #[test]
389
    fn socks5_request_ok_ipv4() {
390
        let mut h = SocksProxyHandshake::new();
391
        let _a = h.handshake_for_tests(&hex!("05 01 00")).unwrap().unwrap();
392
        let a = h
393
            .handshake_for_tests(&hex!("05 01 00 01 7f000007 1f90"))
394
            .unwrap()
395
            .unwrap();
396
        assert_eq!(a.drain, 10);
397
        assert!(a.finished);
398
        assert!(a.reply.is_empty());
399
        assert_eq!(h.state, State::Done);
400

            
401
        let req = h.into_request().unwrap();
402
        assert_eq!(req.version(), SocksVersion::V5);
403
        assert_eq!(req.command(), SocksCmd::CONNECT);
404
        assert_eq!(req.addr().to_string(), "127.0.0.7");
405
        assert_eq!(req.port(), 8080);
406
        assert_eq!(req.auth(), &SocksAuth::NoAuth);
407

            
408
        assert_eq!(
409
            req.reply(
410
                SocksStatus::HOST_UNREACHABLE,
411
                Some(&SocksAddr::Hostname(
412
                    "foo.example.com".to_string().try_into().unwrap()
413
                ))
414
            )
415
            .unwrap(),
416
            hex!("05 04 00 03 0f 666f6f2e6578616d706c652e636f6d 1f90")
417
        );
418
    }
419

            
420
    #[test]
421
    fn socks5_request_ok_ipv6() {
422
        let mut h = SocksProxyHandshake::new();
423
        let _a = h.handshake_for_tests(&hex!("05 01 00")).unwrap().unwrap();
424
        let a = h
425
            .handshake_for_tests(&hex!(
426
                "05 01 00 04 f000 0000 0000 0000 0000 0000 0000 ff11 1f90"
427
            ))
428
            .unwrap()
429
            .unwrap();
430
        assert_eq!(a.drain, 22);
431
        assert!(a.finished);
432
        assert!(a.reply.is_empty());
433
        assert_eq!(h.state, State::Done);
434

            
435
        let req = h.into_request().unwrap();
436
        assert_eq!(req.version(), SocksVersion::V5);
437
        assert_eq!(req.command(), SocksCmd::CONNECT);
438
        assert_eq!(req.addr().to_string(), "f000::ff11");
439
        assert_eq!(req.port(), 8080);
440
        assert_eq!(req.auth(), &SocksAuth::NoAuth);
441

            
442
        assert_eq!(
443
            req.reply(SocksStatus::GENERAL_FAILURE, Some(req.addr()))
444
                .unwrap(),
445
            hex!("05 01 00 04 f000 0000 0000 0000 0000 0000 0000 ff11 1f90")
446
        );
447
    }
448

            
449
    #[test]
450
    fn socks5_request_ok_hostname() {
451
        let mut h = SocksProxyHandshake::new();
452
        let _a = h.handshake_for_tests(&hex!("05 01 00")).unwrap().unwrap();
453
        let a = h
454
            .handshake_for_tests(&hex!("05 01 00 03 0f 666f6f2e6578616d706c652e636f6d 1f90"))
455
            .unwrap()
456
            .unwrap();
457
        assert_eq!(a.drain, 22);
458
        assert!(a.finished);
459
        assert!(a.reply.is_empty());
460
        assert_eq!(h.state, State::Done);
461

            
462
        let req = h.into_request().unwrap();
463
        assert_eq!(req.version(), SocksVersion::V5);
464
        assert_eq!(req.command(), SocksCmd::CONNECT);
465
        assert_eq!(req.addr().to_string(), "foo.example.com");
466
        assert_eq!(req.port(), 8080);
467
        assert_eq!(req.auth(), &SocksAuth::NoAuth);
468

            
469
        assert_eq!(
470
            req.reply(SocksStatus::SUCCEEDED, None).unwrap(),
471
            hex!("05 00 00 01 00000000 0000")
472
        );
473
    }
474

            
475
    #[test]
476
    fn empty_handshake() {
477
        let r = SocksProxyHandshake::new().handshake_for_tests(&[]);
478
        assert!(matches!(r, Err(Truncated { .. })));
479
    }
480

            
481
    #[test]
482
    fn bad_version() {
483
        let mut h = SocksProxyHandshake::new();
484
        let r = h.handshake_for_tests(&hex!("06 01 00"));
485
        assert!(matches!(r, Ok(Err(Error::BadProtocol(6)))));
486

            
487
        let mut h = SocksProxyHandshake::new();
488
        let _a = h.handshake_for_tests(&hex!("05 01 00")).unwrap();
489
        let r = h.handshake_for_tests(&hex!("06 01 00"));
490
        assert!(r.unwrap().is_err());
491
    }
492

            
493
    #[test]
494
    fn fused_result() {
495
        let good_socks4a = &hex!("04 01 0050 CB007107 00")[..];
496

            
497
        // Can't try again after failure.
498
        let mut h = SocksProxyHandshake::new();
499
        let r = h.handshake_for_tests(&hex!("06 01 00"));
500
        assert!(r.unwrap().is_err());
501
        let r = h.handshake_for_tests(good_socks4a);
502
        assert!(matches!(r, Ok(Err(Error::AlreadyFinished(_)))));
503

            
504
        // Can't try again after success
505
        let mut h = SocksProxyHandshake::new();
506
        let r = h.handshake_for_tests(good_socks4a);
507
        assert!(r.is_ok());
508
        let r = h.handshake_for_tests(good_socks4a);
509
        assert!(matches!(r, Ok(Err(Error::AlreadyFinished(_)))));
510
    }
511
}