From 99036e716cecddb025a0e7d24dc4255201446f3d Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Fri, 20 Oct 2023 21:47:58 +0800 Subject: [PATCH 01/11] feat(local): basic support of macOS launchd activate socket https://developer.apple.com/documentation/xpc/1505523-launch_activate_socket https://www.manpagez.com/man/5/launchd.plist/ https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html --- README.md | 3 + crates/shadowsocks-service/src/config.rs | 60 +++++++++ .../src/local/redir/tcprelay/mod.rs | 2 +- .../src/local/socks/server/mod.rs | 50 ++++++-- .../src/local/socks/server/server.rs | 94 ++++++++++++--- .../src/local/socks/server/socks5/mod.rs | 5 +- .../src/local/socks/server/socks5/udprelay.rs | 114 +++++++++++++----- .../src/net/launch_activate_socket.rs | 22 ++++ crates/shadowsocks-service/src/net/mod.rs | 2 + .../shadowsocks-service/src/sys/unix/macos.rs | 82 +++++++++++++ .../shadowsocks-service/src/sys/unix/mod.rs | 9 ++ crates/shadowsocks/src/net/tcp.rs | 12 +- 12 files changed, 392 insertions(+), 63 deletions(-) create mode 100644 crates/shadowsocks-service/src/net/launch_activate_socket.rs create mode 100644 crates/shadowsocks-service/src/sys/unix/macos.rs diff --git a/README.md b/README.md index 4f27d2ee1f13..7b46afd9d17d 100644 --- a/README.md +++ b/README.md @@ -554,6 +554,9 @@ Example configuration: "socks5_auth_config_path": "/path/to/auth.json", // OPTIONAL. Instance specific ACL "acl": "/path/to/acl/file.acl", + // OPTIONAL. macOS launchd activate socket + "launchd_tcp_socket_name": "TCPListener", + "launchd_udp_socket_name": "UDPListener", }, { // SOCKS5, SOCKS4/4a local server diff --git a/crates/shadowsocks-service/src/config.rs b/crates/shadowsocks-service/src/config.rs index 0bc026cf9716..7835cf4f764e 100644 --- a/crates/shadowsocks-service/src/config.rs +++ b/crates/shadowsocks-service/src/config.rs @@ -240,6 +240,14 @@ struct SSLocalExtConfig { #[serde(skip_serializing_if = "Option::is_none")] protocol: Option, + /// macOS launch activate socket + #[cfg(target_os = "macos")] + #[serde(skip_serializing_if = "Option::is_none")] + launchd_udp_socket_name: Option, + #[cfg(target_os = "macos")] + #[serde(skip_serializing_if = "Option::is_none")] + launchd_tcp_socket_name: Option, + /// TCP Transparent Proxy type #[cfg(feature = "local-redir")] #[serde(skip_serializing_if = "Option::is_none")] @@ -888,6 +896,43 @@ pub struct LocalConfig { #[cfg(all(feature = "local-tun", unix))] pub tun_device_fd_from_path: Option, + /// macOS launchd socket for TCP listener + /// + /// + /// + /// + /// ```plist + /// Sockets + /// + /// {launchd_tcp_socket_name} + /// + /// SockType + /// stream + /// ... other keys ... + /// + /// + /// ``` + #[cfg(target_os = "macos")] + pub launchd_tcp_socket_name: Option, + /// macOS launchd socket for UDP listener + /// + /// + /// + /// + /// ```plist + /// Sockets + /// + /// {launchd_udp_socket_name} + /// + /// SockType + /// dgram + /// ... other keys ... + /// + /// + /// ``` + #[cfg(target_os = "macos")] + pub launchd_udp_socket_name: Option, + /// Set `IPV6_V6ONLY` for listener socket pub ipv6_only: bool, @@ -941,6 +986,11 @@ impl LocalConfig { #[cfg(all(feature = "local-tun", unix))] tun_device_fd_from_path: None, + #[cfg(target_os = "macos")] + launchd_tcp_socket_name: None, + #[cfg(target_os = "macos")] + launchd_udp_socket_name: None, + ipv6_only: false, #[cfg(feature = "local")] @@ -1465,6 +1515,12 @@ impl Config { local_config.udp_addr = Some(local_udp_addr); } + #[cfg(target_os = "macos")] + { + local_config.launchd_tcp_socket_name = local.launchd_tcp_socket_name; + local_config.launchd_udp_socket_name = local.launchd_udp_socket_name; + } + match local.mode { Some(mode) => match mode.parse::() { Ok(mode) => local_config.mode = mode, @@ -2423,6 +2479,10 @@ impl fmt::Display for Config { #[allow(unreachable_patterns)] p => Some(p.as_str().to_owned()), }, + #[cfg(target_os = "macos")] + launchd_tcp_socket_name: local.launchd_tcp_socket_name.clone(), + #[cfg(target_os = "macos")] + launchd_udp_socket_name: local.launchd_udp_socket_name.clone(), #[cfg(feature = "local-redir")] tcp_redir: if local.tcp_redir != RedirType::tcp_default() { Some(local.tcp_redir.to_string()) diff --git a/crates/shadowsocks-service/src/local/redir/tcprelay/mod.rs b/crates/shadowsocks-service/src/local/redir/tcprelay/mod.rs index 29324c690483..7c1f2aef8c6d 100644 --- a/crates/shadowsocks-service/src/local/redir/tcprelay/mod.rs +++ b/crates/shadowsocks-service/src/local/redir/tcprelay/mod.rs @@ -112,7 +112,7 @@ impl RedirTcpServer { /// Start serving pub async fn run(self) -> io::Result<()> { - let listener = ShadowTcpListener::from_listener(self.listener, self.context.accept_opts()); + let listener = ShadowTcpListener::from_listener(self.listener, self.context.accept_opts())?; let actual_local_addr = listener.local_addr().expect("determine port bound to"); diff --git a/crates/shadowsocks-service/src/local/socks/server/mod.rs b/crates/shadowsocks-service/src/local/socks/server/mod.rs index 1ccfd3b0bd19..0587e2107533 100644 --- a/crates/shadowsocks-service/src/local/socks/server/mod.rs +++ b/crates/shadowsocks-service/src/local/socks/server/mod.rs @@ -7,8 +7,8 @@ use shadowsocks::{config::Mode, ServerAddr}; use crate::local::{context::ServiceContext, loadbalancing::PingBalancer}; -pub use self::server::{SocksTcpServer, SocksUdpServer}; -use self::socks5::Socks5UdpServer; +pub use self::server::{SocksTcpServer, SocksTcpServerBuilder, SocksUdpServer}; +use self::socks5::Socks5UdpServerBuilder; use super::config::Socks5AuthConfig; @@ -28,6 +28,10 @@ pub struct SocksBuilder { socks5_auth: Socks5AuthConfig, client_config: ServerAddr, balancer: PingBalancer, + #[cfg(target_os = "macos")] + launchd_tcp_socket_name: Option, + #[cfg(target_os = "macos")] + launchd_udp_socket_name: Option, } impl SocksBuilder { @@ -52,6 +56,10 @@ impl SocksBuilder { socks5_auth: Socks5AuthConfig::default(), client_config, balancer, + #[cfg(target_os = "macos")] + launchd_tcp_socket_name: None, + #[cfg(target_os = "macos")] + launchd_udp_socket_name: None, } } @@ -83,33 +91,57 @@ impl SocksBuilder { self.socks5_auth = p; } + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + pub fn set_launchd_tcp_socket_name(&mut self, n: String) { + self.launchd_tcp_socket_name = Some(n); + } + + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + pub fn set_launchd_udp_socket_name(&mut self, n: String) { + self.launchd_udp_socket_name = Some(n); + } + pub async fn build(self) -> io::Result { let udp_bind_addr = self.udp_bind_addr.unwrap_or_else(|| self.client_config.clone()); let mut udp_server = None; if self.mode.enable_udp() { - let server = Socks5UdpServer::new( + let mut builder = Socks5UdpServerBuilder::new( self.context.clone(), - &udp_bind_addr, + udp_bind_addr.clone(), self.udp_expiry_duration, self.udp_capacity, self.balancer.clone(), - ) - .await?; + ); + + #[cfg(target_os = "macos")] + if let Some(s) = self.launchd_udp_socket_name { + builder.set_launchd_socket_name(s); + } + + let server = builder.build().await?; udp_server = Some(server); } let mut tcp_server = None; if self.mode.enable_tcp() { - let server = SocksTcpServer::new( + let mut builder = SocksTcpServerBuilder::new( self.context.clone(), self.client_config, udp_bind_addr, self.balancer.clone(), self.mode, self.socks5_auth, - ) - .await?; + ); + + #[cfg(target_os = "macos")] + if let Some(s) = self.launchd_tcp_socket_name { + builder.set_launchd_socket_name(s); + } + + let server = builder.build().await?; tcp_server = Some(server); } diff --git a/crates/shadowsocks-service/src/local/socks/server/server.rs b/crates/shadowsocks-service/src/local/socks/server/server.rs index f7bbaceaddb4..550183063254 100644 --- a/crates/shadowsocks-service/src/local/socks/server/server.rs +++ b/crates/shadowsocks-service/src/local/socks/server/server.rs @@ -12,46 +12,102 @@ use super::socks5::{Socks5TcpHandler, Socks5UdpServer}; use crate::local::socks::config::Socks5AuthConfig; -/// SOCKS TCP server instance -pub struct SocksTcpServer { +pub struct SocksTcpServerBuilder { context: Arc, - listener: ShadowTcpListener, + client_config: ServerAddr, udp_bind_addr: ServerAddr, balancer: PingBalancer, mode: Mode, socks5_auth: Arc, + launchd_socket_name: Option, } -impl SocksTcpServer { - pub(crate) async fn new( +impl SocksTcpServerBuilder { + pub(crate) fn new( context: Arc, client_config: ServerAddr, udp_bind_addr: ServerAddr, balancer: PingBalancer, mode: Mode, socks5_auth: Socks5AuthConfig, - ) -> io::Result { - let listener = match client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowTcpListener::bind_with_opts(saddr, context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(context.context_ref(), dname, port, |addr| { - ShadowTcpListener::bind_with_opts(&addr, context.accept_opts()).await - })? - .1 - } - }; - Ok(SocksTcpServer { + ) -> SocksTcpServerBuilder { + SocksTcpServerBuilder { context, - listener, + client_config, udp_bind_addr, balancer, mode, socks5_auth: Arc::new(socks5_auth), + launchd_socket_name: None, + } + } + + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + pub fn set_launchd_socket_name(&mut self, n: String) { + self.launchd_socket_name = Some(n); + } + + pub async fn build(self) -> io::Result { + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + let listener = if let Some(launchd_socket_name) = self.launchd_socket_name { + use tokio::net::TcpListener as TokioTcpListener; + use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; + + let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + ShadowTcpListener::from_listener(tokio_listener, self.context.accept_opts())? + } else { + match self.client_config { + ServerAddr::SocketAddr(ref saddr) => { + ShadowTcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(self.context.context_ref(), dname, port, |addr| { + ShadowTcpListener::bind_with_opts(&addr, self.context.accept_opts()).await + })? + .1 + } + } + }; + } else { + let listener = match client_config { + ServerAddr::SocketAddr(ref saddr) => { + ShadowTcpListener::bind_with_opts(saddr, context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(context.context_ref(), dname, port, |addr| { + ShadowTcpListener::bind_with_opts(&addr, context.accept_opts()).await + })? + .1 + } + }; + } + } + + Ok(SocksTcpServer { + context: self.context, + listener, + udp_bind_addr: self.udp_bind_addr, + balancer: self.balancer, + mode: self.mode, + socks5_auth: self.socks5_auth, }) } +} +/// SOCKS TCP server instance +pub struct SocksTcpServer { + context: Arc, + listener: ShadowTcpListener, + udp_bind_addr: ServerAddr, + balancer: PingBalancer, + mode: Mode, + socks5_auth: Arc, +} + +impl SocksTcpServer { /// Get TCP server local addr pub fn local_addr(&self) -> io::Result { self.listener.local_addr() diff --git a/crates/shadowsocks-service/src/local/socks/server/socks5/mod.rs b/crates/shadowsocks-service/src/local/socks/server/socks5/mod.rs index c2138b5cee8e..05525f184ce9 100644 --- a/crates/shadowsocks-service/src/local/socks/server/socks5/mod.rs +++ b/crates/shadowsocks-service/src/local/socks/server/socks5/mod.rs @@ -1,6 +1,9 @@ //! SOCKS5 Local Server -pub use self::{tcprelay::Socks5TcpHandler, udprelay::Socks5UdpServer}; +pub use self::{ + tcprelay::Socks5TcpHandler, + udprelay::{Socks5UdpServer, Socks5UdpServerBuilder}, +}; mod tcprelay; mod udprelay; diff --git a/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs b/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs index 16948ebe375e..65917be9e610 100644 --- a/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs +++ b/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs @@ -31,6 +31,90 @@ use crate::{ net::utils::to_ipv4_mapped, }; +pub struct Socks5UdpServerBuilder { + context: Arc, + client_config: ServerAddr, + time_to_live: Option, + capacity: Option, + balancer: PingBalancer, + #[cfg(target_os = "macos")] + launchd_socket_name: Option, +} + +impl Socks5UdpServerBuilder { + pub(crate) fn new( + context: Arc, + client_config: ServerAddr, + time_to_live: Option, + capacity: Option, + balancer: PingBalancer, + ) -> Socks5UdpServerBuilder { + Socks5UdpServerBuilder { + context, + client_config, + time_to_live, + capacity, + balancer, + #[cfg(target_os = "macos")] + launchd_socket_name: None, + } + } + + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + pub fn set_launchd_socket_name(&mut self, n: String) { + self.launchd_socket_name = Some(n); + } + + pub async fn build(self) -> io::Result { + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + let socket = if let Some(launchd_socket_name) = self.launchd_socket_name { + use tokio::net::UdpSocket as TokioUdpSocket; + use crate::net::launch_activate_socket::get_launch_activate_udp_socket; + + let std_socket = get_launch_activate_udp_socket(&launchd_socket_name)?; + TokioUdpSocket::from_std(std_socket)? + } else { + let shadow_socket = match self.client_config { + ServerAddr::SocketAddr(ref saddr) => { + ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(self.context.context_ref(), dname, port, |addr| { + ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await + })? + .1 + } + }; + shadow_socket.into() + }; + } else { + let shadow_socket = match self.client_config { + ServerAddr::SocketAddr(ref saddr) => { + ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(self.context.context_ref(), dname, port, |addr| { + ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await + })? + .1 + } + }; + let socket = shadow_socket.into(); + } + } + + Ok(Socks5UdpServer { + context: self.context, + time_to_live: self.time_to_live, + capacity: self.capacity, + listener: Arc::new(socket), + balancer: self.balancer, + }) + } +} + #[derive(Clone)] struct Socks5UdpInboundWriter { inbound: Arc, @@ -77,36 +161,6 @@ pub struct Socks5UdpServer { } impl Socks5UdpServer { - pub(crate) async fn new( - context: Arc, - client_config: &ServerAddr, - time_to_live: Option, - capacity: Option, - balancer: PingBalancer, - ) -> io::Result { - let socket = match *client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowUdpSocket::listen_with_opts(saddr, context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(context.context_ref(), dname, port, |addr| { - ShadowUdpSocket::listen_with_opts(&addr, context.accept_opts()).await - })? - .1 - } - }; - let socket: UdpSocket = socket.into(); - let listener = Arc::new(socket); - - Ok(Socks5UdpServer { - context, - time_to_live, - capacity, - listener, - balancer, - }) - } - /// Server's listen address pub fn local_addr(&self) -> io::Result { self.listener.local_addr() diff --git a/crates/shadowsocks-service/src/net/launch_activate_socket.rs b/crates/shadowsocks-service/src/net/launch_activate_socket.rs new file mode 100644 index 000000000000..d7be24860371 --- /dev/null +++ b/crates/shadowsocks-service/src/net/launch_activate_socket.rs @@ -0,0 +1,22 @@ +//! macOS launch activate socket +//! +//! +//! + +use std::{ + io, + net::{TcpListener, UdpSocket}, + os::unix::io::FromRawFd, +}; + +use crate::sys::get_launch_activate_socket; + +pub fn get_launch_activate_tcp_listener(name: &str) -> io::Result { + let fd = get_launch_activate_socket(name)?; + Ok(unsafe { TcpListener::from_raw_fd(fd) }) +} + +pub fn get_launch_activate_udp_socket(name: &str) -> io::Result { + let fd = get_launch_activate_socket(name)?; + Ok(unsafe { UdpSocket::from_raw_fd(fd) }) +} diff --git a/crates/shadowsocks-service/src/net/mod.rs b/crates/shadowsocks-service/src/net/mod.rs index 648aa56ae7a6..44ea46cc9ef1 100644 --- a/crates/shadowsocks-service/src/net/mod.rs +++ b/crates/shadowsocks-service/src/net/mod.rs @@ -3,6 +3,8 @@ pub use self::{flow::FlowStat, mon_socket::MonProxySocket, mon_stream::MonProxyStream}; pub mod flow; +#[cfg(target_os = "macos")] +pub mod launch_activate_socket; pub mod mon_socket; pub mod mon_stream; pub mod packet_window; diff --git a/crates/shadowsocks-service/src/sys/unix/macos.rs b/crates/shadowsocks-service/src/sys/unix/macos.rs new file mode 100644 index 000000000000..4f8fc2f0e8a5 --- /dev/null +++ b/crates/shadowsocks-service/src/sys/unix/macos.rs @@ -0,0 +1,82 @@ +//! macOS specific APIs + +use std::{ffi::CString, io, os::fd::RawFd, ptr}; + +use log::error; + +extern "C" { + /// https://developer.apple.com/documentation/xpc/1505523-launch_activate_socket + fn launch_activate_socket( + name: *const libc::c_char, + fds: *mut *mut libc::c_int, + cnt: *mut libc::size_t, + ) -> libc::c_int; +} + +pub fn get_launch_activate_socket(name: &str) -> io::Result { + let mut fds: *mut libc::c_int = ptr::null_mut(); + let mut cnt: libc::size_t = 0; + + let cname = match CString::new(name) { + Ok(n) => n, + Err(..) => { + return Err(io::Error::new( + io::ErrorKind::Other, + format!("activate socket name \"{}\" contains NUL bytes", name), + )); + } + }; + + unsafe { + let ret = launch_activate_socket(cname.as_ptr(), &mut fds as *mut _, &mut cnt as *mut _); + if ret != 0 { + let err = io::Error::last_os_error(); + match err.raw_os_error() { + Some(libc::ENOENT) => { + error!("activate socket name \"{}\" doesn't exist", name); + } + Some(libc::ESRCH) => { + error!("current process is not managed by launchd"); + } + Some(libc::EALREADY) => { + error!("activate socket name \"{}\" has already been activated", name); + } + _ => {} + } + + return Err(err); + } + } + + let result = if cnt == 0 { + Err(io::Error::new( + io::ErrorKind::InvalidInput, + format!("could not find launch socket with name \"{}\"", name), + )) + } else if cnt > 1 { + for idx in 0..cnt { + unsafe { + let fd = *(fds.offset(idx as isize)); + let _ = libc::close(fd); + } + } + + Err(io::Error::new( + io::ErrorKind::InvalidData, + format!( + "launch socket with name \"{}\" should be unique, but found {}", + name, cnt + ), + )) + } else { + // Take fds[0] as the result + let fd = unsafe { *fds }; + Ok(fd as RawFd) + }; + + if !fds.is_null() { + unsafe { libc::free(fds as *mut _) }; + } + + result +} diff --git a/crates/shadowsocks-service/src/sys/unix/mod.rs b/crates/shadowsocks-service/src/sys/unix/mod.rs index 2c85aeb8c42e..78d1c8311f5f 100644 --- a/crates/shadowsocks-service/src/sys/unix/mod.rs +++ b/crates/shadowsocks-service/src/sys/unix/mod.rs @@ -1,5 +1,14 @@ use std::io; +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(target_os = "macos")] { + mod macos; + pub use self::macos::*; + } +} + #[allow(dead_code)] #[cfg(not(target_os = "android"))] pub fn set_nofile(nofile: u64) -> io::Result<()> { diff --git a/crates/shadowsocks/src/net/tcp.rs b/crates/shadowsocks/src/net/tcp.rs index b89e4dac478e..09fce110db27 100644 --- a/crates/shadowsocks/src/net/tcp.rs +++ b/crates/shadowsocks/src/net/tcp.rs @@ -166,11 +166,17 @@ impl TcpListener { } /// Create a `TcpListener` from tokio's `TcpListener` - pub fn from_listener(listener: TokioTcpListener, accept_opts: AcceptOpts) -> TcpListener { - TcpListener { + pub fn from_listener(listener: TokioTcpListener, accept_opts: AcceptOpts) -> io::Result { + // Enable TFO if supported + // macos requires TCP_FASTOPEN to be set after listen(), but other platform doesn't have this constraint + if accept_opts.tcp.fastopen { + set_tcp_fastopen(&listener)?; + } + + Ok(TcpListener { inner: listener, accept_opts, - } + }) } /// Polls to accept a new incoming connection to this listener. From 6ff791f10bde8e7276bc9f9d2a1b1d061c8d3c1c Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Fri, 20 Oct 2023 21:52:24 +0800 Subject: [PATCH 02/11] fix(local): fixed build on Linux --- crates/shadowsocks-service/src/local/socks/server/mod.rs | 2 ++ .../shadowsocks-service/src/local/socks/server/server.rs | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/shadowsocks-service/src/local/socks/server/mod.rs b/crates/shadowsocks-service/src/local/socks/server/mod.rs index 0587e2107533..edbb5cf85f04 100644 --- a/crates/shadowsocks-service/src/local/socks/server/mod.rs +++ b/crates/shadowsocks-service/src/local/socks/server/mod.rs @@ -108,6 +108,7 @@ impl SocksBuilder { let mut udp_server = None; if self.mode.enable_udp() { + #[allow(unused_mut)] let mut builder = Socks5UdpServerBuilder::new( self.context.clone(), udp_bind_addr.clone(), @@ -127,6 +128,7 @@ impl SocksBuilder { let mut tcp_server = None; if self.mode.enable_tcp() { + #[allow(unused_mut)] let mut builder = SocksTcpServerBuilder::new( self.context.clone(), self.client_config, diff --git a/crates/shadowsocks-service/src/local/socks/server/server.rs b/crates/shadowsocks-service/src/local/socks/server/server.rs index 550183063254..d6b99647e46c 100644 --- a/crates/shadowsocks-service/src/local/socks/server/server.rs +++ b/crates/shadowsocks-service/src/local/socks/server/server.rs @@ -72,13 +72,13 @@ impl SocksTcpServerBuilder { } }; } else { - let listener = match client_config { + let listener = match self.client_config { ServerAddr::SocketAddr(ref saddr) => { - ShadowTcpListener::bind_with_opts(saddr, context.accept_opts()).await? + ShadowTcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? } ServerAddr::DomainName(ref dname, port) => { - lookup_then!(context.context_ref(), dname, port, |addr| { - ShadowTcpListener::bind_with_opts(&addr, context.accept_opts()).await + lookup_then!(self.context.context_ref(), dname, port, |addr| { + ShadowTcpListener::bind_with_opts(&addr, self.context.accept_opts()).await })? .1 } From 66e5b6d7bf02041e8b699dc6e592863b0ee392bf Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Fri, 20 Oct 2023 22:02:09 +0800 Subject: [PATCH 03/11] feat(local): local-http support launch activate socket --- .../src/local/http/server.rs | 44 ++++++++++++++++--- crates/shadowsocks-service/src/local/mod.rs | 18 +++++++- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/crates/shadowsocks-service/src/local/http/server.rs b/crates/shadowsocks-service/src/local/http/server.rs index acca97241a53..83aaec21d2ab 100644 --- a/crates/shadowsocks-service/src/local/http/server.rs +++ b/crates/shadowsocks-service/src/local/http/server.rs @@ -32,6 +32,8 @@ pub struct HttpBuilder { context: Arc, client_config: ServerAddr, balancer: PingBalancer, + #[cfg(target_os = "macos")] + launchd_tcp_socket_name: Option, } impl HttpBuilder { @@ -51,18 +53,46 @@ impl HttpBuilder { context, client_config, balancer, + #[cfg(target_os = "macos")] + launchd_tcp_socket_name: None, } } + #[cfg(target_os = "macos")] + pub fn set_launchd_tcp_socket_name(&mut self, n: String) { + self.launchd_tcp_socket_name = Some(n); + } + /// Build HTTP server instance pub async fn build(self) -> io::Result { - let listener = match self.client_config { - ServerAddr::SocketAddr(sa) => TcpListener::bind_with_opts(&sa, self.context.accept_opts().clone()).await, - ServerAddr::DomainName(ref dname, port) => lookup_then!(self.context.context_ref(), dname, port, |addr| { - TcpListener::bind_with_opts(&addr, self.context.accept_opts().clone()).await - }) - .map(|(_, b)| b), - }?; + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + let listener = if let Some(launchd_socket_name) = self.launchd_tcp_socket_name { + use tokio::net::TcpListener as TokioTcpListener; + use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; + + let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + TcpListener::from_listener(tokio_listener, self.context.accept_opts())? + } else { + match self.client_config { + ServerAddr::SocketAddr(sa) => TcpListener::bind_with_opts(&sa, self.context.accept_opts().clone()).await, + ServerAddr::DomainName(ref dname, port) => lookup_then!(self.context.context_ref(), dname, port, |addr| { + TcpListener::bind_with_opts(&addr, self.context.accept_opts().clone()).await + }) + .map(|(_, b)| b), + }? + }; + } else { + let listener = match self.client_config { + ServerAddr::SocketAddr(sa) => TcpListener::bind_with_opts(&sa, self.context.accept_opts().clone()).await, + ServerAddr::DomainName(ref dname, port) => lookup_then!(self.context.context_ref(), dname, port, |addr| { + TcpListener::bind_with_opts(&addr, self.context.accept_opts().clone()).await + }) + .map(|(_, b)| b), + }?; + } + } let proxy_client_cache = Arc::new(ProxyClientCache::new(self.context.clone())); diff --git a/crates/shadowsocks-service/src/local/mod.rs b/crates/shadowsocks-service/src/local/mod.rs index e098e471dfa2..095cd54991b4 100644 --- a/crates/shadowsocks-service/src/local/mod.rs +++ b/crates/shadowsocks-service/src/local/mod.rs @@ -279,6 +279,15 @@ impl Server { server_builder.set_udp_bind_addr(b.clone()); } + #[cfg(target_os = "macos")] + if let Some(n) = local_config.launchd_tcp_socket_name { + server_builder.set_launchd_tcp_socket_name(n); + } + #[cfg(target_os = "macos")] + if let Some(n) = local_config.launchd_udp_socket_name { + server_builder.set_launchd_udp_socket_name(n); + } + let server = server_builder.build().await?; local_server.socks_servers.push(server); } @@ -315,7 +324,14 @@ impl Server { None => return Err(io::Error::new(ErrorKind::Other, "http requires local address")), }; - let builder = HttpBuilder::with_context(context.clone(), client_addr, balancer); + #[allow(unused_mut)] + let mut builder = HttpBuilder::with_context(context.clone(), client_addr, balancer); + + #[cfg(target_os = "macos")] + if let Some(n) = local_config.launchd_tcp_socket_name { + builder.set_launchd_tcp_socket_name(n); + } + let server = builder.build().await?; local_server.http_servers.push(server); } From 9bed71bba4828339f74a7b42988f8be2c0988905 Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Fri, 20 Oct 2023 22:15:27 +0800 Subject: [PATCH 04/11] feat(local): local-tunnel support launch activate socket --- crates/shadowsocks-service/src/local/mod.rs | 9 ++ .../src/local/socks/server/server.rs | 2 + .../src/local/tunnel/server.rs | 55 ++++++-- .../src/local/tunnel/tcprelay.rs | 93 +++++++++++--- .../src/local/tunnel/udprelay.rs | 120 +++++++++++++----- 5 files changed, 218 insertions(+), 61 deletions(-) diff --git a/crates/shadowsocks-service/src/local/mod.rs b/crates/shadowsocks-service/src/local/mod.rs index 095cd54991b4..b21d2f354bba 100644 --- a/crates/shadowsocks-service/src/local/mod.rs +++ b/crates/shadowsocks-service/src/local/mod.rs @@ -314,6 +314,15 @@ impl Server { server_builder.set_udp_bind_addr(udp_addr); } + #[cfg(target_os = "macos")] + if let Some(n) = local_config.launchd_tcp_socket_name { + server_builder.set_launchd_tcp_socket_name(n); + } + #[cfg(target_os = "macos")] + if let Some(n) = local_config.launchd_udp_socket_name { + server_builder.set_launchd_udp_socket_name(n); + } + let server = server_builder.build().await?; local_server.tunnel_servers.push(server); } diff --git a/crates/shadowsocks-service/src/local/socks/server/server.rs b/crates/shadowsocks-service/src/local/socks/server/server.rs index d6b99647e46c..b7b43f1ceeb0 100644 --- a/crates/shadowsocks-service/src/local/socks/server/server.rs +++ b/crates/shadowsocks-service/src/local/socks/server/server.rs @@ -19,6 +19,7 @@ pub struct SocksTcpServerBuilder { balancer: PingBalancer, mode: Mode, socks5_auth: Arc, + #[cfg(target_os = "macos")] launchd_socket_name: Option, } @@ -38,6 +39,7 @@ impl SocksTcpServerBuilder { balancer, mode, socks5_auth: Arc::new(socks5_auth), + #[cfg(target_os = "macos")] launchd_socket_name: None, } } diff --git a/crates/shadowsocks-service/src/local/tunnel/server.rs b/crates/shadowsocks-service/src/local/tunnel/server.rs index a63baf44f933..a20487b8016d 100644 --- a/crates/shadowsocks-service/src/local/tunnel/server.rs +++ b/crates/shadowsocks-service/src/local/tunnel/server.rs @@ -7,7 +7,10 @@ use shadowsocks::{config::Mode, relay::socks5::Address, ServerAddr}; use crate::local::{context::ServiceContext, loadbalancing::PingBalancer}; -use super::{tcprelay::TunnelTcpServer, udprelay::TunnelUdpServer}; +use super::{ + tcprelay::{TunnelTcpServer, TunnelTcpServerBuilder}, + udprelay::{TunnelUdpServer, TunnelUdpServerBuilder}, +}; pub struct TunnelBuilder { context: Arc, @@ -18,6 +21,10 @@ pub struct TunnelBuilder { client_addr: ServerAddr, udp_addr: Option, balancer: PingBalancer, + #[cfg(target_os = "macos")] + launchd_tcp_socket_name: Option, + #[cfg(target_os = "macos")] + launchd_udp_socket_name: Option, } impl TunnelBuilder { @@ -43,6 +50,10 @@ impl TunnelBuilder { client_addr, udp_addr: None, balancer, + #[cfg(target_os = "macos")] + launchd_tcp_socket_name: None, + #[cfg(target_os = "macos")] + launchd_udp_socket_name: None, } } @@ -66,32 +77,58 @@ impl TunnelBuilder { self.udp_addr = Some(addr); } + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + pub fn set_launchd_tcp_socket_name(&mut self, n: String) { + self.launchd_tcp_socket_name = Some(n); + } + + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + pub fn set_launchd_udp_socket_name(&mut self, n: String) { + self.launchd_udp_socket_name = Some(n); + } + pub async fn build(self) -> io::Result { let mut tcp_server = None; if self.mode.enable_tcp() { - let server = TunnelTcpServer::new( + #[allow(unused_mut)] + let mut builder = TunnelTcpServerBuilder::new( self.context.clone(), - &self.client_addr, + self.client_addr.clone(), self.balancer.clone(), self.forward_addr.clone(), - ) - .await?; + ); + + #[cfg(target_os = "macos")] + if let Some(s) = self.launchd_tcp_socket_name { + builder.set_launchd_socket_name(s); + } + + let server = builder.build().await?; tcp_server = Some(server); } let mut udp_server = None; if self.mode.enable_udp() { - let udp_addr = self.udp_addr.as_ref().unwrap_or(&self.client_addr); + let udp_addr = self.udp_addr.unwrap_or(self.client_addr); - let server = TunnelUdpServer::new( + #[allow(unused_mut)] + let mut builder = TunnelUdpServerBuilder::new( self.context.clone(), udp_addr, self.udp_expiry_duration, self.udp_capacity, self.balancer, self.forward_addr, - ) - .await?; + ); + + #[cfg(target_os = "macos")] + if let Some(s) = self.launchd_udp_socket_name { + builder.set_launchd_socket_name(s); + } + + let server = builder.build().await?; udp_server = Some(server); } diff --git a/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs b/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs index 24168702ca91..44ef476b0fca 100644 --- a/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs +++ b/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs @@ -13,41 +13,94 @@ use crate::local::{ utils::{establish_tcp_tunnel, establish_tcp_tunnel_bypassed}, }; -/// TCP Tunnel instance -pub struct TunnelTcpServer { +pub struct TunnelTcpServerBuilder { context: Arc, - listener: ShadowTcpListener, + client_config: ServerAddr, balancer: PingBalancer, forward_addr: Address, + #[cfg(target_os = "macos")] + launchd_socket_name: Option, } -impl TunnelTcpServer { - pub(crate) async fn new( +impl TunnelTcpServerBuilder { + pub(crate) fn new( context: Arc, - client_config: &ServerAddr, + client_config: ServerAddr, balancer: PingBalancer, forward_addr: Address, - ) -> io::Result { - let listener = match *client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowTcpListener::bind_with_opts(saddr, context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(context.context_ref(), dname, port, |addr| { - ShadowTcpListener::bind_with_opts(&addr, context.accept_opts()).await - })? - .1 + ) -> TunnelTcpServerBuilder { + TunnelTcpServerBuilder { + context, + client_config, + balancer, + forward_addr, + #[cfg(target_os = "macos")] + launchd_socket_name: None, + } + } + + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + pub fn set_launchd_socket_name(&mut self, n: String) { + self.launchd_socket_name = Some(n); + } + + pub async fn build(self) -> io::Result { + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + let listener = if let Some(launchd_socket_name) = self.launchd_socket_name { + use tokio::net::TcpListener as TokioTcpListener; + use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; + + let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + ShadowTcpListener::from_listener(tokio_listener, self.context.accept_opts())? + } else { + match self.client_config { + ServerAddr::SocketAddr(ref saddr) => { + ShadowTcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(self.context.context_ref(), dname, port, |addr| { + ShadowTcpListener::bind_with_opts(&addr, self.context.accept_opts()).await + })? + .1 + } + } + }; + } else { + let listener = match self.client_config { + ServerAddr::SocketAddr(ref saddr) => { + ShadowTcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(self.context.context_ref(), dname, port, |addr| { + ShadowTcpListener::bind_with_opts(&addr, self.context.accept_opts()).await + })? + .1 + } + }; } - }; + } Ok(TunnelTcpServer { - context, + context: self.context, listener, - balancer, - forward_addr, + balancer: self.balancer, + forward_addr: self.forward_addr, }) } +} + +/// TCP Tunnel instance +pub struct TunnelTcpServer { + context: Arc, + listener: ShadowTcpListener, + balancer: PingBalancer, + forward_addr: Address, +} +impl TunnelTcpServer { /// Server's local address pub fn local_addr(&self) -> io::Result { self.listener.local_addr() diff --git a/crates/shadowsocks-service/src/local/tunnel/udprelay.rs b/crates/shadowsocks-service/src/local/tunnel/udprelay.rs index bdcd4d527cd9..aae9dd8c5783 100644 --- a/crates/shadowsocks-service/src/local/tunnel/udprelay.rs +++ b/crates/shadowsocks-service/src/local/tunnel/udprelay.rs @@ -18,6 +18,94 @@ use crate::local::{ net::{UdpAssociationManager, UdpInboundWrite}, }; +pub struct TunnelUdpServerBuilder { + context: Arc, + client_config: ServerAddr, + time_to_live: Option, + capacity: Option, + balancer: PingBalancer, + forward_addr: Address, + #[cfg(target_os = "macos")] + launchd_socket_name: Option, +} + +impl TunnelUdpServerBuilder { + pub(crate) fn new( + context: Arc, + client_config: ServerAddr, + time_to_live: Option, + capacity: Option, + balancer: PingBalancer, + forward_addr: Address, + ) -> TunnelUdpServerBuilder { + TunnelUdpServerBuilder { + context, + client_config, + time_to_live, + capacity, + balancer, + forward_addr, + #[cfg(target_os = "macos")] + launchd_socket_name: None, + } + } + + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + pub fn set_launchd_socket_name(&mut self, n: String) { + self.launchd_socket_name = Some(n); + } + + pub async fn build(self) -> io::Result { + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + let socket = if let Some(launchd_socket_name) = self.launchd_socket_name { + use tokio::net::UdpSocket as TokioUdpSocket; + use crate::net::launch_activate_socket::get_launch_activate_udp_socket; + + let std_socket = get_launch_activate_udp_socket(&launchd_socket_name)?; + TokioUdpSocket::from_std(std_socket)? + } else { + let shadow_socket = match self.client_config { + ServerAddr::SocketAddr(ref saddr) => { + ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(self.context.context_ref(), dname, port, |addr| { + ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await + })? + .1 + } + }; + shadow_socket.into() + }; + } else { + let shadow_socket = match self.client_config { + ServerAddr::SocketAddr(ref saddr) => { + ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(self.context.context_ref(), dname, port, |addr| { + ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await + })? + .1 + } + }; + let socket = shadow_socket.into(); + } + } + + Ok(TunnelUdpServer { + context: self.context, + time_to_live: self.time_to_live, + capacity: self.capacity, + listener: Arc::new(socket), + balancer: self.balancer, + forward_addr: self.forward_addr, + }) + } +} + #[derive(Clone)] struct TunnelUdpInboundWriter { inbound: Arc, @@ -40,38 +128,6 @@ pub struct TunnelUdpServer { } impl TunnelUdpServer { - pub(crate) async fn new( - context: Arc, - client_config: &ServerAddr, - time_to_live: Option, - capacity: Option, - balancer: PingBalancer, - forward_addr: Address, - ) -> io::Result { - let socket = match client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowUdpSocket::listen_with_opts(saddr, context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(context.context_ref(), dname, *port, |addr| { - ShadowUdpSocket::listen_with_opts(&addr, context.accept_opts()).await - })? - .1 - } - }; - let socket: UdpSocket = socket.into(); - let listener = Arc::new(socket); - - Ok(TunnelUdpServer { - context, - time_to_live, - capacity, - listener, - balancer, - forward_addr, - }) - } - /// Get server's local address pub fn local_addr(&self) -> io::Result { self.listener.local_addr() From 01e5a448e770edbe627a7f1cb2255b6610cae6db Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Fri, 20 Oct 2023 22:18:00 +0800 Subject: [PATCH 05/11] feat(readme): updated launchd activate socket for socks4, http --- README.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7b46afd9d17d..c49c50a09ecf 100644 --- a/README.md +++ b/README.md @@ -556,7 +556,7 @@ Example configuration: "acl": "/path/to/acl/file.acl", // OPTIONAL. macOS launchd activate socket "launchd_tcp_socket_name": "TCPListener", - "launchd_udp_socket_name": "UDPListener", + "launchd_udp_socket_name": "UDPListener" }, { // SOCKS5, SOCKS4/4a local server @@ -570,7 +570,10 @@ Example configuration: // - TCP is enabled, then SOCKS5's UDP Association command will return this address // - UDP is enabled, then SOCKS5's UDP server will listen to this address. "local_udp_address": "127.0.0.1", - "local_udp_port": 2081 + "local_udp_port": 2081, + // OPTIONAL. macOS launchd activate socket + "launchd_tcp_socket_name": "TCPListener", + "launchd_udp_socket_name": "UDPListener" }, { // Tunnel local server (feature = "local-tunnel") @@ -583,14 +586,19 @@ Example configuration: "forward_address": "8.8.8.8", "forward_port": 53, // OPTIONAL. Customizing whether to start TCP and UDP tunnel - "mode": "tcp_only" + "mode": "tcp_only", + // OPTIONAL. macOS launchd activate socket + "launchd_tcp_socket_name": "TCPListener", + "launchd_udp_socket_name": "UDPListener" }, { // HTTP local server (feature = "local-http") "protocol": "http", // Listen address "local_address": "127.0.0.1", - "local_port": 3128 + "local_port": 3128, + // OPTIONAL. macOS launchd activate socket + "launchd_tcp_socket_name": "TCPListener" }, { // DNS local server (feature = "local-dns") From 1699daf7d38a882a1862d35db6a181f2b1c173a2 Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Sat, 21 Oct 2023 00:47:54 +0800 Subject: [PATCH 06/11] feat(local): local-dns support launch activate socket --- README.md | 5 +- .../src/local/dns/server.rs | 237 ++++++++++++++---- crates/shadowsocks-service/src/local/mod.rs | 9 + 3 files changed, 205 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index c49c50a09ecf..9d676b0cb525 100644 --- a/README.md +++ b/README.md @@ -618,7 +618,10 @@ Example configuration: // OPTIONAL. Remote DNS's port, 53 by default "remote_dns_port": 53, // OPTIONAL. dns client cache size for fetching dns queries. - "client_cache_size": 5 + "client_cache_size": 5, + // OPTIONAL. macOS launchd activate socket + "launchd_tcp_socket_name": "TCPListener", + "launchd_udp_socket_name": "UDPListener" }, { // Tun local server (feature = "local-tun") diff --git a/crates/shadowsocks-service/src/local/dns/server.rs b/crates/shadowsocks-service/src/local/dns/server.rs index 0026ea55a269..1ed89efd0c25 100644 --- a/crates/shadowsocks-service/src/local/dns/server.rs +++ b/crates/shadowsocks-service/src/local/dns/server.rs @@ -54,6 +54,10 @@ pub struct DnsBuilder { bind_addr: ServerAddr, balancer: PingBalancer, client_cache_size: usize, + #[cfg(target_os = "macos")] + launchd_tcp_socket_name: Option, + #[cfg(target_os = "macos")] + launchd_udp_socket_name: Option, } impl DnsBuilder { @@ -93,6 +97,10 @@ impl DnsBuilder { bind_addr, balancer, client_cache_size, + #[cfg(target_os = "macos")] + launchd_tcp_socket_name: None, + #[cfg(target_os = "macos")] + launchd_udp_socket_name: None, } } @@ -101,6 +109,18 @@ impl DnsBuilder { self.mode = mode; } + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + pub fn set_launchd_tcp_socket_name(&mut self, n: String) { + self.launchd_tcp_socket_name = Some(n); + } + + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + pub fn set_launchd_udp_socket_name(&mut self, n: String) { + self.launchd_udp_socket_name = Some(n); + } + /// Build DNS server pub async fn build(self) -> io::Result { let client = Arc::new(DnsClient::new( @@ -115,20 +135,35 @@ impl DnsBuilder { let mut tcp_server = None; if self.mode.enable_tcp() { - let server = DnsTcpServer::new( + #[allow(unused_mut)] + let mut builder = DnsTcpServerBuilder::new( self.context.clone(), - &self.bind_addr, + self.bind_addr.clone(), local_addr.clone(), remote_addr.clone(), client.clone(), - ) - .await?; + ); + + #[cfg(target_os = "macos")] + if let Some(s) = self.launchd_tcp_socket_name { + builder.set_launchd_socket_name(s); + } + + let server = builder.build().await?; tcp_server = Some(server); } let mut udp_server = None; if self.mode.enable_udp() { - let server = DnsUdpServer::new(self.context, &self.bind_addr, local_addr, remote_addr, client).await?; + #[allow(unused_mut)] + let mut builder = DnsUdpServerBuilder::new(self.context, self.bind_addr, local_addr, remote_addr, client); + + #[cfg(target_os = "macos")] + if let Some(s) = self.launchd_udp_socket_name { + builder.set_launchd_socket_name(s); + } + + let server = builder.build().await?; udp_server = Some(server); } @@ -136,40 +171,97 @@ impl DnsBuilder { } } -/// DNS TCP server instance -pub struct DnsTcpServer { - listener: TcpListener, +struct DnsTcpServerBuilder { + context: Arc, + bind_addr: ServerAddr, local_addr: Arc, remote_addr: Arc
, client: Arc, + #[cfg(target_os = "macos")] + launchd_socket_name: Option, } -impl DnsTcpServer { - async fn new( +impl DnsTcpServerBuilder { + fn new( context: Arc, - bind_addr: &ServerAddr, + bind_addr: ServerAddr, local_addr: Arc, remote_addr: Arc
, client: Arc, - ) -> io::Result { - let listener = match *bind_addr { - ServerAddr::SocketAddr(ref saddr) => TcpListener::bind_with_opts(saddr, context.accept_opts()).await?, - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(context.context_ref(), dname, port, |addr| { - TcpListener::bind_with_opts(&addr, context.accept_opts()).await - })? - .1 + ) -> DnsTcpServerBuilder { + DnsTcpServerBuilder { + context, + bind_addr, + local_addr, + remote_addr, + client, + #[cfg(target_os = "macos")] + launchd_socket_name: None, + } + } + + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + fn set_launchd_socket_name(&mut self, n: String) { + self.launchd_socket_name = Some(n); + } + + async fn build(self) -> io::Result { + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + let listener = if let Some(launchd_socket_name) = self.launchd_socket_name { + use tokio::net::TcpListener as TokioTcpListener; + use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; + + let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + TcpListener::from_listener(tokio_listener, self.context.accept_opts())? + } else { + match self.bind_addr { + ServerAddr::SocketAddr(ref saddr) => { + TcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(self.context.context_ref(), dname, port, |addr| { + TcpListener::bind_with_opts(&addr, self.context.accept_opts()).await + })? + .1 + } + } + }; + } else { + let listener = match self.bind_addr { + ServerAddr::SocketAddr(ref saddr) => { + TcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(self.context.context_ref(), dname, port, |addr| { + TcpListener::bind_with_opts(&addr, self.context.accept_opts()).await + })? + .1 + } + }; } - }; + } Ok(DnsTcpServer { listener, - local_addr, - remote_addr, - client, + local_addr: self.local_addr, + remote_addr: self.remote_addr, + client: self.client, }) } +} + +/// DNS TCP server instance +pub struct DnsTcpServer { + listener: TcpListener, + local_addr: Arc, + remote_addr: Arc
, + client: Arc, +} +impl DnsTcpServer { /// Get server local address pub fn local_addr(&self) -> io::Result { self.listener.local_addr() @@ -272,43 +364,98 @@ impl DnsTcpServer { } } -/// DNS UDP server instance -pub struct DnsUdpServer { - listener: Arc, +struct DnsUdpServerBuilder { + context: Arc, + bind_addr: ServerAddr, local_addr: Arc, remote_addr: Arc
, client: Arc, + #[cfg(target_os = "macos")] + launchd_socket_name: Option, } -impl DnsUdpServer { - async fn new( +impl DnsUdpServerBuilder { + fn new( context: Arc, - bind_addr: &ServerAddr, + bind_addr: ServerAddr, local_addr: Arc, remote_addr: Arc
, client: Arc, - ) -> io::Result { - let socket = match *bind_addr { - ServerAddr::SocketAddr(ref saddr) => ShadowUdpSocket::listen(saddr).await?, - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(context.context_ref(), dname, port, |addr| { - ShadowUdpSocket::listen(&addr).await - })? - .1 - } - }; - let socket: UdpSocket = socket.into(); - - let listener = Arc::new(socket); - - Ok(DnsUdpServer { - listener, + ) -> DnsUdpServerBuilder { + DnsUdpServerBuilder { + context, + bind_addr, local_addr, remote_addr, client, + #[cfg(target_os = "macos")] + launchd_socket_name: None, + } + } + + /// macOS launchd activate socket + #[cfg(target_os = "macos")] + fn set_launchd_socket_name(&mut self, n: String) { + self.launchd_socket_name = Some(n); + } + + async fn build(self) -> io::Result { + cfg_if::cfg_if! { + if #[cfg(target_os = "macos")] { + let socket = if let Some(launchd_socket_name) = self.launchd_socket_name { + use tokio::net::UdpSocket as TokioUdpSocket; + use crate::net::launch_activate_socket::get_launch_activate_udp_socket; + + let std_socket = get_launch_activate_udp_socket(&launchd_socket_name)?; + TokioUdpSocket::from_std(std_socket)? + } else { + let shadow_socket = match self.bind_addr { + ServerAddr::SocketAddr(ref saddr) => { + ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(self.context.context_ref(), dname, port, |addr| { + ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await + })? + .1 + } + }; + shadow_socket.into() + }; + } else { + let shadow_socket = match self.bind_addr { + ServerAddr::SocketAddr(ref saddr) => { + ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? + } + ServerAddr::DomainName(ref dname, port) => { + lookup_then!(self.context.context_ref(), dname, port, |addr| { + ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await + })? + .1 + } + }; + let socket = shadow_socket.into(); + } + } + + Ok(DnsUdpServer { + listener: Arc::new(socket), + local_addr: self.local_addr, + remote_addr: self.remote_addr, + client: self.client, }) } +} +/// DNS UDP server instance +pub struct DnsUdpServer { + listener: Arc, + local_addr: Arc, + remote_addr: Arc
, + client: Arc, +} + +impl DnsUdpServer { /// Get server local address pub fn local_addr(&self) -> io::Result { self.listener.local_addr() diff --git a/crates/shadowsocks-service/src/local/mod.rs b/crates/shadowsocks-service/src/local/mod.rs index b21d2f354bba..f5b5c1e0029a 100644 --- a/crates/shadowsocks-service/src/local/mod.rs +++ b/crates/shadowsocks-service/src/local/mod.rs @@ -391,6 +391,15 @@ impl Server { }; server_builder.set_mode(local_config.mode); + #[cfg(target_os = "macos")] + if let Some(n) = local_config.launchd_tcp_socket_name { + server_builder.set_launchd_tcp_socket_name(n); + } + #[cfg(target_os = "macos")] + if let Some(n) = local_config.launchd_udp_socket_name { + server_builder.set_launchd_udp_socket_name(n); + } + let server = server_builder.build().await?; local_server.dns_servers.push(server); } From bfc4741a12151216264bcff3af71dc894824fdb5 Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Sat, 21 Oct 2023 01:03:31 +0800 Subject: [PATCH 07/11] chore(local): launch activate socket creation log --- crates/shadowsocks-service/src/net/launch_activate_socket.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/shadowsocks-service/src/net/launch_activate_socket.rs b/crates/shadowsocks-service/src/net/launch_activate_socket.rs index d7be24860371..f39cbea23f88 100644 --- a/crates/shadowsocks-service/src/net/launch_activate_socket.rs +++ b/crates/shadowsocks-service/src/net/launch_activate_socket.rs @@ -9,14 +9,18 @@ use std::{ os::unix::io::FromRawFd, }; +use log::debug; + use crate::sys::get_launch_activate_socket; pub fn get_launch_activate_tcp_listener(name: &str) -> io::Result { let fd = get_launch_activate_socket(name)?; + debug!("created TCP listener from launch activate socket {}", fd); Ok(unsafe { TcpListener::from_raw_fd(fd) }) } pub fn get_launch_activate_udp_socket(name: &str) -> io::Result { let fd = get_launch_activate_socket(name)?; + debug!("created UDP socket from launch activate socket {}", fd); Ok(unsafe { UdpSocket::from_raw_fd(fd) }) } From f059d3032e001c7c405cd0474243b970a7b3e630 Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Sun, 22 Oct 2023 01:56:59 +0800 Subject: [PATCH 08/11] feat(local): unified TCP & UDP listener creation --- .../src/local/dns/server.rs | 68 +++++-------------- .../src/local/http/server.rs | 43 ++++++------ .../src/local/socks/server/server.rs | 41 ++++------- .../src/local/socks/server/socks5/udprelay.rs | 36 ++-------- .../src/local/tunnel/tcprelay.rs | 47 +++++-------- .../src/local/tunnel/udprelay.rs | 45 ++++-------- .../src/net/launch_activate_socket.rs | 24 ++++--- .../shadowsocks-service/src/net/listener.rs | 37 ++++++++++ crates/shadowsocks-service/src/net/mod.rs | 1 + .../shadowsocks-service/src/sys/unix/macos.rs | 22 +++--- 10 files changed, 151 insertions(+), 213 deletions(-) create mode 100644 crates/shadowsocks-service/src/net/listener.rs diff --git a/crates/shadowsocks-service/src/local/dns/server.rs b/crates/shadowsocks-service/src/local/dns/server.rs index 1ed89efd0c25..fdcf36968a41 100644 --- a/crates/shadowsocks-service/src/local/dns/server.rs +++ b/crates/shadowsocks-service/src/local/dns/server.rs @@ -32,8 +32,7 @@ use tokio::{ use shadowsocks::{ config::Mode, - lookup_then, - net::{TcpListener, UdpSocket as ShadowUdpSocket}, + net::TcpListener, relay::{udprelay::MAXIMUM_UDP_PAYLOAD_SIZE, Address}, ServerAddr, }; @@ -41,6 +40,7 @@ use shadowsocks::{ use crate::{ acl::AccessControl, local::{context::ServiceContext, loadbalancing::PingBalancer}, + net::listener::{create_standard_tcp_listener, create_standard_udp_listener}, }; use super::{client_cache::DnsClientCache, config::NameServerAddr}; @@ -213,34 +213,18 @@ impl DnsTcpServerBuilder { use tokio::net::TcpListener as TokioTcpListener; use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; - let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; - let tokio_listener = TokioTcpListener::from_std(std_listener)?; - TcpListener::from_listener(tokio_listener, self.context.accept_opts())? - } else { - match self.bind_addr { - ServerAddr::SocketAddr(ref saddr) => { - TcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - TcpListener::bind_with_opts(&addr, self.context.accept_opts()).await - })? - .1 + match get_launch_activate_tcp_listener(&launchd_socket_name)? { + Some(std_listener) => { + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + TcpListener::from_listener(tokio_listener, self.context.accept_opts())? } + None => create_standard_tcp_listener(&self.context, &self.bind_addr).await? } + } else { + create_standard_tcp_listener(&self.context, &self.bind_addr).await? }; } else { - let listener = match self.bind_addr { - ServerAddr::SocketAddr(ref saddr) => { - TcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - TcpListener::bind_with_opts(&addr, self.context.accept_opts()).await - })? - .1 - } - }; + let listener = create_standard_tcp_listener(&self.context, &self.bind_addr).await?; } } @@ -406,35 +390,15 @@ impl DnsUdpServerBuilder { use tokio::net::UdpSocket as TokioUdpSocket; use crate::net::launch_activate_socket::get_launch_activate_udp_socket; - let std_socket = get_launch_activate_udp_socket(&launchd_socket_name)?; - TokioUdpSocket::from_std(std_socket)? + match get_launch_activate_udp_socket(&launchd_socket_name)? { + Some(std_socket) => TokioUdpSocket::from_std(std_socket)?, + None => create_standard_udp_listener(&self.context, &self.bind_addr).await?.into() + } } else { - let shadow_socket = match self.bind_addr { - ServerAddr::SocketAddr(ref saddr) => { - ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await - })? - .1 - } - }; - shadow_socket.into() + create_standard_udp_listener(&self.context, &self.bind_addr).await?.into() }; } else { - let shadow_socket = match self.bind_addr { - ServerAddr::SocketAddr(ref saddr) => { - ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await - })? - .1 - } - }; - let socket = shadow_socket.into(); + let socket = create_standard_udp_listener(&self.context, &self.bind_addr).await?.into(); } } diff --git a/crates/shadowsocks-service/src/local/http/server.rs b/crates/shadowsocks-service/src/local/http/server.rs index 83aaec21d2ab..cd6c7fb60825 100644 --- a/crates/shadowsocks-service/src/local/http/server.rs +++ b/crates/shadowsocks-service/src/local/http/server.rs @@ -16,13 +16,16 @@ use hyper::{ Server, }; use log::{error, info}; -use shadowsocks::{config::ServerAddr, lookup_then, net::TcpListener}; - -use crate::local::{ - context::ServiceContext, - http::connector::Connector, - loadbalancing::PingBalancer, - LOCAL_DEFAULT_KEEPALIVE_TIMEOUT, +use shadowsocks::{config::ServerAddr, net::TcpListener}; + +use crate::{ + local::{ + context::ServiceContext, + http::connector::Connector, + loadbalancing::PingBalancer, + LOCAL_DEFAULT_KEEPALIVE_TIMEOUT, + }, + net::listener::create_standard_tcp_listener, }; use super::{client_cache::ProxyClientCache, dispatcher::HttpDispatcher}; @@ -71,26 +74,18 @@ impl HttpBuilder { use tokio::net::TcpListener as TokioTcpListener; use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; - let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; - let tokio_listener = TokioTcpListener::from_std(std_listener)?; - TcpListener::from_listener(tokio_listener, self.context.accept_opts())? + match get_launch_activate_tcp_listener(&launchd_socket_name)? { + Some(std_listener) => { + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + TcpListener::from_listener(tokio_listener, self.context.accept_opts())? + } + None => create_standard_tcp_listener(&self.context, &self.client_config).await? + } } else { - match self.client_config { - ServerAddr::SocketAddr(sa) => TcpListener::bind_with_opts(&sa, self.context.accept_opts().clone()).await, - ServerAddr::DomainName(ref dname, port) => lookup_then!(self.context.context_ref(), dname, port, |addr| { - TcpListener::bind_with_opts(&addr, self.context.accept_opts().clone()).await - }) - .map(|(_, b)| b), - }? + create_standard_tcp_listener(&self.context, &self.client_config).await? }; } else { - let listener = match self.client_config { - ServerAddr::SocketAddr(sa) => TcpListener::bind_with_opts(&sa, self.context.accept_opts().clone()).await, - ServerAddr::DomainName(ref dname, port) => lookup_then!(self.context.context_ref(), dname, port, |addr| { - TcpListener::bind_with_opts(&addr, self.context.accept_opts().clone()).await - }) - .map(|(_, b)| b), - }?; + let listener = create_standard_tcp_listener(&self.context, &self.client_config).await?; } } diff --git a/crates/shadowsocks-service/src/local/socks/server/server.rs b/crates/shadowsocks-service/src/local/socks/server/server.rs index b7b43f1ceeb0..2ee21e115315 100644 --- a/crates/shadowsocks-service/src/local/socks/server/server.rs +++ b/crates/shadowsocks-service/src/local/socks/server/server.rs @@ -1,17 +1,18 @@ use std::{io, net::SocketAddr, sync::Arc, time::Duration}; use log::{error, info}; -use shadowsocks::{config::Mode, lookup_then, net::TcpListener as ShadowTcpListener, ServerAddr}; +use shadowsocks::{config::Mode, net::TcpListener as ShadowTcpListener, ServerAddr}; use tokio::{net::TcpStream, time}; -use crate::local::{context::ServiceContext, loadbalancing::PingBalancer}; +use crate::{ + local::{context::ServiceContext, loadbalancing::PingBalancer, socks::config::Socks5AuthConfig}, + net::listener::create_standard_tcp_listener, +}; #[cfg(feature = "local-socks4")] use super::socks4::Socks4TcpHandler; use super::socks5::{Socks5TcpHandler, Socks5UdpServer}; -use crate::local::socks::config::Socks5AuthConfig; - pub struct SocksTcpServerBuilder { context: Arc, client_config: ServerAddr, @@ -57,34 +58,18 @@ impl SocksTcpServerBuilder { use tokio::net::TcpListener as TokioTcpListener; use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; - let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; - let tokio_listener = TokioTcpListener::from_std(std_listener)?; - ShadowTcpListener::from_listener(tokio_listener, self.context.accept_opts())? - } else { - match self.client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowTcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - ShadowTcpListener::bind_with_opts(&addr, self.context.accept_opts()).await - })? - .1 + match get_launch_activate_tcp_listener(&launchd_socket_name)? { + Some(std_listener) => { + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + ShadowTcpListener::from_listener(tokio_listener, self.context.accept_opts())? } + None => create_standard_tcp_listener(&self.context, &self.client_config).await? } + } else { + create_standard_tcp_listener(&self.context, &self.client_config).await? }; } else { - let listener = match self.client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowTcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - ShadowTcpListener::bind_with_opts(&addr, self.context.accept_opts()).await - })? - .1 - } - }; + let listener = create_standard_tcp_listener(&self.context, &self.client_config).await?; } } diff --git a/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs b/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs index 65917be9e610..14ce16fa5958 100644 --- a/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs +++ b/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs @@ -12,8 +12,6 @@ use byte_string::ByteStr; use bytes::{BufMut, BytesMut}; use log::{debug, error, info, trace}; use shadowsocks::{ - lookup_then, - net::UdpSocket as ShadowUdpSocket, relay::{ socks5::{Address, UdpAssociateHeader}, udprelay::MAXIMUM_UDP_PAYLOAD_SIZE, @@ -28,7 +26,7 @@ use crate::{ loadbalancing::PingBalancer, net::{UdpAssociationManager, UdpInboundWrite}, }, - net::utils::to_ipv4_mapped, + net::{listener::create_standard_udp_listener, utils::to_ipv4_mapped}, }; pub struct Socks5UdpServerBuilder { @@ -73,35 +71,15 @@ impl Socks5UdpServerBuilder { use tokio::net::UdpSocket as TokioUdpSocket; use crate::net::launch_activate_socket::get_launch_activate_udp_socket; - let std_socket = get_launch_activate_udp_socket(&launchd_socket_name)?; - TokioUdpSocket::from_std(std_socket)? + match get_launch_activate_udp_socket(&launchd_socket_name)? { + Some(std_socket) => TokioUdpSocket::from_std(std_socket)?, + None => create_standard_udp_listener(&self.context, &self.client_config).await?.into() + } } else { - let shadow_socket = match self.client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await - })? - .1 - } - }; - shadow_socket.into() + create_standard_udp_listener(&self.context, &self.client_config).await?.into() }; } else { - let shadow_socket = match self.client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await - })? - .1 - } - }; - let socket = shadow_socket.into(); + let socket = create_standard_udp_listener(&self.context, &self.client_config).await?.into(); } } diff --git a/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs b/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs index 44ef476b0fca..4bc49cd63391 100644 --- a/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs +++ b/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs @@ -3,14 +3,17 @@ use std::{io, net::SocketAddr, sync::Arc, time::Duration}; use log::{error, info, trace}; -use shadowsocks::{lookup_then, net::TcpListener as ShadowTcpListener, relay::socks5::Address, ServerAddr}; +use shadowsocks::{net::TcpListener as ShadowTcpListener, relay::socks5::Address, ServerAddr}; use tokio::{net::TcpStream, time}; -use crate::local::{ - context::ServiceContext, - loadbalancing::PingBalancer, - net::AutoProxyClientStream, - utils::{establish_tcp_tunnel, establish_tcp_tunnel_bypassed}, +use crate::{ + local::{ + context::ServiceContext, + loadbalancing::PingBalancer, + net::AutoProxyClientStream, + utils::{establish_tcp_tunnel, establish_tcp_tunnel_bypassed}, + }, + net::listener::create_standard_tcp_listener, }; pub struct TunnelTcpServerBuilder { @@ -52,34 +55,18 @@ impl TunnelTcpServerBuilder { use tokio::net::TcpListener as TokioTcpListener; use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; - let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; - let tokio_listener = TokioTcpListener::from_std(std_listener)?; - ShadowTcpListener::from_listener(tokio_listener, self.context.accept_opts())? - } else { - match self.client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowTcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - ShadowTcpListener::bind_with_opts(&addr, self.context.accept_opts()).await - })? - .1 + match get_launch_activate_tcp_listener(&launchd_socket_name)? { + Some(std_listener) => { + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + ShadowTcpListener::from_listener(tokio_listener, self.context.accept_opts())? } + None => create_standard_tcp_listener(&self.context, &self.client_config).await? } + } else { + create_standard_tcp_listener(&self.context, &self.client_config).await? }; } else { - let listener = match self.client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowTcpListener::bind_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - ShadowTcpListener::bind_with_opts(&addr, self.context.accept_opts()).await - })? - .1 - } - }; + let listener = create_standard_tcp_listener(&self.context, &self.client_config).await?; } } diff --git a/crates/shadowsocks-service/src/local/tunnel/udprelay.rs b/crates/shadowsocks-service/src/local/tunnel/udprelay.rs index aae9dd8c5783..a7f75b8c0e9a 100644 --- a/crates/shadowsocks-service/src/local/tunnel/udprelay.rs +++ b/crates/shadowsocks-service/src/local/tunnel/udprelay.rs @@ -5,17 +5,18 @@ use std::{io, net::SocketAddr, sync::Arc, time::Duration}; use async_trait::async_trait; use log::{debug, error, info}; use shadowsocks::{ - lookup_then, - net::UdpSocket as ShadowUdpSocket, relay::{socks5::Address, udprelay::MAXIMUM_UDP_PAYLOAD_SIZE}, ServerAddr, }; use tokio::{net::UdpSocket, time}; -use crate::local::{ - context::ServiceContext, - loadbalancing::PingBalancer, - net::{UdpAssociationManager, UdpInboundWrite}, +use crate::{ + local::{ + context::ServiceContext, + loadbalancing::PingBalancer, + net::{UdpAssociationManager, UdpInboundWrite}, + }, + net::listener::create_standard_udp_listener, }; pub struct TunnelUdpServerBuilder { @@ -63,35 +64,15 @@ impl TunnelUdpServerBuilder { use tokio::net::UdpSocket as TokioUdpSocket; use crate::net::launch_activate_socket::get_launch_activate_udp_socket; - let std_socket = get_launch_activate_udp_socket(&launchd_socket_name)?; - TokioUdpSocket::from_std(std_socket)? + match get_launch_activate_udp_socket(&launchd_socket_name)? { + Some(std_socket) => TokioUdpSocket::from_std(std_socket)?, + None => create_standard_udp_listener(&self.context, &self.client_config).await?.into() + } } else { - let shadow_socket = match self.client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await - })? - .1 - } - }; - shadow_socket.into() + create_standard_udp_listener(&self.context, &self.client_config).await?.into() }; } else { - let shadow_socket = match self.client_config { - ServerAddr::SocketAddr(ref saddr) => { - ShadowUdpSocket::listen_with_opts(saddr, self.context.accept_opts()).await? - } - ServerAddr::DomainName(ref dname, port) => { - lookup_then!(self.context.context_ref(), dname, port, |addr| { - ShadowUdpSocket::listen_with_opts(&addr, self.context.accept_opts()).await - })? - .1 - } - }; - let socket = shadow_socket.into(); + let socket = create_standard_udp_listener(&self.context, &self.client_config).await?.into(); } } diff --git a/crates/shadowsocks-service/src/net/launch_activate_socket.rs b/crates/shadowsocks-service/src/net/launch_activate_socket.rs index f39cbea23f88..9189025ce52b 100644 --- a/crates/shadowsocks-service/src/net/launch_activate_socket.rs +++ b/crates/shadowsocks-service/src/net/launch_activate_socket.rs @@ -13,14 +13,22 @@ use log::debug; use crate::sys::get_launch_activate_socket; -pub fn get_launch_activate_tcp_listener(name: &str) -> io::Result { - let fd = get_launch_activate_socket(name)?; - debug!("created TCP listener from launch activate socket {}", fd); - Ok(unsafe { TcpListener::from_raw_fd(fd) }) +pub fn get_launch_activate_tcp_listener(name: &str) -> io::Result> { + match get_launch_activate_socket(name)? { + Some(fd) => { + debug!("created TCP listener from launch activate socket {}", fd); + Ok(Some(unsafe { TcpListener::from_raw_fd(fd) })) + } + None => Ok(None), + } } -pub fn get_launch_activate_udp_socket(name: &str) -> io::Result { - let fd = get_launch_activate_socket(name)?; - debug!("created UDP socket from launch activate socket {}", fd); - Ok(unsafe { UdpSocket::from_raw_fd(fd) }) +pub fn get_launch_activate_udp_socket(name: &str) -> io::Result> { + match get_launch_activate_socket(name)? { + Some(fd) => { + debug!("created UDP socket from launch activate socket {}", fd); + Ok(Some(unsafe { UdpSocket::from_raw_fd(fd) })) + } + None => Ok(None), + } } diff --git a/crates/shadowsocks-service/src/net/listener.rs b/crates/shadowsocks-service/src/net/listener.rs new file mode 100644 index 000000000000..b86187d3b929 --- /dev/null +++ b/crates/shadowsocks-service/src/net/listener.rs @@ -0,0 +1,37 @@ +use std::io; + +use shadowsocks::{ + config::ServerAddr, + lookup_then, + net::{TcpListener, UdpSocket}, +}; + +use crate::local::context::ServiceContext; + +/// Create a standard TCP listener listening on `client_config` +pub async fn create_standard_tcp_listener( + context: &ServiceContext, + client_config: &ServerAddr, +) -> io::Result { + match client_config { + ServerAddr::SocketAddr(saddr) => TcpListener::bind_with_opts(saddr, context.accept_opts()).await, + ServerAddr::DomainName(dname, port) => lookup_then!(context.context_ref(), dname, *port, |addr| { + TcpListener::bind_with_opts(&addr, context.accept_opts()).await + }) + .map(|(_, l)| l), + } +} + +/// Create a standard UDP listener listening on `client_config` +pub async fn create_standard_udp_listener( + context: &ServiceContext, + client_config: &ServerAddr, +) -> io::Result { + match client_config { + ServerAddr::SocketAddr(saddr) => UdpSocket::listen_with_opts(saddr, context.accept_opts()).await, + ServerAddr::DomainName(dname, port) => lookup_then!(context.context_ref(), dname, *port, |addr| { + UdpSocket::listen_with_opts(&addr, context.accept_opts()).await + }) + .map(|(_, s)| s), + } +} diff --git a/crates/shadowsocks-service/src/net/mod.rs b/crates/shadowsocks-service/src/net/mod.rs index 44ea46cc9ef1..7b3c62d947e6 100644 --- a/crates/shadowsocks-service/src/net/mod.rs +++ b/crates/shadowsocks-service/src/net/mod.rs @@ -5,6 +5,7 @@ pub use self::{flow::FlowStat, mon_socket::MonProxySocket, mon_stream::MonProxyS pub mod flow; #[cfg(target_os = "macos")] pub mod launch_activate_socket; +pub mod listener; pub mod mon_socket; pub mod mon_stream; pub mod packet_window; diff --git a/crates/shadowsocks-service/src/sys/unix/macos.rs b/crates/shadowsocks-service/src/sys/unix/macos.rs index 4f8fc2f0e8a5..dc50e3ba80e0 100644 --- a/crates/shadowsocks-service/src/sys/unix/macos.rs +++ b/crates/shadowsocks-service/src/sys/unix/macos.rs @@ -2,7 +2,7 @@ use std::{ffi::CString, io, os::fd::RawFd, ptr}; -use log::error; +use log::{error, warn}; extern "C" { /// https://developer.apple.com/documentation/xpc/1505523-launch_activate_socket @@ -13,7 +13,7 @@ extern "C" { ) -> libc::c_int; } -pub fn get_launch_activate_socket(name: &str) -> io::Result { +pub fn get_launch_activate_socket(name: &str) -> io::Result> { let mut fds: *mut libc::c_int = ptr::null_mut(); let mut cnt: libc::size_t = 0; @@ -33,13 +33,18 @@ pub fn get_launch_activate_socket(name: &str) -> io::Result { let err = io::Error::last_os_error(); match err.raw_os_error() { Some(libc::ENOENT) => { - error!("activate socket name \"{}\" doesn't exist", name); + warn!("activate socket name \"{}\" doesn't exist, error: {}", name, err); + return Ok(None); } Some(libc::ESRCH) => { - error!("current process is not managed by launchd"); + warn!("current process is not managed by launchd, error: {}", err); + return Ok(None); } Some(libc::EALREADY) => { - error!("activate socket name \"{}\" has already been activated", name); + error!( + "activate socket name \"{}\" has already been activated, error: {}", + name, err + ); } _ => {} } @@ -49,10 +54,7 @@ pub fn get_launch_activate_socket(name: &str) -> io::Result { } let result = if cnt == 0 { - Err(io::Error::new( - io::ErrorKind::InvalidInput, - format!("could not find launch socket with name \"{}\"", name), - )) + Ok(None) } else if cnt > 1 { for idx in 0..cnt { unsafe { @@ -71,7 +73,7 @@ pub fn get_launch_activate_socket(name: &str) -> io::Result { } else { // Take fds[0] as the result let fd = unsafe { *fds }; - Ok(fd as RawFd) + Ok(Some(fd as RawFd)) }; if !fds.is_null() { From 428e8067141082643aed879d0a06404923f06a50 Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Sun, 22 Oct 2023 02:06:39 +0800 Subject: [PATCH 09/11] feat(local): moved listener helper functions to local src --- .../src/local/dns/server.rs | 7 +++++-- .../src/local/http/server.rs | 14 ++++++------- .../shadowsocks-service/src/local/net/mod.rs | 2 +- .../src/local/net/tcp/listener.rs | 21 +++++++++++++++++++ .../src/local/net/tcp/mod.rs | 1 + .../src/local/net/udp/listener.rs | 21 +++++++++++++++++++ .../src/local/net/udp/mod.rs | 1 + .../src/local/socks/server/server.rs | 8 ++++--- .../src/local/socks/server/socks5/udprelay.rs | 4 ++-- .../src/local/tunnel/tcprelay.rs | 13 +++++------- .../src/local/tunnel/udprelay.rs | 11 ++++------ crates/shadowsocks-service/src/net/mod.rs | 1 - 12 files changed, 72 insertions(+), 32 deletions(-) create mode 100644 crates/shadowsocks-service/src/local/net/tcp/listener.rs create mode 100644 crates/shadowsocks-service/src/local/net/udp/listener.rs diff --git a/crates/shadowsocks-service/src/local/dns/server.rs b/crates/shadowsocks-service/src/local/dns/server.rs index fdcf36968a41..e240cb62fc24 100644 --- a/crates/shadowsocks-service/src/local/dns/server.rs +++ b/crates/shadowsocks-service/src/local/dns/server.rs @@ -39,8 +39,11 @@ use shadowsocks::{ use crate::{ acl::AccessControl, - local::{context::ServiceContext, loadbalancing::PingBalancer}, - net::listener::{create_standard_tcp_listener, create_standard_udp_listener}, + local::{ + context::ServiceContext, + loadbalancing::PingBalancer, + net::{tcp::listener::create_standard_tcp_listener, udp::listener::create_standard_udp_listener}, + }, }; use super::{client_cache::DnsClientCache, config::NameServerAddr}; diff --git a/crates/shadowsocks-service/src/local/http/server.rs b/crates/shadowsocks-service/src/local/http/server.rs index cd6c7fb60825..bd55e7056c30 100644 --- a/crates/shadowsocks-service/src/local/http/server.rs +++ b/crates/shadowsocks-service/src/local/http/server.rs @@ -18,14 +18,12 @@ use hyper::{ use log::{error, info}; use shadowsocks::{config::ServerAddr, net::TcpListener}; -use crate::{ - local::{ - context::ServiceContext, - http::connector::Connector, - loadbalancing::PingBalancer, - LOCAL_DEFAULT_KEEPALIVE_TIMEOUT, - }, - net::listener::create_standard_tcp_listener, +use crate::local::{ + context::ServiceContext, + http::connector::Connector, + loadbalancing::PingBalancer, + net::tcp::listener::create_standard_tcp_listener, + LOCAL_DEFAULT_KEEPALIVE_TIMEOUT, }; use super::{client_cache::ProxyClientCache, dispatcher::HttpDispatcher}; diff --git a/crates/shadowsocks-service/src/local/net/mod.rs b/crates/shadowsocks-service/src/local/net/mod.rs index ae2743b82888..0426432baf28 100644 --- a/crates/shadowsocks-service/src/local/net/mod.rs +++ b/crates/shadowsocks-service/src/local/net/mod.rs @@ -5,5 +5,5 @@ pub use self::{ udp::{UdpAssociationManager, UdpInboundWrite}, }; -mod tcp; +pub(crate) mod tcp; pub(crate) mod udp; diff --git a/crates/shadowsocks-service/src/local/net/tcp/listener.rs b/crates/shadowsocks-service/src/local/net/tcp/listener.rs new file mode 100644 index 000000000000..57c94ed69157 --- /dev/null +++ b/crates/shadowsocks-service/src/local/net/tcp/listener.rs @@ -0,0 +1,21 @@ +//! Local instance listener helpers + +use std::io; + +use shadowsocks::{config::ServerAddr, lookup_then, net::TcpListener}; + +use crate::local::context::ServiceContext; + +/// Create a standard TCP listener listening on `client_config` +pub async fn create_standard_tcp_listener( + context: &ServiceContext, + client_config: &ServerAddr, +) -> io::Result { + match client_config { + ServerAddr::SocketAddr(saddr) => TcpListener::bind_with_opts(saddr, context.accept_opts()).await, + ServerAddr::DomainName(dname, port) => lookup_then!(context.context_ref(), dname, *port, |addr| { + TcpListener::bind_with_opts(&addr, context.accept_opts()).await + }) + .map(|(_, l)| l), + } +} diff --git a/crates/shadowsocks-service/src/local/net/tcp/mod.rs b/crates/shadowsocks-service/src/local/net/tcp/mod.rs index b2ecb9ecf821..54561e4f0af4 100644 --- a/crates/shadowsocks-service/src/local/net/tcp/mod.rs +++ b/crates/shadowsocks-service/src/local/net/tcp/mod.rs @@ -1,2 +1,3 @@ pub mod auto_proxy_io; pub mod auto_proxy_stream; +pub mod listener; diff --git a/crates/shadowsocks-service/src/local/net/udp/listener.rs b/crates/shadowsocks-service/src/local/net/udp/listener.rs new file mode 100644 index 000000000000..17f283c79c31 --- /dev/null +++ b/crates/shadowsocks-service/src/local/net/udp/listener.rs @@ -0,0 +1,21 @@ +//! Local instance listener helpers + +use std::io; + +use shadowsocks::{config::ServerAddr, lookup_then, net::UdpSocket}; + +use crate::local::context::ServiceContext; + +/// Create a standard UDP listener listening on `client_config` +pub async fn create_standard_udp_listener( + context: &ServiceContext, + client_config: &ServerAddr, +) -> io::Result { + match client_config { + ServerAddr::SocketAddr(saddr) => UdpSocket::listen_with_opts(saddr, context.accept_opts()).await, + ServerAddr::DomainName(dname, port) => lookup_then!(context.context_ref(), dname, *port, |addr| { + UdpSocket::listen_with_opts(&addr, context.accept_opts()).await + }) + .map(|(_, s)| s), + } +} diff --git a/crates/shadowsocks-service/src/local/net/udp/mod.rs b/crates/shadowsocks-service/src/local/net/udp/mod.rs index 1cd5d91ecd02..20371dec0b9a 100644 --- a/crates/shadowsocks-service/src/local/net/udp/mod.rs +++ b/crates/shadowsocks-service/src/local/net/udp/mod.rs @@ -1,3 +1,4 @@ pub use self::association::{UdpAssociationManager, UdpInboundWrite}; pub mod association; +pub mod listener; diff --git a/crates/shadowsocks-service/src/local/socks/server/server.rs b/crates/shadowsocks-service/src/local/socks/server/server.rs index 2ee21e115315..4ae262675577 100644 --- a/crates/shadowsocks-service/src/local/socks/server/server.rs +++ b/crates/shadowsocks-service/src/local/socks/server/server.rs @@ -4,9 +4,11 @@ use log::{error, info}; use shadowsocks::{config::Mode, net::TcpListener as ShadowTcpListener, ServerAddr}; use tokio::{net::TcpStream, time}; -use crate::{ - local::{context::ServiceContext, loadbalancing::PingBalancer, socks::config::Socks5AuthConfig}, - net::listener::create_standard_tcp_listener, +use crate::local::{ + context::ServiceContext, + loadbalancing::PingBalancer, + net::tcp::listener::create_standard_tcp_listener, + socks::config::Socks5AuthConfig, }; #[cfg(feature = "local-socks4")] diff --git a/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs b/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs index 14ce16fa5958..fc765728fd4a 100644 --- a/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs +++ b/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs @@ -24,9 +24,9 @@ use crate::{ local::{ context::ServiceContext, loadbalancing::PingBalancer, - net::{UdpAssociationManager, UdpInboundWrite}, + net::{udp::listener::create_standard_udp_listener, UdpAssociationManager, UdpInboundWrite}, }, - net::{listener::create_standard_udp_listener, utils::to_ipv4_mapped}, + net::utils::to_ipv4_mapped, }; pub struct Socks5UdpServerBuilder { diff --git a/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs b/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs index 4bc49cd63391..dc8d66c6401a 100644 --- a/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs +++ b/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs @@ -6,14 +6,11 @@ use log::{error, info, trace}; use shadowsocks::{net::TcpListener as ShadowTcpListener, relay::socks5::Address, ServerAddr}; use tokio::{net::TcpStream, time}; -use crate::{ - local::{ - context::ServiceContext, - loadbalancing::PingBalancer, - net::AutoProxyClientStream, - utils::{establish_tcp_tunnel, establish_tcp_tunnel_bypassed}, - }, - net::listener::create_standard_tcp_listener, +use crate::local::{ + context::ServiceContext, + loadbalancing::PingBalancer, + net::{tcp::listener::create_standard_tcp_listener, AutoProxyClientStream}, + utils::{establish_tcp_tunnel, establish_tcp_tunnel_bypassed}, }; pub struct TunnelTcpServerBuilder { diff --git a/crates/shadowsocks-service/src/local/tunnel/udprelay.rs b/crates/shadowsocks-service/src/local/tunnel/udprelay.rs index a7f75b8c0e9a..9b1c1356186b 100644 --- a/crates/shadowsocks-service/src/local/tunnel/udprelay.rs +++ b/crates/shadowsocks-service/src/local/tunnel/udprelay.rs @@ -10,13 +10,10 @@ use shadowsocks::{ }; use tokio::{net::UdpSocket, time}; -use crate::{ - local::{ - context::ServiceContext, - loadbalancing::PingBalancer, - net::{UdpAssociationManager, UdpInboundWrite}, - }, - net::listener::create_standard_udp_listener, +use crate::local::{ + context::ServiceContext, + loadbalancing::PingBalancer, + net::{udp::listener::create_standard_udp_listener, UdpAssociationManager, UdpInboundWrite}, }; pub struct TunnelUdpServerBuilder { diff --git a/crates/shadowsocks-service/src/net/mod.rs b/crates/shadowsocks-service/src/net/mod.rs index 7b3c62d947e6..44ea46cc9ef1 100644 --- a/crates/shadowsocks-service/src/net/mod.rs +++ b/crates/shadowsocks-service/src/net/mod.rs @@ -5,7 +5,6 @@ pub use self::{flow::FlowStat, mon_socket::MonProxySocket, mon_stream::MonProxyS pub mod flow; #[cfg(target_os = "macos")] pub mod launch_activate_socket; -pub mod listener; pub mod mon_socket; pub mod mon_stream; pub mod packet_window; From b836f454343fd4ee8298ab5b7196107e8aa14dad Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Sun, 22 Oct 2023 02:07:07 +0800 Subject: [PATCH 10/11] feat(local): deleted unused file --- .../shadowsocks-service/src/net/listener.rs | 37 ------------------- 1 file changed, 37 deletions(-) delete mode 100644 crates/shadowsocks-service/src/net/listener.rs diff --git a/crates/shadowsocks-service/src/net/listener.rs b/crates/shadowsocks-service/src/net/listener.rs deleted file mode 100644 index b86187d3b929..000000000000 --- a/crates/shadowsocks-service/src/net/listener.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::io; - -use shadowsocks::{ - config::ServerAddr, - lookup_then, - net::{TcpListener, UdpSocket}, -}; - -use crate::local::context::ServiceContext; - -/// Create a standard TCP listener listening on `client_config` -pub async fn create_standard_tcp_listener( - context: &ServiceContext, - client_config: &ServerAddr, -) -> io::Result { - match client_config { - ServerAddr::SocketAddr(saddr) => TcpListener::bind_with_opts(saddr, context.accept_opts()).await, - ServerAddr::DomainName(dname, port) => lookup_then!(context.context_ref(), dname, *port, |addr| { - TcpListener::bind_with_opts(&addr, context.accept_opts()).await - }) - .map(|(_, l)| l), - } -} - -/// Create a standard UDP listener listening on `client_config` -pub async fn create_standard_udp_listener( - context: &ServiceContext, - client_config: &ServerAddr, -) -> io::Result { - match client_config { - ServerAddr::SocketAddr(saddr) => UdpSocket::listen_with_opts(saddr, context.accept_opts()).await, - ServerAddr::DomainName(dname, port) => lookup_then!(context.context_ref(), dname, *port, |addr| { - UdpSocket::listen_with_opts(&addr, context.accept_opts()).await - }) - .map(|(_, s)| s), - } -} From 84adf86510bebb9b8409a2920b4c3015c120b629 Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Sun, 22 Oct 2023 11:23:34 +0800 Subject: [PATCH 11/11] feat(local): launch activate socket should always success --- .../src/local/dns/server.rs | 16 ++++-------- .../src/local/http/server.rs | 10 +++---- .../src/local/socks/server/server.rs | 10 +++---- .../src/local/socks/server/socks5/udprelay.rs | 6 ++--- .../src/local/tunnel/tcprelay.rs | 10 +++---- .../src/local/tunnel/udprelay.rs | 6 ++--- .../src/net/launch_activate_socket.rs | 26 +++++++------------ .../shadowsocks-service/src/sys/unix/macos.rs | 17 ++++++------ 8 files changed, 37 insertions(+), 64 deletions(-) diff --git a/crates/shadowsocks-service/src/local/dns/server.rs b/crates/shadowsocks-service/src/local/dns/server.rs index e240cb62fc24..567a5eed55d3 100644 --- a/crates/shadowsocks-service/src/local/dns/server.rs +++ b/crates/shadowsocks-service/src/local/dns/server.rs @@ -216,13 +216,9 @@ impl DnsTcpServerBuilder { use tokio::net::TcpListener as TokioTcpListener; use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; - match get_launch_activate_tcp_listener(&launchd_socket_name)? { - Some(std_listener) => { - let tokio_listener = TokioTcpListener::from_std(std_listener)?; - TcpListener::from_listener(tokio_listener, self.context.accept_opts())? - } - None => create_standard_tcp_listener(&self.context, &self.bind_addr).await? - } + let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + TcpListener::from_listener(tokio_listener, self.context.accept_opts())? } else { create_standard_tcp_listener(&self.context, &self.bind_addr).await? }; @@ -393,10 +389,8 @@ impl DnsUdpServerBuilder { use tokio::net::UdpSocket as TokioUdpSocket; use crate::net::launch_activate_socket::get_launch_activate_udp_socket; - match get_launch_activate_udp_socket(&launchd_socket_name)? { - Some(std_socket) => TokioUdpSocket::from_std(std_socket)?, - None => create_standard_udp_listener(&self.context, &self.bind_addr).await?.into() - } + let std_socket = get_launch_activate_udp_socket(&launchd_socket_name)?; + TokioUdpSocket::from_std(std_socket)? } else { create_standard_udp_listener(&self.context, &self.bind_addr).await?.into() }; diff --git a/crates/shadowsocks-service/src/local/http/server.rs b/crates/shadowsocks-service/src/local/http/server.rs index bd55e7056c30..bf975609cfab 100644 --- a/crates/shadowsocks-service/src/local/http/server.rs +++ b/crates/shadowsocks-service/src/local/http/server.rs @@ -72,13 +72,9 @@ impl HttpBuilder { use tokio::net::TcpListener as TokioTcpListener; use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; - match get_launch_activate_tcp_listener(&launchd_socket_name)? { - Some(std_listener) => { - let tokio_listener = TokioTcpListener::from_std(std_listener)?; - TcpListener::from_listener(tokio_listener, self.context.accept_opts())? - } - None => create_standard_tcp_listener(&self.context, &self.client_config).await? - } + let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + TcpListener::from_listener(tokio_listener, self.context.accept_opts())? } else { create_standard_tcp_listener(&self.context, &self.client_config).await? }; diff --git a/crates/shadowsocks-service/src/local/socks/server/server.rs b/crates/shadowsocks-service/src/local/socks/server/server.rs index 4ae262675577..70614fa8895f 100644 --- a/crates/shadowsocks-service/src/local/socks/server/server.rs +++ b/crates/shadowsocks-service/src/local/socks/server/server.rs @@ -60,13 +60,9 @@ impl SocksTcpServerBuilder { use tokio::net::TcpListener as TokioTcpListener; use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; - match get_launch_activate_tcp_listener(&launchd_socket_name)? { - Some(std_listener) => { - let tokio_listener = TokioTcpListener::from_std(std_listener)?; - ShadowTcpListener::from_listener(tokio_listener, self.context.accept_opts())? - } - None => create_standard_tcp_listener(&self.context, &self.client_config).await? - } + let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + ShadowTcpListener::from_listener(tokio_listener, self.context.accept_opts())? } else { create_standard_tcp_listener(&self.context, &self.client_config).await? }; diff --git a/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs b/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs index fc765728fd4a..4c313d089996 100644 --- a/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs +++ b/crates/shadowsocks-service/src/local/socks/server/socks5/udprelay.rs @@ -71,10 +71,8 @@ impl Socks5UdpServerBuilder { use tokio::net::UdpSocket as TokioUdpSocket; use crate::net::launch_activate_socket::get_launch_activate_udp_socket; - match get_launch_activate_udp_socket(&launchd_socket_name)? { - Some(std_socket) => TokioUdpSocket::from_std(std_socket)?, - None => create_standard_udp_listener(&self.context, &self.client_config).await?.into() - } + let std_socket = get_launch_activate_udp_socket(&launchd_socket_name)?; + TokioUdpSocket::from_std(std_socket)? } else { create_standard_udp_listener(&self.context, &self.client_config).await?.into() }; diff --git a/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs b/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs index dc8d66c6401a..43bc864589c5 100644 --- a/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs +++ b/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs @@ -52,13 +52,9 @@ impl TunnelTcpServerBuilder { use tokio::net::TcpListener as TokioTcpListener; use crate::net::launch_activate_socket::get_launch_activate_tcp_listener; - match get_launch_activate_tcp_listener(&launchd_socket_name)? { - Some(std_listener) => { - let tokio_listener = TokioTcpListener::from_std(std_listener)?; - ShadowTcpListener::from_listener(tokio_listener, self.context.accept_opts())? - } - None => create_standard_tcp_listener(&self.context, &self.client_config).await? - } + let std_listener = get_launch_activate_tcp_listener(&launchd_socket_name)?; + let tokio_listener = TokioTcpListener::from_std(std_listener)?; + ShadowTcpListener::from_listener(tokio_listener, self.context.accept_opts())? } else { create_standard_tcp_listener(&self.context, &self.client_config).await? }; diff --git a/crates/shadowsocks-service/src/local/tunnel/udprelay.rs b/crates/shadowsocks-service/src/local/tunnel/udprelay.rs index 9b1c1356186b..4bace85ff225 100644 --- a/crates/shadowsocks-service/src/local/tunnel/udprelay.rs +++ b/crates/shadowsocks-service/src/local/tunnel/udprelay.rs @@ -61,10 +61,8 @@ impl TunnelUdpServerBuilder { use tokio::net::UdpSocket as TokioUdpSocket; use crate::net::launch_activate_socket::get_launch_activate_udp_socket; - match get_launch_activate_udp_socket(&launchd_socket_name)? { - Some(std_socket) => TokioUdpSocket::from_std(std_socket)?, - None => create_standard_udp_listener(&self.context, &self.client_config).await?.into() - } + let std_socket = get_launch_activate_udp_socket(&launchd_socket_name)?; + TokioUdpSocket::from_std(std_socket)? } else { create_standard_udp_listener(&self.context, &self.client_config).await?.into() }; diff --git a/crates/shadowsocks-service/src/net/launch_activate_socket.rs b/crates/shadowsocks-service/src/net/launch_activate_socket.rs index 9189025ce52b..85cafc0b79be 100644 --- a/crates/shadowsocks-service/src/net/launch_activate_socket.rs +++ b/crates/shadowsocks-service/src/net/launch_activate_socket.rs @@ -13,22 +13,16 @@ use log::debug; use crate::sys::get_launch_activate_socket; -pub fn get_launch_activate_tcp_listener(name: &str) -> io::Result> { - match get_launch_activate_socket(name)? { - Some(fd) => { - debug!("created TCP listener from launch activate socket {}", fd); - Ok(Some(unsafe { TcpListener::from_raw_fd(fd) })) - } - None => Ok(None), - } +/// Get a macOS launch active socket as a `TcpListener` +pub fn get_launch_activate_tcp_listener(name: &str) -> io::Result { + let fd = get_launch_activate_socket(name)?; + debug!("created TCP listener from launch activate socket {}", fd); + Ok(unsafe { TcpListener::from_raw_fd(fd) }) } -pub fn get_launch_activate_udp_socket(name: &str) -> io::Result> { - match get_launch_activate_socket(name)? { - Some(fd) => { - debug!("created UDP socket from launch activate socket {}", fd); - Ok(Some(unsafe { UdpSocket::from_raw_fd(fd) })) - } - None => Ok(None), - } +/// Get a macOS launch activate socket as a `UdpSocket` +pub fn get_launch_activate_udp_socket(name: &str) -> io::Result { + let fd = get_launch_activate_socket(name)?; + debug!("created UDP socket from launch activate socket {}", fd); + Ok(unsafe { UdpSocket::from_raw_fd(fd) }) } diff --git a/crates/shadowsocks-service/src/sys/unix/macos.rs b/crates/shadowsocks-service/src/sys/unix/macos.rs index dc50e3ba80e0..0e887d654e77 100644 --- a/crates/shadowsocks-service/src/sys/unix/macos.rs +++ b/crates/shadowsocks-service/src/sys/unix/macos.rs @@ -2,7 +2,7 @@ use std::{ffi::CString, io, os::fd::RawFd, ptr}; -use log::{error, warn}; +use log::error; extern "C" { /// https://developer.apple.com/documentation/xpc/1505523-launch_activate_socket @@ -13,7 +13,7 @@ extern "C" { ) -> libc::c_int; } -pub fn get_launch_activate_socket(name: &str) -> io::Result> { +pub fn get_launch_activate_socket(name: &str) -> io::Result { let mut fds: *mut libc::c_int = ptr::null_mut(); let mut cnt: libc::size_t = 0; @@ -33,12 +33,10 @@ pub fn get_launch_activate_socket(name: &str) -> io::Result> { let err = io::Error::last_os_error(); match err.raw_os_error() { Some(libc::ENOENT) => { - warn!("activate socket name \"{}\" doesn't exist, error: {}", name, err); - return Ok(None); + error!("activate socket name \"{}\" doesn't exist, error: {}", name, err); } Some(libc::ESRCH) => { - warn!("current process is not managed by launchd, error: {}", err); - return Ok(None); + error!("current process is not managed by launchd, error: {}", err); } Some(libc::EALREADY) => { error!( @@ -54,7 +52,10 @@ pub fn get_launch_activate_socket(name: &str) -> io::Result> { } let result = if cnt == 0 { - Ok(None) + Err(io::Error::new( + io::ErrorKind::InvalidData, + format!("launch socket with name \"{}\" doesn't exist", name), + )) } else if cnt > 1 { for idx in 0..cnt { unsafe { @@ -73,7 +74,7 @@ pub fn get_launch_activate_socket(name: &str) -> io::Result> { } else { // Take fds[0] as the result let fd = unsafe { *fds }; - Ok(Some(fd as RawFd)) + Ok(fd as RawFd) }; if !fds.is_null() {