From be48b83c2816823b6ad4d7a0d59c26c026176b4b Mon Sep 17 00:00:00 2001 From: RednedEpic Date: Sat, 8 Apr 2023 19:01:42 -0500 Subject: [PATCH] Fix connection request handler --- .../network/GeyserServerInitializer.java | 26 ----- .../geyser/network/netty/GeyserServer.java | 27 ++++- .../netty/RakConnectionRequestHandler.java | 100 ++++++++++++++++++ 3 files changed, 126 insertions(+), 27 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/network/netty/RakConnectionRequestHandler.java 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 126847cd5..d659f3d37 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java +++ b/core/src/main/java/org/geysermc/geyser/network/GeyserServerInitializer.java @@ -43,32 +43,6 @@ public class GeyserServerInitializer extends BedrockServerInitializer { this.geyser = geyser; } - //TODO - /* - @Override - public boolean onConnectionRequest(InetSocketAddress inetSocketAddress) { - List allowedProxyIPs = geyser.getConfig().getBedrock().getProxyProtocolWhitelistedIPs(); - if (geyser.getConfig().getBedrock().isEnableProxyProtocol() && !allowedProxyIPs.isEmpty()) { - boolean isWhitelistedIP = false; - for (CIDRMatcher matcher : geyser.getConfig().getBedrock().getWhitelistedIPsMatchers()) { - if (matcher.matches(inetSocketAddress.getAddress())) { - isWhitelistedIP = true; - break; - } - } - - if (!isWhitelistedIP) { - return false; - } - } - - String ip = geyser.getConfig().isLogPlayerIpAddresses() ? inetSocketAddress.toString() : ""; - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.attempt_connect", ip)); - return true; - } - - */ - @Override public void initSession(@Nonnull BedrockServerSession bedrockServerSession) { try { 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 5e1c1331f..1d8605504 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 @@ -44,6 +44,7 @@ import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerOfflineHandle 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.GeyserServerInitializer; import org.geysermc.geyser.ping.GeyserPingInfo; @@ -53,6 +54,7 @@ import org.geysermc.geyser.translator.text.MessageTranslator; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.IntFunction; @@ -95,7 +97,9 @@ public final class GeyserServer { }); // Add our ping handler - this.future.channel().pipeline().addAfter(RakServerOfflineHandler.NAME, RakPingHandler.NAME, new RakPingHandler(this)); + this.future.channel().pipeline() + .addFirst(RakConnectionRequestHandler.NAME, new RakConnectionRequestHandler(this)) + .addAfter(RakServerOfflineHandler.NAME, RakPingHandler.NAME, new RakPingHandler(this)); return future; } @@ -126,6 +130,27 @@ public final class GeyserServer { .childHandler(new GeyserServerInitializer(this.geyser)); } + public boolean onConnectionRequest(InetSocketAddress inetSocketAddress) { + List allowedProxyIPs = geyser.getConfig().getBedrock().getProxyProtocolWhitelistedIPs(); + if (geyser.getConfig().getBedrock().isEnableProxyProtocol() && !allowedProxyIPs.isEmpty()) { + boolean isWhitelistedIP = false; + for (CIDRMatcher matcher : geyser.getConfig().getBedrock().getWhitelistedIPsMatchers()) { + if (matcher.matches(inetSocketAddress.getAddress())) { + isWhitelistedIP = true; + break; + } + } + + if (!isWhitelistedIP) { + return false; + } + } + + String ip = geyser.getConfig().isLogPlayerIpAddresses() ? inetSocketAddress.toString() : ""; + geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.attempt_connect", ip)); + return true; + } + public BedrockPong onQuery(InetSocketAddress inetSocketAddress) { if (geyser.getConfig().isDebugMode() && PRINT_DEBUG_PINGS) { String ip = geyser.getConfig().isLogPlayerIpAddresses() ? inetSocketAddress.toString() : ""; diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/RakConnectionRequestHandler.java b/core/src/main/java/org/geysermc/geyser/network/netty/RakConnectionRequestHandler.java new file mode 100644 index 000000000..2aa3cd6b9 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/network/netty/RakConnectionRequestHandler.java @@ -0,0 +1,100 @@ +/* + * 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.netty; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +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 java.net.InetSocketAddress; + +import static org.cloudburstmc.netty.channel.raknet.RakConstants.ID_CONNECTION_BANNED; +import static org.cloudburstmc.netty.channel.raknet.RakConstants.ID_OPEN_CONNECTION_REQUEST_1; + +@ChannelHandler.Sharable +@RequiredArgsConstructor +public class RakConnectionRequestHandler extends ChannelInboundHandlerAdapter { + public static final String NAME = "rak-connection-request-handler"; + + private final GeyserServer server; + + @Override + public void channelRead(@NonNull ChannelHandlerContext ctx, @NonNull Object msg) throws Exception { + if (!(msg instanceof DatagramPacket packet)) { + ctx.fireChannelRead(msg); + return; + } + + ByteBuf buf = packet.content(); + if (!buf.isReadable()) { + return; // No packet ID + } + + boolean readableMagic = true; + int startIndex = buf.readerIndex(); + try { + int packetId = buf.readUnsignedByte(); + if (packetId == ID_OPEN_CONNECTION_REQUEST_1) { + ByteBuf magicBuf = ctx.channel().config().getOption(RakChannelOption.RAK_UNCONNECTED_MAGIC); + if (!buf.isReadable(magicBuf.readableBytes()) || !ByteBufUtil.equals(buf.readSlice(magicBuf.readableBytes()), magicBuf)) { + readableMagic = false; + } + } else { + readableMagic = false; + } + } finally { + buf.readerIndex(startIndex); + } + + if (!readableMagic) { + ctx.fireChannelRead(msg); + return; + } + + ByteBuf magicBuf = ctx.channel().config().getOption(RakChannelOption.RAK_UNCONNECTED_MAGIC); + long guid = ctx.channel().config().getOption(RakChannelOption.RAK_GUID); + + if (!this.server.onConnectionRequest(packet.sender())) { + this.sendConnectionBanned(ctx, packet.sender(), magicBuf, guid); + } else { + ctx.fireChannelRead(msg); + } + } + + private void sendConnectionBanned(ChannelHandlerContext ctx, InetSocketAddress recipient, ByteBuf magicBuf, long guid) { + ByteBuf buffer = ctx.alloc().ioBuffer(25, 25); + buffer.writeByte(ID_CONNECTION_BANNED); + buffer.writeBytes(magicBuf, magicBuf.readerIndex(), magicBuf.readableBytes()); + buffer.writeLong(guid); + ctx.writeAndFlush(new DatagramPacket(buffer, recipient)); + } +}