From 48c5c23f9bf4f85e1e753e740050b6b1a9475000 Mon Sep 17 00:00:00 2001 From: Chenx Dust Date: Sun, 11 Jan 2026 16:36:58 +0800 Subject: [PATCH] feat: support compile for iOS (#1777) --- easytier/Cargo.toml | 2 +- easytier/src/common/network.rs | 2 +- easytier/src/connector/mod.rs | 6 +++++- easytier/src/gateway/tcp_proxy.rs | 6 +++++- easytier/src/instance/instance.rs | 24 ++++++++++++++++-------- easytier/src/instance/virtual_nic.rs | 22 +++++++++++++++------- easytier/src/launcher.rs | 13 +++++++------ 7 files changed, 50 insertions(+), 25 deletions(-) diff --git a/easytier/Cargo.toml b/easytier/Cargo.toml index 596ee360..05ab4062 100644 --- a/easytier/Cargo.toml +++ b/easytier/Cargo.toml @@ -194,7 +194,7 @@ service-manager = { git = "https://github.com/EasyTier/service-manager-rs.git", zstd = { version = "0.13" } -kcp-sys = { git = "https://github.com/EasyTier/kcp-sys", rev = "71eff18c573a4a71bf99c7fabc6a8b9f211c84c1" } +kcp-sys = { git = "https://github.com/EasyTier/kcp-sys", rev = "94964794caaed5d388463137da59b97499619e5f" } prost-reflect = { version = "0.14.5", default-features = false, features = [ "derive", diff --git a/easytier/src/common/network.rs b/easytier/src/common/network.rs index ac8061d9..df48ab46 100644 --- a/easytier/src/common/network.rs +++ b/easytier/src/common/network.rs @@ -16,7 +16,7 @@ struct InterfaceFilter { iface: NetworkInterface, } -#[cfg(any(target_os = "android", target_env = "ohos"))] +#[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] impl InterfaceFilter { async fn filter_iface(&self) -> bool { true diff --git a/easytier/src/connector/mod.rs b/easytier/src/connector/mod.rs index d0653262..5fe5e15e 100644 --- a/easytier/src/connector/mod.rs +++ b/easytier/src/connector/mod.rs @@ -31,7 +31,11 @@ async fn set_bind_addr_for_peer_connector( is_ipv4: bool, ip_collector: &Arc, ) { - if cfg!(any(target_os = "android", target_env = "ohos")) { + if cfg!(any( + target_os = "android", + target_os = "ios", + target_env = "ohos" + )) { return; } diff --git a/easytier/src/gateway/tcp_proxy.rs b/easytier/src/gateway/tcp_proxy.rs index bcd4da3c..9544f7d1 100644 --- a/easytier/src/gateway/tcp_proxy.rs +++ b/easytier/src/gateway/tcp_proxy.rs @@ -526,7 +526,11 @@ impl TcpProxy { #[cfg(feature = "smoltcp")] if self.global_ctx.get_flags().use_smoltcp || self.global_ctx.no_tun() - || cfg!(any(target_os = "android", target_env = "ohos")) + || cfg!(any( + target_os = "android", + target_os = "ios", + target_env = "ohos" + )) { // use smoltcp network stack diff --git a/easytier/src/instance/instance.rs b/easytier/src/instance/instance.rs index 8b6011e2..9bdb68a7 100644 --- a/easytier/src/instance/instance.rs +++ b/easytier/src/instance/instance.rs @@ -104,8 +104,12 @@ impl IpProxy { self.tcp_proxy.start(true).await?; if let Err(e) = self.icmp_proxy.start().await { tracing::error!("start icmp proxy failed: {:?}", e); - if cfg!(not(any(target_os = "android", target_env = "ohos"))) { - // android and ohos not support icmp proxy + if cfg!(not(any( + target_os = "android", + target_os = "ios", + target_env = "ohos" + ))) { + // android, ios and ohos not support icmp proxy return Err(e); } } @@ -772,7 +776,11 @@ impl Instance { continue; } - #[cfg(not(any(target_os = "android", target_env = "ohos")))] + #[cfg(not(any( + target_os = "android", + target_os = "ios", + target_env = "ohos" + )))] { let mut new_nic_ctx = NicCtx::new( global_ctx_c.clone(), @@ -906,7 +914,7 @@ impl Instance { Self::clear_nic_ctx(self.nic_ctx.clone(), self.peer_packet_receiver.clone()).await; if !self.global_ctx.config.get_flags().no_tun { - #[cfg(not(any(target_os = "android", target_env = "ohos")))] + #[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] { let (output_tx, output_rx) = oneshot::channel(); self.check_for_static_ip(output_tx); @@ -1402,15 +1410,15 @@ impl Instance { self.peer_packet_receiver.clone() } - #[cfg(any(target_os = "android", target_env = "ohos"))] - pub async fn setup_nic_ctx_for_android( + #[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] + pub async fn setup_nic_ctx_for_mobile( nic_ctx: ArcNicCtx, global_ctx: ArcGlobalCtx, peer_manager: Arc, peer_packet_receiver: Arc>, fd: i32, ) -> Result<(), anyhow::Error> { - println!("setup_nic_ctx_for_android, fd: {}", fd); + tracing::info!("setup_nic_ctx_for_mobile, fd: {}", fd); Self::clear_nic_ctx(nic_ctx.clone(), peer_packet_receiver.clone()).await; if fd <= 0 { return Ok(()); @@ -1423,7 +1431,7 @@ impl Instance { close_notifier.clone(), ); new_nic_ctx - .run_for_android(fd) + .run_for_mobile(fd) .await .with_context(|| "add ip failed")?; diff --git a/easytier/src/instance/virtual_nic.rs b/easytier/src/instance/virtual_nic.rs index 42d47cbf..8f9cc749 100644 --- a/easytier/src/instance/virtual_nic.rs +++ b/easytier/src/instance/virtual_nic.rs @@ -442,26 +442,34 @@ impl VirtualNic { Ok(tun::create(&config)?) } - #[cfg(any(target_os = "android", target_env = "ohos"))] - pub async fn create_dev_for_android( + #[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] + pub async fn create_dev_for_mobile( &mut self, tun_fd: std::os::fd::RawFd, ) -> Result, Error> { println!("tun_fd: {}", tun_fd); let mut config = Configuration::default(); config.layer(Layer::L3); + + #[cfg(target_os = "ios")] + config.platform_config(|config| { + // disable packet information so we can process the header by ourselves, see tun2 impl for more details + config.packet_information(false); + }); + config.raw_fd(tun_fd); config.close_fd_on_drop(false); config.up(); + let has_packet_info = cfg!(target_os = "ios"); let dev = tun::create(&config)?; let dev = AsyncDevice::new(dev)?; let (a, b) = BiLock::new(dev); let ft = TunnelWrapper::new( - TunStream::new(a, false), + TunStream::new(a, has_packet_info), FramedWriter::new_with_converter( TunAsyncWrite { l: b }, - TunZCPacketToBytes::new(false), + TunZCPacketToBytes::new(has_packet_info), ), None, ); @@ -1008,11 +1016,11 @@ impl NicCtx { Ok(()) } - #[cfg(any(target_os = "android", target_env = "ohos"))] - pub async fn run_for_android(&mut self, tun_fd: std::os::fd::RawFd) -> Result<(), Error> { + #[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] + pub async fn run_for_mobile(&mut self, tun_fd: std::os::fd::RawFd) -> Result<(), Error> { let tunnel = { let mut nic = self.nic.lock().await; - match nic.create_dev_for_android(tun_fd).await { + match nic.create_dev_for_mobile(tun_fd).await { Ok(ret) => { self.global_ctx .issue_event(GlobalCtxEvent::TunDeviceReady(nic.ifname().to_string())); diff --git a/easytier/src/launcher.rs b/easytier/src/launcher.rs index 9c946d33..17b8ff91 100644 --- a/easytier/src/launcher.rs +++ b/easytier/src/launcher.rs @@ -93,8 +93,8 @@ impl EasyTierLauncher { } } - #[cfg(any(target_os = "android", target_env = "ohos"))] - async fn run_routine_for_android( + #[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] + async fn run_routine_for_mobile( instance: &Instance, data: &EasyTierData, tasks: &mut JoinSet<()>, @@ -111,8 +111,9 @@ impl EasyTierLauncher { let Some(tun_fd) = tun_fd_receiver.recv().await.flatten() else { return; }; - if Some(tun_fd) != old_tun_fd { - let res = Instance::setup_nic_ctx_for_android( + // iOS needs to re-setup nic ctx even if the tun fd is the same + if Some(tun_fd) != old_tun_fd || cfg!(target_os = "ios") { + let res = Instance::setup_nic_ctx_for_mobile( nic_ctx.clone(), global_ctx.clone(), peer_mgr.clone(), @@ -158,8 +159,8 @@ impl EasyTierLauncher { } }); - #[cfg(any(target_os = "android", target_env = "ohos"))] - Self::run_routine_for_android(&instance, &data, &mut tasks).await; + #[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] + Self::run_routine_for_mobile(&instance, &data, &mut tasks).await; instance.run().await?;