Skip to main content

eggress_protocol_shadowsocks/
server.rs

1use tokio::io::AsyncWriteExt;
2use tokio::net::TcpStream;
3use zeroize::Zeroizing;
4
5use crate::error::ShadowsocksError;
6use crate::method::CipherMethod;
7use crate::tcp::shadowsocks_accept;
8
9/// Run a Shadowsocks server that relays traffic to a target.
10///
11/// This is a test helper - not suitable for production use.
12/// Compatible with `shadowsocks_connect` from `crate::tcp`.
13pub async fn run_shadowsocks_server(
14    listener: &tokio::net::TcpListener,
15    password: &str,
16    method: CipherMethod,
17) -> Result<(), ShadowsocksError> {
18    loop {
19        let (stream, _) = listener.accept().await?;
20        let password = Zeroizing::new(password.to_string());
21        tokio::spawn(async move {
22            if let Err(e) = handle_client(stream, password, method).await {
23                eprintln!("client error: {}", e);
24            }
25        });
26    }
27}
28
29async fn handle_client(
30    stream: TcpStream,
31    password: Zeroizing<String>,
32    method: CipherMethod,
33) -> Result<(), ShadowsocksError> {
34    let boxed: eggress_core::BoxStream = Box::new(stream);
35    let (ss_stream, target_addr) = shadowsocks_accept(boxed, &password, method, None).await?;
36
37    // Connect to target
38    let target_str = match &target_addr.host {
39        eggress_core::TargetHost::Ip(ip) => format!("{}:{}", ip, target_addr.port),
40        eggress_core::TargetHost::Domain(d) => format!("{}:{}", d, target_addr.port),
41    };
42    let target_stream = TcpStream::connect(&target_str).await?;
43
44    let (mut ss_read, mut ss_write) = tokio::io::split(ss_stream);
45    let (mut target_read, mut target_write) = target_stream.into_split();
46
47    let client_to_target = async {
48        let _ = tokio::io::copy(&mut ss_read, &mut target_write).await;
49        let _ = target_write.shutdown().await;
50    };
51    let target_to_client = async {
52        let _ = tokio::io::copy(&mut target_read, &mut ss_write).await;
53        let _ = ss_write.shutdown().await;
54    };
55
56    let _ = tokio::join!(client_to_target, target_to_client);
57    Ok(())
58}