From 03808095ab6bbe6d773284ccdb3672c63419ce1b Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 17 Feb 2021 11:15:08 +0100 Subject: [PATCH] Big-endian fixes: networking stack * Fix various places that assumed host byte order was little-endian, use appropriate host <-> network byte order conversion instead. * This in particular affects handling of IPv4 addresses, which are stored internally in network order. * Fix endian assumptions in socket option code (GetSockOpt). * Update test cases and provide /proc test files from a big-endian system. --- .../Unix/System.Native/pal_networking.c | 18 +++- .../StringParsingHelpers.Connections.cs | 2 +- .../FunctionalTests/AddressParsingTests.cs | 40 ++++++-- .../ConnectionsParsingTests.cs | 94 ++++++++++++++----- .../FunctionalTests/NetworkFiles/route-be | 5 + .../tests/FunctionalTests/NetworkFiles/tcp-be | 6 ++ .../FunctionalTests/NetworkFiles/tcp6-be | 9 ++ .../tests/FunctionalTests/NetworkFiles/udp-be | 13 +++ .../FunctionalTests/NetworkFiles/udp6-be | 6 ++ .../src/System/Net/IPAddress.cs | 33 +++---- .../src/System/Net/IPAddressParser.cs | 24 ++--- .../tests/FunctionalTests/IPAddressTest.cs | 49 ++++++---- .../tests/FunctionalTests/IPEndPointTest.cs | 2 +- .../src/System/Net/Sockets/SocketPal.Unix.cs | 1 - 14 files changed, 218 insertions(+), 84 deletions(-) create mode 100644 src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/route-be create mode 100644 src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/tcp-be create mode 100644 src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/tcp6-be create mode 100644 src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/udp-be create mode 100644 src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/udp6-be diff --git a/src/libraries/Native/Unix/System.Native/pal_networking.c b/src/libraries/Native/Unix/System.Native/pal_networking.c index 2e819aaa5c455..11124f34c29bb 100644 --- a/src/libraries/Native/Unix/System.Native/pal_networking.c +++ b/src/libraries/Native/Unix/System.Native/pal_networking.c @@ -2031,7 +2031,14 @@ int32_t SystemNative_GetSockOpt( { if (socketOptionName == SocketOptionName_SO_IP_DONTFRAGMENT) { - *optionValue = *optionValue == IP_PMTUDISC_DO ? 1 : 0; + if (optLen >= (socklen_t)sizeof(int)) + { + *(int*)optionValue = *(int*)optionValue == IP_PMTUDISC_DO ? 1 : 0; + } + else + { + *optionValue = *optionValue == IP_PMTUDISC_DO ? 1 : 0; + } } } #endif @@ -2139,7 +2146,14 @@ SystemNative_SetSockOpt(intptr_t socket, int32_t socketOptionLevel, int32_t sock { if (socketOptionName == SocketOptionName_SO_IP_DONTFRAGMENT) { - *optionValue = *optionValue != 0 ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; + if ((socklen_t)optionLen >= (socklen_t)sizeof(int)) + { + *(int*)optionValue = *(int*)optionValue != 0 ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; + } + else + { + *optionValue = *optionValue != 0 ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; + } } } #endif diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/StringParsingHelpers.Connections.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/StringParsingHelpers.Connections.cs index f48a231517ef2..d53d00eb5887e 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/StringParsingHelpers.Connections.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/StringParsingHelpers.Connections.cs @@ -332,7 +332,7 @@ private static IPAddress ParseIPv6HexString(string hexAddress, bool isNetworkOrd { Debug.Assert(hexAddress.Length == 32); byte[] addressBytes = new byte[16]; - if (isNetworkOrder) + if (isNetworkOrder || !BitConverter.IsLittleEndian) { for (int i = 0; i < 16; i++) { diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/AddressParsingTests.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/AddressParsingTests.cs index 2aafbde026e0c..637cb202fe436 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/AddressParsingTests.cs +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/AddressParsingTests.cs @@ -12,22 +12,44 @@ public class AddressParsingTests : FileCleanupTestBase [Fact] public void HexIPAddressParsing() { - Assert.Equal(IPAddress.Parse("10.105.128.1"), StringParsingHelpers.ParseHexIPAddress("0180690A")); - Assert.Equal(IPAddress.Parse("103.69.35.1"), StringParsingHelpers.ParseHexIPAddress("01234567")); - Assert.Equal(IPAddress.Parse("152.186.220.254"), StringParsingHelpers.ParseHexIPAddress("FEDCBA98")); + if (BitConverter.IsLittleEndian) + { + Assert.Equal(IPAddress.Parse("10.105.128.1"), StringParsingHelpers.ParseHexIPAddress("0180690A")); + Assert.Equal(IPAddress.Parse("103.69.35.1"), StringParsingHelpers.ParseHexIPAddress("01234567")); + Assert.Equal(IPAddress.Parse("152.186.220.254"), StringParsingHelpers.ParseHexIPAddress("FEDCBA98")); - Assert.Equal(IPAddress.Parse("::"), StringParsingHelpers.ParseHexIPAddress("00000000000000000000000000000000")); - Assert.Equal(IPAddress.Parse("::1"), StringParsingHelpers.ParseHexIPAddress("00000000000000000000000001000000")); - Assert.Equal(IPAddress.Parse("fec0::1"), StringParsingHelpers.ParseHexIPAddress("0000C0FE000000000000000001000000")); - Assert.Equal(IPAddress.Parse("fe80::222:222"), StringParsingHelpers.ParseHexIPAddress("000080FE000000000000000022022202")); - Assert.Equal(IPAddress.Parse("fe80::215:5dff:fe00:402"), StringParsingHelpers.ParseHexIPAddress("000080FE00000000FF5D1502020400FE")); + Assert.Equal(IPAddress.Parse("::"), StringParsingHelpers.ParseHexIPAddress("00000000000000000000000000000000")); + Assert.Equal(IPAddress.Parse("::1"), StringParsingHelpers.ParseHexIPAddress("00000000000000000000000001000000")); + Assert.Equal(IPAddress.Parse("fec0::1"), StringParsingHelpers.ParseHexIPAddress("0000C0FE000000000000000001000000")); + Assert.Equal(IPAddress.Parse("fe80::222:222"), StringParsingHelpers.ParseHexIPAddress("000080FE000000000000000022022202")); + Assert.Equal(IPAddress.Parse("fe80::215:5dff:fe00:402"), StringParsingHelpers.ParseHexIPAddress("000080FE00000000FF5D1502020400FE")); + } + else + { + Assert.Equal(IPAddress.Parse("10.105.128.1"), StringParsingHelpers.ParseHexIPAddress("0A698001")); + Assert.Equal(IPAddress.Parse("103.69.35.1"), StringParsingHelpers.ParseHexIPAddress("67452301")); + Assert.Equal(IPAddress.Parse("152.186.220.254"), StringParsingHelpers.ParseHexIPAddress("98BADCFE")); + + Assert.Equal(IPAddress.Parse("::"), StringParsingHelpers.ParseHexIPAddress("00000000000000000000000000000000")); + Assert.Equal(IPAddress.Parse("::1"), StringParsingHelpers.ParseHexIPAddress("00000000000000000000000000000001")); + Assert.Equal(IPAddress.Parse("fec0::1"), StringParsingHelpers.ParseHexIPAddress("FEC00000000000000000000000000001")); + Assert.Equal(IPAddress.Parse("fe80::222:222"), StringParsingHelpers.ParseHexIPAddress("FE800000000000000000000002220222")); + Assert.Equal(IPAddress.Parse("fe80::215:5dff:fe00:402"), StringParsingHelpers.ParseHexIPAddress("FE8000000000000002155DFFFE000402")); + } } [Fact] public void IPv4GatewayAddressParsing() { string fileName = GetTestFilePath(); - FileUtil.NormalizeLineEndings("NetworkFiles/route", fileName); + if (BitConverter.IsLittleEndian) + { + FileUtil.NormalizeLineEndings("NetworkFiles/route", fileName); + } + else + { + FileUtil.NormalizeLineEndings("NetworkFiles/route-be", fileName); + } List gatewayAddresses = new List(); StringParsingHelpers.ParseIPv4GatewayAddressesFromRouteFile(gatewayAddresses, File.ReadAllLines(fileName), "wlan0"); Assert.Equal(3, gatewayAddresses.Count); diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/ConnectionsParsingTests.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/ConnectionsParsingTests.cs index 6a5764c98d91b..9f50bf682a9bc 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/ConnectionsParsingTests.cs +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/ConnectionsParsingTests.cs @@ -34,16 +34,48 @@ public void ActiveTcpConnectionsParsing() { string tcpFile = GetTestFilePath(); string tcp6File = GetTestFilePath(); - FileUtil.NormalizeLineEndings("NetworkFiles/tcp", tcpFile); - FileUtil.NormalizeLineEndings("NetworkFiles/tcp6", tcp6File); + if (BitConverter.IsLittleEndian) + { + FileUtil.NormalizeLineEndings("NetworkFiles/tcp", tcpFile); + FileUtil.NormalizeLineEndings("NetworkFiles/tcp6", tcp6File); + } + else + { + FileUtil.NormalizeLineEndings("NetworkFiles/tcp-be", tcpFile); + FileUtil.NormalizeLineEndings("NetworkFiles/tcp6-be", tcp6File); + } TcpConnectionInformation[] infos = StringParsingHelpers.ParseActiveTcpConnectionsFromFiles(tcpFile, tcp6File); Assert.Equal(11, infos.Length); - ValidateInfo(infos[0], new IPEndPoint(0xFFFFFF01L, 0x01BD), new IPEndPoint(0L, 0), TcpState.Established); - ValidateInfo(infos[1], new IPEndPoint(0x12345678L, 0x008B), new IPEndPoint(0L, 0), TcpState.SynSent); - ValidateInfo(infos[2], new IPEndPoint(0x0101007FL, 0x0035), new IPEndPoint(0L, 0), TcpState.SynReceived); - ValidateInfo(infos[3], new IPEndPoint(0x0100007FL, 0x0277), new IPEndPoint(0L, 0), TcpState.FinWait1); - ValidateInfo(infos[4], new IPEndPoint(0x0100007FL, 0x0277), new IPEndPoint(0x00000001L, 0), TcpState.SynReceived); + + ValidateInfo( + infos[0], + new IPEndPoint(IPAddress.Parse("1.255.255.255"), 0x01BD), + new IPEndPoint(0L, 0), + TcpState.Established); + + ValidateInfo( + infos[1], + new IPEndPoint(IPAddress.Parse("120.86.52.18"), 0x008B), + new IPEndPoint(0L, 0), + TcpState.SynSent); + + ValidateInfo( + infos[2], + new IPEndPoint(IPAddress.Parse("127.0.1.1"), 0x0035), + new IPEndPoint(0L, 0), + TcpState.SynReceived); + + ValidateInfo( + infos[3], + new IPEndPoint(IPAddress.Parse("127.0.0.1"), 0x0277), + new IPEndPoint(0L, 0), + TcpState.FinWait1); + + ValidateInfo(infos[4], + new IPEndPoint(IPAddress.Parse("127.0.0.1"), 0x0277), + new IPEndPoint(IPAddress.Parse("1.0.0.0"), 0), + TcpState.SynReceived); ValidateInfo( infos[5], @@ -87,8 +119,16 @@ public void TcpListenersParsing() { string tcpFile = GetTestFilePath(); string tcp6File = GetTestFilePath(); - FileUtil.NormalizeLineEndings("NetworkFiles/tcp", tcpFile); - FileUtil.NormalizeLineEndings("NetworkFiles/tcp6", tcp6File); + if (BitConverter.IsLittleEndian) + { + FileUtil.NormalizeLineEndings("NetworkFiles/tcp", tcpFile); + FileUtil.NormalizeLineEndings("NetworkFiles/tcp6", tcp6File); + } + else + { + FileUtil.NormalizeLineEndings("NetworkFiles/tcp-be", tcpFile); + FileUtil.NormalizeLineEndings("NetworkFiles/tcp6-be", tcp6File); + } IPEndPoint[] listeners = StringParsingHelpers.ParseActiveTcpListenersFromFiles(tcpFile, tcp6File); // There is only one socket in Listening state @@ -102,24 +142,32 @@ public void UdpListenersParsing() { string udpFile = GetTestFilePath(); string udp6File = GetTestFilePath(); - FileUtil.NormalizeLineEndings("NetworkFiles/udp", udpFile); - FileUtil.NormalizeLineEndings("NetworkFiles/udp6", udp6File); + if (BitConverter.IsLittleEndian) + { + FileUtil.NormalizeLineEndings("NetworkFiles/udp", udpFile); + FileUtil.NormalizeLineEndings("NetworkFiles/udp6", udp6File); + } + else + { + FileUtil.NormalizeLineEndings("NetworkFiles/udp-be", udpFile); + FileUtil.NormalizeLineEndings("NetworkFiles/udp6-be", udp6File); + } IPEndPoint[] listeners = StringParsingHelpers.ParseActiveUdpListenersFromFiles(udpFile, udp6File); Assert.Equal(17, listeners.Length); - Assert.Equal(listeners[0], new IPEndPoint(0x00000000, 0x8E15)); - Assert.Equal(listeners[1], new IPEndPoint(0x00000000, 0x14E9)); - Assert.Equal(listeners[2], new IPEndPoint(0x00000000, 0xB50F)); - Assert.Equal(listeners[3], new IPEndPoint(0x0101007F, 0x0035)); - Assert.Equal(listeners[4], new IPEndPoint(0x00000000, 0x0044)); - Assert.Equal(listeners[5], new IPEndPoint(0xFF83690A, 0x0089)); - Assert.Equal(listeners[6], new IPEndPoint(0x3B80690A, 0x0089)); - Assert.Equal(listeners[7], new IPEndPoint(0x00000000, 0x0089)); - Assert.Equal(listeners[8], new IPEndPoint(0xFF83690A, 0x008A)); - Assert.Equal(listeners[9], new IPEndPoint(0x3B80690A, 0x008A)); - Assert.Equal(listeners[10], new IPEndPoint(0x00000000, 0x008A)); - Assert.Equal(listeners[11], new IPEndPoint(0x00000000, 0x0277)); + Assert.Equal(listeners[0], new IPEndPoint(0, 0x8E15)); + Assert.Equal(listeners[1], new IPEndPoint(0, 0x14E9)); + Assert.Equal(listeners[2], new IPEndPoint(0, 0xB50F)); + Assert.Equal(listeners[3], new IPEndPoint(IPAddress.Parse("127.0.1.1"), 0x0035)); + Assert.Equal(listeners[4], new IPEndPoint(0, 0x0044)); + Assert.Equal(listeners[5], new IPEndPoint(IPAddress.Parse("10.105.131.255"), 0x0089)); + Assert.Equal(listeners[6], new IPEndPoint(IPAddress.Parse("10.105.128.59"), 0x0089)); + Assert.Equal(listeners[7], new IPEndPoint(0, 0x0089)); + Assert.Equal(listeners[8], new IPEndPoint(IPAddress.Parse("10.105.131.255"), 0x008A)); + Assert.Equal(listeners[9], new IPEndPoint(IPAddress.Parse("10.105.128.59"), 0x008A)); + Assert.Equal(listeners[10], new IPEndPoint(0, 0x008A)); + Assert.Equal(listeners[11], new IPEndPoint(0, 0x0277)); Assert.Equal(listeners[12], new IPEndPoint(IPAddress.Parse("::"), 0x14E9)); Assert.Equal(listeners[13], new IPEndPoint(IPAddress.Parse("::"), 0x96D3)); diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/route-be b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/route-be new file mode 100644 index 0000000000000..aa912f68ad91d --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/route-be @@ -0,0 +1,5 @@ +Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +wlan0 00000000 0A698001 0003 0 0 400 00000000 0 0 0 +wlan0 0A698000 67452301 0001 0 0 400 FFFFFC00 0 0 0 +wlan0 A9FE0000 98BADCFE 0001 0 0 1000 FFFF0000 0 0 0 +eth0 00000000 11111111 0001 0 0 1000 FFFF0000 0 0 0 diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/tcp-be b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/tcp-be new file mode 100644 index 0000000000000..e7bbf100e4773 --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/tcp-be @@ -0,0 +1,6 @@ + sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode + 0: 01FFFFFF:01BD 00000000:0000 01 00000000:00000000 00:00000000 00000000 0 0 23053 1 0000000000000000 100 0 0 10 0 + 1: 78563412:008B 00000000:0000 02 00000000:00000000 00:00000000 00000000 0 0 23054 1 0000000000000000 100 0 0 10 0 + 2: 7F000101:0035 00000000:0000 03 00000000:00000000 00:00000000 00000000 0 0 17216 1 0000000000000000 100 0 0 10 0 + 3: 7F000001:0277 00000000:0000 04 00000000:00000000 00:00000000 00000000 0 0 16089 1 0000000000000000 100 0 0 10 0 + 4: 7F000001:0277 01000000:0000 0C 00000000:00000000 00:00000000 00000000 0 0 16089 1 0000000000000000 100 0 0 10 0 diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/tcp6-be b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/tcp6-be new file mode 100644 index 0000000000000..6fdda567697f9 --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/tcp6-be @@ -0,0 +1,9 @@ + sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode + 0: 00000000000000000000000000000000:01BD 00000000000000000000000000000000:0000 05 00000000:00000000 00:00000000 00000000 0 0 23051 1 0000000000000000 100 0 0 10 0 + 1: 00000000000000000000000000000000:008B 00000000000000000000000000000000:0000 06 00000000:00000000 00:00000000 00000000 0 0 23052 1 0000000000000000 100 0 0 10 0 + 2: 00000000000000000000000000000001:0277 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 16088 1 0000000000000000 100 0 0 10 0 + 3: 00000000000000000000000000000001:A696 00000000000000000000000000000001:0277 08 00000000:00000001 00:00000000 00000000 0 0 17035 1 0000000000000000 20 4 24 10 -1 + 4: 00000000000000000000000000000001:A69B 00000000000000000000000000000001:0277 09 00000000:00000001 00:00000000 00000000 1000 0 23248 1 0000000000000000 20 4 16 10 -1 + 5: 00000000000000000000000000000001:A697 00000000000000000000000000000001:0277 0A 00000000:00000001 00:00000000 00000000 0 0 12176 1 0000000000000000 20 4 24 10 -1 + 6: FEC0000000000000AA64000000000001:007B 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 109 0 59682 2 0000000000000000 100 0 0 10 0 + 7: 00000000000000000000000000000001:007C FE8000000000000002155DFFFE000402:007B 01 00000000:00000000 00:00000000 00000000 0 0 24746 2 0000000000000000 100 0 0 10 0 diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/udp-be b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/udp-be new file mode 100644 index 0000000000000..6a981a45a2766 --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/udp-be @@ -0,0 +1,13 @@ + sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops + 572: 00000000:8E15 00000000:0000 07 00000000:00000000 00:00000000 00000000 107 0 11207 2 0000000000000000 0 + 2320: 00000000:14E9 00000000:0000 07 00000000:00000000 00:00000000 00000000 107 0 11205 2 0000000000000000 0 + 2358: 00000000:B50F 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 21943 2 0000000000000000 0 + 5212: 7F000101:0035 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 17215 2 0000000000000000 0 + 5227: 00000000:0044 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 17211 2 0000000000000000 0 + 5296: 0A6983FF:0089 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 20035 2 0000000000000000 0 + 5296: 0A69803B:0089 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 20034 2 0000000000000000 0 + 5296: 00000000:0089 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 20031 2 0000000000000000 0 + 5297: 0A6983FF:008A 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 20037 2 0000000000000000 0 + 5297: 0A69803B:008A 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 20036 2 0000000000000000 0 + 5297: 00000000:008A 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 20032 2 0000000000000000 0 + 5790: 00000000:0277 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 16165 2 0000000000000000 0 diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/udp6-be b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/udp6-be new file mode 100644 index 0000000000000..046ed3bc3a192 --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkFiles/udp6-be @@ -0,0 +1,6 @@ + sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops + 2320: 00000000000000000000000000000000:14E9 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000 107 0 11206 2 0000000000000000 0 + 2810: 00000000000000000000000000000000:96D3 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 21944 2 0000000000000000 0 + 8063: 00000000000000000000000000000000:8B58 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000 107 0 11208 2 0000000000000000 0 + 9960: FEC0000000000000AA64000000000001:007B 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000 109 0 59682 2 0000000000000000 0 + 9961: FE8000000000000002155DFFFE000402:007B 00000000000000000000000000000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 24746 2 0000000000000000 0 diff --git a/src/libraries/System.Net.Primitives/src/System/Net/IPAddress.cs b/src/libraries/System.Net.Primitives/src/System/Net/IPAddress.cs index 66be8c8195bfd..d48c98e0e1632 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/IPAddress.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/IPAddress.cs @@ -17,12 +17,12 @@ namespace System.Net /// public class IPAddress { - public static readonly IPAddress Any = new ReadOnlyIPAddress(0x0000000000000000); - public static readonly IPAddress Loopback = new ReadOnlyIPAddress(0x000000000100007F); - public static readonly IPAddress Broadcast = new ReadOnlyIPAddress(0x00000000FFFFFFFF); + public static readonly IPAddress Any = new ReadOnlyIPAddress(new byte[] { 0, 0, 0, 0 }); + public static readonly IPAddress Loopback = new ReadOnlyIPAddress(new byte[] { 127, 0, 0, 1 }); + public static readonly IPAddress Broadcast = new ReadOnlyIPAddress(new byte[] { 255, 255, 255, 255 }); public static readonly IPAddress None = Broadcast; - internal const long LoopbackMask = 0x00000000000000FF; + internal const uint LoopbackMaskHostOrder = 0xFF000000; public static readonly IPAddress IPv6Any = new IPAddress(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0); public static readonly IPAddress IPv6Loopback = new IPAddress(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, 0); @@ -184,7 +184,7 @@ public IPAddress(ReadOnlySpan address) { if (address.Length == IPAddressParserStatics.IPv4AddressBytes) { - PrivateAddress = BinaryPrimitives.ReadUInt32LittleEndian(address); + PrivateAddress = MemoryMarshal.Read(address); } else if (address.Length == IPAddressParserStatics.IPv6AddressBytes) { @@ -290,10 +290,7 @@ private void WriteIPv6Bytes(Span destination) private void WriteIPv4Bytes(Span destination) { uint address = PrivateAddress; - destination[0] = (byte)(address); - destination[1] = (byte)(address >> 8); - destination[2] = (byte)(address >> 16); - destination[3] = (byte)(address >> 24); + MemoryMarshal.Write(destination, ref address); } /// @@ -431,6 +428,7 @@ public static bool IsLoopback(IPAddress address) } else { + long LoopbackMask = (uint)HostToNetworkOrder(unchecked((int)LoopbackMaskHostOrder)); return ((address.PrivateAddress & LoopbackMask) == (Loopback.PrivateAddress & LoopbackMask)); } } @@ -619,11 +617,11 @@ public IPAddress MapToIPv6() return this; } - uint address = PrivateAddress; + uint address = (uint)NetworkToHostOrder(unchecked((int)PrivateAddress)); ushort[] labels = new ushort[NumberOfLabels]; labels[5] = 0xFFFF; - labels[6] = (ushort)(((address & 0x0000FF00) >> 8) | ((address & 0x000000FF) << 8)); - labels[7] = (ushort)(((address & 0xFF000000) >> 24) | ((address & 0x00FF0000) >> 8)); + labels[6] = (ushort)(address >> 16); + labels[7] = (ushort)address; return new IPAddress(labels, 0); } @@ -637,13 +635,8 @@ public IPAddress MapToIPv4() return this; } - // Cast the ushort values to a uint and mask with unsigned literal before bit shifting. - // Otherwise, we can end up getting a negative value for any IPv4 address that ends with - // a byte higher than 127 due to sign extension of the most significant 1 bit. - long address = ((((uint)_numbers![6] & 0x0000FF00u) >> 8) | (((uint)_numbers[6] & 0x000000FFu) << 8)) | - (((((uint)_numbers[7] & 0x0000FF00u) >> 8) | (((uint)_numbers[7] & 0x000000FFu) << 8)) << 16); - - return new IPAddress(address); + uint address = (uint)_numbers![6] << 16 | (uint)_numbers[7]; + return new IPAddress((uint)HostToNetworkOrder(unchecked((int)address))); } [DoesNotReturn] @@ -651,7 +644,7 @@ public IPAddress MapToIPv4() private sealed class ReadOnlyIPAddress : IPAddress { - public ReadOnlyIPAddress(long newAddress) : base(newAddress) + public ReadOnlyIPAddress(byte[] newAddress) : base(newAddress) { } } } diff --git a/src/libraries/System.Net.Primitives/src/System/Net/IPAddressParser.cs b/src/libraries/System.Net.Primitives/src/System/Net/IPAddressParser.cs index f1c23cac89647..2cab1d597c51a 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/IPAddressParser.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/IPAddressParser.cs @@ -76,14 +76,15 @@ internal static unsafe bool IPv4AddressToString(uint address, Span formatt private static unsafe int IPv4AddressToStringHelper(uint address, char* addressString) { int offset = 0; + address = (uint)IPAddress.NetworkToHostOrder(unchecked((int)address)); - FormatIPv4AddressNumber((int)(address & 0xFF), addressString, ref offset); - addressString[offset++] = '.'; - FormatIPv4AddressNumber((int)((address >> 8) & 0xFF), addressString, ref offset); + FormatIPv4AddressNumber((int)((address >> 24) & 0xFF), addressString, ref offset); addressString[offset++] = '.'; FormatIPv4AddressNumber((int)((address >> 16) & 0xFF), addressString, ref offset); addressString[offset++] = '.'; - FormatIPv4AddressNumber((int)((address >> 24) & 0xFF), addressString, ref offset); + FormatIPv4AddressNumber((int)((address >> 8) & 0xFF), addressString, ref offset); + addressString[offset++] = '.'; + FormatIPv4AddressNumber((int)(address & 0xFF), addressString, ref offset); return offset; } @@ -179,9 +180,9 @@ public static unsafe bool Ipv4StringToAddress(ReadOnlySpan ipSpan, out lon if (tmpAddr != IPv4AddressHelper.Invalid && end == ipSpan.Length) { - // IPv4AddressHelper.ParseNonCanonical returns the bytes in the inverse order. - // Reverse them and return success. - address = BinaryPrimitives.ReverseEndianness((uint)tmpAddr); + // IPv4AddressHelper.ParseNonCanonical returns the bytes in host order. + // Convert to network order and return success. + address = (uint)IPAddress.HostToNetworkOrder(unchecked((int)tmpAddr)); return true; } else @@ -291,9 +292,10 @@ private static void AppendHex(ushort value, StringBuilder buffer) } /// Extracts the IPv4 address from the end of the IPv6 address byte array. - private static uint ExtractIPv4Address(ushort[] address) => (uint)(Reverse(address[7]) << 16) | Reverse(address[6]); - - /// Reverses the two bytes in the ushort. - private static ushort Reverse(ushort number) => (ushort)(((number >> 8) & 0xFF) | ((number << 8) & 0xFF00)); + private static uint ExtractIPv4Address(ushort[] address) + { + uint ipv4address = (uint)address[6] << 16 | (uint)address[7]; + return (uint)IPAddress.HostToNetworkOrder(unchecked((int)ipv4address)); + } } } diff --git a/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPAddressTest.cs b/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPAddressTest.cs index a72fed2d81867..584a219962138 100644 --- a/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPAddressTest.cs +++ b/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPAddressTest.cs @@ -48,13 +48,13 @@ private static IPAddress IPV6Address2() [Theory] [InlineData(MinAddress, new byte[] { 0, 0, 0, 0 })] [InlineData(MaxAddress, new byte[] { 0xFF, 0xFF, 0xFF, 0xFF })] - [InlineData(0x2414188f, new byte[] { 0x8f, 0x18, 0x14, 0x24 })] - [InlineData(0xFF, new byte[] { 0xFF, 0, 0, 0 })] - [InlineData(0xFF00FF, new byte[] { 0xFF, 0, 0xFF, 0 })] - [InlineData(0xFF00FF00, new byte[] { 0, 0xFF, 0, 0xFF })] + [InlineData(0x8f181424, new byte[] { 0x8f, 0x18, 0x14, 0x24 })] + [InlineData(0xFF000000, new byte[] { 0xFF, 0, 0, 0 })] + [InlineData(0xFF00FF00, new byte[] { 0xFF, 0, 0xFF, 0 })] + [InlineData(0x00FF00FF, new byte[] { 0, 0xFF, 0, 0xFF })] public static void Ctor_Long_Success(long address, byte[] expectedBytes) { - IPAddress ip = new IPAddress(address); + IPAddress ip = new IPAddress((uint)IPAddress.HostToNetworkOrder(unchecked((int)address))); Assert.Equal(expectedBytes, ip.GetAddressBytes()); Assert.Equal(AddressFamily.InterNetwork, ip.AddressFamily); } @@ -163,17 +163,34 @@ public static void HostToNetworkOrder_Compare_Equal() short s1 = (short)0x1350; short s2 = (short)0x5013; - Assert.Equal(l2, IPAddress.HostToNetworkOrder(l1)); - Assert.Equal(l4, IPAddress.HostToNetworkOrder(l3)); - Assert.Equal(i2, IPAddress.HostToNetworkOrder(i1)); - Assert.Equal(i4, IPAddress.HostToNetworkOrder(i3)); - Assert.Equal(s2, IPAddress.HostToNetworkOrder(s1)); - - Assert.Equal(l1, IPAddress.NetworkToHostOrder(l2)); - Assert.Equal(l3, IPAddress.NetworkToHostOrder(l4)); - Assert.Equal(i1, IPAddress.NetworkToHostOrder(i2)); - Assert.Equal(i3, IPAddress.NetworkToHostOrder(i4)); - Assert.Equal(s1, IPAddress.NetworkToHostOrder(s2)); + if (BitConverter.IsLittleEndian) + { + Assert.Equal(l2, IPAddress.HostToNetworkOrder(l1)); + Assert.Equal(l4, IPAddress.HostToNetworkOrder(l3)); + Assert.Equal(i2, IPAddress.HostToNetworkOrder(i1)); + Assert.Equal(i4, IPAddress.HostToNetworkOrder(i3)); + Assert.Equal(s2, IPAddress.HostToNetworkOrder(s1)); + + Assert.Equal(l1, IPAddress.NetworkToHostOrder(l2)); + Assert.Equal(l3, IPAddress.NetworkToHostOrder(l4)); + Assert.Equal(i1, IPAddress.NetworkToHostOrder(i2)); + Assert.Equal(i3, IPAddress.NetworkToHostOrder(i4)); + Assert.Equal(s1, IPAddress.NetworkToHostOrder(s2)); + } + else + { + Assert.Equal(l1, IPAddress.HostToNetworkOrder(l1)); + Assert.Equal(l3, IPAddress.HostToNetworkOrder(l3)); + Assert.Equal(i1, IPAddress.HostToNetworkOrder(i1)); + Assert.Equal(i3, IPAddress.HostToNetworkOrder(i3)); + Assert.Equal(s1, IPAddress.HostToNetworkOrder(s1)); + + Assert.Equal(l2, IPAddress.NetworkToHostOrder(l2)); + Assert.Equal(l4, IPAddress.NetworkToHostOrder(l4)); + Assert.Equal(i2, IPAddress.NetworkToHostOrder(i2)); + Assert.Equal(i4, IPAddress.NetworkToHostOrder(i4)); + Assert.Equal(s2, IPAddress.NetworkToHostOrder(s2)); + } } [Fact] diff --git a/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPEndPointTest.cs b/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPEndPointTest.cs index 8e00d00236ec6..bb9b95d438e99 100644 --- a/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPEndPointTest.cs +++ b/src/libraries/System.Net.Primitives/tests/FunctionalTests/IPEndPointTest.cs @@ -131,7 +131,7 @@ public static void Address_SetNull_ThrowsArgumentNullException() public static IEnumerable ToString_TestData() { - yield return new object[] { new IPEndPoint(2, 500), "2.0.0.0:500" }; + yield return new object[] { new IPEndPoint(IPAddress.HostToNetworkOrder(0x02000000), 500), "2.0.0.0:500" }; yield return new object[] { new IPEndPoint(IPAddress.Parse("192.169.0.9"), 500), "192.169.0.9:500" }; yield return new object[] { new IPEndPoint(IPAddress.Parse("0:0:0:0:0:0:0:1"), 500), "[::1]:500" }; } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs index 6f800064abad7..45754c012de58 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs @@ -1483,7 +1483,6 @@ public static unsafe SocketError GetSockOpt(SafeSocketHandle handle, SocketOptio { fixed (byte* pinnedValue = &optionValue[0]) { - Debug.Assert(BitConverter.IsLittleEndian, "Expected little endian"); *((int*)pinnedValue) = outError; } optionLength = sizeof(int);