diff --git a/crates/shadowsocks/src/net/mod.rs b/crates/shadowsocks/src/net/mod.rs index c8c824b864eb..22c5b56b3353 100644 --- a/crates/shadowsocks/src/net/mod.rs +++ b/crates/shadowsocks/src/net/mod.rs @@ -10,6 +10,8 @@ pub use self::{ tcp::{TcpListener, TcpStream}, udp::UdpSocket, }; +#[cfg(target_os = "android")] +pub use self::option::android::{CloneFn, SocketProtectFn, socket_protect_fn}; mod option; mod sys; diff --git a/crates/shadowsocks/src/net/option.rs b/crates/shadowsocks/src/net/option.rs index 24c7f3376981..1a9b707e7360 100644 --- a/crates/shadowsocks/src/net/option.rs +++ b/crates/shadowsocks/src/net/option.rs @@ -59,6 +59,8 @@ pub struct ConnectOpts { /// This is an [Android shadowsocks implementation](https://github.com/shadowsocks/shadowsocks-android) specific feature #[cfg(target_os = "android")] pub vpn_protect_path: Option, + #[cfg(target_os = "android")] + pub vpn_socket_protect_fn: Option>>, /// Outbound socket binds to this IP address, mostly for choosing network interfaces /// @@ -87,3 +89,56 @@ pub struct AcceptOpts { /// Enable IPV6_V6ONLY option for socket pub ipv6_only: bool, } + +#[cfg(target_os = "android")] +pub mod android { + pub fn socket_protect_fn(f: F) -> SocketProtectFn> + where + F: Fn(i32) + Send + Sync + Clone + 'static, + { + SocketProtectFn { + f: Box::new(f), + } + } + + pub trait CloneFn: Fn(i32) + Send + Sync { + fn clone_box(&self) -> Box; + } + + impl CloneFn for F + where + F: Fn(i32), + { + fn clone_box(&self) -> Box { + Box::new(self.clone()) + } + } + + pub struct SocketProtectFn { + f: F, + } + + impl SocketProtectFn + where + F: Fn(i32) + Send + Sync + Clone + 'static + { + pub fn call(&self, fd: i32) { + (self.f)(fd) + } + } + + impl Clone for SocketProtectFn> + { + fn clone(&self) -> Self { + Self { + f: self.f.clone_box(), + } + } + } + + impl std::fmt::Debug for SocketProtectFn { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("SocketProtectFn").finish() + } + } +} diff --git a/crates/shadowsocks/src/net/sys/unix/linux/mod.rs b/crates/shadowsocks/src/net/sys/unix/linux/mod.rs index 76ca4cc8f8d6..ddf448024676 100644 --- a/crates/shadowsocks/src/net/sys/unix/linux/mod.rs +++ b/crates/shadowsocks/src/net/sys/unix/linux/mod.rs @@ -68,6 +68,10 @@ impl TcpStream { Err(..) => return Err(io::Error::new(ErrorKind::TimedOut, "protect() timeout")), } } + + if let Some(ref protect_fn) = opts.vpn_socket_protect_fn { + protect_fn.call(socket.as_raw_fd()); + } } // Set SO_MARK for mark-based routing on Linux (since 2.6.25) @@ -344,6 +348,10 @@ pub async fn bind_outbound_udp_socket(bind_addr: &SocketAddr, config: &ConnectOp Err(..) => return Err(io::Error::new(ErrorKind::TimedOut, "protect() timeout")), } } + + if let Some(ref protect_fn) = opts.vpn_socket_protect_fn { + protect_fn.call(socket.as_raw_fd()); + } } // Set SO_MARK for mark-based routing on Linux (since 2.6.25)