From a15f74a6f966c287343a2945a7f6bffc8682132f Mon Sep 17 00:00:00 2001 From: Alexey <247128645+axkurcom@users.noreply.github.com> Date: Fri, 13 Mar 2026 16:52:24 +0300 Subject: [PATCH] Configured middle_proxy_nat_ip for ME Gate on strartup --- src/maestro/mod.rs | 6 ++- src/network/probe.rs | 64 ++++++++++++++++++++++++-- src/transport/middle_proxy/pool.rs | 4 +- src/transport/middle_proxy/pool_nat.rs | 8 +++- 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/maestro/mod.rs b/src/maestro/mod.rs index 996070e..6724188 100644 --- a/src/maestro/mod.rs +++ b/src/maestro/mod.rs @@ -295,7 +295,11 @@ pub async fn run() -> std::result::Result<(), Box> { probe.detected_ipv4.map(IpAddr::V4), probe.detected_ipv6.map(IpAddr::V6), )); - let decision = decide_network_capabilities(&config.network, &probe); + let decision = decide_network_capabilities( + &config.network, + &probe, + config.general.middle_proxy_nat_ip, + ); log_probe_result(&probe, &decision); startup_tracker .complete_component( diff --git a/src/network/probe.rs b/src/network/probe.rs index 63e23a1..cbd32d9 100644 --- a/src/network/probe.rs +++ b/src/network/probe.rs @@ -226,18 +226,24 @@ async fn probe_stun_servers_parallel( out } -pub fn decide_network_capabilities(config: &NetworkConfig, probe: &NetworkProbe) -> NetworkDecision { +pub fn decide_network_capabilities( + config: &NetworkConfig, + probe: &NetworkProbe, + middle_proxy_nat_ip: Option, +) -> NetworkDecision { let ipv4_dc = config.ipv4 && probe.detected_ipv4.is_some(); let ipv6_dc = config.ipv6.unwrap_or(probe.detected_ipv6.is_some()) && probe.detected_ipv6.is_some(); + let nat_ip_v4 = matches!(middle_proxy_nat_ip, Some(IpAddr::V4(_))); + let nat_ip_v6 = matches!(middle_proxy_nat_ip, Some(IpAddr::V6(_))); let ipv4_me = config.ipv4 && probe.detected_ipv4.is_some() - && (!probe.ipv4_is_bogon || probe.reflected_ipv4.is_some()); + && (!probe.ipv4_is_bogon || probe.reflected_ipv4.is_some() || nat_ip_v4); let ipv6_enabled = config.ipv6.unwrap_or(probe.detected_ipv6.is_some()); let ipv6_me = ipv6_enabled && probe.detected_ipv6.is_some() - && (!probe.ipv6_is_bogon || probe.reflected_ipv6.is_some()); + && (!probe.ipv6_is_bogon || probe.reflected_ipv6.is_some() || nat_ip_v6); let effective_prefer = match config.prefer { 6 if ipv6_me || ipv6_dc => 6, @@ -262,6 +268,58 @@ pub fn decide_network_capabilities(config: &NetworkConfig, probe: &NetworkProbe) } } +#[cfg(test)] +mod tests { + use super::*; + use crate::config::NetworkConfig; + + #[test] + fn manual_nat_ip_enables_ipv4_me_without_reflection() { + let config = NetworkConfig { + ipv4: true, + ..Default::default() + }; + let probe = NetworkProbe { + detected_ipv4: Some(Ipv4Addr::new(10, 0, 0, 10)), + ipv4_is_bogon: true, + ..Default::default() + }; + + let decision = decide_network_capabilities( + &config, + &probe, + Some(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4))), + ); + + assert!(decision.ipv4_me); + } + + #[test] + fn manual_nat_ip_does_not_enable_other_family() { + let config = NetworkConfig { + ipv4: true, + ipv6: Some(true), + ..Default::default() + }; + let probe = NetworkProbe { + detected_ipv4: Some(Ipv4Addr::new(10, 0, 0, 10)), + detected_ipv6: Some(Ipv6Addr::LOCALHOST), + ipv4_is_bogon: true, + ipv6_is_bogon: true, + ..Default::default() + }; + + let decision = decide_network_capabilities( + &config, + &probe, + Some(IpAddr::V4(Ipv4Addr::new(1, 2, 3, 4))), + ); + + assert!(decision.ipv4_me); + assert!(!decision.ipv6_me); + } +} + fn detect_local_ip_v4() -> Option { let socket = UdpSocket::bind("0.0.0.0:0").ok()?; socket.connect("8.8.8.8:80").ok()?; diff --git a/src/transport/middle_proxy/pool.rs b/src/transport/middle_proxy/pool.rs index 2d81e63..08ef142 100644 --- a/src/transport/middle_proxy/pool.rs +++ b/src/transport/middle_proxy/pool.rs @@ -638,9 +638,9 @@ impl MePool { } } + /// Translate the local ME address into the address material sent to the proxy. pub fn translate_our_addr(&self, addr: SocketAddr) -> SocketAddr { - let ip = self.translate_ip_for_nat(addr.ip()); - SocketAddr::new(ip, addr.port()) + self.translate_our_addr_with_reflection(addr, None) } pub fn registry(&self) -> &Arc { diff --git a/src/transport/middle_proxy/pool_nat.rs b/src/transport/middle_proxy/pool_nat.rs index 07ae0b8..b3b7bca 100644 --- a/src/transport/middle_proxy/pool_nat.rs +++ b/src/transport/middle_proxy/pool_nat.rs @@ -159,7 +159,13 @@ impl MePool { addr: std::net::SocketAddr, reflected: Option, ) -> std::net::SocketAddr { - let ip = if let Some(r) = reflected { + let ip = if let Some(nat_ip) = self.nat_ip_cfg { + match (addr.ip(), nat_ip) { + (IpAddr::V4(_), IpAddr::V4(dst)) => IpAddr::V4(dst), + (IpAddr::V6(_), IpAddr::V6(dst)) => IpAddr::V6(dst), + _ => addr.ip(), + } + } else if let Some(r) = reflected { // Use reflected IP (not port) only when local address is non-public. if is_bogon(addr.ip()) || addr.ip().is_loopback() || addr.ip().is_unspecified() { r.ip()