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:
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user