--- /dev/null
+// 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_InterfaceNameToIndex", SetLastError = true)]
+ public static extern unsafe uint InterfaceNameToIndex(string name);
+ }
+}
--- /dev/null
+// 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 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
+ }
+}
{
goto case '/';
}
- else if (name[i] < '0' || name[i] > '9')
- {
- // scope ID must only contain digits
- return false;
- }
}
break;
case ']':
--- /dev/null
+// 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
--- /dev/null
+// 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
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
+#include <net/if.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#endif
#if !HAVE_IN_PKTINFO
-#include <net/if.h>
#if HAVE_GETIFADDRS
#include <ifaddrs.h>
#endif
return SystemNative_ConvertErrorPlatformToPal(errno);
#endif
}
+
+uint32_t SystemNative_InterfaceNameToIndex(char* interfaceName)
+{
+ assert(interfaceName != NULL);
+ if (interfaceName[0] == '%')
+ interfaceName++;
+ return if_nametoindex(interfaceName);
+}
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);
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.LocalFree.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.LocalFree.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs">
+ <Link>Common\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs">
+ <Link>Common\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsUnix)' == 'true'">
<Compile Include="System\Net\SocketException.Unix.cs" />
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.IPAddress.cs">
<Link>Common\Interop\Unix\System.Native\Interop.IPAddress.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs">
+ <Link>Common\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs">
+ <Link>Common\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.SocketAddress.cs">
<Link>Interop\Unix\System.Native\Interop.SocketAddress.cs</Link>
</Compile>
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
+using System.Globalization;
+using System.Net.NetworkInformation;
namespace System.Net
{
string scopeId = null;
IPv6AddressHelper.Parse(ipSpan, numbers, 0, ref scopeId);
- long result = 0;
- if (!string.IsNullOrEmpty(scopeId))
+ if (scopeId?.Length > 1)
{
- if (scopeId.Length < 2)
+ if (uint.TryParse(scopeId.AsSpan(1), NumberStyles.None, CultureInfo.InvariantCulture, out scope))
{
- scope = 0;
- return false;
+ return true; // scopeId is a numeric value
}
-
- for (int i = 1; i < scopeId.Length; i++)
+ uint interfaceIndex = InterfaceInfoPal.InterfaceNameToIndex(scopeId);
+ if (interfaceIndex > 0)
{
- char c = scopeId[i];
- if (c < '0' || c > '9')
- {
- scope = 0;
- return false;
- }
- 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;
}
new object[] { "1::%1", "1::%1" },
new object[] { "::1%12", "::1%12" },
new object[] { "::%123", "::%123" },
+ 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" },
}
}
+ 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<object[]> InvalidIpv6Addresses()
{
yield return new object[] { "[:]" }; // malformed
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
<Compile Include="$(CommonPath)\Interop\Windows\NtDll\Interop.NtStatus.cs">
<Link>ProductionCode\Common\Interop\Windows\NtDll\Interop.NtStatus.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs">
+ <Link>ProductionCode\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs">
+ <Link>ProductionCode\Common\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
<Compile Include="..\..\src\System\Net\SocketException.Unix.cs">
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.SocketAddress.cs">
<Link>ProductionCode\Common\Interop\Unix\System.Native\Interop.SocketAddress.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs">
+ <Link>ProductionCode\Common\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs">
+ <Link>ProductionCode\Common\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs</Link>
+ </Compile>
</ItemGroup>
</Project>
<Compile Include="$(CommonPath)\System\Net\SocketAddressPal.Windows.cs">
<Link>Common\System\Net\SocketAddressPal.Windows.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs">
+ <Link>ProductionCode\System\Net\NetworkInformation\InterfaceInfoPal.Windows.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs">
+ <Link>ProductionCode\Common\Interop\Windows\IpHlpApi\Interop.if_nametoindex.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)\Interop\Windows\Interop.Libraries.cs">
+ <Link>ProductionCode\Common\Interop\Windows\Interop.Libraries.cs</Link>
+ </Compile>
</ItemGroup>
<ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
<Compile Include="..\..\src\System\Net\SocketException.Unix.cs">
<Link>ProductionCode\System\Net\SocketException.Unix.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs">
+ <Link>ProductionCode\System\Net\NetworkInformation\InterfaceInfoPal.Unix.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\Net\SocketAddressPal.Unix.cs">
<Link>Common\System\Net\SocketAddressPal.Unix.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.SocketAddress.cs">
<Link>ProductionCode\Common\Interop\Unix\System.Native\Interop.SocketAddress.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs">
+ <Link>ProductionCode\Common\Interop\Unix\System.Native\Interop.InterfaceNameToIndex.cs</Link>
+ </Compile>
</ItemGroup>
</Project>