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 }