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); }