Skip to content

Commit

Permalink
feat(local): local-dns support launch activate socket
Browse files Browse the repository at this point in the history
  • Loading branch information
zonyitoo committed Oct 20, 2023
1 parent 01e5a44 commit 1699daf
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 46 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
237 changes: 192 additions & 45 deletions crates/shadowsocks-service/src/local/dns/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
#[cfg(target_os = "macos")]
launchd_udp_socket_name: Option<String>,
}

impl DnsBuilder {
Expand Down Expand Up @@ -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,
}
}

Expand All @@ -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<Dns> {
let client = Arc::new(DnsClient::new(
Expand All @@ -115,61 +135,133 @@ 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);
}

Ok(Dns { tcp_server, udp_server })
}
}

/// DNS TCP server instance
pub struct DnsTcpServer {
listener: TcpListener,
struct DnsTcpServerBuilder {
context: Arc<ServiceContext>,
bind_addr: ServerAddr,
local_addr: Arc<NameServerAddr>,
remote_addr: Arc<Address>,
client: Arc<DnsClient>,
#[cfg(target_os = "macos")]
launchd_socket_name: Option<String>,
}

impl DnsTcpServer {
async fn new(
impl DnsTcpServerBuilder {
fn new(
context: Arc<ServiceContext>,
bind_addr: &ServerAddr,
bind_addr: ServerAddr,
local_addr: Arc<NameServerAddr>,
remote_addr: Arc<Address>,
client: Arc<DnsClient>,
) -> io::Result<DnsTcpServer> {
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<DnsTcpServer> {
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<NameServerAddr>,
remote_addr: Arc<Address>,
client: Arc<DnsClient>,
}

impl DnsTcpServer {
/// Get server local address
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.listener.local_addr()
Expand Down Expand Up @@ -272,43 +364,98 @@ impl DnsTcpServer {
}
}

/// DNS UDP server instance
pub struct DnsUdpServer {
listener: Arc<UdpSocket>,
struct DnsUdpServerBuilder {
context: Arc<ServiceContext>,
bind_addr: ServerAddr,
local_addr: Arc<NameServerAddr>,
remote_addr: Arc<Address>,
client: Arc<DnsClient>,
#[cfg(target_os = "macos")]
launchd_socket_name: Option<String>,
}

impl DnsUdpServer {
async fn new(
impl DnsUdpServerBuilder {
fn new(
context: Arc<ServiceContext>,
bind_addr: &ServerAddr,
bind_addr: ServerAddr,
local_addr: Arc<NameServerAddr>,
remote_addr: Arc<Address>,
client: Arc<DnsClient>,
) -> io::Result<DnsUdpServer> {
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<DnsUdpServer> {
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<UdpSocket>,
local_addr: Arc<NameServerAddr>,
remote_addr: Arc<Address>,
client: Arc<DnsClient>,
}

impl DnsUdpServer {
/// Get server local address
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.listener.local_addr()
Expand Down
9 changes: 9 additions & 0 deletions crates/shadowsocks-service/src/local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down

0 comments on commit 1699daf

Please sign in to comment.