diff --git a/DynmapCore/src/main/java/org/dynmap/InternalClientUpdateComponent.java b/DynmapCore/src/main/java/org/dynmap/InternalClientUpdateComponent.java index 733f72e0..8ec8a463 100644 --- a/DynmapCore/src/main/java/org/dynmap/InternalClientUpdateComponent.java +++ b/DynmapCore/src/main/java/org/dynmap/InternalClientUpdateComponent.java @@ -5,6 +5,7 @@ import java.util.concurrent.ConcurrentHashMap; import org.dynmap.servlet.ClientUpdateServlet; import org.dynmap.servlet.SendMessageServlet; +import org.dynmap.utils.IpAddressMatcher; import org.json.simple.JSONObject; import static org.dynmap.JSONUtils.*; @@ -65,12 +66,12 @@ public class InternalClientUpdateComponent extends ClientUpdateComponent { this.core = dcore; if(trustedproxy != null) { for(String s : trustedproxy) { - this.proxyaddress.add(s.trim()); + this.proxyaddress.add(new IpAddressMatcher(s.trim())); } } else { - this.proxyaddress.add("127.0.0.1"); - this.proxyaddress.add("0:0:0:0:0:0:0:1"); + this.proxyaddress.add(new IpAddressMatcher("127.0.0.1")); + this.proxyaddress.add(new IpAddressMatcher("0:0:0:0:0:0:0:1")); } onMessageReceived.addListener(new Event.Listener () { @Override diff --git a/DynmapCore/src/main/java/org/dynmap/servlet/SendMessageServlet.java b/DynmapCore/src/main/java/org/dynmap/servlet/SendMessageServlet.java index cd20acdc..04f925f0 100644 --- a/DynmapCore/src/main/java/org/dynmap/servlet/SendMessageServlet.java +++ b/DynmapCore/src/main/java/org/dynmap/servlet/SendMessageServlet.java @@ -19,6 +19,7 @@ import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -26,6 +27,8 @@ import java.util.LinkedList; import java.util.List; import java.util.logging.Logger; +import org.dynmap.utils.IpAddressMatcher;; + @SuppressWarnings("serial") public class SendMessageServlet extends HttpServlet { protected static final Logger log = Logger.getLogger("Minecraft"); @@ -50,8 +53,16 @@ public class SendMessageServlet extends HttpServlet { public boolean chat_perms = false; public int lengthlimit = 256; public DynmapCore core; - public HashSet proxyaddress = new HashSet(); + public ArrayList proxyaddress = new ArrayList(); + private boolean trustedProxy(String ip) { + for (IpAddressMatcher m : proxyaddress) { + if (m.matches(ip)) { + return true; + } + } + return false; + } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { byte[] bytes; @@ -92,19 +103,13 @@ public class SendMessageServlet extends HttpServlet { if ((message.name == null) || message.name.equals("")) { /* If from trusted proxy, check for client */ String rmtaddr = request.getRemoteAddr(); - if (this.proxyaddress.contains(rmtaddr)) { + if (this.trustedProxy(rmtaddr)) { // If remote address is valid trusted proxy /* If proxied client address, get original IP */ if (request.getHeader("X-Forwarded-For") != null) { - /* If trusted proxies were chained, we get next client address till non-trusted proxy met */ - String[] proxyAddrs = request.getHeader("X-Forwarded-For").split(", "); - for(int i = proxyAddrs.length - 1; i >= 0; i--){ - if (!this.proxyaddress.contains(proxyAddrs[i])) { - /* use remaining addresses as name (maybe we can use the last or the first non-trusted one?) */ - message.name = proxyAddrs[0]; // 0 .. i - for(int j = 1; j <= i; j++) message.name += ", " + proxyAddrs[j]; - break; - } - } + // Split list, since addresses after first are proxy chain + String[] proxyAddrs = request.getHeader("X-Forwarded-For").split(","); + // We only want first - any others are proxies that our local proxy was willing to pass to us + message.name = proxyAddrs[0].trim(); } else { message.name = String.valueOf(o.get("name")); } diff --git a/DynmapCore/src/main/java/org/dynmap/utils/IpAddressMatcher.java b/DynmapCore/src/main/java/org/dynmap/utils/IpAddressMatcher.java new file mode 100644 index 00000000..9d82366c --- /dev/null +++ b/DynmapCore/src/main/java/org/dynmap/utils/IpAddressMatcher.java @@ -0,0 +1,100 @@ +package org.dynmap.utils; +/* + * Copyright 2002-2019 the original author or authors. + * + * Licensed 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 + * + * https://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. + */ + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * Matches a request based on IP Address or subnet mask matching against the remote + * address. + *

+ * Both IPv6 and IPv4 addresses are supported, but a matcher which is configured with an + * IPv4 address will never match a request which returns an IPv6 address, and vice-versa. + * + * @author Luke Taylor + * @since 3.0.2 + * + * Slightly modified by omidzk to have zero dependency to any frameworks other than the JRE. + */ +public final class IpAddressMatcher { + private final int nMaskBits; + private final InetAddress requiredAddress; + + /** + * Takes a specific IP address or a range specified using the IP/Netmask (e.g. + * 192.168.1.0/24 or 202.24.0.0/14). + * + * @param ipAddress the address or range of addresses from which the request must + * come. + */ + public IpAddressMatcher(String ipAddress) { + + if (ipAddress.indexOf('/') > 0) { + String[] addressAndMask = ipAddress.split("/"); + ipAddress = addressAndMask[0]; + nMaskBits = Integer.parseInt(addressAndMask[1]); + } + else { + nMaskBits = -1; + } + requiredAddress = parseAddress(ipAddress); + assert (requiredAddress.getAddress().length * 8 >= nMaskBits) : + String.format("IP address %s is too short for bitmask of length %d", + ipAddress, nMaskBits); + } + + public boolean matches(String address) { + InetAddress remoteAddress = parseAddress(address); + + if (!requiredAddress.getClass().equals(remoteAddress.getClass())) { + return false; + } + + if (nMaskBits < 0) { + return remoteAddress.equals(requiredAddress); + } + + byte[] remAddr = remoteAddress.getAddress(); + byte[] reqAddr = requiredAddress.getAddress(); + + int nMaskFullBytes = nMaskBits / 8; + byte finalByte = (byte) (0xFF00 >> (nMaskBits & 0x07)); + + // System.out.println("Mask is " + new sun.misc.HexDumpEncoder().encode(mask)); + + for (int i = 0; i < nMaskFullBytes; i++) { + if (remAddr[i] != reqAddr[i]) { + return false; + } + } + + if (finalByte != 0) { + return (remAddr[nMaskFullBytes] & finalByte) == (reqAddr[nMaskFullBytes] & finalByte); + } + + return true; + } + + private InetAddress parseAddress(String address) { + try { + return InetAddress.getByName(address); + } + catch (UnknownHostException e) { + throw new IllegalArgumentException("Failed to parse address" + address, e); + } + } +} diff --git a/fabric-1.14.4/src/main/resources/configuration.txt b/fabric-1.14.4/src/main/resources/configuration.txt index a618dd32..9889eaa3 100644 --- a/fabric-1.14.4/src/main/resources/configuration.txt +++ b/fabric-1.14.4/src/main/resources/configuration.txt @@ -391,6 +391,7 @@ grayplayerswhenhidden: true # X-Custom-Header-Of-Mine: "MyHeaderValue" # Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields +# This now supports both IP address, and subnet ranges (e.g. 192.168.1.0/24 or 202.24.0.0/14 ) trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" diff --git a/fabric-1.15.2/src/main/resources/configuration.txt b/fabric-1.15.2/src/main/resources/configuration.txt index 60fd3bed..fbf2a220 100644 --- a/fabric-1.15.2/src/main/resources/configuration.txt +++ b/fabric-1.15.2/src/main/resources/configuration.txt @@ -391,6 +391,7 @@ grayplayerswhenhidden: true # X-Custom-Header-Of-Mine: "MyHeaderValue" # Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields +# This now supports both IP address, and subnet ranges (e.g. 192.168.1.0/24 or 202.24.0.0/14 ) trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" diff --git a/fabric-1.16.4/src/main/resources/configuration.txt b/fabric-1.16.4/src/main/resources/configuration.txt index 83a3da83..41fefecf 100644 --- a/fabric-1.16.4/src/main/resources/configuration.txt +++ b/fabric-1.16.4/src/main/resources/configuration.txt @@ -399,6 +399,7 @@ grayplayerswhenhidden: true # X-Custom-Header-Of-Mine: "MyHeaderValue" # Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields +# This now supports both IP address, and subnet ranges (e.g. 192.168.1.0/24 or 202.24.0.0/14 ) trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" diff --git a/fabric-1.17.1/src/main/resources/configuration.txt b/fabric-1.17.1/src/main/resources/configuration.txt index 83a3da83..41fefecf 100644 --- a/fabric-1.17.1/src/main/resources/configuration.txt +++ b/fabric-1.17.1/src/main/resources/configuration.txt @@ -399,6 +399,7 @@ grayplayerswhenhidden: true # X-Custom-Header-Of-Mine: "MyHeaderValue" # Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields +# This now supports both IP address, and subnet ranges (e.g. 192.168.1.0/24 or 202.24.0.0/14 ) trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" diff --git a/fabric-1.18/src/main/resources/configuration.txt b/fabric-1.18/src/main/resources/configuration.txt index 61de127f..c0379e35 100644 --- a/fabric-1.18/src/main/resources/configuration.txt +++ b/fabric-1.18/src/main/resources/configuration.txt @@ -397,6 +397,7 @@ grayplayerswhenhidden: true # X-Custom-Header-Of-Mine: "MyHeaderValue" # Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields +# This now supports both IP address, and subnet ranges (e.g. 192.168.1.0/24 or 202.24.0.0/14 ) trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" diff --git a/forge-1.14.4/src/main/resources/configuration.txt b/forge-1.14.4/src/main/resources/configuration.txt index 5a76b049..4e9bec12 100644 --- a/forge-1.14.4/src/main/resources/configuration.txt +++ b/forge-1.14.4/src/main/resources/configuration.txt @@ -399,6 +399,7 @@ grayplayerswhenhidden: true # X-Custom-Header-Of-Mine: "MyHeaderValue" # Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields +# This now supports both IP address, and subnet ranges (e.g. 192.168.1.0/24 or 202.24.0.0/14 ) trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" diff --git a/forge-1.15.2/src/main/resources/configuration.txt b/forge-1.15.2/src/main/resources/configuration.txt index 5a76b049..4e9bec12 100644 --- a/forge-1.15.2/src/main/resources/configuration.txt +++ b/forge-1.15.2/src/main/resources/configuration.txt @@ -399,6 +399,7 @@ grayplayerswhenhidden: true # X-Custom-Header-Of-Mine: "MyHeaderValue" # Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields +# This now supports both IP address, and subnet ranges (e.g. 192.168.1.0/24 or 202.24.0.0/14 ) trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" diff --git a/forge-1.16.5/src/main/resources/configuration.txt b/forge-1.16.5/src/main/resources/configuration.txt index 09180111..748a4f77 100644 --- a/forge-1.16.5/src/main/resources/configuration.txt +++ b/forge-1.16.5/src/main/resources/configuration.txt @@ -399,6 +399,7 @@ grayplayerswhenhidden: true # X-Custom-Header-Of-Mine: "MyHeaderValue" # Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields +# This now supports both IP address, and subnet ranges (e.g. 192.168.1.0/24 or 202.24.0.0/14 ) trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" diff --git a/forge-1.17.1/src/main/resources/configuration.txt b/forge-1.17.1/src/main/resources/configuration.txt index 93ecb163..a41e9950 100644 --- a/forge-1.17.1/src/main/resources/configuration.txt +++ b/forge-1.17.1/src/main/resources/configuration.txt @@ -399,6 +399,7 @@ grayplayerswhenhidden: true # X-Custom-Header-Of-Mine: "MyHeaderValue" # Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields +# This now supports both IP address, and subnet ranges (e.g. 192.168.1.0/24 or 202.24.0.0/14 ) trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" diff --git a/forge-1.18/src/main/resources/configuration.txt b/forge-1.18/src/main/resources/configuration.txt index 09180111..748a4f77 100644 --- a/forge-1.18/src/main/resources/configuration.txt +++ b/forge-1.18/src/main/resources/configuration.txt @@ -399,6 +399,7 @@ grayplayerswhenhidden: true # X-Custom-Header-Of-Mine: "MyHeaderValue" # Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields +# This now supports both IP address, and subnet ranges (e.g. 192.168.1.0/24 or 202.24.0.0/14 ) trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1" diff --git a/spigot/src/main/resources/configuration.txt b/spigot/src/main/resources/configuration.txt index d8b39046..87b593fd 100644 --- a/spigot/src/main/resources/configuration.txt +++ b/spigot/src/main/resources/configuration.txt @@ -411,6 +411,7 @@ player-sort-permission-nodes: # X-Custom-Header-Of-Mine: "MyHeaderValue" # Trusted proxies for web server - which proxy addresses are trusted to supply valid X-Forwarded-For fields +# This now supports both IP address, and subnet ranges (e.g. 192.168.1.0/24 or 202.24.0.0/14 ) trusted-proxies: - "127.0.0.1" - "0:0:0:0:0:0:0:1"