diff --git a/lightway-app-utils/src/args/connection_type.rs b/lightway-app-utils/src/args/connection_type.rs index 362d0278..17ccd72e 100644 --- a/lightway-app-utils/src/args/connection_type.rs +++ b/lightway-app-utils/src/args/connection_type.rs @@ -19,10 +19,15 @@ pub enum ConnectionType { } impl ConnectionType { - /// A helper function easier to use especially in mobile + #[allow(missing_docs)] pub fn is_tcp(&self) -> bool { *self == ConnectionType::Tcp } + + #[allow(missing_docs)] + pub fn is_udp(&self) -> bool { + *self == ConnectionType::Udp + } } impl From for LWConnectionType { diff --git a/lightway-server/src/config.rs b/lightway-server/src/config.rs index 81638478..2d8fe5dc 100644 --- a/lightway-server/src/config.rs +++ b/lightway-server/src/config.rs @@ -225,3 +225,50 @@ impl Default for Config { } } } + +impl Config { + /// Ensure the config is validated, and alerted when there's a conflict in the settings. + pub fn validate(&self) -> anyhow::Result<()> { + if self.enable_expresslane { + anyhow::ensure!(self.mode.is_udp(), "Expresslane only work in udp mode") + } + + if self.proxy_protocol { + anyhow::ensure!( + self.mode.is_tcp(), + "Proxy protocol only support with tcp mode" + ) + } + + Ok(()) + } +} + +// Note it easier to see what is different from default in each testcase +#[allow(clippy::field_reassign_with_default)] +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn validate_default_config() { + let config = Config::default(); + assert!(config.validate().is_ok()); + } + + #[test] + fn validate_enable_expresslane() { + let mut config = Config::default(); + config.mode = ConnectionType::Tcp; + config.enable_expresslane = true; + assert!(config.validate().is_err()); + } + + #[test] + fn validate_proxy_protocol() { + let mut config = Config::default(); + config.mode = ConnectionType::Udp; + config.proxy_protocol = true; + assert!(config.validate().is_err()); + } +} diff --git a/lightway-server/src/lib.rs b/lightway-server/src/lib.rs index db6e0a5f..42685d28 100644 --- a/lightway-server/src/lib.rs +++ b/lightway-server/src/lib.rs @@ -262,6 +262,67 @@ pub struct ServerConfig ServerAuth>> { pub randomize_ippool: bool, } +impl ServerAuth>> ServerConfig { + pub fn try_from_auth_and_config(auth: SA, config: config::Config) -> Result { + config.validate()?; + + let mut tun_config = lightway_app_utils::TunConfig::default(); + if let Some(tun_name) = config.tun_name { + tun_config.tun_name(tun_name); + } + tun_config.up(); + + Ok(crate::ServerConfig { + mode: match config.mode { + lightway_app_utils::args::ConnectionType::Udp => { + crate::ServerConnectionMode::Datagram(None) + } + lightway_app_utils::args::ConnectionType::Tcp => { + crate::ServerConnectionMode::Stream(None) + } + }, + auth, + server_cert: config.server_cert, + server_key: config.server_key, + tun_config, + ip_pool: config.ip_pool, + ip_map: config.ip_map.unwrap_or_default().try_into()?, + inside_io: None, + tun_ip: config.tun_ip, + lightway_server_ip: config.lightway_server_ip, + lightway_client_ip: config.lightway_client_ip, + lightway_dns_ip: config.lightway_dns_ip, + use_dynamic_client_ip: false, + enable_expresslane: config.enable_expresslane, + expresslane_keys_rotation_interval: config.expresslane_keys_rotation_interval.into(), + expresslane_cb: None, + expresslane_metrics: None, + event_cb: None, + enable_pqc: config.enable_pqc, + #[cfg(target_os = "linux")] + enable_tun_offload: config.enable_tun_offload, + #[cfg(feature = "io-uring")] + enable_tun_iouring: config.enable_tun_iouring, + #[cfg(feature = "io-uring")] + iouring_entry_count: config.iouring_entry_count, + #[cfg(feature = "io-uring")] + iouring_sqpoll_idle_time: config.iouring_sqpoll_idle_time.into(), + key_update_interval: config.key_update_interval.into(), + connection_age_expiration_interval: config.connection_age_expiration_interval.into(), + statistics_reporting_interval: config.statistics_reporting_interval.into(), + inside_plugins: Default::default(), + outside_plugins: Default::default(), + inside_pkt_codec: None, + bind_address: config.bind_address, + proxy_protocol: config.proxy_protocol, + udp_buffer_size: config.udp_buffer_size, + enable_batch_receive: config.enable_batch_receive, + #[cfg(feature = "debug")] + randomize_ippool: config.randomize_ippool, + }) + } +} + pub(crate) fn handle_inside_io_error(conn: Arc, result: ConnectionResult<()>) { match result { Ok(()) => {} diff --git a/lightway-server/src/main.rs b/lightway-server/src/main.rs index a7941745..c50cc06b 100644 --- a/lightway-server/src/main.rs +++ b/lightway-server/src/main.rs @@ -1,5 +1,4 @@ mod auth; -mod config; use anyhow::{Context, Result, anyhow}; use clap::Parser; @@ -10,10 +9,10 @@ use tokio::fs::read_to_string; use tokio_stream::StreamExt; use tracing::{error, trace}; -use config::{Config, ConfigPatch}; -use lightway_app_utils::{TunConfig, Validate, validate_configuration_file_path}; +use lightway_app_utils::{Validate, validate_configuration_file_path}; #[cfg(feature = "debug")] use lightway_core::set_logging_callback; +use lightway_server::config::{Config, ConfigPatch}; use lightway_server::*; async fn metrics_debug() { @@ -115,6 +114,13 @@ async fn main() -> Result<()> { let fmt = tracing_subscriber::fmt().with_env_filter(filter); config.log_format.init_with_env_filter(fmt); + let server_config = crate::ServerConfig::try_from_auth_and_config( + crate::auth::Auth::new( + config.user_db.as_ref().map(AsRef::as_ref), + config.token_rsa_pub_key_pem.as_ref().map(AsRef::as_ref), + )?, + config, + )?; tokio::spawn(metrics_debug()); @@ -140,62 +146,5 @@ async fn main() -> Result<()> { } }); - let auth = auth::Auth::new( - config.user_db.as_ref().map(AsRef::as_ref), - config.token_rsa_pub_key_pem.as_ref().map(AsRef::as_ref), - )?; - - let mut tun_config = TunConfig::default(); - if let Some(tun_name) = config.tun_name { - tun_config.tun_name(tun_name); - } - tun_config.up(); - let mode = match config.mode { - lightway_app_utils::args::ConnectionType::Udp => ServerConnectionMode::Datagram(None), - lightway_app_utils::args::ConnectionType::Tcp => ServerConnectionMode::Stream(None), - }; - - let config = ServerConfig { - mode, - auth, - server_cert: config.server_cert, - server_key: config.server_key, - tun_config, - ip_pool: config.ip_pool, - ip_map: config.ip_map.unwrap_or_default().try_into()?, - inside_io: None, - tun_ip: config.tun_ip, - lightway_server_ip: config.lightway_server_ip, - lightway_client_ip: config.lightway_client_ip, - lightway_dns_ip: config.lightway_dns_ip, - use_dynamic_client_ip: false, - enable_expresslane: config.enable_expresslane, - expresslane_keys_rotation_interval: config.expresslane_keys_rotation_interval.into(), - expresslane_cb: None, - expresslane_metrics: None, - event_cb: None, - enable_pqc: config.enable_pqc, - #[cfg(target_os = "linux")] - enable_tun_offload: config.enable_tun_offload, - #[cfg(feature = "io-uring")] - enable_tun_iouring: config.enable_tun_iouring, - #[cfg(feature = "io-uring")] - iouring_entry_count: config.iouring_entry_count, - #[cfg(feature = "io-uring")] - iouring_sqpoll_idle_time: config.iouring_sqpoll_idle_time.into(), - key_update_interval: config.key_update_interval.into(), - connection_age_expiration_interval: config.connection_age_expiration_interval.into(), - statistics_reporting_interval: config.statistics_reporting_interval.into(), - inside_plugins: Default::default(), - outside_plugins: Default::default(), - inside_pkt_codec: None, - bind_address: config.bind_address, - proxy_protocol: config.proxy_protocol, - udp_buffer_size: config.udp_buffer_size, - enable_batch_receive: config.enable_batch_receive, - #[cfg(feature = "debug")] - randomize_ippool: config.randomize_ippool, - }; - - server(config).await + server(server_config).await }