diff options
Diffstat (limited to 'paper-server/patches/unapplied/net/minecraft/network/Connection.java.patch')
-rw-r--r-- | paper-server/patches/unapplied/net/minecraft/network/Connection.java.patch | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/paper-server/patches/unapplied/net/minecraft/network/Connection.java.patch b/paper-server/patches/unapplied/net/minecraft/network/Connection.java.patch new file mode 100644 index 0000000000..f1e414f6b1 --- /dev/null +++ b/paper-server/patches/unapplied/net/minecraft/network/Connection.java.patch @@ -0,0 +1,330 @@ +--- a/net/minecraft/network/Connection.java ++++ b/net/minecraft/network/Connection.java +@@ -82,13 +82,13 @@ + marker.add(Connection.PACKET_MARKER); + }); + public static final Supplier<NioEventLoopGroup> NETWORK_WORKER_GROUP = Suppliers.memoize(() -> { +- return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).build()); ++ return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper + }); + public static final Supplier<EpollEventLoopGroup> NETWORK_EPOLL_WORKER_GROUP = Suppliers.memoize(() -> { +- return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).build()); ++ return new EpollEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Epoll Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper + }); + public static final Supplier<DefaultEventLoopGroup> LOCAL_WORKER_GROUP = Suppliers.memoize(() -> { +- return new DefaultEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).build()); ++ return new DefaultEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Local Client IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build()); // Paper + }); + private static final ProtocolInfo<ServerHandshakePacketListener> INITIAL_PROTOCOL = HandshakeProtocols.SERVERBOUND; + private final PacketFlow receiving; +@@ -96,6 +96,11 @@ + private final Queue<Consumer<Connection>> pendingActions = Queues.newConcurrentLinkedQueue(); + public Channel channel; + public SocketAddress address; ++ // Spigot Start ++ public java.util.UUID spoofedUUID; ++ public com.mojang.authlib.properties.Property[] spoofedProfile; ++ public boolean preparing = true; ++ // Spigot End + @Nullable + private volatile PacketListener disconnectListener; + @Nullable +@@ -114,7 +119,42 @@ + private volatile DisconnectionDetails delayedDisconnect; + @Nullable + BandwidthDebugMonitor bandwidthDebugMonitor; ++ public String hostname = ""; // CraftBukkit - add field ++ // Paper start - NetworkClient implementation ++ public int protocolVersion; ++ public java.net.InetSocketAddress virtualHost; ++ private static boolean enableExplicitFlush = Boolean.getBoolean("paper.explicit-flush"); // Paper - Disable explicit network manager flushing ++ // Paper end + ++ // Paper start - add utility methods ++ public final net.minecraft.server.level.ServerPlayer getPlayer() { ++ if (this.packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl impl) { ++ return impl.player; ++ } else if (this.packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl impl) { ++ org.bukkit.craftbukkit.entity.CraftPlayer player = impl.getCraftPlayer(); ++ return player == null ? null : player.getHandle(); ++ } ++ return null; ++ } ++ // 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 ++ @Nullable public SocketAddress haProxyAddress; // Paper - Add API to get player's proxy address ++ + public Connection(PacketFlow side) { + this.receiving = side; + } +@@ -123,6 +163,9 @@ + super.channelActive(channelhandlercontext); + this.channel = channelhandlercontext.channel(); + this.address = this.channel.remoteAddress(); ++ // Spigot Start ++ this.preparing = false; ++ // Spigot End + if (this.delayedDisconnect != null) { + this.disconnect(this.delayedDisconnect); + } +@@ -134,6 +177,21 @@ + } + + public void exceptionCaught(ChannelHandlerContext channelhandlercontext, Throwable throwable) { ++ // Paper start - Handle large packets disconnecting client ++ if (throwable instanceof io.netty.handler.codec.EncoderException && throwable.getCause() instanceof PacketEncoder.PacketTooLargeException packetTooLargeException) { ++ final Packet<?> packet = packetTooLargeException.getPacket(); ++ if (packet.packetTooLarge(this)) { ++ ProtocolSwapHandler.handleOutboundTerminalPacket(channelhandlercontext, packet); ++ return; ++ } else if (packet.isSkippable()) { ++ Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause()); ++ ProtocolSwapHandler.handleOutboundTerminalPacket(channelhandlercontext, packet); ++ return; ++ } else { ++ throwable = throwable.getCause(); ++ } ++ } ++ // Paper end - Handle large packets disconnecting client + if (throwable instanceof SkipPacketException) { + Connection.LOGGER.debug("Skipping packet due to errors", throwable.getCause()); + } else { +@@ -141,8 +199,10 @@ + + this.handlingFault = true; + if (this.channel.isOpen()) { ++ net.minecraft.server.level.ServerPlayer player = this.getPlayer(); // Paper - Add API for quit reason + if (throwable instanceof TimeoutException) { + Connection.LOGGER.debug("Timeout", throwable); ++ if (player != null) player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.TIMED_OUT; // Paper - Add API for quit reason + this.disconnect((Component) Component.translatable("disconnect.timeout")); + } else { + MutableComponent ichatmutablecomponent = Component.translatable("disconnect.genericReason", "Internal Exception: " + String.valueOf(throwable)); +@@ -155,9 +215,11 @@ + disconnectiondetails = new DisconnectionDetails(ichatmutablecomponent); + } + ++ if (player != null) player.quitReason = org.bukkit.event.player.PlayerQuitEvent.QuitReason.ERRONEOUS_STATE; // Paper - Add API for quit reason + if (flag) { + Connection.LOGGER.debug("Failed to sent packet", throwable); +- if (this.getSending() == PacketFlow.CLIENTBOUND) { ++ boolean doesDisconnectExist = this.packetListener.protocol() != ConnectionProtocol.STATUS && this.packetListener.protocol() != ConnectionProtocol.HANDSHAKING; // Paper ++ if (this.getSending() == PacketFlow.CLIENTBOUND && doesDisconnectExist) { // Paper + Packet<?> packet = this.sendLoginDisconnect ? new ClientboundLoginDisconnectPacket(ichatmutablecomponent) : new ClientboundDisconnectPacket(ichatmutablecomponent); + + this.send((Packet) packet, PacketSendListener.thenRun(() -> { +@@ -176,6 +238,7 @@ + + } + } ++ if (net.minecraft.server.MinecraftServer.getServer().isDebugging()) io.papermc.paper.util.TraceUtil.printStackTrace(throwable); // Spigot // Paper + } + + protected void channelRead0(ChannelHandlerContext channelhandlercontext, Packet<?> packet) { +@@ -185,11 +248,61 @@ + 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); + } catch (RunningOnDifferentThreadException cancelledpackethandleexception) { + ; ++ } catch (io.papermc.paper.util.ServerStopRejectedExecutionException ignored) { // Paper - do not prematurely disconnect players on stop + } catch (RejectedExecutionException rejectedexecutionexception) { + this.disconnect((Component) Component.translatable("multiplayer.disconnect.server_shutdown")); + } catch (ClassCastException classcastexception) { +@@ -205,7 +318,7 @@ + } + + private static <T extends PacketListener> void genericsFtw(Packet<T> packet, PacketListener listener) { +- packet.handle(listener); ++ packet.handle((T) listener); // CraftBukkit - decompile error + } + + private void validateListener(ProtocolInfo<?> state, PacketListener listener) { +@@ -418,12 +531,26 @@ + } + } + ++ private static final int MAX_PER_TICK = io.papermc.paper.configuration.GlobalConfiguration.get().misc.maxJoinsPerTick; // Paper - Buffer joins to world ++ private static int joinAttemptsThisTick; // Paper - Buffer joins to world ++ private static int currTick; // Paper - Buffer joins to world + public void tick() { + this.flushQueue(); ++ // Paper start - Buffer joins to world ++ if (Connection.currTick != net.minecraft.server.MinecraftServer.currentTick) { ++ Connection.currTick = net.minecraft.server.MinecraftServer.currentTick; ++ Connection.joinAttemptsThisTick = 0; ++ } ++ // Paper end - Buffer joins to world + PacketListener packetlistener = this.packetListener; + + if (packetlistener instanceof TickablePacketListener tickablepacketlistener) { ++ // Paper start - Buffer joins to world ++ if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) ++ || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING ++ || Connection.joinAttemptsThisTick++ < MAX_PER_TICK) { + tickablepacketlistener.tick(); ++ } // Paper end - Buffer joins to world + } + + if (!this.isConnected() && !this.disconnectionHandled) { +@@ -431,7 +558,7 @@ + } + + if (this.channel != null) { +- this.channel.flush(); ++ if (enableExplicitFlush) this.channel.eventLoop().execute(() -> this.channel.flush()); // Paper - Disable explicit network manager flushing; we don't need to explicit flush here, but allow opt in incase issues are found to a better version + } + + if (this.tickCount++ % 20 == 0) { +@@ -464,12 +591,15 @@ + } + + public void disconnect(DisconnectionDetails disconnectionInfo) { ++ // Spigot Start ++ this.preparing = false; ++ // Spigot End + if (this.channel == null) { + this.delayedDisconnect = disconnectionInfo; + } + + if (this.isConnected()) { +- this.channel.close().awaitUninterruptibly(); ++ this.channel.close(); // We can't wait as this may be called from an event loop. + this.disconnectionDetails = disconnectionInfo; + } + +@@ -537,7 +667,7 @@ + } + + public void configurePacketHandler(ChannelPipeline pipeline) { +- pipeline.addLast("hackfix", new ChannelOutboundHandlerAdapter(this) { ++ pipeline.addLast("hackfix", new ChannelOutboundHandlerAdapter() { // CraftBukkit - decompile error + public void write(ChannelHandlerContext channelhandlercontext, Object object, ChannelPromise channelpromise) throws Exception { + super.write(channelhandlercontext, object, channelpromise); + } +@@ -613,6 +743,14 @@ + + } + ++ // Paper start - add proper async disconnect ++ public void enableAutoRead() { ++ if (this.channel != null) { ++ this.channel.config().setAutoRead(true); ++ } ++ } ++ // Paper end - add proper async disconnect ++ + public void setupCompression(int compressionThreshold, boolean rejectsBadPackets) { + if (compressionThreshold >= 0) { + ChannelHandler channelhandler = this.channel.pipeline().get("decompress"); +@@ -633,6 +771,7 @@ + } else { + this.channel.pipeline().addAfter("prepender", "compress", new CompressionEncoder(compressionThreshold)); + } ++ this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_THRESHOLD_SET); // Paper - Add Channel initialization listeners + } else { + if (this.channel.pipeline().get("decompress") instanceof CompressionDecoder) { + this.channel.pipeline().remove("decompress"); +@@ -641,6 +780,7 @@ + if (this.channel.pipeline().get("compress") instanceof CompressionEncoder) { + this.channel.pipeline().remove("compress"); + } ++ this.channel.pipeline().fireUserEventTriggered(io.papermc.paper.network.ConnectionEvent.COMPRESSION_DISABLED); // Paper - Add Channel initialization listeners + } + + } +@@ -661,6 +801,27 @@ + + packetlistener1.onDisconnect(disconnectiondetails); + } ++ this.pendingActions.clear(); // Free up packet queue. ++ // Paper start - Add PlayerConnectionCloseEvent ++ final PacketListener packetListener = this.getPacketListener(); ++ if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) { ++ /* Player was logged in, either game listener or configuration listener */ ++ final com.mojang.authlib.GameProfile profile = commonPacketListener.getOwner(); ++ new com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent(profile.getId(), ++ profile.getName(), ((InetSocketAddress) this.address).getAddress(), false).callEvent(); ++ } else if (packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginListener) { ++ /* Player is login stage */ ++ switch (loginListener.state) { ++ case VERIFYING: ++ case WAITING_FOR_DUPE_DISCONNECT: ++ case PROTOCOL_SWITCHING: ++ case ACCEPTED: ++ final com.mojang.authlib.GameProfile profile = loginListener.authenticatedProfile; /* Should be non-null at this stage */ ++ new com.destroystokyo.paper.event.player.PlayerConnectionCloseEvent(profile.getId(), profile.getName(), ++ ((InetSocketAddress) this.address).getAddress(), false).callEvent(); ++ } ++ } ++ // Paper end - Add PlayerConnectionCloseEvent + + } + } |