From f6d48c90f93b3d3a0560074d2cd9b3a9be891a64 Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Wed, 8 Apr 2026 20:41:09 +0100 Subject: [PATCH] reduce clientbound compression limits --- .../proxy/connection/MinecraftConnection.java | 4 +++- .../netty/MinecraftCompressDecoder.java | 23 ++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index f7de55e0f..151cbd303 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -38,6 +38,7 @@ import com.velocitypowered.proxy.connection.client.InitialLoginSessionHandler; import com.velocitypowered.proxy.connection.client.StatusSessionHandler; import com.velocitypowered.proxy.network.Connections; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.VelocityConnectionEvent; import com.velocitypowered.proxy.protocol.netty.MinecraftCipherDecoder; @@ -544,9 +545,10 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { } else { int level = server.getConfiguration().getCompressionLevel(); VelocityCompressor compressor = Natives.compress.get().create(level); + final MinecraftDecoder minecraftDecoder = (MinecraftDecoder) channel.pipeline().get(MINECRAFT_DECODER); encoder = new MinecraftCompressorAndLengthEncoder(threshold, compressor); - decoder = new MinecraftCompressDecoder(threshold, compressor); + decoder = new MinecraftCompressDecoder(threshold, compressor, minecraftDecoder.getDirection()); channel.pipeline().remove(FRAME_ENCODER); channel.pipeline().addBefore(MINECRAFT_DECODER, COMPRESSION_DECODER, decoder); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java index 1fe38e50e..9bd040efa 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java @@ -33,20 +33,26 @@ import java.util.List; */ public class MinecraftCompressDecoder extends MessageToMessageDecoder { + private static final int SERVERBOUND_MAXIMUM_UNCOMPRESSED_SIZE = 2 * 1024 * 1024; // 2MiB private static final int VANILLA_MAXIMUM_UNCOMPRESSED_SIZE = 8 * 1024 * 1024; // 8MiB private static final int HARD_MAXIMUM_UNCOMPRESSED_SIZE = 128 * 1024 * 1024; // 128MiB - private static final int UNCOMPRESSED_CAP = + private static final int CLIENTBOUND_UNCOMPRESSED_CAP = Boolean.getBoolean("velocity.increased-compression-cap") ? HARD_MAXIMUM_UNCOMPRESSED_SIZE : VANILLA_MAXIMUM_UNCOMPRESSED_SIZE; + private static final int SERVERBOUND_UNCOMPRESSED_CAP = + Boolean.getBoolean("velocity.increased-compression-cap") + ? HARD_MAXIMUM_UNCOMPRESSED_SIZE : SERVERBOUND_MAXIMUM_UNCOMPRESSED_SIZE; private static final boolean SKIP_COMPRESSION_VALIDATION = Boolean.getBoolean("velocity.skip-uncompressed-packet-size-validation"); + private final ProtocolUtils.Direction direction; private int threshold; private final VelocityCompressor compressor; - public MinecraftCompressDecoder(int threshold, VelocityCompressor compressor) { + public MinecraftCompressDecoder(int threshold, VelocityCompressor compressor, ProtocolUtils.Direction direction) { this.threshold = threshold; this.compressor = compressor; + this.direction = direction; } @Override @@ -65,10 +71,15 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder { checkFrame(claimedUncompressedSize >= threshold, "Uncompressed size %s is less than" + " threshold %s", claimedUncompressedSize, threshold); - checkFrame(claimedUncompressedSize <= UNCOMPRESSED_CAP, - "Uncompressed size %s exceeds hard threshold of %s", claimedUncompressedSize, - UNCOMPRESSED_CAP); - + if (direction == ProtocolUtils.Direction.CLIENTBOUND) { + checkFrame(claimedUncompressedSize <= CLIENTBOUND_UNCOMPRESSED_CAP, + "Uncompressed size %s exceeds hard threshold of %s", claimedUncompressedSize, + CLIENTBOUND_UNCOMPRESSED_CAP); + } else { + checkFrame(claimedUncompressedSize <= SERVERBOUND_UNCOMPRESSED_CAP, + "Uncompressed size %s exceeds hard threshold of %s", claimedUncompressedSize, + SERVERBOUND_UNCOMPRESSED_CAP); + } ByteBuf compatibleIn = ensureCompatible(ctx.alloc(), compressor, in); ByteBuf uncompressed = preferredBuffer(ctx.alloc(), compressor, claimedUncompressedSize); try {