Skip to content

Commit c9c59f9

Browse files
committed
feat(plugin): Support SIP003u, Plugin UDP mode
- ref shadowsocks/shadowsocks-org#180 - "plugin_mode" option in configuration file, and ssmanager API - "plugin_mode" is "tcp_only" by default - ref #1127
1 parent 2dff4ec commit c9c59f9

File tree

13 files changed

+122
-15
lines changed

13 files changed

+122
-15
lines changed

crates/shadowsocks-service/src/config.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ struct SSConfig {
148148
plugin_opts: Option<String>,
149149
#[serde(skip_serializing_if = "Option::is_none")]
150150
plugin_args: Option<Vec<String>>,
151+
#[serde(skip_serializing_if = "Option::is_none")]
152+
plugin_mode: Option<String>,
151153

152154
#[serde(skip_serializing_if = "Option::is_none")]
153155
timeout: Option<u64>,
@@ -326,6 +328,8 @@ struct SSServerExtConfig {
326328
plugin_opts: Option<String>,
327329
#[serde(skip_serializing_if = "Option::is_none")]
328330
plugin_args: Option<Vec<String>>,
331+
#[serde(skip_serializing_if = "Option::is_none")]
332+
plugin_mode: Option<String>,
329333

330334
#[serde(skip_serializing_if = "Option::is_none")]
331335
timeout: Option<u64>,
@@ -1646,6 +1650,20 @@ impl Config {
16461650
plugin: p.clone(),
16471651
plugin_opts: config.plugin_opts.clone(),
16481652
plugin_args: config.plugin_args.clone().unwrap_or_default(),
1653+
plugin_mode: match config.plugin_mode {
1654+
None => Mode::TcpOnly,
1655+
Some(ref mode) => match mode.parse::<Mode>() {
1656+
Ok(m) => m,
1657+
Err(..) => {
1658+
let e = Error::new(
1659+
ErrorKind::Malformed,
1660+
"malformed `plugin_mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`",
1661+
None,
1662+
);
1663+
return Err(e);
1664+
}
1665+
},
1666+
},
16491667
};
16501668
nsvr.set_plugin(plugin);
16511669
}
@@ -1773,6 +1791,20 @@ impl Config {
17731791
plugin: p,
17741792
plugin_opts: svr.plugin_opts,
17751793
plugin_args: svr.plugin_args.unwrap_or_default(),
1794+
plugin_mode: match svr.plugin_mode {
1795+
None => Mode::TcpOnly,
1796+
Some(ref mode) => match mode.parse::<Mode>() {
1797+
Ok(m) => m,
1798+
Err(..) => {
1799+
let e = Error::new(
1800+
ErrorKind::Malformed,
1801+
"malformed `plugin_mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`",
1802+
None,
1803+
);
1804+
return Err(e);
1805+
}
1806+
},
1807+
},
17761808
};
17771809
nsvr.set_plugin(plugin);
17781810
}
@@ -1889,6 +1921,20 @@ impl Config {
18891921
plugin: p,
18901922
plugin_opts: config.plugin_opts,
18911923
plugin_args: config.plugin_args.unwrap_or_default(),
1924+
plugin_mode: match config.plugin_mode {
1925+
None => Mode::TcpOnly,
1926+
Some(ref mode) => match mode.parse::<Mode>() {
1927+
Ok(m) => m,
1928+
Err(..) => {
1929+
let e = Error::new(
1930+
ErrorKind::Malformed,
1931+
"malformed `plugin_mode`, must be one of `tcp_only`, `udp_only` and `tcp_and_udp`",
1932+
None,
1933+
);
1934+
return Err(e);
1935+
}
1936+
},
1937+
},
18921938
});
18931939
}
18941940
}
@@ -2461,6 +2507,13 @@ impl fmt::Display for Config {
24612507
Some(p.plugin_args.clone())
24622508
}
24632509
});
2510+
jconf.plugin_mode = match svr.plugin() {
2511+
None => None,
2512+
Some(p) => match p.plugin_mode {
2513+
Mode::TcpOnly => None,
2514+
_ => Some(p.plugin_mode.to_string()),
2515+
},
2516+
};
24642517
jconf.timeout = svr.timeout().map(|t| t.as_secs());
24652518
jconf.mode = Some(svr.mode().to_string());
24662519

@@ -2510,6 +2563,13 @@ impl fmt::Display for Config {
25102563
Some(p.plugin_args.clone())
25112564
}
25122565
}),
2566+
plugin_mode: match svr.plugin() {
2567+
None => None,
2568+
Some(p) => match p.plugin_mode {
2569+
Mode::TcpOnly => None,
2570+
_ => Some(p.plugin_mode.to_string()),
2571+
},
2572+
},
25132573
timeout: svr.timeout().map(|t| t.as_secs()),
25142574
remarks: svr.remarks().map(ToOwned::to_owned),
25152575
id: svr.id().map(ToOwned::to_owned),

