diff --git a/core/src/main/java/org/geysermc/geyser/network/GeyserBedrockPeer.java b/core/src/main/java/org/geysermc/geyser/network/GeyserBedrockPeer.java new file mode 100644 index 000000000..2138d683c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/network/GeyserBedrockPeer.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.network; + +import io.netty.channel.Channel; +import org.cloudburstmc.protocol.bedrock.BedrockPeer; +import org.cloudburstmc.protocol.bedrock.BedrockSessionFactory; + +import java.net.SocketAddress; + +public class GeyserBedrockPeer extends BedrockPeer { + private SocketAddress proxiedAddress; + + public GeyserBedrockPeer(Channel channel, BedrockSessionFactory sessionFactory) { + super(channel, sessionFactory); + } + + public SocketAddress getRealAddress() { + SocketAddress proxied = this.proxiedAddress; + return proxied == null ? this.getSocketAddress() : proxied; + } + + public void setProxiedAddress(SocketAddress proxiedAddress) { + this.proxiedAddress = proxiedAddress; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java b/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java index d659f3d37..be4b9d3b3 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java +++ b/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java @@ -25,8 +25,10 @@ package org.geysermc.geyser.network; +import io.netty.channel.Channel; import io.netty.channel.DefaultEventLoopGroup; import io.netty.util.concurrent.DefaultThreadFactory; +import org.cloudburstmc.protocol.bedrock.BedrockPeer; import org.cloudburstmc.protocol.bedrock.BedrockServerSession; import org.cloudburstmc.protocol.bedrock.netty.initializer.BedrockServerInitializer; import org.geysermc.geyser.GeyserImpl; @@ -55,6 +57,11 @@ public class GeyserServerInitializer extends BedrockServerInitializer { } } + @Override + protected BedrockPeer createPeer(Channel channel) { + return new GeyserBedrockPeer(channel, this::createSession); + } + /* @Override public void onUnhandledDatagram(@Nonnull ChannelHandlerContext ctx, @Nonnull DatagramPacket packet) { diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java index 1d8605504..83be9ea6e 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserServer.java @@ -27,7 +27,10 @@ package org.geysermc.geyser.network.netty; import com.github.steveice10.packetlib.helper.TransportHelper; import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.EventLoopGroup; import io.netty.channel.epoll.Epoll; import io.netty.channel.epoll.EpollDatagramChannel; @@ -38,21 +41,30 @@ import io.netty.channel.kqueue.KQueueEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.DatagramChannel; import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.handler.codec.haproxy.HAProxyCommand; +import io.netty.handler.codec.haproxy.HAProxyMessage; +import io.netty.handler.codec.haproxy.HAProxyMessageDecoder; import org.cloudburstmc.netty.channel.raknet.RakChannelFactory; import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerOfflineHandler; +import org.cloudburstmc.protocol.bedrock.BedrockPeer; import org.cloudburstmc.protocol.bedrock.BedrockPong; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.network.CIDRMatcher; import org.geysermc.geyser.network.GameProtocol; +import org.geysermc.geyser.network.GeyserBedrockPeer; import org.geysermc.geyser.network.GeyserServerInitializer; +import org.geysermc.geyser.network.netty.handler.RakConnectionRequestHandler; +import org.geysermc.geyser.network.netty.handler.RakPingHandler; import org.geysermc.geyser.ping.GeyserPingInfo; import org.geysermc.geyser.ping.IGeyserPingPassthrough; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.jetbrains.annotations.NotNull; import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -96,10 +108,37 @@ public final class GeyserServer { future.complete(null); }); + Channel channel = this.future.channel(); + // Add our ping handler - this.future.channel().pipeline() + channel.pipeline() .addFirst(RakConnectionRequestHandler.NAME, new RakConnectionRequestHandler(this)) .addAfter(RakServerOfflineHandler.NAME, RakPingHandler.NAME, new RakPingHandler(this)); + + if (this.geyser.getConfig().getBedrock().isEnableProxyProtocol()) { + channel.pipeline().addFirst("proxy-protocol-decoder", new HAProxyMessageDecoder()); + channel.pipeline().addAfter("proxy-protocol-decoder", "proxy-protocol-packet-handler", new ChannelInboundHandlerAdapter() { + + @Override + public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) throws Exception { + if (!(msg instanceof HAProxyMessage message)) { + super.channelRead(ctx, msg); + return; + } + + if (message.command() == HAProxyCommand.PROXY) { + String address = message.sourceAddress(); + int port = message.sourcePort(); + + SocketAddress realAddress = new InetSocketAddress(address, port); + + GeyserBedrockPeer peer = (GeyserBedrockPeer) channel.pipeline().get(BedrockPeer.NAME); + peer.setProxiedAddress(realAddress); + } + } + }); + } + return future; } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/RakConnectionRequestHandler.java b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakConnectionRequestHandler.java similarity index 97% rename from core/src/main/java/org/geysermc/geyser/network/netty/RakConnectionRequestHandler.java rename to core/src/main/java/org/geysermc/geyser/network/netty/handler/RakConnectionRequestHandler.java index 2aa3cd6b9..8c0412240 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/RakConnectionRequestHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakConnectionRequestHandler.java @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.network.netty; +package org.geysermc.geyser.network.netty.handler; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; @@ -34,6 +34,7 @@ import io.netty.channel.socket.DatagramPacket; import lombok.RequiredArgsConstructor; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; +import org.geysermc.geyser.network.netty.GeyserServer; import java.net.InetSocketAddress; diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/RakPingHandler.java b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakPingHandler.java similarity index 92% rename from core/src/main/java/org/geysermc/geyser/network/netty/RakPingHandler.java rename to core/src/main/java/org/geysermc/geyser/network/netty/handler/RakPingHandler.java index 98d9c3e3c..e63bf9dd2 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/RakPingHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/handler/RakPingHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.network.netty; +package org.geysermc.geyser.network.netty.handler; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; @@ -32,6 +32,7 @@ import lombok.RequiredArgsConstructor; import org.cloudburstmc.netty.channel.raknet.RakPing; import org.cloudburstmc.netty.channel.raknet.RakPong; import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption; +import org.geysermc.geyser.network.netty.GeyserServer; @ChannelHandler.Sharable @RequiredArgsConstructor diff --git a/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java b/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java index b6d2124c1..ef462a3e3 100644 --- a/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java @@ -32,9 +32,9 @@ import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.protocol.bedrock.BedrockServerSession; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodecHelper; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; +import org.geysermc.geyser.network.GeyserBedrockPeer; import java.net.InetSocketAddress; -import java.net.SocketAddress; import java.util.ArrayDeque; import java.util.Queue; @@ -86,7 +86,7 @@ public class UpstreamSession { public InetSocketAddress getAddress() { // Will always be an InetSocketAddress. See ProxyChannel#remoteAddress - return (InetSocketAddress) session.getSocketAddress(); + return (InetSocketAddress) ((GeyserBedrockPeer) session.getPeer()).getRealAddress(); } /**