Skip to content

Commit c284918

Browse files
committed
remove shadowsocks, use fast-socks5
Signed-off-by: Eval EXEC <execvy@gmail.com>
1 parent 0d141fe commit c284918

File tree

8 files changed

+120
-189
lines changed

8 files changed

+120
-189
lines changed

multiaddr/src/onion_addr.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::{borrow::Cow, fmt};
22

3+
use data_encoding::BASE32;
4+
35
/// Represents an Onion v3 address
46
#[derive(Clone)]
57
pub struct Onion3Addr<'a>(Cow<'a, [u8; 35]>, u16);
@@ -19,6 +21,11 @@ impl<'a> Onion3Addr<'a> {
1921
pub fn acquire<'b>(self) -> Onion3Addr<'b> {
2022
Onion3Addr(Cow::Owned(self.0.into_owned()), self.1)
2123
}
24+
25+
pub fn hash_string(&self) -> String {
26+
let s = BASE32.encode(self.hash());
27+
s.to_lowercase()
28+
}
2229
}
2330

2431
impl PartialEq for Onion3Addr<'_> {

multiaddr/src/protocol.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,7 @@ impl<'a> fmt::Display for Protocol<'a> {
273273
Wss => write!(f, "/wss"),
274274
Memory(port) => write!(f, "/memory/{}", port),
275275
Onion3(addr) => {
276-
let s = BASE32.encode(addr.hash());
277-
write!(f, "/onion3/{}:{}", s.to_lowercase(), addr.port())
276+
write!(f, "/onion3/{}:{}", addr.hash_string(), addr.port())
278277
}
279278
}
280279
}

tentacle/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ igd = { version = "0.15", optional = true, package = "igd-next" }
4444

4545
#tls
4646
tokio-rustls = { version = "0.26.0", optional = true }
47+
fast-socks5 = "0.10.0"
4748

4849
[target.'cfg(not(target_family = "wasm"))'.dependencies]
4950
# rand 0.8 not support wasm32
5051
rand = "0.8"
5152
socket2 = { version = "0.5.0", features = ["all"] }
52-
shadowsocks = { version = "1.21.0", default-features = false }
5353
url = "2.5.4"
5454

5555
[target.'cfg(target_family = "wasm")'.dependencies]

tentacle/src/builder.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,16 +227,27 @@ where
227227
self
228228
}
229229

230+
fn must_parse_proxy_url(url: String) -> url::Url {
231+
let url = url::Url::parse(&url)
232+
.unwrap_or_else(|err| panic!("parse {} to url::Url failed: {}", url, err));
233+
if url.scheme().ne("socks5") {
234+
panic!("tentacle only support socks5 proxy");
235+
}
236+
url
237+
}
238+
230239
/// Proxy config for tcp
231240
#[cfg(not(target_family = "wasm"))]
232241
pub fn tcp_proxy_config(mut self, proxy_url: String) -> Self {
242+
let proxy_url: url::Url = Self::must_parse_proxy_url(proxy_url);
233243
self.config.tcp_config.tcp.proxy_url = Some(proxy_url);
234244
self
235245
}
236246

237247
/// Onion config for tcp
238248
#[cfg(not(target_family = "wasm"))]
239249
pub fn tcp_onion_config(mut self, onion_url: String) -> Self {
250+
let onion_url: url::Url = Self::must_parse_proxy_url(onion_url);
240251
self.config.tcp_config.tcp.onion_url = Some(onion_url);
241252
self
242253
}
Lines changed: 30 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,35 @@
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,
74
};
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+
}
3318
} else {
34-
HandshakeRequest::new(vec![socks5::SOCKS5_AUTH_METHOD_NONE])
19+
AuthenticationMethod::None
3520
}
3621
};
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())
8135
}
Lines changed: 12 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,15 @@
1-
use std::io;
2-
31
use rand::Rng;
42

5-
#[derive(Debug)]
6-
pub(crate) struct Socks5Config {
7-
pub(crate) proxy_url: String,
8-
pub(crate) auth: Option<(String, String)>,
9-
}
10-
11-
// parse proxy url like "socks5://username:password@localhost:1080" to Socks5Config
12-
pub(crate) fn parse(proxy_url: &str, onion_random_socks_auth: bool) -> io::Result<Socks5Config> {
13-
let parsed_url = url::Url::parse(proxy_url).map_err(|err| {
14-
io::Error::other(format!("parse proxy_url {} failed, {}", proxy_url, err))
15-
})?;
16-
let scheme = parsed_url.scheme();
17-
match scheme {
18-
"socks5" => {
19-
let auth = match parsed_url.username() {
20-
"" => {
21-
if onion_random_socks_auth {
22-
let username = rand::thread_rng()
23-
.sample_iter(&rand::distributions::Alphanumeric)
24-
.take(8)
25-
.map(char::from)
26-
.collect();
27-
let password = rand::thread_rng()
28-
.sample_iter(&rand::distributions::Alphanumeric)
29-
.take(16)
30-
.map(char::from)
31-
.collect();
32-
Some((username, password))
33-
} else {
34-
None
35-
}
36-
}
37-
username => Some((
38-
username.to_string(),
39-
parsed_url.password().unwrap_or("").to_string(),
40-
)),
41-
};
42-
let port = parsed_url.port().ok_or(io::Error::other("missing port"))?;
43-
let proxy_url = String::new()
44-
+ parsed_url
45-
.host_str()
46-
.ok_or(io::Error::other("missing host"))?
47-
+ ":"
48-
+ &format!("{port}");
49-
Ok(Socks5Config { proxy_url, auth })
50-
}
51-
_ => Err(io::Error::other(format!(
52-
"tentacle doesn't support proxy scheme: {}",
53-
scheme
54-
))),
55-
}
3+
pub(crate) fn random_auth() -> (String, String) {
4+
let username = rand::thread_rng()
5+
.sample_iter(&rand::distributions::Alphanumeric)
6+
.take(8)
7+
.map(char::from)
8+
.collect();
9+
let password = rand::thread_rng()
10+
.sample_iter(&rand::distributions::Alphanumeric)
11+
.take(16)
12+
.map(char::from)
13+
.collect();
14+
(username, password)
5615
}

0 commit comments

Comments
 (0)