ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/catalina/valves/RemoteIpValve.java

Path
ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/catalina/valves/RemoteIpValve.java
Status
scanned
Type
file
Name
RemoteIpValve.java
Extension
.java
Programming language
Java
Mime type
text/html
File type
HTML document, ASCII text, with CRLF line terminators
Tag

      
    
Rootfs path

      
    
Size
36081 (35.2 KB)
MD5
4bc58a19a3f21facfe9d78dc75b83128
SHA1
d9b7d7f367217ebc9ab2e950c20458802b5da5f6
SHA256
4fd92b3a80cae54c87163260f4880166ac3ab471813b05653e34632416819600
SHA512

      
    
SHA1_git
96985b40876cd90afde6aefa3b0ae106b38c0e82
Is binary

      
    
Is text
True
Is archive

      
    
Is media

      
    
Is legal

      
    
Is manifest

      
    
Is readme

      
    
Is top level

      
    
Is key file

      
    
RemoteIpValve.java | 35.2 KB |

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.catalina.valves; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayDeque; import java.util.Deque; import java.util.Enumeration; import java.util.regex.Pattern; import jakarta.servlet.ServletException; import org.apache.catalina.AccessLog; import org.apache.catalina.Globals; import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Response; import org.apache.catalina.util.NetMaskSet; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.StringUtils; import org.apache.tomcat.util.http.MimeHeaders; import org.apache.tomcat.util.http.parser.Host; /** * <p> * Tomcat port of <a href="https://httpd.apache.org/docs/trunk/mod/mod_remoteip.html">mod_remoteip</a>, this valve * replaces the apparent client remote IP address and hostname for the request with the IP address list presented by a * proxy or a load balancer via a request headers (e.g. "X-Forwarded-For"). * </p> * <p> * Another feature of this valve is to replace the apparent scheme (http/https) and server port with the scheme * presented by a proxy or a load balancer via a request header (e.g. "X-Forwarded-Proto"). * </p> * <p> * This valve proceeds as follows: * </p> * <p> * If the incoming <code>request.getRemoteAddr()</code> matches the valve's list of internal or trusted proxies: * </p> * <ul> * <li>Loop on the comma-delimited list of IPs and hostnames passed by the preceding load balancer or proxy in the given * request's Http header named <code>$remoteIpHeader</code> (default value <code>x-forwarded-for</code>). Values are * processed in right-to-left order.</li> * <li>For each ip/host of the list: * <ul> * <li>if it matches the internal proxies list, the ip/host is swallowed</li> * <li>if it matches the trusted proxies list, the ip/host is added to the created proxies header</li> * <li>otherwise, the ip/host is declared to be the remote ip and looping is stopped.</li> * </ul> * </li> * <li>If the request http header named <code>$protocolHeader</code> (default value <code>X-Forwarded-Proto</code>) * consists only of forwards that match <code>protocolHeaderHttpsValue</code> configuration parameter (default * <code>https</code>) then <code>request.isSecure = true</code>, <code>request.scheme = https</code> and * <code>request.serverPort = 443</code>. Note that 443 can be overwritten with the <code>$httpsServerPort</code> * configuration parameter.</li> * <li>Mark the request with the attribute {@link Globals#REQUEST_FORWARDED_ATTRIBUTE} and value {@code Boolean.TRUE} to * indicate that this request has been forwarded by one or more proxies.</li> * </ul> * <table border="1"> * <caption>Configuration parameters</caption> * <tr> * <th>RemoteIpValve property</th> * <th>Description</th> * <th>Equivalent mod_remoteip directive</th> * <th>Format</th> * <th>Default Value</th> * </tr> * <tr> * <td>remoteIpHeader</td> * <td>Name of the Http Header read by this valve that holds the list of traversed IP addresses starting from the * requesting client</td> * <td>RemoteIPHeader</td> * <td>Compliant http header name</td> * <td>x-forwarded-for</td> * </tr> * <tr> * <td>internalProxies</td> * <td>Either a comma separated list of CIDR blocks or a single regular expression that matches the IP addresses of * internal proxies. If they appear in the <code>remoteIpHeader</code> value, they will be trusted and will not appear * in the <code>proxiesHeader</code> value</td> * <td>RemoteIPInternalProxy</td> * <td>Comma separated list of CIDR blocks or a single regular expression {@link Pattern}</td> * <td>10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16,100.64.0.0/10,127.0.0.0/8,::1/128,fe80::/10,fc00::/7</td> * </tr> * <tr> * <td>proxiesHeader</td> * <td>Name of the http header created by this valve to hold the list of proxies that have been processed in the * incoming <code>remoteIpHeader</code></td> * <td>proxiesHeader</td> * <td>Compliant http header name</td> * <td>x-forwarded-by</td> * </tr> * <tr> * <td>trustedProxies</td> * <td>Either a comma separated list of CIDR blocks or a single regular expression that matches the IP addresses of * internal proxies. If they appear in the <code>remoteIpHeader</code> value, they will be trusted and will appear in * the <code>proxiesHeader</code> value</td> * <td>RemoteIPTrustedProxy</td> * <td>Comma separated list of CIDR blocks or a single regular expression {@link Pattern}</td> * <td>&nbsp;</td> * </tr> * <tr> * <td>protocolHeader</td> * <td>Name of the http header read by this valve that holds the flag that this request</td> * <td>N/A</td> * <td>Compliant http header name like <code>X-Forwarded-Proto</code>, <code>X-Forwarded-Ssl</code> or * <code>Front-End-Https</code></td> * <td><code>X-Forwarded-Proto</code></td> * </tr> * <tr> * <td>protocolHeaderHttpsValue</td> * <td>Value of the <code>protocolHeader</code> to indicate that it is a Https request</td> * <td>N/A</td> * <td>String like <code>https</code> or <code>ON</code></td> * <td><code>https</code></td> * </tr> * <tr> * <td>httpServerPort</td> * <td>Value returned by {@link jakarta.servlet.ServletRequest#getServerPort()} when the <code>protocolHeader</code> * indicates <code>http</code> protocol</td> * <td>N/A</td> * <td>integer</td> * <td>80</td> * </tr> * <tr> * <td>httpsServerPort</td> * <td>Value returned by {@link jakarta.servlet.ServletRequest#getServerPort()} when the <code>protocolHeader</code> * indicates <code>https</code> protocol</td> * <td>N/A</td> * <td>integer</td> * <td>443</td> * </tr> * </table> * <p> * This Valve may be attached to any Container, depending on the granularity of the filtering you wish to perform. * </p> * <hr> * <p> * <strong>Sample with internal proxies</strong> * </p> * <p> * RemoteIpValve configuration: * </p> * <code> * &lt;Valve * className="org.apache.catalina.valves.RemoteIpValve" * internalProxies="192.168.0.10/31" * remoteIpHeader="x-forwarded-for" * proxiesHeader="x-forwarded-by" * protocolHeader="x-forwarded-proto" * /&gt;</code> * <table border="1"> * <caption>Request Values</caption> * <tr> * <th>property</th> * <th>Value Before RemoteIpValve</th> * <th>Value After RemoteIpValve</th> * </tr> * <tr> * <td>request.remoteAddr</td> * <td>192.168.0.10</td> * <td>140.211.11.130</td> * </tr> * <tr> * <td>request.header['x-forwarded-for']</td> * <td>140.211.11.130, 192.168.0.10</td> * <td>null</td> * </tr> * <tr> * <td>request.header['x-forwarded-by']</td> * <td>null</td> * <td>null</td> * </tr> * <tr> * <td>request.header['x-forwarded-proto']</td> * <td>https</td> * <td>https</td> * </tr> * <tr> * <td>request.scheme</td> * <td>http</td> * <td>https</td> * </tr> * <tr> * <td>request.secure</td> * <td>false</td> * <td>true</td> * </tr> * <tr> * <td>request.serverPort</td> * <td>80</td> * <td>443</td> * </tr> * </table> * <p> * Note : <code>x-forwarded-by</code> header is null because only internal proxies as been traversed by the request. * <code>x-forwarded-by</code> is null because all the proxies are trusted or internal. * </p> * <hr> * <p> * <strong>Sample with trusted proxies</strong> * </p> * <p> * RemoteIpValve configuration: * </p> * <code> * &lt;Valve * className="org.apache.catalina.valves.RemoteIpValve" * internalProxies="192.168.0.10/31" * remoteIpHeader="x-forwarded-for" * proxiesHeader="x-forwarded-by" * trustedProxies="proxy1|proxy2" * /&gt;</code> * <table border="1"> * <caption>Request Values</caption> * <tr> * <th>property</th> * <th>Value Before RemoteIpValve</th> * <th>Value After RemoteIpValve</th> * </tr> * <tr> * <td>request.remoteAddr</td> * <td>192.168.0.10</td> * <td>140.211.11.130</td> * </tr> * <tr> * <td>request.header['x-forwarded-for']</td> * <td>140.211.11.130, proxy1, proxy2</td> * <td>null</td> * </tr> * <tr> * <td>request.header['x-forwarded-by']</td> * <td>null</td> * <td>proxy1, proxy2</td> * </tr> * </table> * <p> * Note : <code>proxy1</code> and <code>proxy2</code> are both trusted proxies that come in <code>x-forwarded-for</code> * header, they both are migrated in <code>x-forwarded-by</code> header. <code>x-forwarded-by</code> is null because all * the proxies are trusted or internal. * </p> * <hr> * <p> * <strong>Sample with internal and trusted proxies</strong> * </p> * <p> * RemoteIpValve configuration: * </p> * <code> * &lt;Valve * className="org.apache.catalina.valves.RemoteIpValve" * internalProxies="192.168.0.10/31" * remoteIpHeader="x-forwarded-for" * proxiesHeader="x-forwarded-by" * trustedProxies="proxy1|proxy2" * /&gt;</code> * <table border="1"> * <caption>Request Values</caption> * <tr> * <th>property</th> * <th>Value Before RemoteIpValve</th> * <th>Value After RemoteIpValve</th> * </tr> * <tr> * <td>request.remoteAddr</td> * <td>192.168.0.10</td> * <td>140.211.11.130</td> * </tr> * <tr> * <td>request.header['x-forwarded-for']</td> * <td>140.211.11.130, proxy1, proxy2, 192.168.0.10</td> * <td>null</td> * </tr> * <tr> * <td>request.header['x-forwarded-by']</td> * <td>null</td> * <td>proxy1, proxy2</td> * </tr> * </table> * <p> * Note : <code>proxy1</code> and <code>proxy2</code> are both trusted proxies that come in <code>x-forwarded-for</code> * header, they both are migrated in <code>x-forwarded-by</code> header. As <code>192.168.0.10</code> is an internal * proxy, it does not appear in <code>x-forwarded-by</code>. <code>x-forwarded-by</code> is null because all the proxies * are trusted or internal. * </p> * <hr> * <p> * <strong>Sample with an untrusted proxy</strong> * </p> * <p> * RemoteIpValve configuration: * </p> * <code> * &lt;Valve * className="org.apache.catalina.valves.RemoteIpValve" * internalProxies="192.168.0.10/31" * remoteIpHeader="x-forwarded-for" * proxiesHeader="x-forwarded-by" * trustedProxies="proxy1|proxy2" * /&gt;</code> * <table border="1"> * <caption>Request Values</caption> * <tr> * <th>property</th> * <th>Value Before RemoteIpValve</th> * <th>Value After RemoteIpValve</th> * </tr> * <tr> * <td>request.remoteAddr</td> * <td>192.168.0.10</td> * <td>untrusted-proxy</td> * </tr> * <tr> * <td>request.header['x-forwarded-for']</td> * <td>140.211.11.130, untrusted-proxy, proxy1</td> * <td>140.211.11.130</td> * </tr> * <tr> * <td>request.header['x-forwarded-by']</td> * <td>null</td> * <td>proxy1</td> * </tr> * </table> * <p> * Note : <code>x-forwarded-by</code> holds the trusted proxy <code>proxy1</code>. <code>x-forwarded-by</code> holds * <code>140.211.11.130</code> because <code>untrusted-proxy</code> is not trusted and thus, we cannot trust that * <code>untrusted-proxy</code> is the actual remote ip. <code>request.remoteAddr</code> is <code>untrusted-proxy</code> * that is an IP verified by <code>proxy1</code>. * </p> */ public class RemoteIpValve extends ValveBase { private static final Log log = LogFactory.getLog(RemoteIpValve.class); private String hostHeader = null; private boolean changeLocalName = false; private int httpServerPort = 80; private int httpsServerPort = 443; private String portHeader = null; private boolean changeLocalPort = false; private Pattern internalProxiesRegex = null; private NetMaskSet internalProxiesCidr = NetMaskSet.parse("10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16,100.64.0.0/10,127.0.0.0/8," + "::1/128,fe80::/10,fc00::/7"); private String protocolHeader = "X-Forwarded-Proto"; private String protocolHeaderHttpsValue = "https"; private String proxiesHeader = "X-Forwarded-By"; private String remoteIpHeader = "X-Forwarded-For"; private boolean requestAttributesEnabled = true; private Pattern trustedProxiesRegex = null; private NetMaskSet trustedProxiesCidr = null; /** * Default constructor that ensures {@link ValveBase#ValveBase(boolean)} is called with <code>true</code>. */ public RemoteIpValve() { // Async requests are supported with this valve super(true); } /** * Obtain the name of the HTTP header used to override the value returned by {@link Request#getServerName()} and * (optionally depending on {link {@link #isChangeLocalName()} {@link Request#getLocalName()}. * * @return The HTTP header name */ public String getHostHeader() { return hostHeader; } /** * Set the name of the HTTP header used to override the value returned by {@link Request#getServerName()} and * (optionally depending on {link {@link #isChangeLocalName()} {@link Request#getLocalName()}. * * @param hostHeader The HTTP header name */ public void setHostHeader(String hostHeader) { this.hostHeader = hostHeader; } public boolean isChangeLocalName() { return changeLocalName; } public void setChangeLocalName(boolean changeLocalName) { this.changeLocalName = changeLocalName; } public int getHttpServerPort() { return httpServerPort; } public int getHttpsServerPort() { return httpsServerPort; } /** * Obtain the name of the HTTP header used to override the value returned by {@link Request#getServerPort()} and * (optionally depending on {link {@link #isChangeLocalPort()} {@link Request#getLocalPort()}. * * @return The HTTP header name */ public String getPortHeader() { return portHeader; } /** * Set the name of the HTTP header used to override the value returned by {@link Request#getServerPort()} and * (optionally depending on {link {@link #isChangeLocalPort()} {@link Request#getLocalPort()}. * * @param portHeader The HTTP header name */ public void setPortHeader(String portHeader) { this.portHeader = portHeader; } public boolean isChangeLocalPort() { return changeLocalPort; } public void setChangeLocalPort(boolean changeLocalPort) { this.changeLocalPort = changeLocalPort; } /** * Obtain the currently configured internal proxies. * * @return The currently configured internal proxies. */ public String getInternalProxies() { if (internalProxiesCidr != null) { return internalProxiesCidr.toString(); } else if (internalProxiesRegex != null) { return internalProxiesRegex.toString(); } else { return null; } } /** * @see #setProtocolHeader(String) * * @return the protocol header (e.g. "X-Forwarded-Proto") */ public String getProtocolHeader() { return protocolHeader; } /** * @see RemoteIpValve#setProtocolHeaderHttpsValue(String) * * @return the value of the protocol header for incoming https request (e.g. "https") */ public String getProtocolHeaderHttpsValue() { return protocolHeaderHttpsValue; } /** * @see #setProxiesHeader(String) * * @return the proxies header name (e.g. "X-Forwarded-By") */ public String getProxiesHeader() { return proxiesHeader; } /** * @see #setRemoteIpHeader(String) * * @return the remote IP header name (e.g. "X-Forwarded-For") */ public String getRemoteIpHeader() { return remoteIpHeader; } /** * @see #setRequestAttributesEnabled(boolean) * * @return <code>true</code> if the attributes will be logged, otherwise <code>false</code> */ public boolean getRequestAttributesEnabled() { return requestAttributesEnabled; } /** * Obtain the currently configured trusted proxies. * * @return The currently configured trusted proxies. */ public String getTrustedProxies() { if (trustedProxiesCidr != null) { return trustedProxiesCidr.toString(); } else if (trustedProxiesRegex != null) { return trustedProxiesRegex.toString(); } else { return null; } } @Override public void invoke(Request request, Response response) throws IOException, ServletException { final String originalRemoteAddr = request.getRemoteAddr(); final String originalRemoteHost = request.getRemoteHost(); final String originalScheme = request.getScheme(); final boolean originalSecure = request.isSecure(); final String originalServerName = request.getServerName(); final String originalLocalName = isChangeLocalName() ? request.getLocalName() : null; final int originalServerPort = request.getServerPort(); final int originalLocalPort = request.getLocalPort(); final String originalProxiesHeader = request.getHeader(proxiesHeader); final String originalRemoteIpHeader = request.getHeader(remoteIpHeader); boolean isInternal = isInternalProxy(originalRemoteAddr); if (isInternal || isTrustedProxy(originalRemoteAddr)) { String remoteIp = null; Deque<String> proxiesHeaderValue = new ArrayDeque<>(); StringBuilder concatRemoteIpHeaderValue = new StringBuilder(); for (Enumeration<String> e = request.getHeaders(remoteIpHeader); e.hasMoreElements();) { if (!concatRemoteIpHeaderValue.isEmpty()) { concatRemoteIpHeaderValue.append(", "); } concatRemoteIpHeaderValue.append(e.nextElement()); } String[] remoteIpHeaderValue = StringUtils.splitCommaSeparated(concatRemoteIpHeaderValue.toString()); int idx; if (!isInternal) { proxiesHeaderValue.addFirst(originalRemoteAddr); } // loop on remoteIpHeaderValue to find the first trusted remote ip and to build the proxies chain for (idx = remoteIpHeaderValue.length - 1; idx >= 0; idx--) { String currentRemoteIp = remoteIpHeaderValue[idx]; remoteIp = currentRemoteIp; if (isInternalProxy(currentRemoteIp)) { // do nothing, internalProxies IPs are not appended to the } else if (isTrustedProxy(currentRemoteIp)) { proxiesHeaderValue.addFirst(currentRemoteIp); } else { idx--; // decrement idx because break statement doesn't do it break; } } // continue to loop on remoteIpHeaderValue to build the new value of the remoteIpHeader Deque<String> newRemoteIpHeaderValue = new ArrayDeque<>(); for (; idx >= 0; idx--) { String currentRemoteIp = remoteIpHeaderValue[idx]; newRemoteIpHeaderValue.addFirst(currentRemoteIp); } if (remoteIp != null) { request.setRemoteAddr(remoteIp); if (request.getConnector().getEnableLookups()) { // This isn't a lazy lookup but that would be a little more // invasive - mainly in Request.getRemoteHost() - and if // enableLookups is true it seems reasonable that the // hotsname will be required so look it up here. try { InetAddress inetAddress = InetAddress.getByName(remoteIp); // We know we need a DNS look up so use getCanonicalHostName() request.setRemoteHost(inetAddress.getCanonicalHostName()); } catch (UnknownHostException e) { if (log.isDebugEnabled()) { log.debug(sm.getString("remoteIpValve.invalidRemoteAddress", remoteIp), e); } request.setRemoteHost(remoteIp); } } else { request.setRemoteHost(remoteIp); } if (proxiesHeaderValue.isEmpty()) { request.getCoyoteRequest().getMimeHeaders().removeHeader(proxiesHeader); } else { String commaDelimitedListOfProxies = StringUtils.join(proxiesHeaderValue); request.getCoyoteRequest().getMimeHeaders().setValue(proxiesHeader) .setString(commaDelimitedListOfProxies); } if (newRemoteIpHeaderValue.isEmpty()) { request.getCoyoteRequest().getMimeHeaders().removeHeader(remoteIpHeader); } else { String commaDelimitedRemoteIpHeaderValue = StringUtils.join(newRemoteIpHeaderValue); request.getCoyoteRequest().getMimeHeaders().setValue(remoteIpHeader) .setString(commaDelimitedRemoteIpHeaderValue); } } if (protocolHeader != null) { String protocolHeaderValue = request.getHeader(protocolHeader); if (protocolHeaderValue == null) { // Don't modify the secure, scheme and serverPort attributes // of the request } else if (isForwardedProtoHeaderValueSecure(protocolHeaderValue)) { request.setSecure(true); request.getCoyoteRequest().scheme().setString("https"); setPorts(request, httpsServerPort); } else { request.setSecure(false); request.getCoyoteRequest().scheme().setString("http"); setPorts(request, httpServerPort); } } if (hostHeader != null) { String hostHeaderValue = request.getHeader(hostHeader); if (hostHeaderValue != null) { try { int portIndex = Host.parse(hostHeaderValue); if (portIndex > -1) { log.debug(sm.getString("remoteIpValve.invalidHostWithPort", hostHeaderValue, hostHeader)); hostHeaderValue = hostHeaderValue.substring(0, portIndex); } request.getCoyoteRequest().serverName().setString(hostHeaderValue); if (isChangeLocalName()) { request.getCoyoteRequest().localName().setString(hostHeaderValue); } } catch (IllegalArgumentException iae) { log.debug(sm.getString("remoteIpValve.invalidHostHeader", hostHeaderValue, hostHeader), iae); } } } request.setAttribute(Globals.REQUEST_FORWARDED_ATTRIBUTE, Boolean.TRUE); if (log.isTraceEnabled()) { log.trace("Incoming request " + request.getRequestURI() + " with originalRemoteAddr [" + originalRemoteAddr + "], originalRemoteHost=[" + originalRemoteHost + "], originalSecure=[" + originalSecure + "], originalScheme=[" + originalScheme + "], originalServerName=[" + originalServerName + "], originalServerPort=[" + originalServerPort + "] will be seen as newRemoteAddr=[" + request.getRemoteAddr() + "], newRemoteHost=[" + request.getRemoteHost() + "], newSecure=[" + request.isSecure() + "], newScheme=[" + request.getScheme() + "], newServerName=[" + request.getServerName() + "], newServerPort=[" + request.getServerPort() + "]"); } } else { if (log.isTraceEnabled()) { log.trace("Skip RemoteIpValve for request " + request.getRequestURI() + " with originalRemoteAddr '" + request.getRemoteAddr() + "'"); } } if (requestAttributesEnabled) { request.setAttribute(AccessLog.REMOTE_ADDR_ATTRIBUTE, request.getRemoteAddr()); request.setAttribute(Globals.REMOTE_ADDR_ATTRIBUTE, request.getRemoteAddr()); request.setAttribute(AccessLog.REMOTE_HOST_ATTRIBUTE, request.getRemoteHost()); request.setAttribute(AccessLog.PROTOCOL_ATTRIBUTE, request.getProtocol()); request.setAttribute(AccessLog.SERVER_NAME_ATTRIBUTE, request.getServerName()); request.setAttribute(AccessLog.SERVER_PORT_ATTRIBUTE, Integer.valueOf(request.getServerPort())); } try { getNext().invoke(request, response); } finally { if (!request.isAsync()) { request.setRemoteAddr(originalRemoteAddr); request.setRemoteHost(originalRemoteHost); request.setSecure(originalSecure); request.getCoyoteRequest().scheme().setString(originalScheme); request.getCoyoteRequest().serverName().setString(originalServerName); if (isChangeLocalName()) { request.getCoyoteRequest().localName().setString(originalLocalName); } request.setServerPort(originalServerPort); request.setLocalPort(originalLocalPort); MimeHeaders headers = request.getCoyoteRequest().getMimeHeaders(); if (originalProxiesHeader == null || originalProxiesHeader.isEmpty()) { headers.removeHeader(proxiesHeader); } else { headers.setValue(proxiesHeader).setString(originalProxiesHeader); } if (originalRemoteIpHeader == null || originalRemoteIpHeader.isEmpty()) { headers.removeHeader(remoteIpHeader); } else { headers.setValue(remoteIpHeader).setString(originalRemoteIpHeader); } } } } /** * Checks if the given IP address is from an internal proxy. * * @param remoteIp The IP address to check * * @return {@code true} if the IP address is from an internal proxy, otherwise {@code false} */ private boolean isInternalProxy(String remoteIp) { if (internalProxiesRegex != null && internalProxiesRegex.matcher(remoteIp).matches()) { return true; } return checkIsCidr(internalProxiesCidr, remoteIp); } /** * Checks if the given IP address is from a trusted proxy. * * @param remoteIp The IP address to check * * @return {@code true} if the IP address is from a trusted proxy, otherwise {@code false} */ private boolean isTrustedProxy(String remoteIp) { if (trustedProxiesRegex != null && trustedProxiesRegex.matcher(remoteIp).matches()) { return true; } return checkIsCidr(trustedProxiesCidr, remoteIp); } private boolean checkIsCidr(NetMaskSet netMaskSet, String remoteIp) { if (netMaskSet == null) { return false; } try { return netMaskSet.contains(remoteIp); } catch (UnknownHostException uhe) { log.debug(sm.getString("remoteIpFilter.invalidRemoteAddress", remoteIp), uhe); } return false; } /* * Considers the value to be secure if it exclusively holds forwards for {@link #protocolHeaderHttpsValue}. */ private boolean isForwardedProtoHeaderValueSecure(String protocolHeaderValue) { if (!protocolHeaderValue.contains(",")) { return protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue); } String[] forwardedProtocols = StringUtils.splitCommaSeparated(protocolHeaderValue); if (forwardedProtocols.length == 0) { return false; } for (String forwardedProtocol : forwardedProtocols) { if (!protocolHeaderHttpsValue.equalsIgnoreCase(forwardedProtocol)) { return false; } } return true; } private void setPorts(Request request, int defaultPort) { int port = defaultPort; if (portHeader != null) { String portHeaderValue = request.getHeader(portHeader); if (portHeaderValue != null) { try { port = Integer.parseInt(portHeaderValue); } catch (NumberFormatException nfe) { if (log.isDebugEnabled()) { log.debug(sm.getString("remoteIpValve.invalidPortHeader", portHeaderValue, portHeader), nfe); } } } } request.setServerPort(port); if (changeLocalPort) { request.setLocalPort(port); } } /** * <p> * Server Port value if the {@link #protocolHeader} is not <code>null</code> and does not indicate HTTP * </p> * <p> * Default value : 80 * </p> * * @param httpServerPort The server port */ public void setHttpServerPort(int httpServerPort) { this.httpServerPort = httpServerPort; } /** * <p> * Server Port value if the {@link #protocolHeader} indicates HTTPS * </p> * <p> * Default value : 443 * </p> * * @param httpsServerPort The server port */ public void setHttpsServerPort(int httpsServerPort) { this.httpsServerPort = httpsServerPort; } /** * Set the internal proxies either as a comma separated list of CIDR blocks or a single regular expression. * * @param internalProxies The new internal proxies */ public void setInternalProxies(String internalProxies) { if (internalProxies == null || internalProxies.isEmpty()) { this.internalProxiesRegex = null; this.internalProxiesCidr = null; } else if (internalProxies.indexOf('/') > 0) { this.internalProxiesRegex = null; this.internalProxiesCidr = NetMaskSet.parse(internalProxies); } else { this.internalProxiesRegex = Pattern.compile(internalProxies); this.internalProxiesCidr = null; } } /** * <p> * Header that holds the incoming protocol, usually named <code>X-Forwarded-Proto</code>. If <code>null</code>, * request.scheme and request.secure will not be modified. * </p> * <p> * Default value : <code>X-Forwarded-Proto</code> * </p> * * @param protocolHeader The header name */ public void setProtocolHeader(String protocolHeader) { this.protocolHeader = protocolHeader; } /** * <p> * Case-insensitive value of the protocol header to indicate that the incoming http request uses SSL. * </p> * <p> * Default value : <code>https</code> * </p> * * @param protocolHeaderHttpsValue The header name */ public void setProtocolHeaderHttpsValue(String protocolHeaderHttpsValue) { this.protocolHeaderHttpsValue = protocolHeaderHttpsValue; } /** * <p> * The proxiesHeader directive specifies a header into which mod_remoteip will collect a list of all of the * intermediate client IP addresses trusted to resolve the actual remote IP. Note that intermediate * RemoteIPTrustedProxy addresses are recorded in this header, while any intermediate RemoteIPInternalProxy * addresses are discarded. * </p> * <p> * Name of the http header that holds the list of trusted proxies that has been traversed by the http request. * </p> * <p> * The value of this header can be comma-delimited. * </p> * <p> * Default value : <code>X-Forwarded-By</code> * </p> * * @param proxiesHeader The header name */ public void setProxiesHeader(String proxiesHeader) { this.proxiesHeader = proxiesHeader; } /** * <p> * Name of the http header from which the remote ip is extracted. * </p> * <p> * The value of this header can be comma-delimited. * </p> * <p> * Default value : <code>X-Forwarded-For</code> * </p> * * @param remoteIpHeader The header name */ public void setRemoteIpHeader(String remoteIpHeader) { this.remoteIpHeader = remoteIpHeader; } /** * Should this valve set request attributes for IP address, Hostname, protocol and port used for the request? These * are typically used in conjunction with the {@link AccessLog} which will otherwise log the original values. * Default is <code>true</code>. The attributes set are: * <ul> * <li>org.apache.catalina.AccessLog.RemoteAddr</li> * <li>org.apache.catalina.AccessLog.RemoteHost</li> * <li>org.apache.catalina.AccessLog.Protocol</li> * <li>org.apache.catalina.AccessLog.ServerPort</li> * <li>org.apache.tomcat.remoteAddr</li> * </ul> * * @param requestAttributesEnabled <code>true</code> causes the attributes to be set, <code>false</code> disables * the setting of the attributes. */ public void setRequestAttributesEnabled(boolean requestAttributesEnabled) { this.requestAttributesEnabled = requestAttributesEnabled; } /** * Set the trusted proxies either as a comma separated list of CIDR blocks or a single regular expression. * * @param trustedProxies The new trusted proxies */ public void setTrustedProxies(String trustedProxies) { if (trustedProxies == null || trustedProxies.isEmpty()) { this.trustedProxiesRegex = null; this.trustedProxiesCidr = null; } else if (trustedProxies.indexOf('/') > 0) { this.trustedProxiesRegex = null; this.trustedProxiesCidr = NetMaskSet.parse(trustedProxies); } else { this.trustedProxiesCidr = null; this.trustedProxiesRegex = Pattern.compile(trustedProxies); } } }
Detected license expression
apache-2.0
Detected license expression (SPDX)
Apache-2.0
Percentage of license text
3.65
Copyrights

      
    
Holders

      
    
Authors

      
    
License detections License expression License expression SPDX
apache_2_0-4bde3f57-78aa-4201-96bf-531cba09e7de apache-2.0 Apache-2.0
URL Start line End line
http://www.apache.org/licenses/LICENSE-2.0 9 9
https://httpd.apache.org/docs/trunk/mod/mod_remoteip.html 42 42