Added untested rate limits

This commit is contained in:
Anuken
2020-01-07 14:16:48 -05:00
parent 3e0556de05
commit 1f3bab5fa3
6 changed files with 53 additions and 13 deletions

View File

@@ -160,7 +160,7 @@ public class NetClient implements ApplicationListener{
throw new ValidateException(player, "Player has sent a message above the text limit."); throw new ValidateException(player, "Player has sent a message above the text limit.");
} }
String original = message; Events.fire(new PlayerChatEvent(player, message));
//check if it's a command //check if it's a command
CommandResponse response = netServer.clientCommands.handleMessage(message, player); CommandResponse response = netServer.clientCommands.handleMessage(message, player);
@@ -197,8 +197,6 @@ public class NetClient implements ApplicationListener{
player.sendMessage(text); player.sendMessage(text);
} }
} }
Events.fire(new PlayerChatEvent(player, message, original));
} }
public static String colorizeName(int id, String name){ public static String colorizeName(int id, String name){

View File

@@ -35,7 +35,7 @@ import static mindustry.Vars.*;
public class NetServer implements ApplicationListener{ public class NetServer implements ApplicationListener{
private final static int maxSnapshotSize = 430, timerBlockSync = 0; private final static int maxSnapshotSize = 430, timerBlockSync = 0;
private final static float serverSyncTime = 12, kickDuration = 30 * 1000, blockSyncTime = 60 * 8; private final static float serverSyncTime = 12, blockSyncTime = 60 * 8;
private final static Vec2 vector = new Vec2(); private final static Vec2 vector = new Vec2();
private final static Rect viewport = new Rect(); private final static Rect viewport = new Rect();
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */ /** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
@@ -115,7 +115,7 @@ public class NetServer implements ApplicationListener{
return; return;
} }
if(Time.millis() - info.lastKicked < kickDuration){ if(Time.millis() < info.lastKicked){
con.kick(KickReason.recentKick); con.kick(KickReason.recentKick);
return; return;
} }

View File

@@ -64,13 +64,10 @@ public class EventType{
public static class PlayerChatEvent{ public static class PlayerChatEvent{
public final Player player; public final Player player;
public final String message; public final String message;
/** The original, unfiltered message. */
public final String originalMessage;
public PlayerChatEvent(Player player, String message, String originalMessage){ public PlayerChatEvent(Player player, String message){
this.player = player; this.player = player;
this.message = message; this.message = message;
this.originalMessage = originalMessage;
} }
} }

View File

@@ -2,6 +2,7 @@ package mindustry.net;
import arc.*; import arc.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*;
import arc.util.ArcAnnotate.*; import arc.util.ArcAnnotate.*;
import mindustry.*; import mindustry.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
@@ -19,6 +20,38 @@ public class Administration{
public Administration(){ public Administration(){
load(); load();
//anti-spam
addChatFilter((player, message) -> {
long resetTime = Config.messageRateLimit.num() * 1000;
if(Config.antiSpam.bool() && !player.isLocal && !player.isAdmin){
//prevent people from spamming messages quickly
if(resetTime > 0 && Time.timeSinceMillis(player.getInfo().lastMessageTime) < resetTime){
//supress message
player.sendMessage("[scarlet]You may only send messages every " + Config.messageRateLimit.num() + " seconds.");
player.getInfo().messageInfractions ++;
//kick player for spamming and prevent connection if they've done this several times
if(player.getInfo().messageInfractions >= Config.messageSpamKick.num() && Config.messageSpamKick.num() != 0){
player.con.kick("You have been kicked for spamming.", 1000 * 60 * 2);
}
player.lastText = message;
return null;
}else{
player.getInfo().messageInfractions = 0;
}
//prevent players from sending the same message twice in the span of 50 seconds
if(message.equals(player.lastText) && Time.timeSinceMillis(player.getInfo().lastMessageTime) < 1000 * 50){
player.sendMessage("[scarlet]You may not send the same message twice.");
return null;
}
player.lastText = message;
player.getInfo().lastMessageTime = Time.millis();
}
return message;
});
} }
/** Adds a chat filter. This will transform the chat messages of every player. /** Adds a chat filter. This will transform the chat messages of every player.
@@ -326,6 +359,9 @@ public class Administration{
crashReport("Whether to send crash reports.", false, "crashreport"), crashReport("Whether to send crash reports.", false, "crashreport"),
logging("Whether to log everything to files.", true), logging("Whether to log everything to files.", true),
strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", true), strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", true),
antiSpam("Whether spammers are automatically kicked and rate-limited.", true),
messageRateLimit("Message rate limit in seconds. 0 to disable.", 0),
messageSpamKick("How many times a player must send a message before the cooldown to get kicked. 0 to disable.", 3),
socketInput("Allows a local application to control this server through a local TCP socket.", false, "socket", () -> Events.fire(Trigger.socketConfigChanged)), socketInput("Allows a local application to control this server through a local TCP socket.", false, "socket", () -> Events.fire(Trigger.socketConfigChanged)),
socketInputPort("The port for socket input.", 6859, () -> Events.fire(Trigger.socketConfigChanged)), socketInputPort("The port for socket input.", 6859, () -> Events.fire(Trigger.socketConfigChanged)),
socketInputAddress("The bind address for socket input.", "localhost", () -> Events.fire(Trigger.socketConfigChanged)), socketInputAddress("The bind address for socket input.", "localhost", () -> Events.fire(Trigger.socketConfigChanged)),
@@ -402,7 +438,11 @@ public class Administration{
public int timesKicked; public int timesKicked;
public int timesJoined; public int timesJoined;
public boolean banned, admin; public boolean banned, admin;
public long lastKicked; //last kicked timestamp public long lastKicked; //last kicked time to expiration
public transient long lastMessageTime;
public transient String lastSentMessage;
public transient int messageInfractions;
PlayerInfo(String id){ PlayerInfo(String id){
this.id = id; this.id = id;

View File

@@ -37,7 +37,7 @@ public abstract class NetConnection{
if(player != null && (reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote) && player.uuid != null){ if(player != null && (reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote) && player.uuid != null){
PlayerInfo info = netServer.admins.getInfo(player.uuid); PlayerInfo info = netServer.admins.getInfo(player.uuid);
info.timesKicked++; info.timesKicked++;
info.lastKicked = Math.max(Time.millis(), info.lastKicked); info.lastKicked = Math.max(Time.millis() + 30 * 1000, info.lastKicked);
} }
Call.onKick(this, reason); Call.onKick(this, reason);
@@ -49,12 +49,17 @@ public abstract class NetConnection{
/** Kick with an arbitrary reason. */ /** Kick with an arbitrary reason. */
public void kick(String reason){ public void kick(String reason){
kick(reason, 30 * 1000);
}
/** Kick with an arbitrary reason, and a kick duration in milliseconds. */
public void kick(String reason, int kickDuration){
Log.info("Kicking connection {0}; Reason: {1}", address, reason.replace("\n", " ")); Log.info("Kicking connection {0}; Reason: {1}", address, reason.replace("\n", " "));
if(player != null && player.uuid != null){ if(player != null && player.uuid != null){
PlayerInfo info = netServer.admins.getInfo(player.uuid); PlayerInfo info = netServer.admins.getInfo(player.uuid);
info.timesKicked++; info.timesKicked++;
info.lastKicked = Math.max(Time.millis(), info.lastKicked); info.lastKicked = Math.max(Time.millis() + kickDuration, info.lastKicked);
} }
Call.onKick(this, reason); Call.onKick(this, reason);

View File

@@ -1,3 +1,3 @@
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=c365173e586b84c7edd062d82675001c7b96b0b8 archash=9f70d5a39a910bd855430d74e41d0b8753b47442