Skip to main content

tor_socksproto/handshake/
proxy.rs

1//! Types to implement the SOCKS handshake.
2
3use super::framework::{HandshakeImpl, ImplNextStep};
4use crate::msg::{SocksAddr, SocksAuth, SocksCmd, SocksRequest, SocksStatus, SocksVersion};
5use crate::{Error, Result};
6
7use tor_bytes::{EncodeResult, Error as BytesError};
8use tor_bytes::{Reader, Writer};
9use tor_error::internal;
10
11use derive_deftly::Deftly;
12
13use 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)]
25pub 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)]
41enum 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
58impl HandshakeImpl for SocksProxyHandshake {
59    fn handshake_impl(&mut self, input: &mut Reader<'_>) -> Result<ImplNextStep> {
60        match (self.state, input.peek(1)?[0]) {
61            (State::Initial, 4) => self.s4(input),
62            (State::Initial, 5) => self.s5_initial(input),
63            (State::Initial, v) => Err(Error::BadProtocol(v)),
64            (State::Socks5Username, 1) => self.s5_uname(input),
65            (State::Socks5Wait, 5) => self.s5(input),
66            (State::Done, _) => Err(Error::AlreadyFinished(internal!(
67                "called handshake() after handshaking was done"
68            ))),
69            (State::Failed, _) => Err(Error::AlreadyFinished(internal!(
70                "called handshake() after handshaking failed"
71            ))),
72            (_, _) => Err(Error::Syntax),
73        }
74    }
75}
76
77impl SocksProxyHandshake {
78    /// Construct a new SocksProxyHandshake in its initial state
79    pub fn new() -> Self {
80        SocksProxyHandshake {
81            state: State::Initial,
82            socks5_auth: None,
83            handshake: None,
84        }
85    }
86
87    /// Complete a socks4 or socks4a handshake.
88    fn s4(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
89        let version_number = r.take_u8()?;
90        if version_number.try_into() != Ok(SocksVersion::V4) {
91            return Err(internal!("called s4 on wrong type {:?}", version_number).into());
92        }
93
94        let cmd: SocksCmd = r.take_u8()?.into();
95        let port = r.take_u16()?;
96        let ip = r.take_u32()?;
97        let username: Vec<u8> = r.take_until(0)?.into();
98        let auth = if username.is_empty() {
99            SocksAuth::NoAuth
100        } else {
101            SocksAuth::Socks4(username)
102        };
103
104        let addr = if ip != 0 && (ip >> 8) == 0 {
105            // Socks4a; a hostname is given.
106            let hostname = r.take_until(0)?;
107            let hostname = std::str::from_utf8(hostname)
108                .map_err(|_| Error::Syntax)?
109                .to_string();
110            let hostname = hostname
111                .try_into()
112                .map_err(|_| BytesError::InvalidMessage("hostname too long".into()))?;
113            SocksAddr::Hostname(hostname)
114        } else {
115            let ip4: std::net::Ipv4Addr = ip.into();
116            SocksAddr::Ip(ip4.into())
117        };
118
119        let request = SocksRequest::new(SocksVersion::V4, cmd, addr, port, auth)?;
120
121        self.state = State::Done;
122        self.handshake = Some(request);
123
124        Ok(ImplNextStep::Finished)
125    }
126
127    /// Socks5: initial handshake to negotiate authentication method.
128    fn s5_initial(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
129        use super::{NO_AUTHENTICATION, USERNAME_PASSWORD};
130        let version_number = r.take_u8()?;
131        if version_number.try_into() != Ok(SocksVersion::V5) {
132            return Err(internal!("called on wrong handshake type {:?}", version_number).into());
133        }
134
135        let nmethods = r.take_u8()?;
136        let methods = r.take(nmethods as usize)?;
137
138        // Prefer username/password, then none.
139        let (next, reply) = if methods.contains(&USERNAME_PASSWORD) {
140            (State::Socks5Username, [5, USERNAME_PASSWORD])
141        } else if methods.contains(&NO_AUTHENTICATION) {
142            self.socks5_auth = Some(SocksAuth::NoAuth);
143            (State::Socks5Wait, [5, NO_AUTHENTICATION])
144        } else {
145            // In theory we should reply with "NO ACCEPTABLE METHODS".
146            return Err(Error::NotImplemented("authentication methods".into()));
147        };
148
149        self.state = next;
150        Ok(ImplNextStep::Reply {
151            reply: reply.into(),
152        })
153    }
154
155    /// Socks5: second step for username/password authentication.
156    fn s5_uname(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
157        let ver = r.take_u8()?;
158        if ver != 1 {
159            return Err(Error::NotImplemented(
160                format!("username/password version {}", ver).into(),
161            ));
162        }
163
164        let ulen = r.take_u8()?;
165        let username = r.take(ulen as usize)?;
166        let plen = r.take_u8()?;
167        let passwd = r.take(plen as usize)?;
168
169        self.socks5_auth = Some(SocksAuth::Username(username.into(), passwd.into()));
170        self.state = State::Socks5Wait;
171        Ok(ImplNextStep::Reply { reply: vec![1, 0] })
172    }
173
174    /// Socks5: final step, to receive client's request.
175    fn s5(&mut self, r: &mut Reader<'_>) -> Result<ImplNextStep> {
176        let version_number = r.take_u8()?;
177        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        }
184        let cmd = r.take_u8()?.into();
185        let _ignore = r.take_u8()?;
186        let addr = r.extract()?;
187        let port = r.take_u16()?;
188
189        let auth = self
190            .socks5_auth
191            .take()
192            .ok_or_else(|| internal!("called s5 without negotiating auth"))?;
193
194        let request = SocksRequest::new(SocksVersion::V5, cmd, addr, port, auth)?;
195
196        self.state = State::Done;
197        self.handshake = Some(request);
198
199        Ok(ImplNextStep::Finished)
200    }
201
202    /// Return true if this handshake is finished.
203    pub fn finished(&self) -> bool {
204        self.state == State::Done
205    }
206
207    /// Consume this handshake's state; if it finished successfully,
208    /// return a SocksRequest.
209    pub fn into_request(self) -> Option<SocksRequest> {
210        self.handshake
211    }
212}
213
214impl Default for SocksProxyHandshake {
215    fn default() -> Self {
216        Self::new()
217    }
218}
219
220impl 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    pub fn reply(&self, status: SocksStatus, addr: Option<&SocksAddr>) -> EncodeResult<Vec<u8>> {
226        match self.version() {
227            SocksVersion::V4 => self.s4(status, addr),
228            SocksVersion::V5 => self.s5(status, addr),
229        }
230    }
231
232    /// Format a SOCKS4 reply.
233    fn s4(&self, status: SocksStatus, addr: Option<&SocksAddr>) -> EncodeResult<Vec<u8>> {
234        let mut w = Vec::new();
235        w.write_u8(0);
236        w.write_u8(status.into_socks4_status());
237        match addr {
238            Some(SocksAddr::Ip(IpAddr::V4(ip))) => {
239                w.write_u16(self.port());
240                w.write(ip)?;
241            }
242            _ => {
243                w.write_u16(0);
244                w.write_u32(0);
245            }
246        }
247        Ok(w)
248    }
249
250    /// Format a SOCKS5 reply.
251    fn s5(&self, status: SocksStatus, addr: Option<&SocksAddr>) -> EncodeResult<Vec<u8>> {
252        let mut w = Vec::new();
253        w.write_u8(5);
254        w.write_u8(status.into());
255        w.write_u8(0); // reserved.
256        if let Some(a) = addr {
257            w.write(a)?;
258            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            match self.addr() {
266                SocksAddr::Ip(IpAddr::V6(_)) => {
267                    w.write(&SocksAddr::Ip(Ipv6Addr::UNSPECIFIED.into()))?;
268                }
269                SocksAddr::Ip(IpAddr::V4(_)) | SocksAddr::Hostname(_) => {
270                    w.write(&SocksAddr::Ip(Ipv4Addr::UNSPECIFIED.into()))?;
271                }
272            }
273            w.write_u16(0);
274        }
275        Ok(w)
276    }
277}
278
279#[cfg(test)]
280mod 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}