-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Obsolete Microsoft.AspNetCore.HttpOverrides.IPNetwork #62490
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 16 commits
8258d90
8bbc434
7372e0b
1e44ff7
7e5db2a
f71426d
7993c1f
996592b
2d015aa
6346519
21547f6
74be29f
61c9246
dfc068c
a0f13a0
4f63a58
1c2b21f
b74969e
f637aec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,204 +3,65 @@ | |
|
||
using System.Diagnostics.CodeAnalysis; | ||
using System.Net; | ||
using System.Net.Sockets; | ||
|
||
namespace Microsoft.AspNetCore.HttpOverrides; | ||
|
||
/// <summary> | ||
/// A representation of an IP network based on CIDR notation. | ||
/// </summary> | ||
[System.Obsolete("Please use System.Net.IPNetwork instead")] | ||
public class IPNetwork | ||
{ | ||
private readonly System.Net.IPNetwork _network; | ||
|
||
/// <summary> | ||
/// Create a new <see cref="IPNetwork"/> with the specified <see cref="IPAddress"/> and prefix length. | ||
/// </summary> | ||
/// <param name="prefix">The <see cref="IPAddress"/>.</param> | ||
/// <param name="prefixLength">The prefix length.</param> | ||
/// <exception cref="ArgumentOutOfRangeException"><paramref name="prefixLength"/> is out of range.</exception> | ||
public IPNetwork(IPAddress prefix, int prefixLength) : this(prefix, prefixLength, true) | ||
public IPNetwork(IPAddress prefix, int prefixLength) | ||
{ | ||
_network = new(prefix, prefixLength); | ||
} | ||
|
||
private IPNetwork(IPAddress prefix, int prefixLength, bool checkPrefixLengthRange) | ||
{ | ||
if (checkPrefixLengthRange && | ||
!IsValidPrefixLengthRange(prefix, prefixLength)) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(prefixLength), "The prefix length was out of range."); | ||
} | ||
|
||
Prefix = prefix; | ||
PrefixLength = prefixLength; | ||
PrefixBytes = Prefix.GetAddressBytes(); | ||
Mask = CreateMask(); | ||
} | ||
private IPNetwork(System.Net.IPNetwork network) => _network = network; | ||
|
||
/// <summary> | ||
/// Get the <see cref="IPAddress"/> that represents the prefix for the network. | ||
/// </summary> | ||
public IPAddress Prefix { get; } | ||
|
||
private byte[] PrefixBytes { get; } | ||
public IPAddress Prefix => _network.BaseAddress; | ||
|
||
/// <summary> | ||
/// The CIDR notation of the subnet mask | ||
/// </summary> | ||
public int PrefixLength { get; } | ||
|
||
private byte[] Mask { get; } | ||
public int PrefixLength => _network.PrefixLength; | ||
|
||
/// <summary> | ||
/// Determine whether a given The <see cref="IPAddress"/> is part of the IP network. | ||
/// </summary> | ||
/// <param name="address">The <see cref="IPAddress"/>.</param> | ||
/// <returns><see langword="true"/> if the <see cref="IPAddress"/> is part of the IP network. Otherwise, <see langword="false"/>.</returns> | ||
public bool Contains(IPAddress address) | ||
{ | ||
if (Prefix.AddressFamily != address.AddressFamily) | ||
{ | ||
return false; | ||
} | ||
|
||
var addressBytes = address.GetAddressBytes(); | ||
for (int i = 0; i < PrefixBytes.Length && Mask[i] != 0; i++) | ||
{ | ||
if ((PrefixBytes[i] & Mask[i]) != (addressBytes[i] & Mask[i])) | ||
{ | ||
return false; | ||
} | ||
} | ||
public bool Contains(IPAddress address) => _network.Contains(address); | ||
|
||
return true; | ||
} | ||
/// <inheritdoc cref="System.Net.IPNetwork.Parse(ReadOnlySpan{char})"/> | ||
public static IPNetwork Parse(ReadOnlySpan<char> networkSpan) => System.Net.IPNetwork.Parse(networkSpan); | ||
|
||
private byte[] CreateMask() | ||
{ | ||
var mask = new byte[PrefixBytes.Length]; | ||
int remainingBits = PrefixLength; | ||
int i = 0; | ||
while (remainingBits >= 8) | ||
{ | ||
mask[i] = 0xFF; | ||
i++; | ||
remainingBits -= 8; | ||
} | ||
if (remainingBits > 0) | ||
{ | ||
mask[i] = (byte)(0xFF << (8 - remainingBits)); | ||
} | ||
|
||
return mask; | ||
} | ||
|
||
private static bool IsValidPrefixLengthRange(IPAddress prefix, int prefixLength) | ||
{ | ||
if (prefixLength < 0) | ||
{ | ||
return false; | ||
} | ||
|
||
return prefix.AddressFamily switch | ||
{ | ||
AddressFamily.InterNetwork => prefixLength <= 32, | ||
AddressFamily.InterNetworkV6 => prefixLength <= 128, | ||
_ => true | ||
}; | ||
} | ||
|
||
/// <summary> | ||
/// Converts the specified <see cref="ReadOnlySpan{T}"/> of <see langword="char"/> representation of | ||
/// an IP address and a prefix length to its <see cref="IPNetwork"/> equivalent. | ||
/// </summary> | ||
/// <param name="networkSpan">The <see cref="ReadOnlySpan{T}"/> of <see langword="char"/> to convert, in CIDR notation.</param> | ||
/// <returns> | ||
///The <see cref="IPNetwork"/> equivalent to the IP address and prefix length contained in <paramref name="networkSpan"/>. | ||
/// </returns> | ||
/// <exception cref="FormatException"><paramref name="networkSpan"/> is not in the correct format.</exception> | ||
/// <exception cref="ArgumentOutOfRangeException">The prefix length contained in <paramref name="networkSpan"/> is out of range.</exception> | ||
/// <inheritdoc cref="TryParseComponents(ReadOnlySpan{char}, out IPAddress?, out int)"/> | ||
public static IPNetwork Parse(ReadOnlySpan<char> networkSpan) | ||
/// <inheritdoc cref="System.Net.IPNetwork.TryParse(ReadOnlySpan{char}, out System.Net.IPNetwork)"/> | ||
public static bool TryParse(ReadOnlySpan<char> networkSpan, [NotNullWhen(true)] out IPNetwork? network) | ||
{ | ||
if (!TryParseComponents(networkSpan, out var prefix, out var prefixLength)) | ||
{ | ||
throw new FormatException("An invalid IP address or prefix length was specified."); | ||
} | ||
|
||
if (!IsValidPrefixLengthRange(prefix, prefixLength)) | ||
if (System.Net.IPNetwork.TryParse(networkSpan, out var ipNetwork)) | ||
{ | ||
throw new ArgumentOutOfRangeException(nameof(networkSpan), "The prefix length was out of range."); | ||
network = ipNetwork; | ||
return true; | ||
} | ||
|
||
return new IPNetwork(prefix, prefixLength, false); | ||
network = null; | ||
return false; | ||
} | ||
|
||
/// <summary> | ||
/// Converts the specified <see cref="ReadOnlySpan{T}"/> of <see langword="char"/> representation of | ||
/// an IP address and a prefix length to its <see cref="IPNetwork"/> equivalent, and returns a value | ||
/// that indicates whether the conversion succeeded. | ||
/// Convert <see cref="System.Net.IPNetwork" /> to <see cref="Microsoft.AspNetCore.HttpOverrides.IPNetwork" /> implicitly | ||
/// </summary> | ||
/// <param name="networkSpan">The <see cref="ReadOnlySpan{T}"/> of <see langword="char"/> to validate.</param> | ||
/// <param name="network"> | ||
/// When this method returns, contains the <see cref="IPNetwork"/> equivalent to the IP Address | ||
/// and prefix length contained in <paramref name="networkSpan"/>, if the conversion succeeded, | ||
/// or <see langword="null"/> if the conversion failed. This parameter is passed uninitialized. | ||
/// </param> | ||
/// <returns> | ||
/// <see langword="true"/> if the <paramref name="networkSpan"/> parameter was | ||
/// converted successfully; otherwise <see langword="false"/>. | ||
/// </returns> | ||
/// <inheritdoc cref="TryParseComponents(ReadOnlySpan{char}, out IPAddress?, out int)"/> | ||
public static bool TryParse(ReadOnlySpan<char> networkSpan, [NotNullWhen(true)] out IPNetwork? network) | ||
{ | ||
network = null; | ||
|
||
if (!TryParseComponents(networkSpan, out var prefix, out var prefixLength)) | ||
{ | ||
return false; | ||
} | ||
|
||
if (!IsValidPrefixLengthRange(prefix, prefixLength)) | ||
{ | ||
return false; | ||
} | ||
|
||
network = new IPNetwork(prefix, prefixLength, false); | ||
return true; | ||
} | ||
|
||
/// <remarks> | ||
/// <para> | ||
/// The specified representation must be expressed using CIDR (Classless Inter-Domain Routing) notation, or 'slash notation', | ||
/// which contains an IPv4 or IPv6 address and the subnet mask prefix length, separated by a forward slash. | ||
/// </para> | ||
/// <example> | ||
/// e.g. <c>"192.168.0.1/31"</c> for IPv4, <c>"2001:db8:3c4d::1/127"</c> for IPv6 | ||
/// </example> | ||
/// </remarks> | ||
private static bool TryParseComponents( | ||
ReadOnlySpan<char> networkSpan, | ||
[NotNullWhen(true)] out IPAddress? prefix, | ||
out int prefixLength) | ||
{ | ||
prefix = null; | ||
prefixLength = default; | ||
|
||
var forwardSlashIndex = networkSpan.IndexOf('/'); | ||
if (forwardSlashIndex < 0) | ||
{ | ||
return false; | ||
} | ||
|
||
if (!IPAddress.TryParse(networkSpan.Slice(0, forwardSlashIndex), out prefix)) | ||
{ | ||
return false; | ||
} | ||
|
||
if (!int.TryParse(networkSpan.Slice(forwardSlashIndex + 1), out prefixLength)) | ||
{ | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
public static implicit operator IPNetwork(System.Net.IPNetwork ipNetwork) => new IPNetwork(ipNetwork); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need this? In general we try to stay away from implicit operators that allocate. What does this help? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trying to improve the experience when using a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is so users of Although, I think regardless this would be a binary breaking change because they'd still need to recompile to get the implicit operator? In which case, it's probably better to just not have the implicit operator and force them to use the new type. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,4 @@ | ||
#nullable enable | ||
*REMOVED*Microsoft.AspNetCore.Builder.ForwardedHeadersOptions.KnownNetworks.get -> System.Collections.Generic.IList<Microsoft.AspNetCore.HttpOverrides.IPNetwork!>! | ||
Microsoft.AspNetCore.Builder.ForwardedHeadersOptions.KnownNetworks.get -> System.Collections.Generic.IList<System.Net.IPNetwork>! | ||
static Microsoft.AspNetCore.HttpOverrides.IPNetwork.implicit operator Microsoft.AspNetCore.HttpOverrides.IPNetwork!(System.Net.IPNetwork ipNetwork) -> Microsoft.AspNetCore.HttpOverrides.IPNetwork! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change won't be necessary once the runtime is updated, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I think so, will revert in later update