Skip to main content

eggress_protocol_shadowsocks/
server.rs

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