diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 938ac77..80bfbce 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -39,3 +39,22 @@ jobs: with: file: coverage.lcov format: lcov + + windows-net48: + name: Test net48 (Windows) + runs-on: windows-latest + + steps: + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.x + - name: Restore + run: dotnet restore ./src --verbosity m + - name: Build TestProject (net48) + run: dotnet build ./src/TestProject/TestProject.csproj -c Debug -f net48 --no-restore + - name: Run net48 tests against netstandard2.0 build + run: | + & .\src\TestProject\bin\Debug\net48\TestProject.exe + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } diff --git a/src/System.Net.IPNetwork/CidrNetworkAware.cs b/src/System.Net.IPNetwork/CidrNetworkAware.cs index 4b72711..3721044 100644 --- a/src/System.Net.IPNetwork/CidrNetworkAware.cs +++ b/src/System.Net.IPNetwork/CidrNetworkAware.cs @@ -69,13 +69,13 @@ public bool TryGuessCidr(string? ip, out byte cidr) // Reject if user passed a slash - this API expects a plain address. // (You can relax this if you want to honor an explicitly supplied prefix.) - if (ip.Contains('/')) + if (ip!.IndexOf('/') >= 0) return false; if (!IPAddress.TryParse(ip.Trim(), out var ipAddress)) return false; - switch (ipAddress.AddressFamily) + switch (ipAddress!.AddressFamily) { case AddressFamily.InterNetwork: cidr = GuessIpv4(ipAddress); diff --git a/src/System.Net.IPNetwork/IPNetwork2WideSubnet.cs b/src/System.Net.IPNetwork/IPNetwork2WideSubnet.cs index 5dbbb61..b99c809 100644 --- a/src/System.Net.IPNetwork/IPNetwork2WideSubnet.cs +++ b/src/System.Net.IPNetwork/IPNetwork2WideSubnet.cs @@ -141,7 +141,7 @@ internal static bool InternalWideSubnet(bool tryWide, IPNetwork2[] ipnetworks, [ IPNetwork2 nnin0 = nnin[0]; BigInteger uintNnin0 = nnin0.ipaddress; - IPNetwork2 nninX = nnin[^1]; + IPNetwork2 nninX = nnin[nnin.Length - 1]; IPAddress ipaddressX = nninX.Last; AddressFamily family = ipnetworks[0].family; diff --git a/src/System.Net.IPNetwork/Polyfills.cs b/src/System.Net.IPNetwork/Polyfills.cs new file mode 100644 index 0000000..47e5eb3 --- /dev/null +++ b/src/System.Net.IPNetwork/Polyfills.cs @@ -0,0 +1,15 @@ +// +// Copyright (c) IPNetwork. All rights reserved. +// + +#if NETSTANDARD2_0 +namespace System.Diagnostics.CodeAnalysis; + +[AttributeUsage(AttributeTargets.Parameter, Inherited = false)] +internal sealed class NotNullWhenAttribute : Attribute +{ + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + public bool ReturnValue { get; } +} +#endif diff --git a/src/System.Net.IPNetwork/System.Net.IPNetwork.csproj b/src/System.Net.IPNetwork/System.Net.IPNetwork.csproj index a4a22d3..d8a5c76 100644 --- a/src/System.Net.IPNetwork/System.Net.IPNetwork.csproj +++ b/src/System.Net.IPNetwork/System.Net.IPNetwork.csproj @@ -1,7 +1,7 @@  - net10.0;net9.0;net8.0;netstandard2.1 + net10.0;net9.0;net8.0;netstandard2.1;netstandard2.0 true IPNetwork2 4.0.0 diff --git a/src/System.Net.IPNetwork/UniqueLocalAddress.cs b/src/System.Net.IPNetwork/UniqueLocalAddress.cs index 293fecb..daf8178 100644 --- a/src/System.Net.IPNetwork/UniqueLocalAddress.cs +++ b/src/System.Net.IPNetwork/UniqueLocalAddress.cs @@ -179,7 +179,7 @@ private static byte[] GenerateGlobalIdFromMac(byte[] macAddress) byte[] timestamp = BitConverter.GetBytes(DateTimeOffset.UtcNow.ToUnixTimeSeconds()); Array.Copy(timestamp, 0, input, macAddress.Length, timestamp.Length); -#if NETSTANDARD2_1 +#if NETSTANDARD using var sha2 = SHA256.Create(); byte[] hash = sha2.ComputeHash(input); #else @@ -198,7 +198,7 @@ private static byte[] GenerateGlobalIdFromMac(byte[] macAddress) private static byte[] GenerateGlobalIdFromSeed(string seed) { byte[] seedBytes = Encoding.UTF8.GetBytes(seed); -#if NETSTANDARD2_1 +#if NETSTANDARD using var sha2 = SHA256.Create(); byte[] hash = sha2.ComputeHash(seedBytes); #else diff --git a/src/System.Net.IPNetwork/packages.lock.json b/src/System.Net.IPNetwork/packages.lock.json index ab2b1d3..4989b6e 100644 --- a/src/System.Net.IPNetwork/packages.lock.json +++ b/src/System.Net.IPNetwork/packages.lock.json @@ -1,6 +1,22 @@ { "version": 1, "dependencies": { + ".NETStandard,Version=v2.0": { + "NETStandard.Library": { + "type": "Direct", + "requested": "[2.0.3, )", + "resolved": "2.0.3", + "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + } + }, ".NETStandard,Version=v2.1": {}, "net10.0": {}, "net8.0": {}, diff --git a/src/TestProject/IPAddressExtensionTests.cs b/src/TestProject/IPAddressExtensionTests.cs index 4970af2..5e45732 100644 --- a/src/TestProject/IPAddressExtensionTests.cs +++ b/src/TestProject/IPAddressExtensionTests.cs @@ -98,7 +98,14 @@ e XOR'd with the byte count so the two sequences will be different. */ foreach (int _ in Enumerable.Range(1, 1000)) { /* Hash the current interation to get a new block of deterministic bytes. */ +#if NET5_0_OR_GREATER hashInput = SHA256.HashData(hashInput); +#else + using (var sha = SHA256.Create()) + { + hashInput = sha.ComputeHash(hashInput); + } +#endif /* Convert the first n bytes for an address. 4 will have an IPv4. 16 will make an IPv6. */ yield return new IPAddress(hashInput.Take(byteCount).ToArray()).ToString(); diff --git a/src/TestProject/TestProject.csproj b/src/TestProject/TestProject.csproj index 9c27055..948c3fd 100644 --- a/src/TestProject/TestProject.csproj +++ b/src/TestProject/TestProject.csproj @@ -1,7 +1,7 @@ - net10.0 + net10.0;net48 false True true @@ -16,6 +16,7 @@ 5 True true + Exe @@ -49,9 +50,14 @@ - + + + + + + diff --git a/src/TestProject/packages.lock.json b/src/TestProject/packages.lock.json index 5a5f402..19f703b 100644 --- a/src/TestProject/packages.lock.json +++ b/src/TestProject/packages.lock.json @@ -1,6 +1,216 @@ { "version": 1, "dependencies": { + ".NETFramework,Version=v4.8": { + "coverlet.collector": { + "type": "Direct", + "requested": "[10.0.0, )", + "resolved": "10.0.0", + "contentHash": "WFejCcOUR6k8UYyDnnR6Gk+obFYMsWrZuNqPJnsVFGVhpPSN0y20D4qbdKJnXinYGx9PQ397Hf9TnU1NBST8vA==" + }, + "coverlet.msbuild": { + "type": "Direct", + "requested": "[10.0.0, )", + "resolved": "10.0.0", + "contentHash": "pmUxktztlMnsIvgHjzxG3fHRAXpqmZSA+W8dIsbVMfwI01SnBndrBIOE3Stg6987+o7HjBa62C4q5um3Ia6d9g==" + }, + "Microsoft.CodeCoverage": { + "type": "Direct", + "requested": "[18.5.1, )", + "resolved": "18.5.1", + "contentHash": "vMFDR1ZjqzzgKmM0zrPie7Gv9Y+ZppjODB5Quzu9Eq0TlIusUfUCYFPEawO91zQuqwzvdFbJSU7WHNtjStffJQ==" + }, + "Microsoft.NET.Test.Sdk": { + "type": "Direct", + "requested": "[18.5.1, )", + "resolved": "18.5.1", + "contentHash": "SfqVaLiIqAbRWuPg5BP4QFwBIirQj/YIL8Dhxl6zntBKbXp0cQykoV480SmwG+yRMiWptxEI6NbHQuGSZ8b97w==", + "dependencies": { + "Microsoft.CodeCoverage": "18.5.1" + } + }, + "Microsoft.NETFramework.ReferenceAssemblies": { + "type": "Direct", + "requested": "[1.0.3, )", + "resolved": "1.0.3", + "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", + "dependencies": { + "Microsoft.NETFramework.ReferenceAssemblies.net48": "1.0.3" + } + }, + "MSTest.TestAdapter": { + "type": "Direct", + "requested": "[4.2.3, )", + "resolved": "4.2.3", + "contentHash": "oVV/luk0bBghnVvLaw8MwFlD7It0Cx9P2nKobeqIafmTQqFFWY69Wo801dxjeNaLzO/o9WQ84WSK84gXJuubhg==", + "dependencies": { + "MSTest.TestFramework": "4.2.3", + "Microsoft.Testing.Extensions.VSTestBridge": "2.2.3", + "Microsoft.Testing.Platform.MSBuild": "2.2.3", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "MSTest.TestFramework": { + "type": "Direct", + "requested": "[4.2.3, )", + "resolved": "4.2.3", + "contentHash": "9zzij59YLh+tf+FRLNqhzHjmdspR91bol+jdQxLlxxTGMAML6LDbvuyXKMGdcrE84+QpKkk6KjTVBC5PBGrDeA==", + "dependencies": { + "MSTest.Analyzers": "4.2.3" + } + }, + "NetArchTest.eNhancedEdition": { + "type": "Direct", + "requested": "[1.4.5, )", + "resolved": "1.4.5", + "contentHash": "dfWIjcLS2MBGz403OoT+vxr/4Dz/f7MnQhEwmgaf7PXlWzG39LSiUPhW7OPx9Ebg/GNWvDAttlpq5FY0mG/qkg==", + "dependencies": { + "Mono.Cecil": "0.11.6" + } + }, + "Newtonsoft.Json": { + "type": "Direct", + "requested": "[13.0.4, )", + "resolved": "13.0.4", + "contentHash": "pdgNNMai3zv51W5aq268sujXUyx7SNdE2bj1wZcWjAQrKMFZV260lbqYop1d2GM67JI1huLRwxo9ZqnfF/lC6A==" + }, + "Microsoft.ApplicationInsights": { + "type": "Transitive", + "resolved": "2.23.0", + "contentHash": "nWArUZTdU7iqZLycLKWe0TDms48KKGE6pONH2terYNa8REXiqixrMOkf1sk5DHGMaUTqONU2YkS4SAXBhLStgw==", + "dependencies": { + "System.Diagnostics.DiagnosticSource": "5.0.0" + } + }, + "Microsoft.NETFramework.ReferenceAssemblies.net48": { + "type": "Transitive", + "resolved": "1.0.3", + "contentHash": "zMk4D+9zyiEWByyQ7oPImPN/Jhpj166Ky0Nlla4eXlNL8hI/BtSJsgR8Inldd4NNpIAH3oh8yym0W2DrhXdSLQ==" + }, + "Microsoft.Testing.Extensions.Telemetry": { + "type": "Transitive", + "resolved": "2.2.3", + "contentHash": "mLdW+JOR3kXYGTdgR/qc/UZBA0r+eCR2k6bUxTcuDj5w9WdIQ7Lol5MBUU7YOSGd9bs9bvhSYWAptgz0YtQqCA==", + "dependencies": { + "Microsoft.ApplicationInsights": "2.23.0", + "Microsoft.Testing.Platform": "2.2.3", + "System.Diagnostics.DiagnosticSource": "6.0.0" + } + }, + "Microsoft.Testing.Extensions.TrxReport.Abstractions": { + "type": "Transitive", + "resolved": "2.2.3", + "contentHash": "hntvxJEkmUAx6C2xXc/PO38DqEQl4rimzOgSvTR1hAMruMid7R4RcXOrzzF33J66gKaN7jRaQ0TMW/nNfaV9jw==", + "dependencies": { + "Microsoft.Testing.Platform": "2.2.3" + } + }, + "Microsoft.Testing.Extensions.VSTestBridge": { + "type": "Transitive", + "resolved": "2.2.3", + "contentHash": "7WlJISO8QKUK+d+WhgnANwy4ACwUrvICnviY/mthPwjZ2gVeDaSUAeBnMy2cxfzZgm8VATtGUDbYzUxsgV2CyQ==", + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "18.3.0", + "Microsoft.Testing.Extensions.Telemetry": "2.2.3", + "Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.2.3", + "Microsoft.Testing.Platform": "2.2.3" + } + }, + "Microsoft.Testing.Platform": { + "type": "Transitive", + "resolved": "2.2.3", + "contentHash": "LhM1/Qoi8Ams5QcD4r3f09CSOono9iQr3NEJQItFtyzWB55nWTgEOsVqXqMWWWIwk3nkPqc+XfnlJmp8xUI5fg==" + }, + "Microsoft.Testing.Platform.MSBuild": { + "type": "Transitive", + "resolved": "2.2.3", + "contentHash": "Q22jJYJLx4srTinsAuoCskqmzjrBJC8YeGJMHHIcrf1dQeHoEZ7wsqDzTlENkMoke2qfufF7U+9u58nlZunH/Q==", + "dependencies": { + "Microsoft.Testing.Platform": "2.2.3" + } + }, + "Microsoft.TestPlatform.ObjectModel": { + "type": "Transitive", + "resolved": "18.3.0", + "contentHash": "AEIEX2aWdPO9XbtR96eBaJxmXRD9vaI9uQ1T/JbPEKlTAZwYx0ZrMzKyULMdh/HH9Sg03kXCoN7LszQ90o6nPQ==", + "dependencies": { + "System.Reflection.Metadata": "8.0.0" + } + }, + "Mono.Cecil": { + "type": "Transitive", + "resolved": "0.11.6", + "contentHash": "f33RkDtZO8VlGXCtmQIviOtxgnUdym9xx/b1p9h91CRGOsJFxCFOFK1FDbVt1OCf1aWwYejUFa2MOQyFWTFjbA==" + }, + "MSTest.Analyzers": { + "type": "Transitive", + "resolved": "4.2.3", + "contentHash": "dxOZt8/LWuiox7rugInJoIa5Mmu3pBmXdfaoZOx/mxx8+sUFFpjBXPlWXQXGeWzpkVPNC3x1Jf7rt2h2Zjyvvg==" + }, + "System.Buffers": { + "type": "Transitive", + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" + }, + "System.Collections.Immutable": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "frQDfv0rl209cKm1lnwTgFPzNigy2EKk1BS3uAvHvlBVKe5cymGyHO+Sj+NLv5VF/AhHsqPIUUwya5oV4CHMUw==", + "dependencies": { + "System.Memory": "4.5.4", + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.5", + "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "dependencies": { + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.5.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, + "System.Numerics.Vectors": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==", + "dependencies": { + "System.Collections.Immutable": "8.0.0", + "System.Memory": "4.5.5" + } + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "4.5.3" + } + }, + "IPNetwork2": { + "type": "Project" + } + }, "net10.0": { "coverlet.collector": { "type": "Direct",