proxy.rs
  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      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  
 77  impl 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 = r.take_u8()?.try_into()?;
 90          if version != SocksVersion::V4 {
 91              return Err(internal!("called s4 on wrong type {:?}", version).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(version, 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: SocksVersion = r.take_u8()?.try_into()?;
131          if version != SocksVersion::V5 {
132              return Err(internal!("called on wrong handshake type {:?}", version).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: SocksVersion = r.take_u8()?.try_into()?;
177          if version != SocksVersion::V5 {
178              return Err(
179                  internal!("called s5 on non socks5 handshake with type {:?}", version).into(),
180              );
181          }
182          let cmd = r.take_u8()?.into();
183          let _ignore = r.take_u8()?;
184          let addr = r.extract()?;
185          let port = r.take_u16()?;
186  
187          let auth = self
188              .socks5_auth
189              .take()
190              .ok_or_else(|| internal!("called s5 without negotiating auth"))?;
191  
192          let request = SocksRequest::new(version, cmd, addr, port, auth)?;
193  
194          self.state = State::Done;
195          self.handshake = Some(request);
196  
197          Ok(ImplNextStep::Finished)
198      }
199  
200      /// Return true if this handshake is finished.
201      pub fn finished(&self) -> bool {
202          self.state == State::Done
203      }
204  
205      /// Consume this handshake's state; if it finished successfully,
206      /// return a SocksRequest.
207      pub fn into_request(self) -> Option<SocksRequest> {
208          self.handshake
209      }
210  }
211  
212  impl Default for SocksProxyHandshake {
213      fn default() -> Self {
214          Self::new()
215      }
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      pub fn reply(&self, status: SocksStatus, addr: Option<&SocksAddr>) -> EncodeResult<Vec<u8>> {
224          match self.version() {
225              SocksVersion::V4 => self.s4(status, addr),
226              SocksVersion::V5 => self.s5(status, addr),
227          }
228      }
229  
230      /// Format a SOCKS4 reply.
231      fn s4(&self, status: SocksStatus, addr: Option<&SocksAddr>) -> EncodeResult<Vec<u8>> {
232          let mut w = Vec::new();
233          w.write_u8(0);
234          w.write_u8(status.into_socks4_status());
235          match addr {
236              Some(SocksAddr::Ip(IpAddr::V4(ip))) => {
237                  w.write_u16(self.port());
238                  w.write(ip)?;
239              }
240              _ => {
241                  w.write_u16(0);
242                  w.write_u32(0);
243              }
244          }
245          Ok(w)
246      }
247  
248      /// Format a SOCKS5 reply.
249      fn s5(&self, status: SocksStatus, addr: Option<&SocksAddr>) -> EncodeResult<Vec<u8>> {
250          let mut w = Vec::new();
251          w.write_u8(5);
252          w.write_u8(status.into());
253          w.write_u8(0); // reserved.
254          if let Some(a) = addr {
255              w.write(a)?;
256              w.write_u16(self.port());
257          } else {
258              // TODO: sometimes I think we want to answer with ::, not 0.0.0.0
259              w.write(&SocksAddr::Ip(std::net::Ipv4Addr::UNSPECIFIED.into()))?;
260              w.write_u16(0);
261          }
262          Ok(w)
263      }
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  }