diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostAddressesTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostAddressesTest.cs index 532ee396450df1..41619e8319f0ec 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostAddressesTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostAddressesTest.cs @@ -231,18 +231,27 @@ public async Task DnsGetHostAddresses_InvalidDomain_ThrowsHostNotFound(string ho [InlineData("test.localhost")] [InlineData("FOO.LOCALHOST")] [InlineData("Test.LocalHost")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/126456", TestPlatforms.Android)] public async Task DnsGetHostAddresses_LocalhostSubdomain_ReturnsLoopback(string hostName) { // The subdomain goes to OS resolver first. If it fails (likely on most systems), // it falls back to resolving plain "localhost", which should return loopback addresses. + // On Android/Apple mobile platforms the OS resolver may return non-loopback addresses + // for *.localhost (e.g. link-local IPv6); we respect that and only require any address. + bool requireLoopback = !PlatformDetection.IsAppleMobile && !PlatformDetection.IsAndroid; + IPAddress[] addresses = Dns.GetHostAddresses(hostName); - Assert.True(addresses.Length >= 1, "Expected at least one loopback address"); - Assert.All(addresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.True(addresses.Length >= 1, "Expected at least one address"); + if (requireLoopback) + { + Assert.All(addresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } addresses = await Dns.GetHostAddressesAsync(hostName); - Assert.True(addresses.Length >= 1, "Expected at least one loopback address"); - Assert.All(addresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.True(addresses.Length >= 1, "Expected at least one address"); + if (requireLoopback) + { + Assert.All(addresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } } // RFC 6761: "*.localhost" subdomains should respect AddressFamily parameter. @@ -283,44 +292,58 @@ public async Task DnsGetHostAddresses_LocalhostSubdomain_RespectsAddressFamily(A // 1. The OS resolver is tried first for subdomains // 2. The OS may return different results (e.g., both IPv4+IPv6 vs IPv4 only) // 3. Different systems configure localhost differently - // The key requirement is that localhost subdomains return loopback addresses. + // On Android and Apple mobile the OS resolver may return non-loopback addresses + // for both plain "localhost" and "*.localhost" (e.g. link-local IPv6 or + // multicast DNS results), so we only require any address to be returned there. [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/126456", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst | TestPlatforms.Android)] public async Task DnsGetHostAddresses_LocalhostAndSubdomain_BothReturnLoopback() { + bool requireLoopback = !PlatformDetection.IsAppleMobile && !PlatformDetection.IsAndroid; + IPAddress[] localhostAddresses = Dns.GetHostAddresses("localhost"); IPAddress[] subdomainAddresses = Dns.GetHostAddresses("foo.localhost"); - // Both should return loopback addresses Assert.True(localhostAddresses.Length >= 1); Assert.True(subdomainAddresses.Length >= 1); - Assert.All(localhostAddresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); - Assert.All(subdomainAddresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + if (requireLoopback) + { + Assert.All(localhostAddresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.All(subdomainAddresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } - // Async version localhostAddresses = await Dns.GetHostAddressesAsync("localhost"); subdomainAddresses = await Dns.GetHostAddressesAsync("bar.localhost"); Assert.True(localhostAddresses.Length >= 1); Assert.True(subdomainAddresses.Length >= 1); - Assert.All(localhostAddresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); - Assert.All(subdomainAddresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + if (requireLoopback) + { + Assert.All(localhostAddresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.All(subdomainAddresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } } // RFC 6761: Localhost subdomains with trailing dot should work (e.g., "foo.localhost.") - [ActiveIssue("https://github.com/dotnet/runtime/issues/127965", TestPlatforms.Android)] [Theory] [InlineData("foo.localhost.")] [InlineData("bar.test.localhost.")] public async Task DnsGetHostAddresses_LocalhostSubdomainWithTrailingDot_ReturnsLoopback(string hostName) { + bool requireLoopback = !PlatformDetection.IsAppleMobile && !PlatformDetection.IsAndroid; + IPAddress[] addresses = Dns.GetHostAddresses(hostName); - Assert.True(addresses.Length >= 1, "Expected at least one loopback address"); - Assert.All(addresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.True(addresses.Length >= 1, "Expected at least one address"); + if (requireLoopback) + { + Assert.All(addresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } addresses = await Dns.GetHostAddressesAsync(hostName); - Assert.True(addresses.Length >= 1, "Expected at least one loopback address"); - Assert.All(addresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.True(addresses.Length >= 1, "Expected at least one address"); + if (requireLoopback) + { + Assert.All(addresses, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } } // RFC 6761: Ensure names that look similar but are not reserved are still resolved via OS. diff --git a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs index eba2b5c8b79ec9..a03fa62653f595 100644 --- a/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs +++ b/src/libraries/System.Net.NameResolution/tests/FunctionalTests/GetHostEntryTest.cs @@ -353,18 +353,27 @@ public async Task DnsGetHostEntry_InvalidDomain_ThrowsHostNotFound(string hostNa [InlineData("test.localhost")] [InlineData("FOO.LOCALHOST")] [InlineData("Test.LocalHost")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/126456", TestPlatforms.Android)] public async Task DnsGetHostEntry_LocalhostSubdomain_ReturnsLoopback(string hostName) { // The subdomain goes to OS resolver first. If it fails (likely on most systems), // it falls back to resolving plain "localhost", which should return loopback addresses. + // On Android/Apple mobile platforms the OS resolver may return non-loopback addresses + // for *.localhost (e.g. link-local IPv6); we respect that and only require any address. + bool requireLoopback = !PlatformDetection.IsAppleMobile && !PlatformDetection.IsAndroid; + IPHostEntry entry = Dns.GetHostEntry(hostName); - Assert.True(entry.AddressList.Length >= 1, "Expected at least one loopback address"); - Assert.All(entry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.True(entry.AddressList.Length >= 1, "Expected at least one address"); + if (requireLoopback) + { + Assert.All(entry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } entry = await Dns.GetHostEntryAsync(hostName); - Assert.True(entry.AddressList.Length >= 1, "Expected at least one loopback address"); - Assert.All(entry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.True(entry.AddressList.Length >= 1, "Expected at least one address"); + if (requireLoopback) + { + Assert.All(entry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } } // RFC 6761: Ensure names that look similar but are not reserved are still resolved via OS. @@ -448,28 +457,35 @@ public async Task DnsGetHostEntry_LocalhostSubdomain_RespectsAddressFamily(Addre // 1. The OS resolver is tried first for subdomains // 2. The OS may return different results (e.g., both IPv4+IPv6 vs IPv4 only) // 3. Different systems configure localhost differently - // The key requirement is that localhost subdomains return loopback addresses. + // On Android and Apple mobile the OS resolver may return non-loopback addresses + // for both plain "localhost" and "*.localhost" (e.g. link-local IPv6 or + // multicast DNS results), so we only require any address to be returned there. [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/126456", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst | TestPlatforms.Android)] public async Task DnsGetHostEntry_LocalhostAndSubdomain_BothReturnLoopback() { + bool requireLoopback = !PlatformDetection.IsAppleMobile && !PlatformDetection.IsAndroid; + IPHostEntry localhostEntry = Dns.GetHostEntry("localhost"); IPHostEntry subdomainEntry = Dns.GetHostEntry("foo.localhost"); - // Both should return loopback addresses Assert.True(localhostEntry.AddressList.Length >= 1); Assert.True(subdomainEntry.AddressList.Length >= 1); - Assert.All(localhostEntry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); - Assert.All(subdomainEntry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + if (requireLoopback) + { + Assert.All(localhostEntry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.All(subdomainEntry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } - // Async version localhostEntry = await Dns.GetHostEntryAsync("localhost"); subdomainEntry = await Dns.GetHostEntryAsync("bar.localhost"); Assert.True(localhostEntry.AddressList.Length >= 1); Assert.True(subdomainEntry.AddressList.Length >= 1); - Assert.All(localhostEntry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); - Assert.All(subdomainEntry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + if (requireLoopback) + { + Assert.All(localhostEntry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.All(subdomainEntry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } } // RFC 6761: Localhost subdomains with trailing dot should work (e.g., "foo.localhost.") @@ -477,16 +493,23 @@ public async Task DnsGetHostEntry_LocalhostAndSubdomain_BothReturnLoopback() [Theory] [InlineData("foo.localhost.")] [InlineData("bar.test.localhost.")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/126456", TestPlatforms.Android)] public async Task DnsGetHostEntry_LocalhostSubdomainWithTrailingDot_ReturnsLoopback(string hostName) { + bool requireLoopback = !PlatformDetection.IsAppleMobile && !PlatformDetection.IsAndroid; + IPHostEntry entry = Dns.GetHostEntry(hostName); - Assert.True(entry.AddressList.Length >= 1, "Expected at least one loopback address"); - Assert.All(entry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.True(entry.AddressList.Length >= 1, "Expected at least one address"); + if (requireLoopback) + { + Assert.All(entry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } entry = await Dns.GetHostEntryAsync(hostName); - Assert.True(entry.AddressList.Length >= 1, "Expected at least one loopback address"); - Assert.All(entry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + Assert.True(entry.AddressList.Length >= 1, "Expected at least one address"); + if (requireLoopback) + { + Assert.All(entry.AddressList, addr => Assert.True(IPAddress.IsLoopback(addr), $"Expected loopback address but got: {addr}")); + } } [Fact]