mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-01 05:47:45 +01:00
Add packet limiter config
Example config: packet-limiter: kick-message: '&cSent too many packets' limits: all: interval: 7.0 max-packet-rate: 500.0 ServerboundPlaceRecipePacket: interval: 4.0 max-packet-rate: 5.0 action: DROP all section refers to all incoming packets, the action for all is hard coded to KICK. For specific limits, the section name is the class's name, and an action can be defined: DROP or KICK If interval or rate are less-than 0, the limit is ignored
This commit is contained in:
parent
740e6b1eed
commit
0277ecd75d
@ -29,7 +29,7 @@
|
|||||||
@Nullable
|
@Nullable
|
||||||
private volatile PacketListener disconnectListener;
|
private volatile PacketListener disconnectListener;
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -114,6 +119,24 @@
|
@@ -114,7 +119,41 @@
|
||||||
private volatile DisconnectionDetails delayedDisconnect;
|
private volatile DisconnectionDetails delayedDisconnect;
|
||||||
@Nullable
|
@Nullable
|
||||||
BandwidthDebugMonitor bandwidthDebugMonitor;
|
BandwidthDebugMonitor bandwidthDebugMonitor;
|
||||||
@ -39,7 +39,7 @@
|
|||||||
+ public java.net.InetSocketAddress virtualHost;
|
+ public java.net.InetSocketAddress virtualHost;
|
||||||
+ private static boolean enableExplicitFlush = Boolean.getBoolean("paper.explicit-flush"); // Paper - Disable explicit network manager flushing
|
+ private static boolean enableExplicitFlush = Boolean.getBoolean("paper.explicit-flush"); // Paper - Disable explicit network manager flushing
|
||||||
+ // Paper end
|
+ // Paper end
|
||||||
+
|
|
||||||
+ // Paper start - add utility methods
|
+ // Paper start - add utility methods
|
||||||
+ public final net.minecraft.server.level.ServerPlayer getPlayer() {
|
+ public final net.minecraft.server.level.ServerPlayer getPlayer() {
|
||||||
+ if (this.packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl impl) {
|
+ if (this.packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl impl) {
|
||||||
@ -51,10 +51,27 @@
|
|||||||
+ return null;
|
+ return null;
|
||||||
+ }
|
+ }
|
||||||
+ // Paper end - add utility methods
|
+ // Paper end - add utility methods
|
||||||
|
+ // Paper start - packet limiter
|
||||||
|
+ protected final Object PACKET_LIMIT_LOCK = new Object();
|
||||||
|
+ protected final @Nullable io.papermc.paper.util.IntervalledCounter allPacketCounts = io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.isEnabled() ? new io.papermc.paper.util.IntervalledCounter(
|
||||||
|
+ (long)(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.interval() * 1.0e9)
|
||||||
|
+ ) : null;
|
||||||
|
+ protected final java.util.Map<Class<? extends net.minecraft.network.protocol.Packet<?>>, io.papermc.paper.util.IntervalledCounter> packetSpecificLimits = new java.util.HashMap<>();
|
||||||
|
+
|
||||||
|
+ private boolean stopReadingPackets;
|
||||||
|
+ private void killForPacketSpam() {
|
||||||
|
+ this.sendPacket(new ClientboundDisconnectPacket(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage)), PacketSendListener.thenRun(() -> {
|
||||||
|
+ this.disconnect(io.papermc.paper.adventure.PaperAdventure.asVanilla(io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.kickMessage));
|
||||||
|
+ }), true);
|
||||||
|
+ this.setReadOnly();
|
||||||
|
+ this.stopReadingPackets = true;
|
||||||
|
+ }
|
||||||
|
+ // Paper end - packet limiter
|
||||||
|
+
|
||||||
public Connection(PacketFlow side) {
|
public Connection(PacketFlow side) {
|
||||||
this.receiving = side;
|
this.receiving = side;
|
||||||
@@ -123,6 +146,9 @@
|
}
|
||||||
|
@@ -123,6 +162,9 @@
|
||||||
super.channelActive(channelhandlercontext);
|
super.channelActive(channelhandlercontext);
|
||||||
this.channel = channelhandlercontext.channel();
|
this.channel = channelhandlercontext.channel();
|
||||||
this.address = this.channel.remoteAddress();
|
this.address = this.channel.remoteAddress();
|
||||||
@ -64,7 +81,7 @@
|
|||||||
if (this.delayedDisconnect != null) {
|
if (this.delayedDisconnect != null) {
|
||||||
this.disconnect(this.delayedDisconnect);
|
this.disconnect(this.delayedDisconnect);
|
||||||
}
|
}
|
||||||
@@ -141,8 +167,10 @@
|
@@ -141,8 +183,10 @@
|
||||||
|
|
||||||
this.handlingFault = true;
|
this.handlingFault = true;
|
||||||
if (this.channel.isOpen()) {
|
if (this.channel.isOpen()) {
|
||||||
@ -75,7 +92,7 @@
|
|||||||
this.disconnect((Component) Component.translatable("disconnect.timeout"));
|
this.disconnect((Component) Component.translatable("disconnect.timeout"));
|
||||||
} else {
|
} else {
|
||||||
MutableComponent ichatmutablecomponent = Component.translatable("disconnect.genericReason", "Internal Exception: " + String.valueOf(throwable));
|
MutableComponent ichatmutablecomponent = Component.translatable("disconnect.genericReason", "Internal Exception: " + String.valueOf(throwable));
|
||||||
@@ -155,6 +183,7 @@
|
@@ -155,6 +199,7 @@
|
||||||
disconnectiondetails = new DisconnectionDetails(ichatmutablecomponent);
|
disconnectiondetails = new DisconnectionDetails(ichatmutablecomponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +100,7 @@
|
|||||||
if (flag) {
|
if (flag) {
|
||||||
Connection.LOGGER.debug("Failed to sent packet", throwable);
|
Connection.LOGGER.debug("Failed to sent packet", throwable);
|
||||||
if (this.getSending() == PacketFlow.CLIENTBOUND) {
|
if (this.getSending() == PacketFlow.CLIENTBOUND) {
|
||||||
@@ -176,6 +205,7 @@
|
@@ -176,6 +221,7 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,7 +108,63 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) {
|
protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) {
|
||||||
@@ -205,7 +235,7 @@
|
@@ -185,6 +231,55 @@
|
||||||
|
if (packetlistener == null) {
|
||||||
|
throw new IllegalStateException("Received a packet before the packet listener was initialized");
|
||||||
|
} else {
|
||||||
|
+ // Paper start - packet limiter
|
||||||
|
+ if (this.stopReadingPackets) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ if (this.allPacketCounts != null ||
|
||||||
|
+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.containsKey(packet.getClass())) {
|
||||||
|
+ long time = System.nanoTime();
|
||||||
|
+ synchronized (PACKET_LIMIT_LOCK) {
|
||||||
|
+ if (this.allPacketCounts != null) {
|
||||||
|
+ this.allPacketCounts.updateAndAdd(1, time);
|
||||||
|
+ if (this.allPacketCounts.getRate() >= io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.allPackets.maxPacketRate()) {
|
||||||
|
+ this.killForPacketSpam();
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (Class<?> check = packet.getClass(); check != Object.class; check = check.getSuperclass()) {
|
||||||
|
+ io.papermc.paper.configuration.GlobalConfiguration.PacketLimiter.PacketLimit packetSpecificLimit =
|
||||||
|
+ io.papermc.paper.configuration.GlobalConfiguration.get().packetLimiter.overrides.get(check);
|
||||||
|
+ if (packetSpecificLimit == null || !packetSpecificLimit.isEnabled()) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ io.papermc.paper.util.IntervalledCounter counter = this.packetSpecificLimits.computeIfAbsent((Class)check, (clazz) -> {
|
||||||
|
+ return new io.papermc.paper.util.IntervalledCounter((long)(packetSpecificLimit.interval() * 1.0e9));
|
||||||
|
+ });
|
||||||
|
+ counter.updateAndAdd(1, time);
|
||||||
|
+ if (counter.getRate() >= packetSpecificLimit.maxPacketRate()) {
|
||||||
|
+ switch (packetSpecificLimit.action()) {
|
||||||
|
+ case DROP:
|
||||||
|
+ return;
|
||||||
|
+ case KICK:
|
||||||
|
+ String deobfedPacketName = io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(check.getName());
|
||||||
|
+
|
||||||
|
+ String playerName;
|
||||||
|
+ if (this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl impl) {
|
||||||
|
+ playerName = impl.getOwner().getName();
|
||||||
|
+ } else {
|
||||||
|
+ playerName = this.getLoggableAddress(net.minecraft.server.MinecraftServer.getServer().logIPs());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Connection.LOGGER.warn("{} kicked for packet spamming: {}", playerName, deobfedPacketName.substring(deobfedPacketName.lastIndexOf(".") + 1));
|
||||||
|
+ this.killForPacketSpam();
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Paper end - packet limiter
|
||||||
|
if (packetlistener.shouldHandleMessage(packet)) {
|
||||||
|
try {
|
||||||
|
Connection.genericsFtw(packet, packetlistener);
|
||||||
|
@@ -205,7 +300,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T extends PacketListener> void genericsFtw(Packet<T> packet, PacketListener listener) {
|
private static <T extends PacketListener> void genericsFtw(Packet<T> packet, PacketListener listener) {
|
||||||
@ -100,7 +173,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void validateListener(ProtocolInfo<?> state, PacketListener listener) {
|
private void validateListener(ProtocolInfo<?> state, PacketListener listener) {
|
||||||
@@ -418,12 +448,26 @@
|
@@ -418,12 +513,26 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +200,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isConnected() && !this.disconnectionHandled) {
|
if (!this.isConnected() && !this.disconnectionHandled) {
|
||||||
@@ -431,7 +475,7 @@
|
@@ -431,7 +540,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.channel != null) {
|
if (this.channel != null) {
|
||||||
@ -136,7 +209,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.tickCount++ % 20 == 0) {
|
if (this.tickCount++ % 20 == 0) {
|
||||||
@@ -464,12 +508,15 @@
|
@@ -464,12 +573,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disconnect(DisconnectionDetails disconnectionInfo) {
|
public void disconnect(DisconnectionDetails disconnectionInfo) {
|
||||||
@ -153,7 +226,7 @@
|
|||||||
this.disconnectionDetails = disconnectionInfo;
|
this.disconnectionDetails = disconnectionInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,7 +584,7 @@
|
@@ -537,7 +649,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public void configurePacketHandler(ChannelPipeline pipeline) {
|
public void configurePacketHandler(ChannelPipeline pipeline) {
|
||||||
@ -162,7 +235,7 @@
|
|||||||
public void write(ChannelHandlerContext channelhandlercontext, Object object, ChannelPromise channelpromise) throws Exception {
|
public void write(ChannelHandlerContext channelhandlercontext, Object object, ChannelPromise channelpromise) throws Exception {
|
||||||
super.write(channelhandlercontext, object, channelpromise);
|
super.write(channelhandlercontext, object, channelpromise);
|
||||||
}
|
}
|
||||||
@@ -633,6 +680,7 @@
|
@@ -633,6 +745,7 @@
|
||||||
} else {
|
} else {
|
||||||
this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressionThreshold));
|
this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressionThreshold));
|
||||||
}
|
}
|
||||||
@ -170,7 +243,7 @@
|
|||||||
} else {
|
} else {
|
||||||
if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) {
|
if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) {
|
||||||
this.channel.pipeline().remove("decompress");
|
this.channel.pipeline().remove("decompress");
|
||||||
@@ -641,6 +689,7 @@
|
@@ -641,6 +754,7 @@
|
||||||
if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) {
|
if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) {
|
||||||
this.channel.pipeline().remove("compress");
|
this.channel.pipeline().remove("compress");
|
||||||
}
|
}
|
||||||
@ -178,7 +251,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -661,6 +710,27 @@
|
@@ -661,6 +775,27 @@
|
||||||
|
|
||||||
packetlistener1.onDisconnect(disconnectiondetails);
|
packetlistener1.onDisconnect(disconnectiondetails);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user