Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-19 14:30:17 +01:00
Allow configuration of RakNet limits (#4532)
* Allow configuration of RakNet limits Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> * Validate packet limiter system properties Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com> --------- Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
Dieser Commit ist enthalten in:
Ursprung
fbafdbb2a7
Commit
c9ca4c82f7
@ -40,9 +40,11 @@ import org.geysermc.geyser.api.network.AuthType;
|
|||||||
import org.geysermc.geyser.network.CIDRMatcher;
|
import org.geysermc.geyser.network.CIDRMatcher;
|
||||||
import org.geysermc.geyser.text.AsteriskSerializer;
|
import org.geysermc.geyser.text.AsteriskSerializer;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
import org.geysermc.geyser.util.WebUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -233,7 +235,18 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
|||||||
List<CIDRMatcher> matchers = this.whitelistedIPsMatchers;
|
List<CIDRMatcher> matchers = this.whitelistedIPsMatchers;
|
||||||
if (matchers == null) {
|
if (matchers == null) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
this.whitelistedIPsMatchers = matchers = proxyProtocolWhitelistedIPs.stream()
|
// Check if proxyProtocolWhitelistedIPs contains URLs we need to fetch and parse by line
|
||||||
|
List<String> whitelistedCIDRs = new ArrayList<>();
|
||||||
|
for (String ip: proxyProtocolWhitelistedIPs) {
|
||||||
|
if (!ip.startsWith("http")) {
|
||||||
|
whitelistedCIDRs.add(ip);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebUtils.getLineStream(ip).forEach(whitelistedCIDRs::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.whitelistedIPsMatchers = matchers = whitelistedCIDRs.stream()
|
||||||
.map(CIDRMatcher::new)
|
.map(CIDRMatcher::new)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ import net.jodah.expiringmap.ExpiringMap;
|
|||||||
import org.cloudburstmc.netty.channel.raknet.RakChannelFactory;
|
import org.cloudburstmc.netty.channel.raknet.RakChannelFactory;
|
||||||
import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption;
|
import org.cloudburstmc.netty.channel.raknet.config.RakChannelOption;
|
||||||
import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerOfflineHandler;
|
import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerOfflineHandler;
|
||||||
|
import org.cloudburstmc.netty.handler.codec.raknet.server.RakServerRateLimiter;
|
||||||
import org.cloudburstmc.protocol.bedrock.BedrockPong;
|
import org.cloudburstmc.protocol.bedrock.BedrockPong;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.command.defaults.ConnectionTestCommand;
|
import org.geysermc.geyser.command.defaults.ConnectionTestCommand;
|
||||||
@ -71,6 +72,10 @@ import java.util.concurrent.TimeUnit;
|
|||||||
import java.util.function.IntFunction;
|
import java.util.function.IntFunction;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_GLOBAL_PACKET_LIMIT;
|
||||||
|
import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_OFFLINE_PACKET_LIMIT;
|
||||||
|
import static org.cloudburstmc.netty.channel.raknet.RakConstants.DEFAULT_PACKET_LIMIT;
|
||||||
|
|
||||||
public final class GeyserServer {
|
public final class GeyserServer {
|
||||||
private static final boolean PRINT_DEBUG_PINGS = Boolean.parseBoolean(System.getProperty("Geyser.PrintPingsInDebugMode", "true"));
|
private static final boolean PRINT_DEBUG_PINGS = Boolean.parseBoolean(System.getProperty("Geyser.PrintPingsInDebugMode", "true"));
|
||||||
|
|
||||||
@ -141,23 +146,31 @@ public final class GeyserServer {
|
|||||||
bootstrapFutures = new ChannelFuture[listenCount];
|
bootstrapFutures = new ChannelFuture[listenCount];
|
||||||
for (int i = 0; i < listenCount; i++) {
|
for (int i = 0; i < listenCount; i++) {
|
||||||
ChannelFuture future = bootstrap.bind(address);
|
ChannelFuture future = bootstrap.bind(address);
|
||||||
addHandlers(future);
|
modifyHandlers(future);
|
||||||
bootstrapFutures[i] = future;
|
bootstrapFutures[i] = future;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Bootstraps.allOf(bootstrapFutures);
|
return Bootstraps.allOf(bootstrapFutures);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addHandlers(ChannelFuture future) {
|
private void modifyHandlers(ChannelFuture future) {
|
||||||
Channel channel = future.channel();
|
Channel channel = future.channel();
|
||||||
// Add our ping handler
|
// Add our ping handler
|
||||||
channel.pipeline()
|
channel.pipeline()
|
||||||
.addFirst(RakConnectionRequestHandler.NAME, new RakConnectionRequestHandler(this))
|
.addFirst(RakConnectionRequestHandler.NAME, new RakConnectionRequestHandler(this))
|
||||||
.addAfter(RakServerOfflineHandler.NAME, RakPingHandler.NAME, new RakPingHandler(this));
|
.addAfter(RakServerOfflineHandler.NAME, RakPingHandler.NAME, new RakPingHandler(this));
|
||||||
|
|
||||||
// Add proxy handler
|
// Add proxy handler
|
||||||
if (this.geyser.getConfig().getBedrock().isEnableProxyProtocol()) {
|
boolean isProxyProtocol = this.geyser.getConfig().getBedrock().isEnableProxyProtocol();
|
||||||
|
if (isProxyProtocol) {
|
||||||
channel.pipeline().addFirst("proxy-protocol-decoder", new ProxyServerHandler());
|
channel.pipeline().addFirst("proxy-protocol-decoder", new ProxyServerHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean isWhitelistedProxyProtocol = isProxyProtocol && !this.geyser.getConfig().getBedrock().getProxyProtocolWhitelistedIPs().isEmpty();
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
@ -199,11 +212,26 @@ public final class GeyserServer {
|
|||||||
GeyserServerInitializer serverInitializer = new GeyserServerInitializer(this.geyser);
|
GeyserServerInitializer serverInitializer = new GeyserServerInitializer(this.geyser);
|
||||||
playerGroup = serverInitializer.getEventLoopGroup();
|
playerGroup = serverInitializer.getEventLoopGroup();
|
||||||
this.geyser.getLogger().debug("Setting MTU to " + this.geyser.getConfig().getMtu());
|
this.geyser.getLogger().debug("Setting MTU to " + this.geyser.getConfig().getMtu());
|
||||||
|
|
||||||
|
int rakPacketLimit = positivePropOrDefault("Geyser.RakPacketLimit", DEFAULT_PACKET_LIMIT);
|
||||||
|
this.geyser.getLogger().debug("Setting RakNet packet limit to " + rakPacketLimit);
|
||||||
|
|
||||||
|
boolean isWhitelistedProxyProtocol = this.geyser.getConfig().getBedrock().isEnableProxyProtocol()
|
||||||
|
&& !this.geyser.getConfig().getBedrock().getProxyProtocolWhitelistedIPs().isEmpty();
|
||||||
|
int rakOfflinePacketLimit = positivePropOrDefault("Geyser.RakOfflinePacketLimit", isWhitelistedProxyProtocol ? Integer.MAX_VALUE : DEFAULT_OFFLINE_PACKET_LIMIT);
|
||||||
|
this.geyser.getLogger().debug("Setting RakNet offline packet limit to " + rakOfflinePacketLimit);
|
||||||
|
|
||||||
|
int rakGlobalPacketLimit = positivePropOrDefault("Geyser.RakGlobalPacketLimit", DEFAULT_GLOBAL_PACKET_LIMIT);
|
||||||
|
this.geyser.getLogger().debug("Setting RakNet global packet limit to " + rakGlobalPacketLimit);
|
||||||
|
|
||||||
return new ServerBootstrap()
|
return new ServerBootstrap()
|
||||||
.channelFactory(RakChannelFactory.server(TRANSPORT.datagramChannel()))
|
.channelFactory(RakChannelFactory.server(TRANSPORT.datagramChannel()))
|
||||||
.group(group, childGroup)
|
.group(group, childGroup)
|
||||||
.option(RakChannelOption.RAK_HANDLE_PING, true)
|
.option(RakChannelOption.RAK_HANDLE_PING, true)
|
||||||
.option(RakChannelOption.RAK_MAX_MTU, this.geyser.getConfig().getMtu())
|
.option(RakChannelOption.RAK_MAX_MTU, this.geyser.getConfig().getMtu())
|
||||||
|
.option(RakChannelOption.RAK_PACKET_LIMIT, rakPacketLimit)
|
||||||
|
.option(RakChannelOption.RAK_OFFLINE_PACKET_LIMIT, rakOfflinePacketLimit)
|
||||||
|
.option(RakChannelOption.RAK_GLOBAL_PACKET_LIMIT, rakGlobalPacketLimit)
|
||||||
.childHandler(serverInitializer);
|
.childHandler(serverInitializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,6 +380,27 @@ public final class GeyserServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int positivePropOrDefault(String property, int defaultValue) {
|
||||||
|
String value = System.getProperty(property);
|
||||||
|
try {
|
||||||
|
int parsed = value != null ? Integer.parseInt(value) : defaultValue;
|
||||||
|
|
||||||
|
if (parsed < 1) {
|
||||||
|
GeyserImpl.getInstance().getLogger().warning(
|
||||||
|
"Non-postive integer value for " + property + ": " + value + ". Using default value: " + defaultValue
|
||||||
|
);
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
GeyserImpl.getInstance().getLogger().warning(
|
||||||
|
"Invalid integer value for " + property + ": " + value + ". Using default value: " + defaultValue
|
||||||
|
);
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Transport compatibleTransport() {
|
private static Transport compatibleTransport() {
|
||||||
TransportHelper.TransportMethod transportMethod = TransportHelper.determineTransportMethod();
|
TransportHelper.TransportMethod transportMethod = TransportHelper.determineTransportMethod();
|
||||||
if (transportMethod == TransportHelper.TransportMethod.EPOLL) {
|
if (transportMethod == TransportHelper.TransportMethod.EPOLL) {
|
||||||
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.util;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||||
import com.fasterxml.jackson.annotation.Nulls;
|
import com.fasterxml.jackson.annotation.Nulls;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||||
import org.geysermc.geyser.GeyserBootstrap;
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
@ -56,6 +57,8 @@ public class FileUtils {
|
|||||||
*/
|
*/
|
||||||
public static <T> T loadConfig(File src, Class<T> valueType) throws IOException {
|
public static <T> T loadConfig(File src, Class<T> valueType) throws IOException {
|
||||||
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory())
|
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory())
|
||||||
|
// Allow inference of single values as arrays
|
||||||
|
.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
|
||||||
.setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
|
.setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
|
||||||
return objectMapper.readValue(src, valueType);
|
return objectMapper.readValue(src, valueType);
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class WebUtils {
|
public class WebUtils {
|
||||||
|
|
||||||
@ -176,6 +177,13 @@ public class WebUtils {
|
|||||||
return connectionToString(con);
|
return connectionToString(con);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a SRV record for the given address
|
||||||
|
*
|
||||||
|
* @param geyser Geyser instance
|
||||||
|
* @param remoteAddress Address to find the SRV record for
|
||||||
|
* @return The SRV record or null if not found
|
||||||
|
*/
|
||||||
public static String @Nullable [] findSrvRecord(GeyserImpl geyser, String remoteAddress) {
|
public static String @Nullable [] findSrvRecord(GeyserImpl geyser, String remoteAddress) {
|
||||||
try {
|
try {
|
||||||
// Searches for a server address and a port from a SRV record of the specified host name
|
// Searches for a server address and a port from a SRV record of the specified host name
|
||||||
@ -193,4 +201,26 @@ public class WebUtils {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a stream of lines from the given URL
|
||||||
|
*
|
||||||
|
* @param reqURL URL to fetch
|
||||||
|
* @return Stream of lines from the URL or an empty stream if the request fails
|
||||||
|
*/
|
||||||
|
public static Stream<String> getLineStream(String reqURL) {
|
||||||
|
try {
|
||||||
|
URL url = new URL(reqURL);
|
||||||
|
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
||||||
|
con.setRequestMethod("GET");
|
||||||
|
con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); // Otherwise Java 8 fails on checking updates
|
||||||
|
con.setConnectTimeout(10000);
|
||||||
|
con.setReadTimeout(10000);
|
||||||
|
|
||||||
|
return connectionToString(con).lines();
|
||||||
|
} catch (Exception e) {
|
||||||
|
GeyserImpl.getInstance().getLogger().error("Error while trying to get a stream from " + reqURL, e);
|
||||||
|
return Stream.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,8 @@ bedrock:
|
|||||||
# A list of allowed PROXY protocol speaking proxy IP addresses/subnets. Only effective when "enable-proxy-protocol" is enabled, and
|
# A list of allowed PROXY protocol speaking proxy IP addresses/subnets. Only effective when "enable-proxy-protocol" is enabled, and
|
||||||
# should really only be used when you are not able to use a proper firewall (usually true with shared hosting providers etc.).
|
# should really only be used when you are not able to use a proper firewall (usually true with shared hosting providers etc.).
|
||||||
# Keeping this list empty means there is no IP address whitelist.
|
# Keeping this list empty means there is no IP address whitelist.
|
||||||
# Both IP addresses and subnets are supported.
|
# IP addresses, subnets, and links to plain text files are supported.
|
||||||
#proxy-protocol-whitelisted-ips: [ "127.0.0.1", "172.18.0.0/16" ]
|
#proxy-protocol-whitelisted-ips: [ "127.0.0.1", "172.18.0.0/16", "https://example.com/whitelist.txt" ]
|
||||||
remote:
|
remote:
|
||||||
# The IP address of the remote (Java Edition) server
|
# The IP address of the remote (Java Edition) server
|
||||||
# If it is "auto", for standalone version the remote address will be set to 127.0.0.1,
|
# If it is "auto", for standalone version the remote address will be set to 127.0.0.1,
|
||||||
|
@ -11,7 +11,7 @@ gson = "2.3.1" # Provided by Spigot 1.8.8
|
|||||||
websocket = "1.5.1"
|
websocket = "1.5.1"
|
||||||
protocol = "3.0.0.Beta1-20240313.120922-126"
|
protocol = "3.0.0.Beta1-20240313.120922-126"
|
||||||
protocol-connection = "3.0.0.Beta1-20240313.120922-125"
|
protocol-connection = "3.0.0.Beta1-20240313.120922-125"
|
||||||
raknet = "1.0.0.CR1-20240330.101522-15"
|
raknet = "1.0.0.CR1-20240330.103819-16"
|
||||||
blockstateupdater="1.20.70-20240303.125052-2"
|
blockstateupdater="1.20.70-20240303.125052-2"
|
||||||
mcauthlib = "d9d773e"
|
mcauthlib = "d9d773e"
|
||||||
mcprotocollib = "1.20.4-2-20240116.220521-7"
|
mcprotocollib = "1.20.4-2-20240116.220521-7"
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren