From c96b38f915e3f76eb291cc948b93ba38b4f829a2 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Mon, 30 Mar 2026 08:12:21 -0600 Subject: [PATCH] fix: bind echoip client to gateway's specific IPv4 to avoid EADDRINUSE Using Ipv4Addr::UNSPECIFIED (0.0.0.0) as the local address with SO_BINDTODEVICE caused bind(0.0.0.0:0) to fail with "Address in use" on interfaces where port 443 was already in use. Binding to the gateway's actual IPv4 address instead still forces IPv4 DNS filtering while avoiding the kernel-level conflict. --- core/src/net/gateway.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/core/src/net/gateway.rs b/core/src/net/gateway.rs index ee0e9b4dc..7ebcc12eb 100644 --- a/core/src/net/gateway.rs +++ b/core/src/net/gateway.rs @@ -241,11 +241,19 @@ pub async fn check_port( .await .map_or(false, |r| r.is_ok()); + let local_ipv4 = ip_info + .subnets + .iter() + .find_map(|s| match s.addr() { + IpAddr::V4(v4) => Some(v4), + _ => None, + }) + .unwrap_or(Ipv4Addr::UNSPECIFIED); let client = reqwest::Client::builder(); #[cfg(target_os = "linux")] let client = client .interface(gateway.as_str()) - .local_address(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); + .local_address(IpAddr::V4(local_ipv4)); let client = client.build()?; let mut res = None; @@ -784,12 +792,16 @@ async fn watcher( } } -async fn get_wan_ipv4(iface: &str, base_url: &Url) -> Result, Error> { +async fn get_wan_ipv4( + iface: &str, + base_url: &Url, + local_ipv4: Ipv4Addr, +) -> Result, Error> { let client = reqwest::Client::builder(); #[cfg(target_os = "linux")] let client = client .interface(iface) - .local_address(IpAddr::V4(Ipv4Addr::UNSPECIFIED)); + .local_address(IpAddr::V4(local_ipv4)); let url = base_url.join("/ip").with_kind(ErrorKind::ParseUrl)?; let text = client .build()? @@ -1412,7 +1424,14 @@ async fn poll_ip_info( Some(NetworkInterfaceType::Bridge | NetworkInterfaceType::Loopback) ) { - match get_wan_ipv4(iface.as_str(), &echoip_url).await { + let local_ipv4 = subnets + .iter() + .find_map(|s| match s.addr() { + IpAddr::V4(v4) => Some(v4), + _ => None, + }) + .unwrap_or(Ipv4Addr::UNSPECIFIED); + match get_wan_ipv4(iface.as_str(), &echoip_url, local_ipv4).await { Ok(a) => { wan_ip = a; }