Skip to content

Commit

Permalink
Fix per-server outbound options not taking effect (part 2) (#1491)
Browse files Browse the repository at this point in the history
* Fix per-server outbound options not taking effect
1. Add outbound_bind_addr and outbound_bind_interface into ServerInstanceConfig
2. Add new interfaces for specifying ConnectOpts in AutoProxyClientStream

* Resolve some clippy warnings
  • Loading branch information
stormynoct committed Apr 18, 2024
1 parent ff01e90 commit c68172b
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 14 deletions.
52 changes: 50 additions & 2 deletions crates/shadowsocks-service/src/config.rs
Expand Up @@ -393,6 +393,12 @@ struct SSServerExtConfig {
#[serde(skip_serializing_if = "Option::is_none")]
#[cfg(any(target_os = "linux", target_os = "android"))]
outbound_fwmark: Option<u32>,

#[serde(skip_serializing_if = "Option::is_none")]
outbound_bind_addr: Option<IpAddr>,

#[serde(skip_serializing_if = "Option::is_none")]
outbound_bind_interface: Option<String>,
}

/// Server config type
Expand Down Expand Up @@ -1178,9 +1184,11 @@ pub struct ServerInstanceConfig {
pub config: ServerConfig,
/// Server's private ACL, set to `None` will use the global `AccessControl`
pub acl: Option<AccessControl>,
/// Server's outbound fwmark to support split tunnel
/// Server's outbound fwmark / address / interface to support split tunnel
#[cfg(any(target_os = "linux", target_os = "android"))]
pub outbound_fwmark: Option<u32>,
pub outbound_bind_addr: Option<IpAddr>,
pub outbound_bind_interface: Option<String>,
}

impl ServerInstanceConfig {
Expand All @@ -1191,6 +1199,8 @@ impl ServerInstanceConfig {
acl: None,
#[cfg(any(target_os = "linux", target_os = "android"))]
outbound_fwmark: None,
outbound_bind_addr: None,
outbound_bind_interface: None,
}
}
}
Expand Down Expand Up @@ -1861,11 +1871,25 @@ impl Config {
nsvr.set_timeout(timeout);
}

let mut outbound_bind_addr: Option<IpAddr> = None;

if let Some(ref bind_addr) = config.outbound_bind_addr {
match bind_addr.parse::<IpAddr>() {
Ok(b) => outbound_bind_addr = Some(b),
Err(..) => {
let err = Error::new(ErrorKind::Invalid, "invalid outbound_bind_addr", None);
return Err(err);
}
}
}

let server_instance = ServerInstanceConfig {
config: nsvr,
acl: None,
#[cfg(any(target_os = "linux", target_os = "android"))]
outbound_fwmark: config.outbound_fwmark,
outbound_bind_addr,
outbound_bind_interface: config.outbound_bind_interface.clone(),
};

nconfig.server.push(server_instance);
Expand Down Expand Up @@ -2029,11 +2053,25 @@ impl Config {
nsvr.set_weight(weight);
}

let mut outbound_bind_addr: Option<IpAddr> = None;

if let Some(ref bind_addr) = config.outbound_bind_addr {
match bind_addr.parse::<IpAddr>() {
Ok(b) => outbound_bind_addr = Some(b),
Err(..) => {
let err = Error::new(ErrorKind::Invalid, "invalid outbound_bind_addr", None);
return Err(err);
}
}
}

let mut server_instance = ServerInstanceConfig {
config: nsvr,
acl: None,
#[cfg(any(target_os = "linux", target_os = "android"))]
outbound_fwmark: config.outbound_fwmark,
outbound_bind_addr,
outbound_bind_interface: config.outbound_bind_interface.clone(),
};

if let Some(acl_path) = svr.acl {
Expand All @@ -2056,6 +2094,14 @@ impl Config {
server_instance.outbound_fwmark = Some(outbound_fwmark);
}

if let Some(outbound_bind_addr) = svr.outbound_bind_addr {
server_instance.outbound_bind_addr = Some(outbound_bind_addr);
}

if let Some(ref outbound_bind_interface) = svr.outbound_bind_interface {
server_instance.outbound_bind_interface = Some(outbound_bind_interface.clone());
}

nconfig.server.push(server_instance);
}
}
Expand Down Expand Up @@ -2829,7 +2875,9 @@ impl fmt::Display for Config {
.as_ref()
.and_then(|a| a.file_path().to_str().map(ToOwned::to_owned)),
#[cfg(any(target_os = "linux", target_os = "android"))]
outbound_fwmark: inst.outbound_fwmark.clone(),
outbound_fwmark: inst.outbound_fwmark,
outbound_bind_addr: inst.outbound_bind_addr,
outbound_bind_interface: inst.outbound_bind_interface.clone(),
});
}

Expand Down
7 changes: 6 additions & 1 deletion crates/shadowsocks-service/src/local/http/utils.rs
Expand Up @@ -131,7 +131,12 @@ pub async fn connect_host(
} else {
let server = balancer.best_tcp_server();

match AutoProxyClientStream::connect(context, server.as_ref(), host).await {
match AutoProxyClientStream::connect_with_opts(
context,
server.as_ref(),
host,
server.connect_opts_ref()
).await {
Ok(s) => Ok((s, Some(server))),
Err(err) => {
error!(
Expand Down
Expand Up @@ -86,6 +86,14 @@ impl ServerIdent {
connect_opts.fwmark = Some(fwmark);
}

if let Some(bind_local_addr) = svr_cfg.outbound_bind_addr {
connect_opts.bind_local_addr = Some(bind_local_addr);
}

if let Some(ref bind_interface) = svr_cfg.outbound_bind_interface {
connect_opts.bind_interface = Some(bind_interface.clone());
}

ServerIdent {
tcp_score: ServerScore::new(svr_cfg.config.weight().tcp_weight(), max_server_rtt, check_window),
udp_score: ServerScore::new(svr_cfg.config.weight().udp_weight(), max_server_rtt, check_window),
Expand Down
54 changes: 49 additions & 5 deletions crates/shadowsocks-service/src/local/net/tcp/auto_proxy_stream.rs
Expand Up @@ -10,7 +10,7 @@ use std::{

use pin_project::pin_project;
use shadowsocks::{
net::TcpStream,
net::{ConnectOpts, TcpStream},
relay::{socks5::Address, tcprelay::proxy_stream::ProxyClientStream},
};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
Expand All @@ -37,19 +37,44 @@ impl AutoProxyClientStream {
server: &ServerIdent,
addr: A,
) -> io::Result<AutoProxyClientStream>
where
A: Into<Address>,
{
AutoProxyClientStream::connect_with_opts(context.clone(), server, addr, context.connect_opts_ref()).await
}

/// Connect to target `addr` via shadowsocks' server configured by `svr_cfg`
pub async fn connect_with_opts<A>(
context: Arc<ServiceContext>,
server: &ServerIdent,
addr: A,
opts: &ConnectOpts,
) -> io::Result<AutoProxyClientStream>
where
A: Into<Address>,
{
let addr = addr.into();
if context.check_target_bypassed(&addr).await {
AutoProxyClientStream::connect_bypassed(context, addr).await
AutoProxyClientStream::connect_bypassed_with_opts(context, addr, opts).await
} else {
AutoProxyClientStream::connect_proxied(context, server, addr).await
AutoProxyClientStream::connect_proxied_with_opts(context, server, addr, opts).await
}
}

/// Connect directly to target `addr`
pub async fn connect_bypassed<A>(context: Arc<ServiceContext>, addr: A) -> io::Result<AutoProxyClientStream>
where
A: Into<Address>,
{
AutoProxyClientStream::connect_bypassed_with_opts(context.clone(), addr, context.connect_opts_ref()).await
}

/// Connect directly to target `addr`
pub async fn connect_bypassed_with_opts<A>(
context: Arc<ServiceContext>,
addr: A,
connect_opts: &ConnectOpts,
) -> io::Result<AutoProxyClientStream>
where
A: Into<Address>,
{
Expand All @@ -61,7 +86,7 @@ impl AutoProxyClientStream {
addr = mapped_addr;
}
let stream =
TcpStream::connect_remote_with_opts(context.context_ref(), &addr, context.connect_opts_ref()).await?;
TcpStream::connect_remote_with_opts(context.context_ref(), &addr, connect_opts).await?;
Ok(AutoProxyClientStream::Bypassed(stream))
}

Expand All @@ -71,6 +96,25 @@ impl AutoProxyClientStream {
server: &ServerIdent,
addr: A,
) -> io::Result<AutoProxyClientStream>
where
A: Into<Address>,
{
AutoProxyClientStream::connect_proxied_with_opts(
context.clone(),
server,
addr,
context.connect_opts_ref()
)
.await
}

/// Connect to target `addr` via shadowsocks' server configured by `svr_cfg`
pub async fn connect_proxied_with_opts<A>(
context: Arc<ServiceContext>,
server: &ServerIdent,
addr: A,
connect_opts: &ConnectOpts,
) -> io::Result<AutoProxyClientStream>
where
A: Into<Address>,
{
Expand All @@ -85,7 +129,7 @@ impl AutoProxyClientStream {
context.context(),
server.server_config(),
addr,
context.connect_opts_ref(),
connect_opts,
|stream| MonProxyStream::from_stream(stream, flow_stat),
)
.await
Expand Down
Expand Up @@ -572,7 +572,7 @@ where
let svr_cfg = server.server_config();

let socket =
ProxySocket::connect_with_opts(self.context.context(), svr_cfg, self.context.connect_opts_ref())
ProxySocket::connect_with_opts(self.context.context(), svr_cfg, server.connect_opts_ref())
.await?;
let socket = MonProxySocket::from_socket(socket, self.context.flow_stat());

Expand Down
2 changes: 1 addition & 1 deletion crates/shadowsocks-service/src/local/redir/tcprelay/mod.rs
Expand Up @@ -47,7 +47,7 @@ async fn establish_client_tcp_redir<'a>(
let server = balancer.best_tcp_server();
let svr_cfg = server.server_config();

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

establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, addr).await
}
Expand Down
Expand Up @@ -102,7 +102,13 @@ impl Socks4TcpHandler {
} else {
let server = self.balancer.best_tcp_server();

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

r
Expand Down
Expand Up @@ -254,7 +254,13 @@ impl Socks5TcpHandler {
} else {
let server = self.balancer.best_tcp_server();

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

r
Expand Down
2 changes: 1 addition & 1 deletion crates/shadowsocks-service/src/local/tun/tcp.rs
Expand Up @@ -576,7 +576,7 @@ async fn establish_client_tcp_redir<'a>(
let server = balancer.best_tcp_server();
let svr_cfg = server.server_config();

let mut remote = AutoProxyClientStream::connect(context, &server, addr).await?;
let mut remote = AutoProxyClientStream::connect_with_opts(context, &server, addr, server.connect_opts_ref()).await?;
establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, addr).await
}

Expand Down
8 changes: 7 additions & 1 deletion crates/shadowsocks-service/src/local/tunnel/tcprelay.rs
Expand Up @@ -138,6 +138,12 @@ async fn handle_tcp_client(
svr_cfg.addr(),
);

let mut remote = AutoProxyClientStream::connect_proxied(context, &server, forward_addr).await?;
let mut remote = AutoProxyClientStream::connect_proxied_with_opts(
context,
&server,
forward_addr,
server.connect_opts_ref()
)
.await?;
establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, forward_addr).await
}
2 changes: 2 additions & 0 deletions crates/shadowsocks-service/src/manager/server.rs
Expand Up @@ -410,6 +410,8 @@ impl Manager {
acl: None, // Set with --acl command line argument
#[cfg(any(target_os = "linux", target_os = "android"))]
outbound_fwmark: None,
outbound_bind_addr: None,
outbound_bind_interface: None,
};

let mut config = Config::new(ConfigType::Server);
Expand Down
8 changes: 8 additions & 0 deletions crates/shadowsocks-service/src/server/mod.rs
Expand Up @@ -116,6 +116,14 @@ pub async fn run(config: Config) -> io::Result<()> {
connect_opts.fwmark = Some(fwmark);
}

if let Some(bind_local_addr) = inst.outbound_bind_addr {
connect_opts.bind_local_addr = Some(bind_local_addr);
}

if let Some(bind_interface) = inst.outbound_bind_interface {
connect_opts.bind_interface = Some(bind_interface);
}

server_builder.set_connect_opts(connect_opts.clone());
server_builder.set_accept_opts(accept_opts.clone());

Expand Down

0 comments on commit c68172b

Please sign in to comment.