Skip to content

Commit d362a77

Browse files
committed
Improve protection against spam attacks
1 parent f3f8261 commit d362a77

10 files changed

Lines changed: 49 additions & 24 deletions

File tree

bungeeguard-backend/src/main/java/me/lucko/bungeeguard/backend/BungeeGuardBackend.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ public interface BungeeGuardBackend {
1212
Path getConfigPath();
1313

1414
void reloadConfig();
15+
16+
boolean isVerbose();
1517
}

bungeeguard-backend/src/main/java/me/lucko/bungeeguard/backend/listener/AbstractHandshakeListener.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import me.lucko.bungeeguard.backend.BungeeGuardBackend;
2929
import me.lucko.bungeeguard.backend.TokenStore;
3030

31+
import java.util.concurrent.atomic.AtomicLong;
32+
3133
/**
3234
* An abstract handshake listener.
3335
*/
@@ -38,7 +40,7 @@ public abstract class AbstractHandshakeListener {
3840
protected final String noDataKickMessage;
3941
protected final String invalidTokenKickMessage;
4042

41-
private long throttle;
43+
private final AtomicLong throttle = new AtomicLong();
4244

4345
protected AbstractHandshakeListener(BungeeGuardBackend plugin, TokenStore tokenStore) {
4446
this.plugin = plugin;
@@ -47,13 +49,8 @@ protected AbstractHandshakeListener(BungeeGuardBackend plugin, TokenStore tokenS
4749
this.invalidTokenKickMessage = plugin.getKickMessage("invalid-token-kick-message");
4850
}
4951

50-
public boolean isThrottled() {
51-
long cur = System.currentTimeMillis();
52-
if (cur - this.throttle >= 1000L) {
53-
this.throttle = cur;
54-
return false;
55-
} else {
56-
return true;
57-
}
52+
public boolean isRateLimitAllowed() {
53+
long current = System.currentTimeMillis();
54+
return current - this.throttle.getAndSet(current) >= 1000;
5855
}
5956
}

bungeeguard-spigot/src/main/java/me/lucko/bungeeguard/spigot/BungeeCordHandshake.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,12 @@ private static BungeeCordHandshake decodeAndVerify0(String handshake, TokenStore
9090
readIndex = 1;
9191
}
9292
String socketAddressHostname = split[readIndex++];
93-
UUID uniqueId = UUID.fromString(split[readIndex++].replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
93+
UUID uniqueId;
94+
try {
95+
uniqueId = UUID.fromString(split[readIndex++].replaceFirst("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5"));
96+
} catch (NumberFormatException e) {
97+
return new Fail(Fail.Reason.INVALID_UNIQUE_ID, encodeBase64(handshake));
98+
}
9499

95100
String connectionDescription = uniqueId + " @ " + encodeBase64(socketAddressHostname);
96101

@@ -108,7 +113,7 @@ private static BungeeCordHandshake decodeAndVerify0(String handshake, TokenStore
108113
JsonObject property = iterator.next();
109114
if (property.get(PROPERTY_NAME_KEY).getAsString().equals(BUNGEEGUARD_TOKEN_NAME)) {
110115
if (bungeeGuardToken != null) {
111-
return new Fail(Fail.Reason.INCORRECT_TOKEN, connectionDescription + " - more than one token");
116+
return new Fail(Fail.Reason.DUPLICATED_TOKEN, connectionDescription);
112117
}
113118

114119
bungeeGuardToken = property.get(PROPERTY_VALUE_KEY).getAsString();
@@ -195,8 +200,7 @@ public String describeConnection() {
195200
}
196201

197202
public enum Reason {
198-
INVALID_HANDSHAKE, NO_TOKEN, INCORRECT_TOKEN
203+
INVALID_HANDSHAKE, INVALID_UNIQUE_ID, NO_TOKEN, DUPLICATED_TOKEN, INCORRECT_TOKEN
199204
}
200205
}
201-
202206
}

bungeeguard-spigot/src/main/java/me/lucko/bungeeguard/spigot/BungeeGuardBackendPlugin.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ public Path getConfigPath() {
139139
return new File(getDataFolder(), "config.yml").toPath();
140140
}
141141

142+
@Override
143+
public boolean isVerbose() {
144+
return getConfig().getBoolean("verbose", false);
145+
}
146+
142147
private boolean isBungeeEnabled() {
143148
YamlConfiguration spigotConfig = getServer().spigot().getSpigotConfig();
144149
return spigotConfig.getBoolean("settings.bungeecord") || spigotConfig.getBoolean("spigot.settings.bungeecord");
@@ -173,5 +178,4 @@ private static boolean classExists(String className) {
173178
return false;
174179
}
175180
}
176-
177181
}

bungeeguard-spigot/src/main/java/me/lucko/bungeeguard/spigot/listener/PaperHandshakeListener.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
public class PaperHandshakeListener extends AbstractHandshakeListener implements Listener {
4545

4646
private static final Method getOriginalSocketAddressHostname;
47+
4748
static {
4849
Method method = null;
4950
try {
@@ -69,17 +70,17 @@ public void onHandshake(PlayerHandshakeEvent e) {
6970
BungeeCordHandshake.Fail fail = (BungeeCordHandshake.Fail) decoded;
7071

7172
// if the logging is not throttled, we send the error message
72-
if (!isThrottled()) {
73-
String ip = "";
73+
if (isRateLimitAllowed()) {
74+
String ip = "null";
7475
if (getOriginalSocketAddressHostname != null) {
7576
try {
76-
ip = getOriginalSocketAddressHostname.invoke(e) + " - ";
77+
ip = (String) getOriginalSocketAddressHostname.invoke(e);
7778
} catch (ReflectiveOperationException ex) {
7879
this.logger.log(Level.SEVERE, "Unable to get original address", ex);
7980
}
8081
}
8182

82-
this.logger.warning("Denying connection from " + ip + fail.describeConnection() + " - reason: " + fail.reason().name());
83+
this.logger.warning("Denying connection from " + ip + " - " + (plugin.isVerbose() ? fail.describeConnection() : "") + " - reason: " + fail.reason().name());
8384
}
8485

8586
if (fail.reason() == BungeeCordHandshake.Fail.Reason.INCORRECT_TOKEN) {

bungeeguard-spigot/src/main/java/me/lucko/bungeeguard/spigot/listener/ProtocolHandshakeListener.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,16 @@ public ProtocolHandshakeListener(BungeeGuardBackend plugin, TokenStore tokenStor
5454
}
5555

5656
public void registerAdapter(Plugin plugin) {
57-
ProtocolLibrary.getProtocolManager().addPacketListener(new Adapter(plugin));
57+
ProtocolLibrary.getProtocolManager().addPacketListener(new Adapter(plugin, super.plugin));
5858
}
5959

6060
private final class Adapter extends PacketAdapter {
61-
Adapter(Plugin plugin) {
61+
62+
private final BungeeGuardBackend backend;
63+
64+
Adapter(Plugin plugin, BungeeGuardBackend backend) {
6265
super(plugin, ListenerPriority.LOWEST, PacketType.Handshake.Client.SET_PROTOCOL);
66+
this.backend = backend;
6367
}
6468

6569
@Override
@@ -80,7 +84,7 @@ public void onPacketReceiving(PacketEvent event) {
8084
Player player = event.getPlayer();
8185

8286
// if the logging is not throttled, we send the error message
83-
if (!isThrottled()) {
87+
if (isRateLimitAllowed()) {
8488
String ip = "null";
8589
InetSocketAddress address = player.getAddress();
8690
if (address != null) {
@@ -89,7 +93,7 @@ public void onPacketReceiving(PacketEvent event) {
8993
ip = BungeeCordHandshake.encodeBase64(ip);
9094
}
9195
}
92-
this.plugin.getLogger().warning("Denying connection from " + ip + " - " + fail.describeConnection() + " - reason: " + fail.reason().name());
96+
this.plugin.getLogger().warning("Denying connection from " + ip + " - " + (backend.isVerbose() ? fail.describeConnection() : "") + " - reason: " + fail.reason().name());
9397
}
9498

9599
String kickMessage;

bungeeguard-spigot/src/main/resources/config.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,8 @@ invalid-token-kick-message:
2626
- '&cThe token sent by proxy server is not allowed by this backend server.'
2727
- ''
2828
- '§7More information:'
29-
- '&bdocs.nickuc.com/bungeeguard'
29+
- '&bdocs.nickuc.com/bungeeguard'
30+
31+
# Defines if BungeeGuard should detail errors in the console.
32+
# Useful for debugging purposes.
33+
verbose: false

bungeeguard-sponge/src/main/java/me/lucko/bungeeguard/sponge/BungeeGuardSponge.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,9 @@ public void reloadConfig() {
170170
throw new RuntimeException("Unable to load config", e);
171171
}
172172
}
173+
174+
@Override
175+
public boolean isVerbose() {
176+
return this.config.getNode("verbose").getBoolean(false);
177+
}
173178
}

bungeeguard-sponge/src/main/java/me/lucko/bungeeguard/sponge/HandshakeListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public void onClientAuth(ClientConnectionEvent.Auth e) {
6666

6767
if (bungeeGuardToken == null || !this.tokenStore.isAllowed(bungeeGuardToken)) {
6868
// if the logging is not throttled, we send the error message
69-
if (!isThrottled()) {
69+
if (isRateLimitAllowed()) {
7070
String connectionDescription = profile.getUniqueId() + " @ " + e.getConnection().getAddress().getHostString();
7171
String reason = bungeeGuardToken == null ? "No Token" : "Invalid token";
7272

bungeeguard-sponge/src/main/resources/bungeeguard.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,7 @@ invalid-token-kick-message = [
3030
"§7More information:",
3131
"&bdocs.nickuc.com/bungeeguard",
3232
]
33+
34+
# Defines if BungeeGuard should detail errors in the console.
35+
# Useful for debugging purposes.
36+
verbose = false

0 commit comments

Comments
 (0)