1pub mod cli;
7pub mod config;
8mod connector;
9mod error;
10mod handler;
11pub mod socks5;
12
13pub use cli::ClientArgs;
14pub use config::{ClientConfig, load_client_config};
15pub use connector::ClientState;
16pub use error::ClientError;
17
18use std::sync::Arc;
19use std::time::Duration;
20
21use tokio::net::TcpListener;
22use tokio_rustls::TlsConnector;
23use tokio_util::sync::CancellationToken;
24use tracing::{error, info};
25use trojan_auth::sha224_hex;
26use trojan_core::defaults::DEFAULT_TLS_HANDSHAKE_TIMEOUT_SECS;
27use trojan_dns::DnsResolver;
28
29pub async fn run(config: ClientConfig, shutdown: CancellationToken) -> Result<(), ClientError> {
31 let hash_hex = sha224_hex(&config.client.password);
33
34 let dns_resolver = DnsResolver::new(&config.client.dns)
36 .map_err(|e| ClientError::Config(format!("dns resolver: {e}")))?;
37 info!(dns = ?config.client.dns.strategy, "dns resolver initialized");
38
39 let tls_config = connector::build_tls_config(&config.client.tls)?;
41 let tls_connector = TlsConnector::from(Arc::new(tls_config));
42 let sni = connector::resolve_sni(&config.client.tls, &config.client.remote)?;
43
44 let state = Arc::new(ClientState {
45 hash_hex,
46 remote_addr: config.client.remote.clone(),
47 tls_connector,
48 sni,
49 tcp_config: config.client.tcp.clone(),
50 tls_handshake_timeout: Duration::from_secs(DEFAULT_TLS_HANDSHAKE_TIMEOUT_SECS),
51 dns_resolver,
52 });
53
54 let listener = TcpListener::bind(&config.client.listen).await?;
56 info!(listen = %config.client.listen, remote = %config.client.remote, "trojan client started");
57
58 loop {
59 tokio::select! {
60 result = listener.accept() => {
61 match result {
62 Ok((stream, peer)) => {
63 let state = state.clone();
64 tokio::spawn(async move {
65 handler::handle_socks5_conn(stream, peer, state).await;
66 });
67 }
68 Err(e) => {
69 error!(error = %e, "failed to accept connection");
70 }
71 }
72 }
73 _ = shutdown.cancelled() => {
74 info!("shutting down client");
75 break;
76 }
77 }
78 }
79
80 Ok(())
81}