Skip to content

Commit 97eddb6

Browse files
committed
migrate to new extensible socks5 server API
Signed-off-by: yuguorui <yuguorui@pku.edu.cn>
1 parent eea30c1 commit 97eddb6

File tree

3 files changed

+64
-97
lines changed

3 files changed

+64
-97
lines changed

Cargo.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ iprange = "0.6.6"
1515
ipnet = "2.3.1"
1616
url = "2.2.2"
1717
itertools = "0.10.3"
18-
fast-socks5 = { git = "https://github.com/yuguorui/fast-socks5.git", rev = "9b5480f6" }
18+
fast-socks5 = { git = "https://github.com/valpackett/fast-socks5.git", rev = "4c8985c" }
1919
maxminddb = "0.17"
2020
lazy_static = "1.4.0"
2121
tuple = "0.5.1"

src/socks5.rs

Lines changed: 56 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use std::sync::Arc;
2-
3-
use fast_socks5::server::Socks5Socket;
4-
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
1+
use fast_socks5::server::Socks5ServerProtocol;
2+
use fast_socks5::ReplyError;
3+
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite};
54
use tokio::net::UdpSocket;
65
use tokio::net::{TcpListener, TcpStream};
76

@@ -34,100 +33,68 @@ pub async fn socks5_worker() -> Result<()> {
3433
match listener.accept().await {
3534
Ok((mut _socket, _)) => {
3635
tokio::spawn(async {
37-
let mut config = fast_socks5::server::BaseConfig::<
38-
TcpStream,
39-
fast_socks5::server::DenyAuthentication,
40-
RforRelaySocket,
41-
>::default()
42-
.with_command_executor(RforRelaySocket::default());
43-
44-
config.set_dns_resolve(false);
45-
config.set_udp_support(true);
46-
let mut socks5_socket = Socks5Socket::new(_socket, Arc::new(config));
47-
socks5_socket
48-
.set_reply_ip(std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)));
49-
50-
match socks5_socket.upgrade_to_socks5().await {
51-
Ok(_) => {}
52-
Err(e) => println!("socks5 error: {}", e),
53-
}
36+
socks5_instance(_socket).await.unwrap_or_else(|e| {
37+
println!("socks5 error: {:#}", e);
38+
});
5439
});
5540
}
5641
Err(e) => println!("couldn't get client: {:?}", e),
5742
}
5843
}
5944
}
6045

