From 100ef0fa28dd9be4aef296335b006f22a1bf7205 Mon Sep 17 00:00:00 2001 From: Alexey <247128645+axkurcom@users.noreply.github.com> Date: Mon, 9 Mar 2026 23:37:29 +0300 Subject: [PATCH] Correct IP:port/public-host:public-port in API --- src/api/mod.rs | 23 ++++++++------- src/api/users.rs | 72 +++++++++++++++++++++++++++------------------- src/maestro/mod.rs | 11 +++++-- 3 files changed, 63 insertions(+), 43 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 0a51231..ff9d2f9 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -75,8 +75,7 @@ pub(super) struct ApiShared { pub(super) me_pool: Arc>>>, pub(super) upstream_manager: Arc, pub(super) config_path: PathBuf, - pub(super) startup_detected_ip_v4: Option, - pub(super) startup_detected_ip_v6: Option, + pub(super) detected_ips_rx: watch::Receiver<(Option, Option)>, pub(super) mutation_lock: Arc>, pub(super) minimal_cache: Arc>>, pub(super) runtime_edge_connections_cache: Arc>>, @@ -91,6 +90,10 @@ impl ApiShared { fn next_request_id(&self) -> u64 { self.request_id.fetch_add(1, Ordering::Relaxed) } + + fn detected_link_ips(&self) -> (Option, Option) { + *self.detected_ips_rx.borrow() + } } pub async fn serve( @@ -102,8 +105,7 @@ pub async fn serve( config_rx: watch::Receiver>, admission_rx: watch::Receiver, config_path: PathBuf, - startup_detected_ip_v4: Option, - startup_detected_ip_v6: Option, + detected_ips_rx: watch::Receiver<(Option, Option)>, process_started_at_epoch_secs: u64, startup_tracker: Arc, ) { @@ -134,8 +136,7 @@ pub async fn serve( me_pool, upstream_manager, config_path, - startup_detected_ip_v4, - startup_detected_ip_v6, + detected_ips_rx, mutation_lock: Arc::new(Mutex::new(())), minimal_cache: Arc::new(Mutex::new(None)), runtime_edge_connections_cache: Arc::new(Mutex::new(None)), @@ -356,12 +357,13 @@ async fn handle( } ("GET", "/v1/stats/users") | ("GET", "/v1/users") => { let revision = current_revision(&shared.config_path).await?; + let (detected_ip_v4, detected_ip_v6) = shared.detected_link_ips(); let users = users_from_config( &cfg, &shared.stats, &shared.ip_tracker, - shared.startup_detected_ip_v4, - shared.startup_detected_ip_v6, + detected_ip_v4, + detected_ip_v6, ) .await; Ok(success_response(StatusCode::OK, users, revision)) @@ -399,12 +401,13 @@ async fn handle( { if method == Method::GET { let revision = current_revision(&shared.config_path).await?; + let (detected_ip_v4, detected_ip_v6) = shared.detected_link_ips(); let users = users_from_config( &cfg, &shared.stats, &shared.ip_tracker, - shared.startup_detected_ip_v4, - shared.startup_detected_ip_v6, + detected_ip_v4, + detected_ip_v6, ) .await; if let Some(user_info) = users.into_iter().find(|entry| entry.username == user) diff --git a/src/api/users.rs b/src/api/users.rs index d156896..7265044 100644 --- a/src/api/users.rs +++ b/src/api/users.rs @@ -90,13 +90,14 @@ pub(super) async fn create_user( if let Some(limit) = updated_limit { shared.ip_tracker.set_user_limit(&body.username, limit).await; } + let (detected_ip_v4, detected_ip_v6) = shared.detected_link_ips(); let users = users_from_config( &cfg, &shared.stats, &shared.ip_tracker, - shared.startup_detected_ip_v4, - shared.startup_detected_ip_v6, + detected_ip_v4, + detected_ip_v6, ) .await; let user = users @@ -118,8 +119,8 @@ pub(super) async fn create_user( links: build_user_links( &cfg, &secret, - shared.startup_detected_ip_v4, - shared.startup_detected_ip_v6, + detected_ip_v4, + detected_ip_v6, ), }); @@ -185,12 +186,13 @@ pub(super) async fn patch_user( if let Some(limit) = updated_limit { shared.ip_tracker.set_user_limit(user, limit).await; } + let (detected_ip_v4, detected_ip_v6) = shared.detected_link_ips(); let users = users_from_config( &cfg, &shared.stats, &shared.ip_tracker, - shared.startup_detected_ip_v4, - shared.startup_detected_ip_v6, + detected_ip_v4, + detected_ip_v6, ) .await; let user_info = users @@ -232,12 +234,13 @@ pub(super) async fn rotate_secret( let revision = save_config_to_disk(&shared.config_path, &cfg).await?; drop(_guard); + let (detected_ip_v4, detected_ip_v6) = shared.detected_link_ips(); let users = users_from_config( &cfg, &shared.stats, &shared.ip_tracker, - shared.startup_detected_ip_v4, - shared.startup_detected_ip_v6, + detected_ip_v4, + detected_ip_v6, ) .await; let user_info = users @@ -418,17 +421,6 @@ fn resolve_link_hosts( return vec![host.to_string()]; } - let mut startup_hosts = Vec::new(); - if let Some(ip) = startup_detected_ip_v4 { - push_unique_host(&mut startup_hosts, &ip.to_string()); - } - if let Some(ip) = startup_detected_ip_v6 { - push_unique_host(&mut startup_hosts, &ip.to_string()); - } - if !startup_hosts.is_empty() { - return startup_hosts; - } - let mut hosts = Vec::new(); for listener in &cfg.server.listeners { if let Some(host) = listener @@ -443,24 +435,44 @@ fn resolve_link_hosts( if let Some(ip) = listener.announce_ip { if !ip.is_unspecified() { push_unique_host(&mut hosts, &ip.to_string()); + continue; + } + } + if listener.ip.is_unspecified() { + let detected_ip = if listener.ip.is_ipv4() { + startup_detected_ip_v4 + } else { + startup_detected_ip_v6 + }; + if let Some(ip) = detected_ip { + push_unique_host(&mut hosts, &ip.to_string()); + } else { + push_unique_host(&mut hosts, &listener.ip.to_string()); } continue; } - if !listener.ip.is_unspecified() { - push_unique_host(&mut hosts, &listener.ip.to_string()); - } + push_unique_host(&mut hosts, &listener.ip.to_string()); } - if hosts.is_empty() { - if let Some(host) = cfg.server.listen_addr_ipv4.as_deref() { - push_host_from_legacy_listen(&mut hosts, host); - } - if let Some(host) = cfg.server.listen_addr_ipv6.as_deref() { - push_host_from_legacy_listen(&mut hosts, host); - } + if !hosts.is_empty() { + return hosts; } - hosts + if let Some(ip) = startup_detected_ip_v4.or(startup_detected_ip_v6) { + return vec![ip.to_string()]; + } + + if let Some(host) = cfg.server.listen_addr_ipv4.as_deref() { + push_host_from_legacy_listen(&mut hosts, host); + } + if let Some(host) = cfg.server.listen_addr_ipv6.as_deref() { + push_host_from_legacy_listen(&mut hosts, host); + } + if !hosts.is_empty() { + return hosts; + } + + vec!["UNKNOWN".to_string()] } fn push_host_from_legacy_listen(hosts: &mut Vec, raw: &str) { diff --git a/src/maestro/mod.rs b/src/maestro/mod.rs index 92b42e3..fcb4d3f 100644 --- a/src/maestro/mod.rs +++ b/src/maestro/mod.rs @@ -20,7 +20,7 @@ mod runtime_tasks; mod shutdown; mod tls_bootstrap; -use std::net::SocketAddr; +use std::net::{IpAddr, SocketAddr}; use std::sync::Arc; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; use tokio::sync::{RwLock, Semaphore, watch}; @@ -189,6 +189,7 @@ pub async fn run() -> std::result::Result<(), Box> { } let (api_config_tx, api_config_rx) = watch::channel(Arc::new(config.clone())); + let (detected_ips_tx, detected_ips_rx) = watch::channel((None::, None::)); let initial_admission_open = !config.general.use_middle_proxy; let (admission_tx, admission_rx) = watch::channel(initial_admission_open); let initial_route_mode = if config.general.use_middle_proxy { @@ -223,6 +224,7 @@ pub async fn run() -> std::result::Result<(), Box> { let admission_rx_api = admission_rx.clone(); let config_path_api = std::path::PathBuf::from(&config_path); let startup_tracker_api = startup_tracker.clone(); + let detected_ips_rx_api = detected_ips_rx.clone(); tokio::spawn(async move { api::serve( listen, @@ -233,8 +235,7 @@ pub async fn run() -> std::result::Result<(), Box> { config_rx_api, admission_rx_api, config_path_api, - None, - None, + detected_ips_rx_api, process_started_at_epoch_secs, startup_tracker_api, ) @@ -288,6 +289,10 @@ pub async fn run() -> std::result::Result<(), Box> { config.general.stun_nat_probe_concurrency, ) .await?; + detected_ips_tx.send_replace(( + probe.detected_ipv4.map(IpAddr::V4), + probe.detected_ipv6.map(IpAddr::V6), + )); let decision = decide_network_capabilities(&config.network, &probe); log_probe_result(&probe, &decision); startup_tracker