crates/shadowsocks-service/src/local/tunnel/tcprelay.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ async fn handle_tcp_client(
7474
"establishing tcp tunnel {} <-> {} through sever {} (outbound: {})",
7575
peer_addr,
7676
forward_addr,
77-
svr_cfg.external_addr(),
77+
svr_cfg.tcp_external_addr(),
7878
svr_cfg.addr(),
7979
);
8080

crates/shadowsocks-service/src/local/utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ where
3030
"established tcp tunnel {} <-> {} through sever {} (outbound: {})",
3131
peer_addr,
3232
target_addr,
33-
svr_cfg.external_addr(),
33+
svr_cfg.tcp_external_addr(),
3434
svr_cfg.addr(),
3535
);
3636
} else {

crates/shadowsocks-service/src/manager/server.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ impl Manager {
256256
info!(
257257
"closed managed server listening on {}, inbound address {}",
258258
v.svr_cfg.addr(),
259-
v.svr_cfg.external_addr()
259+
v.svr_cfg.tcp_external_addr()
260260
);
261261
}
262262

@@ -444,6 +444,18 @@ impl Manager {
444444
plugin: plugin.clone(),
445445
plugin_opts: req.plugin_opts.clone(),
446446
plugin_args: Vec::new(),
447+
plugin_mode: match req.plugin_mode {
448+
None => Mode::TcpOnly,
449+
Some(ref mode) => match mode.parse::<Mode>() {
450+
Ok(m) => m,
451+
Err(..) => {
452+
error!("unrecognized plugin_mode \"{}\", req: {:?}", mode, req);
453+
454+
let err = format!("unrecognized plugin_mode \"{}\"", mode);
455+
return Ok(AddResponse(err));
456+
}
457+
},
458+
},
447459
};
448460
svr_cfg.set_plugin(p);
449461
} else if let Some(ref plugin) = self.svr_cfg.plugin {
@@ -536,6 +548,7 @@ impl Manager {
536548
no_delay: None,
537549
plugin: None,
538550
plugin_opts: None,
551+
plugin_mode: None,
539552
mode: None,
540553
users,
541554
};

crates/shadowsocks/src/config.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -541,9 +541,24 @@ impl ServerConfig {
541541
self.plugin_addr.as_ref()
542542
}
543543

544-
/// Get server's external address
545-
pub fn external_addr(&self) -> &ServerAddr {
546-
self.plugin_addr.as_ref().unwrap_or(&self.addr)
544+
/// Get server's TCP external address
545+
pub fn tcp_external_addr(&self) -> &ServerAddr {
546+
if let Some(plugin) = self.plugin() {
547+
if plugin.plugin_mode.enable_tcp() {
548+
return self.plugin_addr.as_ref().unwrap_or(&self.addr);
549+
}
550+
}
551+
&self.addr
552+
}
553+
554+
/// Get server's UDP external address
555+
pub fn udp_external_addr(&self) -> &ServerAddr {
556+
if let Some(plugin) = self.plugin() {
557+
if plugin.plugin_mode.enable_udp() {
558+
return self.plugin_addr.as_ref().unwrap_or(&self.addr);
559+
}
560+
}
561+
&self.addr
547562
}
548563

549564
/// Set timeout
@@ -790,6 +805,7 @@ impl ServerConfig {
790805
plugin: p.to_owned(),
791806
plugin_opts: vsp.next().map(ToOwned::to_owned),
792807
plugin_args: Vec::new(), // SIP002 doesn't have arguments for plugins
808+
plugin_mode: Mode::TcpOnly, // SIP002 doesn't support SIP003u
793809
};
794810
svrconfig.set_plugin(plugin);
795811
}

crates/shadowsocks/src/manager/protocol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ pub struct ServerConfig {
3737
#[serde(skip_serializing_if = "Option::is_none")]
3838
pub plugin_opts: Option<String>,
3939
#[serde(skip_serializing_if = "Option::is_none")]
40+
pub plugin_mode: Option<String>,
41+
#[serde(skip_serializing_if = "Option::is_none")]
4042
pub mode: Option<String>,
4143
#[serde(skip_serializing_if = "Option::is_none")]
4244
pub users: Option<Vec<ServerUserConfig>>,

crates/shadowsocks/src/plugin/mod.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use std::{
2222
use log::{debug, error};
2323
use tokio::{net::TcpStream, process::Child, time};
2424

25-
use crate::config::ServerAddr;
25+
use crate::config::{Mode, ServerAddr};
2626

2727
mod obfs_proxy;
2828
mod ss_plugin;
@@ -33,6 +33,7 @@ pub struct PluginConfig {
3333
pub plugin: String,
3434
pub plugin_opts: Option<String>,
3535
pub plugin_args: Vec<String>,
36+
pub plugin_mode: Mode,
3637
}
3738

3839
/// Mode of Plugin
@@ -60,6 +61,7 @@ pub enum PluginMode {
6061
pub struct Plugin {
6162
process: Child,
6263
local_addr: SocketAddr,
64+
mode: Mode,
6365
}
6466

6567
impl Plugin {
@@ -108,7 +110,11 @@ impl Plugin {
108110
}
109111
}
110112

111-
Ok(Plugin { process, local_addr })
113+
Ok(Plugin {
114+
process,
115+
local_addr,
116+
mode: c.plugin_mode,
117+
})
112118
}
113119
}
114120
}
@@ -120,6 +126,12 @@ impl Plugin {
120126

121127
/// Check if plugin have been started
122128
pub async fn wait_started(&self, timeout: Duration) -> bool {
129+
// Only test started with TCP connect()
130+
// XXX: Is there an easy way to test if UDP port was listening? (no ICMP!)
131+
if !self.mode.enable_tcp() {
132+
return true;
133+
}
134+
123135
let start_time = Instant::now();
124136

125137
loop {
@@ -130,6 +142,7 @@ impl Plugin {
130142
}
131143

132144
let remain_time = timeout - elapsed_time;
145+
133146
match time::timeout(remain_time, TcpStream::connect(self.local_addr)).await {
134147
Ok(Ok(..)) => {
135148
return true;

crates/shadowsocks/src/relay/tcprelay/proxy_listener.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ impl ProxyListener {
3939
svr_cfg: &ServerConfig,
4040
accept_opts: AcceptOpts,
4141
) -> io::Result<ProxyListener> {
42-
let listener = match svr_cfg.external_addr() {
42+
let listener = match svr_cfg.tcp_external_addr() {
4343
ServerAddr::SocketAddr(sa) => TcpListener::bind_with_opts(sa, accept_opts).await?,
4444
ServerAddr::DomainName(domain, port) => {
4545
lookup_then!(&context, domain, *port, |addr| {

crates/shadowsocks/src/relay/tcprelay/proxy_stream/client.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ where
115115
Some(d) => {
116116
match time::timeout(
117117
d,
118-
OutboundTcpStream::connect_server_with_opts(&context, svr_cfg.external_addr(), opts),
118+
OutboundTcpStream::connect_server_with_opts(&context, svr_cfg.tcp_external_addr(), opts),
119119
)
120120
.await
121121
{
@@ -129,13 +129,13 @@ where
129129
}
130130
}
131131
}
132-
None => OutboundTcpStream::connect_server_with_opts(&context, svr_cfg.external_addr(), opts).await?,
132+
None => OutboundTcpStream::connect_server_with_opts(&context, svr_cfg.tcp_external_addr(), opts).await?,
133133
};
134134

135135
trace!(
136136
"connected tcp remote {} (outbound: {}) with {:?}",
137137
svr_cfg.addr(),
138-
svr_cfg.external_addr(),
138+
svr_cfg.tcp_external_addr(),
139139
opts
140140
);
141141

crates/shadowsocks/src/relay/udprelay/proxy_socket.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ impl ProxySocket {
9898
) -> ProxySocketResult<ProxySocket> {
9999
// Note: Plugins doesn't support UDP relay
100100

101-
let socket = ShadowUdpSocket::connect_server_with_opts(&context, svr_cfg.addr(), opts).await?;
101+
let socket = ShadowUdpSocket::connect_server_with_opts(&context, svr_cfg.udp_external_addr(), opts).await?;
102102

103-
trace!("connected udp remote {} with {:?}", svr_cfg.addr(), opts);
103+
trace!("connected udp remote {} with {:?}", svr_cfg.udp_external_addr(), opts);
104104

105105
Ok(ProxySocket::from_socket(
106106
UdpSocketType::Client,
@@ -158,7 +158,7 @@ impl ProxySocket {
158158
opts: AcceptOpts,
159159
) -> ProxySocketResult<ProxySocket> {
160160
// Plugins doesn't support UDP
161-
let socket = match svr_cfg.addr() {
161+
let socket = match svr_cfg.udp_external_addr() {
162162
ServerAddr::SocketAddr(sa) => ShadowUdpSocket::listen_with_opts(sa, opts).await?,
163163
ServerAddr::DomainName(domain, port) => {
164164
lookup_then!(&context, domain, *port, |addr| {

src/service/local.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
583583
plugin: p,
584584
plugin_opts: matches.get_one::<String>("PLUGIN_OPT").cloned(),
585585
plugin_args: Vec::new(),
586+
plugin_mode: Mode::TcpOnly,
586587
};
587588

588589
sc.set_plugin(plugin);

src/service/manager.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
373373
plugin: p,
374374
plugin_opts: matches.get_one::<String>("PLUGIN_OPT").cloned(),
375375
plugin_args: Vec::new(),
376+
plugin_mode: Mode::TcpOnly,
376377
});
377378
}
378379

src/service/server.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ pub fn main(matches: &ArgMatches) -> ExitCode {
354354
plugin: p,
355355
plugin_opts: matches.get_one::<String>("PLUGIN_OPT").cloned(),
356356
plugin_args: Vec::new(),
357+
plugin_mode: Mode::TcpOnly,
357358
};
358359

359360
sc.set_plugin(plugin);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy