mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-11-27 04:25:12 +01:00
Implement a packet limiting system,
This means that if a client sends more than a maximum, it will be disconnected. It also means if a client goes over a threshold multiple times over a period of time, it will be disconnected. Improvements are welcome, it's mostly down to how the user configures it. (Some values are higher so that we don't kill every server with a tiny bit of lag)
This commit is contained in:
parent
cf20e8ac5f
commit
a81d52a54f
@ -397,6 +397,36 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
|
||||
return getConfig().getBoolean("block-break-patch", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPPS() {
|
||||
return getConfig().getInt("max-pps", 140);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaxPPSKickMessage() {
|
||||
return getConfig().getString("max-pps-kick-msg", "Sending packets too fast? lag?");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackingPeriod() {
|
||||
return getConfig().getInt("tracking-period", 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWarningPPS() {
|
||||
return getConfig().getInt("tracking-warning-pps", 120);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxWarnings() {
|
||||
return getConfig().getInt("tracking-max-warnings", 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaxWarningsKickMessage() {
|
||||
return getConfig().getString("tracking-max-kick-msg", "You are sending too many packets, :(");
|
||||
}
|
||||
|
||||
public boolean isAutoTeam() {
|
||||
// Collision has to be enabled first
|
||||
return isPreventCollision() && getConfig().getBoolean("auto-team", true);
|
||||
@ -432,4 +462,33 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
|
||||
public Map<UUID, UserConnection> getPortedPlayers() {
|
||||
return portedPlayers;
|
||||
}
|
||||
|
||||
public boolean handlePPS(UserConnection info) {
|
||||
// Max PPS Checker
|
||||
if (getMaxPPS() > 0) {
|
||||
if (info.getPacketsPerSecond() >= getMaxPPS()) {
|
||||
info.disconnect(getMaxPPSKickMessage());
|
||||
return true; // don't send current packet
|
||||
}
|
||||
}
|
||||
|
||||
// Tracking PPS Checker
|
||||
if (getMaxWarnings() > 0 && getTrackingPeriod() > 0) {
|
||||
if (info.getSecondsObserved() > getTrackingPeriod()) {
|
||||
// Reset
|
||||
info.setWarnings(0);
|
||||
info.setSecondsObserved(1);
|
||||
} else {
|
||||
info.setSecondsObserved(info.getSecondsObserved() + 1);
|
||||
if (info.getPacketsPerSecond() >= getWarningPPS()) {
|
||||
info.setWarnings(info.getWarnings() + 1);
|
||||
}
|
||||
}
|
||||
if (info.getWarnings() >= getMaxWarnings()) {
|
||||
info.disconnect(getMaxWarningsKickMessage());
|
||||
return true; // don't send current packet
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -100,4 +100,46 @@ public interface ViaVersionConfig {
|
||||
* @return true if it is enabled.
|
||||
*/
|
||||
boolean isBlockBreakPatch();
|
||||
|
||||
/**
|
||||
* Get the maximum number of packets a client can send per second.
|
||||
*
|
||||
* @return The number of packets a client can send per second.
|
||||
*/
|
||||
int getMaxPPS();
|
||||
|
||||
/**
|
||||
* Get the kick message sent if the user hits the max packets per second.
|
||||
*
|
||||
* @return Kick message, with colour codes using '&'
|
||||
*/
|
||||
String getMaxPPSKickMessage();
|
||||
|
||||
/**
|
||||
* The time in seconds that should be tracked for warnings
|
||||
*
|
||||
* @return Time in seconds that should be tracked for warnings
|
||||
*/
|
||||
int getTrackingPeriod();
|
||||
|
||||
/**
|
||||
* The number of packets per second to count as a warning
|
||||
*
|
||||
* @return The number of packets per second to count as a warning.
|
||||
*/
|
||||
int getWarningPPS();
|
||||
|
||||
/**
|
||||
* Get the maximum number of warnings the client can have in the interval
|
||||
*
|
||||
* @return The number of packets a client can send per second.
|
||||
*/
|
||||
int getMaxWarnings();
|
||||
|
||||
/**
|
||||
* Get the kick message sent if the user goes over the warnings in the interval
|
||||
*
|
||||
* @return Kick message, with colour codes using '&'
|
||||
*/
|
||||
String getMaxWarningsKickMessage();
|
||||
}
|
||||
|
@ -1,28 +1,37 @@
|
||||
package us.myles.ViaVersion.api.data;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Data
|
||||
public class UserConnection {
|
||||
@Getter
|
||||
private final SocketChannel channel;
|
||||
Map<Class, StoredObject> storedObjects = new ConcurrentHashMap<>();
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean active = true;
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean pendingDisconnect = false;
|
||||
private Object lastPacket;
|
||||
@Getter
|
||||
private long sentPackets = 0L;
|
||||
@Getter
|
||||
private long receivedPackets = 0L;
|
||||
// Used for tracking pps
|
||||
private long startTime = 0L;
|
||||
private long intervalPackets = 0L;
|
||||
private long packetsPerSecond = -1L;
|
||||
// Used for handling warnings (over time)
|
||||
private int secondsObserved = 0;
|
||||
private int warnings = 0;
|
||||
|
||||
|
||||
public UserConnection(SocketChannel socketChannel) {
|
||||
@ -97,7 +106,45 @@ public class UserConnection {
|
||||
/**
|
||||
* Used for incrementing the number of packets received from the client
|
||||
*/
|
||||
public void incrementReceived() {
|
||||
public boolean incrementReceived() {
|
||||
// handle stats
|
||||
Long diff = System.currentTimeMillis() - startTime;
|
||||
if (diff >= 1000) {
|
||||
packetsPerSecond = intervalPackets;
|
||||
startTime = System.currentTimeMillis();
|
||||
intervalPackets = 1;
|
||||
return true;
|
||||
} else {
|
||||
intervalPackets++;
|
||||
}
|
||||
// increase total
|
||||
this.receivedPackets++;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect a connection
|
||||
*
|
||||
* @param reason The reason to use, not used if player is not active.
|
||||
*/
|
||||
public void disconnect(final String reason) {
|
||||
if(!getChannel().isOpen()) return;
|
||||
if(pendingDisconnect) return;
|
||||
pendingDisconnect = true;
|
||||
if (get(ProtocolInfo.class).getUuid() != null) {
|
||||
final UUID uuid = get(ProtocolInfo.class).getUuid();
|
||||
if (Bukkit.getPlayer(uuid) != null) {
|
||||
Bukkit.getScheduler().runTask(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player != null)
|
||||
player.kickPlayer(ChatColor.translateAlternateColorCodes('&', reason));
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
getChannel().close(); // =)
|
||||
}
|
||||
}
|
||||
|
@ -130,6 +130,7 @@ public class ViaCommandHandler implements ViaVersionCommand, CommandExecutor, Ta
|
||||
|
||||
private void registerDefaults() throws Exception {
|
||||
registerSubCommand(new ListSubCmd());
|
||||
registerSubCommand(new PPSSubCmd());
|
||||
registerSubCommand(new DebugSubCmd());
|
||||
registerSubCommand(new DisplayLeaksSubCmd());
|
||||
registerSubCommand(new DontBugMeSubCmd());
|
||||
|
@ -0,0 +1,62 @@
|
||||
package us.myles.ViaVersion.commands.defaultsubs;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.api.ViaVersion;
|
||||
import us.myles.ViaVersion.api.command.ViaSubCommand;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class PPSSubCmd extends ViaSubCommand {
|
||||
@Override
|
||||
public String name() {
|
||||
return "pps";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Shows the packets per second of online players";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String usage() {
|
||||
return "pps";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, String[] args) {
|
||||
Map<Integer, Set<String>> playerVersions = new HashMap<>();
|
||||
int totalPackets = 0;
|
||||
int clients = 0;
|
||||
long max = 0;
|
||||
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
int playerVersion = ViaVersion.getInstance().getPlayerVersion(p);
|
||||
if (!playerVersions.containsKey(playerVersion))
|
||||
playerVersions.put(playerVersion, new HashSet<String>());
|
||||
UserConnection uc = ((ViaVersionPlugin) ViaVersion.getInstance()).getConnection(p);
|
||||
if (uc.getPacketsPerSecond() > -1) {
|
||||
playerVersions.get(playerVersion).add(p.getName() + " (" + uc.getPacketsPerSecond() + " PPS)");
|
||||
totalPackets += uc.getPacketsPerSecond();
|
||||
if (uc.getPacketsPerSecond() > max) {
|
||||
max = uc.getPacketsPerSecond();
|
||||
}
|
||||
clients++;
|
||||
}
|
||||
}
|
||||
Map<Integer, Set<String>> sorted = new TreeMap<>(playerVersions);
|
||||
sendMessage(sender, "&4Live Packets Per Second");
|
||||
if (clients > 1) {
|
||||
sendMessage(sender, "&cAverage: &f" + (totalPackets / clients));
|
||||
sendMessage(sender, "&cHighest: &f" + max);
|
||||
}
|
||||
for (Map.Entry<Integer, Set<String>> entry : sorted.entrySet())
|
||||
sendMessage(sender, "&8[&6%s&8]: &b%s", ProtocolVersion.getProtocol(entry.getKey()).getName(), entry.getValue());
|
||||
sorted.clear();
|
||||
return true;
|
||||
}
|
||||
}
|
@ -3,7 +3,10 @@ package us.myles.ViaVersion.handlers;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.ViaVersion;
|
||||
import us.myles.ViaVersion.api.ViaVersionAPI;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.exception.CancelException;
|
||||
@ -29,9 +32,19 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
|
||||
// use transformers
|
||||
if (bytebuf.readableBytes() > 0) {
|
||||
if (info.isActive()) {
|
||||
// Ignore if pending disconnect
|
||||
if (info.isPendingDisconnect()) {
|
||||
return;
|
||||
}
|
||||
// Increment received
|
||||
info.incrementReceived();
|
||||
boolean second = info.incrementReceived();
|
||||
// Check PPS
|
||||
if(second) {
|
||||
if (((ViaVersionPlugin) ViaVersion.getConfig()).handlePPS(info))
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.isActive()) {
|
||||
// Handle ID
|
||||
int id = Type.VAR_INT.read(bytebuf);
|
||||
// Transform
|
||||
|
@ -39,9 +39,9 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
|
||||
if (bytebuf.readableBytes() == 0) {
|
||||
throw new CancelException();
|
||||
}
|
||||
if (info.isActive()) {
|
||||
// Increment sent
|
||||
info.incrementSent();
|
||||
if (info.isActive()) {
|
||||
// Handle ID
|
||||
int id = Type.VAR_INT.read(bytebuf);
|
||||
// Transform
|
||||
|
@ -31,3 +31,22 @@ suppress-entityid-errors: false
|
||||
block-break-patch: true
|
||||
# Should we cache our items, this will prevent server from being lagged out, however the cost is a constant task caching items
|
||||
item-cache: true
|
||||
# Anti-Cheat, Packets Per Second (PPS) limiter
|
||||
# Clients by default send around 20-90 packets per second.
|
||||
|
||||
# What is the maximum per second a client can send
|
||||
# Use -1 to disable.
|
||||
max-pps: 400
|
||||
max-pps-kick-msg: "You are sending too many packets!"
|
||||
|
||||
# We can also kick them if over a period they send over a threshold a certain amount of times.
|
||||
|
||||
# Period to track (in seconds)
|
||||
# Use -1 to disable.
|
||||
tracking-period: 6
|
||||
# How many packets per second counts as a warning
|
||||
tracking-warning-pps: 120
|
||||
# How many warnings over the interval can we have
|
||||
# This can never be higher than "tracking-interval"
|
||||
tracking-max-warnings: 4
|
||||
tracking-max-kick-msg: "You are sending too many packets, :("
|
Loading…
Reference in New Issue
Block a user