diff --git a/crates/shadowsocks-service/src/config.rs b/crates/shadowsocks-service/src/config.rs index 873ef4ed..18488828 100644 --- a/crates/shadowsocks-service/src/config.rs +++ b/crates/shadowsocks-service/src/config.rs @@ -242,6 +242,10 @@ struct SSConfig { #[cfg(feature = "local-online-config")] #[serde(skip_serializing_if = "Option::is_none")] online_config: Option, + + #[cfg(feature = "local-online-config")] + #[serde(skip_serializing_if = "Option::is_none")] + version: Option, } #[derive(Serialize, Deserialize, Debug, Default)] @@ -425,6 +429,11 @@ pub enum ConfigType { /// Config for Manager server Manager, + + /// Config for online config (SIP008) + /// https://shadowsocks.org/doc/sip008.html + #[cfg(feature = "local-online-config")] + OnlineConfig, } impl ConfigType { @@ -442,6 +451,12 @@ impl ConfigType { pub fn is_manager(self) -> bool { self == ConfigType::Manager } + + /// Chec if it is online config type (SIP008) + #[cfg(feature = "local-online-config")] + pub fn is_online_config(self) -> bool { + self == ConfigType::OnlineConfig + } } cfg_if! { @@ -1834,6 +1849,25 @@ impl Config { // // This behavior causes lots of confusion. use outbound_bind_addr instead } + #[cfg(feature = "local-online-config")] + ConfigType::OnlineConfig => { + // SIP008. https://shadowsocks.org/doc/sip008.html + // "version" should be set to "1" + match config.version { + Some(1) => {} + Some(v) => { + let err = Error::new( + ErrorKind::Invalid, + "invalid online config version", + Some(format!("version: {v}")), + ); + return Err(err); + } + None => { + warn!("OnlineConfig \"version\" is missing in the configuration, assuming it is a compatible version for this project"); + } + } + } } // Standard config @@ -2566,6 +2600,16 @@ impl Config { return Err(err); } + #[cfg(feature = "local-online-config")] + if self.config_type.is_online_config() && self.server.is_empty() { + let err = Error::new( + ErrorKind::MissingField, + "missing any valid servers in configuration", + None, + ); + return Err(err); + } + if self.config_type.is_manager() && self.manager.is_none() { let err = Error::new( ErrorKind::MissingField, @@ -2606,6 +2650,20 @@ impl Config { return Err(err); } } + + #[cfg(feature = "local-online-config")] + if self.config_type.is_online_config() { + // Only server could bind to INADDR_ANY + let ip = sa.ip(); + if ip.is_unspecified() { + let err = Error::new( + ErrorKind::Malformed, + "`server` shouldn't be an unspecified address (INADDR_ANY)", + None, + ); + return Err(err); + } + } } ServerAddr::DomainName(dn, port) => { if dn.is_empty() || *port == 0 { diff --git a/crates/shadowsocks/src/config.rs b/crates/shadowsocks/src/config.rs index fb617942..1c2ea525 100644 --- a/crates/shadowsocks/src/config.rs +++ b/crates/shadowsocks/src/config.rs @@ -302,7 +302,7 @@ impl Default for ServerUserManager { } /// The source of the ServerConfig -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum ServerSource { Default, //< Default source, created in code Configuration, //< Created from configuration diff --git a/src/service/local.rs b/src/service/local.rs index a4566436..a4a5f743 100644 --- a/src/service/local.rs +++ b/src/service/local.rs @@ -575,6 +575,7 @@ pub fn define_command_line_options(mut app: Command) -> Command { /// Create `Runtime` and `main` entry pub fn create(matches: &ArgMatches) -> Result<(Runtime, impl Future), ExitCode> { + #[cfg_attr(not(feature = "local-online-config"), allow(unused_mut))] let (mut config, runtime) = { let config_path_opt = matches.get_one::("CONFIG").cloned().or_else(|| { if !matches.contains_id("SERVER_CONFIG") { @@ -1140,8 +1141,7 @@ async fn get_online_config_servers( } }; - // NOTE: ConfigType::Local will force verify local_address and local_port keys. SIP008 standard doesn't include those keys. - let online_config = match Config::load_from_str(&body, ConfigType::Server) { + let online_config = match Config::load_from_str(&body, ConfigType::OnlineConfig) { Ok(c) => c, Err(err) => { error!( @@ -1152,6 +1152,14 @@ async fn get_online_config_servers( } }; + if let Err(err) = online_config.check_integrity() { + error!( + "server-loader task failed to load from url: {}, error: {}", + online_config_url, err + ); + return Err(Box::new(err)); + } + Ok(online_config.server) } @@ -1188,6 +1196,7 @@ impl ServerReloader { struct ConfigDisplay<'a>(&'a ServerReloader); impl Display for ConfigDisplay<'_> { + #[cfg_attr(not(feature = "local-online-config"), allow(unused_assignments, unused_variables))] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut is_first = true; @@ -1266,6 +1275,7 @@ impl ServerReloader { #[cfg(unix)] { + #[cfg_attr(not(feature = "local-online-config"), allow(unused_mut))] let mut has_things_to_do = arc_self.config_path.is_some(); #[cfg(feature = "local-online-config")] {