diff --git a/src/libraries/Common/src/System/Net/IPEndPointExtensions.cs b/src/libraries/Common/src/System/Net/IPEndPointExtensions.cs index 0e242e592fab1e..d4a48060e3cc5b 100644 --- a/src/libraries/Common/src/System/Net/IPEndPointExtensions.cs +++ b/src/libraries/Common/src/System/Net/IPEndPointExtensions.cs @@ -17,7 +17,9 @@ public static IPAddress GetIPAddress(ReadOnlySpan socketAddressBuffer) Span address = stackalloc byte[IPAddressParserStatics.IPv6AddressBytes]; uint scope; SocketAddressPal.GetIPv6Address(socketAddressBuffer, address, out scope); - return new IPAddress(address, (long)scope); + + // Clear scope if set for anything but Link Local address (always starts with fe80 first 10bits). + return new IPAddress(address, (address[0] == 0xFE && (address[1] & 0xC0) == 0x80) ? (long)scope : 0); } else if (family == AddressFamily.InterNetwork) { diff --git a/src/libraries/Common/tests/System/Net/Configuration.Sockets.cs b/src/libraries/Common/tests/System/Net/Configuration.Sockets.cs index 0e70009e544ce1..f9f9ba1dc17e5d 100644 --- a/src/libraries/Common/tests/System/Net/Configuration.Sockets.cs +++ b/src/libraries/Common/tests/System/Net/Configuration.Sockets.cs @@ -1,15 +1,51 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Net.NetworkInformation; + namespace System.Net.Test.Common { public static partial class Configuration { public static partial class Sockets { - public static Uri SocketServer => GetUriValue("DOTNET_TEST_NET_SOCKETS_SERVERURI", new Uri("http://" + DefaultAzureServer)); + public static Uri SocketServer => GetUriValue("DOTNET_TEST_NET_SOCKETS_SERVERURI", new Uri("http://" + DefaultAzureServer)); + + public static string InvalidHost => GetValue("DOTNET_TEST_NET_SOCKETS_INVALIDSERVER", "notahostname.invalid.corp.microsoft.com"); + + public static IPAddress? LinkLocalAddress => GetIPv6LinkLocalAddress(); + + public static IEnumerable LocalAddresses() + { + if (LinkLocalAddress != null) + { + yield return new[] { LinkLocalAddress }; + } + if (Socket.OSSupportsIPv4) + { + yield return new[] { IPAddress.Loopback }; + } + if (Socket.OSSupportsIPv6) + { + yield return new[] { IPAddress.IPv6Loopback }; + } + } - public static string InvalidHost => GetValue("DOTNET_TEST_NET_SOCKETS_INVALIDSERVER", "notahostname.invalid.corp.microsoft.com"); + private static IPAddress GetIPv6LinkLocalAddress() => + NetworkInterface + .GetAllNetworkInterfaces() + .Where(i => !i.Description.StartsWith("PANGP Virtual Ethernet")) // This is a VPN adapter, but is reported as a regular Ethernet interface with + // a valid link-local address, but the link-local address doesn't actually work. + // So just manually filter it out. + .Where(i => !i.Name.Contains("Tailscale")) // Same as PANGP above. + .SelectMany(i => i.GetIPProperties().UnicastAddresses) + .Select(a => a.Address) + .Where(a => a.IsIPv6LinkLocal) + .FirstOrDefault(); } } } diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs index d92baef2828671..fe4c61a9577b6c 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.cs @@ -18,6 +18,8 @@ namespace System.Net.Http.Functional.Tests { + using Configuration = System.Net.Test.Common.Configuration; + #if WINHTTPHANDLER_TEST using HttpClientHandler = System.Net.Http.WinHttpClientHandler; #endif @@ -168,7 +170,7 @@ public async Task GetAsync_IPv6LinkLocalAddressUri_Success() using HttpClientHandler handler = CreateHttpClientHandler(allowAllCertificates: true); using HttpClient client = CreateHttpClient(handler); - var options = new GenericLoopbackOptions { Address = TestHelper.GetIPv6LinkLocalAddress() }; + var options = new GenericLoopbackOptions { Address = Configuration.Sockets.LinkLocalAddress }; if (options.Address == null) { throw new SkipTestException("Unable to find valid IPv6 LL address."); diff --git a/src/libraries/Common/tests/System/Net/Http/TestHelper.cs b/src/libraries/Common/tests/System/Net/Http/TestHelper.cs index 1866f6a26cd115..c1d7a047070e6c 100644 --- a/src/libraries/Common/tests/System/Net/Http/TestHelper.cs +++ b/src/libraries/Common/tests/System/Net/Http/TestHelper.cs @@ -2,8 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Linq; -using System.Net.NetworkInformation; using System.Net.Security; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; @@ -104,18 +102,6 @@ public static Task WhenAllCompletedOrAnyFailedWithTimeout(int timeoutInMilliseco public static Func AllowAllCertificates = (_, __, ___, ____) => true; #endif - public static IPAddress GetIPv6LinkLocalAddress() => - NetworkInterface - .GetAllNetworkInterfaces() - .Where(i => !i.Description.StartsWith("PANGP Virtual Ethernet")) // This is a VPN adapter, but is reported as a regular Ethernet interface with - // a valid link-local address, but the link-local address doesn't actually work. - // So just manually filter it out. - .Where(i => !i.Name.Contains("Tailscale")) // Same as PANGP above. - .SelectMany(i => i.GetIPProperties().UnicastAddresses) - .Select(a => a.Address) - .Where(a => a.IsIPv6LinkLocal) - .FirstOrDefault(); - public static byte[] GenerateRandomContent(int size) { byte[] data = new byte[size]; diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs index 87775923829108..ce7500c0e2fbc2 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; -using System.Net; using System.Net.Sockets; -using System.Net.Test.Common; using System.Threading.Tasks; - +using Microsoft.DotNet.XUnitExtensions; using Xunit; using Xunit.Abstractions; diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs index 14b5d9ffaf1d1f..dcb12e8b7f87b0 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs @@ -304,5 +304,28 @@ public async Task NetworkInterface_LoopbackInterfaceIndex_MatchesReceivedPackets ipv6 ? NetworkInterface.IPv6LoopbackInterfaceIndex : NetworkInterface.LoopbackInterfaceIndex); } } + + [ConditionalFact] + public void NetworkInterface_UnicastLLA_ScopeIdSet() + { + bool foundLla = false; + foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) + { + IPInterfaceProperties prop = nic.GetIPProperties(); + foreach (UnicastIPAddressInformation info in prop.UnicastAddresses) + { + if (info.Address.IsIPv6LinkLocal) + { + foundLla = true; + Assert.NotEqual(0, info.Address.ScopeId); + } + } + } + + if (!foundLla) + { + throw new SkipTestException("Did not find any LLA"); + } + } } } diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs index 6d04d3df863d9a..dba45d813945ff 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/QuicConnectionTests.cs @@ -12,20 +12,23 @@ namespace System.Net.Quic.Tests { + using Configuration = System.Net.Test.Common.Configuration; + [Collection(nameof(DisableParallelization))] [ConditionalClass(typeof(QuicTestBase), nameof(QuicTestBase.IsSupported))] public sealed class QuicConnectionTests : QuicTestBase { const int ExpectedErrorCode = 1234; + public static IEnumerable LocalAddresses = Configuration.Sockets.LocalAddresses(); public QuicConnectionTests(ITestOutputHelper output) : base(output) { } [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task TestConnect(bool ipv6) + [MemberData(nameof(LocalAddresses))] + public async Task TestConnect(IPAddress address) { - await using QuicListener listener = await CreateQuicListener(ipv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback); + await using QuicListener listener = await CreateQuicListener(address); + Assert.Equal(address, listener.LocalEndPoint.Address); var options = CreateQuicClientOptions(listener.LocalEndPoint); ValueTask connectTask = CreateQuicConnection(options); @@ -35,27 +38,19 @@ public async Task TestConnect(bool ipv6) await using QuicConnection serverConnection = acceptTask.Result; await using QuicConnection clientConnection = connectTask.Result; - IgnoreScopeIdIPEndpointComparer endPointComparer = new(); - Assert.Equal(listener.LocalEndPoint, serverConnection.LocalEndPoint, endPointComparer); - Assert.Equal(listener.LocalEndPoint, clientConnection.RemoteEndPoint, endPointComparer); - Assert.Equal(clientConnection.LocalEndPoint, serverConnection.RemoteEndPoint, endPointComparer); + Assert.Equal(listener.LocalEndPoint, serverConnection.LocalEndPoint); + Assert.Equal(listener.LocalEndPoint, clientConnection.RemoteEndPoint); + if (PlatformDetection.IsWindows && address.IsIPv6LinkLocal) + { + // https://github.com/microsoft/msquic/issues/3813 + Assert.Equal(clientConnection.LocalEndPoint, serverConnection.RemoteEndPoint); + } Assert.Equal(ApplicationProtocol.ToString(), clientConnection.NegotiatedApplicationProtocol.ToString()); Assert.Equal(ApplicationProtocol.ToString(), serverConnection.NegotiatedApplicationProtocol.ToString()); Assert.Equal(options.ClientAuthenticationOptions.TargetHost, clientConnection.TargetHostName); Assert.Equal(options.ClientAuthenticationOptions.TargetHost, serverConnection.TargetHostName); } - private class IgnoreScopeIdIPEndpointComparer : IEqualityComparer - { - public bool Equals(IPEndPoint x, IPEndPoint y) - { - byte[] xBytes = x.Address.GetAddressBytes(); - byte[] yBytes = y.Address.GetAddressBytes(); - return xBytes.AsSpan().SequenceEqual(yBytes) && x.Port == y.Port; - } - public int GetHashCode([DisallowNull] IPEndPoint obj) => obj.Port; - } - private static async Task OpenAndUseStreamAsync(QuicConnection c) { QuicStream s = await c.OpenOutboundStreamAsync(QuicStreamType.Bidirectional); diff --git a/src/libraries/System.Net.Quic/tests/FunctionalTests/System.Net.Quic.Functional.Tests.csproj b/src/libraries/System.Net.Quic/tests/FunctionalTests/System.Net.Quic.Functional.Tests.csproj index 55ddd30f86abbb..67faecde3b4c9f 100644 --- a/src/libraries/System.Net.Quic/tests/FunctionalTests/System.Net.Quic.Functional.Tests.csproj +++ b/src/libraries/System.Net.Quic/tests/FunctionalTests/System.Net.Quic.Functional.Tests.csproj @@ -24,6 +24,7 @@ +