From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Telesphoreo Date: Fri, 22 Apr 2022 01:30:41 -0500 Subject: [PATCH] block server-side chunkbans diff --git a/src/main/java/net/minecraft/network/PacketEncoder.java b/src/main/java/net/minecraft/network/PacketEncoder.java index 5fce1177e7198d791d4ab1c64b394c5b1c145782..273af3a2e336c4dd23ef0028f51bcb5d3e9b26e4 100644 --- a/src/main/java/net/minecraft/network/PacketEncoder.java +++ b/src/main/java/net/minecraft/network/PacketEncoder.java @@ -5,9 +5,17 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import io.papermc.paper.adventure.PaperAdventure; // Paper + import java.io.IOException; + +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.game.*; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.util.profiling.jfr.JvmProfiler; import org.slf4j.Logger; @@ -41,30 +49,93 @@ public class PacketEncoder extends MessageToByteEncoder> { packet.write(friendlyByteBuf); int j = friendlyByteBuf.writerIndex() - i; if (j > 8388608) { - throw new IllegalArgumentException("Packet too big (is " + j + ", should be less than 8388608): " + packet); - } else { - int k = channelHandlerContext.channel().attr(Connection.ATTRIBUTE_PROTOCOL).get().getId(); - JvmProfiler.INSTANCE.onPacketSent(k, integer, channelHandlerContext.channel().remoteAddress(), j); + // Scissors start + noKicking(friendlyByteBuf, packet, integer, channelHandlerContext); + //throw new IllegalArgumentException("Packet too big (is " + j + ", should be less than 8388608): " + packet); + // Scissors end } } catch (Throwable var10) { + // Scissors start + noKicking(friendlyByteBuf, packet, integer, channelHandlerContext); + /* LOGGER.error("Packet encoding of packet ID {} threw (skippable? {})", integer, packet.isSkippable(), var10); // Paper - Give proper error message if (packet.isSkippable()) { throw new SkipPacketException(var10); } else { throw var10; } + */ + // Scissors end } // Paper start int packetLength = friendlyByteBuf.readableBytes(); if (packetLength > MAX_PACKET_SIZE) { - throw new PacketTooLargeException(packet, packetLength); + // Scissors start + friendlyByteBuf.clear(); + noKicking(friendlyByteBuf, packet, integer, channelHandlerContext); + packetLength = friendlyByteBuf.readableBytes(); + if (packetLength > MAX_PACKET_SIZE) { + friendlyByteBuf.clear(); + //throw new PacketTooLargeException(packet, packetLength); + } + //throw new PacketTooLargeException(packet, packetLength); + // Scissors end } // Paper end } } } + // Scissors start + private static void noKicking(FriendlyByteBuf friendlyByteBuf, Packet packet, Integer integer, ChannelHandlerContext channelHandlerContext) { + // no kicking!! + friendlyByteBuf.clear(); + friendlyByteBuf.writeVarInt(integer); + friendlyByteBuf.adventure$locale = channelHandlerContext.channel().attr(PaperAdventure.LOCALE_ATTRIBUTE).get(); // Paper + boolean didIt = true; + if (packet instanceof ClientboundBlockEntityDataPacket blockEntityDataPacket) { + packet = new ClientboundBlockEntityDataPacket(blockEntityDataPacket.getPos(), blockEntityDataPacket.getType(), new CompoundTag()); + } else if (packet instanceof ClientboundLevelChunkPacket chunkPacket) { + chunkPacket.clearNbt(); + } else if (packet instanceof ClientboundSetEntityDataPacket entityDataPacket) { + friendlyByteBuf.writeVarInt(entityDataPacket.getId()); + friendlyByteBuf.writeByte(255); + didIt = false;//prevent default packet writing + } else if (packet instanceof ClientboundContainerSetContentPacket containerSetContentPacket) { + containerSetContentPacket.clearNbt(); + } else if (packet instanceof ClientboundSetEquipmentPacket setEquipmentPacket) { + friendlyByteBuf.writeVarInt(setEquipmentPacket.getEntity()); + didIt = false;//prevent default + } else if (packet instanceof ClientboundContainerSetSlotPacket containerSetSlotPacket) { + //i really would rather cancel this packet entirely buuut idk how sOOOOoooo + friendlyByteBuf.writeByte(containerSetSlotPacket.getContainerId()); + friendlyByteBuf.writeVarInt(containerSetSlotPacket.getStateId()); + friendlyByteBuf.writeShort(containerSetSlotPacket.getSlot()); + friendlyByteBuf.writeItem(ItemStack.EMPTY); + didIt = false;//prevent default + } else if (packet instanceof ClientboundMapItemDataPacket mapItemDataPacket) { + packet = new ClientboundMapItemDataPacket(mapItemDataPacket.getMapId(),mapItemDataPacket.getScale(),mapItemDataPacket.isLocked(),null,null); + } else { + didIt = false; + LOGGER.info(packet.getClass().getName() + " overflowed/errored and was not caught!!"); + } + if (didIt) { + try { + int i = friendlyByteBuf.writerIndex(); + packet.write(friendlyByteBuf); + int j = friendlyByteBuf.writerIndex() - i; + if (j > 8388608) { + friendlyByteBuf.clear(); + //throw new IllegalArgumentException("Packet too big (is " + j + ", should be less than 8388608): " + packet); + } + } catch (Throwable var69) { + friendlyByteBuf.clear(); + } + } + } + // Scissors end + // Paper start private static int MAX_PACKET_SIZE = 2097152; diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java index dbd8b9b09b82c1b75e8be9dc7416d9f0863c8c87..f71f68d1482f7e0481a95533e42e8ee5089f15ff 100644 --- a/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java +++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundContainerSetContentPacket.java @@ -10,7 +10,14 @@ public class ClientboundContainerSetContentPacket implements Packet items; - private final ItemStack carriedItem; + private ItemStack carriedItem; // Scissors - removed "final" + + // Scissors start + public void clearNbt(){ + this.items.clear(); + this.carriedItem = ItemStack.EMPTY; + } + // Scissors end public ClientboundContainerSetContentPacket(int syncId, int revision, NonNullList contents, ItemStack cursorStack) { this.containerId = syncId; diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacket.java new file mode 100644 index 0000000000000000000000000000000000000000..89c385c5ec88c8b51f9e118b65f3b9c2a58c7d9b --- /dev/null +++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacket.java @@ -0,0 +1,212 @@ +package net.minecraft.network.protocol.game; + +import com.google.common.collect.Lists; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import java.util.BitSet; +import java.util.List; +import java.util.Map.Entry; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.LongArrayTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.protocol.Packet; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.chunk.ChunkBiomeContainer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; + +public class ClientboundLevelChunkPacket implements Packet { + public static final int TWO_MEGABYTES = 2097152; + private final int x; + private final int z; + private final BitSet availableSections; + private final CompoundTag heightmaps; + private final int[] biomes; + private final byte[] buffer; + private final List blockEntitiesTags; + // Paper start + private final java.util.List extraPackets = new java.util.ArrayList<>(); + private static final int TE_LIMIT = Integer.getInteger("Paper.excessiveTELimit", 750); + + @Override + public java.util.List getExtraPackets() { + return extraPackets; + } + // Paper end + + // Paper start - Async-Anti-Xray - Ready flag for the connection + private volatile boolean ready; + + @Override + public boolean isReady() { + return this.ready; + } + + public void setReady(boolean ready) { + this.ready = ready; + } + // Paper end + + // Scissors start + public void clearNbt() { + this.blockEntitiesTags.clear(); + this.extraPackets.clear(); + } + // Scissors end + + // Paper start - Anti-Xray - Add chunk packet info + @Deprecated public ClientboundLevelChunkPacket(LevelChunk chunk) { this(chunk, true); } // Notice for updates: Please make sure this constructor isn't used anywhere + public ClientboundLevelChunkPacket(LevelChunk chunk, boolean modifyBlocks) { + com.destroystokyo.paper.antixray.ChunkPacketInfo chunkPacketInfo = modifyBlocks ? chunk.level.chunkPacketBlockController.getChunkPacketInfo(this, chunk) : null; + // Paper end + ChunkPos chunkPos = chunk.getPos(); + this.x = chunkPos.x; + this.z = chunkPos.z; + this.heightmaps = new CompoundTag(); + + for(Entry entry : chunk.getHeightmaps()) { + if (entry.getKey().sendToClient()) { + this.heightmaps.put(entry.getKey().getSerializationKey(), new LongArrayTag(entry.getValue().getRawData())); + } + } + + this.biomes = chunk.getBiomes().writeBiomes(); + this.buffer = new byte[this.calculateChunkSize(chunk)]; + + // Paper start - Anti-Xray - Add chunk packet info + if (chunkPacketInfo != null) { + chunkPacketInfo.setBuffer(this.buffer); + } + + this.availableSections = this.extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), chunk, chunkPacketInfo); + // Paper end + this.blockEntitiesTags = Lists.newArrayList(); + int totalTileEntities = 0; // Paper + + for(Entry entry2 : chunk.getBlockEntities().entrySet()) { + BlockEntity blockEntity = entry2.getValue(); + // Paper start - improve oversized chunk data packet handling + if (++totalTileEntities > TE_LIMIT) { + ClientboundBlockEntityDataPacket updatePacket = blockEntity.getUpdatePacket(); + if (updatePacket != null) { + this.extraPackets.add(updatePacket); + continue; + } + } + // Paper end + CompoundTag compoundTag = blockEntity.getUpdateTag(); + if (blockEntity instanceof net.minecraft.world.level.block.entity.SkullBlockEntity) { net.minecraft.world.level.block.entity.SkullBlockEntity.sanitizeTileEntityUUID(compoundTag); } // Paper + this.blockEntitiesTags.add(compoundTag); + } + + chunk.level.chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks + } + + public ClientboundLevelChunkPacket(FriendlyByteBuf buf) { + this.x = buf.readInt(); + this.z = buf.readInt(); + this.availableSections = buf.readBitSet(); + this.heightmaps = buf.readNbt(); + if (this.heightmaps == null) { + throw new RuntimeException("Can't read heightmap in packet for [" + this.x + ", " + this.z + "]"); + } else { + this.biomes = buf.readVarIntArray(ChunkBiomeContainer.MAX_SIZE); + int i = buf.readVarInt(); + if (i > 2097152) { // Paper - diff on change - if this changes, update PacketEncoder + throw new RuntimeException("Chunk Packet trying to allocate too much memory on read."); + } else { + this.buffer = new byte[i]; + buf.readBytes(this.buffer); + this.blockEntitiesTags = buf.readList(FriendlyByteBuf::readNbt); + } + } + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeInt(this.x); + buf.writeInt(this.z); + buf.writeBitSet(this.availableSections); + buf.writeNbt(this.heightmaps); + buf.writeVarIntArray(this.biomes); + buf.writeVarInt(this.buffer.length); + buf.writeBytes(this.buffer); + buf.writeCollection(this.blockEntitiesTags, FriendlyByteBuf::writeNbt); + } + + @Override + public void handle(ClientGamePacketListener listener) { + listener.handleLevelChunk(this); + } + + public FriendlyByteBuf getReadBuffer() { + return new FriendlyByteBuf(Unpooled.wrappedBuffer(this.buffer)); + } + + private ByteBuf getWriteBuffer() { + ByteBuf byteBuf = Unpooled.wrappedBuffer(this.buffer); + byteBuf.writerIndex(0); + return byteBuf; + } + + // Paper start - Anti-Xray - Add chunk packet info + @Deprecated public BitSet extractChunkData(FriendlyByteBuf buf, LevelChunk chunk) { return extractChunkData(buf, chunk, null); } // Notice for updates: Please make sure this method isn't used anywhere + public BitSet extractChunkData(FriendlyByteBuf buf, LevelChunk chunk, com.destroystokyo.paper.antixray.ChunkPacketInfo chunkPacketInfo) { + // Paper end + BitSet bitSet = new BitSet(); + LevelChunkSection[] levelChunkSections = chunk.getSections(); + int i = 0; + + for(int j = levelChunkSections.length; i < j; ++i) { + LevelChunkSection levelChunkSection = levelChunkSections[i]; + if (levelChunkSection != LevelChunk.EMPTY_SECTION && !levelChunkSection.isEmpty()) { + bitSet.set(i); + levelChunkSection.write(buf, chunkPacketInfo); // Paper - Anti-Xray - Add chunk packet info + } + } + + return bitSet; + } + + protected int calculateChunkSize(LevelChunk chunk) { + int i = 0; + LevelChunkSection[] levelChunkSections = chunk.getSections(); + int j = 0; + + for(int k = levelChunkSections.length; j < k; ++j) { + LevelChunkSection levelChunkSection = levelChunkSections[j]; + if (levelChunkSection != LevelChunk.EMPTY_SECTION && !levelChunkSection.isEmpty()) { + i += levelChunkSection.getSerializedSize(); + } + } + + return i; + } + + public int getX() { + return this.x; + } + + public int getZ() { + return this.z; + } + + public BitSet getAvailableSections() { + return this.availableSections; + } + + public CompoundTag getHeightmaps() { + return this.heightmaps; + } + + public List getBlockEntitiesTags() { + return this.blockEntitiesTags; + } + + public int[] getBiomes() { + return this.biomes; + } +}