mirror of
https://github.com/webbukkit/dynmap.git
synced 2024-11-13 05:54:40 +01:00
Add support for trusted-proxies subnet ranges, handle nested proxies
This commit is contained in:
parent
037d1803a7
commit
a9b4ace851
@ -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<Message> () {
|
||||
@Override
|
||||
|
@ -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<String> proxyaddress = new HashSet<String>();
|
||||
public ArrayList<IpAddressMatcher> proxyaddress = new ArrayList<IpAddressMatcher>();
|
||||
|
||||
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"));
|
||||
}
|
||||
|
100
DynmapCore/src/main/java/org/dynmap/utils/IpAddressMatcher.java
Normal file
100
DynmapCore/src/main/java/org/dynmap/utils/IpAddressMatcher.java
Normal file
@ -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.
|
||||
* <p>
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user