61-
#[derive(Copy, Clone, Default)]
62-
pub struct RforRelaySocket;
63-
64-
#[async_trait::async_trait]
65-
impl fast_socks5::server::CommandExecutor<TcpStream> for RforRelaySocket {
66-
async fn connect(
67-
&self,
68-
inbound: &mut TcpStream,
69-
target_addr: &fast_socks5::util::target_addr::TargetAddr,
70-
_timeout: u64,
71-
_nodelay: bool,
72-
) -> fast_socks5::Result<()> {
73-
inbound
74-
.write(&fast_socks5::server::new_reply(
75-
&fast_socks5::ReplyError::Succeeded,
76-
std::net::SocketAddr::new(std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)), 0),
77-
))
78-
.await
79-
.context("Can't write successful reply")?;
80-
81-
inbound.flush().await.context("Can't flush the reply!")?;
82-
83-
let context = match target_addr {
84-
fast_socks5::util::target_addr::TargetAddr::Ip(sock_addr) => RouteContext {
85-
src_addr: inbound.peer_addr()?,
86-
dst_addr: crate::rules::TargetAddr::Ip(sock_addr.to_owned()),
87-
inbound_proto: Some(InboundProtocol::SOCKS5),
88-
socket_type: crate::rules::SocketType::STREAM,
89-
},
90-
fast_socks5::util::target_addr::TargetAddr::Domain(domain, port) => RouteContext {
91-
src_addr: inbound.peer_addr()?,
92-
dst_addr: crate::rules::TargetAddr::Domain(
93-
domain.to_owned(),
94-
port.to_owned(),
95-
None,
96-
),
97-
inbound_proto: Some(InboundProtocol::SOCKS5),
98-
socket_type: crate::rules::SocketType::STREAM,
99-
},
100-
};
101-
transfer_tcp(inbound, context).await?;
102-
103-
Ok(())
104-
}
46+
async fn socks5_instance(socket: TcpStream) -> Result<()> {
47+
let (proto, cmd, target_addr) = Socks5ServerProtocol::accept_no_auth(socket).await?
48+
.read_command().await?;
49+
50+
let empty_ip = std::net::IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0));
51+
let empty_sockaddr = std::net::SocketAddr::new(empty_ip, 0);
52+
match cmd {
53+
fast_socks5::Socks5Command::TCPConnect => {
54+
let mut inner = proto.reply_success(empty_sockaddr).await?;
55+
let src_addr = inner.peer_addr()?;
56+
57+
let context = match target_addr {
58+
fast_socks5::util::target_addr::TargetAddr::Ip(sock_addr) => RouteContext {
59+
src_addr: src_addr,
60+
dst_addr: crate::rules::TargetAddr::Ip(sock_addr.to_owned()),
61+
inbound_proto: Some(InboundProtocol::SOCKS5),
62+
socket_type: crate::rules::SocketType::STREAM,
63+
},
64+
fast_socks5::util::target_addr::TargetAddr::Domain(domain, port) => RouteContext {
65+
src_addr: src_addr,
66+
dst_addr: crate::rules::TargetAddr::Domain(
67+
domain.to_owned(),
68+
port.to_owned(),
69+
None,
70+
),
71+
inbound_proto: Some(InboundProtocol::SOCKS5),
72+
socket_type: crate::rules::SocketType::STREAM,
73+
},
74+
};
75+
76+
transfer_tcp(&mut inner, context.clone()).await.with_context(
77+
|| format!("failed to relay {}", context),
78+
)?;
79+
}
80+
fast_socks5::Socks5Command::TCPBind => {
81+
proto.reply_error(&ReplyError::CommandNotSupported).await?;
82+
return Err(ReplyError::CommandNotSupported.into());
83+
}
84+
fast_socks5::Socks5Command::UDPAssociate => {
85+
// Listen with UDP6 socket, so the client can connect to it with either
86+
// IPv4 or IPv6.
87+
let peer_sock = UdpSocket::bind("[::]:0").await?;
10588

106-
/// Bind to a random UDP port, wait for the traffic from
107-
/// the client, and then forward the data to the remote addr.
108-
async fn udp_associate(
109-
&self,
110-
inbound: &mut TcpStream,
111-
_: Option<&fast_socks5::util::target_addr::TargetAddr>,
112-
reply_ip: std::net::IpAddr,
113-
) -> fast_socks5::Result<()> {
114-
115-
// Listen with UDP6 socket, so the client can connect to it with either
116-
// IPv4 or IPv6.
117-
let peer_sock = UdpSocket::bind("[::]:0").await?;
118-
119-
// Respect the pre-populated reply IP address.
120-
inbound
121-
.write(&fast_socks5::server::new_reply(
122-
&fast_socks5::ReplyError::Succeeded,
123-
std::net::SocketAddr::new(reply_ip, peer_sock.local_addr()?.port()),
124-
))
125-
.await
126-
.context("Can't write successful reply")?;
127-
128-
transfer_udp(inbound, peer_sock).await?;
129-
Ok(())
89+
let mut inner = proto.reply_success(std::net::SocketAddr::new(
90+
empty_ip, peer_sock.local_addr().unwrap().port())
91+
).await?;
92+
93+
transfer_udp(&mut inner, peer_sock).await?;
94+
}
13095
}
96+
97+
Ok(())
13198
}
13299

133100
async fn handle_udp_request(inbound: &UdpSocket, outbound: &dyn ProxyDgram) -> Result<()> {

0 commit comments

Comments
 (0)