diff --git a/Cargo.toml b/Cargo.toml index 9925869..63ec162 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "overtls" -version = "0.2.19" +version = "0.2.20" edition = "2021" license = "MIT" description = "A simple proxy tunnel, minimalist tool for bypassing the GFW." @@ -40,6 +40,7 @@ rustls-pemfile = "2.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" socks5-impl = "0.5" +socket2 = "0.5" thiserror = "1.0" tokio = { version = "1", features = ["full"] } tokio-rustls = { version = "0.26", default-features = false, features = [ diff --git a/src/api.rs b/src/api.rs index 241cff2..92a4e20 100644 --- a/src/api.rs +++ b/src/api.rs @@ -40,8 +40,10 @@ pub unsafe extern "C" fn over_tls_client_run( ctx: *mut c_void, ) -> c_int { log::set_max_level(verbosity.into()); - if let Err(err) = log::set_boxed_logger(Box::::default()) { - log::info!("failed to set logger, error={:?}", err); + if !crate::dump_logger::check_logger() { + if let Err(err) = log::set_boxed_logger(Box::::default()) { + log::warn!("failed to set logger, error={:?}", err); + } } let config_path = std::ffi::CStr::from_ptr(config_path).to_str(); if let Err(err) = config_path { @@ -82,8 +84,10 @@ pub unsafe extern "C" fn over_tls_client_run_with_ssr_url( ctx: *mut c_void, ) -> c_int { log::set_max_level(verbosity.into()); - if let Err(err) = log::set_boxed_logger(Box::::default()) { - log::info!("failed to set logger, error={:?}", err); + if !crate::dump_logger::check_logger() { + if let Err(err) = log::set_boxed_logger(Box::::default()) { + log::warn!("failed to set logger, error={:?}", err); + } } let url = std::ffi::CStr::from_ptr(url).to_str(); if let Err(err) = url { diff --git a/src/bin/overtls.rs b/src/bin/overtls.rs index 6a733e3..3984da6 100644 --- a/src/bin/overtls.rs +++ b/src/bin/overtls.rs @@ -23,7 +23,7 @@ fn main() -> Result<()> { unsafe extern "C" fn log_cb(_: overtls::ArgVerbosity, msg: *const std::os::raw::c_char, _ctx: *mut std::os::raw::c_void) { println!("{:?}", unsafe { std::ffi::CStr::from_ptr(msg).to_str() }); } - unsafe { overtls::overtls_set_log_callback(Some(log_cb), std::ptr::null_mut()) }; + unsafe { overtls::overtls_set_log_callback(true, Some(log_cb), std::ptr::null_mut()) }; unsafe extern "C" fn port_cb(port: i32, _ctx: *mut std::os::raw::c_void) { log::info!("Listening on {}", port); diff --git a/src/client.rs b/src/client.rs index 9827595..2c45a76 100644 --- a/src/client.rs +++ b/src/client.rs @@ -37,8 +37,11 @@ where F: FnOnce(SocketAddr) + Send + Sync + 'static, { log::info!("starting {} {} client...", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); - log::trace!("with following settings:"); - log::trace!("{}", serde_json::to_string_pretty(config)?); + #[cfg(not(target_os = "ios"))] + { + log::trace!("with following settings:"); + log::trace!("{}", serde_json::to_string_pretty(config)?); + } let client = config.client.as_ref().ok_or("client")?; @@ -232,7 +235,7 @@ pub(crate) async fn create_plaintext_ws_stream( config: &Config, udp_tunnel: Option, ) -> Result> { - let stream = crate::tcp_stream::create(server_addr).await?; + let stream = crate::tcp_stream::tokio_create(server_addr).await?; let ws_stream = create_ws_stream(dst_addr, config, udp_tunnel, stream).await?; Ok(ws_stream) } diff --git a/src/config.rs b/src/config.rs index b3a4cba..659e421 100644 --- a/src/config.rs +++ b/src/config.rs @@ -303,10 +303,9 @@ impl Config { if !self.is_server { let mut addr = (server_host, client.server_port).to_socket_addrs()?; let addr = addr.next().ok_or("address not available")?; - #[cfg(not(target_os = "android"))] { let timeout = std::time::Duration::from_secs(self.test_timeout_secs); - std::net::TcpStream::connect_timeout(&addr, timeout)?; + crate::tcp_stream::std_create(addr, Some(timeout))?; } if client.listen_host.is_empty() { client.listen_host = if addr.is_ipv4() { diff --git a/src/dump_logger.rs b/src/dump_logger.rs index 67e97f6..bab8d93 100644 --- a/src/dump_logger.rs +++ b/src/dump_logger.rs @@ -5,15 +5,29 @@ use std::{ }; static DUMP_CALLBACK: Mutex> = Mutex::new(None); +static LOGGER_SETTED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); + +pub(crate) fn check_logger() -> bool { + LOGGER_SETTED.load(std::sync::atomic::Ordering::SeqCst) +} /// # Safety /// /// set dump log info callback. #[no_mangle] pub unsafe extern "C" fn overtls_set_log_callback( + set_logger: bool, callback: Option, ctx: *mut c_void, ) { + if set_logger { + LOGGER_SETTED.store(true, std::sync::atomic::Ordering::Relaxed); + log::set_max_level(log::LevelFilter::Trace); + if let Err(err) = log::set_boxed_logger(Box::::default()) { + log::warn!("failed to set logger, error={:?}", err); + } + } + if let Ok(mut cb) = DUMP_CALLBACK.lock() { *cb = Some(DumpCallback(callback, ctx)); } else { @@ -44,14 +58,25 @@ impl log::Log for DumpLogger { } fn log(&self, record: &log::Record) { + #[cfg(not(target_os = "ios"))] if self.enabled(record.metadata()) { let current_crate_name = env!("CARGO_CRATE_NAME"); if record.module_path().unwrap_or("").starts_with(current_crate_name) { if let Err(err) = self.do_dump_log(record) { - log::error!("failed to dump log, error={:?}", err); + eprint!("failed to dump log, error={:?}", err); } } } + #[cfg(target_os = "ios")] + if self.enabled(record.metadata()) { + let module = record.module_path().unwrap_or(""); + if module.starts_with("rustls") || module.starts_with("tungstenite") || module.starts_with("tokio_tungstenite") { + return; + } + if let Err(err) = self.do_dump_log(record) { + eprint!("failed to dump log, error={:?}", err); + } + } } fn flush(&self) {} @@ -59,14 +84,17 @@ impl log::Log for DumpLogger { impl DumpLogger { fn do_dump_log(&self, record: &log::Record) -> Result<(), BoxError> { - let timestamp: chrono::DateTime = chrono::Local::now(); + let _timestamp: chrono::DateTime = chrono::Local::now(); + #[cfg(not(target_os = "ios"))] let msg = format!( "[{} {:<5} {}] - {}", - timestamp.format("%Y-%m-%d %H:%M:%S"), + _timestamp.format("%Y-%m-%d %H:%M:%S"), record.level(), record.module_path().unwrap_or(""), record.args() ); + #[cfg(target_os = "ios")] + let msg = format!("[{:<5} {}] - {}", record.level(), record.module_path().unwrap_or(""), record.args()); let c_msg = std::ffi::CString::new(msg)?; let ptr = c_msg.as_ptr(); if let Ok(cb) = DUMP_CALLBACK.lock() { diff --git a/src/server.rs b/src/server.rs index 9f18a1d..3739121 100644 --- a/src/server.rs +++ b/src/server.rs @@ -195,7 +195,7 @@ where let to_stream = create_tls_client_stream(cert_store, forward_addr, host).await?; forward_traffic(stream, to_stream, data).await } else { - let to_stream = crate::tcp_stream::create(forward_addr).await?; + let to_stream = crate::tcp_stream::tokio_create(forward_addr).await?; forward_traffic(stream, to_stream, data).await } } @@ -319,7 +319,7 @@ async fn normal_tunnel( client_id: &Option, dst_addr: SocketAddr, ) -> Result<()> { - let mut outgoing = crate::tcp_stream::create(dst_addr).await?; + let mut outgoing = crate::tcp_stream::tokio_create(dst_addr).await?; let mut buffer = [0; crate::STREAM_BUFFER_SIZE]; loop { tokio::select! { diff --git a/src/tcp_stream.rs b/src/tcp_stream.rs index bccb09f..44fe2dc 100644 --- a/src/tcp_stream.rs +++ b/src/tcp_stream.rs @@ -1,8 +1,4 @@ -use crate::error::Result; -use std::net::SocketAddr; -use tokio::net::TcpStream; - -pub(crate) async fn create(addr: SocketAddr) -> Result { +pub(crate) async fn tokio_create(addr: std::net::SocketAddr) -> std::io::Result { #[cfg(target_os = "android")] { let socket = if addr.is_ipv4() { @@ -20,5 +16,35 @@ pub(crate) async fn create(addr: SocketAddr) -> Result { } #[cfg(not(target_os = "android"))] - Ok(TcpStream::connect(addr).await?) + tokio::net::TcpStream::connect(addr).await +} + +pub(crate) fn std_create(addr: std::net::SocketAddr, timeout: Option) -> std::io::Result { + use socket2::{Domain, SockAddr, Socket, Type}; + let domain = if addr.is_ipv4() { Domain::IPV4 } else { Domain::IPV6 }; + let socket = Socket::new(domain, Type::STREAM, None)?; + + #[cfg(target_os = "android")] + { + use std::os::unix::io::AsRawFd; + crate::android::tun_callbacks::on_socket_created(socket.as_raw_fd()); + } + + if let Some(timeout) = timeout { + socket.connect_timeout(&SockAddr::from(addr), timeout)?; + } else { + socket.connect(&SockAddr::from(addr))?; + } + + #[cfg(unix)] + { + use std::os::unix::io::{FromRawFd, IntoRawFd}; + Ok(unsafe { std::net::TcpStream::from_raw_fd(socket.into_raw_fd()) }) + } + + #[cfg(windows)] + { + use std::os::windows::io::{FromRawSocket, IntoRawSocket}; + Ok(unsafe { std::net::TcpStream::from_raw_socket(socket.into_raw_socket()) }) + } } diff --git a/src/tls.rs b/src/tls.rs index f3f8488..e979c7e 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -45,7 +45,7 @@ pub(crate) async fn create_tls_client_stream( .with_no_client_auth(); let connector = TlsConnector::from(std::sync::Arc::new(config)); - let stream = crate::tcp_stream::create(addr).await?; + let stream = crate::tcp_stream::tokio_create(addr).await?; let domain = ServerName::try_from(domain)?.to_owned();