ResourcePack limit

This commit is contained in:
OurLobanov 2024-06-21 17:15:42 +03:00
parent 383d16d49b
commit 644cbb05f8
2 changed files with 69 additions and 51 deletions

View file

@ -9,30 +9,37 @@ import java.util.HashMap;
import java.util.Map;
public class PacketCooldownManager {
private static final Map<String, CooldownSettings> PACKET_COOLDOWN_SETTINGS = new HashMap<>();
static {
setPacketCooldown(LoginPacket.class, -1, 2);
setPacketCooldown(TextPacket.class, 1000, 10);
setPacketCooldown(CommandRequestPacket.class, 1000, 10);
setPacketCooldown(ModalFormResponsePacket.class, 1000, 10);
}
private final Map<String, CooldownSettings> packetCooldownSettings = new HashMap<>();
private final GeyserSession session;
@Setter
private long cooldownMillisDebug;
private long expiryTimeMillisDebug;
public static void setPacketCooldown(Class<? extends BedrockPacket> packetClass, int cooldownMillis, int maxCount) {
PACKET_COOLDOWN_SETTINGS.put(packetClass.getSimpleName(), new CooldownSettings(cooldownMillis, maxCount));
public PacketCooldownManager(GeyserSession session, long cooldownMillisDebug) {
this.session = session;
this.setCooldownMillisDebug(cooldownMillisDebug);
this.expiryTimeMillisDebug = 0;
setPacketCooldown(LoginPacket.class, -1, 2);
setPacketCooldown(ResourcePackClientResponsePacket.class, -1, 4);
setPacketCooldown(ResourcePackChunkRequestPacket.class, -1, 0);
setPacketCooldown(TextPacket.class, 1000, 10);
setPacketCooldown(CommandRequestPacket.class, 1000, 10);
setPacketCooldown(ModalFormResponsePacket.class, 1000, 10);
}
public void setPacketCooldown(Class<? extends BedrockPacket> packetClass, int cooldownMillis, int maxCount) {
packetCooldownSettings.put(packetClass.getSimpleName(), new CooldownSettings(cooldownMillis, maxCount));
}
private final Map<String, CooldownTracker> activeCooldowns = new HashMap<>();
private boolean isCooldownActive(String packetName) {
private boolean isCooldownActive(BedrockPacket packet) {
String packetName = packet.getClass().getSimpleName();
CooldownTracker tracker = activeCooldowns.get(packetName);
if (tracker != null && tracker.getCount() >= PACKET_COOLDOWN_SETTINGS.get(packetName).maxCount()) {
if (tracker.getExpiryTime() <= System.currentTimeMillis()) {
if (tracker != null && tracker.getCount() >= packetCooldownSettings.get(packetName).maxCount()) {
if (tracker.getExpiryTime() != -1 && tracker.getExpiryTime() <= System.currentTimeMillis()) {
activeCooldowns.remove(packetName);
} else {
return true;
@ -41,22 +48,27 @@ public class PacketCooldownManager {
return false;
}
private void updateCooldown(String packetName, long cooldownMillis) {
private void updateCooldown(BedrockPacket packet) {
String packetName = packet.getClass().getSimpleName();
CooldownSettings settings = packetCooldownSettings.get(packetName);
activeCooldowns.computeIfAbsent(packetName, k -> new CooldownTracker());
CooldownTracker tracker = activeCooldowns.get(packetName);
tracker.incrementCount();
tracker.setExpiryTime(System.currentTimeMillis() + cooldownMillis);
if (settings.cooldownMillis() == -1) {
tracker.setExpiryTime(settings.cooldownMillis());
} else {
tracker.setExpiryTime(System.currentTimeMillis() + settings.cooldownMillis());
}
}
public boolean handle(BedrockPacket packet) {
String packetName = packet.getClass().getSimpleName();
if (PACKET_COOLDOWN_SETTINGS.containsKey(packetName)) {
CooldownSettings settings = PACKET_COOLDOWN_SETTINGS.get(packetName);
updateCooldown(packetName, settings.cooldownMillis());
if (isCooldownActive(packetName)) {
if (packetCooldownSettings.containsKey(packetName)) {
updateCooldown(packet);
if (isCooldownActive(packet)) {
if (expiryTimeMillisDebug <= System.currentTimeMillis()) {
CooldownTracker tracker = activeCooldowns.get(packetName);
String message = session.getSocketAddress().getAddress().toString() + " -> Attempted to send too many packets " + packet.getClass().getSimpleName() + "count " + tracker.getCount();
String message = session.getSocketAddress().getAddress().toString() + " -> Attempted to send too many packets " + packet.getClass().getSimpleName() + " count " + tracker.getCount();
if (session.isLoggedIn()) {
message += " by user " + session.bedrockUsername();
}
@ -69,16 +81,9 @@ public class PacketCooldownManager {
return true;
}
public PacketCooldownManager(GeyserSession session, long cooldownMillisDebug) {
this.session = session;
this.setCooldownMillisDebug(cooldownMillisDebug);
this.expiryTimeMillisDebug = 0;
}
private record CooldownSettings(int cooldownMillis, int maxCount) {
}
@Getter
private class CooldownTracker {
private long count;

View file

@ -36,20 +36,7 @@ import org.cloudburstmc.protocol.bedrock.data.ResourcePackType;
import org.cloudburstmc.protocol.bedrock.netty.codec.compression.CompressionStrategy;
import org.cloudburstmc.protocol.bedrock.netty.codec.compression.SimpleCompressionStrategy;
import org.cloudburstmc.protocol.bedrock.netty.codec.compression.ZlibCompression;
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
import org.cloudburstmc.protocol.bedrock.packet.LoginPacket;
import org.cloudburstmc.protocol.bedrock.packet.ModalFormResponsePacket;
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
import org.cloudburstmc.protocol.bedrock.packet.NetworkSettingsPacket;
import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket;
import org.cloudburstmc.protocol.bedrock.packet.RequestNetworkSettingsPacket;
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackChunkDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackChunkRequestPacket;
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackClientResponsePacket;
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackDataInfoPacket;
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackStackPacket;
import org.cloudburstmc.protocol.bedrock.packet.ResourcePacksInfoPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket;
import org.cloudburstmc.protocol.bedrock.packet.*;
import org.cloudburstmc.protocol.common.PacketSignal;
import org.cloudburstmc.protocol.common.util.Zlib;
import org.geysermc.geyser.Constants;
@ -73,15 +60,12 @@ import org.geysermc.geyser.util.VersionCheckUtils;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.OptionalInt;
public class UpstreamPacketHandler extends LoggingPacketHandler {
private boolean networkSettingsRequested = false;
private final Deque<String> packsToSent = new ArrayDeque<>();
private final CompressionStrategy compressionStrategy;
private SessionLoadResourcePacksEventImpl resourcePackLoadEvent;
@ -226,6 +210,13 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
@Override
public PacketSignal handle(ResourcePackClientResponsePacket packet) {
if (this.handleLimit(packet)) {
return PacketSignal.HANDLED;
}
if (packet.getPackIds().size() > this.resourcePackLoadEvent.getPacks().size()) {
session.disconnect("Packet " + packet.getClass().getName() + " PackIds max count");
return PacketSignal.HANDLED;
}
switch (packet.getStatus()) {
case COMPLETED:
if (geyser.getConfig().getRemote().authType() != AuthType.ONLINE) {
@ -238,8 +229,24 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
break;
case SEND_PACKS:
packsToSent.addAll(packet.getPackIds());
sendPackDataInfo(packsToSent.pop());
int chunkIndex = 1;
for (String id : packet.getPackIds()) {
String[] packID = id.split("_", 2);
if (packID.length != 2) {
session.disconnect("Invalid packID id: " + id);
break;
}
ResourcePack pack = this.resourcePackLoadEvent.getPacks().get(packID[0]);
if (pack == null) {
session.disconnect("Invalid request unknown pack " + packID[0] + ", available packs: " + this.resourcePackLoadEvent.getPacks().keySet());
break;
}
sendPackDataInfo(id);
chunkIndex += (int) ((this.resourcePackLoadEvent.getPacks().get(packID[0]).codec().size() + GeyserResourcePack.CHUNK_SIZE) / GeyserResourcePack.CHUNK_SIZE);
}
cooldownHandler.setPacketCooldown(ResourcePackChunkRequestPacket.class, -1, chunkIndex);
break;
case HAVE_ALL_PACKS:
@ -317,8 +324,15 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
@Override
public PacketSignal handle(ResourcePackChunkRequestPacket packet) {
if (this.handleLimit(packet)) {
return PacketSignal.HANDLED;
}
ResourcePackChunkDataPacket data = new ResourcePackChunkDataPacket();
ResourcePack pack = this.resourcePackLoadEvent.getPacks().get(packet.getPackId().toString());
if (pack == null) {
session.disconnect("Invalid request for chunk " + packet.getChunkIndex() + " of unknown pack " + packet.getPackId() + ", available packs: " + this.resourcePackLoadEvent.getPacks().keySet());
return PacketSignal.HANDLED;
}
PackCodec codec = pack.codec();
data.setChunkIndex(packet.getChunkIndex());
@ -327,6 +341,10 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
data.setPackId(packet.getPackId());
int offset = packet.getChunkIndex() * GeyserResourcePack.CHUNK_SIZE;
if (offset < 0 || offset >= codec.size()) {
session.disconnect("Invalid out-of-bounds request for chunk " + packet.getChunkIndex() + " of " + packet.getPackId() + " offset " + offset + ", file size " + codec.size());
return PacketSignal.HANDLED;
}
long remainingSize = codec.size() - offset;
byte[] packData = new byte[(int) MathUtils.constrain(remainingSize, 0, GeyserResourcePack.CHUNK_SIZE)];
@ -341,11 +359,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
session.sendUpstreamPacket(data);
// Check if it is the last chunk and send next pack in queue when available.
if (remainingSize <= GeyserResourcePack.CHUNK_SIZE && !packsToSent.isEmpty()) {
sendPackDataInfo(packsToSent.pop());
}
return PacketSignal.HANDLED;
}