Skip to main content

overtls/
lib.rs

1pub(crate) mod android;
2pub(crate) mod api;
3pub(crate) mod client;
4pub(crate) mod cmdopt;
5pub(crate) mod config;
6pub(crate) mod dns;
7pub(crate) mod dump_logger;
8pub(crate) mod error;
9pub(crate) mod panel_sync;
10pub(crate) mod server;
11pub(crate) mod tcp_stream;
12pub(crate) mod tls;
13pub(crate) mod traffic_audit;
14pub(crate) mod traffic_status;
15pub(crate) mod udprelay;
16pub(crate) mod weirduri;
17pub mod win_svc;
18
19pub use api::{over_tls_client_run, over_tls_client_run_with_ssr_url, over_tls_client_stop, overtls_free_string, overtls_generate_url};
20use bytes::BytesMut;
21pub use client::run_client;
22pub use cmdopt::{ArgVerbosity, CmdOpt, Role};
23pub use config::{Client as ClientConfig, Config, PanelSync, Server as ServerConfig, TunnelPath};
24pub use dump_logger::overtls_set_log_callback;
25pub use error::{BoxError, Error, Result};
26pub use server::run_server;
27use socks5_impl::protocol::{Address, StreamOperation};
28pub use tokio_util::sync::CancellationToken;
29pub use traffic_status::{TrafficStatus, overtls_set_traffic_status_callback};
30
31#[cfg(target_os = "windows")]
32pub(crate) const STREAM_BUFFER_SIZE: usize = 1024 * 32;
33#[cfg(not(target_os = "windows"))]
34pub(crate) const STREAM_BUFFER_SIZE: usize = 1024 * 32 * 3;
35
36pub(crate) fn ensure_rustls_crypto_provider() -> Result<()> {
37    if rustls::crypto::CryptoProvider::get_default().is_some() {
38        return Ok(());
39    }
40
41    let install_result = rustls::crypto::ring::default_provider().install_default();
42
43    if rustls::crypto::CryptoProvider::get_default().is_none() {
44        if let Err(e) = install_result {
45            return Err(Error::from(format!("failed to install rustls ring CryptoProvider: {e:?}")));
46        } else {
47            return Err(Error::from(
48                "failed to install rustls ring CryptoProvider: provider is still not set after successful installation",
49            ));
50        }
51    }
52
53    Ok(())
54}
55
56pub(crate) fn addess_to_b64str(addr: &Address, url_safe: bool) -> String {
57    let mut buf = BytesMut::with_capacity(1024);
58    addr.write_to_buf(&mut buf);
59    if url_safe {
60        base64easy::encode(&buf, base64easy::EngineKind::UrlSafeNoPad)
61    } else {
62        base64easy::encode(&buf, base64easy::EngineKind::StandardNoPad)
63    }
64}
65
66pub(crate) fn b64str_to_address(s: &str, url_safe: bool) -> Result<Address> {
67    let buf = if url_safe {
68        let result = base64easy::decode(s, base64easy::EngineKind::UrlSafeNoPad);
69        if result.is_err() {
70            base64easy::decode(s, base64easy::EngineKind::UrlSafe)?
71        } else {
72            result?
73        }
74    } else {
75        let result = base64easy::decode(s, base64easy::EngineKind::StandardNoPad);
76        if result.is_err() {
77            // backward compatibility for SSRoT
78            base64easy::decode(s, base64easy::EngineKind::Standard)?
79        } else {
80            result?
81        }
82    };
83    Address::try_from(&buf[..]).map_err(|e| e.into())
84}
85
86#[doc(hidden)]
87pub async fn async_main(config: Config, allow_shutdown: bool, shutdown_token: CancellationToken) -> Result<()> {
88    let ctrlc_fired = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
89    let mut ctrlc_handle = None;
90    if allow_shutdown {
91        let shutdown_token_clone = shutdown_token.clone();
92        let ctrlc_fired_clone = ctrlc_fired.clone();
93        let handle = ctrlc2::AsyncCtrlC::new(move || {
94            log::info!("Ctrl-C received, exiting...");
95            ctrlc_fired_clone.store(true, std::sync::atomic::Ordering::SeqCst);
96            shutdown_token_clone.cancel();
97            true
98        })?;
99        ctrlc_handle = Some(handle);
100    }
101
102    let main_body = async {
103        if config.is_server {
104            if config.exist_server() {
105                run_server(&config, shutdown_token).await?;
106            } else {
107                return Err(Error::from("Config is not a server config"));
108            }
109        } else if config.exist_client() {
110            let callback = |addr| {
111                log::trace!("Listening on {addr}");
112            };
113            run_client(&config, shutdown_token, Some(callback)).await?;
114        } else {
115            return Err("Config is not a client config".into());
116        }
117
118        if ctrlc_fired.load(std::sync::atomic::Ordering::SeqCst) {
119            let Some(handle) = ctrlc_handle else {
120                return Ok(());
121            };
122            log::info!("Waiting for Ctrl-C handler to finish...");
123            handle.await.map_err(|e| e.to_string())?;
124        }
125        Ok(())
126    };
127
128    if let Err(e) = main_body.await {
129        log::error!("main_body error: \"{e}\"");
130    }
131
132    Ok(())
133}