From 7136e2a20c63526f217c1ce9ca05f4ced26b0bba Mon Sep 17 00:00:00 2001 From: ssrlive <30760636+ssrlive@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:18:40 +0800 Subject: [PATCH] refactor desktop_run_async --- Cargo.toml | 2 +- cbindgen.toml | 1 + src/bin/main.rs | 3 +- src/desktop_api.rs | 116 ++++++++++++++++++++++++++++----------------- src/mobile_api.rs | 101 +++++++++++++++++++-------------------- src/win_svc.rs | 2 +- 6 files changed, 127 insertions(+), 98 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 171b742..e93e99b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tun2proxy" -version = "0.6.7" +version = "0.7.0" edition = "2021" license = "MIT" repository = "https://github.com/tun2proxy/tun2proxy" diff --git a/cbindgen.toml b/cbindgen.toml index 8354c6c..10e4235 100644 --- a/cbindgen.toml +++ b/cbindgen.toml @@ -3,6 +3,7 @@ cpp_compat = true [export] include = [ + "tun2proxy_run_with_cli", "tun2proxy_with_fd_run", "tun2proxy_with_name_run", "tun2proxy_with_name_stop", diff --git a/src/bin/main.rs b/src/bin/main.rs index e39b7b4..d5b1ebe 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,3 +1,4 @@ +use tun::DEFAULT_MTU as MTU; use tun2proxy::{Args, BoxError}; fn main() -> Result<(), BoxError> { @@ -49,7 +50,7 @@ async fn main_async(args: Args) -> Result<(), BoxError> { } unsafe { tun2proxy::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; - if let Err(err) = tun2proxy::desktop_run_async(args, shutdown_token).await { + if let Err(err) = tun2proxy::desktop_run_async(args, MTU, false, shutdown_token).await { log::error!("main loop error: {}", err); } } diff --git a/src/desktop_api.rs b/src/desktop_api.rs index 17428fb..ed8dbb5 100644 --- a/src/desktop_api.rs +++ b/src/desktop_api.rs @@ -5,7 +5,6 @@ use crate::{ ArgVerbosity, Args, }; use std::os::raw::{c_char, c_int}; -use tproxy_config::{TproxyArgs, TUN_GATEWAY, TUN_IPV4, TUN_NETMASK}; use tun::{AbstractDevice, DEFAULT_MTU as MTU}; static TUN_QUIT: std::sync::Mutex> = std::sync::Mutex::new(None); @@ -29,6 +28,42 @@ pub unsafe extern "C" fn tun2proxy_with_name_run( _root_privilege: bool, verbosity: ArgVerbosity, ) -> c_int { + let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap(); + let proxy = ArgProxy::try_from(proxy_url).unwrap(); + let tun = std::ffi::CStr::from_ptr(tun).to_str().unwrap().to_string(); + + let mut args = Args::default(); + if let Ok(bypass) = std::ffi::CStr::from_ptr(bypass).to_str() { + args.bypass(bypass.parse().unwrap()); + } + args.proxy(proxy).tun(tun).dns(dns_strategy).verbosity(verbosity); + + #[cfg(target_os = "linux")] + args.setup(_root_privilege); + + desktop_run(args) +} + +/// # Safety +/// Run the tun2proxy component with command line arguments +/// Parameters: +/// - cli_args: The command line arguments, +/// e.g. `tun2proxy-bin --setup --proxy socks5://127.0.0.1:1080 --bypass 98.76.54.0/24 --dns over-tcp --verbosity trace` +#[no_mangle] +pub unsafe extern "C" fn tun2proxy_run_with_cli_args(cli_args: *const c_char) -> c_int { + let Ok(cli_args) = std::ffi::CStr::from_ptr(cli_args).to_str() else { + return -5; + }; + let args = ::parse_from(cli_args.split_whitespace()); + desktop_run(args) +} + +pub fn desktop_run(args: Args) -> c_int { + log::set_max_level(args.verbosity.into()); + if let Err(err) = log::set_boxed_logger(Box::::default()) { + log::warn!("set logger error: {}", err); + } + let shutdown_token = tokio_util::sync::CancellationToken::new(); { if let Ok(mut lock) = TUN_QUIT.lock() { @@ -41,51 +76,38 @@ pub unsafe extern "C" fn tun2proxy_with_name_run( } } - log::set_max_level(verbosity.into()); - if let Err(err) = log::set_boxed_logger(Box::::default()) { - log::warn!("set logger error: {}", err); - } - - let proxy_url = std::ffi::CStr::from_ptr(proxy_url).to_str().unwrap(); - let proxy = ArgProxy::try_from(proxy_url).unwrap(); - let tun = std::ffi::CStr::from_ptr(tun).to_str().unwrap().to_string(); - - let mut args = Args::default(); - args.proxy(proxy).tun(tun).dns(dns_strategy).verbosity(verbosity); - - #[cfg(target_os = "linux")] - args.setup(_root_privilege); - - if let Ok(bypass) = std::ffi::CStr::from_ptr(bypass).to_str() { - args.bypass(bypass.parse().unwrap()); - } - - let main_loop = async move { - if let Err(err) = desktop_run_async(args, shutdown_token).await { + let Ok(rt) = tokio::runtime::Builder::new_multi_thread().enable_all().build() else { + return -3; + }; + let res = rt.block_on(async move { + if let Err(err) = desktop_run_async(args, MTU, false, shutdown_token).await { log::error!("main loop error: {}", err); return Err(err); } Ok(()) - }; - - let exit_code = match tokio::runtime::Builder::new_multi_thread().enable_all().build() { - Err(_e) => -3, - Ok(rt) => match rt.block_on(main_loop) { - Ok(_) => 0, - Err(_e) => -4, - }, - }; - - exit_code + }); + match res { + Ok(_) => 0, + Err(_) => -4, + } } /// Run the tun2proxy component with some arguments. -pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::CancellationToken) -> std::io::Result<()> { - let bypass_ips = args.bypass.clone(); - +pub async fn desktop_run_async( + args: Args, + tun_mtu: u16, + _packet_information: bool, + shutdown_token: tokio_util::sync::CancellationToken, +) -> std::io::Result<()> { let mut tun_config = tun::Configuration::default(); - tun_config.address(TUN_IPV4).netmask(TUN_NETMASK).mtu(MTU).up(); - tun_config.destination(TUN_GATEWAY); + + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] + { + use tproxy_config::{TUN_GATEWAY, TUN_IPV4, TUN_NETMASK}; + tun_config.address(TUN_IPV4).netmask(TUN_NETMASK).mtu(tun_mtu).up(); + tun_config.destination(TUN_GATEWAY); + } + #[cfg(unix)] if let Some(fd) = args.tun_fd { tun_config.raw_fd(fd); @@ -112,11 +134,17 @@ pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::Can cfg.device_guid(12324323423423434234_u128); }); + #[cfg(any(target_os = "ios", target_os = "macos"))] + tun_config.platform_config(|cfg| { + cfg.packet_information(_packet_information); + }); + + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] #[allow(unused_variables)] - let mut tproxy_args = TproxyArgs::new() + let mut tproxy_args = tproxy_config::TproxyArgs::new() .tun_dns(args.dns_addr) .proxy_addr(args.proxy.addr) - .bypass_ips(&bypass_ips) + .bypass_ips(&args.bypass) .ipv6_default_route(args.ipv6_enabled); #[allow(unused_mut, unused_assignments, unused_variables)] @@ -124,12 +152,14 @@ pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::Can let device = tun::create_as_async(&tun_config)?; + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] if let Ok(tun_name) = device.tun_name() { tproxy_args = tproxy_args.tun_name(&tun_name); } // TproxyState implements the Drop trait to restore network configuration, // so we need to assign it to a variable, even if it is not used. + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] let mut _restore: Option = None; #[cfg(target_os = "linux")] @@ -166,10 +196,8 @@ pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::Can } } - let join_handle = tokio::spawn(crate::run(device, MTU, args, shutdown_token)); - join_handle.await.map_err(std::io::Error::from)??; - - Ok::<(), std::io::Error>(()) + let join_handle = tokio::spawn(crate::run(device, tun_mtu, args, shutdown_token)); + Ok(join_handle.await.map_err(std::io::Error::from)??) } /// # Safety diff --git a/src/mobile_api.rs b/src/mobile_api.rs index a32f68d..3f885d5 100644 --- a/src/mobile_api.rs +++ b/src/mobile_api.rs @@ -8,68 +8,67 @@ static TUN_QUIT: std::sync::Mutex> = /// Dummy function to make the build pass. #[doc(hidden)] #[cfg(not(target_os = "macos"))] -pub async fn desktop_run_async(_: Args, _: tokio_util::sync::CancellationToken) -> std::io::Result<()> { +pub async fn desktop_run_async(_: Args, _: u16, _: bool, _: tokio_util::sync::CancellationToken) -> std::io::Result<()> { Ok(()) } +pub async fn mobile_run_async( + args: Args, + tun_mtu: u16, + _packet_information: bool, + shutdown_token: tokio_util::sync::CancellationToken, +) -> std::io::Result<()> { + let mut config = tun::Configuration::default(); + + #[cfg(unix)] + if let Some(fd) = args.tun_fd { + config.raw_fd(fd); + if let Some(v) = args.close_fd_on_drop { + config.close_fd_on_drop(v); + }; + } else if let Some(ref tun) = args.tun { + config.tun_name(tun); + } + #[cfg(windows)] + if let Some(ref tun) = args.tun { + config.tun_name(tun); + } + + #[cfg(any(target_os = "ios", target_os = "macos"))] + config.platform_config(|config| { + config.packet_information(_packet_information); + }); + + let device = tun::create_as_async(&config).map_err(std::io::Error::from)?; + let join_handle = tokio::spawn(crate::run(device, tun_mtu, args, shutdown_token)); + + Ok(join_handle.await.map_err(std::io::Error::from)??) +} + pub fn mobile_run(args: Args, tun_mtu: u16, _packet_information: bool) -> c_int { let shutdown_token = tokio_util::sync::CancellationToken::new(); - { - if let Ok(mut lock) = TUN_QUIT.lock() { - if lock.is_some() { - log::error!("tun2proxy already started"); - return -1; - } - *lock = Some(shutdown_token.clone()); - } else { - log::error!("failed to lock tun2proxy quit token"); - return -2; + if let Ok(mut lock) = TUN_QUIT.lock() { + if lock.is_some() { + log::error!("tun2proxy already started"); + return -1; } + *lock = Some(shutdown_token.clone()); + } else { + log::error!("failed to lock tun2proxy quit token"); + return -2; } - let block = async move { - let mut config = tun::Configuration::default(); - - #[cfg(unix)] - if let Some(fd) = args.tun_fd { - config.raw_fd(fd); - if let Some(v) = args.close_fd_on_drop { - config.close_fd_on_drop(v); - }; - } else if let Some(ref tun) = args.tun { - config.tun_name(tun); - } - #[cfg(windows)] - if let Some(ref tun) = args.tun { - config.tun_name(tun); - } - - #[cfg(any(target_os = "ios", target_os = "macos"))] - config.platform_config(|config| { - config.packet_information(_packet_information); - }); - - let device = tun::create_as_async(&config).map_err(std::io::Error::from)?; - let join_handle = tokio::spawn(crate::run(device, tun_mtu, args, shutdown_token)); - - join_handle.await.map_err(std::io::Error::from)? + let Ok(rt) = tokio::runtime::Builder::new_multi_thread().enable_all().build() else { + log::error!("failed to create tokio runtime with"); + return -1; }; - - let exit_code = match tokio::runtime::Builder::new_multi_thread().enable_all().build() { + match rt.block_on(mobile_run_async(args, tun_mtu, _packet_information, shutdown_token)) { + Ok(_) => 0, Err(e) => { - log::error!("failed to create tokio runtime with error: {:?}", e); - -1 + log::error!("failed to run tun2proxy with error: {:?}", e); + -2 } - Ok(rt) => match rt.block_on(block) { - Ok(_) => 0, - Err(e) => { - log::error!("failed to run tun2proxy with error: {:?}", e); - -2 - } - }, - }; - - exit_code + } } pub fn mobile_stop() -> c_int { diff --git a/src/win_svc.rs b/src/win_svc.rs index afca2f1..e775049 100644 --- a/src/win_svc.rs +++ b/src/win_svc.rs @@ -78,7 +78,7 @@ fn run_service(_arguments: Vec) -> Result<(), crate::BoxErro } unsafe { crate::tun2proxy_set_traffic_status_callback(1, Some(traffic_cb), std::ptr::null_mut()) }; - if let Err(err) = crate::desktop_run_async(args, shutdown_token).await { + if let Err(err) = crate::desktop_run_async(args, tun::DEFAULT_MTU, false, shutdown_token).await { log::error!("main loop error: {}", err); } Ok::<(), crate::Error>(())