Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Allow interface names in IPv6 link-local addresses #35278

Merged
merged 17 commits into from
Jun 15, 2019
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
@@ -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_InterfaceNameToIndex", SetLastError = true)]
public static extern unsafe uint InterfaceNameToIndex(string name);
}
}
19 changes: 19 additions & 0 deletions src/Common/src/Interop/Windows/IpHlpApi/Interop.if_nametoindex.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this isn't available in UWP, which is why a few of the legs are failing with a BCL0015 error. It'll need to be conditionally used when not building for that configuration.

#else
internal static uint if_nametoindex(string name) => 0;
#endif
}
}
5 changes: 0 additions & 5 deletions src/Common/src/System/Net/IPv6AddressHelper.Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,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 ']':
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
10 changes: 9 additions & 1 deletion src/Native/Unix/System.Native/pal_networking.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#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>
Expand All @@ -50,7 +51,6 @@
#include <sys/uio.h>
#endif
#if !HAVE_IN_PKTINFO
#include <net/if.h>
#if HAVE_GETIFADDRS
#include <ifaddrs.h>
#endif
Expand Down Expand Up @@ -2689,3 +2689,11 @@ 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);
if (interfaceName[0] == '%')
interfaceName++;
return if_nametoindex(interfaceName);
}
2 changes: 2 additions & 0 deletions src/Native/Unix/System.Native/pal_networking.h
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,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);
12 changes: 12 additions & 0 deletions src/System.Net.Primitives/src/System.Net.Primitives.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@
<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" />
Expand Down Expand Up @@ -176,6 +182,12 @@
<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>
Expand Down
33 changes: 12 additions & 21 deletions src/System.Net.Primitives/src/System/Net/IPAddressParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -210,33 +212,22 @@ public static unsafe bool Ipv6StringToAddress(ReadOnlySpan<char> ipSpan, Span<us
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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +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%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" },
Expand Down Expand Up @@ -344,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<object[]> InvalidIpv6Addresses()
{
yield return new object[] { "[:]" }; // malformed
Expand Down Expand Up @@ -399,9 +419,7 @@ public static IEnumerable<object[]> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@
<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">
Expand Down Expand Up @@ -156,5 +162,11 @@
<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>
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,23 @@
<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>
Expand All @@ -132,5 +144,8 @@
<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>