Skip to content

Commit 4e5d673

Browse files
committed
Add forwarding SOCKS server
1 parent 228bb05 commit 4e5d673

File tree

6 files changed

+80
-8
lines changed

6 files changed

+80
-8
lines changed

test/socks-server/src/lib.rs

+60
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use futures::StreamExt;
22
use std::io;
33
use std::net::IpAddr;
44
use std::net::SocketAddr;
5+
use fast_socks5::util::target_addr::TargetAddr;
6+
use fast_socks5::client::{Config, Socks5Stream};
57

68
#[derive(err_derive::Error, Debug)]
79
#[error(no_from)]
@@ -19,6 +21,7 @@ pub struct Handle {
1921
bind_addr: SocketAddr,
2022
}
2123

24+
/// Spawn a SOCKS server bound to `bind_addr`
2225
pub async fn spawn(bind_addr: SocketAddr) -> Result<Handle, Error> {
2326
let bind_addr = match bind_addr.port() {
2427
0 => SocketAddr::new(bind_addr.ip(), find_free_port(bind_addr.ip())?),
@@ -36,6 +39,8 @@ pub async fn spawn(bind_addr: SocketAddr) -> Result<Handle, Error> {
3639
match new_client {
3740
Ok(socket) => {
3841
let fut = socket.upgrade_to_socks5();
42+
43+
// Act as normal SOCKS server
3944
tokio::spawn(async move {
4045
match fut.await {
4146
Ok(_socket) => log::info!("socks client disconnected"),
@@ -52,6 +57,61 @@ pub async fn spawn(bind_addr: SocketAddr) -> Result<Handle, Error> {
5257
Ok(Handle { handle, bind_addr })
5358
}
5459

60+
/// Spawn a SOCKS server that forwards everything via another SOCKS server at `via_socks_server`
61+
pub async fn spawn_via(bind_addr: SocketAddr, via_socks_server: SocketAddr)-> Result<Handle, Error> {
62+
let bind_addr = match bind_addr.port() {
63+
0 => SocketAddr::new(bind_addr.ip(), find_free_port(bind_addr.ip())?),
64+
_ => bind_addr,
65+
};
66+
let socks_server: fast_socks5::server::Socks5Server =
67+
fast_socks5::server::Socks5Server::bind(bind_addr)
68+
.await
69+
.map_err(Error::StartSocksServer)?;
70+
71+
let handle = tokio::spawn(async move {
72+
let mut incoming = socks_server.incoming();
73+
74+
while let Some(new_client) = incoming.next().await {
75+
match new_client {
76+
Ok(mut socket) => {
77+
let (target_host, target_port) = match socket.target_addr().cloned() {
78+
Some(TargetAddr::Domain(host, port)) => (host, port),
79+
Some(TargetAddr::Ip(addr)) => (addr.ip().to_string(), addr.port()),
80+
None => {
81+
log::error!("missing target address");
82+
continue;
83+
}
84+
};
85+
86+
let mut client = match Socks5Stream::connect(
87+
via_socks_server,
88+
target_host,
89+
target_port,
90+
Config::default(),
91+
).await {
92+
Ok(client) => client,
93+
Err(error) => {
94+
log::error!("failed to connect client to proxy: {error}");
95+
continue;
96+
}
97+
};
98+
99+
tokio::spawn(async move {
100+
match tokio::io::copy_bidirectional(&mut client, &mut socket).await {
101+
Ok(_socket) => log::info!("socks client disconnected"),
102+
Err(error) => log::error!("socks client failed: {error}"),
103+
}
104+
});
105+
}
106+
Err(error) => {
107+
log::error!("failed to accept socks client: {error}");
108+
}
109+
}
110+
}
111+
});
112+
Ok(Handle { handle, bind_addr })
113+
}
114+
55115
impl Handle {
56116
pub fn bind_addr(&self) -> SocketAddr {
57117
self.bind_addr

test/test-rpc/src/client.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,9 @@ impl ServiceClient {
218218
pub async fn start_socks_server(
219219
&self,
220220
bind_addr: SocketAddr,
221+
via_socks_server: Option<SocketAddr>,
221222
) -> Result<crate::net::SocksHandle, Error> {
222-
crate::net::SocksHandle::start_server(self.client.clone(), bind_addr).await
223+
crate::net::SocksHandle::start_server(self.client.clone(), bind_addr, via_socks_server).await
223224
}
224225

225226
/// Restarts the app.

test/test-rpc/src/lib.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,12 @@ mod service {
150150
/// Perform DNS resolution.
151151
async fn resolve_hostname(hostname: String) -> Result<Vec<SocketAddr>, Error>;
152152

153-
/// Start a SOCKS5 server bound to the given address. Return an ID that can be used with
154-
/// `stop_socks_server`, and the address that the listening socket was actually bound to.
153+
/// Start a SOCKS5 server bound to the given address. This optionally proxies everything via a
154+
/// SOCKS server at `via_socks_server`. Return an ID that can be used with `stop_socks_server`,
155+
/// and the address that the listening socket was actually bound to.
155156
async fn start_socks_server(
156157
bind_addr: SocketAddr,
158+
via_socks_server: Option<SocketAddr>,
157159
) -> Result<(net::SocksHandleId, SocketAddr), Error>;
158160

159161
/// Stop a SOCKS5 server that was previously started with `start_socks_server`.

test/test-rpc/src/net.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@ impl SocksHandle {
3131
pub(crate) async fn start_server(
3232
client: crate::service::ServiceClient,
3333
bind_addr: SocketAddr,
34+
via_socks_server: Option<SocketAddr>,
3435
) -> Result<Self, Error> {
3536
let (stop_tx, stop_rx) = oneshot::channel();
3637

3738
let (id, bind_addr) = client
38-
.start_socks_server(tarpc::context::current(), bind_addr)
39+
.start_socks_server(tarpc::context::current(), bind_addr, via_socks_server)
3940
.await??;
4041

4142
tokio::spawn(async move {

test/test-runner/src/main.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -169,14 +169,16 @@ impl Service for TestServer {
169169
.collect())
170170
}
171171

172-
/// Start a SOCKS5 server bound to the given address. Return an ID that can be used with
173-
/// `stop_socks_server`, and the address that the listening socket was actually bound to.
172+
/// Start a SOCKS5 server bound to the given address. This optionally proxies everything via a
173+
/// SOCKS server at `via_socks_server`. Return an ID that can be used with `stop_socks_server`,
174+
/// and the address that the listening socket was actually bound to.
174175
async fn start_socks_server(
175176
self,
176177
_: context::Context,
177178
bind_addr: SocketAddr,
179+
via_socks_server: Option<SocketAddr>,
178180
) -> Result<(SocksHandleId, SocketAddr), test_rpc::Error> {
179-
socks::start_server(bind_addr).await
181+
socks::start_server(bind_addr, via_socks_server).await
180182
}
181183

182184
/// Stop a SOCKS5 server that was previously started with `start_socks_server`.

test/test-runner/src/socks.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,21 @@ use test_rpc::net::SocksHandleId;
88
static SERVERS: Lazy<Mutex<HashMap<SocksHandleId, socks_server::Handle>>> =
99
Lazy::new(|| Mutex::new(HashMap::new()));
1010

11+
/// Spawn a SOCKS server that sends everything through the test-manager SOCKS server
1112
pub async fn start_server(
1213
bind_addr: SocketAddr,
14+
via_socks_server: Option<SocketAddr>,
1315
) -> Result<(SocksHandleId, SocketAddr), test_rpc::Error> {
1416
let next_nonce = {
1517
static NONCE: AtomicUsize = AtomicUsize::new(0);
1618
|| NONCE.fetch_add(1, Ordering::Relaxed)
1719
};
1820
let id = SocksHandleId(next_nonce());
1921

20-
let handle = socks_server::spawn(bind_addr).await.map_err(|error| {
22+
let handle = match via_socks_server {
23+
Some(proxy) => socks_server::spawn_via(bind_addr, proxy).await,
24+
None => socks_server::spawn(bind_addr).await,
25+
}.map_err(|error| {
2126
log::error!("Failed to spawn SOCKS server: {error}");
2227
test_rpc::Error::SocksServer
2328
})?;
@@ -30,6 +35,7 @@ pub async fn start_server(
3035
Ok((id, bind_addr))
3136
}
3237

38+
/// Stop SOCKS server given some ID returned by `start_server`
3339
pub async fn stop_server(id: SocksHandleId) -> Result<(), test_rpc::Error> {
3440
let handle = {
3541
let mut servers = SERVERS.lock().unwrap();

0 commit comments

Comments
 (0)