1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-29 03:39:22 +00:00

Increase packet limits for multiple connected clients playing from one IP address (#5351)

* Fix https://github.com/GeyserMC/Geyser/issues/4926

* Extend the RakServerRateLimiter, now that it is possible

* Update core/src/main/java/org/geysermc/geyser/network/netty/handler/RakGeyserRateLimiter.java

* cast to int
This commit is contained in:
chris
2025-02-23 18:37:01 +01:00
committed by GitHub
parent 07be402563
commit 87d9907413
4 changed files with 89 additions and 2 deletions

View File

@@ -59,6 +59,7 @@ import org.geysermc.geyser.network.CIDRMatcher;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.network.GeyserServerInitializer;
import org.geysermc.geyser.network.netty.handler.RakConnectionRequestHandler;
import org.geysermc.geyser.network.netty.handler.RakGeyserRateLimiter;
import org.geysermc.geyser.network.netty.handler.RakPingHandler;
import org.geysermc.geyser.network.netty.proxy.ProxyServerHandler;
import org.geysermc.geyser.ping.GeyserPingInfo;
@@ -175,6 +176,9 @@ public final class GeyserServer {
if (Boolean.parseBoolean(System.getProperty("Geyser.RakRateLimitingDisabled", "false")) || isWhitelistedProxyProtocol) {
// We would already block any non-whitelisted IP addresses in onConnectionRequest so we can remove the rate limiter
channel.pipeline().remove(RakServerRateLimiter.NAME);
} else {
// Use our own rate limiter to allow multiple players from the same IP
channel.pipeline().replace(RakServerRateLimiter.NAME, RakGeyserRateLimiter.NAME, new RakGeyserRateLimiter(channel));
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2019-2025 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.handler;
import io.netty.channel.Channel;
import org.cloudburstmc.netty.channel.raknet.RakServerChannel;
import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerRateLimiter;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.session.SessionManager;
import java.net.InetAddress;
public class RakGeyserRateLimiter extends RakServerRateLimiter {
public static final String NAME = "rak-geyser-rate-limiter";
private final SessionManager sessionManager;
public RakGeyserRateLimiter(Channel channel) {
super((RakServerChannel) channel);
this.sessionManager = GeyserImpl.getInstance().getSessionManager();
}
@Override
protected int getAddressMaxPacketCount(InetAddress address) {
// Using a factor of 0.8 for now, as the default packet count is already padded for multiple
return (int) (super.getAddressMaxPacketCount(address) * sessionManager.getAddressMultiplier(address) * 0.8);
}
}

View File

@@ -32,8 +32,15 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.text.GeyserLocale;
import java.util.*;
import java.net.InetAddress;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public final class SessionManager {
/**
@@ -47,6 +54,13 @@ public final class SessionManager {
@Getter
private final Map<UUID, GeyserSession> sessions = new ConcurrentHashMap<>();
/**
* Stores the number of connected sessions per address they're connected from.
* Used to raise per-IP connection limits.
*/
@Getter(AccessLevel.PACKAGE)
private final Map<InetAddress, AtomicInteger> connectedClients = new ConcurrentHashMap<>();
/**
* Called once the player has successfully authenticated to the Geyser server.
*/
@@ -60,6 +74,14 @@ public final class SessionManager {
public void addSession(UUID uuid, GeyserSession session) {
pendingSessions.remove(session);
sessions.put(uuid, session);
connectedClients.compute(session.getSocketAddress().getAddress(), (key, count) -> {
if (count == null) {
return new AtomicInteger(0);
}
count.getAndIncrement();
return count;
});
}
public void removeSession(GeyserSession session) {
@@ -68,6 +90,17 @@ public final class SessionManager {
// Connection was likely pending
pendingSessions.remove(session);
}
connectedClients.computeIfPresent(session.getSocketAddress().getAddress(), (key, count) -> {
if (count.decrementAndGet() <= 0) {
return null;
}
return count;
});
}
public int getAddressMultiplier(InetAddress ip) {
AtomicInteger atomicInteger = connectedClients.get(ip);
return atomicInteger == null ? 1 : atomicInteger.get();
}
public @Nullable GeyserSession sessionByXuid(@NonNull String xuid) {

View File

@@ -13,7 +13,7 @@ websocket = "1.5.1"
protocol-connection = "3.0.0.Beta6-20250212.131009-3"
protocol-common = "3.0.0.Beta6-20250212.131009-3"
protocol-codec = "3.0.0.Beta6-20250212.131009-3"
raknet = "1.0.0.CR3-20250128.101054-17"
raknet = "1.0.0.CR3-20250218.160705-18"
minecraftauth = "4.1.1"
mcprotocollib = "1.21.4-20250218.175633-22"
adventure = "4.14.0"