diff --git a/src/AMWD.Common.AspNetCore/Attributes/IPAllowListAttribute.cs b/src/AMWD.Common.AspNetCore/Attributes/IPAllowListAttribute.cs
index 5db301a..db2c3d0 100644
--- a/src/AMWD.Common.AspNetCore/Attributes/IPAllowListAttribute.cs
+++ b/src/AMWD.Common.AspNetCore/Attributes/IPAllowListAttribute.cs
@@ -3,7 +3,12 @@ using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+
+#if NET10_0_OR_GREATER
+using IPNetwork = System.Net.IPNetwork;
+#else
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
+#endif
namespace Microsoft.AspNetCore.Mvc.Filters
{
diff --git a/src/AMWD.Common.AspNetCore/Attributes/IPBlockListAttribute.cs b/src/AMWD.Common.AspNetCore/Attributes/IPBlockListAttribute.cs
index 3b4ba29..dc3d847 100644
--- a/src/AMWD.Common.AspNetCore/Attributes/IPBlockListAttribute.cs
+++ b/src/AMWD.Common.AspNetCore/Attributes/IPBlockListAttribute.cs
@@ -3,7 +3,12 @@ using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+
+#if NET10_0_OR_GREATER
+using IPNetwork = System.Net.IPNetwork;
+#else
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
+#endif
namespace Microsoft.AspNetCore.Mvc.Filters
{
diff --git a/src/AMWD.Common.AspNetCore/Extensions/ApplicationBuilderExtensions.cs b/src/AMWD.Common.AspNetCore/Extensions/ApplicationBuilderExtensions.cs
index 293d7b1..9c0c96f 100644
--- a/src/AMWD.Common.AspNetCore/Extensions/ApplicationBuilderExtensions.cs
+++ b/src/AMWD.Common.AspNetCore/Extensions/ApplicationBuilderExtensions.cs
@@ -2,7 +2,12 @@
using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpOverrides;
+
+#if NET10_0_OR_GREATER
+using IPNetwork = System.Net.IPNetwork;
+#else
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
+#endif
namespace Microsoft.AspNetCore.Builder
{
@@ -19,9 +24,9 @@ namespace Microsoft.AspNetCore.Builder
/// A base path (e.g. running in a sub-directory /app) for the application can be defined via ASPNETCORE_APPL_PATH environment variable.
///
///
- /// Additionally you can specify the proxy server by using or a when there are multiple proxy servers.
+ /// Additionally you can specify the proxy server by using or a when there are multiple proxy servers.
///
- /// When neither nor is set, the default subnets are configured:
+ /// When neither nor is set, the default subnets are configured:
///
/// - 127.0.0.0/8
/// - ::1/128
@@ -32,49 +37,108 @@ namespace Microsoft.AspNetCore.Builder
/// - fd00::/8
///
///
- /// The application builder.
- /// The where proxy requests are received from (optional).
- /// The where proxy requests are received from (optional).
+ /// The application builder.
+ /// The where proxy requests are received from (optional).
+ /// The where proxy requests are received from (optional).
/// A custom base path (optional, ASPNETCORE_APPL_PATH is prefererred).
- public static IApplicationBuilder UseProxyHosting(this IApplicationBuilder app, IPNetwork network = null, IPAddress address = null, string basePath = null)
+#if NET10_0_OR_GREATER
+ public static IApplicationBuilder UseProxyHosting(this IApplicationBuilder appBuilder, IPNetwork? proxyNetwork = null, IPAddress proxyAddress = null, string basePath = null)
+#else
+
+ public static IApplicationBuilder UseProxyHosting(this IApplicationBuilder appBuilder, IPNetwork proxyNetwork = null, IPAddress proxyAddress = null, string basePath = null)
+#endif
{
- string path = Environment.GetEnvironmentVariable("ASPNETCORE_APPL_PATH");
- if (string.IsNullOrWhiteSpace(path))
- path = basePath;
+ string envPath = Environment.GetEnvironmentVariable("ASPNETCORE_APPL_PATH");
+ string envProxy = Environment.GetEnvironmentVariable("ASPNETCORE_APPL_PROXY");
- if (!string.IsNullOrWhiteSpace(path))
- app.UsePathBase(new PathString(path));
+ if (string.IsNullOrWhiteSpace(envPath))
+ envPath = basePath;
- var options = new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All };
- options.KnownProxies.Clear();
- options.KnownNetworks.Clear();
+ // Set PathBase from environment variable when available.
+ // This allows the application to be hosted behind a reverse proxy with a specific sub-path.
+ if (!string.IsNullOrWhiteSpace(envPath))
+ appBuilder.UsePathBase(new PathString(envPath));
- if (network == null && address == null)
+ // Configure Forwarded Headers to correctly handle reverse proxy scenarios.
+ var forwardedHeadersOptions = new ForwardedHeadersOptions
{
- // localhost
- options.KnownNetworks.Add(new IPNetwork(IPAddress.Loopback, 8));
- options.KnownNetworks.Add(new IPNetwork(IPAddress.IPv6Loopback, 128));
+ ForwardedHeaders = ForwardedHeaders.All
+ };
- // private IPv4 networks
- // see https://en.wikipedia.org/wiki/Private_network#Private_IPv4_addresses
- options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
- options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("172.16.0.0"), 12));
- options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("192.168.0.0"), 16));
+ // Reset KnownProxies and KnownNetworks to avoid default restrictions.
+ forwardedHeadersOptions.KnownProxies.Clear();
- // private IPv6 networks
- // see https://en.wikipedia.org/wiki/Private_network#Private_IPv6_addresses
- options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("fd00::"), 8));
+#if NET10_0_OR_GREATER
+ forwardedHeadersOptions.KnownIPNetworks.Clear();
+#else
+ forwardedHeadersOptions.KnownNetworks.Clear();
+#endif
+
+ // If no specific proxy address or network is provided, use environment variable or defaults.
+ if (proxyAddress == null && proxyNetwork == null)
+ {
+ if (string.IsNullOrWhiteSpace(envProxy))
+ {
+#if NET10_0_OR_GREATER
+ // Always trust localhost.
+ forwardedHeadersOptions.KnownIPNetworks.Add(IPNetwork.Parse("127.0.0.0/8"));
+ forwardedHeadersOptions.KnownIPNetworks.Add(IPNetwork.Parse("::1/128"));
+
+ // Trust common private network ranges.
+ forwardedHeadersOptions.KnownIPNetworks.Add(IPNetwork.Parse("10.0.0.0/8"));
+ forwardedHeadersOptions.KnownIPNetworks.Add(IPNetwork.Parse("172.16.0.0/12"));
+ forwardedHeadersOptions.KnownIPNetworks.Add(IPNetwork.Parse("192.168.0.0/16"));
+ forwardedHeadersOptions.KnownIPNetworks.Add(IPNetwork.Parse("fd00::/8"));
+#else
+ // Always trust localhost.
+ forwardedHeadersOptions.KnownNetworks.Add(IPNetwork.Parse("127.0.0.0/8"));
+ forwardedHeadersOptions.KnownNetworks.Add(IPNetwork.Parse("::1/128"));
+
+ // Trust common private network ranges.
+ forwardedHeadersOptions.KnownNetworks.Add(IPNetwork.Parse("10.0.0.0/8"));
+ forwardedHeadersOptions.KnownNetworks.Add(IPNetwork.Parse("172.16.0.0/12"));
+ forwardedHeadersOptions.KnownNetworks.Add(IPNetwork.Parse("192.168.0.0/16"));
+ forwardedHeadersOptions.KnownNetworks.Add(IPNetwork.Parse("fd00::/8"));
+#endif
+ }
+ else
+ {
+ // Try to parse proxies from environment variable.
+ string[] envProxies = envProxy.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
+ foreach (string proxy in envProxies)
+ {
+ if (IPAddress.TryParse(proxy, out var address))
+ {
+ forwardedHeadersOptions.KnownProxies.Add(address);
+ continue;
+ }
+
+ if (IPNetwork.TryParse(proxy, out var network))
+ {
+#if NET10_0_OR_GREATER
+ forwardedHeadersOptions.KnownIPNetworks.Add(network);
+#else
+ forwardedHeadersOptions.KnownNetworks.Add(network);
+#endif
+ continue;
+ }
+ }
+ }
}
- if (network != null)
- options.KnownNetworks.Add(network);
+ if (proxyAddress != null)
+ forwardedHeadersOptions.KnownProxies.Add(proxyAddress);
- if (address != null)
- options.KnownProxies.Add(address);
+#if NET10_0_OR_GREATER
+ if (proxyNetwork.HasValue)
+ forwardedHeadersOptions.KnownIPNetworks.Add(proxyNetwork.Value);
+#else
+ if (proxyNetwork != null)
+ forwardedHeadersOptions.KnownNetworks.Add(proxyNetwork);
+#endif
- app.UseForwardedHeaders(options);
-
- return app;
+ appBuilder.UseForwardedHeaders(forwardedHeadersOptions);
+ return appBuilder;
}
}
}