Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.Future;
import lombok.Getter;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.netty.channel.raknet.RakChannelFactory;
import org.cloudburstmc.netty.channel.raknet.config.DefaultRakServerThrottle;
import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption;
Expand Down Expand Up @@ -234,9 +235,24 @@ private ServerBootstrap createBootstrap() {
.childHandler(serverInitializer);
}

public boolean onConnectionRequest(InetSocketAddress inetSocketAddress, InetSocketAddress clientAddress) {
public boolean onConnectionRequest(InetSocketAddress inetSocketAddress, @Nullable InetSocketAddress clientAddress) {
boolean haproxyEnabled = geyser.config().advanced().bedrock().useHaproxyProtocol();

if (clientAddress == null) {
// getClientAddress returns null when no PROXY header has been cached for this sender:
// upstream not emitting a header per UDP datagram, a PROXY v2 LOCAL frame the upstream
// library mishandles, or the cached entry expired.
if (haproxyEnabled) {
geyser.getLogger().warning(
"Rejecting Bedrock connection from " + inetSocketAddress + ": use-haproxy-protocol is enabled but no PROXY header was received. Verify your reverse proxy sends a PROXY v2 header on every UDP datagram."
);
}
connectionAttempts++;
return false;
}

List<String> allowedProxyIPs = geyser.config().advanced().bedrock().haproxyProtocolWhitelistedIps();
if (geyser.config().advanced().bedrock().useHaproxyProtocol() && !allowedProxyIPs.isEmpty()) {
if (haproxyEnabled && !allowedProxyIPs.isEmpty()) {
boolean isWhitelistedIP = false;
for (CIDRMatcher matcher : getWhitelistedIPsMatchers()) {
if (matcher.matches(inetSocketAddress.getAddress())) {
Expand All @@ -255,7 +271,7 @@ public boolean onConnectionRequest(InetSocketAddress inetSocketAddress, InetSock

ConnectionRequestEvent requestEvent = new ConnectionRequestEvent(
clientAddress,
geyser.config().advanced().bedrock().useHaproxyProtocol() ? inetSocketAddress : null
haproxyEnabled ? inetSocketAddress : null
);
geyser.eventBus().fire(requestEvent);
if (requestEvent.isCancelled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ protected void channelRead0(ChannelHandlerContext ctx, RakPing msg) {

InetSocketAddress address = msg.getSender();
InetSocketAddress clientAddress = ((RakServerChannel) ctx.channel()).getClientAddress(address);
if (clientAddress == null) {
// Drop silently when no PROXY header was resolved. Responding with the raw sender (the
// proxy's IP) would leak that address to ping passthrough. GeyserServer#onConnectionRequest
// surfaces the misconfiguration via a warning when a client actually tries to connect.
return;
}
RakPong pong = msg.reply(guid, this.server.onQuery(ctx.channel(), clientAddress).toByteBuf());
ctx.writeAndFlush(pong);
}
Expand Down
Loading