Skip to content

Commit

Permalink
allow sslocal run without servers (#818)
Browse files Browse the repository at this point in the history
If no server was configured, then sslocal will bypass all connections
and packets.
  • Loading branch information
zonyitoo committed May 15, 2022
1 parent 5146c7d commit 855f7fa
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 446 deletions.
9 changes: 0 additions & 9 deletions crates/shadowsocks-service/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1936,15 +1936,6 @@ impl Config {
local_config.check_integrity()?;
}

if self.server.is_empty() {
let err = Error::new(
ErrorKind::MissingField,
"missing `servers` for client configuration",
None,
);
return Err(err);
}

// Balancer related checks
if let Some(rtt) = self.balancer.max_server_rtt {
if rtt.as_secs() == 0 {
Expand Down
5 changes: 5 additions & 0 deletions crates/shadowsocks-service/src/local/dns/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ fn check_name_in_proxy_list(acl: &AccessControl, name: &Name) -> Option<bool> {

/// given the query, determine whether remote/local query should be used, or inconclusive
fn should_forward_by_query(context: &ServiceContext, balancer: &PingBalancer, query: &Query) -> Option<bool> {
// No server was configured, then always resolve with local
if balancer.is_empty() {
return Some(false);
}

// Check if we are trying to make queries for remote servers
//
// This happens normally because VPN or TUN device receives DNS queries from local servers' plugins
Expand Down
47 changes: 33 additions & 14 deletions crates/shadowsocks-service/src/local/http/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use shadowsocks::relay::socks5::Address;
use crate::local::{
context::ServiceContext,
loadbalancing::PingBalancer,
net::AutoProxyClientStream,
utils::establish_tcp_tunnel,
net::{AutoProxyClientStream, AutoProxyIo},
utils::{establish_tcp_tunnel, establish_tcp_tunnel_bypassed},
};

use super::{
Expand Down Expand Up @@ -101,10 +101,24 @@ impl HttpDispatcher {
// Connect to Shadowsocks' remote
//
// FIXME: What STATUS should I return for connection error?
let server = self.balancer.best_tcp_server();
let mut stream = AutoProxyClientStream::connect(self.context, server.as_ref(), &host).await?;
let mut server_opt = None;
let mut stream = if self.balancer.is_empty() {
AutoProxyClientStream::connect_bypassed(self.context, &host).await?
} else {
let server = self.balancer.best_tcp_server();

debug!("CONNECT relay connected {} <-> {}", self.client_addr, host);
let stream = AutoProxyClientStream::connect(self.context, server.as_ref(), &host).await?;
server_opt = Some(server);

stream
};

debug!(
"CONNECT relay connected {} <-> {} ({})",
self.client_addr,
host,
if stream.is_bypassed() { "bypassed" } else { "proxied" }
);

// Upgrade to a TCP tunnel
//
Expand All @@ -118,14 +132,19 @@ impl HttpDispatcher {
Ok(mut upgraded) => {
trace!("CONNECT tunnel upgrade success, {} <-> {}", client_addr, host);

let _ = establish_tcp_tunnel(
server.server_config(),
&mut upgraded,
&mut stream,
client_addr,
&host,
)
.await;
let _ = match server_opt {
Some(server) => {
establish_tcp_tunnel(
server.server_config(),
&mut upgraded,
&mut stream,
client_addr,
&host,
)
.await
}
None => establish_tcp_tunnel_bypassed(&mut upgraded, &mut stream, client_addr, &host).await,
};
}
Err(e) => {
error!(
Expand Down Expand Up @@ -153,7 +172,7 @@ impl HttpDispatcher {

// Set keep-alive for connection with remote
set_conn_keep_alive(version, self.req.headers_mut(), conn_keep_alive);
let client = if self.context.check_target_bypassed(&host).await {
let client = if self.balancer.is_empty() || self.context.check_target_bypassed(&host).await {
trace!("bypassed {} -> {} {:?}", self.client_addr, host, self.req);
HttpClientEnum::Bypass(self.bypass_client)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ impl PingBalancerBuilder {
}

fn find_best_idx(servers: &[Arc<ServerIdent>], mode: Mode) -> (usize, usize) {
if servers.is_empty() {
trace!("init without any TCP and UDP servers");
return (0, 0);
}

let mut best_tcp_idx = 0;
let mut best_udp_idx = 0;

Expand Down Expand Up @@ -157,8 +162,6 @@ impl PingBalancerBuilder {
}

pub async fn build(self) -> io::Result<PingBalancer> {
assert!(!self.servers.is_empty(), "build PingBalancer without any servers");

if let Some(intv) = self.check_best_interval {
if intv > self.check_interval {
return Err(io::Error::new(
Expand Down Expand Up @@ -215,12 +218,19 @@ struct PingBalancerContext {

impl PingBalancerContext {
fn best_tcp_server(&self) -> Arc<ServerIdent> {
assert!(!self.is_empty(), "no available server");
self.servers[self.best_tcp_idx.load(Ordering::Relaxed)].clone()
}

fn best_udp_server(&self) -> Arc<ServerIdent> {
assert!(!self.is_empty(), "no available server");
self.servers[self.best_udp_idx.load(Ordering::Relaxed)].clone()
}

#[inline]
fn is_empty(&self) -> bool {
self.servers.is_empty()
}
}

impl PingBalancerContext {
Expand Down Expand Up @@ -328,8 +338,9 @@ impl PingBalancerContext {
}

async fn init_score(&self) {
assert!(!self.servers.is_empty(), "check PingBalancer without any servers");

if self.servers.is_empty() {
return;
}
self.check_once(true).await;
}

Expand All @@ -342,6 +353,10 @@ impl PingBalancerContext {
}

fn probing_required(&self) -> bool {
if self.servers.is_empty() {
return false;
}

let mut tcp_count = 0;
let mut udp_count = 0;

Expand Down Expand Up @@ -376,6 +391,9 @@ impl PingBalancerContext {
/// Check each servers' score and update the best server's index
async fn check_once(&self, first_run: bool) {
let servers = &self.servers;
if servers.is_empty() {
return;
}

let mut vfut_tcp = Vec::with_capacity(servers.len());
let mut vfut_udp = Vec::with_capacity(servers.len());
Expand Down Expand Up @@ -496,6 +514,9 @@ impl PingBalancerContext {
/// Check the best server only
async fn check_best_server(&self) {
let servers = &self.servers;
if servers.is_empty() {
return;
}

let mut vfut = Vec::new();

Expand Down Expand Up @@ -689,6 +710,13 @@ impl PingBalancer {
context.best_udp_server()
}

/// Check if there is no available server
#[inline]
pub fn is_empty(&self) -> bool {
let context = self.inner.context.load();
context.is_empty()
}

/// Get the server list
pub fn servers(&self) -> PingServerIter<'_> {
let context = self.inner.context.load();
Expand Down
1 change: 0 additions & 1 deletion crates/shadowsocks-service/src/local/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ impl Server {
/// Starts a shadowsocks local server
pub async fn create(config: Config) -> io::Result<Server> {
assert!(config.config_type == ConfigType::Local && !config.local.is_empty());
assert!(!config.server.is_empty());

trace!("{:?}", config);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ where

async fn dispatch_received_packet(&mut self, target_addr: &Address, data: &[u8]) {
// Check if target should be bypassed. If so, send packets directly.
let bypassed = self.context.check_target_bypassed(target_addr).await;
let bypassed = self.balancer.is_empty() || self.context.check_target_bypassed(target_addr).await;

trace!(
"udp relay {} -> {} ({}) with {} bytes",
Expand Down
7 changes: 6 additions & 1 deletion crates/shadowsocks-service/src/local/redir/tcprelay/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{
loadbalancing::PingBalancer,
net::AutoProxyClientStream,
redir::redir_ext::{TcpListenerRedirExt, TcpStreamRedirExt},
utils::{establish_tcp_tunnel, to_ipv4_mapped},
utils::{establish_tcp_tunnel, establish_tcp_tunnel_bypassed, to_ipv4_mapped},
},
};

Expand All @@ -37,6 +37,11 @@ async fn establish_client_tcp_redir<'a>(
peer_addr: SocketAddr,
addr: &Address,
) -> io::Result<()> {
if balancer.is_empty() {
let mut remote = AutoProxyClientStream::connect_bypassed(context, addr).await?;
return establish_tcp_tunnel_bypassed(&mut stream, &mut remote, peer_addr, addr).await;
}

let server = balancer.best_tcp_server();
let svr_cfg = server.server_config();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::local::{
context::ServiceContext,
loadbalancing::PingBalancer,
net::AutoProxyClientStream,
utils::establish_tcp_tunnel,
utils::{establish_tcp_tunnel, establish_tcp_tunnel_bypassed},
};

use crate::local::socks::socks4::{
Expand Down Expand Up @@ -95,11 +95,20 @@ impl Socks4TcpHandler {
return Ok(());
}

let server = self.balancer.best_tcp_server();
let svr_cfg = server.server_config();
let target_addr = target_addr.into();
let mut server_opt = None;
let server_result = if self.balancer.is_empty() {
AutoProxyClientStream::connect_bypassed(self.context, &target_addr).await
} else {
let server = self.balancer.best_tcp_server();

let mut remote = match AutoProxyClientStream::connect(self.context, &server, &target_addr).await {
let r = AutoProxyClientStream::connect(self.context, &server, &target_addr).await;
server_opt = Some(server);

r
};

let mut remote = match server_result {
Ok(remote) => {
// Tell the client that we are ready
let handshake_rsp = HandshakeResponse::new(ResultCode::RequestGranted);
Expand Down Expand Up @@ -132,6 +141,12 @@ impl Socks4TcpHandler {
// UNWRAP.
let mut stream = stream.into_inner();

establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, &target_addr).await
match server_opt {
Some(server) => {
let svr_cfg = server.server_config();
establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, &target_addr).await
}
None => establish_tcp_tunnel_bypassed(&mut stream, &mut remote, peer_addr, &target_addr).await,
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use crate::{
loadbalancing::PingBalancer,
net::AutoProxyClientStream,
socks::config::Socks5AuthConfig,
utils::establish_tcp_tunnel,
utils::{establish_tcp_tunnel, establish_tcp_tunnel_bypassed},
},
net::utils::ignore_until_end,
};
Expand Down Expand Up @@ -251,10 +251,19 @@ impl Socks5TcpHandler {
return Ok(());
}

let server = self.balancer.best_tcp_server();
let svr_cfg = server.server_config();
let mut server_opt = None;
let remote_result = if self.balancer.is_empty() {
AutoProxyClientStream::connect_bypassed(self.context.clone(), &target_addr).await
} else {
let server = self.balancer.best_tcp_server();

let r = AutoProxyClientStream::connect(self.context.clone(), &server, &target_addr).await;
server_opt = Some(server);

r
};

let mut remote = match AutoProxyClientStream::connect(self.context.clone(), &server, &target_addr).await {
let mut remote = match remote_result {
Ok(remote) => {
// Tell the client that we are ready
let header =
Expand All @@ -280,7 +289,13 @@ impl Socks5TcpHandler {
}
};

establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, &target_addr).await
match server_opt {
Some(server) => {
let svr_cfg = server.server_config();
establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, &target_addr).await
}
None => establish_tcp_tunnel_bypassed(&mut stream, &mut remote, peer_addr, &target_addr).await,
}
}

async fn handle_udp_associate(self, mut stream: TcpStream, client_addr: Address) -> io::Result<()> {
Expand Down
8 changes: 6 additions & 2 deletions crates/shadowsocks-service/src/local/tun/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use crate::local::{
context::ServiceContext,
loadbalancing::PingBalancer,
net::AutoProxyClientStream,
utils::{establish_tcp_tunnel, to_ipv4_mapped},
utils::{establish_tcp_tunnel, establish_tcp_tunnel_bypassed, to_ipv4_mapped},
};

use super::virt_device::VirtTunDevice;
Expand Down Expand Up @@ -477,11 +477,15 @@ async fn establish_client_tcp_redir<'a>(
peer_addr: SocketAddr,
addr: &Address,
) -> io::Result<()> {
if balancer.is_empty() {
let mut remote = AutoProxyClientStream::connect_bypassed(context, addr).await?;
return establish_tcp_tunnel_bypassed(&mut stream, &mut remote, peer_addr, addr).await;
}

let server = balancer.best_tcp_server();
let svr_cfg = server.server_config();

let mut remote = AutoProxyClientStream::connect(context, &server, addr).await?;

establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, addr).await
}

Expand Down
10 changes: 8 additions & 2 deletions crates/shadowsocks-service/src/local/tunnel/tcprelay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::local::{
context::ServiceContext,
loadbalancing::PingBalancer,
net::AutoProxyClientStream,
utils::establish_tcp_tunnel,
utils::{establish_tcp_tunnel, establish_tcp_tunnel_bypassed},
};

pub async fn run_tcp_tunnel(
Expand Down Expand Up @@ -61,6 +61,13 @@ async fn handle_tcp_client(
peer_addr: SocketAddr,
forward_addr: Address,
) -> io::Result<()> {
if balancer.is_empty() {
trace!("establishing tcp tunnel {} <-> {} direct", peer_addr, forward_addr);

let mut remote = AutoProxyClientStream::connect_bypassed(context, &forward_addr).await?;
return establish_tcp_tunnel_bypassed(&mut stream, &mut remote, peer_addr, &forward_addr).await;
}

let server = balancer.best_tcp_server();
let svr_cfg = server.server_config();
trace!(
Expand All @@ -72,6 +79,5 @@ async fn handle_tcp_client(
);

let mut remote = AutoProxyClientStream::connect_proxied(context, &server, &forward_addr).await?;

establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, &forward_addr).await
}
Loading

0 comments on commit 855f7fa

Please sign in to comment.