From 3d009158f2884c1de8d8f87c56e677e4f502d86b Mon Sep 17 00:00:00 2001 From: FVoronin Date: Sat, 3 Apr 2021 14:36:01 +0500 Subject: [PATCH] Fix IPNetwork.Contains behavior for prefixes which are not at start of subnet range --- src/Middleware/HttpOverrides/src/IPNetwork.cs | 26 +++++++++++++++++-- .../HttpOverrides/test/IPNetworkTest.cs | 12 +++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/Middleware/HttpOverrides/src/IPNetwork.cs b/src/Middleware/HttpOverrides/src/IPNetwork.cs index 9c5ff7591ed2..94fad9d2d850 100644 --- a/src/Middleware/HttpOverrides/src/IPNetwork.cs +++ b/src/Middleware/HttpOverrides/src/IPNetwork.cs @@ -1,7 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Net; +using System.Net.Sockets; namespace Microsoft.AspNetCore.HttpOverrides { @@ -17,6 +19,8 @@ public class IPNetwork /// The prefix length. public IPNetwork(IPAddress prefix, int prefixLength) { + CheckPrefixLengthRange(prefix, prefixLength); + Prefix = prefix; PrefixLength = prefixLength; PrefixBytes = Prefix.GetAddressBytes(); @@ -31,7 +35,7 @@ public IPNetwork(IPAddress prefix, int prefixLength) private byte[] PrefixBytes { get; } /// - /// The CIDR notation of the subnet mask + /// The CIDR notation of the subnet mask /// public int PrefixLength { get; } @@ -52,7 +56,7 @@ public bool Contains(IPAddress address) var addressBytes = address.GetAddressBytes(); for (int i = 0; i < PrefixBytes.Length && Mask[i] != 0; i++) { - if (PrefixBytes[i] != (addressBytes[i] & Mask[i])) + if ((PrefixBytes[i] & Mask[i]) != (addressBytes[i] & Mask[i])) { return false; } @@ -79,5 +83,23 @@ private byte[] CreateMask() return mask; } + + private static void CheckPrefixLengthRange(IPAddress prefix, int prefixLength) + { + if (prefixLength < 0) + { + throw new ArgumentOutOfRangeException(nameof(prefixLength)); + } + + if (prefix.AddressFamily == AddressFamily.InterNetwork && prefixLength > 32) + { + throw new ArgumentOutOfRangeException(nameof(prefixLength)); + } + + if (prefix.AddressFamily == AddressFamily.InterNetworkV6 && prefixLength > 128) + { + throw new ArgumentOutOfRangeException(nameof(prefixLength)); + } + } } } diff --git a/src/Middleware/HttpOverrides/test/IPNetworkTest.cs b/src/Middleware/HttpOverrides/test/IPNetworkTest.cs index cd5c37b906a9..4bd6aad4afb9 100644 --- a/src/Middleware/HttpOverrides/test/IPNetworkTest.cs +++ b/src/Middleware/HttpOverrides/test/IPNetworkTest.cs @@ -12,6 +12,15 @@ public class IPNetworkTest [InlineData("174.0.0.0", 7, "175.1.1.10")] [InlineData("10.174.0.0", 15, "10.175.1.10")] [InlineData("10.168.0.0", 14, "10.171.1.10")] + [InlineData("192.168.0.1", 31, "192.168.0.0")] + [InlineData("192.168.0.1", 31, "192.168.0.1")] + [InlineData("192.168.0.1", 32, "192.168.0.1")] + [InlineData("192.168.1.1", 0, "0.0.0.0")] + [InlineData("192.168.1.1", 0, "255.255.255.255")] + [InlineData("2001:db8:3c4d::", 127, "2001:db8:3c4d::1")] + [InlineData("2001:db8:3c4d::1", 128, "2001:db8:3c4d::1")] + [InlineData("2001:db8:3c4d::1", 0, "::")] + [InlineData("2001:db8:3c4d::1", 0, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")] public void Contains_Positive(string prefixText, int length, string addressText) { var network = new IPNetwork(IPAddress.Parse(prefixText), length); @@ -23,6 +32,9 @@ public void Contains_Positive(string prefixText, int length, string addressText) [InlineData("174.0.0.0", 7, "173.1.1.10")] [InlineData("10.174.0.0", 15, "10.173.1.10")] [InlineData("10.168.0.0", 14, "10.172.1.10")] + [InlineData("192.168.0.1", 31, "192.168.0.2")] + [InlineData("192.168.0.1", 32, "192.168.0.0")] + [InlineData("2001:db8:3c4d::", 127, "2001:db8:3c4d::2")] public void Contains_Negative(string prefixText, int length, string addressText) { var network = new IPNetwork(IPAddress.Parse(prefixText), length);