From 0a4eb5ce4ab91cbd6e22745d5d9571f0394fabde Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 13 Feb 2019 02:24:51 +0300 Subject: [PATCH 01/14] Handle interface names in ipv6 addresses (link-local) --- .../Interop.GetNativeIPInterfaceIndex.cs | 15 +++++++++++++++ .../Windows/Interop.GetNativeIPInterfaceIndex.cs | 14 ++++++++++++++ .../src/System/Net/IPv6AddressHelper.Common.cs | 10 ++++------ .../Unix/System.Native/pal_networkstatistics.c | 6 ++++++ .../Unix/System.Native/pal_networkstatistics.h | 2 ++ .../src/System.Net.Primitives.csproj | 6 ++++++ .../src/System/Net/IPAddressParser.cs | 11 ++++++----- .../tests/FunctionalTests/IPAddressParsing.cs | 2 ++ 8 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 src/Common/src/Interop/Unix/System.Native/Interop.GetNativeIPInterfaceIndex.cs create mode 100644 src/Common/src/Interop/Windows/Interop.GetNativeIPInterfaceIndex.cs diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.GetNativeIPInterfaceIndex.cs b/src/Common/src/Interop/Unix/System.Native/Interop.GetNativeIPInterfaceIndex.cs new file mode 100644 index 000000000000..2a44ee27c34b --- /dev/null +++ b/src/Common/src/Interop/Unix/System.Native/Interop.GetNativeIPInterfaceIndex.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Sys + { + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetNativeIPInterfaceIndex")] + public static extern unsafe uint GetNativeIPInterfaceIndex(string name); + } +} diff --git a/src/Common/src/Interop/Windows/Interop.GetNativeIPInterfaceIndex.cs b/src/Common/src/Interop/Windows/Interop.GetNativeIPInterfaceIndex.cs new file mode 100644 index 000000000000..cf40993d38f6 --- /dev/null +++ b/src/Common/src/Interop/Windows/Interop.GetNativeIPInterfaceIndex.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Sys + { + public static uint GetNativeIPInterfaceIndex(string name) => 0; //TODO: um.. where should I put `if_nametoindex` for Windows (available since Vista) + } +} diff --git a/src/Common/src/System/Net/IPv6AddressHelper.Common.cs b/src/Common/src/System/Net/IPv6AddressHelper.Common.cs index beb5e867eae5..906e9c1e6290 100644 --- a/src/Common/src/System/Net/IPv6AddressHelper.Common.cs +++ b/src/Common/src/System/Net/IPv6AddressHelper.Common.cs @@ -143,11 +143,6 @@ internal unsafe static bool IsValidStrict(char* name, int start, ref int end) { goto case '/'; } - else if (name[i] < '0' || name[i] > '9') - { - // scope ID must only contain digits - return false; - } } break; case ']': @@ -307,7 +302,10 @@ internal static unsafe void Parse(ReadOnlySpan address, ushort* numbers, i for (++i; i < address.Length && address[i] != ']' && address[i] != '/'; ++i) { } - scopeId = new string(address.Slice(start, i - start)); + if (i - start > 0) + scopeId = new string(address.Slice(start + 1, i - start)); // + 1 to ignore '%' + else + scopeId = string.Empty; // ignore prefix if any for (; i < address.Length && address[i] != ']'; ++i) { diff --git a/src/Native/Unix/System.Native/pal_networkstatistics.c b/src/Native/Unix/System.Native/pal_networkstatistics.c index d5feba971f8c..2667cee5bec5 100644 --- a/src/Native/Unix/System.Native/pal_networkstatistics.c +++ b/src/Native/Unix/System.Native/pal_networkstatistics.c @@ -437,6 +437,12 @@ int32_t SystemNative_GetActiveUdpListeners(IPEndPointInfo* infos, int32_t* infoC return 0; } +uint32_t SystemNative_GetNativeIPInterfaceIndex(char* interfaceName) +{ + assert(interfaceName != NULL); + return if_nametoindex(interfaceName); +} + int32_t SystemNative_GetNativeIPInterfaceStatistics(char* interfaceName, NativeIPInterfaceStatistics* retStats) { assert(interfaceName != NULL && retStats != NULL); diff --git a/src/Native/Unix/System.Native/pal_networkstatistics.h b/src/Native/Unix/System.Native/pal_networkstatistics.h index 743415259714..67fcb4a87052 100644 --- a/src/Native/Unix/System.Native/pal_networkstatistics.h +++ b/src/Native/Unix/System.Native/pal_networkstatistics.h @@ -167,6 +167,8 @@ DLLEXPORT int32_t SystemNative_GetEstimatedUdpListenerCount(void); DLLEXPORT int32_t SystemNative_GetActiveUdpListeners(IPEndPointInfo* infos, int32_t* infoCount); +DLLEXPORT uint32_t SystemNative_GetNativeIPInterfaceIndex(char* interfaceName); + DLLEXPORT int32_t SystemNative_GetNativeIPInterfaceStatistics(char* interfaceName, NativeIPInterfaceStatistics* retStats); DLLEXPORT int32_t SystemNative_GetNumRoutes(void); diff --git a/src/System.Net.Primitives/src/System.Net.Primitives.csproj b/src/System.Net.Primitives/src/System.Net.Primitives.csproj index 9f4d94aa9977..9b333629de57 100644 --- a/src/System.Net.Primitives/src/System.Net.Primitives.csproj +++ b/src/System.Net.Primitives/src/System.Net.Primitives.csproj @@ -143,6 +143,9 @@ Common\Interop\Windows\Kernel32\Interop.LocalFree.cs + + Common\Interop\Windows\Interop.GetNativeIPInterfaceIndex.cs + @@ -176,6 +179,9 @@ Common\Interop\Unix\System.Native\Interop.IPAddress.cs + + Common\Interop\Unix\System.Native\Interop.GetNativeIPInterfaceIndex.cs + Interop\Unix\System.Native\Interop.SocketAddress.cs diff --git a/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs b/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs index fc8207856f32..d2d9d8d02ae7 100644 --- a/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs +++ b/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs @@ -213,19 +213,20 @@ public static unsafe bool Ipv6StringToAddress(ReadOnlySpan ipSpan, ushort* long result = 0; if (!string.IsNullOrEmpty(scopeId)) { - if (scopeId.Length < 2) + uint interfaceIndex = Interop.Sys.GetNativeIPInterfaceIndex(scopeId); + if (interfaceIndex >= 0) { - scope = 0; - return false; + scope = interfaceIndex; + return true; } - for (int i = 1; i < scopeId.Length; i++) + for (int i = 0; i < scopeId.Length; i++) { char c = scopeId[i]; if (c < '0' || c > '9') { scope = 0; - return false; + return true; } result = (result * 10) + (c - '0'); if (result > uint.MaxValue) diff --git a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs index a57aac898d89..6831c5034eef 100644 --- a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs +++ b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs @@ -286,6 +286,8 @@ public void ParseIPv4_InvalidAddress_ThrowsFormatExceptionWithInnerException(str new object[] { "1::%1", "1::%1" }, new object[] { "::1%12", "::1%12" }, new object[] { "::%123", "::%123" }, + new object[] { "Fe08::1%13542", "fe08::1%awdl0" }, + new object[] { "Fe08::1%13542", "fe08::1%gpd0" }, // v4 as v6 new object[] { "FE08::192.168.0.1", "fe08::c0a8:1" }, // Output is not IPv4 mapped new object[] { "::192.168.0.1", "::192.168.0.1" }, From 7c86a81078d4f35697c7b6eb53b412b3000e0ae0 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 13 Feb 2019 03:02:45 +0300 Subject: [PATCH 02/14] fix test projects --- .../tests/PalTests/System.Net.Primitives.Pal.Tests.csproj | 6 ++++++ .../UnitTests/System.Net.Primitives.UnitTests.Tests.csproj | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj b/src/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj index 06457de405bc..cca410ecb18f 100644 --- a/src/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj +++ b/src/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj @@ -115,6 +115,9 @@ ProductionCode\Common\Interop\Windows\NtDll\Interop.NtStatus.cs + + ProductionCode\Common\Interop\Windows\Interop.GetNativeIPInterfaceIndex.cs + @@ -156,5 +159,8 @@ ProductionCode\Common\Interop\Unix\System.Native\Interop.SocketAddress.cs + + ProductionCode\Common\Interop\Unix\System.Native\Interop.GetNativeIPInterfaceIndex.cs + diff --git a/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj b/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj index 36f7e64bb2d7..8ba1633aa418 100644 --- a/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj +++ b/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj @@ -112,6 +112,9 @@ Common\System\Net\SocketAddressPal.Windows.cs + + ProductionCode\Common\Interop\Windows\Interop.GetNativeIPInterfaceIndex.cs + @@ -132,5 +135,8 @@ ProductionCode\Common\Interop\Unix\System.Native\Interop.SocketAddress.cs + + ProductionCode\Common\Interop\Unix\System.Native\Interop.GetNativeIPInterfaceIndex.cs + From a013304e16662f0f8f09aa0f53d6136f8a1b3943 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 13 Feb 2019 11:44:05 +0300 Subject: [PATCH 03/14] Address feedback --- ...dex.cs => Interop.InterfaceNameToIndex.cs} | 4 +-- .../Interop.if_nametoindex.cs} | 5 +-- .../InterfaceInfoPal.Unix.cs | 14 ++++++++ .../InterfaceInfoPal.Windows.cs | 14 ++++++++ .../System.Native/pal_networkstatistics.c | 2 +- .../System.Native/pal_networkstatistics.h | 2 +- .../src/System.Net.Primitives.csproj | 14 +++++--- .../src/System/Net/IPAddressParser.cs | 32 +++++++------------ .../tests/FunctionalTests/IPAddressParsing.cs | 1 + .../System.Net.Primitives.Pal.Tests.csproj | 14 +++++--- ...stem.Net.Primitives.UnitTests.Tests.csproj | 17 +++++++--- 11 files changed, 80 insertions(+), 39 deletions(-) rename src/Common/src/Interop/Unix/System.Native/{Interop.GetNativeIPInterfaceIndex.cs => Interop.InterfaceNameToIndex.cs} (76%) rename src/Common/src/Interop/Windows/{Interop.GetNativeIPInterfaceIndex.cs => IpHlpApi/Interop.if_nametoindex.cs} (61%) create mode 100644 src/Common/src/System/Net/NetworkInformation/InterfaceInfoPal.Unix.cs create mode 100644 src/Common/src/System/Net/NetworkInformation/InterfaceInfoPal.Windows.cs diff --git a/src/Common/src/Interop/Unix/System.Native/Interop.GetNativeIPInterfaceIndex.cs b/src/Common/src/Interop/Unix/System.Native/Interop.InterfaceNameToIndex.cs similarity index 76% rename from src/Common/src/Interop/Unix/System.Native/Interop.GetNativeIPInterfaceIndex.cs rename to src/Common/src/Interop/Unix/System.Native/Interop.InterfaceNameToIndex.cs index 2a44ee27c34b..36f8686c23ea 100644 --- a/src/Common/src/Interop/Unix/System.Native/Interop.GetNativeIPInterfaceIndex.cs +++ b/src/Common/src/Interop/Unix/System.Native/Interop.InterfaceNameToIndex.cs @@ -9,7 +9,7 @@ internal static partial class Interop { internal static partial class Sys { - [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetNativeIPInterfaceIndex")] - public static extern unsafe uint GetNativeIPInterfaceIndex(string name); + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_InterfaceNameToIndex", SetLastError = true)] + public static extern unsafe uint InterfaceNameToIndex(string name); } } diff --git a/src/Common/src/Interop/Windows/Interop.GetNativeIPInterfaceIndex.cs b/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs similarity index 61% rename from src/Common/src/Interop/Windows/Interop.GetNativeIPInterfaceIndex.cs rename to src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs index cf40993d38f6..afbdcfae0059 100644 --- a/src/Common/src/Interop/Windows/Interop.GetNativeIPInterfaceIndex.cs +++ b/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs @@ -7,8 +7,9 @@ internal static partial class Interop { - internal static partial class Sys + internal static partial class IpHlpApi { - public static uint GetNativeIPInterfaceIndex(string name) => 0; //TODO: um.. where should I put `if_nametoindex` for Windows (available since Vista) + [DllImport(Interop.Libraries.IpHlpApi)] + internal extern static uint if_nametoindex(string name); } } diff --git a/src/Common/src/System/Net/NetworkInformation/InterfaceInfoPal.Unix.cs b/src/Common/src/System/Net/NetworkInformation/InterfaceInfoPal.Unix.cs new file mode 100644 index 000000000000..8e9b2fc77c44 --- /dev/null +++ b/src/Common/src/System/Net/NetworkInformation/InterfaceInfoPal.Unix.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Net.NetworkInformation +{ + internal static class InterfaceInfoPal + { + public static uint InterfaceNameToIndex(string interfaceName) + { + return Interop.Sys.InterfaceNameToIndex(interfaceName); + } + } +} \ No newline at end of file diff --git a/src/Common/src/System/Net/NetworkInformation/InterfaceInfoPal.Windows.cs b/src/Common/src/System/Net/NetworkInformation/InterfaceInfoPal.Windows.cs new file mode 100644 index 000000000000..3ea7c72f5037 --- /dev/null +++ b/src/Common/src/System/Net/NetworkInformation/InterfaceInfoPal.Windows.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Net.NetworkInformation +{ + internal static class InterfaceInfoPal + { + public static uint InterfaceNameToIndex(string interfaceName) + { + return Interop.IpHlpApi.if_nametoindex(interfaceName); + } + } +} \ No newline at end of file diff --git a/src/Native/Unix/System.Native/pal_networkstatistics.c b/src/Native/Unix/System.Native/pal_networkstatistics.c index 2667cee5bec5..4f3c2cf2e038 100644 --- a/src/Native/Unix/System.Native/pal_networkstatistics.c +++ b/src/Native/Unix/System.Native/pal_networkstatistics.c @@ -437,7 +437,7 @@ int32_t SystemNative_GetActiveUdpListeners(IPEndPointInfo* infos, int32_t* infoC return 0; } -uint32_t SystemNative_GetNativeIPInterfaceIndex(char* interfaceName) +uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName) { assert(interfaceName != NULL); return if_nametoindex(interfaceName); diff --git a/src/Native/Unix/System.Native/pal_networkstatistics.h b/src/Native/Unix/System.Native/pal_networkstatistics.h index 67fcb4a87052..1935af9fd020 100644 --- a/src/Native/Unix/System.Native/pal_networkstatistics.h +++ b/src/Native/Unix/System.Native/pal_networkstatistics.h @@ -167,7 +167,7 @@ DLLEXPORT int32_t SystemNative_GetEstimatedUdpListenerCount(void); DLLEXPORT int32_t SystemNative_GetActiveUdpListeners(IPEndPointInfo* infos, int32_t* infoCount); -DLLEXPORT uint32_t SystemNative_GetNativeIPInterfaceIndex(char* interfaceName); +DLLEXPORT uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName); DLLEXPORT int32_t SystemNative_GetNativeIPInterfaceStatistics(char* interfaceName, NativeIPInterfaceStatistics* retStats); diff --git a/src/System.Net.Primitives/src/System.Net.Primitives.csproj b/src/System.Net.Primitives/src/System.Net.Primitives.csproj index 9b333629de57..985d31bc72de 100644 --- a/src/System.Net.Primitives/src/System.Net.Primitives.csproj +++ b/src/System.Net.Primitives/src/System.Net.Primitives.csproj @@ -143,8 +143,11 @@ Common\Interop\Windows\Kernel32\Interop.LocalFree.cs - - Common\Interop\Windows\Interop.GetNativeIPInterfaceIndex.cs + + Common\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs + + + Common\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs @@ -179,8 +182,11 @@ Common\Interop\Unix\System.Native\Interop.IPAddress.cs - - Common\Interop\Unix\System.Native\Interop.GetNativeIPInterfaceIndex.cs + + Common\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs + + + Common\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs Interop\Unix\System.Native\Interop.SocketAddress.cs diff --git a/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs b/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs index d2d9d8d02ae7..93f39268f5dd 100644 --- a/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs +++ b/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs @@ -7,6 +7,8 @@ using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; +using System.Globalization; +using System.Net.NetworkInformation; namespace System.Net { @@ -210,34 +212,22 @@ public static unsafe bool Ipv6StringToAddress(ReadOnlySpan ipSpan, ushort* string scopeId = null; IPv6AddressHelper.Parse(ipSpan, numbers, 0, ref scopeId); - long result = 0; if (!string.IsNullOrEmpty(scopeId)) { - uint interfaceIndex = Interop.Sys.GetNativeIPInterfaceIndex(scopeId); - if (interfaceIndex >= 0) + if (uint.TryParse(scopeId, NumberStyles.None, CultureInfo.InvariantCulture, out scope)) { - scope = interfaceIndex; - return true; + return true; // scopeId is a numeric value } - - for (int i = 0; i < scopeId.Length; i++) + uint interfaceIndex = InterfaceInfoPal.InterfaceNameToIndex(scopeId); + if (interfaceIndex > 0) { - char c = scopeId[i]; - if (c < '0' || c > '9') - { - scope = 0; - return true; - } - result = (result * 10) + (c - '0'); - if (result > uint.MaxValue) - { - scope = 0; - return false; - } + scope = interfaceIndex; + return true; // scopeId is a known interface name } + // scopeId is an unknown interface name } - - scope = (uint)result; + // scopeId is not presented + scope = 0; return true; } diff --git a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs index 6831c5034eef..d85c93a27878 100644 --- a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs +++ b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs @@ -288,6 +288,7 @@ public void ParseIPv4_InvalidAddress_ThrowsFormatExceptionWithInnerException(str new object[] { "::%123", "::%123" }, new object[] { "Fe08::1%13542", "fe08::1%awdl0" }, new object[] { "Fe08::1%13542", "fe08::1%gpd0" }, + new object[] { "Fe08::1%13542", "fe08::1%unknowninterface" }, // v4 as v6 new object[] { "FE08::192.168.0.1", "fe08::c0a8:1" }, // Output is not IPv4 mapped new object[] { "::192.168.0.1", "::192.168.0.1" }, diff --git a/src/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj b/src/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj index cca410ecb18f..88a2e064484c 100644 --- a/src/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj +++ b/src/System.Net.Primitives/tests/PalTests/System.Net.Primitives.Pal.Tests.csproj @@ -115,8 +115,11 @@ ProductionCode\Common\Interop\Windows\NtDll\Interop.NtStatus.cs - - ProductionCode\Common\Interop\Windows\Interop.GetNativeIPInterfaceIndex.cs + + ProductionCode\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs + + + ProductionCode\Common\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs @@ -159,8 +162,11 @@ ProductionCode\Common\Interop\Unix\System.Native\Interop.SocketAddress.cs - - ProductionCode\Common\Interop\Unix\System.Native\Interop.GetNativeIPInterfaceIndex.cs + + ProductionCode\Common\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs + + + ProductionCode\Common\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs diff --git a/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj b/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj index 8ba1633aa418..36bdc6cd1031 100644 --- a/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj +++ b/src/System.Net.Primitives/tests/UnitTests/System.Net.Primitives.UnitTests.Tests.csproj @@ -112,14 +112,23 @@ Common\System\Net\SocketAddressPal.Windows.cs - - ProductionCode\Common\Interop\Windows\Interop.GetNativeIPInterfaceIndex.cs + + ProductionCode\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs + + + ProductionCode\Common\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs + + + ProductionCode\Common\Interop\Windows\Interop.Libraries.cs ProductionCode\System\Net\SocketException.Unix.cs + + ProductionCode\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs + Common\System\Net\SocketAddressPal.Unix.cs @@ -135,8 +144,8 @@ ProductionCode\Common\Interop\Unix\System.Native\Interop.SocketAddress.cs - - ProductionCode\Common\Interop\Unix\System.Native\Interop.GetNativeIPInterfaceIndex.cs + + ProductionCode\Common\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs From d0cb7b23fb21f4d2a4675a8a4070e405dc9bbe0f Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 13 Feb 2019 11:55:14 +0300 Subject: [PATCH 04/14] Add SetLastError to if_nametoindex --- .../src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs b/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs index afbdcfae0059..660e20e7bfe3 100644 --- a/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs +++ b/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs @@ -9,7 +9,7 @@ internal static partial class Interop { internal static partial class IpHlpApi { - [DllImport(Interop.Libraries.IpHlpApi)] + [DllImport(Interop.Libraries.IpHlpApi, SetLastError = true)] internal extern static uint if_nametoindex(string name); } } From a579f40df6f546b747d0e3ee951d9a0904770dea Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 13 Feb 2019 17:20:28 +0300 Subject: [PATCH 05/14] fix tests --- src/Common/src/System/Net/IPv6AddressHelper.Common.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Common/src/System/Net/IPv6AddressHelper.Common.cs b/src/Common/src/System/Net/IPv6AddressHelper.Common.cs index 906e9c1e6290..361696ba24fd 100644 --- a/src/Common/src/System/Net/IPv6AddressHelper.Common.cs +++ b/src/Common/src/System/Net/IPv6AddressHelper.Common.cs @@ -302,7 +302,7 @@ internal static unsafe void Parse(ReadOnlySpan address, ushort* numbers, i for (++i; i < address.Length && address[i] != ']' && address[i] != '/'; ++i) { } - if (i - start > 0) + if (address.Length > start + 1 && i - start > 0) scopeId = new string(address.Slice(start + 1, i - start)); // + 1 to ignore '%' else scopeId = string.Empty; From eadf307042daf7760e61c7ccbb49392f4d9e8973 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 13 Feb 2019 18:06:38 +0300 Subject: [PATCH 06/14] fix tests --- .../src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs | 1 + src/Common/src/System/Net/IPv6AddressHelper.Common.cs | 6 +++--- .../tests/FunctionalTests/IPAddressParsing.cs | 6 +----- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs b/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs index 660e20e7bfe3..dbd735ce0e05 100644 --- a/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs +++ b/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs @@ -9,6 +9,7 @@ internal static partial class Interop { internal static partial class IpHlpApi { + // Available since Windows Vista and Windows Server 2008 [DllImport(Interop.Libraries.IpHlpApi, SetLastError = true)] internal extern static uint if_nametoindex(string name); } diff --git a/src/Common/src/System/Net/IPv6AddressHelper.Common.cs b/src/Common/src/System/Net/IPv6AddressHelper.Common.cs index 361696ba24fd..5842aa431f80 100644 --- a/src/Common/src/System/Net/IPv6AddressHelper.Common.cs +++ b/src/Common/src/System/Net/IPv6AddressHelper.Common.cs @@ -298,12 +298,12 @@ internal static unsafe void Parse(ReadOnlySpan address, ushort* numbers, i numberIsValid = false; } - start = i; + start = i + 1; for (++i; i < address.Length && address[i] != ']' && address[i] != '/'; ++i) { } - if (address.Length > start + 1 && i - start > 0) - scopeId = new string(address.Slice(start + 1, i - start)); // + 1 to ignore '%' + if (address.Length > start && i - start > 0) + scopeId = new string(address.Slice(start, i - start)); else scopeId = string.Empty; // ignore prefix if any diff --git a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs index d85c93a27878..0819fc4be054 100644 --- a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs +++ b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs @@ -286,9 +286,7 @@ public void ParseIPv4_InvalidAddress_ThrowsFormatExceptionWithInnerException(str new object[] { "1::%1", "1::%1" }, new object[] { "::1%12", "::1%12" }, new object[] { "::%123", "::%123" }, - new object[] { "Fe08::1%13542", "fe08::1%awdl0" }, - new object[] { "Fe08::1%13542", "fe08::1%gpd0" }, - new object[] { "Fe08::1%13542", "fe08::1%unknowninterface" }, + new object[] { "Fe08::1%unknowninterface", "fe08::1" }, // v4 as v6 new object[] { "FE08::192.168.0.1", "fe08::c0a8:1" }, // Output is not IPv4 mapped new object[] { "::192.168.0.1", "::192.168.0.1" }, @@ -383,9 +381,7 @@ public static IEnumerable InvalidIpv6Addresses() yield return new object[] { "G::" }; // invalid hex yield return new object[] { "FFFFF::" }; // invalid value yield return new object[] { ":%12" }; // colon scope - yield return new object[] { "::%1a" }; // alphanumeric scope yield return new object[] { "[2001:0db8:85a3:08d3:1319:8a2e:0370:7344]:443/" }; // errneous ending slash after ignored port - yield return new object[] { "::1234%0x12" }; // invalid scope ID yield return new object[] { "e3fff:ffff:ffff:ffff:ffff:ffff:ffff:abcd" }; // 1st number too long yield return new object[] { "3fff:effff:ffff:ffff:ffff:ffff:ffff:abcd" }; // 2nd number too long From 35cea6404c13815e76d1d03c456b68fa5fe503a8 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 13 Feb 2019 18:29:11 +0300 Subject: [PATCH 07/14] Add more tests --- .../tests/FunctionalTests/IPAddressParsing.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs index 0819fc4be054..28d206d29ff4 100644 --- a/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs +++ b/src/System.Net.Primitives/tests/FunctionalTests/IPAddressParsing.cs @@ -345,6 +345,25 @@ public void TryParseIPv6_ValidAddress_RoundtripMatchesExpected(string address, s } } + public static readonly object[][] ScopeIds = + { + new object[] { "Fe08::1%123", 123}, + new object[] { "Fe08::1%12345678", 12345678}, + new object[] { "fe80::e8b0:63ff:fee8:6b3b%9", 9}, + new object[] { "fe80::e8b0:63ff:fee8:6b3b", 0}, + new object[] { "fe80::e8b0:63ff:fee8:6b3b%abcd0", 0}, + new object[] { "::%unknownInterface", 0}, + new object[] { "::%0", 0}, + }; + + [Theory] + [MemberData(nameof(ScopeIds))] + public void ParseIPv6_ExtractsScopeId(string address, int expectedScopeId) + { + IPAddress ip = Parse(address); + Assert.Equal(expectedScopeId, ip.ScopeId); + } + public static IEnumerable InvalidIpv6Addresses() { yield return new object[] { ":::4df" }; From 333fed98a7631e1df1a3f23871a986e0b0ccaeb2 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 13 Feb 2019 18:41:41 +0300 Subject: [PATCH 08/14] move native impl to pal_networking.c/h --- src/Native/Unix/System.Native/pal_networking.c | 6 ++++++ src/Native/Unix/System.Native/pal_networking.h | 2 ++ src/Native/Unix/System.Native/pal_networkstatistics.c | 6 ------ src/Native/Unix/System.Native/pal_networkstatistics.h | 2 -- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Native/Unix/System.Native/pal_networking.c b/src/Native/Unix/System.Native/pal_networking.c index b95346b41880..6a6acc27a527 100644 --- a/src/Native/Unix/System.Native/pal_networking.c +++ b/src/Native/Unix/System.Native/pal_networking.c @@ -2568,3 +2568,9 @@ int32_t SystemNative_SendFile(intptr_t out_fd, intptr_t in_fd, int64_t offset, i return SystemNative_ConvertErrorPlatformToPal(errno); #endif } + +uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName) +{ + assert(interfaceName != NULL); + return if_nametoindex(interfaceName); +} \ No newline at end of file diff --git a/src/Native/Unix/System.Native/pal_networking.h b/src/Native/Unix/System.Native/pal_networking.h index 9bb8072350a1..5b0547e2076a 100644 --- a/src/Native/Unix/System.Native/pal_networking.h +++ b/src/Native/Unix/System.Native/pal_networking.h @@ -410,3 +410,5 @@ DLLEXPORT char* SystemNative_GetPeerUserName(intptr_t socket); DLLEXPORT void SystemNative_GetDomainSocketSizes(int32_t* pathOffset, int32_t* pathSize, int32_t* addressSize); DLLEXPORT int32_t SystemNative_SendFile(intptr_t out_fd, intptr_t in_fd, int64_t offset, int64_t count, int64_t* sent); + +DLLEXPORT uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName); \ No newline at end of file diff --git a/src/Native/Unix/System.Native/pal_networkstatistics.c b/src/Native/Unix/System.Native/pal_networkstatistics.c index 4f3c2cf2e038..d5feba971f8c 100644 --- a/src/Native/Unix/System.Native/pal_networkstatistics.c +++ b/src/Native/Unix/System.Native/pal_networkstatistics.c @@ -437,12 +437,6 @@ int32_t SystemNative_GetActiveUdpListeners(IPEndPointInfo* infos, int32_t* infoC return 0; } -uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName) -{ - assert(interfaceName != NULL); - return if_nametoindex(interfaceName); -} - int32_t SystemNative_GetNativeIPInterfaceStatistics(char* interfaceName, NativeIPInterfaceStatistics* retStats) { assert(interfaceName != NULL && retStats != NULL); diff --git a/src/Native/Unix/System.Native/pal_networkstatistics.h b/src/Native/Unix/System.Native/pal_networkstatistics.h index 1935af9fd020..743415259714 100644 --- a/src/Native/Unix/System.Native/pal_networkstatistics.h +++ b/src/Native/Unix/System.Native/pal_networkstatistics.h @@ -167,8 +167,6 @@ DLLEXPORT int32_t SystemNative_GetEstimatedUdpListenerCount(void); DLLEXPORT int32_t SystemNative_GetActiveUdpListeners(IPEndPointInfo* infos, int32_t* infoCount); -DLLEXPORT uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName); - DLLEXPORT int32_t SystemNative_GetNativeIPInterfaceStatistics(char* interfaceName, NativeIPInterfaceStatistics* retStats); DLLEXPORT int32_t SystemNative_GetNumRoutes(void); From 0ae85cf874be4510126c5bbfdb7475dcfd9285a1 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 13 Feb 2019 18:57:38 +0300 Subject: [PATCH 09/14] add newlines to pal_networking --- src/Native/Unix/System.Native/pal_networking.c | 2 +- src/Native/Unix/System.Native/pal_networking.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Native/Unix/System.Native/pal_networking.c b/src/Native/Unix/System.Native/pal_networking.c index 6a6acc27a527..ba2125519c07 100644 --- a/src/Native/Unix/System.Native/pal_networking.c +++ b/src/Native/Unix/System.Native/pal_networking.c @@ -2573,4 +2573,4 @@ uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName) { assert(interfaceName != NULL); return if_nametoindex(interfaceName); -} \ No newline at end of file +} diff --git a/src/Native/Unix/System.Native/pal_networking.h b/src/Native/Unix/System.Native/pal_networking.h index 5b0547e2076a..9557f819c874 100644 --- a/src/Native/Unix/System.Native/pal_networking.h +++ b/src/Native/Unix/System.Native/pal_networking.h @@ -411,4 +411,4 @@ DLLEXPORT void SystemNative_GetDomainSocketSizes(int32_t* pathOffset, int32_t* p DLLEXPORT int32_t SystemNative_SendFile(intptr_t out_fd, intptr_t in_fd, int64_t offset, int64_t count, int64_t* sent); -DLLEXPORT uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName); \ No newline at end of file +DLLEXPORT uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName); From c82c16c72dc0155b32647893971612ac8d9160a9 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Wed, 13 Feb 2019 19:10:56 +0300 Subject: [PATCH 10/14] fix build --- src/Native/Unix/System.Native/pal_networking.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Native/Unix/System.Native/pal_networking.c b/src/Native/Unix/System.Native/pal_networking.c index ba2125519c07..aada78db5fd7 100644 --- a/src/Native/Unix/System.Native/pal_networking.c +++ b/src/Native/Unix/System.Native/pal_networking.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,6 @@ #include #endif #if !HAVE_IN_PKTINFO -#include #if HAVE_GETIFADDRS #include #endif From 30554396188be78978b2f7df90c34ee9c71a909b Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 25 Feb 2019 12:07:36 +0300 Subject: [PATCH 11/14] remove "Vista" comment from Interop.if_nametoindex.cs --- .../src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs b/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs index dbd735ce0e05..660e20e7bfe3 100644 --- a/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs +++ b/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs @@ -9,7 +9,6 @@ internal static partial class Interop { internal static partial class IpHlpApi { - // Available since Windows Vista and Windows Server 2008 [DllImport(Interop.Libraries.IpHlpApi, SetLastError = true)] internal extern static uint if_nametoindex(string name); } From 93bbedb4dc885e8f4670cb337bdb72728e9d5cf0 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 10 Jun 2019 18:42:14 +0300 Subject: [PATCH 12/14] test fix for Uri.cs --- src/System.Private.Uri/src/System/Uri.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Private.Uri/src/System/Uri.cs b/src/System.Private.Uri/src/System/Uri.cs index fabc1041ba59..224bb93b0804 100644 --- a/src/System.Private.Uri/src/System/Uri.cs +++ b/src/System.Private.Uri/src/System/Uri.cs @@ -1193,7 +1193,7 @@ public string DnsSafeHost if (HostType == Flags.IPv6HostType) { ret = _info.ScopeId != null ? - string.Concat(ret.AsSpan(1, ret.Length - 2), _info.ScopeId) : + string.Concat(ret.AsSpan(1, ret.Length - 2), "%", _info.ScopeId) : ret.Substring(1, ret.Length - 2); } // Validate that this basic host qualifies as Dns safe, From dea480744b1b46163ee9e526bacd14c203093ba0 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 10 Jun 2019 21:53:31 +0300 Subject: [PATCH 13/14] undo changes --- src/Common/src/System/Net/IPv6AddressHelper.Common.cs | 7 ++----- src/Native/Unix/System.Native/pal_networking.c | 2 ++ .../src/System/Net/IPAddressParser.cs | 4 ++-- src/System.Private.Uri/src/System/Uri.cs | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Common/src/System/Net/IPv6AddressHelper.Common.cs b/src/Common/src/System/Net/IPv6AddressHelper.Common.cs index 6832f886ee85..b0c85e35026c 100644 --- a/src/Common/src/System/Net/IPv6AddressHelper.Common.cs +++ b/src/Common/src/System/Net/IPv6AddressHelper.Common.cs @@ -312,14 +312,11 @@ internal static void Parse(ReadOnlySpan address, Span numbers, int numberIsValid = false; } - start = i + 1; + start = i; for (++i; i < address.Length && address[i] != ']' && address[i] != '/'; ++i) { } - if (address.Length > start && i - start > 0) - scopeId = new string(address.Slice(start, i - start)); - else - scopeId = string.Empty; + scopeId = new string(address.Slice(start, i - start)); // ignore prefix if any for (; i < address.Length && address[i] != ']'; ++i) { diff --git a/src/Native/Unix/System.Native/pal_networking.c b/src/Native/Unix/System.Native/pal_networking.c index e261d0b9c97b..abf5e7407901 100644 --- a/src/Native/Unix/System.Native/pal_networking.c +++ b/src/Native/Unix/System.Native/pal_networking.c @@ -2693,5 +2693,7 @@ int32_t SystemNative_SendFile(intptr_t out_fd, intptr_t in_fd, int64_t offset, i uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName) { assert(interfaceName != NULL); + if (interfaceName[0] == '%') + interfaceName++; return if_nametoindex(interfaceName); } diff --git a/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs b/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs index 994a4c333276..ce0674dff969 100644 --- a/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs +++ b/src/System.Net.Primitives/src/System/Net/IPAddressParser.cs @@ -212,9 +212,9 @@ public static unsafe bool Ipv6StringToAddress(ReadOnlySpan ipSpan, Span 1) { - if (uint.TryParse(scopeId, NumberStyles.None, CultureInfo.InvariantCulture, out scope)) + if (uint.TryParse(scopeId.AsSpan(1), NumberStyles.None, CultureInfo.InvariantCulture, out scope)) { return true; // scopeId is a numeric value } diff --git a/src/System.Private.Uri/src/System/Uri.cs b/src/System.Private.Uri/src/System/Uri.cs index 224bb93b0804..fabc1041ba59 100644 --- a/src/System.Private.Uri/src/System/Uri.cs +++ b/src/System.Private.Uri/src/System/Uri.cs @@ -1193,7 +1193,7 @@ public string DnsSafeHost if (HostType == Flags.IPv6HostType) { ret = _info.ScopeId != null ? - string.Concat(ret.AsSpan(1, ret.Length - 2), "%", _info.ScopeId) : + string.Concat(ret.AsSpan(1, ret.Length - 2), _info.ScopeId) : ret.Substring(1, ret.Length - 2); } // Validate that this basic host qualifies as Dns safe, From 43f8b19b52f339588bc0d0e786a610e9d9c6a215 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Fri, 14 Jun 2019 19:10:58 +0300 Subject: [PATCH 14/14] Always return 0 for if_nametoindex on UAP --- .../src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs b/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs index 660e20e7bfe3..292559175f9a 100644 --- a/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs +++ b/src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs @@ -9,7 +9,11 @@ internal static partial class Interop { internal static partial class IpHlpApi { +#if !uap [DllImport(Interop.Libraries.IpHlpApi, SetLastError = true)] internal extern static uint if_nametoindex(string name); +#else + internal static uint if_nametoindex(string name) => 0; +#endif } }