diff --git a/src/args.rs b/src/args.rs index bd9d413..b0766f6 100644 --- a/src/args.rs +++ b/src/args.rs @@ -16,7 +16,7 @@ pub struct Args { /// Name of the tun interface, such as tun0, utun4, etc. /// If this option is not provided, the OS will generate a random one. - #[arg(short, long, value_name = "name", conflicts_with = "tun_fd")] + #[arg(short, long, value_name = "name", conflicts_with = "tun_fd", value_parser = validate_tun)] pub tun: Option, /// File descriptor of the tun interface @@ -31,7 +31,7 @@ pub struct Args { /// File descriptor for UNIX datagram socket meant to transfer /// network sockets from global namespace to the new one. /// See `unshare(1)`, `namespaces(7)`, `sendmsg(2)`, `unix(7)`. - #[arg(long)] + #[arg(long, value_name = "fd")] pub socket_transfer_fd: Option, /// Specify a command to run with root-like capabilities in the new namespace. @@ -43,9 +43,9 @@ pub struct Args { #[arg(short = '6', long)] pub ipv6_enabled: bool, - #[arg(short, long)] /// Routing and system setup, which decides whether to setup the routing and system configuration. /// This option is only available on Linux and requires root-like privileges. See `capabilities(7)`. + #[arg(short, long, default_value = if cfg!(target_os = "linux") { "false" } else { "true" })] pub setup: bool, /// DNS handling strategy @@ -73,8 +73,20 @@ pub struct Args { pub verbosity: ArgVerbosity, } +fn validate_tun(p: &str) -> Result { + #[cfg(target_os = "macos")] + if p.len() <= 4 || &p[..4] != "utun" { + return Err(Error::from("Invalid tun interface name, please use utunX")); + } + Ok(p.to_string()) +} + impl Default for Args { fn default() -> Self { + #[cfg(target_os = "linux")] + let setup = false; + #[cfg(not(target_os = "linux"))] + let setup = true; Args { proxy: ArgProxy::default(), tun: None, @@ -83,7 +95,7 @@ impl Default for Args { socket_transfer_fd: None, admin_command: Vec::new(), ipv6_enabled: false, - setup: false, + setup, dns: ArgDns::default(), dns_addr: "8.8.8.8".parse().unwrap(), bypass: vec![], @@ -95,9 +107,16 @@ impl Default for Args { } impl Args { + #[allow(clippy::let_and_return)] pub fn parse_args() -> Self { use clap::Parser; - Self::parse() + let args = Self::parse(); + #[cfg(target_os = "linux")] + if !args.setup && args.tun.is_none() { + eprintln!("Missing required argument, '--tun' must present when '--setup' is not used."); + std::process::exit(-1); + } + args } pub fn proxy(&mut self, proxy: ArgProxy) -> &mut Self { diff --git a/src/desktop_api.rs b/src/desktop_api.rs index 71f67dc..72da377 100644 --- a/src/desktop_api.rs +++ b/src/desktop_api.rs @@ -83,25 +83,25 @@ pub unsafe extern "C" fn tun2proxy_with_name_run( pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::CancellationToken) -> std::io::Result<()> { let bypass_ips = args.bypass.clone(); - let mut config = tun2::Configuration::default(); - config.address(TUN_IPV4).netmask(TUN_NETMASK).mtu(MTU).up(); - config.destination(TUN_GATEWAY); + let mut tun_config = tun2::Configuration::default(); + tun_config.address(TUN_IPV4).netmask(TUN_NETMASK).mtu(MTU).up(); + tun_config.destination(TUN_GATEWAY); if let Some(tun_fd) = args.tun_fd { - config.raw_fd(tun_fd); + tun_config.raw_fd(tun_fd); } else if let Some(ref tun) = args.tun { - config.tun_name(tun); + tun_config.tun_name(tun); } #[cfg(target_os = "linux")] - config.platform_config(|config| { + tun_config.platform_config(|cfg| { #[allow(deprecated)] - config.packet_information(true); - config.ensure_root_privileges(args.setup); + cfg.packet_information(true); + cfg.ensure_root_privileges(args.setup); }); #[cfg(target_os = "windows")] - config.platform_config(|config| { - config.device_guid(Some(12324323423423434234_u128)); + tun_config.platform_config(|cfg| { + cfg.device_guid(Some(12324323423423434234_u128)); }); #[allow(unused_variables)] @@ -113,7 +113,7 @@ pub async fn desktop_run_async(args: Args, shutdown_token: tokio_util::sync::Can #[allow(unused_mut, unused_assignments, unused_variables)] let mut setup = true; - let device = tun2::create_as_async(&config)?; + let device = tun2::create_as_async(&tun_config)?; if let Ok(tun_name) = device.as_ref().tun_name() { tproxy_args = tproxy_args.tun_name(&tun_name);