From 437d1c055c61527d53f38179ba07fbed68c3e1a5 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sun, 3 Mar 2024 18:36:28 +0100 Subject: [PATCH] Fixed ReplayMod, FML2, FML3, FORGE, Hostname detection Signed-off-by: Lixfel --- build.gradle | 9 ++ src/de/steamwar/bungeecore/BungeeCore.java | 3 +- src/de/steamwar/bungeecore/Node.java | 8 +- ...verProtocolFixer.java => IPSanitizer.java} | 57 ++++---- .../bungeecore/listeners/PluginMessage.java | 64 +++++++-- src/de/steamwar/bungeecore/mods/FML.java | 8 +- src/de/steamwar/bungeecore/mods/FML2.java | 126 +++++++++++------- src/de/steamwar/bungeecore/mods/Hostname.java | 58 ++++++++ .../steamwar/bungeecore/mods/ReplayMod.java | 40 +++--- .../bungeecore/mods/ServerListPing.java | 56 -------- .../bungeecore/mods/WorldDownloader.java | 3 + 11 files changed, 261 insertions(+), 171 deletions(-) rename src/de/steamwar/bungeecore/listeners/{SubserverProtocolFixer.java => IPSanitizer.java} (52%) create mode 100644 src/de/steamwar/bungeecore/mods/Hostname.java diff --git a/build.gradle b/build.gradle index 95a7911f..c88301df 100644 --- a/build.gradle +++ b/build.gradle @@ -71,6 +71,15 @@ repositories { } } +shadowJar { + exclude 'META-INF/*' + //https://imperceptiblethoughts.com/shadow/configuration/minimizing/ + minimize { + exclude project(':') + } + duplicatesStrategy DuplicatesStrategy.INCLUDE +} + dependencies { compileOnly 'org.projectlombok:lombok:1.18.22' testCompileOnly 'org.projectlombok:lombok:1.18.22' diff --git a/src/de/steamwar/bungeecore/BungeeCore.java b/src/de/steamwar/bungeecore/BungeeCore.java index c043d27c..5c34f26e 100644 --- a/src/de/steamwar/bungeecore/BungeeCore.java +++ b/src/de/steamwar/bungeecore/BungeeCore.java @@ -92,6 +92,7 @@ public class BungeeCore extends Plugin { }); ProxyServer.getInstance().getScheduler().schedule(this, TabCompletionCache::invalidateOldEntries, 1, 1, TimeUnit.SECONDS); + new Hostname(); new ServerListPing(); new PluginMessage(); new Schematica(); @@ -104,7 +105,7 @@ public class BungeeCore extends Plugin { new ChatListener(); new BanListener(); new CheckListener(); - new SubserverProtocolFixer(); + new IPSanitizer(); local = new Node.LocalNode(); if(MAIN_SERVER) { diff --git a/src/de/steamwar/bungeecore/Node.java b/src/de/steamwar/bungeecore/Node.java index 682e4d65..b7b244cd 100644 --- a/src/de/steamwar/bungeecore/Node.java +++ b/src/de/steamwar/bungeecore/Node.java @@ -22,7 +22,10 @@ package de.steamwar.bungeecore; import net.md_5.bungee.BungeeCord; import net.md_5.bungee.api.ProxyServer; -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; import java.nio.file.Files; import java.util.*; import java.util.concurrent.TimeUnit; @@ -31,6 +34,7 @@ import java.util.logging.Level; public abstract class Node { + //-Xquickstart Langzeitperformance testen! private static final List OPENJ9_ARGS = Arrays.asList( "-XX:+EnableCRIUSupport", "-XX:-CRIURestoreNonPortableMode", "-Xgc:excessiveGCratio=80", "-Xdisableexplicitgc", "-Xnoclassgc", "-Xmos128M", "-Xmns48M", "-XX:+ExitOnOutOfMemoryError", // initial heap half values of memory observed by 1.19 spectate server @@ -118,6 +122,8 @@ public abstract class Node { cmd.add(worldDir); cmd.add("--level-name"); cmd.add(levelName); + cmd.add("--plugins"); + cmd.add("/home/lixfel/bpl"); cmd.add("--port"); cmd.add(String.valueOf(port)); cmd.add("nogui"); diff --git a/src/de/steamwar/bungeecore/listeners/SubserverProtocolFixer.java b/src/de/steamwar/bungeecore/listeners/IPSanitizer.java similarity index 52% rename from src/de/steamwar/bungeecore/listeners/SubserverProtocolFixer.java rename to src/de/steamwar/bungeecore/listeners/IPSanitizer.java index ff74ed7c..cc637ea1 100644 --- a/src/de/steamwar/bungeecore/listeners/SubserverProtocolFixer.java +++ b/src/de/steamwar/bungeecore/listeners/IPSanitizer.java @@ -19,52 +19,41 @@ package de.steamwar.bungeecore.listeners; -import net.md_5.bungee.BungeeCord; +import de.steamwar.bungeecore.BungeeCore; import net.md_5.bungee.api.event.LoginEvent; import net.md_5.bungee.connection.InitialHandler; -import net.md_5.bungee.connection.LoginResult; import net.md_5.bungee.event.EventHandler; -import net.md_5.bungee.protocol.Property; -import net.md_5.bungee.util.AddressUtil; +import net.md_5.bungee.netty.ChannelWrapper; import java.lang.reflect.Field; import java.net.InetSocketAddress; import java.util.logging.Level; -public class SubserverProtocolFixer extends BasicListener { +public class IPSanitizer extends BasicListener { + + private static final Field initialHandlerCh; + static { + try { + initialHandlerCh = InitialHandler.class.getDeclaredField("ch"); + } catch (NoSuchFieldException e) { + throw new SecurityException("Could not initialize Reflection", e); + } + initialHandlerCh.setAccessible(true); + } + + public static ChannelWrapper getChannelWrapper(InitialHandler handler) { + try { + return (ChannelWrapper) initialHandlerCh.get(handler); + } catch (IllegalAccessException e) { + throw new SecurityException("Could not get channel wrapper", e); + } + } private final InetSocketAddress inetSocketAddress = new InetSocketAddress("127.127.127.127", 25565); - private Field field; - - { - try { - field = InitialHandler.class.getDeclaredField("extraDataInHandshake"); - field.setAccessible(true); - } catch (NoSuchFieldException e) { - BungeeCord.getInstance().getLogger().log(Level.SEVERE, e.getMessage(), e); - } - } - @EventHandler public void loginEvent(LoginEvent e) { - InitialHandler initialHandler = ((InitialHandler) e.getConnection()); - - String undashedUUID = initialHandler.getUniqueId().toString().replace("-", ""); - String extraData = "\00" + AddressUtil.sanitizeAddress(inetSocketAddress) + "\00" + undashedUUID; - - LoginResult result = initialHandler.getLoginProfile(); - if (result != null) { - Property[] properties = result.getProperties(); - if (properties.length > 0) { - extraData += "\00" + BungeeCord.getInstance().gson.toJson(properties); - } - } - - try { - field.set(initialHandler, extraData); - } catch (IllegalAccessException ex) { - BungeeCord.getInstance().getLogger().log(Level.SEVERE, ex.getMessage(), ex); - } + BungeeCore.get().getLogger().log(Level.INFO, e.getConnection().getSocketAddress() + " has logged in with user name " + e.getConnection().getName()); + getChannelWrapper((InitialHandler) e.getConnection()).setRemoteAddress(inetSocketAddress); } } diff --git a/src/de/steamwar/bungeecore/listeners/PluginMessage.java b/src/de/steamwar/bungeecore/listeners/PluginMessage.java index d032be72..b57b2372 100644 --- a/src/de/steamwar/bungeecore/listeners/PluginMessage.java +++ b/src/de/steamwar/bungeecore/listeners/PluginMessage.java @@ -28,24 +28,29 @@ import de.steamwar.messages.ChatSender; import de.steamwar.network.packets.NetworkPacket; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.Unpooled; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.event.PluginMessageEvent; +import net.md_5.bungee.connection.InitialHandler; import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.protocol.DefinedPacket; import java.net.InetSocketAddress; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.logging.Level; public class PluginMessage extends BasicListener { public static void send(ProxiedPlayer player, String legacyChannel, String channel, byte[] data) { // 1.12 format change - player.sendData(player.getPendingConnection().getVersion() > 340 ? channel : legacyChannel, data); + send(player, player.getPendingConnection().getVersion() > 340 ? channel : legacyChannel, data); + } + + public static void send(ProxiedPlayer player, String channel, byte[] data) { + if(((InitialHandler)player.getPendingConnection()).getRegisteredChannels().contains(channel)) + player.sendData(channel, data); } //TODO change to warning level @@ -55,6 +60,8 @@ public class PluginMessage extends BasicListener { private final Lunar lunar = new Lunar(); + private final Set knownBrands = new HashSet<>(); + private final Set knownChannels = new HashSet<>(); private final Map handlers = new HashMap<>(); public PluginMessage() { @@ -63,8 +70,31 @@ public class PluginMessage extends BasicListener { FabricModSender fabricModSender = new FabricModSender(); WorldDownloader wdl = new WorldDownloader(); - register("REGISTER", false, directional(PASS_THROUGH, this::clientRegistersChannel)); - register("minecraft:register", false, directional(PASS_THROUGH, this::clientRegistersChannel)); + knownBrands.add("vanilla"); + knownBrands.add("fabric"); + knownBrands.add("forge"); //Forge registers all channels the server registers + + knownChannels.add("fabric:container/open"); + knownChannels.add("fabric:registry/sync/direct"); + knownChannels.add("fabric-screen-handler-api-v1:open_screen"); + + knownChannels.add(FML.CHANNEL); + knownChannels.add("fml:loginwrapper"); + knownChannels.add("fml:handshake"); + knownChannels.add("fml:play"); + knownChannels.add("forge:tier_sorting"); + knownChannels.add("forge:split"); + knownChannels.add("forge:login"); + knownChannels.add("forge:handshake"); + + knownChannels.add("Replay|Restrict"); + knownChannels.add("replaymod:restrict"); + knownChannels.add("WDL|CONTROL"); + knownChannels.add("wdl:control"); + knownChannels.add("worldedit:cui"); + + register("REGISTER", false, directional(this::serverRegistersChannel, this::clientRegistersChannel)); + register("minecraft:register", false, directional(this::serverRegistersChannel, this::clientRegistersChannel)); register("BungeeCord", false, onlySWSource(PASS_THROUGH)); register("bungeecord:main", false, onlySWSource(PASS_THROUGH)); @@ -73,6 +103,7 @@ public class PluginMessage extends BasicListener { register("sw:script_syntax", false, directional(onlySWSource(PASS_THROUGH), UNKNOWN)); register("sw:bridge", false, directional(onlySWSource(async(event -> NetworkPacket.handle(new ServerMetaInfo(((Server) event.getSender()).getInfo()), event.getData()))), UNKNOWN)); + register("worldedit:cui", false, PASS_THROUGH); register("fabricmodsender:mods", true, directional(UNKNOWN, fabricModSender::handlePluginMessage)); register("WDL|REQUEST", false, DROP); @@ -83,7 +114,7 @@ public class PluginMessage extends BasicListener { register(ApolloManager.PLUGIN_MESSAGE_CHANNEL, true, async(lunar::handlePluginMessage)); register("LMC", true, directional(UNKNOWN, async(labyMod::handlePluginMessage))); register("labymod3:main", true, directional(UNKNOWN, async(labyMod::handlePluginMessage))); - register(FML.CHANNEL, true, directional(UNKNOWN, fml::handlePluginMessage)); + register(FML.CHANNEL, true, directional(UNKNOWN, async(fml::handlePluginMessage))); //litematica/malilib https://github.com/maruohon/litematica/issues/75 https://github.com/maruohon/malilib/blob/liteloader_1.12.2/src/main/java/malilib/network/message/ConfigLockPacketHandler.java#L65 } @@ -114,7 +145,7 @@ public class PluginMessage extends BasicListener { if(channel.equals(ApolloManager.PLUGIN_MESSAGE_CHANNEL)) lunar.sendRestrictions(player); - if(!handlers.containsKey(channel)) + if(!knownChannels.contains(channel)) //TODO change to warning level BungeeCore.get().getLogger().log(Level.INFO, () -> player.getName() + " registered unknown channel " + channel); } @@ -122,15 +153,22 @@ public class PluginMessage extends BasicListener { PASS_THROUGH.handle(event); } + private void serverRegistersChannel(PluginMessageEvent event) { + ProxiedPlayer player = (ProxiedPlayer)event.getReceiver(); + + List channels = new ArrayList<>(Arrays.asList(new String(event.getData()).split("\0"))); + channels.removeIf(channel -> channel.equals("sw:bridge")); + player.sendData((player).getPendingConnection().getVersion() > 340 ? "minecraft:register" : "REGISTER", String.join("\0", channels).getBytes()); + } + private void userBrand(PluginMessageEvent event) { ProxiedPlayer player = (ProxiedPlayer) event.getSender(); - String brand = new String(event.getData()); + ByteBuf buf = Unpooled.wrappedBuffer(event.getData()); + String brand = DefinedPacket.readString(buf); - if(brand.equals("vanilla")) { - // nothing to do - } else if(brand.startsWith("lunarclient:")) { + if(brand.startsWith("lunarclient:")) { lunar.sendRestrictions(player); - } else { + } else if(!knownBrands.contains(brand)) { //TODO change to warning level BungeeCore.get().getLogger().log(Level.INFO, () -> player.getName() + " joined with unknown brand " + brand); } diff --git a/src/de/steamwar/bungeecore/mods/FML.java b/src/de/steamwar/bungeecore/mods/FML.java index 9a5c8fd6..1bd78053 100644 --- a/src/de/steamwar/bungeecore/mods/FML.java +++ b/src/de/steamwar/bungeecore/mods/FML.java @@ -25,6 +25,7 @@ import de.steamwar.sql.Mod; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.connection.PendingConnection; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.event.PluginMessageEvent; import net.md_5.bungee.api.event.PostLoginEvent; @@ -38,6 +39,10 @@ import java.util.concurrent.TimeUnit; public class FML extends BasicListener { // https://wiki.vg/Minecraft_Forge_Handshake#FML_protocol_.281.7_-_1.12.29 + public static boolean isFML(PendingConnection connection, String type) { + return ((InitialHandler)connection).getExtraDataInHandshake().equals("\0" + type); + } + public static final String CHANNEL = "FML|HS"; private final byte[] helloPacket = new byte[]{ /* Packet type: ServerHello */ 0, @@ -58,9 +63,8 @@ public class FML extends BasicListener { } } - if(((InitialHandler)player.getPendingConnection()).getHandshake().getHost().endsWith("\0FML\0")) { + if(isFML(player.getPendingConnection(), "FML\0")) player.sendData(CHANNEL, helloPacket); - } } public void handlePluginMessage(PluginMessageEvent event) { diff --git a/src/de/steamwar/bungeecore/mods/FML2.java b/src/de/steamwar/bungeecore/mods/FML2.java index b6be9841..b52a7b3e 100644 --- a/src/de/steamwar/bungeecore/mods/FML2.java +++ b/src/de/steamwar/bungeecore/mods/FML2.java @@ -21,6 +21,7 @@ package de.steamwar.bungeecore.mods; import de.steamwar.bungeecore.BungeeCore; import de.steamwar.bungeecore.listeners.BasicListener; +import de.steamwar.bungeecore.listeners.IPSanitizer; import de.steamwar.sql.Mod; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; @@ -29,67 +30,91 @@ import net.md_5.bungee.api.connection.PendingConnection; import net.md_5.bungee.api.event.LoginEvent; import net.md_5.bungee.connection.InitialHandler; import net.md_5.bungee.event.EventHandler; -import net.md_5.bungee.netty.ChannelWrapper; import net.md_5.bungee.netty.HandlerBoss; import net.md_5.bungee.netty.PacketHandler; import net.md_5.bungee.protocol.DefinedPacket; import net.md_5.bungee.protocol.packet.LoginPayloadRequest; import net.md_5.bungee.protocol.packet.LoginPayloadResponse; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.logging.Level; public class FML2 extends BasicListener { - // https://wiki.vg/Minecraft_Forge_Handshake#FML2_protocol_.281.13_-_Current.29 + // FML2: https://wiki.vg/Minecraft_Forge_Handshake#FML2_protocol_.281.13_-_Current.29 + // FML3: https://github.com/adde0109/Ambassador/tree/non-api/src/main/java/org/adde0109/ambassador/forge - public static boolean isFML2(PendingConnection connection) { - return ((InitialHandler)connection).getHandshake().getHost().endsWith("\0FML2\0"); - } + // FORGE: https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/NetworkInitialization.java + // FORGE: https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/ForgePacketHandler.java + // FORGE: https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/packets/ModVersions.java - private final Field initialHandlerCh; + private final byte[] fml2ModListPacket; + private final byte[] fml3ModListPacket; + private final byte[] forgeModListPacket; public FML2() { - try { - initialHandlerCh = InitialHandler.class.getDeclaredField("ch"); - } catch (NoSuchFieldException e) { - throw new SecurityException("Could not initialize Reflection", e); - } - initialHandlerCh.setAccessible(true); - } + fml2ModListPacket = generateModListPacket(false); + fml3ModListPacket = generateModListPacket(true); - //TODO current identifier is \0FORGE and fmlNetworkVersion 0 ? - //TODO links for current implementation (if current checker not working) - //https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/ServerStatusPing.java - //https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/NetworkContext.java#L26 - //https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/tasks/ForgeNetworkConfigurationHandler.java#L20 - //https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/NetworkRegistry.java#L177 + ByteBuf packet = Unpooled.buffer(); + packet.writeByte(1); // Mod list packet + DefinedPacket.writeVarInt(0, packet); // Mod amount + + ByteBuf wrapper = Unpooled.buffer(); + wrapper.writeByte(0); // Login wrapper packet + DefinedPacket.writeString("forge:handshake", wrapper); + DefinedPacket.writeVarInt(packet.readableBytes(), wrapper); + wrapper.writeBytes(packet); + + forgeModListPacket = new byte[wrapper.readableBytes()]; + wrapper.readBytes(forgeModListPacket); + } @EventHandler public void onLogin(LoginEvent event) { PendingConnection connection = event.getConnection(); - if(!isFML2(connection)) + boolean fml2 = FML.isFML(connection, "FML2\0"); + boolean fml3 = FML.isFML(connection, "FML3\0"); + boolean forge = FML.isFML(connection, "FORGE"); + if(!fml2 && !fml3 && !forge) return; - try { - ((ChannelWrapper) initialHandlerCh.get(connection)).getHandle().pipeline().get(HandlerBoss.class).setHandler(new FML2LoginHandler(event)); - } catch (IllegalAccessException e) { - BungeeCore.get().getLogger().log(Level.SEVERE, "Could not get Channel", e); - return; - } + IPSanitizer.getChannelWrapper((InitialHandler) connection).getHandle().pipeline().get(HandlerBoss.class).setHandler(new FML2LoginHandler(event)); event.registerIntent(BungeeCore.get()); - connection.unsafe().sendPacket(new LoginPayloadRequest(1, "fml:loginwrapper", new byte[] { - /* fml:handshake */ 13,102,109,108,58,104,97,110,100,115,104,97,107,101, - /* Packet length */ 4, - /* Type mod list */ 1, - /* Mod count */ 0, - /* Channel count */ 0, - /* Registry count */ 0 - })); + if(forge) + connection.unsafe().sendPacket(new LoginPayloadRequest(1, "forge:login", forgeModListPacket)); + else + connection.unsafe().sendPacket(new LoginPayloadRequest(1, "fml:loginwrapper", fml3 ? fml3ModListPacket : fml2ModListPacket)); + } + + private byte[] generateModListPacket(boolean fml3) { + ByteBuf packet = Unpooled.buffer(); + packet.writeByte(1); // Mod list packet + DefinedPacket.writeVarInt(0, packet); // Mod amount + + if(fml3) { + DefinedPacket.writeVarInt(1, packet); // Channel amount + DefinedPacket.writeString("forge:tier_sorting", packet); + DefinedPacket.writeString("1.0", packet); + } else { + DefinedPacket.writeVarInt(0, packet); // Channel amount + } + + DefinedPacket.writeVarInt(0, packet); // Registries amount + if(fml3) + DefinedPacket.writeVarInt(0, packet); // DataPacks amount + + ByteBuf wrapper = Unpooled.buffer(); + DefinedPacket.writeString("fml:handshake", wrapper); + DefinedPacket.writeVarInt(packet.readableBytes(), wrapper); + wrapper.writeBytes(packet); + + byte[] data = new byte[wrapper.readableBytes()]; + wrapper.readBytes(data); + return data; } private static class FML2LoginHandler extends PacketHandler { @@ -101,40 +126,51 @@ public class FML2 extends BasicListener { @Override public String toString() { - return "SteamWar FML2 Handler"; + return "SteamWar Forge Handler"; } @Override public void handle(LoginPayloadResponse response) { + boolean forge = FML.isFML(event.getConnection(), "FORGE"); byte[] data = response.getData(); if(data == null) { - abort(response, "Not FML2 client"); + abort(response, "Not FML2/3 client"); return; } ByteBuf buf = Unpooled.wrappedBuffer(data); - if(!DefinedPacket.readString(buf).equals("fml:handshake")) { - abort(response, "Not FML2 handshake response"); + if(forge && buf.readByte() != 0) { + abort(response, "Not FORGE login wrapper"); return; } - int packetLength = DefinedPacket.readVarInt(buf); - if(packetLength != buf.readableBytes()) { - abort(response, "FML2 packet size mismatch"); + if(!DefinedPacket.readString(buf).equals(forge ? "forge:handshake" : "fml:handshake")) { + abort(response, "Not FML2/3/FORGE handshake response"); return; } - if(DefinedPacket.readVarInt(buf) != /* Mod List Reply */ 2) { - abort(response, "FML2 no mod list reply"); + if(DefinedPacket.readVarInt(buf) != buf.readableBytes()) { + abort(response, "FML2/3/FORGE packet size mismatch"); + return; + } + + if(DefinedPacket.readVarInt(buf) != (forge ? /* Mod Versions */ 1 : /* Mod List Reply */ 2)) { + abort(response, "Not FML2/3/FORGE mod list reply"); return; } List mods = new ArrayList<>(); int modCount = DefinedPacket.readVarInt(buf); - for(int i = 0; i < modCount; i++) + for(int i = 0; i < modCount; i++) { mods.add(Mod.getOrCreate(DefinedPacket.readString(buf), Mod.Platform.FORGE)); + if(forge) { + DefinedPacket.readString(buf); // Human readable name + DefinedPacket.readString(buf); // Version + } + } + if(!ModUtils.handleMods(event.getConnection().getUniqueId(), Locale.getDefault(), event::setReason, mods)) event.setCancelled(true); diff --git a/src/de/steamwar/bungeecore/mods/Hostname.java b/src/de/steamwar/bungeecore/mods/Hostname.java new file mode 100644 index 00000000..a9728dc9 --- /dev/null +++ b/src/de/steamwar/bungeecore/mods/Hostname.java @@ -0,0 +1,58 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2024 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.mods; + +import de.steamwar.bungeecore.BungeeCore; +import de.steamwar.bungeecore.listeners.BasicListener; +import net.md_5.bungee.api.event.PlayerHandshakeEvent; +import net.md_5.bungee.connection.InitialHandler; +import net.md_5.bungee.event.EventHandler; + +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; + +public class Hostname extends BasicListener { + + private final Set knownHostnames = new HashSet<>(); + private final Set knownExtraData = new HashSet<>(); + + public Hostname() { + knownHostnames.add("steamwar.de"); + knownHostnames.add("78.31.71.136"); + + knownExtraData.add(""); + knownExtraData.add("\0FML\0"); + knownExtraData.add("\0FML2\0"); + knownExtraData.add("\0FML3\0"); + knownExtraData.add("\0FORGE"); + } + + @EventHandler + public void onHandshake(PlayerHandshakeEvent event) { + String extraDataInHandshake = ((InitialHandler) event.getConnection()).getExtraDataInHandshake(); + if (!knownHostnames.contains(event.getHandshake().getHost().toLowerCase())) { + BungeeCore.get().getLogger().log(Level.WARNING, () -> event.getConnection().getSocketAddress() + " connected with unknown hostname " + event.getHandshake() + " " + extraDataInHandshake); + } else if (!knownExtraData.contains(extraDataInHandshake)) { + BungeeCore.get().getLogger().log(Level.WARNING, () -> event.getConnection().getSocketAddress() + " connected with unknown extra data " + event.getHandshake() + " " + extraDataInHandshake); + + } + } +} diff --git a/src/de/steamwar/bungeecore/mods/ReplayMod.java b/src/de/steamwar/bungeecore/mods/ReplayMod.java index d3c813ab..2130ebc0 100644 --- a/src/de/steamwar/bungeecore/mods/ReplayMod.java +++ b/src/de/steamwar/bungeecore/mods/ReplayMod.java @@ -20,9 +20,13 @@ package de.steamwar.bungeecore.mods; import de.steamwar.bungeecore.Bauserver; +import de.steamwar.bungeecore.Builderserver; +import de.steamwar.bungeecore.BungeeCore; import de.steamwar.bungeecore.Subserver; import de.steamwar.bungeecore.listeners.BasicListener; import de.steamwar.bungeecore.listeners.PluginMessage; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.event.ServerSwitchEvent; import net.md_5.bungee.event.EventHandler; @@ -34,38 +38,36 @@ import java.util.Arrays; public class ReplayMod extends BasicListener { // https://gist.github.com/Johni0702/2547c463e51f65f312cb // https://github.com/ReplayMod/replay-restrictions/blob/master/bungeecord/src/main/java/de/johni0702/replay/restrictions/BungeeCordPlugin.java + // https://github.com/ReplayMod/ReplayMod/blob/stable/src/main/java/com/replaymod/core/utils/Restrictions.java private final byte[] restrict; - private final byte[] unlock; public ReplayMod() { - restrict = generatePacket(true); - unlock = generatePacket(false); - } - - @EventHandler - public void onPlayerJoin(ServerSwitchEvent event) { - ProxiedPlayer player = event.getPlayer(); - Subserver server = Subserver.getSubserver(player.getServer().getInfo()); - - PluginMessage.send( - player, "Replay|Restrict", "replaymod:restrict", - (server instanceof Bauserver && ((Bauserver) server).getOwner().equals(player.getUniqueId())) ? unlock : restrict - ); - } - - private byte[] generatePacket(boolean restrict) { ByteArrayOutputStream stream = new ByteArrayOutputStream(); try { for(String restriction : Arrays.asList("no_xray", "no_noclip", "only_first_person", "only_recording_player")) { byte[] bytes = restriction.getBytes(); stream.write(bytes.length); stream.write(bytes); - stream.write(restrict ? 1 : 0); + stream.write(1); // restrict } } catch (IOException e) { throw new SecurityException(e); } - return stream.toByteArray(); + restrict = stream.toByteArray(); + } + + @EventHandler + public void onPlayerJoin(ServerSwitchEvent event) { + ProxiedPlayer player = event.getPlayer(); + ServerInfo server = player.getServer().getInfo(); + if(ProxyServer.getInstance().getServerInfo(BungeeCore.LOBBY_SERVER) == server) + return; + + Subserver subserver = Subserver.getSubserver(server); + if(subserver instanceof Builderserver || (subserver instanceof Bauserver && ((Bauserver) subserver).getOwner().equals(player.getUniqueId()))) + return; + + PluginMessage.send(player, "Replay|Restrict", "replaymod:restrict", restrict); } } diff --git a/src/de/steamwar/bungeecore/mods/ServerListPing.java b/src/de/steamwar/bungeecore/mods/ServerListPing.java index ae12cfff..e774794c 100644 --- a/src/de/steamwar/bungeecore/mods/ServerListPing.java +++ b/src/de/steamwar/bungeecore/mods/ServerListPing.java @@ -21,31 +21,17 @@ package de.steamwar.bungeecore.mods; import com.google.gson.*; import de.steamwar.bungeecore.listeners.BasicListener; -import lombok.AllArgsConstructor; import net.md_5.bungee.BungeeCord; import net.md_5.bungee.api.ServerPing; -import net.md_5.bungee.api.connection.PendingConnection; -import net.md_5.bungee.api.event.ProxyPingEvent; -import net.md_5.bungee.event.EventHandler; -import net.md_5.bungee.event.EventPriority; -import net.md_5.bungee.protocol.ProtocolConstants; import java.lang.reflect.Field; import java.lang.reflect.Type; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; public class ServerListPing extends BasicListener implements JsonSerializer, JsonDeserializer { // https://github.com/Aizistral-Studios/No-Chat-Reports/discussions/206 // https://github.com/Aizistral-Studios/No-Chat-Reports/wiki/How-to-Get-Safe-Server-Status - // https://wiki.vg/Minecraft_Forge_Handshake#Changes_to_Server_List_Ping_2 private final Gson gson; - private final Map versionMap = new HashMap<>(); - private final FML2Channel[] fml2Channels = new FML2Channel[]{new FML2Channel("minecraft:register"), new FML2Channel("minecraft:unregister"), new FML2Channel("fml:handshake")}; - - private final Map connections = new ConcurrentHashMap<>(); public ServerListPing() { BungeeCord bungeeCord = BungeeCord.getInstance(); @@ -55,25 +41,11 @@ public class ServerListPing extends BasicListener implements JsonSerializer !connection.isConnected()); // Prevent long term leaks - } - @Override public JsonElement serialize(ServerPing ping, Type type, JsonSerializationContext context) { JsonElement element = gson.toJsonTree(ping, type); @@ -81,14 +53,6 @@ public class ServerListPing extends BasicListener implements JsonSerializer