Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose a global switch to disable IPV6 #55012

Merged
merged 8 commits into from
Jul 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,8 @@

namespace System.Net
{
internal static class SocketProtocolSupportPal
internal static partial class SocketProtocolSupportPal
{
public static bool OSSupportsIPv6 { get; } = IsSupported(AddressFamily.InterNetworkV6);
public static bool OSSupportsIPv4 { get; } = IsSupported(AddressFamily.InterNetwork);
public static bool OSSupportsUnixDomainSockets { get; } = IsSupported(AddressFamily.Unix);

private static unsafe bool IsSupported(AddressFamily af)
{
IntPtr invalid = (IntPtr)(-1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,8 @@

namespace System.Net
{
internal static class SocketProtocolSupportPal
internal static partial class SocketProtocolSupportPal
{
public static bool OSSupportsIPv6 { get; } = IsSupported(AddressFamily.InterNetworkV6);
public static bool OSSupportsIPv4 { get; } = IsSupported(AddressFamily.InterNetwork);
public static bool OSSupportsUnixDomainSockets { get; } = IsSupported(AddressFamily.Unix);

private static bool IsSupported(AddressFamily af)
{
Interop.Winsock.EnsureInitialized();
Expand Down
36 changes: 36 additions & 0 deletions src/libraries/Common/src/System/Net/SocketProtocolSupportPal.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Net.Sockets;

namespace System.Net
{
internal static partial class SocketProtocolSupportPal
{
private const string DisableIPv6AppCtxSwitch = "System.Net.DisableIPv6";
private const string DisableIPv6EnvironmentVariable = "DOTNET_SYSTEM_NET_DISABLEIPV6";

public static bool OSSupportsIPv6 { get; } = IsSupported(AddressFamily.InterNetworkV6) && !IsIPv6Disabled();
public static bool OSSupportsIPv4 { get; } = IsSupported(AddressFamily.InterNetwork);
public static bool OSSupportsUnixDomainSockets { get; } = IsSupported(AddressFamily.Unix);

private static bool IsIPv6Disabled()
{
// First check for the AppContext switch, giving it priority over the environment variable.
if (AppContext.TryGetSwitch(DisableIPv6AppCtxSwitch, out bool disabled))
{
return disabled;
}

// AppContext switch wasn't used. Check the environment variable.
string? envVar = Environment.GetEnvironmentVariable(DisableIPv6EnvironmentVariable);

if (envVar is not null)
{
return envVar == "1" || envVar.Equals("true", StringComparison.OrdinalIgnoreCase);
}

return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
Link="Common\System\Net\IPAddressParserStatics.cs" />
<Compile Include="$(CommonPath)System\Net\IPEndPointStatics.cs"
Link="Common\System\Net\IPEndPointStatics.cs" />
<Compile Include="$(CommonPath)System\Net\SocketProtocolSupportPal.cs"
Link="Common\System\Net\SocketProtocolSupportPal.cs" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetsWindows)' == 'true'">
<Compile Include="System\Net\NameResolutionPal.Windows.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ private static unsafe void ParseHostEntry(Interop.Sys.HostEntry hostEntry, bool
Interop.Sys.IPAddress* addressHandle = hostEntry.IPAddressList;
for (int i = 0; i < hostEntry.IPAddressCount; i++)
{
if (Array.IndexOf(nativeAddresses, addressHandle[i], 0, nativeAddressCount) == -1)
Interop.Sys.IPAddress nativeAddr = addressHandle[i];
if (Array.IndexOf(nativeAddresses, nativeAddr, 0, nativeAddressCount) == -1 &&
(!nativeAddr.IsIPv6 || SocketProtocolSupportPal.OSSupportsIPv6)) // Do not include IPv6 addresses if IPV6 support is force-disabled
{
nativeAddresses[nativeAddressCount++] = addressHandle[i];
nativeAddresses[nativeAddressCount++] = nativeAddr;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.DotNet.RemoteExecutor;
using Microsoft.DotNet.XUnitExtensions;
using Xunit;

Expand All @@ -21,9 +21,16 @@ public async Task Dns_GetHostEntryAsync_IPAddress_Ok()
await TestGetHostEntryAsync(() => Dns.GetHostEntryAsync(localIPAddress));
}

[ActiveIssue("https://github.com/dotnet/runtime/issues/1488", TestPlatforms.OSX)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/51377", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotArm64Process))] // [ActiveIssue("https://github.com/dotnet/runtime/issues/27622")]

public static bool GetHostEntryWorks =
// [ActiveIssue("https://github.com/dotnet/runtime/issues/27622")]
PlatformDetection.IsNotArmNorArm64Process &&
// [ActiveIssue("https://github.com/dotnet/runtime/issues/1488", TestPlatforms.OSX)]
PlatformDetection.IsNotOSX &&
// [ActiveIssue("https://github.com/dotnet/runtime/issues/51377", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
!PlatformDetection.IsiOS && !PlatformDetection.IstvOS && !PlatformDetection.IsMacCatalyst;

[ConditionalTheory(nameof(GetHostEntryWorks))]
[InlineData("")]
[InlineData(TestSettings.LocalHost)]
public async Task Dns_GetHostEntry_HostString_Ok(string hostName)
Expand Down Expand Up @@ -77,12 +84,10 @@ public async Task Dns_GetHostEntry_HostString_Ok(string hostName)
}
}

[ActiveIssue("https://github.com/dotnet/runtime/issues/1488", TestPlatforms.OSX)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/51377", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotArm64Process))] // [ActiveIssue("https://github.com/dotnet/runtime/issues/27622")]
[ConditionalTheory(nameof(GetHostEntryWorks))]
[InlineData("")]
[InlineData(TestSettings.LocalHost)]
public async Task Dns_GetHostEntryAsync_HostString_Ok(string hostName)
public async Task Dns_GetHostEntryAsync_HostString_Ok(string hostName)
{
if (PlatformDetection.IsSLES)
{
Expand Down Expand Up @@ -112,6 +117,44 @@ private static async Task TestGetHostEntryAsync(Func<Task<IPHostEntry>> getHostE
Assert.Equal<IPAddress>(list1, list2);
}

public static bool GetHostEntry_DisableIPv6_Condition = GetHostEntryWorks && RemoteExecutor.IsSupported;

[ConditionalTheory(nameof(GetHostEntry_DisableIPv6_Condition))]
[InlineData("")]
[InlineData(TestSettings.LocalHost)]
public void Dns_GetHostEntry_DisableIPv6_ExcludesIPv6Addresses(string hostnameOuter)
{
RemoteExecutor.Invoke(RunTest, hostnameOuter).Dispose();

static void RunTest(string hostnameInner)
{
AppContext.SetSwitch("System.Net.DisableIPv6", true);
IPHostEntry entry = Dns.GetHostEntry(hostnameInner);
foreach (IPAddress address in entry.AddressList)
{
Assert.NotEqual(AddressFamily.InterNetworkV6, address.AddressFamily);
}
}
}

[ConditionalTheory(nameof(GetHostEntry_DisableIPv6_Condition))]
[InlineData("")]
[InlineData(TestSettings.LocalHost)]
public void Dns_GetHostEntryAsync_DisableIPv6_ExcludesIPv6Addresses(string hostnameOuter)
{
RemoteExecutor.Invoke(RunTest, hostnameOuter).Dispose();

static async Task RunTest(string hostnameInner)
{
AppContext.SetSwitch("System.Net.DisableIPv6", true);
IPHostEntry entry = await Dns.GetHostEntryAsync(hostnameInner);
foreach (IPAddress address in entry.AddressList)
{
Assert.NotEqual(AddressFamily.InterNetworkV6, address.AddressFamily);
}
}
}

[Fact]
public async Task Dns_GetHostEntry_NullStringHost_Fail()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
Link="Common\System\Net\IPEndPointStatics.cs" />
<Compile Include="$(CommonPath)System\Net\IPAddressParserStatics.cs"
Link="Common\System\Net\IPAddressParserStatics.cs" />
<Compile Include="$(CommonPath)System\Net\SocketProtocolSupportPal.cs"
Link="Common\System\Net\SocketProtocolSupportPal.cs" />
<Compile Include="$(CommonTestPath)System\Net\Configuration.cs"
Link="Common\System\Net\Configuration.cs" />
<Compile Include="$(CommonTestPath)System\Net\Configuration.Http.cs"
Expand Down
2 changes: 2 additions & 0 deletions src/libraries/System.Net.Ping/src/System.Net.Ping.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
Link="Common\System\Net\IPAddressParserStatics.cs" />
<Compile Include="$(CommonPath)System\Net\SocketAddress.cs"
Link="Common\System\Net\SocketAddress.cs" />
<Compile Include="$(CommonPath)System\Net\SocketProtocolSupportPal.cs"
Link="Common\System\Net\SocketProtocolSupportPal.cs" />
<!-- Logging -->
<Compile Include="$(CommonPath)System\Net\Logging\NetEventSource.Common.cs"
Link="Common\System\Net\Logging\NetEventSource.Common.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
Link="Common\System\Net\SocketAddress.cs" />
<Compile Include="$(CommonPath)System\Net\TcpValidationHelpers.cs"
Link="Common\System\Net\TcpValidationHelpers.cs" />
<Compile Include="$(CommonPath)System\Net\SocketProtocolSupportPal.cs"
Link="Common\System\Net\SocketProtocolSupportPal.cs" />
<Compile Include="$(CommonPath)System\Threading\Tasks\TaskToApm.cs"
Link="Common\System\Threading\Tasks\TaskToApm.cs" />
<!-- System.Net.Internals -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@


using System.Threading;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;

namespace System.Net.Sockets.Tests
Expand All @@ -25,6 +26,37 @@ public void SupportsIPv6_MatchesOSSupportsIPv6()
#pragma warning restore
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void DisableIPv6_OSSupportsIPv6_False()
{
RemoteInvokeOptions options = new RemoteInvokeOptions();
options.StartInfo.EnvironmentVariables["DOTNET_SYSTEM_NET_DISABLEIPV6"] = "1";
RemoteExecutor.Invoke(RunTest, options).Dispose();

static void RunTest()
{
Assert.False(Socket.OSSupportsIPv6);
}
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void DisableIPv6_SocketConstructor_CreatesIPv4Socket()
{
RemoteExecutor.Invoke(RunTest).Dispose();

static void RunTest()
{
AppContext.SetSwitch("System.Net.DisableIPv6", true);
using Socket socket1 = new Socket(SocketType.Stream, ProtocolType.Tcp);
using Socket socket2 = new Socket(SocketType.Dgram, ProtocolType.Udp);

Assert.Equal(AddressFamily.InterNetwork, socket1.AddressFamily);
Assert.Equal(AddressFamily.InterNetwork, socket2.AddressFamily);
Assert.False(socket1.DualMode);
Assert.False(socket2.DualMode);
}
}

[Fact]
public void IOControl_FIONREAD_Success()
{
Expand Down