feat(shadowsocks-service): online config plugin whitelist (#1943)

This commit is contained in:
zonyitoo
2025-04-29 23:35:14 +08:00
parent 965ea0355d
commit 7ab6772549
3 changed files with 44 additions and 0 deletions

View File

@@ -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<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
allowed_plugins: Option<Vec<String>>,
}
/// Server config type
@@ -1289,6 +1292,8 @@ pub struct OnlineConfig {
pub config_url: String,
/// Update interval, 3600s by default
pub update_interval: Option<Duration>,
/// Allowed plugins
pub allowed_plugins: Option<Vec<String>>,
}
/// 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(),
});
}

View File

@@ -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<HashSet<String>>,
}
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<V, S>(&mut self, allowed_plugins: V)
where
V: Iterator<Item = S>,
S: Into<String>,
{
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<OnlineConfigService> {
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<HashSet<String>>,
}
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();

View File

@@ -933,6 +933,7 @@ pub fn create(matches: &ArgMatches) -> ShadowsocksResult<(Runtime, impl Future<O
config.online_config = Some(OnlineConfig {
config_url: online_config_url.clone(),
update_interval: online_config_update_interval.map(Duration::from_secs),
allowed_plugins: None,
});
}