diff --git a/src/main/java/net/minestom/server/extras/bungee/BungeeCordProxy.java b/src/main/java/net/minestom/server/extras/bungee/BungeeCordProxy.java new file mode 100644 index 000000000..9886e1f75 --- /dev/null +++ b/src/main/java/net/minestom/server/extras/bungee/BungeeCordProxy.java @@ -0,0 +1,27 @@ +package net.minestom.server.extras.bungee; + +/** + * BungeeCord forwarding support. This does not count as a security feature and you will still be required to manage your firewall. + *

+ * Please consider using {@link net.minestom.server.extras.velocity.VelocityProxy} instead. + */ +public final class BungeeCordProxy { + + private static boolean enabled; + + /** + * Enables bungee IP forwarding. + */ + public static void enable() { + BungeeCordProxy.enabled = true; + } + + /** + * Gets if bungee IP forwarding is enabled. + * + * @return true if forwarding is enabled + */ + public static boolean isEnabled() { + return enabled; + } +} diff --git a/src/main/java/net/minestom/server/network/PacketProcessor.java b/src/main/java/net/minestom/server/network/PacketProcessor.java index df8d60e9b..77d4d6556 100644 --- a/src/main/java/net/minestom/server/network/PacketProcessor.java +++ b/src/main/java/net/minestom/server/network/PacketProcessor.java @@ -14,13 +14,19 @@ import net.minestom.server.network.packet.client.handshake.HandshakePacket; import net.minestom.server.network.player.NettyPlayerConnection; import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.utils.binary.BinaryReader; +import net.minestom.server.utils.binary.Readable; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public final class PacketProcessor { + private final static Logger LOGGER = LoggerFactory.getLogger(PacketProcessor.class); + private final Map connectionPlayerConnectionMap = new ConcurrentHashMap<>(); // Protocols state @@ -34,7 +40,7 @@ public final class PacketProcessor { this.playPacketsHandler = new ClientPlayPacketsHandler(); } - public void process(ChannelHandlerContext channel, InboundPacket packet) { + public void process(@NotNull ChannelHandlerContext channel, @NotNull InboundPacket packet) { // Create the netty player connection object if not existing PlayerConnection playerConnection = connectionPlayerConnectionMap.computeIfAbsent( channel, c -> new NettyPlayerConnection((SocketChannel) channel.channel()) @@ -51,7 +57,7 @@ public final class PacketProcessor { // Should be handshake packet if (packet.packetId == 0) { HandshakePacket handshakePacket = new HandshakePacket(); - handshakePacket.read(binaryReader); + safeRead(playerConnection, handshakePacket, binaryReader); handshakePacket.process(playerConnection); } return; @@ -61,17 +67,17 @@ public final class PacketProcessor { case PLAY: final Player player = playerConnection.getPlayer(); ClientPlayPacket playPacket = (ClientPlayPacket) playPacketsHandler.getPacketInstance(packet.packetId); - playPacket.read(binaryReader); + safeRead(playerConnection, playPacket, binaryReader); player.addPacketToQueue(playPacket); break; case LOGIN: final ClientPreplayPacket loginPacket = (ClientPreplayPacket) loginPacketsHandler.getPacketInstance(packet.packetId); - loginPacket.read(binaryReader); + safeRead(playerConnection, loginPacket, binaryReader); loginPacket.process(playerConnection); break; case STATUS: final ClientPreplayPacket statusPacket = (ClientPreplayPacket) statusPacketsHandler.getPacketInstance(packet.packetId); - statusPacket.read(binaryReader); + safeRead(playerConnection, statusPacket, binaryReader); statusPacket.process(playerConnection); break; } @@ -91,4 +97,14 @@ public final class PacketProcessor { public void removePlayerConnection(ChannelHandlerContext channel) { connectionPlayerConnectionMap.remove(channel); } + + private void safeRead(@NotNull PlayerConnection connection, @NotNull Readable readable, @NotNull BinaryReader reader) { + try { + readable.read(reader); + } catch (Exception e) { + final Player player = connection.getPlayer(); + final String username = player != null ? player.getUsername() : "null"; + LOGGER.warn("Connection " + connection.getRemoteAddress() + " (" + username + ") sent an unexpected packet."); + } + } } diff --git a/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java b/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java index 9658a9af1..8ccff15cd 100644 --- a/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java +++ b/src/main/java/net/minestom/server/network/packet/client/handshake/HandshakePacket.java @@ -3,6 +3,7 @@ package net.minestom.server.network.packet.client.handshake; import net.minestom.server.MinecraftServer; import net.minestom.server.chat.ChatColor; import net.minestom.server.chat.ColoredText; +import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.network.ConnectionState; import net.minestom.server.network.packet.client.ClientPreplayPacket; import net.minestom.server.network.packet.server.login.LoginDisconnectPacket; @@ -11,6 +12,8 @@ import net.minestom.server.network.player.PlayerConnection; import net.minestom.server.utils.binary.BinaryReader; import org.jetbrains.annotations.NotNull; +import java.net.SocketAddress; + public class HandshakePacket implements ClientPreplayPacket { /** @@ -18,6 +21,8 @@ public class HandshakePacket implements ClientPreplayPacket { */ private static final ColoredText INVALID_VERSION_TEXT = ColoredText.of(ChatColor.RED, "Invalid Version, please use " + MinecraftServer.VERSION_NAME); + private static final ColoredText INVALID_BUNGEE_FORWARDING = ColoredText.of(ChatColor.RED, "If you wish to use IP forwarding, please enable it in your BungeeCord config as well!"); + private int protocolVersion; private String serverAddress; private int serverPort; @@ -33,6 +38,29 @@ public class HandshakePacket implements ClientPreplayPacket { @Override public void process(@NotNull PlayerConnection connection) { + + if (BungeeCordProxy.isEnabled() && connection instanceof NettyPlayerConnection) { + NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) connection; + + if (serverAddress != null) { + final String[] split = serverAddress.split("\00"); + + if (split.length == 3 || split.length == 4) { + this.serverAddress = split[0]; + + final SocketAddress socketAddress = new java.net.InetSocketAddress(split[1], ((java.net.InetSocketAddress) connection.getRemoteAddress()).getPort()); + nettyPlayerConnection.setRemoteAddress(socketAddress); + } else { + nettyPlayerConnection.sendPacket(new LoginDisconnectPacket(INVALID_BUNGEE_FORWARDING)); + nettyPlayerConnection.disconnect(); + return; + } + } else { + // Happen when a client ping the server, ignore + return; + } + } + switch (nextState) { case 1: connection.setConnectionState(ConnectionState.STATUS); diff --git a/src/test/java/demo/Main.java b/src/test/java/demo/Main.java index 9b106397a..1891e5b6e 100644 --- a/src/test/java/demo/Main.java +++ b/src/test/java/demo/Main.java @@ -7,6 +7,7 @@ import demo.commands.GamemodeCommand; import demo.commands.TestCommand; import net.minestom.server.MinecraftServer; import net.minestom.server.command.CommandManager; +import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.instance.block.BlockManager; import net.minestom.server.instance.block.rule.vanilla.RedstonePlacementRule; import net.minestom.server.storage.StorageManager; @@ -51,8 +52,9 @@ public class Main { PlayerInit.init(); //VelocityProxy.enable("rBeJJ79W4MVU"); + BungeeCordProxy.enable(); - //MojangAuth.init(); + // MojangAuth.init(); minecraftServer.start("0.0.0.0", 25565, PlayerInit.getResponseDataConsumer()); } diff --git a/src/test/java/demo/PlayerInit.java b/src/test/java/demo/PlayerInit.java index 2dfa2c6e7..4705aecbd 100644 --- a/src/test/java/demo/PlayerInit.java +++ b/src/test/java/demo/PlayerInit.java @@ -5,8 +5,6 @@ import demo.generator.NoiseTestGenerator; import net.minestom.server.MinecraftServer; import net.minestom.server.benchmark.BenchmarkManager; import net.minestom.server.chat.ColoredText; -import net.minestom.server.data.Data; -import net.minestom.server.data.NbtDataImpl; import net.minestom.server.entity.*; import net.minestom.server.entity.damage.DamageType; import net.minestom.server.entity.type.monster.EntityZombie; @@ -174,11 +172,7 @@ public class PlayerInit { } ItemStack itemStack = new ItemStack(Material.DIAMOND_PICKAXE, (byte) 64); - Data data = new NbtDataImpl(); - data.set("test", 51); - itemStack.setData(data); player.getInventory().addItemStack(itemStack); - System.out.println("test " + data.get("test")); //player.getInventory().addItemStack(new ItemStack(Material.STONE, (byte)64)); }); diff --git a/src/test/java/demo/commands/TestCommand.java b/src/test/java/demo/commands/TestCommand.java index 456458317..83a5abd57 100644 --- a/src/test/java/demo/commands/TestCommand.java +++ b/src/test/java/demo/commands/TestCommand.java @@ -5,6 +5,7 @@ import net.minestom.server.command.builder.Arguments; import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.arguments.Argument; import net.minestom.server.command.builder.arguments.ArgumentType; +import net.minestom.server.item.ItemStack; public class TestCommand extends Command { @@ -17,7 +18,7 @@ public class TestCommand extends Command { //addSyntax(this::execute, dynamicWord); } - Argument test = ArgumentType.DynamicWord("testArg").fromRestrictions(value -> value.contains("a")); + Argument test = ArgumentType.ItemStack("item"); test.setCallback((source, value, error) -> { System.out.println("ERROR " + error); @@ -29,7 +30,8 @@ public class TestCommand extends Command { }); addSyntax((source, args) -> { - System.out.println("HEY IT WORKS"); + ItemStack itemStack = args.getItemStack("item"); + System.out.println("HEY IT WORKS "+itemStack.getMaterial()); }, test); }