mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-29 12:37:42 +01:00
Add rate limiter for incoming packets
Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
parent
164cf9fe2b
commit
198618ba98
@ -60,10 +60,6 @@ public final class MinecraftServer {
|
||||
public static final int TICK_PER_SECOND = Integer.getInteger("minestom.tps", 20);
|
||||
public static final int TICK_MS = 1000 / TICK_PER_SECOND;
|
||||
|
||||
// Network monitoring
|
||||
private static int rateLimit = 300;
|
||||
private static int maxPacketSize = 30_000;
|
||||
|
||||
// In-Game Manager
|
||||
private static volatile ServerProcess serverProcess;
|
||||
|
||||
@ -112,42 +108,6 @@ public final class MinecraftServer {
|
||||
PacketUtils.broadcastPacket(PluginMessagePacket.getBrandPacket());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum number of packets a client can send over 1 second.
|
||||
*
|
||||
* @return the packet count limit over 1 second, 0 if not enabled
|
||||
*/
|
||||
public static int getRateLimit() {
|
||||
return rateLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the number of packet a client can send over 1 second without being disconnected.
|
||||
*
|
||||
* @param rateLimit the number of packet, 0 to disable
|
||||
*/
|
||||
public static void setRateLimit(int rateLimit) {
|
||||
MinecraftServer.rateLimit = rateLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum packet size (in bytes) that a client can send without getting disconnected.
|
||||
*
|
||||
* @return the maximum packet size
|
||||
*/
|
||||
public static int getMaxPacketSize() {
|
||||
return maxPacketSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the maximum packet size (in bytes) that a client can send without getting disconnected.
|
||||
*
|
||||
* @param maxPacketSize the new max packet size
|
||||
*/
|
||||
public static void setMaxPacketSize(int maxPacketSize) {
|
||||
MinecraftServer.maxPacketSize = maxPacketSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server difficulty showed in game option.
|
||||
*
|
||||
|
@ -44,6 +44,7 @@ import net.minestom.server.inventory.PlayerInventory;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.item.metadata.WrittenBookMeta;
|
||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||
import net.minestom.server.message.ChatMessageType;
|
||||
import net.minestom.server.message.ChatPosition;
|
||||
import net.minestom.server.message.Messenger;
|
||||
@ -106,6 +107,8 @@ import java.util.function.UnaryOperator;
|
||||
public class Player extends LivingEntity implements CommandSender, Localizable, HoverEventSource<ShowEntity>, Identified, NamedAndIdentified {
|
||||
|
||||
private static final Component REMOVE_MESSAGE = Component.text("You have been removed from the server without reason.", NamedTextColor.RED);
|
||||
private static final int PACKET_PER_TICK = Integer.getInteger("minestom.packet-per-tick", 20);
|
||||
private static final int PACKET_QUEUE_SIZE = Integer.getInteger("minestom.packet-queue-size", 1000);
|
||||
|
||||
private long lastKeepAlive;
|
||||
private boolean answerKeepAlive;
|
||||
@ -319,9 +322,6 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
|
||||
@Override
|
||||
public void update(long time) {
|
||||
// Network tick
|
||||
this.playerConnection.update();
|
||||
|
||||
// Process received packets
|
||||
interpretPacketQueue();
|
||||
|
||||
@ -1731,8 +1731,13 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
@ApiStatus.Internal
|
||||
@ApiStatus.Experimental
|
||||
public void interpretPacketQueue() {
|
||||
if (this.packets.size() >= PACKET_QUEUE_SIZE) {
|
||||
kick(Component.text("Too Many Packets", NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
final PacketListenerManager manager = MinecraftServer.getPacketListenerManager();
|
||||
// This method is NOT thread-safe
|
||||
this.packets.drain(packet -> MinecraftServer.getPacketListenerManager().processClientPacket(packet, this));
|
||||
this.packets.drain(packet -> manager.processClientPacket(packet, this), PACKET_PER_TICK);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,5 @@
|
||||
package net.minestom.server.network;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.packet.client.ClientPacket;
|
||||
import net.minestom.server.network.packet.client.ClientPacketsHandler;
|
||||
@ -41,11 +40,7 @@ public record PacketProcessor(@NotNull ClientPacketsHandler statusHandler,
|
||||
}
|
||||
|
||||
public void process(@NotNull PlayerConnection connection, int packetId, ByteBuffer body) {
|
||||
if (MinecraftServer.getRateLimit() > 0) {
|
||||
// Increment packet count (checked in PlayerConnection#update)
|
||||
connection.getPacketCounter().incrementAndGet();
|
||||
}
|
||||
var packet = create(connection.getConnectionState(), packetId, body);
|
||||
final ClientPacket packet = create(connection.getConnectionState(), packetId, body);
|
||||
if (packet instanceof ClientPreplayPacket prePlayPacket) {
|
||||
prePlayPacket.process(connection);
|
||||
} else {
|
||||
|
@ -1,11 +1,8 @@
|
||||
package net.minestom.server.network.player;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.server.network.packet.server.SendablePacket;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@ -15,57 +12,21 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* A PlayerConnection is an object needed for all created {@link Player}.
|
||||
* It can be extended to create a new kind of player (NPC for instance).
|
||||
*/
|
||||
public abstract class PlayerConnection {
|
||||
protected static final PacketListenerManager PACKET_LISTENER_MANAGER = MinecraftServer.getPacketListenerManager();
|
||||
|
||||
private Player player;
|
||||
private volatile ConnectionState connectionState;
|
||||
volatile boolean online;
|
||||
|
||||
// Text used to kick client sending too many packets
|
||||
private static final Component rateLimitKickMessage = Component.text("Too Many Packets", NamedTextColor.RED);
|
||||
|
||||
//Connection Stats
|
||||
private final AtomicInteger packetCounter = new AtomicInteger(0);
|
||||
private final AtomicInteger lastPacketCounter = new AtomicInteger(0);
|
||||
private short tickCounter = 0;
|
||||
|
||||
public PlayerConnection() {
|
||||
this.online = true;
|
||||
this.connectionState = ConnectionState.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates values related to the network connection.
|
||||
*/
|
||||
public void update() {
|
||||
// Check rate limit
|
||||
if (MinecraftServer.getRateLimit() > 0) {
|
||||
tickCounter++;
|
||||
if (tickCounter % MinecraftServer.TICK_PER_SECOND == 0 && tickCounter > 0) {
|
||||
tickCounter = 0;
|
||||
// Retrieve the packet count
|
||||
final int count = packetCounter.getAndSet(0);
|
||||
this.lastPacketCounter.set(count);
|
||||
if (count > MinecraftServer.getRateLimit()) {
|
||||
// Sent too many packets
|
||||
player.kick(rateLimitKickMessage);
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public @NotNull AtomicInteger getPacketCounter() {
|
||||
return packetCounter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a printable identifier for this connection, will be the player username
|
||||
* or the connection remote address.
|
||||
@ -189,15 +150,6 @@ public abstract class PlayerConnection {
|
||||
return connectionState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of packet the client sent over the last second.
|
||||
*
|
||||
* @return the number of packet sent over the last second
|
||||
*/
|
||||
public int getLastPacketCounter() {
|
||||
return lastPacketCounter.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PlayerConnection{" +
|
||||
|
Loading…
Reference in New Issue
Block a user