diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 43109a8f..7ad58bcd 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -783,6 +783,7 @@ dependencies = [ "log", "prost", "prost-build", + "rand 0.8.5", "serde", "serde_json", "sqlx", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index efc93ab2..e40dabb8 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -37,6 +37,7 @@ tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", br local-ip-address = "0.5.5" tokio = { version = "1.32", features = ["full"] } log = "0.4.20" +rand = "0.8.5" [features] # this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled. diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 6465f27f..f12dd166 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -37,7 +37,10 @@ pub async fn connect(location_id: i64, handle: tauri::AppHandle) -> Result<(), S let address = local_ip().map_err(|err| err.to_string())?; let connection = Connection::new(location_id, address.to_string()); state.active_connections.lock().unwrap().push(connection); - debug!("Active connections: {:#?}", state.active_connections.lock().unwrap()); + debug!( + "Active connections: {:#?}", + state.active_connections.lock().unwrap() + ); handle .emit_all( "connection-changed", @@ -61,11 +64,21 @@ pub async fn connect(location_id: i64, handle: tauri::AppHandle) -> Result<(), S .await .map_err(|err| err.to_string()) .unwrap(); + debug!("Saving location stats: {:#?}", location_stats); let _ = location_stats.save(&state.get_pool()).await; + debug!("Saved location stats: {:#?}", location_stats); } } - Err(_) => { - debug!("Stopped stats thread for location: {}", location.name); + Err(e) => { + error!( + "Error {} while reading data for interface: {}", + e, location.name + ); + debug!( + "Stopped stats thread for location: {}. Error: {}", + location.name, + e.to_string() + ); break; } } diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index dd1cb221..2dcf28cc 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -14,6 +14,7 @@ pub async fn setup_interface(location: &Location, pool: &DbPool) -> Result<(), E let interface_name = remove_whitespace(&location.name); debug!("Creating interface: {}", interface_name); let api = WGApi::new(interface_name.clone(), false)?; + api.create_interface()?; if let Some(keys) = WireguardKeys::find_by_instance_id(pool, location.instance_id).await? { // TODO: handle unwrap @@ -49,24 +50,34 @@ pub async fn setup_interface(location: &Location, pool: &DbPool) -> Result<(), E } } } - if let Some((address, port)) = location.endpoint.split_once(':') { + if let Some(port) = find_random_free_port() { let interface_config = InterfaceConfiguration { name: interface_name.clone(), prvkey: keys.prvkey, - address: address.into(), - port: port.parse().unwrap(), - peers: vec![peer], + address: location.address.clone(), + port: port.into(), + peers: vec![peer.clone()], }; debug!("Creating interface {:#?}", interface_config); - api.configure_interface(&interface_config)?; - info!("created interface {:#?}", interface_config); - Ok(()) + if let Err(err) = api.configure_interface(&interface_config) { + error!("Failed to configure interface: {}", err.to_string()); + Err(Error::InternalError) + } else { + if let Err(err) = api.configure_peer(&peer) { + error!("Failed to configure peer: {}", err.to_string()); + return Err(Error::InternalError); + } + info!("created interface {:#?}", interface_config); + Ok(()) + } } else { - error!("Failed to parse location endpoint: {}", location.endpoint); + error!("Error finding free port"); Err(Error::InternalError) } } else { error!("No keys found for instance: {}", location.instance_id); + error!("Removing interface: {}", location.name); + api.remove_interface()?; Err(Error::InternalError) } } @@ -98,3 +109,30 @@ fn add_route(allowed_ip: &str, interface_name: &str) -> Result<(), std::io::Erro .output()?; Ok(()) } + +use std::net::TcpListener; + +fn find_random_free_port() -> Option { + const MAX_PORT: u16 = 65535; + const MIN_PORT: u16 = 6000; + + // Create a TcpListener to check for port availability + for _ in 0..(MAX_PORT - MIN_PORT + 1) { + let port = rand::random::() % (MAX_PORT - MIN_PORT) + MIN_PORT; + if is_port_free(port) { + return Some(port); + } + } + + None // No free port found in the specified range +} + +fn is_port_free(port: u16) -> bool { + if let Ok(listener) = TcpListener::bind(format!("127.0.0.1:{}", port)) { + // Port is available; close the listener + drop(listener); + true + } else { + false + } +}