allow setting mode independently for every locals and servers

ref #452

- adding `mode` in `locals` and `servers` extended format`
redir and tunnel supports customizing UDP binding address by `udp_addr`

BREAKING CHANGES:

- `sslocal` and `ssserver` command line option `-u` and `-U` can only
  control mode of command line specified local or server instance`
This commit is contained in:
zonyitoo
2021-03-13 16:02:49 +08:00
committed by ty
parent 6bebb6c6c0
commit 0ac0f15459
21 changed files with 230 additions and 242 deletions

View File

@@ -17,10 +17,10 @@ use shadowsocks_service::config::RedirType;
use shadowsocks_service::shadowsocks::relay::socks5::Address;
use shadowsocks_service::{
acl::AccessControl,
config::{Config, ConfigType, LocalConfig, Mode, ProtocolType},
config::{Config, ConfigType, LocalConfig, ProtocolType},
run_local,
shadowsocks::{
config::{ServerAddr, ServerConfig},
config::{Mode, ServerAddr, ServerConfig},
crypto::v1::{available_ciphers, CipherKind},
plugin::PluginConfig,
},
@@ -40,12 +40,11 @@ fn main() {
(version: VERSION)
(about: "A fast tunnel proxy that helps you bypass firewalls.")
(@arg UDP_ONLY: -u conflicts_with[TCP_AND_UDP] "Server mode UDP_ONLY")
(@arg TCP_AND_UDP: -U "Server mode TCP_AND_UDP")
(@arg CONFIG: -c --config +takes_value required_unless_all(&["LOCAL_ADDR", "SERVER_CONFIG"]) "Shadowsocks configuration file (https://shadowsocks.org/en/config/quick-guide.html)")
(@arg LOCAL_ADDR: -b --("local-addr") +takes_value {validator::validate_server_addr} "Local address, listen only to this address if specified")
(@arg UDP_ONLY: -u conflicts_with[TCP_AND_UDP] requires[LOCAL_ADDR] "Server mode UDP_ONLY")
(@arg TCP_AND_UDP: -U requires[LOCAL_ADDR] "Server mode TCP_AND_UDP")
(@arg SERVER_ADDR: -s --("server-addr") +takes_value {validator::validate_server_addr} requires[PASSWORD ENCRYPT_METHOD] "Server address")
(@arg PASSWORD: -k --password +takes_value requires[SERVER_ADDR] "Server's password")
@@ -324,18 +323,17 @@ fn main() {
}
}
if matches.is_present("UDP_ONLY") {
local_config.mode = Mode::UdpOnly;
}
if matches.is_present("TCP_AND_UDP") {
local_config.mode = Mode::TcpAndUdp;
}
config.local.push(local_config);
}
// override the config's mode if UDP_ONLY is set
if matches.is_present("UDP_ONLY") {
config.mode = Mode::UdpOnly;
}
if matches.is_present("TCP_AND_UDP") {
config.mode = Mode::TcpAndUdp;
}
if matches.is_present("NO_DELAY") {
config.no_delay = true;
}

View File

