|
1 | | -use std::io; |
2 | | - |
3 | | -use log::debug; |
4 | | -use shadowsocks::relay::socks5::{ |
5 | | - self, Address, Command, Error as Socks5Error, HandshakeRequest, HandshakeResponse, |
6 | | - PasswdAuthRequest, PasswdAuthResponse, Reply, TcpRequestHeader, TcpResponseHeader, |
| 1 | +use fast_socks5::{ |
| 2 | + client::{Config as ConnectConfig, Socks5Stream}, |
| 3 | + AuthenticationMethod, Socks5Command, |
7 | 4 | }; |
8 | | -use tokio::io::{AsyncRead, AsyncWrite}; |
9 | | - |
10 | | -use super::socks5_config::Socks5Config; |
11 | | - |
12 | | -pub async fn establish_connection<S, A>( |
13 | | - mut s: S, |
14 | | - target_addr: A, |
15 | | - socks5_config: Socks5Config, |
16 | | -) -> Result<S, Socks5Error> |
17 | | -where |
18 | | - S: AsyncRead + AsyncWrite + Unpin, |
19 | | - A: Into<Address>, |
20 | | -{ |
21 | | - debug!( |
22 | | - "client connecting proxy server: config {}, with auth: {}", |
23 | | - socks5_config.proxy_url, |
24 | | - socks5_config.auth.is_some() |
25 | | - ); |
26 | | - // destruct socks5_config |
27 | | - let Socks5Config { auth, proxy_url: _ } = socks5_config; |
28 | | - |
29 | | - // 1. Handshake |
30 | | - let hs = { |
31 | | - if auth.is_some() { |
32 | | - HandshakeRequest::new(vec![socks5::SOCKS5_AUTH_METHOD_PASSWORD]) |
| 5 | +use tokio::net::TcpStream; |
| 6 | + |
| 7 | +pub async fn connect( |
| 8 | + socks_server: url::Url, |
| 9 | + target_addr: String, |
| 10 | + target_port: u16, |
| 11 | +) -> Result<TcpStream, fast_socks5::SocksError> { |
| 12 | + let auth = { |
| 13 | + if let Some(password) = socks_server.password() { |
| 14 | + AuthenticationMethod::Password { |
| 15 | + username: socks_server.username().to_string(), |
| 16 | + password: password.to_string(), |
| 17 | + } |
33 | 18 | } else { |
34 | | - HandshakeRequest::new(vec![socks5::SOCKS5_AUTH_METHOD_NONE]) |
| 19 | + AuthenticationMethod::None |
35 | 20 | } |
36 | 21 | }; |
37 | | - debug!("client connected, going to send handshake: {:?}", hs); |
38 | | - |
39 | | - hs.write_to(&mut s).await?; |
40 | | - |
41 | | - let hsp = HandshakeResponse::read_from(&mut s).await?; |
42 | | - |
43 | | - debug!("got handshake response: {:?}", hsp); |
44 | | - match hsp.chosen_method { |
45 | | - socks5::SOCKS5_AUTH_METHOD_NONE => (), |
46 | | - socks5::SOCKS5_AUTH_METHOD_PASSWORD => { |
47 | | - if let Some((uname, passwd)) = auth { |
48 | | - let pr = PasswdAuthRequest::new(uname, passwd); |
49 | | - pr.write_to(&mut s).await?; |
50 | | - let prp = PasswdAuthResponse::read_from(&mut s).await?; |
51 | | - match Reply::from_u8(prp.status) { |
52 | | - Reply::Succeeded => debug!("password auth succeeded"), |
53 | | - r => return Err(Socks5Error::Reply(r)), |
54 | | - } |
55 | | - } else { |
56 | | - return Err(Socks5Error::PasswdAuthInvalidRequest); |
57 | | - } |
58 | | - } |
59 | | - _ => { |
60 | | - return Err(Socks5Error::IoError(io::Error::other(format!( |
61 | | - "unsupported auth method: {}", |
62 | | - hsp.chosen_method |
63 | | - )))) |
64 | | - } |
65 | | - } |
66 | | - |
67 | | - // 2. Send request header |
68 | | - let h = TcpRequestHeader::new(Command::TcpConnect, target_addr.into()); |
69 | | - debug!("going to connect, req: {:?}", h); |
70 | | - h.write_to(&mut s).await?; |
71 | | - |
72 | | - let hp = TcpResponseHeader::read_from(&mut s).await?; |
73 | | - |
74 | | - debug!("got response: {:?}", hp); |
75 | | - match hp.reply { |
76 | | - Reply::Succeeded => (), |
77 | | - r => return Err(Socks5Error::Reply(r)), |
78 | | - } |
79 | | - |
80 | | - Ok(s) |
| 22 | + let socks_server_host = socks_server.host_str().ok_or_else(|| { |
| 23 | + fast_socks5::SocksError::ArgumentInputError("socks_server should have host") |
| 24 | + })?; |
| 25 | + Socks5Stream::connect_raw( |
| 26 | + Socks5Command::TCPConnect, |
| 27 | + socks_server_host, |
| 28 | + target_addr, |
| 29 | + target_port, |
| 30 | + Some(auth), |
| 31 | + ConnectConfig::default(), |
| 32 | + ) |
| 33 | + .await |
| 34 | + .map(|socket| socket.get_socket()) |
81 | 35 | } |
0 commit comments