Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions src/DefaultBuilder/src/ForwardedHeadersOptionsSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ public void Configure(ForwardedHeadersOptions options)
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
// Only loopback proxies are allowed by default. Clear that restriction because forwarders are
// being enabled by explicit configuration.
#pragma warning disable ASPDEPR005 // KnownNetworks is obsolete
options.KnownNetworks.Clear();
#pragma warning restore ASPDEPR005 // KnownNetworks is obsolete
options.KnownIPNetworks.Clear();
options.KnownProxies.Clear();
}
Expand Down
140 changes: 140 additions & 0 deletions src/Middleware/HttpOverrides/src/DualIPNetworkList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#pragma warning disable ASPDEPR005 // Type or member is obsolete

using AspNetIPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
using IPAddress = System.Net.IPAddress;
using IPNetwork = System.Net.IPNetwork;

namespace Microsoft.AspNetCore.Builder;

/// <summary>
/// Internal list implementation that keeps <see cref="System.Net.IPNetwork"/> and the obsolete
/// <see cref="Microsoft.AspNetCore.HttpOverrides.IPNetwork"/> collections in sync. Modifications
/// through either interface are reflected in the other.
/// </summary>
internal sealed class DualIPNetworkList : IList<IPNetwork>, IList<AspNetIPNetwork>
{
// Two independent underlying lists so each side behaves exactly like a List<T> with respect to
// enumeration versioning, capacity growth, etc. They are kept strictly in sync by all mutating operations.
private readonly List<IPNetwork> _system = new();
private readonly List<AspNetIPNetwork> _aspnet = new();

public DualIPNetworkList()
{
// Default entry (loopback) added to both representations.
var loopback = new IPNetwork(IPAddress.Loopback, 8);
_system.Add(loopback);
_aspnet.Add(new AspNetIPNetwork(loopback.BaseAddress, loopback.PrefixLength));
}

int ICollection<IPNetwork>.Count => _system.Count;
int ICollection<AspNetIPNetwork>.Count => _aspnet.Count;

bool ICollection<IPNetwork>.IsReadOnly => false;
bool ICollection<AspNetIPNetwork>.IsReadOnly => false;

IPNetwork IList<IPNetwork>.this[int index]
{
get => _system[index];
set
{
_system[index] = value;
_aspnet[index] = new AspNetIPNetwork(value.BaseAddress, value.PrefixLength);
}
}

AspNetIPNetwork IList<AspNetIPNetwork>.this[int index]
{
get => _aspnet[index];
set
{
_aspnet[index] = value;
_system[index] = new IPNetwork(value.Prefix, value.PrefixLength);
}
}

void ICollection<IPNetwork>.Add(IPNetwork item)
{
_system.Add(item);
_aspnet.Add(new AspNetIPNetwork(item.BaseAddress, item.PrefixLength));
}

void ICollection<AspNetIPNetwork>.Add(AspNetIPNetwork item)
{
_aspnet.Add(item);
_system.Add(new IPNetwork(item.Prefix, item.PrefixLength));
}

public void Clear()
{
_system.Clear();
_aspnet.Clear();
}

void ICollection<IPNetwork>.Clear() => Clear();
void ICollection<AspNetIPNetwork>.Clear() => Clear();

bool ICollection<IPNetwork>.Contains(IPNetwork item) => _system.Contains(item);
bool ICollection<AspNetIPNetwork>.Contains(AspNetIPNetwork item) => _aspnet.Contains(item);

public void CopyTo(IPNetwork[] array, int arrayIndex) => _system.CopyTo(array, arrayIndex);
public void CopyTo(AspNetIPNetwork[] array, int arrayIndex) => _aspnet.CopyTo(array, arrayIndex);

void ICollection<IPNetwork>.CopyTo(IPNetwork[] array, int arrayIndex) => CopyTo(array, arrayIndex);
void ICollection<AspNetIPNetwork>.CopyTo(AspNetIPNetwork[] array, int arrayIndex) => CopyTo(array, arrayIndex);

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => _system.GetEnumerator();

IEnumerator<IPNetwork> IEnumerable<IPNetwork>.GetEnumerator() => _system.GetEnumerator();
IEnumerator<AspNetIPNetwork> IEnumerable<AspNetIPNetwork>.GetEnumerator() => _aspnet.GetEnumerator();

int IList<IPNetwork>.IndexOf(IPNetwork item) => _system.IndexOf(item);
int IList<AspNetIPNetwork>.IndexOf(AspNetIPNetwork item) => _aspnet.IndexOf(item);

void IList<IPNetwork>.Insert(int index, IPNetwork item)
{
_system.Insert(index, item);
_aspnet.Insert(index, new AspNetIPNetwork(item.BaseAddress, item.PrefixLength));
}

void IList<AspNetIPNetwork>.Insert(int index, AspNetIPNetwork item)
{
_aspnet.Insert(index, item);
_system.Insert(index, new IPNetwork(item.Prefix, item.PrefixLength));
}

bool ICollection<IPNetwork>.Remove(IPNetwork item)
{
var idx = _system.IndexOf(item);
if (idx >= 0)
{
RemoveAt(idx);
return true;
}
return false;
}

bool ICollection<AspNetIPNetwork>.Remove(AspNetIPNetwork item)
{
var idx = _aspnet.IndexOf(item);
if (idx >= 0)
{
RemoveAt(idx);
return true;
}
return false;
}

public void RemoveAt(int index)
{
_system.RemoveAt(index);
_aspnet.RemoveAt(index);
}

void IList<IPNetwork>.RemoveAt(int index) => RemoveAt(index);
void IList<AspNetIPNetwork>.RemoveAt(int index) => RemoveAt(index);
}

#pragma warning restore ASPDEPR005 // Type or member is obsolete
15 changes: 1 addition & 14 deletions src/Middleware/HttpOverrides/src/ForwardedHeadersMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,7 @@ public void ApplyForwarders(HttpContext context)
// Host and Scheme initial values are never inspected, no need to set them here.
};

var checkKnownIps = _options.KnownIPNetworks.Count > 0
#pragma warning disable ASPDEPR005 // KnownNetworks is obsolete
|| _options.KnownNetworks.Count > 0
#pragma warning restore ASPDEPR005 // KnownNetworks is obsolete
|| _options.KnownProxies.Count > 0;
var checkKnownIps = _options.KnownIPNetworks.Count > 0 || _options.KnownProxies.Count > 0;
bool applyChanges = false;
int entriesConsumed = 0;

Expand Down Expand Up @@ -410,15 +406,6 @@ private bool CheckKnownAddress(IPAddress address)
return true;
}
}
#pragma warning disable ASPDEPR005 // KnownNetworks is obsolete
foreach (var network in _options.KnownNetworks)
{
if (network.Contains(address))
{
return true;
}
}
#pragma warning restore ASPDEPR005 // KnownNetworks is obsolete
return false;
}

Expand Down
8 changes: 6 additions & 2 deletions src/Middleware/HttpOverrides/src/ForwardedHeadersOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ namespace Microsoft.AspNetCore.Builder;
/// </summary>
public class ForwardedHeadersOptions
{
// Backing dual list that keeps the obsolete and new types in sync.
// Once the obsolete IList<IPNetwork> property is removed this can be changed to a simple List<IPNetwork>.
private readonly DualIPNetworkList _knownNetworks = new();

/// <summary>
/// Gets or sets the header used to retrieve the originating client IP. Defaults to the value specified by
/// <see cref="ForwardedHeadersDefaults.XForwardedForHeaderName"/>.
Expand Down Expand Up @@ -87,12 +91,12 @@ public class ForwardedHeadersOptions
/// Obsolete, please use <see cref="KnownIPNetworks"/> instead
/// </summary>
[Obsolete("Please use KnownIPNetworks instead. For more information, visit https://aka.ms/aspnet/deprecate/005.", DiagnosticId = "ASPDEPR005")]
public IList<AspNetIPNetwork> KnownNetworks { get; } = new List<AspNetIPNetwork>() { new(IPAddress.Loopback, 8) };
public IList<AspNetIPNetwork> KnownNetworks => _knownNetworks;

/// <summary>
/// Address ranges of known proxies to accept forwarded headers from.
/// </summary>
public IList<IPNetwork> KnownIPNetworks { get; } = new List<IPNetwork>() { new(IPAddress.Loopback, 8) };
public IList<IPNetwork> KnownIPNetworks => _knownNetworks;

/// <summary>
/// The allowed values from x-forwarded-host. If the list is empty then all hosts are allowed.
Expand Down
Loading
Loading