tor_socksproto/handshake/
proxy.rs1use 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#[derive(Clone, Debug, Deftly)]
24#[derive_deftly(Handshake)]
25pub struct SocksProxyHandshake {
26 state: State,
29 socks5_auth: Option<SocksAuth>,
32 #[deftly(handshake(output))]
34 handshake: Option<SocksRequest>,
35}
36
37#[derive(Clone, Debug, Copy, PartialEq, Eq)]
41enum State {
42 Initial,
44 Socks5Username,
47 Socks5Wait,
50 Done,
54 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 pub fn new() -> Self {
80 SocksProxyHandshake {
81 state: State::Initial,
82 socks5_auth: None,
83 handshake: None,
84 }
85 }
86
87 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 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 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 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 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 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 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 pub fn finished(&self) -> bool {
204 self.state == State::Done
205 }
206
207 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 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 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 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); if let Some(a) = addr {
257 w.write(a)?;
258 w.write_u16(self.port());
259 } else {
260 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 #![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)] 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()); 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()); 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 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 let mut h = SocksProxyHandshake::new();
493 let _a = h.handshake_for_tests(&hex!("05 01 00")).unwrap().unwrap();
494 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 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 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}