added rate limiting, added connections per ip limit
This commit is contained in:
parent
f26e1b8f6d
commit
7e3aee8699
|
@ -20,12 +20,14 @@ public class EaglerSPClient {
|
||||||
public final long createdOn;
|
public final long createdOn;
|
||||||
public boolean serverNotifiedOfClose = false;
|
public boolean serverNotifiedOfClose = false;
|
||||||
public LoginState state = LoginState.INIT;
|
public LoginState state = LoginState.INIT;
|
||||||
|
public final String address;
|
||||||
|
|
||||||
EaglerSPClient(WebSocket sock, EaglerSPServer srv, String id) {
|
EaglerSPClient(WebSocket sock, EaglerSPServer srv, String id, String addr) {
|
||||||
this.socket = sock;
|
this.socket = sock;
|
||||||
this.server = srv;
|
this.server = srv;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.createdOn = System.currentTimeMillis();
|
this.createdOn = System.currentTimeMillis();
|
||||||
|
this.address = addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void send(IPacket packet) {
|
public void send(IPacket packet) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.java_websocket.WebSocket;
|
||||||
import org.java_websocket.handshake.ClientHandshake;
|
import org.java_websocket.handshake.ClientHandshake;
|
||||||
import org.java_websocket.server.WebSocketServer;
|
import org.java_websocket.server.WebSocketServer;
|
||||||
|
|
||||||
|
import net.lax1dude.eaglercraft.sp.relay.RateLimiter.RateLimit;
|
||||||
import net.lax1dude.eaglercraft.sp.relay.pkt.*;
|
import net.lax1dude.eaglercraft.sp.relay.pkt.*;
|
||||||
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds.LocalWorld;
|
import net.lax1dude.eaglercraft.sp.relay.pkt.IPacket07LocalWorlds.LocalWorld;
|
||||||
|
|
||||||
|
@ -26,6 +27,9 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
public static EaglerSPRelay instance;
|
public static EaglerSPRelay instance;
|
||||||
public static final EaglerSPRelayConfig config = new EaglerSPRelayConfig();
|
public static final EaglerSPRelayConfig config = new EaglerSPRelayConfig();
|
||||||
|
|
||||||
|
private static RateLimiter pingRateLimiter = null;
|
||||||
|
private static RateLimiter worldRateLimiter = null;
|
||||||
|
|
||||||
public static final DebugLogger logger = DebugLogger.getLogger("EaglerSPRelay");
|
public static final DebugLogger logger = DebugLogger.getLogger("EaglerSPRelay");
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException, InterruptedException {
|
public static void main(String[] args) throws IOException, InterruptedException {
|
||||||
|
@ -35,9 +39,24 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
logger.debug("Debug logging enabled");
|
logger.debug("Debug logging enabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Starting EaglerSPRelay version {}...", Constants.versionName);
|
logger.info("Starting EaglerSPRelay version {}...", Constants.versionName);
|
||||||
config.load(new File("relayConfig.ini"));
|
config.load(new File("relayConfig.ini"));
|
||||||
|
|
||||||
|
if(config.isPingRateLimitEnable()) {
|
||||||
|
pingRateLimiter = new RateLimiter(config.getPingRateLimitPeriod() * 1000,
|
||||||
|
config.getPingRateLimitLimit(), config.getPingRateLimitLockoutLimit(),
|
||||||
|
config.getPingRateLimitLockoutDuration() * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(config.isWorldRateLimitEnable()) {
|
||||||
|
worldRateLimiter = new RateLimiter(config.getWorldRateLimitPeriod() * 1000,
|
||||||
|
config.getWorldRateLimitLimit(), config.getWorldRateLimitLockoutLimit(),
|
||||||
|
config.getWorldRateLimitLockoutDuration() * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
EaglerSPRelayConfigRelayList.loadRelays(new File("relays.txt"));
|
EaglerSPRelayConfigRelayList.loadRelays(new File("relays.txt"));
|
||||||
|
|
||||||
logger.info("Starting WebSocket Server...");
|
logger.info("Starting WebSocket Server...");
|
||||||
instance = new EaglerSPRelay(new InetSocketAddress(config.getAddress(), config.getPort()));
|
instance = new EaglerSPRelay(new InetSocketAddress(config.getAddress(), config.getPort()));
|
||||||
instance.setConnectionLostTimeout(20);
|
instance.setConnectionLostTimeout(20);
|
||||||
|
@ -45,6 +64,7 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
instance.start();
|
instance.start();
|
||||||
|
|
||||||
Thread tickThread = new Thread((() -> {
|
Thread tickThread = new Thread((() -> {
|
||||||
|
int rateLimitUpdateCounter = 0;
|
||||||
while(true) {
|
while(true) {
|
||||||
try {
|
try {
|
||||||
long millis = System.currentTimeMillis();
|
long millis = System.currentTimeMillis();
|
||||||
|
@ -52,7 +72,7 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
Iterator<Entry<WebSocket,PendingConnection>> itr = pendingConnections.entrySet().iterator();
|
Iterator<Entry<WebSocket,PendingConnection>> itr = pendingConnections.entrySet().iterator();
|
||||||
while(itr.hasNext()) {
|
while(itr.hasNext()) {
|
||||||
Entry<WebSocket,PendingConnection> etr = itr.next();
|
Entry<WebSocket,PendingConnection> etr = itr.next();
|
||||||
if(millis - etr.getValue().openTime > 1000l) {
|
if(millis - etr.getValue().openTime > 500l) {
|
||||||
etr.getKey().close();
|
etr.getKey().close();
|
||||||
itr.remove();
|
itr.remove();
|
||||||
}
|
}
|
||||||
|
@ -62,16 +82,25 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
Iterator<EaglerSPClient> itr = clientConnections.values().iterator();
|
Iterator<EaglerSPClient> itr = clientConnections.values().iterator();
|
||||||
while(itr.hasNext()) {
|
while(itr.hasNext()) {
|
||||||
EaglerSPClient cl = itr.next();
|
EaglerSPClient cl = itr.next();
|
||||||
if(millis - cl.createdOn > 500l) {
|
if(millis - cl.createdOn > 5000l) {
|
||||||
cl.disconnect(IPacketFEDisconnectClient.TYPE_TIMEOUT, "Took too long to connect!");
|
cl.disconnect(IPacketFEDisconnectClient.TYPE_TIMEOUT, "Took too long to connect!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(++rateLimitUpdateCounter > 300) {
|
||||||
|
if(pingRateLimiter != null) {
|
||||||
|
pingRateLimiter.update();
|
||||||
|
}
|
||||||
|
if(worldRateLimiter != null) {
|
||||||
|
worldRateLimiter.update();
|
||||||
|
}
|
||||||
|
rateLimitUpdateCounter = 0;
|
||||||
|
}
|
||||||
}catch(Throwable t) {
|
}catch(Throwable t) {
|
||||||
logger.error("Error in update loop!");
|
logger.error("Error in update loop!");
|
||||||
logger.error(t);
|
logger.error(t);
|
||||||
}
|
}
|
||||||
Util.sleep(50l);
|
Util.sleep(100l);
|
||||||
}
|
}
|
||||||
}), "Relay Tick");
|
}), "Relay Tick");
|
||||||
tickThread.setDaemon(true);
|
tickThread.setDaemon(true);
|
||||||
|
@ -114,6 +143,7 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
private static final Map<WebSocket,EaglerSPClient> clientConnections = new HashMap();
|
private static final Map<WebSocket,EaglerSPClient> clientConnections = new HashMap();
|
||||||
private static final Map<String,EaglerSPServer> serverCodes = new HashMap();
|
private static final Map<String,EaglerSPServer> serverCodes = new HashMap();
|
||||||
private static final Map<WebSocket,EaglerSPServer> serverConnections = new HashMap();
|
private static final Map<WebSocket,EaglerSPServer> serverConnections = new HashMap();
|
||||||
|
private static final Map<String,List<EaglerSPClient>> clientAddressSets = new HashMap();
|
||||||
private static final Map<String,List<EaglerSPServer>> serverAddressSets = new HashMap();
|
private static final Map<String,List<EaglerSPServer>> serverAddressSets = new HashMap();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -131,7 +161,32 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
}else {
|
}else {
|
||||||
addr = arg0.getRemoteSocketAddress().getAddress().getHostAddress().toLowerCase();
|
addr = arg0.getRemoteSocketAddress().getAddress().getHostAddress().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int totalCons = 0;
|
||||||
|
synchronized(pendingConnections) {
|
||||||
|
Iterator<PendingConnection> pendingItr = pendingConnections.values().iterator();
|
||||||
|
while(pendingItr.hasNext()) {
|
||||||
|
if(pendingItr.next().address.equals(addr)) {
|
||||||
|
++totalCons;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
synchronized(clientAddressSets) {
|
||||||
|
List<EaglerSPClient> lst = clientAddressSets.get(addr);
|
||||||
|
if(lst != null) {
|
||||||
|
totalCons += lst.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(totalCons >= config.getConnectionsPerIP()) {
|
||||||
|
logger.debug("[{}]: Too many connections are open on this address", arg0.getAttachment());
|
||||||
|
arg0.send(IPacketFEDisconnectClient.ratelimitPacketTooMany);
|
||||||
|
arg0.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
arg0.setAttachment(addr);
|
arg0.setAttachment(addr);
|
||||||
|
|
||||||
PendingConnection waiting = new PendingConnection(millis, addr);
|
PendingConnection waiting = new PendingConnection(millis, addr);
|
||||||
logger.debug("[{}]: Connection opened", arg0.getRemoteSocketAddress());
|
logger.debug("[{}]: Connection opened", arg0.getRemoteSocketAddress());
|
||||||
synchronized(pendingConnections) {
|
synchronized(pendingConnections) {
|
||||||
|
@ -165,6 +220,21 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(ipkt.connectionType == 0x01) {
|
if(ipkt.connectionType == 0x01) {
|
||||||
|
if(!rateLimit(worldRateLimiter, arg0, waiting.address)) {
|
||||||
|
logger.debug("[{}]: Got world ratelimited", arg0.getAttachment());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
synchronized(serverAddressSets) {
|
||||||
|
List<EaglerSPServer> lst = serverAddressSets.get(waiting.address);
|
||||||
|
if(lst != null) {
|
||||||
|
if(lst.size() >= config.getWorldsPerIP()) {
|
||||||
|
logger.debug("[{}]: Too many worlds are open on this address", arg0.getAttachment());
|
||||||
|
arg0.send(IPacketFEDisconnectClient.ratelimitPacketTooMany);
|
||||||
|
arg0.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
logger.debug("[{}]: Connected as a server", arg0.getAttachment());
|
logger.debug("[{}]: Connected as a server", arg0.getAttachment());
|
||||||
EaglerSPServer srv;
|
EaglerSPServer srv;
|
||||||
synchronized(serverCodes) {
|
synchronized(serverCodes) {
|
||||||
|
@ -200,57 +270,71 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
}
|
}
|
||||||
srv.send(new IPacket01ICEServers(EaglerSPRelayConfigRelayList.relayServers));
|
srv.send(new IPacket01ICEServers(EaglerSPRelayConfigRelayList.relayServers));
|
||||||
logger.debug("[{}][Relay -> Server] PKT 0x01: Send ICE server list to server", arg0.getAttachment());
|
logger.debug("[{}][Relay -> Server] PKT 0x01: Send ICE server list to server", arg0.getAttachment());
|
||||||
}else if(ipkt.connectionType == 0x02) {
|
}else {
|
||||||
String code = ipkt.connectionCode;
|
if(!rateLimit(pingRateLimiter, arg0, waiting.address)) {
|
||||||
logger.debug("[{}]: Connected as a client, requested server code: {}", arg0.getAttachment(), code);
|
logger.debug("[{}]: Got ping ratelimited", arg0.getAttachment());
|
||||||
if(code.length() != config.getCodeLength()) {
|
return;
|
||||||
logger.debug("The code '{}' is invalid because it's the wrong length, disconnecting");
|
}
|
||||||
arg0.send(IPacket.writePacket(new IPacketFFErrorCode(IPacketFFErrorCode.TYPE_CODE_LENGTH,
|
if(ipkt.connectionType == 0x02) {
|
||||||
"The join code is the wrong length, it should be " + config.getCodeLength() + " chars long")));
|
String code = ipkt.connectionCode;
|
||||||
|
logger.debug("[{}]: Connected as a client, requested server code: {}", arg0.getAttachment(), code);
|
||||||
|
if(code.length() != config.getCodeLength()) {
|
||||||
|
logger.debug("The code '{}' is invalid because it's the wrong length, disconnecting");
|
||||||
|
arg0.send(IPacket.writePacket(new IPacketFFErrorCode(IPacketFFErrorCode.TYPE_CODE_LENGTH,
|
||||||
|
"The join code is the wrong length, it should be " + config.getCodeLength() + " chars long")));
|
||||||
|
arg0.close();
|
||||||
|
}else {
|
||||||
|
EaglerSPServer srv;
|
||||||
|
synchronized(serverCodes) {
|
||||||
|
srv = serverCodes.get(code);
|
||||||
|
}
|
||||||
|
if(srv == null) {
|
||||||
|
arg0.send(IPacket.writePacket(new IPacketFFErrorCode(IPacketFFErrorCode.TYPE_INCORRECT_CODE,
|
||||||
|
"Invalid code, no LAN world found!")));
|
||||||
|
arg0.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String id;
|
||||||
|
EaglerSPClient cl;
|
||||||
|
synchronized(clientIds) {
|
||||||
|
int j = 0;
|
||||||
|
do {
|
||||||
|
id = EaglerSPClient.generateClientId();
|
||||||
|
}while(clientIds.containsKey(id));
|
||||||
|
cl = new EaglerSPClient(arg0, srv, id, waiting.address);
|
||||||
|
clientIds.put(id, cl);
|
||||||
|
ipkt.connectionCode = id;
|
||||||
|
arg0.send(IPacket.writePacket(ipkt));
|
||||||
|
srv.handleNewClient(cl);
|
||||||
|
}
|
||||||
|
synchronized(clientConnections) {
|
||||||
|
clientConnections.put(arg0, cl);
|
||||||
|
}
|
||||||
|
synchronized(clientAddressSets) {
|
||||||
|
List<EaglerSPClient> lst = clientAddressSets.get(cl.address);
|
||||||
|
if(lst == null) {
|
||||||
|
lst = new ArrayList();
|
||||||
|
clientAddressSets.put(cl.address, lst);
|
||||||
|
}
|
||||||
|
lst.add(cl);
|
||||||
|
}
|
||||||
|
cl.send(new IPacket01ICEServers(EaglerSPRelayConfigRelayList.relayServers));
|
||||||
|
logger.debug("[{}][Relay -> Client] PKT 0x01: Send ICE server list to client", arg0.getAttachment());
|
||||||
|
}
|
||||||
|
}else if(ipkt.connectionType == 0x02) {
|
||||||
|
logger.debug("[{}]: Pinging the server", arg0.getAttachment());
|
||||||
|
arg0.send(IPacket.writePacket(new IPacket69Pong(Constants.protocolVersion, config.getComment(), Constants.versionBrand)));
|
||||||
|
arg0.close();
|
||||||
|
}else if(ipkt.connectionType == 0x03) {
|
||||||
|
logger.debug("[{}]: Polling the server for other worlds", arg0.getAttachment());
|
||||||
|
arg0.send(IPacket.writePacket(new IPacket07LocalWorlds(getLocalWorlds(waiting.address))));
|
||||||
arg0.close();
|
arg0.close();
|
||||||
}else {
|
}else {
|
||||||
EaglerSPServer srv;
|
logger.debug("[{}]: Unknown connection type: {}", arg0.getAttachment(), ipkt.connectionType);
|
||||||
synchronized(serverCodes) {
|
arg0.send(IPacket.writePacket(new IPacketFFErrorCode(IPacketFFErrorCode.TYPE_ILLEGAL_OPERATION,
|
||||||
srv = serverCodes.get(code);
|
"Unexpected Init Packet")));
|
||||||
}
|
arg0.close();
|
||||||
if(srv == null) {
|
|
||||||
arg0.send(IPacket.writePacket(new IPacketFFErrorCode(IPacketFFErrorCode.TYPE_INCORRECT_CODE,
|
|
||||||
"Invalid code, no LAN world found!")));
|
|
||||||
arg0.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String id;
|
|
||||||
EaglerSPClient cl;
|
|
||||||
synchronized(clientIds) {
|
|
||||||
int j = 0;
|
|
||||||
do {
|
|
||||||
id = EaglerSPClient.generateClientId();
|
|
||||||
}while(clientIds.containsKey(id));
|
|
||||||
cl = new EaglerSPClient(arg0, srv, id);
|
|
||||||
clientIds.put(id, cl);
|
|
||||||
ipkt.connectionCode = id;
|
|
||||||
arg0.send(IPacket.writePacket(ipkt));
|
|
||||||
srv.handleNewClient(cl);
|
|
||||||
}
|
|
||||||
synchronized(clientConnections) {
|
|
||||||
clientConnections.put(arg0, cl);
|
|
||||||
}
|
|
||||||
cl.send(new IPacket01ICEServers(EaglerSPRelayConfigRelayList.relayServers));
|
|
||||||
logger.debug("[{}][Relay -> Client] PKT 0x01: Send ICE server list to client", arg0.getAttachment());
|
|
||||||
}
|
}
|
||||||
}else if(ipkt.connectionType == 0x02) {
|
|
||||||
logger.debug("[{}]: Pinging the server", arg0.getAttachment());
|
|
||||||
arg0.send(IPacket.writePacket(new IPacket69Pong(Constants.protocolVersion, config.getComment(), Constants.versionBrand)));
|
|
||||||
arg0.close();
|
|
||||||
}else if(ipkt.connectionType == 0x03) {
|
|
||||||
logger.debug("[{}]: Polling the server for other worlds", arg0.getAttachment());
|
|
||||||
arg0.send(IPacket.writePacket(new IPacket07LocalWorlds(getLocalWorlds(waiting.address))));
|
|
||||||
arg0.close();
|
|
||||||
}else {
|
|
||||||
logger.debug("[{}]: Unknown connection type: {}", arg0.getAttachment(), ipkt.connectionType);
|
|
||||||
arg0.send(IPacket.writePacket(new IPacketFFErrorCode(IPacketFFErrorCode.TYPE_ILLEGAL_OPERATION,
|
|
||||||
"Unexpected Init Packet")));
|
|
||||||
arg0.close();
|
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
logger.debug("[{}]: Pending connection did not send a 0x00 packet to identify "
|
logger.debug("[{}]: Pending connection did not send a 0x00 packet to identify "
|
||||||
|
@ -314,6 +398,15 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
synchronized(serverCodes) {
|
synchronized(serverCodes) {
|
||||||
serverCodes.remove(srv.code);
|
serverCodes.remove(srv.code);
|
||||||
}
|
}
|
||||||
|
synchronized(serverAddressSets) {
|
||||||
|
List<EaglerSPServer> lst = serverAddressSets.get(srv.serverAddress);
|
||||||
|
if(lst != null) {
|
||||||
|
lst.remove(srv);
|
||||||
|
if(lst.size() == 0) {
|
||||||
|
serverAddressSets.remove(srv.serverAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
ArrayList<EaglerSPClient> clientList;
|
ArrayList<EaglerSPClient> clientList;
|
||||||
synchronized(clientConnections) {
|
synchronized(clientConnections) {
|
||||||
clientList = new ArrayList(clientConnections.values());
|
clientList = new ArrayList(clientConnections.values());
|
||||||
|
@ -326,18 +419,20 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
cl.socket.close();
|
cl.socket.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
synchronized(serverAddressSets) {
|
|
||||||
List<EaglerSPServer> lst = serverAddressSets.get(srv.serverAddress);
|
|
||||||
lst.remove(srv);
|
|
||||||
if(lst.size() == 0) {
|
|
||||||
serverAddressSets.remove(srv.serverAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else {
|
}else {
|
||||||
EaglerSPClient cl;
|
EaglerSPClient cl;
|
||||||
synchronized(clientConnections) {
|
synchronized(clientConnections) {
|
||||||
cl = clientConnections.remove(arg0);
|
cl = clientConnections.remove(arg0);
|
||||||
}
|
}
|
||||||
|
synchronized(clientAddressSets) {
|
||||||
|
List<EaglerSPClient> lst = clientAddressSets.get(cl.address);
|
||||||
|
if(lst != null) {
|
||||||
|
lst.remove(cl);
|
||||||
|
if(lst.size() == 0) {
|
||||||
|
clientAddressSets.remove(cl.address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if(cl != null) {
|
if(cl != null) {
|
||||||
logger.debug("[{}]: Client closed, id: {}", arg0.getAttachment(), cl.id);
|
logger.debug("[{}]: Client closed, id: {}", arg0.getAttachment(), cl.id);
|
||||||
synchronized(clientIds) {
|
synchronized(clientIds) {
|
||||||
|
@ -375,5 +470,30 @@ public class EaglerSPRelay extends WebSocketServer {
|
||||||
}
|
}
|
||||||
return lst;
|
return lst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean rateLimit(RateLimiter limiter, WebSocket sock, String addr) {
|
||||||
|
if(limiter != null) {
|
||||||
|
RateLimit l = limiter.limit(addr);
|
||||||
|
if(l == RateLimit.NONE) {
|
||||||
|
return true;
|
||||||
|
}else if(l == RateLimit.LIMIT) {
|
||||||
|
sock.send(IPacketFEDisconnectClient.ratelimitPacketBlock);
|
||||||
|
sock.close();
|
||||||
|
return false;
|
||||||
|
}else if(l == RateLimit.LIMIT_NOW_LOCKOUT) {
|
||||||
|
sock.send(IPacketFEDisconnectClient.ratelimitPacketBlockLock);
|
||||||
|
sock.close();
|
||||||
|
return false;
|
||||||
|
}else if(l == RateLimit.LOCKOUT) {
|
||||||
|
sock.send(IPacketFEDisconnectClient.ratelimitPacketLocked);
|
||||||
|
sock.close();
|
||||||
|
return false;
|
||||||
|
}else {
|
||||||
|
return true; // ?
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,22 @@ public class EaglerSPRelayConfig {
|
||||||
private int codeLength = 5;
|
private int codeLength = 5;
|
||||||
private String codeChars = "abcdefghijklmnopqrstuvwxyz0123456789$%&*+?!";
|
private String codeChars = "abcdefghijklmnopqrstuvwxyz0123456789$%&*+?!";
|
||||||
private boolean codeMixCase = false;
|
private boolean codeMixCase = false;
|
||||||
private int connectionsPerIP = 256;
|
|
||||||
private boolean rateLimitEnable = false;
|
private int connectionsPerIP = 128;
|
||||||
private int rateLimitPeriod = 128;
|
private int worldsPerIP = 32;
|
||||||
private int rateLimitLimit = 48;
|
|
||||||
private int rateLimitLockoutLimit = 64;
|
private boolean openRateLimitEnable = true;
|
||||||
private int rateLimitLockoutDuration = 600;
|
private int openRateLimitPeriod = 192;
|
||||||
|
private int openRateLimitLimit = 32;
|
||||||
|
private int openRateLimitLockoutLimit = 48;
|
||||||
|
private int openRateLimitLockoutDuration = 600;
|
||||||
|
|
||||||
|
private boolean pingRateLimitEnable = true;
|
||||||
|
private int pingRateLimitPeriod = 256;
|
||||||
|
private int pingRateLimitLimit = 128;
|
||||||
|
private int pingRateLimitLockoutLimit = 192;
|
||||||
|
private int pingRateLimitLockoutDuration = 300;
|
||||||
|
|
||||||
private String originWhitelist = "";
|
private String originWhitelist = "";
|
||||||
private String[] originWhitelistArray = new String[0];
|
private String[] originWhitelistArray = new String[0];
|
||||||
private boolean enableRealIpHeader = false;
|
private boolean enableRealIpHeader = false;
|
||||||
|
@ -35,11 +45,17 @@ public class EaglerSPRelayConfig {
|
||||||
}else {
|
}else {
|
||||||
EaglerSPRelay.logger.info("Loading config file: {}", conf.getAbsoluteFile());
|
EaglerSPRelay.logger.info("Loading config file: {}", conf.getAbsoluteFile());
|
||||||
boolean gotPort = false, gotCodeLength = false, gotCodeChars = false;
|
boolean gotPort = false, gotCodeLength = false, gotCodeChars = false;
|
||||||
boolean gotCodeMixCase = false, gotConnectionsPerIP = false;
|
boolean gotCodeMixCase = false;
|
||||||
boolean gotRateLimitEnable = false, gotRateLimitPeriod = false;
|
boolean gotConnectionsPerIP = false, gotWorldsPerIP = false,
|
||||||
boolean gotRateLimitLimit = false, gotRateLimitLockoutLimit = false;
|
gotOpenRateLimitEnable = false, gotOpenRateLimitPeriod = false,
|
||||||
boolean gotRateLimitLockoutDuration = false, gotOriginWhitelist = false;
|
gotOpenRateLimitLimit = false, gotOpenRateLimitLockoutLimit = false,
|
||||||
boolean gotEnableRealIpHeader = false, gotAddress = false, gotComment = false;
|
gotOpenRateLimitLockoutDuration = false;
|
||||||
|
boolean gotPingRateLimitEnable = false, gotPingRateLimitPeriod = false,
|
||||||
|
gotPingRateLimitLimit = false, gotPingRateLimitLockoutLimit = false,
|
||||||
|
gotPingRateLimitLockoutDuration = false;
|
||||||
|
boolean gotOriginWhitelist = false, gotEnableRealIpHeader = false,
|
||||||
|
gotAddress = false, gotComment = false;
|
||||||
|
|
||||||
Throwable t2 = null;
|
Throwable t2 = null;
|
||||||
try(BufferedReader reader = new BufferedReader(new FileReader(conf))) {
|
try(BufferedReader reader = new BufferedReader(new FileReader(conf))) {
|
||||||
String s;
|
String s;
|
||||||
|
@ -86,6 +102,66 @@ public class EaglerSPRelayConfig {
|
||||||
t2 = t;
|
t2 = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}else if(ss[0].equalsIgnoreCase("worlds-per-ip")) {
|
||||||
|
try {
|
||||||
|
worldsPerIP = Integer.parseInt(ss[1]);
|
||||||
|
gotWorldsPerIP = true;
|
||||||
|
}catch(Throwable t) {
|
||||||
|
EaglerSPRelay.logger.warn("Invalid worlds-per-ip {} in conf {}", ss[1], conf.getAbsoluteFile());
|
||||||
|
EaglerSPRelay.logger.warn(t);
|
||||||
|
t2 = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if(ss[0].equalsIgnoreCase("world-ratelimit-enable")) {
|
||||||
|
try {
|
||||||
|
openRateLimitEnable = getBooleanValue(ss[1]);
|
||||||
|
gotOpenRateLimitEnable = true;
|
||||||
|
}catch(Throwable t) {
|
||||||
|
EaglerSPRelay.logger.warn("Invalid world-ratelimit-enable {} in conf {}", ss[1], conf.getAbsoluteFile());
|
||||||
|
EaglerSPRelay.logger.warn(t);
|
||||||
|
t2 = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if(ss[0].equalsIgnoreCase("world-ratelimit-period")) {
|
||||||
|
try {
|
||||||
|
openRateLimitPeriod = Integer.parseInt(ss[1]);
|
||||||
|
gotOpenRateLimitPeriod = true;
|
||||||
|
}catch(Throwable t) {
|
||||||
|
EaglerSPRelay.logger.warn("Invalid world-ratelimit-period {} in conf {}", ss[1], conf.getAbsoluteFile());
|
||||||
|
EaglerSPRelay.logger.warn(t);
|
||||||
|
t2 = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if(ss[0].equalsIgnoreCase("world-ratelimit-limit")) {
|
||||||
|
try {
|
||||||
|
openRateLimitLimit = Integer.parseInt(ss[1]);
|
||||||
|
gotOpenRateLimitLimit = true;
|
||||||
|
}catch(Throwable t) {
|
||||||
|
EaglerSPRelay.logger.warn("Invalid world-ratelimit-limit {} in conf {}", ss[1], conf.getAbsoluteFile());
|
||||||
|
EaglerSPRelay.logger.warn(t);
|
||||||
|
t2 = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if(ss[0].equalsIgnoreCase("world-ratelimit-lockout-limit")) {
|
||||||
|
try {
|
||||||
|
openRateLimitLockoutLimit = Integer.parseInt(ss[1]);
|
||||||
|
gotOpenRateLimitLockoutLimit = true;
|
||||||
|
}catch(Throwable t) {
|
||||||
|
EaglerSPRelay.logger.warn("Invalid world-ratelimit-lockout-limit {} in conf {}", ss[1], conf.getAbsoluteFile());
|
||||||
|
EaglerSPRelay.logger.warn(t);
|
||||||
|
t2 = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else if(ss[0].equalsIgnoreCase("world-ratelimit-lockout-duration")) {
|
||||||
|
try {
|
||||||
|
openRateLimitLockoutDuration = Integer.parseInt(ss[1]);
|
||||||
|
gotOpenRateLimitLockoutDuration = true;
|
||||||
|
}catch(Throwable t) {
|
||||||
|
EaglerSPRelay.logger.warn("Invalid world-ratelimit-lockout-duration {} in conf {}", ss[1], conf.getAbsoluteFile());
|
||||||
|
EaglerSPRelay.logger.warn(t);
|
||||||
|
t2 = t;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}else if(ss[0].equalsIgnoreCase("connections-per-ip")) {
|
}else if(ss[0].equalsIgnoreCase("connections-per-ip")) {
|
||||||
try {
|
try {
|
||||||
connectionsPerIP = Integer.parseInt(ss[1]);
|
connectionsPerIP = Integer.parseInt(ss[1]);
|
||||||
|
@ -96,52 +172,52 @@ public class EaglerSPRelayConfig {
|
||||||
t2 = t;
|
t2 = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}else if(ss[0].equalsIgnoreCase("ratelimit-enable")) {
|
}else if(ss[0].equalsIgnoreCase("ping-ratelimit-enable")) {
|
||||||
try {
|
try {
|
||||||
rateLimitEnable = getBooleanValue(ss[1]);
|
pingRateLimitEnable = getBooleanValue(ss[1]);
|
||||||
gotRateLimitEnable = true;
|
gotPingRateLimitEnable = true;
|
||||||
}catch(Throwable t) {
|
}catch(Throwable t) {
|
||||||
EaglerSPRelay.logger.warn("Invalid rate-limit-enable {} in conf {}", ss[1], conf.getAbsoluteFile());
|
EaglerSPRelay.logger.warn("Invalid ping-ratelimit-enable {} in conf {}", ss[1], conf.getAbsoluteFile());
|
||||||
EaglerSPRelay.logger.warn(t);
|
EaglerSPRelay.logger.warn(t);
|
||||||
t2 = t;
|
t2 = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}else if(ss[0].equalsIgnoreCase("ratelimit-period")) {
|
}else if(ss[0].equalsIgnoreCase("ping-ratelimit-period")) {
|
||||||
try {
|
try {
|
||||||
rateLimitPeriod = Integer.parseInt(ss[1]);
|
pingRateLimitPeriod = Integer.parseInt(ss[1]);
|
||||||
gotRateLimitPeriod = true;
|
gotPingRateLimitPeriod = true;
|
||||||
}catch(Throwable t) {
|
}catch(Throwable t) {
|
||||||
EaglerSPRelay.logger.warn("Invalid ratelimit-period {} in conf {}", ss[1], conf.getAbsoluteFile());
|
EaglerSPRelay.logger.warn("Invalid ping-ratelimit-period {} in conf {}", ss[1], conf.getAbsoluteFile());
|
||||||
EaglerSPRelay.logger.warn(t);
|
EaglerSPRelay.logger.warn(t);
|
||||||
t2 = t;
|
t2 = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}else if(ss[0].equalsIgnoreCase("ratelimit-limit")) {
|
}else if(ss[0].equalsIgnoreCase("ping-ratelimit-limit")) {
|
||||||
try {
|
try {
|
||||||
rateLimitLimit = Integer.parseInt(ss[1]);
|
pingRateLimitLimit = Integer.parseInt(ss[1]);
|
||||||
gotRateLimitLimit = true;
|
gotPingRateLimitLimit = true;
|
||||||
}catch(Throwable t) {
|
}catch(Throwable t) {
|
||||||
EaglerSPRelay.logger.warn("Invalid ratelimit-limit {} in conf {}", ss[1], conf.getAbsoluteFile());
|
EaglerSPRelay.logger.warn("Invalid ping-ratelimit-limit {} in conf {}", ss[1], conf.getAbsoluteFile());
|
||||||
EaglerSPRelay.logger.warn(t);
|
EaglerSPRelay.logger.warn(t);
|
||||||
t2 = t;
|
t2 = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}else if(ss[0].equalsIgnoreCase("ratelimit-lockout-limit")) {
|
}else if(ss[0].equalsIgnoreCase("ping-ratelimit-lockout-limit")) {
|
||||||
try {
|
try {
|
||||||
rateLimitLockoutLimit = Integer.parseInt(ss[1]);
|
pingRateLimitLockoutLimit = Integer.parseInt(ss[1]);
|
||||||
gotRateLimitLockoutLimit = true;
|
gotPingRateLimitLockoutLimit = true;
|
||||||
}catch(Throwable t) {
|
}catch(Throwable t) {
|
||||||
EaglerSPRelay.logger.warn("Invalid ratelimit-lockout-limit {} in conf {}", ss[1], conf.getAbsoluteFile());
|
EaglerSPRelay.logger.warn("Invalid ping-ratelimit-lockout-limit {} in conf {}", ss[1], conf.getAbsoluteFile());
|
||||||
EaglerSPRelay.logger.warn(t);
|
EaglerSPRelay.logger.warn(t);
|
||||||
t2 = t;
|
t2 = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}else if(ss[0].equalsIgnoreCase("ratelimit-lockout-duration")) {
|
}else if(ss[0].equalsIgnoreCase("ping-ratelimit-lockout-duration")) {
|
||||||
try {
|
try {
|
||||||
rateLimitLockoutDuration = Integer.parseInt(ss[1]);
|
pingRateLimitLockoutDuration = Integer.parseInt(ss[1]);
|
||||||
gotRateLimitLockoutDuration = true;
|
gotPingRateLimitLockoutDuration = true;
|
||||||
}catch(Throwable t) {
|
}catch(Throwable t) {
|
||||||
EaglerSPRelay.logger.warn("Invalid ratelimit-lockout-duration {} in conf {}", ss[1], conf.getAbsoluteFile());
|
EaglerSPRelay.logger.warn("Invalid ping-ratelimit-lockout-duration {} in conf {}", ss[1], conf.getAbsoluteFile());
|
||||||
EaglerSPRelay.logger.warn(t);
|
EaglerSPRelay.logger.warn(t);
|
||||||
t2 = t;
|
t2 = t;
|
||||||
break;
|
break;
|
||||||
|
@ -174,10 +250,14 @@ public class EaglerSPRelayConfig {
|
||||||
t2 = t;
|
t2 = t;
|
||||||
}
|
}
|
||||||
if(t2 != null || !gotPort || !gotCodeLength || !gotCodeChars ||
|
if(t2 != null || !gotPort || !gotCodeLength || !gotCodeChars ||
|
||||||
!gotCodeMixCase || !gotConnectionsPerIP || !gotRateLimitEnable ||
|
!gotCodeMixCase || !gotWorldsPerIP || !gotOpenRateLimitEnable ||
|
||||||
!gotRateLimitPeriod || !gotRateLimitLimit || !gotRateLimitLockoutLimit ||
|
!gotOpenRateLimitPeriod || !gotOpenRateLimitLimit ||
|
||||||
!gotRateLimitLockoutDuration || !gotOriginWhitelist ||
|
!gotOpenRateLimitLockoutLimit || !gotOpenRateLimitLockoutDuration ||
|
||||||
!gotEnableRealIpHeader || !gotAddress || !gotComment) {
|
!gotConnectionsPerIP || !gotPingRateLimitEnable ||
|
||||||
|
!gotPingRateLimitPeriod || !gotPingRateLimitLimit ||
|
||||||
|
!gotPingRateLimitLockoutLimit || !gotPingRateLimitLockoutDuration ||
|
||||||
|
!gotOriginWhitelist || !gotEnableRealIpHeader || !gotAddress ||
|
||||||
|
!gotComment) {
|
||||||
EaglerSPRelay.logger.warn("Updating config file: {}", conf.getAbsoluteFile());
|
EaglerSPRelay.logger.warn("Updating config file: {}", conf.getAbsoluteFile());
|
||||||
save(conf);
|
save(conf);
|
||||||
}
|
}
|
||||||
|
@ -204,11 +284,17 @@ public class EaglerSPRelayConfig {
|
||||||
w.println("code-chars=" + codeChars);
|
w.println("code-chars=" + codeChars);
|
||||||
w.println("code-mix-case=" + codeMixCase);
|
w.println("code-mix-case=" + codeMixCase);
|
||||||
w.println("connections-per-ip=" + connectionsPerIP);
|
w.println("connections-per-ip=" + connectionsPerIP);
|
||||||
w.println("ratelimit-enable=" + rateLimitEnable);
|
w.println("ping-ratelimit-enable=" + pingRateLimitEnable);
|
||||||
w.println("ratelimit-period=" + rateLimitPeriod);
|
w.println("ping-ratelimit-period=" + pingRateLimitPeriod);
|
||||||
w.println("ratelimit-limit=" + rateLimitLimit);
|
w.println("ping-ratelimit-limit=" + pingRateLimitLimit);
|
||||||
w.println("ratelimit-lockout-limit=" + rateLimitLockoutLimit);
|
w.println("ping-ratelimit-lockout-limit=" + pingRateLimitLockoutLimit);
|
||||||
w.println("ratelimit-lockout-duration=" + rateLimitLockoutDuration);
|
w.println("ping-ratelimit-lockout-duration=" + pingRateLimitLockoutDuration);
|
||||||
|
w.println("worlds-per-ip=" + worldsPerIP);
|
||||||
|
w.println("world-ratelimit-enable=" + openRateLimitEnable);
|
||||||
|
w.println("world-ratelimit-period=" + openRateLimitPeriod);
|
||||||
|
w.println("world-ratelimit-limit=" + openRateLimitLimit);
|
||||||
|
w.println("world-ratelimit-lockout-limit=" + openRateLimitLockoutLimit);
|
||||||
|
w.println("world-ratelimit-lockout-duration=" + openRateLimitLockoutDuration);
|
||||||
w.println("origin-whitelist=" + originWhitelist);
|
w.println("origin-whitelist=" + originWhitelist);
|
||||||
w.println("enable-real-ip-header=" + enableRealIpHeader);
|
w.println("enable-real-ip-header=" + enableRealIpHeader);
|
||||||
w.print("server-comment=" + serverComment);
|
w.print("server-comment=" + serverComment);
|
||||||
|
@ -252,24 +338,48 @@ public class EaglerSPRelayConfig {
|
||||||
return connectionsPerIP;
|
return connectionsPerIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRateLimitEnable() {
|
public boolean isPingRateLimitEnable() {
|
||||||
return rateLimitEnable;
|
return pingRateLimitEnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRateLimitPeriod() {
|
public int getPingRateLimitPeriod() {
|
||||||
return rateLimitPeriod;
|
return pingRateLimitPeriod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRateLimitLimit() {
|
public int getPingRateLimitLimit() {
|
||||||
return rateLimitLimit;
|
return pingRateLimitLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRateLimitLockoutLimit() {
|
public int getPingRateLimitLockoutLimit() {
|
||||||
return rateLimitLockoutLimit;
|
return pingRateLimitLockoutLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRateLimitLockoutDuration() {
|
public int getPingRateLimitLockoutDuration() {
|
||||||
return rateLimitLockoutDuration;
|
return pingRateLimitLockoutDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWorldsPerIP() {
|
||||||
|
return worldsPerIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWorldRateLimitEnable() {
|
||||||
|
return openRateLimitEnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWorldRateLimitPeriod() {
|
||||||
|
return openRateLimitPeriod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWorldRateLimitLimit() {
|
||||||
|
return openRateLimitLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWorldRateLimitLockoutLimit() {
|
||||||
|
return openRateLimitLockoutLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWorldRateLimitLockoutDuration() {
|
||||||
|
return openRateLimitLockoutDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOriginWhitelist() {
|
public String getOriginWhitelist() {
|
||||||
|
@ -279,6 +389,23 @@ public class EaglerSPRelayConfig {
|
||||||
public String[] getOriginWhitelistArray() {
|
public String[] getOriginWhitelistArray() {
|
||||||
return originWhitelistArray;
|
return originWhitelistArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getIsWhitelisted(String domain) {
|
||||||
|
domain = domain.toLowerCase();
|
||||||
|
for(int i = 0; i < originWhitelistArray.length; ++i) {
|
||||||
|
String etr = originWhitelistArray[i].toLowerCase();
|
||||||
|
if(etr.startsWith("*")) {
|
||||||
|
if(domain.endsWith(etr.substring(1))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
if(domain.equals(etr)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isEnableRealIpHeader() {
|
public boolean isEnableRealIpHeader() {
|
||||||
return enableRealIpHeader;
|
return enableRealIpHeader;
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
package net.lax1dude.eaglercraft.sp.relay;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class RateLimiter {
|
||||||
|
|
||||||
|
private final int period;
|
||||||
|
private final int limit;
|
||||||
|
private final int lockoutLimit;
|
||||||
|
private final int lockoutDuration;
|
||||||
|
|
||||||
|
private class RateLimitEntry {
|
||||||
|
|
||||||
|
protected long timer;
|
||||||
|
protected int count;
|
||||||
|
protected long lockedTimer;
|
||||||
|
protected boolean locked;
|
||||||
|
|
||||||
|
protected RateLimitEntry() {
|
||||||
|
timer = System.currentTimeMillis();
|
||||||
|
count = 0;
|
||||||
|
lockedTimer = 0l;
|
||||||
|
locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void update() {
|
||||||
|
long millis = System.currentTimeMillis();
|
||||||
|
if(locked) {
|
||||||
|
if(millis - lockedTimer > RateLimiter.this.lockoutDuration) {
|
||||||
|
timer = millis;
|
||||||
|
count = 0;
|
||||||
|
lockedTimer = 0l;
|
||||||
|
locked = false;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
long p = RateLimiter.this.period;
|
||||||
|
int breaker = 0;
|
||||||
|
while(millis - timer > p) {
|
||||||
|
timer += p;
|
||||||
|
--count;
|
||||||
|
if(count < 0 || ++breaker > 100) {
|
||||||
|
timer = millis;
|
||||||
|
count = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum RateLimit {
|
||||||
|
NONE, LIMIT, LIMIT_NOW_LOCKOUT, LOCKOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<String, RateLimitEntry> limiters = new HashMap();
|
||||||
|
|
||||||
|
public RateLimiter(int period, int limit, int lockoutLimit, int lockoutDuration) {
|
||||||
|
this.period = period;
|
||||||
|
this.limit = limit;
|
||||||
|
this.lockoutLimit = lockoutLimit;
|
||||||
|
this.lockoutDuration = lockoutDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RateLimit limit(String addr) {
|
||||||
|
synchronized(this) {
|
||||||
|
RateLimitEntry etr = limiters.get(addr);
|
||||||
|
|
||||||
|
if(etr == null) {
|
||||||
|
etr = new RateLimitEntry();
|
||||||
|
limiters.put(addr, etr);
|
||||||
|
}else {
|
||||||
|
etr.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(etr.locked) {
|
||||||
|
return RateLimit.LOCKOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
++etr.count;
|
||||||
|
if(etr.count >= lockoutLimit) {
|
||||||
|
etr.count = 0;
|
||||||
|
etr.locked = true;
|
||||||
|
etr.lockedTimer = System.currentTimeMillis();
|
||||||
|
return RateLimit.LIMIT_NOW_LOCKOUT;
|
||||||
|
}else if(etr.count > limit) {
|
||||||
|
return RateLimit.LIMIT;
|
||||||
|
}else {
|
||||||
|
return RateLimit.NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update() {
|
||||||
|
synchronized(this) {
|
||||||
|
Iterator<RateLimitEntry> itr = limiters.values().iterator();
|
||||||
|
while(itr.hasNext()) {
|
||||||
|
if(itr.next().count == 0) {
|
||||||
|
itr.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
synchronized(this) {
|
||||||
|
limiters.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package net.lax1dude.eaglercraft.sp.relay.pkt;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class IPacketFEDisconnectClient extends IPacket {
|
public class IPacketFEDisconnectClient extends IPacket {
|
||||||
|
|
||||||
|
@ -41,5 +42,10 @@ public class IPacketFEDisconnectClient extends IPacket {
|
||||||
public int packetLength() {
|
public int packetLength() {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final ByteBuffer ratelimitPacketTooMany = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x00 });
|
||||||
|
public static final ByteBuffer ratelimitPacketBlock = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x01 });
|
||||||
|
public static final ByteBuffer ratelimitPacketBlockLock = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x02 });
|
||||||
|
public static final ByteBuffer ratelimitPacketLocked = ByteBuffer.wrap(new byte[] { (byte)0xFC, (byte)0x03 });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user