Skip to content

Commit 8f2c205

Browse files
authored
fix(http.sys): correctly parse port values in range [32768:65535] (#62506)
1 parent 1fe9483 commit 8f2c205

File tree

3 files changed

+74
-7
lines changed

3 files changed

+74
-7
lines changed

src/Servers/HttpSys/HttpSysServer.slnf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,4 @@
5555
"src\\WebEncoders\\src\\Microsoft.Extensions.WebEncoders.csproj"
5656
]
5757
}
58-
}
58+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Net;
5+
using Microsoft.AspNetCore.HttpSys.Internal;
6+
using Windows.Win32.Networking.WinSock;
7+
using Xunit;
8+
using static Microsoft.AspNetCore.HttpSys.Internal.SocketAddress;
9+
using SocketAddress = Microsoft.AspNetCore.HttpSys.Internal.SocketAddress;
10+
11+
namespace Microsoft.AspNetCore.Server.HttpSys.Tests.NativeInterop;
12+
13+
public class SocketAddressTests
14+
{
15+
[Theory]
16+
[InlineData(80)]
17+
[InlineData(443)]
18+
[InlineData(8080)]
19+
[InlineData(32767)] // max signed short
20+
[InlineData(32768)] // min value that causes negative when cast to short
21+
[InlineData(42000)]
22+
[InlineData(65535)] // Max port number
23+
public void IPv6_GetPort_ReturnsCorrectPort_ForAllValidPorts(ushort expectedPort)
24+
{
25+
var nativeIpV6Address = new SOCKADDR_IN6
26+
{
27+
sin6_family = ADDRESS_FAMILY.AF_INET6,
28+
sin6_port = (ushort)IPAddress.HostToNetworkOrder((short)expectedPort)
29+
};
30+
31+
var socketAddress = new SocketAddressIPv6(nativeIpV6Address);
32+
var actualPort = socketAddress.GetPort();
33+
34+
Assert.Equal(expectedPort, actualPort);
35+
Assert.True(actualPort >= 0, "Port should never be negative");
36+
Assert.True(actualPort <= 65535, "Port should not exceed maximum valid port");
37+
}
38+
39+
[Theory]
40+
[InlineData(80)]
41+
[InlineData(443)]
42+
[InlineData(8080)]
43+
[InlineData(42000)]
44+
[InlineData(32767)]
45+
[InlineData(32768)]
46+
[InlineData(65535)]
47+
public void IPv4_GetPort_ReturnsCorrectPort_ForAllValidPorts(ushort expectedPort)
48+
{
49+
var nativeIpV4Address = new SOCKADDR_IN
50+
{
51+
sin_family = ADDRESS_FAMILY.AF_INET,
52+
sin_port = (ushort)IPAddress.HostToNetworkOrder((short)expectedPort)
53+
};
54+
55+
var socketAddress = new SocketAddressIPv4(nativeIpV4Address);
56+
var actualPort = socketAddress.GetPort();
57+
58+
Assert.Equal(expectedPort, actualPort);
59+
Assert.True(actualPort >= 0, "Port should never be negative");
60+
Assert.True(actualPort <= 65535, "Port should not exceed maximum valid port");
61+
}
62+
}

src/Shared/HttpSys/NativeInterop/SocketAddress.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System.Buffers.Binary;
45
using System.Net;
56
using Windows.Win32.Networking.WinSock;
67

@@ -25,7 +26,8 @@ internal abstract class SocketAddress
2526
};
2627
}
2728

28-
private sealed class SocketAddressIPv4 : SocketAddress
29+
// internal for testing
30+
internal sealed class SocketAddressIPv4 : SocketAddress
2931
{
3032
private readonly SOCKADDR_IN _sockaddr;
3133

@@ -36,8 +38,9 @@ internal SocketAddressIPv4(in SOCKADDR_IN sockaddr)
3638

3739
internal override int GetPort()
3840
{
39-
// sin_port is network byte order
40-
return IPAddress.NetworkToHostOrder((short)_sockaddr.sin_port);
41+
// _sockaddr.sin_port has network byte order.
42+
// cast to ushort is important to avoid negative values for the TCP port
43+
return (ushort)IPAddress.NetworkToHostOrder((short)_sockaddr.sin_port);
4144
}
4245

4346
internal override IPAddress? GetIPAddress()
@@ -47,7 +50,8 @@ internal override int GetPort()
4750
}
4851
}
4952

50-
private sealed class SocketAddressIPv6 : SocketAddress
53+
// internal for testing
54+
internal sealed class SocketAddressIPv6 : SocketAddress
5155
{
5256
private readonly SOCKADDR_IN6 _sockaddr;
5357

@@ -58,8 +62,9 @@ internal SocketAddressIPv6(in SOCKADDR_IN6 sockaddr)
5862

5963
internal override int GetPort()
6064
{
61-
// sin6_port is network byte order
62-
return IPAddress.NetworkToHostOrder((short)_sockaddr.sin6_port);
65+
// _sockaddr.sin6_port has network byte order.
66+
// cast to ushort is important to avoid negative values for the TCP port
67+
return (ushort)IPAddress.NetworkToHostOrder((short)_sockaddr.sin6_port);
6368
}
6469

6570
internal override IPAddress? GetIPAddress()

0 commit comments

Comments
 (0)