Skip to content

Commit

Permalink
feat(local): local-tunnel 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 66e5b6d commit 9bed71b
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 61 deletions.
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 @@ -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);
}
Expand Down
2 changes: 2 additions & 0 deletions crates/shadowsocks-service/src/local/socks/server/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub struct SocksTcpServerBuilder {
balancer: PingBalancer,
mode: Mode,
socks5_auth: Arc<Socks5AuthConfig>,
#[cfg(target_os = "macos")]
launchd_socket_name: Option<String>,
}

Expand All @@ -38,6 +39,7 @@ impl SocksTcpServerBuilder {
balancer,
mode,
socks5_auth: Arc::new(socks5_auth),
#[cfg(target_os = "macos")]
launchd_socket_name: None,
}
}
Expand Down
55 changes: 46 additions & 9 deletions crates/shadowsocks-service/src/local/tunnel/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ServiceContext>,
Expand All @@ -18,6 +21,10 @@ pub struct TunnelBuilder {
client_addr: ServerAddr,
udp_addr: Option<ServerAddr>,
balancer: PingBalancer,
#[cfg(target_os = "macos")]
launchd_tcp_socket_name: Option<String>,
#[cfg(target_os = "macos")]
launchd_udp_socket_name: Option<String>,
}

impl TunnelBuilder {
Expand All @@ -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,
}
}

Expand All @@ -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<Tunnel> {
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);
}

Expand Down
93 changes: 73 additions & 20 deletions crates/shadowsocks-service/src/local/tunnel/tcprelay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ServiceContext>,
listener: ShadowTcpListener,
client_config: ServerAddr,
balancer: PingBalancer,
forward_addr: Address,
#[cfg(target_os = "macos")]
launchd_socket_name: Option<String>,
}

impl TunnelTcpServer {
pub(crate) async fn new(
impl TunnelTcpServerBuilder {
pub(crate) fn new(
context: Arc<ServiceContext>,
client_config: &ServerAddr,
client_config: ServerAddr,
balancer: PingBalancer,
forward_addr: Address,
) -> io::Result<TunnelTcpServer> {
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<TunnelTcpServer> {
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<ServiceContext>,
listener: ShadowTcpListener,
balancer: PingBalancer,
forward_addr: Address,
}

impl TunnelTcpServer {
/// Server's local address
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.listener.local_addr()
Expand Down
120 changes: 88 additions & 32 deletions crates/shadowsocks-service/src/local/tunnel/udprelay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,94 @@ use crate::local::{
net::{UdpAssociationManager, UdpInboundWrite},
};

pub struct TunnelUdpServerBuilder {
context: Arc<ServiceContext>,
client_config: ServerAddr,
time_to_live: Option<Duration>,
capacity: Option<usize>,
balancer: PingBalancer,
forward_addr: Address,
#[cfg(target_os = "macos")]
launchd_socket_name: Option<String>,
}

impl TunnelUdpServerBuilder {
pub(crate) fn new(
context: Arc<ServiceContext>,
client_config: ServerAddr,
time_to_live: Option<Duration>,
capacity: Option<usize>,
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<TunnelUdpServer> {
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<UdpSocket>,
Expand All @@ -40,38 +128,6 @@ pub struct TunnelUdpServer {
}

impl TunnelUdpServer {
pub(crate) async fn new(
context: Arc<ServiceContext>,
client_config: &ServerAddr,
time_to_live: Option<Duration>,
capacity: Option<usize>,
balancer: PingBalancer,
forward_addr: Address,
) -> io::Result<TunnelUdpServer> {
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<SocketAddr> {
self.listener.local_addr()
Expand Down

0 comments on commit 9bed71b

Please sign in to comment.