Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-12-23 23:00:35 +01:00
Refactored rate-limiting.
If rate-limiting is disabled, we now use a simple stub implementation that is simpler to reason with.
Dieser Commit ist enthalten in:
Ursprung
89e51bbcb9
Commit
a378ccdee0
@ -34,8 +34,9 @@ import com.velocitypowered.proxy.scheduler.VelocityScheduler;
|
||||
import com.velocitypowered.proxy.server.ServerMap;
|
||||
import com.velocitypowered.proxy.util.AddressUtil;
|
||||
import com.velocitypowered.proxy.util.EncryptionUtils;
|
||||
import com.velocitypowered.proxy.util.Ratelimiter;
|
||||
import com.velocitypowered.proxy.util.VelocityChannelRegistrar;
|
||||
import com.velocitypowered.proxy.util.ratelimit.Ratelimiter;
|
||||
import com.velocitypowered.proxy.util.ratelimit.Ratelimiters;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.file.Files;
|
||||
@ -166,7 +167,7 @@ public class VelocityServer implements ProxyServer {
|
||||
servers.register(new ServerInfo(entry.getKey(), AddressUtil.parseAddress(entry.getValue())));
|
||||
}
|
||||
|
||||
ipAttemptLimiter = new Ratelimiter(configuration.getLoginRatelimit());
|
||||
ipAttemptLimiter = Ratelimiters.createWithMilliseconds(configuration.getLoginRatelimit());
|
||||
httpClient = new NettyHttpClient(this);
|
||||
loadPlugins();
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.velocitypowered.proxy.util;
|
||||
package com.velocitypowered.proxy.util.ratelimit;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Ticker;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
@ -11,28 +12,25 @@ import java.util.concurrent.TimeUnit;
|
||||
/**
|
||||
* A simple rate-limiter based on a Guava {@link Cache}.
|
||||
*/
|
||||
public class Ratelimiter {
|
||||
public class GuavaCacheRatelimiter implements Ratelimiter {
|
||||
|
||||
private final Cache<InetAddress, Long> expiringCache;
|
||||
private final long timeoutNanos;
|
||||
|
||||
public Ratelimiter(long timeoutMs) {
|
||||
this(timeoutMs, Ticker.systemTicker());
|
||||
GuavaCacheRatelimiter(long time, TimeUnit unit) {
|
||||
this(time, unit, Ticker.systemTicker());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
Ratelimiter(long timeoutMs, Ticker ticker) {
|
||||
if (timeoutMs == 0) {
|
||||
this.timeoutNanos = timeoutMs;
|
||||
this.expiringCache = CacheBuilder.newBuilder().maximumSize(0).build();
|
||||
} else {
|
||||
this.timeoutNanos = TimeUnit.MILLISECONDS.toNanos(timeoutMs);
|
||||
this.expiringCache = CacheBuilder.newBuilder()
|
||||
.ticker(ticker)
|
||||
.concurrencyLevel(Runtime.getRuntime().availableProcessors())
|
||||
.expireAfterWrite(timeoutMs, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
}
|
||||
GuavaCacheRatelimiter(long time, TimeUnit unit, Ticker ticker) {
|
||||
Preconditions.checkNotNull(unit, "unit");
|
||||
Preconditions.checkNotNull(ticker, "ticker");
|
||||
this.timeoutNanos = unit.toNanos(time);
|
||||
this.expiringCache = CacheBuilder.newBuilder()
|
||||
.ticker(ticker)
|
||||
.concurrencyLevel(Runtime.getRuntime().availableProcessors())
|
||||
.expireAfterWrite(time, unit)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -41,10 +39,9 @@ public class Ratelimiter {
|
||||
* @param address the address to rate limit
|
||||
* @return true if we should allow the client, false if we should rate-limit
|
||||
*/
|
||||
@Override
|
||||
public boolean attempt(InetAddress address) {
|
||||
if (timeoutNanos == 0) {
|
||||
return true;
|
||||
}
|
||||
Preconditions.checkNotNull(address, "address");
|
||||
long expectedNewValue = System.nanoTime() + timeoutNanos;
|
||||
long last;
|
||||
try {
|
@ -0,0 +1,15 @@
|
||||
package com.velocitypowered.proxy.util.ratelimit;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* A {@link Ratelimiter} that does no rate-limiting.
|
||||
*/
|
||||
enum NoopCacheRatelimiter implements Ratelimiter {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public boolean attempt(InetAddress address) {
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.velocitypowered.proxy.util.ratelimit;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* Allows rate limiting of clients.
|
||||
*/
|
||||
public interface Ratelimiter {
|
||||
|
||||
/**
|
||||
* Determines whether or not to allow the connection.
|
||||
* @param address the address to rate limit
|
||||
* @return true if allowed, false if not
|
||||
*/
|
||||
boolean attempt(InetAddress address);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.velocitypowered.proxy.util.ratelimit;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class Ratelimiters {
|
||||
private Ratelimiters() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
public static Ratelimiter createWithMilliseconds(long ms) {
|
||||
return ms <= 0 ? NoopCacheRatelimiter.INSTANCE : new GuavaCacheRatelimiter(ms,
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.velocitypowered.proxy.util;
|
||||
package com.velocitypowered.proxy.util.ratelimit;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
@ -9,11 +9,11 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class RatelimiterTest {
|
||||
class GuavaCacheRatelimiterTest {
|
||||
|
||||
@Test
|
||||
void attemptZero() {
|
||||
Ratelimiter noRatelimiter = new Ratelimiter(0);
|
||||
Ratelimiter noRatelimiter = new GuavaCacheRatelimiter(0, TimeUnit.MILLISECONDS);
|
||||
assertTrue(noRatelimiter.attempt(InetAddress.getLoopbackAddress()));
|
||||
assertTrue(noRatelimiter.attempt(InetAddress.getLoopbackAddress()));
|
||||
}
|
||||
@ -28,7 +28,7 @@ class RatelimiterTest {
|
||||
return base + extra.get();
|
||||
}
|
||||
};
|
||||
Ratelimiter ratelimiter = new Ratelimiter(1000, testTicker);
|
||||
Ratelimiter ratelimiter = new GuavaCacheRatelimiter(1000, TimeUnit.MILLISECONDS, testTicker);
|
||||
assertTrue(ratelimiter.attempt(InetAddress.getLoopbackAddress()));
|
||||
assertFalse(ratelimiter.attempt(InetAddress.getLoopbackAddress()));
|
||||
extra.addAndGet(TimeUnit.SECONDS.toNanos(2));
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren