diff --git a/java/org/apache/catalina/filters/RemoteIpFilter.java b/java/org/apache/catalina/filters/RemoteIpFilter.java
index 13a0eb7bf9b7..8781a470d298 100644
--- a/java/org/apache/catalina/filters/RemoteIpFilter.java
+++ b/java/org/apache/catalina/filters/RemoteIpFilter.java
@@ -21,6 +21,7 @@
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayDeque;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.Enumeration;
@@ -44,6 +45,7 @@
import org.apache.catalina.AccessLog;
import org.apache.catalina.Globals;
import org.apache.catalina.connector.RequestFacade;
+import org.apache.catalina.util.NetMask;
import org.apache.catalina.util.RequestUtil;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
@@ -667,6 +669,8 @@ public PushBuilder newPushBuilder() {
protected static final String INTERNAL_PROXIES_PARAMETER = "internalProxies";
+ protected static final String INTERNAL_PROXIES_MASKS_PARAMETER = "internalProxiesMasks";
+
// Log must be non-static as loggers are created per class-loader and this
// Filter may be used in multiple class loaders
private transient Log log = LogFactory.getLog(RemoteIpFilter.class);
@@ -690,6 +694,8 @@ public PushBuilder newPushBuilder() {
protected static final String TRUSTED_PROXIES_PARAMETER = "trustedProxies";
+ protected static final String TRUSTED_PROXIES_MASKS_PARAMETER = "trustedProxiesMasks";
+
protected static final String ENABLE_LOOKUPS_PARAMETER = "enableLookups";
/**
@@ -725,6 +731,11 @@ protected static String[] commaDelimitedListToStringArray(String commaDelimitedS
"172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" + "172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|" +
"172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}|" + "0:0:0:0:0:0:0:1|::1");
+ /**
+ * @see #setInternalProxiesMasks(String)
+ */
+ private List
+ * List of network masks defining the internal proxies.
+ * This value will be used if internalProxies is not defined
+ *
+ * Default value:
+ *
+ *
+ *
* Header that holds the incoming host, usually named X-Forwarded-Host
.
@@ -1292,6 +1376,23 @@ public void setTrustedProxies(String trustedProxies) {
}
}
+ /**
+ *
+ * List of network masks defining the trusted proxies. + * This value will be used if trustedProxies is not defined + *
+ * @param trustedProxiesMasks The list of network masks + */ + public void setTrustedProxiesMasks(String trustedProxiesMasks) { + if (trustedProxiesMasks == null || trustedProxiesMasks.length() == 0) { + this.trustedProxiesMasks = null; + } else { + this.trustedProxiesMasks = Arrays.stream(trustedProxiesMasks.split(",")) + .map(NetMask::new) + .toList(); + } + } + public void setEnableLookups(boolean enableLookups) { this.enableLookups = enableLookups; } diff --git a/test/org/apache/catalina/filters/TestRemoteIpFilter.java b/test/org/apache/catalina/filters/TestRemoteIpFilter.java index 82c8bb8f7948..ced733684a86 100644 --- a/test/org/apache/catalina/filters/TestRemoteIpFilter.java +++ b/test/org/apache/catalina/filters/TestRemoteIpFilter.java @@ -18,8 +18,11 @@ import java.io.IOException; import java.io.PrintWriter; +import java.io.UncheckedIOException; import java.net.HttpURLConnection; +import java.net.InetAddress; import java.net.URI; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -37,6 +40,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.apache.catalina.util.NetMask; import org.junit.Assert; import org.junit.Test; @@ -492,6 +496,40 @@ public void testInvokeAllProxiesAreTrustedOrInternal() throws Exception { Assert.assertEquals("remoteHost", "140.211.11.130", actualRemoteHost); } + @Test + public void testInvokeAllProxiesAreTrustedOrInternal_withNetMasks() throws Exception { + + // PREPARE + FilterDef filterDef = new FilterDef(); + filterDef.addInitParameter("internalProxiesMasks", "192.168.0.0/24,192.168.5.0/24"); + filterDef.addInitParameter("trustedProxiesMasks", "192.0.2.0/24,198.51.100.0/24"); + filterDef.addInitParameter("remoteIpHeader", "x-forwarded-for"); + filterDef.addInitParameter("proxiesHeader", "x-forwarded-by"); + + MockHttpServletRequest request = new MockHttpServletRequest(); + + request.setRemoteAddr("192.168.0.10"); + request.setRemoteHost("remote-host-original-value"); + request.setHeader("x-forwarded-for", "140.211.11.130, 192.0.2.50, 198.51.100.33, 192.168.0.100, 192.168.5.1"); + + // TEST + HttpServletRequest actualRequest = testRemoteIpFilter(filterDef, request).getRequest(); + + // VERIFY + String actualXForwardedFor = actualRequest.getHeader("x-forwarded-for"); + Assert.assertNull("all proxies are trusted, x-forwarded-for must be null", actualXForwardedFor); + + String actualXForwardedBy = actualRequest.getHeader("x-forwarded-by"); + Assert.assertEquals("all proxies are trusted, they must appear in x-forwarded-by", "192.0.2.50,198.51.100.33", + actualXForwardedBy); + + String actualRemoteAddr = actualRequest.getRemoteAddr(); + Assert.assertEquals("remoteAddr", "140.211.11.130", actualRemoteAddr); + + String actualRemoteHost = actualRequest.getRemoteHost(); + Assert.assertEquals("remoteHost", "140.211.11.130", actualRemoteHost); + } + @Test public void testInvokeNotAllowedRemoteAddr() throws Exception { // PREPARE @@ -868,4 +906,38 @@ private void doTestPattern(Pattern pattern, String input, boolean expectedMatch) boolean match = pattern.matcher(input).matches(); Assert.assertEquals(input, Boolean.valueOf(expectedMatch), Boolean.valueOf(match)); } + + @Test + public void testInternalProxiesMasks() { + RemoteIpFilter remoteIpFilter = new RemoteIpFilter(); + List