From a68c8abe487f788e57c3daed6456c08c29a861f5 Mon Sep 17 00:00:00 2001 From: lbl <49143209+lbl8603@users.noreply.github.com> Date: Sat, 31 Aug 2024 00:08:24 +0800 Subject: [PATCH] set_ignore_packet_info --- README.md | 5 -- examples/ping-tun.rs | 6 +-- examples/write.rs | 9 ++-- src/device.rs | 10 ++-- src/platform/android/device.rs | 4 +- src/platform/freebsd/device.rs | 4 +- src/platform/ios/device.rs | 12 +++-- src/platform/ios/mod.rs | 33 +----------- src/platform/linux/device.rs | 10 +--- src/platform/macos/device.rs | 12 +++-- src/platform/macos/mod.rs | 36 +------------ src/platform/posix/fd.rs | 1 + src/platform/posix/tun.rs | 98 ++++++++++++++++++---------------- 13 files changed, 88 insertions(+), 152 deletions(-) diff --git a/README.md b/README.md index 38a5c8b..aff11af 100644 --- a/README.md +++ b/README.md @@ -99,11 +99,6 @@ class PacketTunnelProvider: NEPacketTunnelProvider { pub extern "C" fn start_tun(fd: std::os::raw::c_int) { let mut rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(async { - let mut cfg = tun_rs::Configuration::default(); - #[cfg(target_os = "ios")] - cfg.platform_config(|p_cfg| { - p_cfg.packet_information(true); - }); // This is safe if the provided fd is valid let tun = unsafe{tun_rs::AsyncDevice::from_raw_fd(fd)}; let mut buf = [0u8;1500]; diff --git a/examples/ping-tun.rs b/examples/ping-tun.rs index 208942f..c7cb61b 100644 --- a/examples/ping-tun.rs +++ b/examples/ping-tun.rs @@ -40,12 +40,10 @@ async fn main_entry(mut quit: Receiver<()>) -> Result<(), BoxError> { config.device_guid(9099482345783245345345_u128); }); + let dev = tun_rs::create_as_async(&config)?; #[cfg(target_os = "macos")] - config.platform_config(|config| { - config.packet_information(false); - }); + dev.set_ignore_packet_info(true); - let dev = tun_rs::create_as_async(&config)?; let size = dev.mtu()? as usize + tun_rs::PACKET_INFORMATION_LENGTH; let mut buf = vec![0; size]; loop { diff --git a/examples/write.rs b/examples/write.rs index fb26e85..531b337 100644 --- a/examples/write.rs +++ b/examples/write.rs @@ -2,7 +2,7 @@ use packet::{builder::Builder, icmp, ip, Packet}; #[allow(unused_imports)] use std::sync::{mpsc::Receiver, Arc}; -use tun_rs::BoxError; +use tun_rs::{AbstractDevice, BoxError}; fn main() -> Result<(), BoxError> { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("trace")).init(); @@ -36,12 +36,9 @@ fn main_entry(quit: Receiver<()>) -> Result<(), BoxError> { // .destination((10, 0, 0, 1)) .up(); - #[cfg(target_os = "macos")] - config.platform_config(|config| { - config.packet_information(false); - }); - let dev = Arc::new(tun_rs::create(&config)?); + #[cfg(target_os = "macos")] + dev.set_ignore_packet_info(true); let mut buf = [0; 4096]; #[cfg(feature = "experimental")] diff --git a/src/device.rs b/src/device.rs index e4df00e..adcbbf7 100644 --- a/src/device.rs +++ b/src/device.rs @@ -98,9 +98,13 @@ pub trait AbstractDevice { ))] fn set_mtu(&self, value: u16) -> Result<()>; - /// Return whether the underlying tun device on the platform has packet information - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios",))] - fn packet_information(&self) -> bool; + /// Ignore packet-information during reading and writing + #[cfg(any(target_os = "macos", target_os = "ios"))] + fn ignore_packet_info(&self) -> bool; + + /// Ignore packet-information during reading and writing + #[cfg(any(target_os = "macos", target_os = "ios"))] + fn set_ignore_packet_info(&self, ign: bool); /// Set mac address #[cfg(any(target_os = "windows", target_os = "linux", target_os = "freebsd",))] diff --git a/src/platform/android/device.rs b/src/platform/android/device.rs index 8d0395f..cf9ce8e 100644 --- a/src/platform/android/device.rs +++ b/src/platform/android/device.rs @@ -12,9 +12,7 @@ pub struct Device { impl FromRawFd for Device { unsafe fn from_raw_fd(fd: RawFd) -> Self { let tun = Fd::new(fd, true).unwrap(); - Device { - tun: Tun::new(tun, false), - } + Device { tun: Tun::new(tun) } } } diff --git a/src/platform/freebsd/device.rs b/src/platform/freebsd/device.rs index 852b7ae..832d2bc 100644 --- a/src/platform/freebsd/device.rs +++ b/src/platform/freebsd/device.rs @@ -40,7 +40,7 @@ impl FromRawFd for Device { unsafe fn from_raw_fd(fd: RawFd) -> Self { let tun = Fd::new(fd, true).unwrap(); Device { - tun: Tun::new(tun, false), + tun: Tun::new(tun), ctl: unsafe { ctl().unwrap() }, alias_lock: Mutex::new(()), } @@ -110,7 +110,7 @@ impl Device { }; Device { - tun: Tun::new(tun, false), + tun: Tun::new(tun), ctl, alias_lock: Mutex::new(()), } diff --git a/src/platform/ios/device.rs b/src/platform/ios/device.rs index 46b62a9..189f6f5 100644 --- a/src/platform/ios/device.rs +++ b/src/platform/ios/device.rs @@ -16,9 +16,7 @@ pub struct Device { impl FromRawFd for Device { unsafe fn from_raw_fd(fd: RawFd) -> Self { let tun = Fd::new(fd, true).unwrap(); - Device { - tun: Tun::new(tun, true), - } + Device { tun: Tun::new(tun) } } } @@ -45,8 +43,12 @@ impl Device { } impl AbstractDevice for Device { - fn packet_information(&self) -> bool { - self.tun.packet_information() + fn ignore_packet_info(&self) -> bool { + self.tun.ignore_packet_info() + } + + fn set_ignore_packet_info(&self, ign: bool) { + self.tun.set_ignore_packet_info(ign) } } diff --git a/src/platform/ios/mod.rs b/src/platform/ios/mod.rs index b936edb..8be49b1 100644 --- a/src/platform/ios/mod.rs +++ b/src/platform/ios/mod.rs @@ -7,37 +7,8 @@ use crate::configuration::Configuration; use crate::error::Result; /// iOS-only interface configuration. -#[derive(Copy, Clone, Debug)] -pub struct PlatformConfig { - /// switch of Enable/Disable packet information for network driver - pub(crate) packet_information: bool, -} - -impl Default for PlatformConfig { - fn default() -> Self { - PlatformConfig { - packet_information: true, // default is true in iOS - } - } -} - -impl PlatformConfig { - /// Enable or disable packet information, the first 4 bytes of - /// each packet delivered from/to iOS underlying API is a header with flags and protocol type when enabled. - /// - /// - If get the fd from - /// ```Objective-C - /// int32_t tunFd = [[NEPacketTunnelProvider::packetFlow valueForKeyPath:@"socket.fileDescriptor"] intValue]; - /// ``` - /// there exist PI. - /// - /// - But if get packet from `[NEPacketTunnelProvider::packetFlow readPacketsWithCompletionHandler:]` - /// and write packet via `[NEPacketTunnelProvider::packetFlow writePackets:withProtocols:]`, there is no PI. - pub fn packet_information(&mut self, value: bool) -> &mut Self { - self.packet_information = value; - self - } -} +#[derive(Copy, Clone, Debug, Default)] +pub struct PlatformConfig; use super::Device as DeviceWrapper; /// Create a TUN device with the given name. diff --git a/src/platform/linux/device.rs b/src/platform/linux/device.rs index 778fd6b..cef7a75 100644 --- a/src/platform/linux/device.rs +++ b/src/platform/linux/device.rs @@ -31,9 +31,7 @@ pub struct Device { impl FromRawFd for Device { unsafe fn from_raw_fd(fd: RawFd) -> Self { let tun = Fd::new(fd, true).unwrap(); - Device { - tun: Tun::new(tun, false), - } + Device { tun: Tun::new(tun) } } } @@ -80,7 +78,7 @@ impl Device { } let device = Device { - tun: Tun::new(tun_fd, config.platform_config.packet_information), + tun: Tun::new(tun_fd), }; configure(&device, config)?; Ok(device) @@ -345,10 +343,6 @@ impl AbstractDevice for Device { } } - fn packet_information(&self) -> bool { - self.tun.packet_information() - } - fn set_mac_address(&self, eth_addr: [u8; ETHER_ADDR_LEN as usize]) -> Result<()> { unsafe { let mut req = self.request()?; diff --git a/src/platform/macos/device.rs b/src/platform/macos/device.rs index 1044d4a..a9230cd 100644 --- a/src/platform/macos/device.rs +++ b/src/platform/macos/device.rs @@ -44,7 +44,7 @@ impl FromRawFd for Device { unsafe fn from_raw_fd(fd: RawFd) -> Self { let tun = Fd::new(fd, true).unwrap(); Device { - tun: Tun::new(tun, true), + tun: Tun::new(tun), alias_lock: Mutex::new(()), } } @@ -115,7 +115,7 @@ impl Device { let ctl = Some(posix::Fd::new(libc::socket(AF_INET, SOCK_DGRAM, 0), true)?); Device { - tun: posix::Tun::new(tun, config.platform_config.packet_information), + tun: posix::Tun::new(tun), alias_lock: Mutex::new(()), } }; @@ -474,8 +474,12 @@ impl AbstractDevice for Device { Ok(()) } - fn packet_information(&self) -> bool { - self.tun.packet_information() + fn ignore_packet_info(&self) -> bool { + self.tun.ignore_packet_info() + } + + fn set_ignore_packet_info(&self, ign: bool) { + self.tun.set_ignore_packet_info(ign) } } diff --git a/src/platform/macos/mod.rs b/src/platform/macos/mod.rs index 040e8eb..22f0146 100644 --- a/src/platform/macos/mod.rs +++ b/src/platform/macos/mod.rs @@ -9,40 +9,8 @@ use crate::configuration::Configuration; use crate::error::Result; /// macOS-only interface configuration. -#[derive(Copy, Clone, Debug)] -pub struct PlatformConfig { - pub(crate) packet_information: bool, -} - -impl Default for PlatformConfig { - fn default() -> Self { - PlatformConfig { - packet_information: true, // default is true in macOS - } - } -} - -impl PlatformConfig { - /// Enable or disable packet information, the first 4 bytes of - /// each packet delivered from/to macOS underlying API is a header with flags and protocol type when enabled. - /// - /// - If we open an `utun` device, there always exist PI. - /// - /// - If we use `Network Extension` to build our App: - /// - /// - If get the fd from - /// ```Objective-C - /// int32_t tunFd = [[NEPacketTunnelProvider::packetFlow valueForKeyPath:@"socket.fileDescriptor"] intValue]; - /// ``` - /// there exist PI. - /// - /// - But if get packet from `[NEPacketTunnelProvider::packetFlow readPacketsWithCompletionHandler:]` - /// and write packet via `[NEPacketTunnelProvider::packetFlow writePackets:withProtocols:]`, there is no PI. - pub fn packet_information(&mut self, value: bool) -> &mut Self { - self.packet_information = value; - self - } -} +#[derive(Copy, Clone, Debug, Default)] +pub struct PlatformConfig; use super::Device as DeviceWrapper; /// Create a TUN device with the given name. diff --git a/src/platform/posix/fd.rs b/src/platform/posix/fd.rs index 60c5569..a3cbcb1 100644 --- a/src/platform/posix/fd.rs +++ b/src/platform/posix/fd.rs @@ -50,6 +50,7 @@ impl Fd { Ok(amount as usize) } + #[inline] pub fn write(&self, buf: &[u8]) -> io::Result { let fd = self.as_raw_fd(); let amount = unsafe { libc::write(fd, buf.as_ptr() as *const _, buf.len()) }; diff --git a/src/platform/posix/tun.rs b/src/platform/posix/tun.rs index 64fa6ed..8e48842 100644 --- a/src/platform/posix/tun.rs +++ b/src/platform/posix/tun.rs @@ -1,10 +1,15 @@ use crate::platform::posix::Fd; +#[cfg(any(target_os = "macos", target_os = "ios"))] use crate::PACKET_INFORMATION_LENGTH as PIL; +#[cfg(any(target_os = "macos", target_os = "ios"))] use bytes::BufMut; use std::io::{self, Read, Write}; use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use std::sync::atomic::{AtomicBool, Ordering}; /// Infer the protocol based on the first nibble in the packet buffer. +#[cfg(any(target_os = "macos", target_os = "ios"))] pub(crate) fn is_ipv6(buf: &[u8]) -> std::io::Result { use std::io::{Error, ErrorKind::InvalidData}; if buf.is_empty() { @@ -16,11 +21,8 @@ pub(crate) fn is_ipv6(buf: &[u8]) -> std::io::Result { p => Err(Error::new(InvalidData, format!("IP version {}", p))), } } - -pub(crate) fn generate_packet_information( - _packet_information: bool, - _ipv6: bool, -) -> Option<[u8; PIL]> { +#[cfg(any(target_os = "macos", target_os = "ios"))] +pub(crate) fn generate_packet_information(_ipv6: bool) -> Option<[u8; PIL]> { #[cfg(any(target_os = "linux", target_os = "android"))] const TUN_PROTO_IP6: [u8; PIL] = (libc::ETH_P_IPV6 as u32).to_be_bytes(); #[cfg(any(target_os = "linux", target_os = "android"))] @@ -37,17 +39,13 @@ pub(crate) fn generate_packet_information( #[cfg(target_os = "freebsd")] const TUN_PROTO_IP4: [u8; PIL] = 0x0800_u32.to_be_bytes(); - #[cfg(unix)] - if _packet_information { - if _ipv6 { - return Some(TUN_PROTO_IP6); - } else { - return Some(TUN_PROTO_IP4); - } + if _ipv6 { + Some(TUN_PROTO_IP6) + } else { + Some(TUN_PROTO_IP4) } - None } - +#[cfg(any(target_os = "macos", target_os = "ios"))] #[rustversion::since(1.79)] macro_rules! local_buf_util { ($e:expr,$size:expr) => { @@ -59,7 +57,7 @@ macro_rules! local_buf_util { } }; } - +#[cfg(any(target_os = "macos", target_os = "ios"))] #[rustversion::before(1.79)] macro_rules! local_buf_util { ($e:expr,$size:expr) =>{ @@ -90,14 +88,14 @@ macro_rules! local_buf_util { } } } - +#[cfg(any(target_os = "macos", target_os = "ios"))] #[rustversion::since(1.79)] macro_rules! need_mut { ($id:ident, $e:expr) => { let $id = $e; }; } - +#[cfg(any(target_os = "macos", target_os = "ios"))] #[rustversion::before(1.79)] macro_rules! need_mut { ($id:ident, $e:expr) => { @@ -107,78 +105,84 @@ macro_rules! need_mut { pub struct Tun { pub(crate) fd: Fd, - pub(crate) offset: usize, - pub(crate) packet_information: bool, + #[cfg(any(target_os = "macos", target_os = "ios"))] + ignore_packet_information: AtomicBool, } impl Tun { - pub(crate) fn new(fd: Fd, packet_information: bool) -> Self { - #[cfg(any(target_os = "macos", target_os = "ios"))] - let offset = if !packet_information { PIL } else { 0 }; - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - let offset = 0; + pub(crate) fn new(fd: Fd) -> Self { Self { fd, - offset, - packet_information, + #[cfg(any(target_os = "macos", target_os = "ios"))] + ignore_packet_information: AtomicBool::new(false), } } pub fn set_nonblock(&self) -> io::Result<()> { self.fd.set_nonblock() } - - pub fn packet_information(&self) -> bool { - self.packet_information + #[cfg(not(any(target_os = "macos", target_os = "ios")))] + pub(crate) fn send(&self, in_buf: &[u8]) -> io::Result { + self.fd.write(in_buf) } - + #[cfg(any(target_os = "macos", target_os = "ios"))] pub(crate) fn send(&self, in_buf: &[u8]) -> io::Result { - if self.offset != 0 { + if self.ignore_packet_info() { let ipv6 = is_ipv6(in_buf)?; - if let Some(header) = generate_packet_information(true, ipv6) { + if let Some(header) = generate_packet_information(ipv6) { const STACK_BUF_LEN: usize = crate::DEFAULT_MTU as usize + PIL; - let in_buf_len = in_buf.len() + self.offset; + let in_buf_len = in_buf.len() + PIL; // The following logic is to prevent dynamically allocating Vec on every send // As long as the MTU is set to value lesser than 1500, this api uses `stack_buf` // and avoids `Vec` allocation - let local_buf_v0 = - local_buf_util!(in_buf_len > STACK_BUF_LEN && self.offset != 0, in_buf_len); + let local_buf_v0 = local_buf_util!(in_buf_len > STACK_BUF_LEN, in_buf_len); need_mut! {local_buf_v1,local_buf_v0}; #[allow(clippy::useless_asref)] let local_buf = local_buf_v1.as_mut(); - (&mut local_buf[..self.offset]).put_slice(header.as_ref()); - (&mut local_buf[self.offset..in_buf_len]).put_slice(in_buf); + (&mut local_buf[..PIL]).put_slice(header.as_ref()); + (&mut local_buf[PIL..in_buf_len]).put_slice(in_buf); let amount = self.fd.write(&local_buf[..in_buf_len])?; - return Ok(amount - self.offset); + return Ok(amount - PIL); } } - let amount = self.fd.write(in_buf)?; - Ok(amount - self.offset) + self.fd.write(in_buf) } - + #[cfg(not(any(target_os = "macos", target_os = "ios")))] + pub(crate) fn recv(&self, in_buf: &mut [u8]) -> io::Result { + self.fd.read(in_buf) + } + #[cfg(any(target_os = "macos", target_os = "ios"))] pub(crate) fn recv(&self, mut in_buf: &mut [u8]) -> io::Result { - if self.offset != 0 { + if self.ignore_packet_info() { const STACK_BUF_LEN: usize = crate::DEFAULT_MTU as usize + PIL; - let in_buf_len = in_buf.len() + self.offset; + let in_buf_len = in_buf.len() + PIL; // The following logic is to prevent dynamically allocating Vec on every recv // As long as the MTU is set to value lesser than 1500, this api uses `stack_buf` // and avoids `Vec` allocation - let local_buf_v0 = - local_buf_util!(in_buf_len > STACK_BUF_LEN && self.offset != 0, in_buf_len); + let local_buf_v0 = local_buf_util!(in_buf_len > STACK_BUF_LEN, in_buf_len); need_mut! {local_buf_v1,local_buf_v0}; #[allow(clippy::useless_asref)] let local_buf = local_buf_v1.as_mut(); let amount = self.fd.read(local_buf)?; - in_buf.put_slice(&local_buf[self.offset..amount]); - Ok(amount - self.offset) + in_buf.put_slice(&local_buf[PIL..amount]); + Ok(amount - PIL) } else { self.fd.read(in_buf) } } + #[cfg(any(target_os = "macos", target_os = "ios"))] + #[inline] + pub(crate) fn ignore_packet_info(&self) -> bool { + self.ignore_packet_information.load(Ordering::Relaxed) + } + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub(crate) fn set_ignore_packet_info(&self, ign: bool) { + self.ignore_packet_information.store(ign, Ordering::Relaxed) + } #[cfg(feature = "experimental")] pub(crate) fn shutdown(&self) -> io::Result<()> { self.fd.shutdown()