@@ -16,10 +16,10 @@ use tokio::{self, runtime::Builder};
use shadowsocks_service::{
acl::AccessControl,
config::{Config, ConfigType, ManagerConfig, ManagerServerHost, Mode},
config::{Config, ConfigType, ManagerConfig, ManagerServerHost},
run_manager,
shadowsocks::{
config::ManagerAddr,
config::{ManagerAddr, Mode},
crypto::v1::{available_ciphers, CipherKind},
},
};
@@ -138,16 +138,17 @@ fn main() {
config.local_addr = Some(bind_addr);
}
// Overrides
if matches.is_present("UDP_ONLY") {
if config.mode.enable_tcp() {
config.mode = Mode::TcpAndUdp;
} else {
config.mode = Mode::UdpOnly;
if let Some(ref mut m) = config.manager {
m.mode = m.mode.merge(Mode::UdpOnly);
}
}
if matches.is_present("TCP_AND_UDP") {
config.mode = Mode::TcpAndUdp;
if let Some(ref mut m) = config.manager {
m.mode = Mode::TcpAndUdp;
}
}
if matches.is_present("NO_DELAY") {

View File

@@ -16,10 +16,10 @@ use tokio::{self, runtime::Builder};
use shadowsocks_service::{
acl::AccessControl,
config::{Config, ConfigType, ManagerConfig, Mode},
config::{Config, ConfigType, ManagerConfig},
run_server,
shadowsocks::{
config::{ManagerAddr, ServerAddr, ServerConfig},
config::{ManagerAddr, Mode, ServerAddr, ServerConfig},
crypto::v1::{available_ciphers, CipherKind},
plugin::PluginConfig,
},
@@ -40,9 +40,6 @@ fn main() {
(version: VERSION)
(about: "A fast tunnel proxy that helps you bypass firewalls.")
(@arg UDP_ONLY: -u conflicts_with[TCP_AND_UDP] "Server mode UDP_ONLY")
(@arg TCP_AND_UDP: -U "Server mode TCP_AND_UDP")
(@arg CONFIG: -c --config +takes_value required_unless("SERVER_ADDR") "Shadowsocks configuration file (https://shadowsocks.org/en/config/quick-guide.html)")
(@arg BIND_ADDR: -b --("bind-addr") +takes_value {validator::validate_ip_addr} "Bind address, outbound socket will bind this address")
@@ -51,6 +48,8 @@ fn main() {
(@arg PASSWORD: -k --password +takes_value requires[SERVER_ADDR] "Server's password")
(@arg ENCRYPT_METHOD: -m --("encrypt-method") +takes_value requires[SERVER_ADDR] possible_values(available_ciphers()) +next_line_help "Server's encryption method")
(@arg TIMEOUT: --timeout +takes_value {validator::validate_u64} requires[SERVER_ADDR] "Server's timeout seconds for TCP relay")
(@arg UDP_ONLY: -u conflicts_with[TCP_AND_UDP] requires[SERVER_ADDR] "Server mode UDP_ONLY")
(@arg TCP_AND_UDP: -U requires[SERVER_ADDR] "Server mode TCP_AND_UDP")
(@arg PLUGIN: --plugin +takes_value requires[SERVER_ADDR] "SIP003 (https://shadowsocks.org/en/spec/Plugin.html) plugin")
(@arg PLUGIN_OPT: --("plugin-opts") +takes_value requires[PLUGIN] "Set SIP003 plugin options")
@@ -168,6 +167,14 @@ fn main() {
sc.set_plugin(plugin);
}
if matches.is_present("UDP_ONLY") {
sc.set_mode(sc.mode().merge(Mode::UdpOnly));
}
if matches.is_present("TCP_AND_UDP") {
sc.set_mode(Mode::TcpAndUdp);
}
config.server.push(sc);
}
@@ -176,18 +183,6 @@ fn main() {
config.local_addr = Some(bind_addr);
}
if matches.is_present("UDP_ONLY") {
if config.mode.enable_tcp() {
config.mode = Mode::TcpAndUdp;
} else {
config.mode = Mode::UdpOnly;
}
}
if matches.is_present("TCP_AND_UDP") {
config.mode = Mode::TcpAndUdp;
}
if matches.is_present("NO_DELAY") {
config.no_delay = true;
}

View File

@@ -62,7 +62,7 @@ use serde::{Deserialize, Serialize};
#[cfg(any(feature = "local-tunnel", feature = "local-dns"))]
use shadowsocks::relay::socks5::Address;
use shadowsocks::{
config::{ManagerAddr, ServerAddr, ServerConfig},
config::{ManagerAddr, Mode, ServerAddr, ServerConfig},
crypto::v1::CipherKind,
plugin::PluginConfig,
};
@@ -132,6 +132,9 @@ struct SSLocalExtConfig {
local_address: Option<String>,
local_port: u16,
#[serde(skip_serializing_if = "Option::is_none")]
mode: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
local_udp_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
@@ -202,6 +205,8 @@ struct SSServerExtConfig {
remarks: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
mode: Option<String>,
}
/// Server config type
@@ -234,47 +239,6 @@ impl ConfigType {
}
}
/// Server mode
#[derive(Clone, Copy, Debug)]
pub enum Mode {
TcpOnly,
TcpAndUdp,
UdpOnly,
}
impl Mode {
pub fn enable_udp(self) -> bool {
matches!(self, Mode::UdpOnly | Mode::TcpAndUdp)
}
pub fn enable_tcp(self) -> bool {
matches!(self, Mode::TcpOnly | Mode::TcpAndUdp)
}
}
impl fmt::Display for Mode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Mode::TcpOnly => f.write_str("tcp_only"),
Mode::TcpAndUdp => f.write_str("tcp_and_udp"),
Mode::UdpOnly => f.write_str("udp_only"),
}
}
}
impl FromStr for Mode {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"tcp_only" => Ok(Mode::TcpOnly),
"tcp_and_udp" => Ok(Mode::TcpAndUdp),
"udp_only" => Ok(Mode::UdpOnly),
_ => Err(()),
}
}
}
cfg_if! {
if #[cfg(feature = "local-redir")] {
use strum::IntoEnumIterator;
@@ -502,6 +466,8 @@ pub struct ManagerConfig {
///
/// Note: Outbound address is defined in Config.local_addr
pub server_host: ManagerServerHost,
/// Server's mode
pub mode: Mode,
}
impl ManagerConfig {
@@ -512,6 +478,7 @@ impl ManagerConfig {
method: None,
timeout: None,
server_host: ManagerServerHost::default(),
mode: Mode::TcpOnly,
}
}
}
@@ -597,6 +564,10 @@ pub struct LocalConfig {
pub addr: ServerAddr,
pub protocol: ProtocolType,
/// Mode
/// Uses global `mode` if not specified
pub mode: Mode,
/// UDP server bind address. Uses `addr` if not specified
///
/// Resolving Android's issue: [shadowsocks/shadowsocks-android#2571](https://github.com/shadowsocks/shadowsocks-android/issues/2571)
@@ -631,6 +602,8 @@ impl LocalConfig {
LocalConfig {
addr,
protocol,
mode: Mode::TcpOnly,
udp_addr: None,
#[cfg(feature = "local-tunnel")]
@@ -767,8 +740,6 @@ pub struct Config {
/// Manager's configuration
pub manager: Option<ManagerConfig>,
/// Server mode, `tcp_only`, `tcp_and_udp`, and `udp_only`
pub mode: Mode,
/// Config is for Client or Server
pub config_type: ConfigType,
@@ -872,7 +843,6 @@ impl Config {
manager: None,
mode: Mode::TcpOnly,
config_type,
udp_timeout: None,
@@ -919,6 +889,22 @@ impl Config {
}
}
// Mode
let mut global_mode = Mode::TcpOnly;
if let Some(m) = config.mode {
match m.parse::<Mode>() {
Ok(xm) => global_mode = xm,
Err(..) => {
let e = Error::new(
ErrorKind::Malformed,
"malformed `mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`",
None,
);
return Err(e);
}
}
}
match config_type {
ConfigType::Local => {
// Standard config
@@ -985,6 +971,19 @@ impl Config {
local_config.udp_addr = Some(local_udp_addr);
}
match local.mode {
Some(mode) => match mode.parse::<Mode>() {
Ok(mode) => local_config.mode = mode,
Err(..) => {
let err = Error::new(ErrorKind::Malformed, "invalid `mode`", None);
return Err(err);
}
},
None => {
local_config.mode = global_mode;
}
}
#[cfg(feature = "local-tunnel")]
if let Some(forward_address) = local.forward_address {
let forward_port = match local.forward_port {
@@ -1076,53 +1075,6 @@ impl Config {
}
}
// match config.local_address {
// Some(la) => {
// let local_port = if config_type.is_local() {
// let local_port = config.local_port.unwrap_or(0);
// if local_port == 0 {
// let err = Error::new(ErrorKind::MissingField, "missing `local_port`", None);
// return Err(err);
// }
// local_port
// } else if config_type.is_server() || config_type.is_manager() {
// // server's local_port is ignored
// 0
// } else {
// config.local_port.unwrap_or(0)
// };
// let local_addr = match la.parse::<IpAddr>() {
// Ok(ip) => ServerAddr::from(SocketAddr::new(ip, local_port)),
// Err(..) => {
// // treated as domain
// ServerAddr::from((la, local_port))
// }
// };
// nconfig.local_addr = Some(local_addr);
// }
// None => {
// if config_type.is_local() && config.local_port.is_some() {
// // Implementation note: This is not implemented like libev which will choose IPv6 or IPv6 LoopBack address
// // by checking all its remote servers if all of them supports IPv6.
// let ip = if config.ipv6_first.unwrap_or(false) {
// Ipv6Addr::LOCALHOST.into()
// } else {
// Ipv4Addr::LOCALHOST.into()
// };
// let local_port = config.local_port.unwrap_or(0);
// if local_port == 0 {
// let err = Error::new(ErrorKind::MissingField, "`local_port` shouldn't be 0", None);
// return Err(err);
// }
// let local_addr = ServerAddr::from(SocketAddr::new(ip, local_port));
// nconfig.local_addr = Some(local_addr);
// }
// }
// };
// Standard config
// Server
match (config.server, config.server_port, config.password, config.method) {
@@ -1148,6 +1100,7 @@ impl Config {
};
let mut nsvr = ServerConfig::new(addr, pwd, method);
nsvr.set_mode(global_mode);
if let Some(p) = config.plugin {
// SIP008 allows "plugin" to be an empty string
@@ -1212,6 +1165,17 @@ impl Config {
let mut nsvr = ServerConfig::new(addr, svr.password, method);
match svr.mode {
Some(mode) => match mode.parse::<Mode>() {
Ok(mode) => nsvr.set_mode(mode),
Err(..) => {
let err = Error::new(ErrorKind::Malformed, "invalid `mode`", None);
return Err(err);
}
},
None => nsvr.set_mode(global_mode),
}
if let Some(p) = svr.plugin {
// SIP008 allows "plugin" to be an empty string
// Empty string implies "no plugin"
@@ -1273,7 +1237,8 @@ impl Config {
}
};
let manager_config = ManagerConfig::new(manager);
let mut manager_config = ManagerConfig::new(manager);
manager_config.mode = global_mode;
nconfig.manager = Some(manager_config);
}
@@ -1304,21 +1269,6 @@ impl Config {
};
}
// Mode
if let Some(m) = config.mode {
match m.parse::<Mode>() {
Ok(xm) => nconfig.mode = xm,
Err(..) => {
let e = Error::new(
ErrorKind::Malformed,
"malformed `mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`",
None,
);
return Err(e);
}
}
}
// TCP nodelay
if let Some(b) = config.no_delay {
nconfig.no_delay = b;
@@ -1608,6 +1558,7 @@ impl fmt::Display for Config {
ServerAddr::DomainName(.., port) => *port,
}),
},
mode: Some(local.mode.to_string()),
protocol: match local.protocol {
ProtocolType::Socks => None,
p => Some(p.as_str().to_owned()),
@@ -1710,6 +1661,7 @@ impl fmt::Display for Config {
}
});
jconf.timeout = svr.timeout().map(|t| t.as_secs());
jconf.mode = Some(svr.mode().to_string());
}
// For >1 servers, uses extended multiple server format
_ => {
@@ -1740,6 +1692,7 @@ impl fmt::Display for Config {
timeout: svr.timeout().map(|t| t.as_secs()),
remarks: svr.remarks().map(ToOwned::to_owned),
id: svr.id().map(ToOwned::to_owned),
mode: Some(svr.mode().to_string()),
});
}
@@ -1761,9 +1714,11 @@ impl fmt::Display for Config {
#[cfg(unix)]
ManagerAddr::UnixSocketAddr(..) => None,
};
}
jconf.mode = Some(self.mode.to_string());
if jconf.mode.is_none() {
jconf.mode = Some(m.mode.to_string());
}
}
if self.no_delay {
jconf.no_delay = Some(self.no_delay);

View File

@@ -41,8 +41,9 @@ pub async fn build_dns_resolver(dns: DnsConfig, ipv6_first: bool, connect_opts:
},
#[cfg(feature = "local-dns")]
DnsConfig::LocalDns(ns) => {
use crate::{config::Mode, local::dns::dns_resolver::DnsResolver as LocalDnsResolver};
use crate::local::dns::dns_resolver::DnsResolver as LocalDnsResolver;
use log::trace;
use shadowsocks::config::Mode;
trace!("initializing direct DNS resolver for {}", ns);

View File

@@ -8,14 +8,12 @@ use std::{
use async_trait::async_trait;
use futures::future;
use log::{debug, trace};
use shadowsocks::{dns_resolver::DnsResolve, net::ConnectOpts};
use shadowsocks::{config::Mode, dns_resolver::DnsResolve, net::ConnectOpts};
use trust_dns_resolver::proto::{
op::{Message, Query},
rr::{DNSClass, Name, RData, RecordType},
};
use crate::config::Mode;
use super::{client_cache::DnsClientCache, config::NameServerAddr};
pub struct DnsResolver {

View File

@@ -16,6 +16,7 @@ use futures::future::{self, Either};
use log::{debug, error, info, trace, warn};
use rand::{thread_rng, Rng};
use shadowsocks::{
config::Mode,
lookup_then,
net::{TcpListener, UdpSocket as ShadowUdpSocket},
relay::{udprelay::MAXIMUM_UDP_PAYLOAD_SIZE, Address},
@@ -33,7 +34,6 @@ use trust_dns_resolver::proto::{
use crate::{
acl::AccessControl,
config::Mode,
local::{context::ServiceContext, loadbalancing::PingBalancer},
};

View File

@@ -16,6 +16,7 @@ use byte_string::ByteStr;
use futures::future::{self, AbortHandle};
use log::{debug, info, trace};
use shadowsocks::{
config::Mode,
relay::{
socks5::Address,
tcprelay::proxy_stream::ProxyClientStream,
@@ -28,7 +29,7 @@ use tokio::{
time,
};
use crate::{config::Mode, local::context::ServiceContext};
use crate::local::context::ServiceContext;
use super::{
server_data::ServerIdent,

View File

@@ -11,6 +11,7 @@ use futures::{
};
use log::{error, trace, warn};
use shadowsocks::{
config::Mode,
net::{AcceptOpts, ConnectOpts},
plugin::{Plugin, PluginMode},
};
@@ -104,17 +105,16 @@ pub async fn run(mut config: Config) -> io::Result<()> {
// Check if any of the local servers enable TCP connections
let mode = config.mode;
let enable_tcp = config.local.iter().any(|local_config| match local_config.protocol {
ProtocolType::Socks => mode.enable_tcp(),
ProtocolType::Socks => local_config.mode.enable_tcp(),
#[cfg(feature = "local-tunnel")]
ProtocolType::Tunnel => mode.enable_tcp(),
ProtocolType::Tunnel => local_config.mode.enable_tcp(),
#[cfg(feature = "local-http")]
ProtocolType::Http => true,
#[cfg(feature = "local-redir")]
ProtocolType::Redir => mode.enable_tcp(),
ProtocolType::Redir => local_config.mode.enable_tcp(),
#[cfg(feature = "local-dns")]
ProtocolType::Dns => mode.enable_tcp(),
ProtocolType::Dns => local_config.mode.enable_tcp(),
});
if enable_tcp {
@@ -169,7 +169,13 @@ pub async fn run(mut config: Config) -> io::Result<()> {
//
// XXX: This have to be called after allocating plugins' addresses
let balancer = {
let mut balancer_builder = PingBalancerBuilder::new(context.clone(), config.mode);
let mut mode = Mode::TcpOnly;
for local in &config.local {
mode = mode.merge(local.mode);
}
let mut balancer_builder = PingBalancerBuilder::new(context.clone(), mode);
for server in config.server {
balancer_builder.add_server(ServerIdent::new(server));
}
@@ -179,21 +185,6 @@ pub async fn run(mut config: Config) -> io::Result<()> {
balancer
};
// #[cfg(feature = "local-dns")]
// if matches!(config.local_protocol, ProtocolType::Dns) || config.dns_bind_addr.is_some() {
// use self::dns::Dns;
// let local_addr = config.local_dns_addr.expect("missing local_dns_addr");
// let remote_addr = config.remote_dns_addr.expect("missing remote_dns_addr");
// let bind_addr = config.dns_bind_addr.as_ref().unwrap_or_else(|| &client_config);
// let mut server = Dns::with_context(context.clone(), local_addr, remote_addr);
// server.set_mode(config.mode);
// vfut.push(server.run(bind_addr, balancer.clone()).boxed());
// }
#[cfg(feature = "local-flow-stat")]
if let Some(stat_path) = config.stat_path {
// For Android's flow statistic
@@ -211,7 +202,7 @@ pub async fn run(mut config: Config) -> io::Result<()> {
use self::socks::Socks;
let mut server = Socks::with_context(context.clone());
server.set_mode(config.mode);
server.set_mode(local_config.mode);
if let Some(c) = config.udp_max_associations {
server.set_udp_capacity(c);
@@ -242,12 +233,13 @@ pub async fn run(mut config: Config) -> io::Result<()> {
if let Some(d) = config.udp_timeout {
server.set_udp_expiry_duration(d);
}
server.set_mode(config.mode);
server.set_mode(local_config.mode);
if config.no_delay {
server.set_nodelay(true);
}
vfut.push(async move { server.run(&client_addr, balancer).await }.boxed());
let udp_addr = local_config.udp_addr.unwrap_or_else(|| client_addr.clone());
vfut.push(async move { server.run(&client_addr, &udp_addr, balancer).await }.boxed());
}
#[cfg(feature = "local-http")]
ProtocolType::Http => {
@@ -267,14 +259,15 @@ pub async fn run(mut config: Config) -> io::Result<()> {
if let Some(d) = config.udp_timeout {
server.set_udp_expiry_duration(d);
}
server.set_mode(config.mode);
server.set_mode(local_config.mode);
if config.no_delay {
server.set_nodelay(true);
}
server.set_tcp_redir(local_config.tcp_redir);
server.set_udp_redir(local_config.udp_redir);
vfut.push(async move { server.run(&client_addr, balancer).await }.boxed());
let udp_addr = local_config.udp_addr.unwrap_or_else(|| client_addr.clone());
vfut.push(async move { server.run(&client_addr, &udp_addr, balancer).await }.boxed());
}
#[cfg(feature = "local-dns")]
ProtocolType::Dns => {
@@ -286,7 +279,7 @@ pub async fn run(mut config: Config) -> io::Result<()> {
Dns::with_context(context.clone(), local_addr.clone(), remote_addr.clone())
};
server.set_mode(config.mode);
server.set_mode(local_config.mode);
vfut.push(async move { server.run(&client_addr, balancer).await }.boxed());
}

View File

@@ -3,10 +3,10 @@
use std::{io, sync::Arc, time::Duration};
use futures::{future, FutureExt};
use shadowsocks::ServerAddr;
use shadowsocks::{config::Mode, ServerAddr};
use crate::{
config::{Mode, RedirType},
config::RedirType,
local::{context::ServiceContext, loadbalancing::PingBalancer},
};
@@ -74,15 +74,15 @@ impl Redir {
}
/// Start serving
pub async fn run(self, client_config: &ServerAddr, balancer: PingBalancer) -> io::Result<()> {
pub async fn run(self, tcp_addr: &ServerAddr, udp_addr: &ServerAddr, balancer: PingBalancer) -> io::Result<()> {
let mut vfut = Vec::new();
if self.mode.enable_tcp() {
vfut.push(self.run_tcp_tunnel(client_config, balancer.clone()).boxed());
vfut.push(self.run_tcp_tunnel(tcp_addr, balancer.clone()).boxed());
}
if self.mode.enable_udp() {
vfut.push(self.run_udp_tunnel(client_config, balancer).boxed());
vfut.push(self.run_udp_tunnel(udp_addr, balancer).boxed());
}
let (res, ..) = future::select_all(vfut).await;

View File

@@ -4,13 +4,10 @@ use std::{io, net::SocketAddr, sync::Arc, time::Duration};
use futures::{future, FutureExt};
use log::{error, info};
use shadowsocks::{lookup_then, net::TcpListener as ShadowTcpListener, ServerAddr};
use shadowsocks::{config::Mode, lookup_then, net::TcpListener as ShadowTcpListener, ServerAddr};
use tokio::{net::TcpStream, time};
use crate::{
config::Mode,
local::{context::ServiceContext, loadbalancing::PingBalancer},
};
use crate::local::{context::ServiceContext, loadbalancing::PingBalancer};
#[cfg(feature = "local-socks4")]
use self::socks4::Socks4TcpHandler;

View File

@@ -7,19 +7,17 @@ use std::{
};
use log::{debug, trace, warn};
use shadowsocks::config::Mode;
use tokio::{
io::{AsyncWriteExt, BufReader},
net::TcpStream,
};
use crate::{
config::Mode,
local::{
context::ServiceContext,
loadbalancing::PingBalancer,
net::AutoProxyClientStream,
utils::establish_tcp_tunnel,
},
use crate::local::{
context::ServiceContext,
loadbalancing::PingBalancer,
net::AutoProxyClientStream,
utils::establish_tcp_tunnel,
};
use crate::local::socks::socks4::{Address, Command, HandshakeRequest, HandshakeResponse, ResultCode};

View File

@@ -8,6 +8,7 @@ use std::{
use log::{debug, error, trace, warn};
use shadowsocks::{
config::Mode,
relay::socks5::{
self,
Address,
@@ -23,7 +24,6 @@ use shadowsocks::{
use tokio::net::TcpStream;
use crate::{
config::Mode,
local::{
context::ServiceContext,
loadbalancing::PingBalancer,

View File

@@ -3,12 +3,9 @@
use std::{io, sync::Arc, time::Duration};
use futures::{future, FutureExt};
use shadowsocks::{relay::socks5::Address, ServerAddr};
use shadowsocks::{config::Mode, relay::socks5::Address, ServerAddr};
use crate::{
config::Mode,
local::{context::ServiceContext, loadbalancing::PingBalancer},
};
use crate::local::{context::ServiceContext, loadbalancing::PingBalancer};
use super::{tcprelay::run_tcp_tunnel, udprelay::UdpTunnel};
@@ -62,15 +59,15 @@ impl Tunnel {
}
/// Start serving
pub async fn run(self, client_config: &ServerAddr, balancer: PingBalancer) -> io::Result<()> {
pub async fn run(self, tcp_addr: &ServerAddr, udp_addr: &ServerAddr, balancer: PingBalancer) -> io::Result<()> {
let mut vfut = Vec::new();
if self.mode.enable_tcp() {
vfut.push(self.run_tcp_tunnel(client_config, balancer.clone()).boxed());
vfut.push(self.run_tcp_tunnel(tcp_addr, balancer.clone()).boxed());
}
if self.mode.enable_udp() {
vfut.push(self.run_udp_tunnel(client_config, balancer).boxed());
vfut.push(self.run_udp_tunnel(udp_addr, balancer).boxed());
}
let (res, ..) = future::select_all(vfut).await;

View File

@@ -31,7 +31,6 @@ pub async fn run(config: Config) -> io::Result<()> {
}
let mut manager = Manager::new(config.manager.expect("missing manager config"));
manager.set_mode(config.mode);
let mut connect_opts = ConnectOpts {
#[cfg(any(target_os = "linux", target_os = "android"))]
@@ -73,7 +72,7 @@ pub async fn run(config: Config) -> io::Result<()> {
}
for svr_cfg in config.server {
manager.add_server(svr_cfg, None).await;
manager.add_server(svr_cfg).await;
}
manager.run().await

View File

@@ -5,7 +5,7 @@ use std::{collections::HashMap, io, net::SocketAddr, sync::Arc, time::Duration};
use futures::future::{self, AbortHandle};
use log::{error, info};
use shadowsocks::{
config::{ServerConfig, ServerType},
config::{Mode, ServerConfig, ServerType},
context::{Context, SharedContext},
crypto::v1::CipherKind,
dns_resolver::DnsResolver,
@@ -30,7 +30,7 @@ use tokio::sync::Mutex;
use crate::{
acl::AccessControl,
config::{ManagerConfig, ManagerServerHost, Mode},
config::{ManagerConfig, ManagerServerHost},
net::FlowStat,
server::Server,
};
@@ -52,7 +52,6 @@ pub struct Manager {
context: SharedContext,
servers: Mutex<HashMap<u16, ServerInstance>>,
svr_cfg: ManagerConfig,
mode: Mode,
connect_opts: ConnectOpts,
accept_opts: AcceptOpts,
udp_expiry_duration: Option<Duration>,
@@ -72,7 +71,6 @@ impl Manager {
context,
servers: Mutex::new(HashMap::new()),
svr_cfg,
mode: Mode::TcpOnly,
connect_opts: ConnectOpts::default(),
accept_opts: AcceptOpts::default(),
udp_expiry_duration: None,
@@ -101,11 +99,6 @@ impl Manager {
self.udp_capacity = Some(c);
}
/// Set server's default mode
pub fn set_mode(&mut self, mode: Mode) {
self.mode = mode;
}
/// Get the manager's configuration
pub fn config(&self) -> &ManagerConfig {
&self.svr_cfg
@@ -166,7 +159,7 @@ impl Manager {
}
}
pub async fn add_server(&self, svr_cfg: ServerConfig, mode: Option<Mode>) {
pub async fn add_server(&self, svr_cfg: ServerConfig) {
// Each server should use a separate Context, but shares
//
// * AccessControlList
@@ -185,8 +178,6 @@ impl Manager {
server.set_udp_capacity(c);
}
server.set_mode(mode.unwrap_or(self.mode));
if let Some(ref acl) = self.acl {
server.set_acl(acl.clone());
}
@@ -261,7 +252,9 @@ impl Manager {
},
};
self.add_server(svr_cfg, mode).await;
svr_cfg.set_mode(mode.unwrap_or(self.svr_cfg.mode));
self.add_server(svr_cfg).await;
Ok(AddResponse("ok".to_owned()))
}

View File

@@ -91,7 +91,6 @@ pub async fn run(config: Config) -> io::Result<()> {
if let Some(d) = config.udp_timeout {
server.set_udp_expiry_duration(d);
}
server.set_mode(config.mode);
if let Some(ref m) = config.manager {
server.set_manager_addr(m.addr.clone());
}

View File

@@ -18,7 +18,7 @@ use shadowsocks::{
};
use tokio::time;
use crate::{acl::AccessControl, config::Mode, net::FlowStat};
use crate::{acl::AccessControl, net::FlowStat};
use super::{context::ServiceContext, tcprelay::TcpServer, udprelay::UdpServer};
@@ -26,7 +26,6 @@ use super::{context::ServiceContext, tcprelay::TcpServer, udprelay::UdpServer};
pub struct Server {
context: Arc<ServiceContext>,
svr_cfg: ServerConfig,
mode: Mode,
udp_expiry_duration: Option<Duration>,
udp_capacity: Option<usize>,
manager_addr: Option<ManagerAddr>,
@@ -44,7 +43,6 @@ impl Server {
Server {
context,
svr_cfg,
mode: Mode::TcpOnly,
udp_expiry_duration: None,
udp_capacity: None,
manager_addr: None,
@@ -78,11 +76,6 @@ impl Server {
self.udp_capacity = Some(c);
}
/// Set server's mode
pub fn set_mode(&mut self, mode: Mode) {
self.mode = mode;
}
/// Set manager's address to report `stat`
pub fn set_manager_addr(&mut self, manager_addr: ManagerAddr) {
self.manager_addr = Some(manager_addr);
@@ -114,7 +107,7 @@ impl Server {
pub async fn run(mut self) -> io::Result<()> {
let vfut = FuturesUnordered::new();
if self.mode.enable_tcp() {
if self.svr_cfg.mode().enable_tcp() {
if let Some(plugin_cfg) = self.svr_cfg.plugin() {
let plugin = Plugin::start(plugin_cfg, self.svr_cfg.addr(), PluginMode::Server)?;
self.svr_cfg.set_plugin_addr(plugin.local_addr().into());
@@ -139,7 +132,7 @@ impl Server {
vfut.push(tcp_fut);
}
if self.mode.enable_udp() {
if self.svr_cfg.mode().enable_udp() {
let udp_fut = self.run_udp_server().boxed();
vfut.push(udp_fut);
}

View File

@@ -42,6 +42,61 @@ impl ServerType {
}
}
/// Server mode
#[derive(Clone, Copy, Debug)]
pub enum Mode {
TcpOnly = 0x01,
TcpAndUdp = 0x03,
UdpOnly = 0x02,
}
impl Mode {
/// Check if UDP is enabled
pub fn enable_udp(self) -> bool {
matches!(self, Mode::UdpOnly | Mode::TcpAndUdp)
}
/// Check if TCP is enabled
pub fn enable_tcp(self) -> bool {
matches!(self, Mode::TcpOnly | Mode::TcpAndUdp)
}
/// Merge with another Mode
pub fn merge(&self, mode: Mode) -> Mode {
let me = *self as u8;
let fm = mode as u8;
match me | fm {
0x01 => Mode::TcpOnly,
0x02 => Mode::UdpOnly,
0x03 => Mode::TcpAndUdp,
_ => unreachable!(),
}
}
}
impl fmt::Display for Mode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Mode::TcpOnly => f.write_str("tcp_only"),
Mode::TcpAndUdp => f.write_str("tcp_and_udp"),
Mode::UdpOnly => f.write_str("udp_only"),
}
}
}
impl FromStr for Mode {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"tcp_only" => Ok(Mode::TcpOnly),
"tcp_and_udp" => Ok(Mode::TcpAndUdp),
"udp_only" => Ok(Mode::UdpOnly),
_ => Err(()),
}
}
}
/// Configuration for a server
#[derive(Clone, Debug)]
pub struct ServerConfig {
@@ -60,10 +115,14 @@ pub struct ServerConfig {
plugin: Option<PluginConfig>,
/// Plugin address
plugin_addr: Option<ServerAddr>,
/// Remark (Profile Name), normally used as an identifier of this erver
remarks: Option<String>,
/// ID (SIP008) is a random generated UUID
id: Option<String>,
/// Mode
mode: Mode,
}
impl ServerConfig {
@@ -88,6 +147,7 @@ impl ServerConfig {
plugin_addr: None,
remarks: None,
id: None,
mode: Mode::TcpOnly,
}
}
@@ -194,6 +254,16 @@ impl ServerConfig {
self.id = Some(id.into())
}
/// Get server's `Mode`
pub fn mode(&self) -> Mode {
self.mode
}
/// Set server's `Mode`
pub fn set_mode(&mut self, mode: Mode) {
self.mode = mode;
}
/// Get URL for QRCode
/// ```plain
/// ss:// + base64(method:password@host:port)

View File

@@ -11,12 +11,12 @@ use tokio::{
};
use shadowsocks_service::{
config::{Config, ConfigType, LocalConfig, Mode, ProtocolType},
config::{Config, ConfigType, LocalConfig, ProtocolType},
local::socks::client::socks5::Socks5TcpClient,
run_local,
run_server,
shadowsocks::{
config::{ServerAddr, ServerConfig},
config::{Mode, ServerAddr, ServerConfig},
crypto::v1::CipherKind,
relay::socks5::Address,
},
@@ -42,14 +42,14 @@ impl Socks5TestServer {
svr_config: {
let mut cfg = Config::new(ConfigType::Server);
cfg.server = vec![ServerConfig::new(svr_addr, pwd.to_owned(), method)];
cfg.mode = if enable_udp { Mode::TcpAndUdp } else { Mode::TcpOnly };
cfg.server[0].set_mode(if enable_udp { Mode::TcpAndUdp } else { Mode::TcpOnly });
cfg
},
cli_config: {
let mut cfg = Config::new(ConfigType::Local);
cfg.local = vec![LocalConfig::new(ServerAddr::from(local_addr), ProtocolType::Socks)];
cfg.local[0].mode = if enable_udp { Mode::TcpAndUdp } else { Mode::TcpOnly };
cfg.server = vec![ServerConfig::new(svr_addr, pwd.to_owned(), method)];
cfg.mode = if enable_udp { Mode::TcpAndUdp } else { Mode::TcpOnly };
cfg
},
}

View File

@@ -7,11 +7,11 @@ use log::debug;
use tokio::time::{self, Duration};
use shadowsocks_service::{
config::{Config, ConfigType, LocalConfig, Mode, ProtocolType},
config::{Config, ConfigType, LocalConfig, ProtocolType},
local::socks::client::socks5::Socks5UdpClient,
run_local,
run_server,
shadowsocks::{crypto::v1::CipherKind, relay::socks5::Address, ServerConfig},
shadowsocks::{config::Mode, crypto::v1::CipherKind, relay::socks5::Address, ServerConfig},
};
const SERVER_ADDR: &str = "127.0.0.1:8093";
@@ -29,19 +29,19 @@ fn get_svr_config() -> Config {
PASSWORD.to_owned(),
METHOD,
)];
cfg.mode = Mode::TcpAndUdp;
cfg.server[0].set_mode(Mode::TcpAndUdp);
cfg
}
fn get_cli_config() -> Config {
let mut cfg = Config::new(ConfigType::Local);
cfg.local = vec![LocalConfig::new(LOCAL_ADDR.parse().unwrap(), ProtocolType::Socks)];
cfg.local[0].mode = Mode::TcpAndUdp;
cfg.server = vec![ServerConfig::new(
SERVER_ADDR.parse::<SocketAddr>().unwrap(),
PASSWORD.to_owned(),
METHOD,
)];
cfg.mode = Mode::TcpAndUdp;
cfg
}