Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix per-server outbound options not taking effect (part 2) #1491

Merged
merged 2 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 50 additions & 2 deletions crates/shadowsocks-service/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,12 @@
#[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 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 @@
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 @@ -1518,8 +1528,8 @@
};
#[cfg(target_os = "macos")]
{
local_config.launchd_tcp_socket_name = config.launchd_tcp_socket_name.clone();

Check warning on line 1531 in crates/shadowsocks-service/src/config.rs

View workflow job for this annotation

GitHub Actions / clippy-check (macos-latest)

assigning the result of `Clone::clone()` may be inefficient

warning: assigning the result of `Clone::clone()` may be inefficient --> crates/shadowsocks-service/src/config.rs:1531:25 | 1531 | local_config.launchd_tcp_socket_name = config.launchd_tcp_socket_name.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `local_config.launchd_tcp_socket_name.clone_from(&config.launchd_tcp_socket_name)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#assigning_clones = note: `#[warn(clippy::assigning_clones)]` on by default
local_config.launchd_udp_socket_name = config.launchd_udp_socket_name.clone();

Check warning on line 1532 in crates/shadowsocks-service/src/config.rs

View workflow job for this annotation

GitHub Actions / clippy-check (macos-latest)

assigning the result of `Clone::clone()` may be inefficient

warning: assigning the result of `Clone::clone()` may be inefficient --> crates/shadowsocks-service/src/config.rs:1532:25 | 1532 | local_config.launchd_udp_socket_name = config.launchd_udp_socket_name.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `local_config.launchd_udp_socket_name.clone_from(&config.launchd_udp_socket_name)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#assigning_clones
}

let local_instance = LocalInstanceConfig {
Expand Down Expand Up @@ -1861,11 +1871,25 @@
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 @@
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 @@
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 @@ -2567,8 +2613,8 @@

#[cfg(target_os = "macos")]
{
jconf.launchd_tcp_socket_name = local.launchd_tcp_socket_name.clone();

Check warning on line 2616 in crates/shadowsocks-service/src/config.rs

View workflow job for this annotation

GitHub Actions / clippy-check (macos-latest)

assigning the result of `Clone::clone()` may be inefficient

warning: assigning the result of `Clone::clone()` may be inefficient --> crates/shadowsocks-service/src/config.rs:2616:21 | 2616 | jconf.launchd_tcp_socket_name = local.launchd_tcp_socket_name.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `jconf.launchd_tcp_socket_name.clone_from(&local.launchd_tcp_socket_name)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#assigning_clones
jconf.launchd_udp_socket_name = local.launchd_udp_socket_name.clone();

Check warning on line 2617 in crates/shadowsocks-service/src/config.rs

View workflow job for this annotation

GitHub Actions / clippy-check (macos-latest)

assigning the result of `Clone::clone()` may be inefficient

warning: assigning the result of `Clone::clone()` may be inefficient --> crates/shadowsocks-service/src/config.rs:2617:21 | 2617 | jconf.launchd_udp_socket_name = local.launchd_udp_socket_name.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `jconf.launchd_udp_socket_name.clone_from(&local.launchd_udp_socket_name)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#assigning_clones
}

if local.protocol != ProtocolType::Socks {
Expand Down Expand Up @@ -2829,7 +2875,9 @@
.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 Expand Up @@ -2933,7 +2981,7 @@
}

jconf.outbound_bind_addr = self.outbound_bind_addr.map(|i| i.to_string());
jconf.outbound_bind_interface = self.outbound_bind_interface.clone();

Check warning on line 2984 in crates/shadowsocks-service/src/config.rs

View workflow job for this annotation

GitHub Actions / clippy-check (ubuntu-latest)

assigning the result of `Clone::clone()` may be inefficient

warning: assigning the result of `Clone::clone()` may be inefficient --> crates/shadowsocks-service/src/config.rs:2984:9 | 2984 | jconf.outbound_bind_interface = self.outbound_bind_interface.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `jconf.outbound_bind_interface.clone_from(&self.outbound_bind_interface)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#assigning_clones = note: `#[warn(clippy::assigning_clones)]` on by default

Check warning on line 2984 in crates/shadowsocks-service/src/config.rs

View workflow job for this annotation

GitHub Actions / clippy-check (macos-latest)

assigning the result of `Clone::clone()` may be inefficient

warning: assigning the result of `Clone::clone()` may be inefficient --> crates/shadowsocks-service/src/config.rs:2984:9 | 2984 | jconf.outbound_bind_interface = self.outbound_bind_interface.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `jconf.outbound_bind_interface.clone_from(&self.outbound_bind_interface)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#assigning_clones

// Security
if self.security.replay_attack.policy != ReplayAttackPolicy::default() {
Expand Down
7 changes: 6 additions & 1 deletion crates/shadowsocks-service/src/local/http/utils.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading