diff --git a/src/bin/local.rs b/src/bin/local.rs index 44cdadd3..5c595a70 100644 --- a/src/bin/local.rs +++ b/src/bin/local.rs @@ -256,19 +256,6 @@ fn main() { config.server.push(svr_addr); } - #[cfg(target_os = "android")] - if matches.is_present("VPN_MODE") { - // A socket `protect_path` in CWD - // Same as shadowsocks-libev's android.c - config.protect_path = Some(From::from("protect_path")); - - // Set default config.local_dns_addr - #[cfg(feature = "local-dns")] - if config.local_dns_addr.is_none() { - config.local_dns_addr = Some(From::from("local_dns_path")); - } - } - #[cfg(feature = "local-flow-stat")] { if let Some(stat_path) = matches.value_of("STAT_PATH") { @@ -283,8 +270,6 @@ fn main() { if let Some(local_dns_addr) = matches.value_of("LOCAL_DNS_ADDR") { let addr = local_dns_addr.parse::().expect("local dns address"); config.local_dns_addr = Some(addr); - } else if config.local_dns_addr.is_none() { - panic!("--local-dns-addr is required for local-dns relay"); } if let Some(remote_dns_addr) = matches.value_of("REMOTE_DNS_ADDR") { @@ -298,6 +283,19 @@ fn main() { } } + #[cfg(target_os = "android")] + if matches.is_present("VPN_MODE") { + // A socket `protect_path` in CWD + // Same as shadowsocks-libev's android.c + config.protect_path = Some(From::from("protect_path")); + + // Set default config.local_dns_addr + #[cfg(feature = "local-dns")] + if config.local_dns_addr.is_none() { + config.local_dns_addr = Some(From::from("local_dns_path")); + } + } + if let Some(local_addr) = matches.value_of("LOCAL_ADDR") { let local_addr = local_addr.parse::().expect("local bind addr"); config.local_addr = Some(local_addr); @@ -412,6 +410,12 @@ fn main() { return; } + if let Err(err) = config.check_integrity() { + eprintln!("config integrity check failed, {}", err); + println!("{}", matches.usage()); + return; + } + #[cfg(unix)] if matches.is_present("DAEMONIZE") { daemonize::daemonize(matches.value_of("DAEMONIZE_PID_PATH")); diff --git a/src/bin/manager.rs b/src/bin/manager.rs index 1382cf1d..8e8d5dd0 100644 --- a/src/bin/manager.rs +++ b/src/bin/manager.rs @@ -192,6 +192,12 @@ fn main() { return; } + if let Err(err) = config.check_integrity() { + eprintln!("config integrity check failed, {}", err); + println!("{}", matches.usage()); + return; + } + #[cfg(unix)] if matches.is_present("DAEMONIZE") { daemonize::daemonize(matches.value_of("DAEMONIZE_PID_PATH")); diff --git a/src/bin/server.rs b/src/bin/server.rs index 87564a77..8ea8b294 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -216,6 +216,12 @@ fn main() { return; } + if let Err(err) = config.check_integrity() { + eprintln!("config integrity check failed, {}", err); + println!("{}", matches.usage()); + return; + } + #[cfg(unix)] if matches.is_present("DAEMONIZE") { daemonize::daemonize(matches.value_of("DAEMONIZE_PID_PATH")); diff --git a/src/config.rs b/src/config.rs index 5d2db932..99bee631 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1614,44 +1614,109 @@ impl Config { /// Check if all required fields are already set pub fn check_integrity(&self) -> Result<(), Error> { if self.config_type.is_local() { - if self.local_addr.is_some() { - return Ok(()); + if self.local_addr.is_none() { + let err = Error::new( + ErrorKind::MissingField, + "missing `local_address` and `local_port` for client configuration", + None, + ); + return Err(err); } - let err = Error::new( - ErrorKind::MissingField, - "missing `local_address` and `local_port` for client configuration", - None, - ); - return Err(err); + if self.server.is_empty() { + let err = Error::new( + ErrorKind::MissingField, + "missing `servers` for client configuration", + None, + ); + return Err(err); + } } if self.config_type.is_server() { - if !self.server.is_empty() { - return Ok(()); + if self.server.is_empty() { + let err = Error::new( + ErrorKind::MissingField, + "missing any valid servers in configuration", + None, + ); + return Err(err); } - - let err = Error::new( - ErrorKind::MissingField, - "missing any valid servers in configuration", - None, - ); - return Err(err); } if self.config_type.is_manager() { - if self.manager.is_some() { - return Ok(()); + if self.manager.is_none() { + let err = Error::new( + ErrorKind::MissingField, + "missing `manager_addr` and `manager_port` in configuration", + None, + ); + return Err(err); + } + } + + #[cfg(feature = "local-dns")] + if self.config_type == ConfigType::DnsLocal { + if self.dns_bind_addr.is_none() || self.local_dns_addr.is_none() || self.remote_dns_addr.is_none() { + let err = Error::new( + ErrorKind::MissingField, + "missing `dns_bind_addr`, `local_dns_addr` or `remote_dns_addr` in configuration", + None, + ); + return Err(err); + } + } else if self.dns_bind_addr.is_some() { + // Run a DNS server in the same process + if self.local_dns_addr.is_none() || self.remote_dns_addr.is_none() { + let err = Error::new( + ErrorKind::MissingField, + "missing `local_dns_addr` or `remote_dns_addr` in configuration", + None, + ); + return Err(err); + } + } + + #[cfg(all( + feature = "local-http", + any(feature = "local-http-native-tls", feature = "local-http-rustls") + ))] + if self.config_type == ConfigType::HttpsLocal { + #[cfg(feature = "local-http-rustls")] + if self.tls_identity_certificate_path.is_none() || self.tls_identity_private_key_path.is_none() { + let err = Error::new( + ErrorKind::MissingField, + "missing `tls_identity_certificate_path` or `tls_identity_private_key_path` in configuration", + None, + ); + return Err(err); } - let err = Error::new( - ErrorKind::MissingField, - "missing `manager_addr` and `manager_port` in configuration", - None, - ); + #[cfg(feature = "local-http-native-tls")] + if self.tls_identity_path.is_none() || self.tls_identity_password.is_none() { + let err = Error::new( + ErrorKind::MissingField, + "missing `tls_identity_path` or `tls_identity_password` in configuration", + None, + ); + return Err(err); + } + } + + #[cfg(feature = "local-flow-stat")] + if self.stat_path.is_none() { + let err = Error::new(ErrorKind::MissingField, "missing `stat_path` in configuration", None); return Err(err); } + #[cfg(feature = "local-tunnel")] + if self.config_type == ConfigType::TunnelLocal { + if self.forward.is_none() { + let err = Error::new(ErrorKind::MissingField, "missing `forward` in configuration", None); + return Err(err); + } + } + Ok(()) } diff --git a/src/relay/local.rs b/src/relay/local.rs index 51478e15..5b8aa90d 100644 --- a/src/relay/local.rs +++ b/src/relay/local.rs @@ -20,6 +20,11 @@ pub async fn run(mut config: Config) -> io::Result<()> { assert!(config.config_type.is_local()); + if let Err(err) = config.check_integrity() { + let e = io::Error::new(ErrorKind::Other, err.desc); + return Err(e); + } + if let Some(nofile) = config.nofile { debug!("setting RLIMIT_NOFILE to {}", nofile); if let Err(err) = set_nofile(nofile) { diff --git a/src/relay/manager.rs b/src/relay/manager.rs index 0cb82c5f..357957c5 100644 --- a/src/relay/manager.rs +++ b/src/relay/manager.rs @@ -576,6 +576,11 @@ impl ManagerService { pub async fn run(config: Config) -> io::Result<()> { assert!(config.config_type.is_manager()); + if let Err(err) = config.check_integrity() { + let e = io::Error::new(ErrorKind::Other, err.desc); + return Err(e); + } + if let Some(nofile) = config.nofile { debug!("setting RLIMIT_NOFILE to {}", nofile); if let Err(err) = set_nofile(nofile) { diff --git a/src/relay/server.rs b/src/relay/server.rs index 0d517ca4..bea4190d 100644 --- a/src/relay/server.rs +++ b/src/relay/server.rs @@ -45,6 +45,11 @@ pub(crate) async fn run_with( assert!(config.config_type.is_server()); + if let Err(err) = config.check_integrity() { + let e = io::Error::new(ErrorKind::Other, err.desc); + return Err(e); + } + if let Some(nofile) = config.nofile { debug!("setting RLIMIT_NOFILE to {}", nofile); if let Err(err) = set_nofile(nofile) {