From c1a3569da707fe316db29c3e8f8dc1f9047584e0 Mon Sep 17 00:00:00 2001 From: zhangyh <717572325@qq.com> Date: Wed, 15 Oct 2025 16:29:22 +0800 Subject: [PATCH 1/6] Include IPv4 link-local addresses in the regular field --- netwatch/src/ip.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/netwatch/src/ip.rs b/netwatch/src/ip.rs index 2580aae..0d97078 100644 --- a/netwatch/src/ip.rs +++ b/netwatch/src/ip.rs @@ -83,15 +83,8 @@ impl LocalAddresses { } } - if regular4.is_empty() && regular6.is_empty() { - // if we have no usable IP addresses then be willing to accept - // addresses we otherwise wouldn't, like: - // + 169.254.x.x (AWS Lambda uses NAT with these) - // + IPv6 ULA (Google Cloud Run uses these with address translation) - regular4 = linklocal4; - regular6 = ula6; - } let mut regular = regular4; + regular.extend(linklocal4); regular.extend(regular6); regular.sort(); From 09d215aad26378c855498a32198e97be4c7a0610 Mon Sep 17 00:00:00 2001 From: zhangyh <717572325@qq.com> Date: Thu, 16 Oct 2025 09:49:46 +0800 Subject: [PATCH 2/6] use chain to combine extend operations --- netwatch/src/ip.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/netwatch/src/ip.rs b/netwatch/src/ip.rs index 0d97078..a892e2c 100644 --- a/netwatch/src/ip.rs +++ b/netwatch/src/ip.rs @@ -84,8 +84,7 @@ impl LocalAddresses { } let mut regular = regular4; - regular.extend(linklocal4); - regular.extend(regular6); + regular.extend(linklocal4.into_iter().chain(regular6)); regular.sort(); loopback.sort(); From 5f367fe81fea940f3b18ceb08ec63a1f2dc122fc Mon Sep 17 00:00:00 2001 From: zhangyh <717572325@qq.com> Date: Thu, 16 Oct 2025 10:16:35 +0800 Subject: [PATCH 3/6] update comments --- netwatch/src/ip.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netwatch/src/ip.rs b/netwatch/src/ip.rs index a892e2c..cd2e6ca 100644 --- a/netwatch/src/ip.rs +++ b/netwatch/src/ip.rs @@ -29,8 +29,8 @@ impl Default for LocalAddresses { #[cfg(not(wasm_browser))] impl LocalAddresses { /// Returns the machine's IP addresses. - /// If there are no regular addresses it will return any IPv4 linklocal or IPv6 unique local - /// addresses because we know of environments where these are used with NAT to provide connectivity. + /// Regular includes all non-loopback IPv4 (including link-local). + /// IPv6 link-local and unique local are excluded from regular. pub fn new() -> Self { let ifaces = netdev::interface::get_interfaces(); Self::from_raw_interfaces(&ifaces) From 879c4c6f2d3f4892520429dedeaf02cc10915853 Mon Sep 17 00:00:00 2001 From: zhangyh <717572325@qq.com> Date: Tue, 3 Mar 2026 01:45:28 +0000 Subject: [PATCH 4/6] add link_local field to LocalAddresses --- netwatch/src/ip.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/netwatch/src/ip.rs b/netwatch/src/ip.rs index cd2e6ca..f630c2c 100644 --- a/netwatch/src/ip.rs +++ b/netwatch/src/ip.rs @@ -17,6 +17,8 @@ pub struct LocalAddresses { pub loopback: Vec, /// Regular addresses. pub regular: Vec, + /// Link-local addresses (e.g. 169.254.x.x). + pub link_local: Vec, } #[cfg(not(wasm_browser))] @@ -29,8 +31,8 @@ impl Default for LocalAddresses { #[cfg(not(wasm_browser))] impl LocalAddresses { /// Returns the machine's IP addresses. - /// Regular includes all non-loopback IPv4 (including link-local). - /// IPv6 link-local and unique local are excluded from regular. + /// If there are no regular addresses it will return any IPv4 linklocal or IPv6 unique local + /// addresses because we know of environments where these are used with NAT to provide connectivity. pub fn new() -> Self { let ifaces = netdev::interface::get_interfaces(); Self::from_raw_interfaces(&ifaces) @@ -83,13 +85,28 @@ impl LocalAddresses { } } + let mut link_local = linklocal4.clone(); + + if regular4.is_empty() && regular6.is_empty() { + // if we have no usable IP addresses then be willing to accept + // addresses we otherwise wouldn't, like: + // + 169.254.x.x (AWS Lambda uses NAT with these) + // + IPv6 ULA (Google Cloud Run uses these with address translation) + regular4 = linklocal4; + regular6 = ula6; + } let mut regular = regular4; - regular.extend(linklocal4.into_iter().chain(regular6)); + regular.extend(regular6); regular.sort(); loopback.sort(); + link_local.sort(); - LocalAddresses { loopback, regular } + LocalAddresses { + loopback, + regular, + link_local, + } } } From afb7c791a77a02191095ead287ac912dabcaf9e7 Mon Sep 17 00:00:00 2001 From: zhangyh <717572325@qq.com> Date: Tue, 3 Mar 2026 01:51:27 +0000 Subject: [PATCH 5/6] separate link-local from regular addresses --- netwatch/src/ip.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/netwatch/src/ip.rs b/netwatch/src/ip.rs index f630c2c..d3766b9 100644 --- a/netwatch/src/ip.rs +++ b/netwatch/src/ip.rs @@ -85,14 +85,12 @@ impl LocalAddresses { } } - let mut link_local = linklocal4.clone(); + let mut link_local = linklocal4; if regular4.is_empty() && regular6.is_empty() { // if we have no usable IP addresses then be willing to accept // addresses we otherwise wouldn't, like: - // + 169.254.x.x (AWS Lambda uses NAT with these) // + IPv6 ULA (Google Cloud Run uses these with address translation) - regular4 = linklocal4; regular6 = ula6; } let mut regular = regular4; From 7678d9c4910226fc77325852cf16d4ac443a83e1 Mon Sep 17 00:00:00 2001 From: zhangyh <717572325@qq.com> Date: Tue, 3 Mar 2026 09:20:18 +0000 Subject: [PATCH 6/6] include IPv6 link-local addresses in link_local field --- netwatch/src/ip.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/netwatch/src/ip.rs b/netwatch/src/ip.rs index d3766b9..70ada2f 100644 --- a/netwatch/src/ip.rs +++ b/netwatch/src/ip.rs @@ -17,7 +17,7 @@ pub struct LocalAddresses { pub loopback: Vec, /// Regular addresses. pub regular: Vec, - /// Link-local addresses (e.g. 169.254.x.x). + /// Link-local addresses pub link_local: Vec, } @@ -43,6 +43,7 @@ impl LocalAddresses { let mut regular4 = Vec::new(); let mut regular6 = Vec::new(); let mut linklocal4 = Vec::new(); + let mut linklocal6 = Vec::new(); let mut ula6 = Vec::new(); for iface in ifaces { @@ -65,14 +66,9 @@ impl LocalAddresses { } else if is_link_local(ip) { if ip.is_ipv4() { linklocal4.push(ip); + } else { + linklocal6.push(ip); } - - // We know of no cases where the IPv6 fe80:: addresses - // are used to provide WAN connectivity. It is also very - // common for users to have no IPv6 WAN connectivity, - // but their OS supports IPv6 so they have an fe80:: - // address. We don't want to report all of those - // IPv6 LL to Control. } else if ip.is_ipv6() && is_private(&ip) { // Google Cloud Run uses NAT with IPv6 Unique // Local Addresses to provide IPv6 connectivity. @@ -86,6 +82,7 @@ impl LocalAddresses { } let mut link_local = linklocal4; + link_local.extend(linklocal6); if regular4.is_empty() && regular6.is_empty() { // if we have no usable IP addresses then be willing to accept