From 7ab67725495169a88570eb25d6cc5409ea3ea1eb Mon Sep 17 00:00:00 2001 From: zonyitoo Date: Tue, 29 Apr 2025 23:35:14 +0800 Subject: [PATCH] feat(shadowsocks-service): online config plugin whitelist (#1943) --- crates/shadowsocks-service/src/config.rs | 7 ++++ .../src/local/online_config/mod.rs | 36 +++++++++++++++++++ src/service/local.rs | 1 + 3 files changed, 44 insertions(+) diff --git a/crates/shadowsocks-service/src/config.rs b/crates/shadowsocks-service/src/config.rs index 1b3067e2..dad398ae 100644 --- a/crates/shadowsocks-service/src/config.rs +++ b/crates/shadowsocks-service/src/config.rs @@ -413,7 +413,10 @@ struct SSServerExtConfig { #[derive(Serialize, Deserialize, Debug, Default)] struct SSOnlineConfig { config_url: String, + #[serde(skip_serializing_if = "Option::is_none")] update_interval: Option, + #[serde(skip_serializing_if = "Option::is_none")] + allowed_plugins: Option>, } /// Server config type @@ -1289,6 +1292,8 @@ pub struct OnlineConfig { pub config_url: String, /// Update interval, 3600s by default pub update_interval: Option, + /// Allowed plugins + pub allowed_plugins: Option>, } /// Configuration @@ -2453,6 +2458,7 @@ impl Config { nconfig.online_config = Some(OnlineConfig { config_url: online_config.config_url, update_interval: online_config.update_interval.map(Duration::from_secs), + allowed_plugins: online_config.allowed_plugins, }); } @@ -3195,6 +3201,7 @@ impl fmt::Display for Config { jconf.online_config = Some(SSOnlineConfig { config_url: online_config.config_url.clone(), update_interval: online_config.update_interval.as_ref().map(Duration::as_secs), + allowed_plugins: online_config.allowed_plugins.clone(), }); } diff --git a/crates/shadowsocks-service/src/local/online_config/mod.rs b/crates/shadowsocks-service/src/local/online_config/mod.rs index 407e8f9e..871c2ff4 100644 --- a/crates/shadowsocks-service/src/local/online_config/mod.rs +++ b/crates/shadowsocks-service/src/local/online_config/mod.rs @@ -3,6 +3,7 @@ //! Online Configuration Delivery URL (https://shadowsocks.org/doc/sip008.html) use std::{ + collections::HashSet, io, sync::Arc, time::{Duration, Instant}, @@ -29,6 +30,7 @@ pub struct OnlineConfigServiceBuilder { config_url: String, balancer: PingBalancer, config_update_interval: Duration, + allowed_plugins: Option>, } impl OnlineConfigServiceBuilder { @@ -39,6 +41,7 @@ impl OnlineConfigServiceBuilder { config_url, balancer, config_update_interval: Duration::from_secs(3600), + allowed_plugins: None, } } @@ -47,6 +50,19 @@ impl OnlineConfigServiceBuilder { self.config_update_interval = update_interval; } + /// Allowed plugins (whitelist) from SIP008 server + pub fn set_allowed_plugins(&mut self, allowed_plugins: V) + where + V: Iterator, + S: Into, + { + let mut allowed_plugins_set = HashSet::new(); + for plugin in allowed_plugins { + allowed_plugins_set.insert(plugin.into()); + } + self.allowed_plugins = Some(allowed_plugins_set); + } + /// Build OnlineConfigService pub async fn build(self) -> io::Result { let mut service = OnlineConfigService { @@ -55,6 +71,7 @@ impl OnlineConfigServiceBuilder { config_url: self.config_url, config_update_interval: self.config_update_interval, balancer: self.balancer, + allowed_plugins: self.allowed_plugins, }; // Run once after creation. @@ -70,6 +87,7 @@ pub struct OnlineConfigService { config_url: String, config_update_interval: Duration, balancer: PingBalancer, + allowed_plugins: Option>, } impl OnlineConfigService { @@ -196,6 +214,24 @@ impl OnlineConfigService { let after_read_time = Instant::now(); + // Check plugin whitelist + if let Some(ref allowed_plugins) = self.allowed_plugins { + for server in &online_config.server { + if let Some(ref plugin) = server.config.plugin() { + if !allowed_plugins.contains(&plugin.plugin) { + error!( + "server-loader task found not allowed plugin: {}, url: {}", + plugin.plugin, self.config_url + ); + return Err(io::Error::new( + io::ErrorKind::Other, + format!("not allowed plugin: {}", plugin.plugin), + )); + } + } + } + } + // Merge with static servers let server_len = online_config.server.len(); diff --git a/src/service/local.rs b/src/service/local.rs index 4a1f61d1..73314e87 100644 --- a/src/service/local.rs +++ b/src/service/local.rs @@ -933,6 +933,7 @@ pub fn create(matches: &ArgMatches) -> ShadowsocksResult<(Runtime, impl Future