Add KeepAliveFrequency check, add missing @GlobalConfig.

Limit the number of keep-alive packets to one per second.
This commit is contained in:
asofold 2015-02-09 16:16:52 +01:00
parent c4b6845b8f
commit 85dcb33a98
11 changed files with 162 additions and 32 deletions

View File

@ -0,0 +1,51 @@
package fr.neatmonster.nocheatplus.checks.net.protocollib;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ListenerOptions;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import fr.neatmonster.nocheatplus.NCPAPIProvider;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.net.NetConfigCache;
import fr.neatmonster.nocheatplus.checks.net.NetDataFactory;
import fr.neatmonster.nocheatplus.stats.Counters;
/**
* Convenience base class for PacketAdapter creation with using config, data, counters.
* @author asofold
*
*/
public abstract class BaseAdapter extends PacketAdapter {
protected final Counters counters = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Counters.class);
protected final NetConfigCache configFactory = (NetConfigCache) CheckType.NET.getConfigFactory();
protected final NetDataFactory dataFactory = (NetDataFactory) CheckType.NET.getDataFactory();
public BaseAdapter(AdapterParameteters params) {
super(params);
}
public BaseAdapter(Plugin plugin, Iterable<? extends PacketType> types) {
super(plugin, types);
}
public BaseAdapter(Plugin plugin, ListenerPriority listenerPriority, Iterable<? extends PacketType> types, ListenerOptions... options) {
super(plugin, listenerPriority, types, options);
}
public BaseAdapter(Plugin plugin, ListenerPriority listenerPriority, Iterable<? extends PacketType> types) {
super(plugin, listenerPriority, types);
}
public BaseAdapter(Plugin plugin, ListenerPriority listenerPriority, PacketType... types) {
super(plugin, listenerPriority, types);
}
public BaseAdapter(Plugin plugin, PacketType... types) {
super(plugin, types);
}
}

View File

@ -7,7 +7,6 @@ import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
@ -16,12 +15,8 @@ import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
import fr.neatmonster.nocheatplus.checks.net.NetConfig;
import fr.neatmonster.nocheatplus.checks.net.NetConfigCache;
import fr.neatmonster.nocheatplus.checks.net.NetData;
import fr.neatmonster.nocheatplus.checks.net.NetDataFactory;
import fr.neatmonster.nocheatplus.logging.Streams;
import fr.neatmonster.nocheatplus.stats.Counters;
import fr.neatmonster.nocheatplus.time.monotonic.Monotonic;
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
import fr.neatmonster.nocheatplus.utilities.TrigUtil;
@ -32,7 +27,7 @@ import fr.neatmonster.nocheatplus.utilities.TrigUtil;
* @author dev1mc
*
*/
public class FlyingFrequency extends PacketAdapter {
public class FlyingFrequency extends BaseAdapter {
// Setup for flying packets.
public static final int numBooleans = 3;
@ -44,40 +39,31 @@ public class FlyingFrequency extends PacketAdapter {
public static final double minMoveDistSq = 1f / 256; // PlayerConnection magic.
public static final float minLookChange = 10f;
/** Dummy check to access hasBypass for FlyingFrequency. */
private final Check frequency = new Check(CheckType.NET_FLYINGFREQUENCY) {
// Dummy check to access hasBypass.
};
/** Dummy check for bypass checking and actions execution. */
private final Check frequency = new Check(CheckType.NET_FLYINGFREQUENCY) {};
private final Counters counters = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Counters.class);
private final int idNullPlayer = counters.registerKey("packet.flying.nullplayer");
private final int idHandled = counters.registerKey("packet.flying.handled");
private final int idAsyncFlying = counters.registerKey("packet.flying.asynchronous");
private boolean cancelRedundant = true;
private final NetConfigCache configs;
private final NetDataFactory dataFactory;
public FlyingFrequency(Plugin plugin) {
// PacketPlayInFlying[3, legacy: 10]
super(plugin, ListenerPriority.LOW, PacketType.Play.Client.FLYING); // TODO: How does POS and POS_LOOK relate/translate?
this.configs = (NetConfigCache) CheckType.NET.getConfigFactory();
this.dataFactory = (NetDataFactory) CheckType.NET.getDataFactory();
super(plugin, ListenerPriority.LOW, PacketType.Play.Client.FLYING);
}
@Override
public void onPacketReceiving(final PacketEvent event) {
final long time = System.currentTimeMillis();
final Player player = event.getPlayer();
if (player == null) {
// TODO: Need config?
counters.add(idNullPlayer, 1);
counters.add(ProtocolLibComponent.idNullPlayer, 1);
event.setCancelled(true);
return;
}
final NetConfig cc = configs.getConfig(player.getWorld());
final NetConfig cc = configFactory.getConfig(player.getWorld());
if (!cc.flyingFrequencyActive) {
return;
}
@ -85,7 +71,7 @@ public class FlyingFrequency extends PacketAdapter {
counters.add(idHandled, 1);
final NetData data = dataFactory.getData(player);
final long time = Monotonic.millis();
// Counting all packets.
// TODO: Consider using the NetStatic check.
data.flyingFrequencyAll.add(time, 1f);
@ -141,7 +127,7 @@ public class FlyingFrequency extends PacketAdapter {
lastTime = data.flyingFrequencyTimeNotOnGround;
data.flyingFrequencyTimeNotOnGround = time;
}
if (time - lastTime > 1000) {
if (time < lastTime || time - lastTime > 1000) {
// Override
onGroundSkip = true;
}

View File

@ -0,0 +1,57 @@
package fr.neatmonster.nocheatplus.checks.net.protocollib;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketEvent;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.net.NetConfig;
import fr.neatmonster.nocheatplus.checks.net.NetData;
public class KeepAliveFrequency extends BaseAdapter {
/** Dummy check for bypass checking and actions execution. */
private final Check check = new Check(CheckType.NET_KEEPALIVEFREQUENCY) {};
public KeepAliveFrequency(Plugin plugin) {
super(plugin, ListenerPriority.LOW, PacketType.Play.Client.KEEP_ALIVE);
}
@Override
public void onPacketReceiving(final PacketEvent event) {
final long time = System.currentTimeMillis();
final Player player = event.getPlayer();
if (player == null) {
counters.add(ProtocolLibComponent.idNullPlayer, 1);
event.setCancelled(true);
return;
}
final NetConfig cc = configFactory.getConfig(player);
if (!cc.keepAliveFrequencyActive) {
return;
}
final NetData data = dataFactory.getData(player);
// TODO: Better modeling of actual packet sequences (flying vs. keep alive vs. request/ping).
// TODO: Better integration wih god-mode check / trigger reset ndt.
data.keepAliveFreq.add(time, 1f);
// Use last time accepted as a hard reference.
final float first = data.keepAliveFreq.bucketScore(0);
if (first > 1f && !check.hasBypass(player)) {
// Trigger a violation.
final double vl = Math.max(first - 1f, data.keepAliveFreq.score(1f) - data.keepAliveFreq.numberOfBuckets());
if (check.executeActions(player, vl, 1.0, cc.keepAliveFrequencyActions)) {
event.setCancelled(true);
}
}
}
@Override
public void onPacketSending(PacketEvent event) {
// TODO: Maybe detect if keep alive wasn't asked for + allow cancel.
}
}

View File

@ -19,6 +19,7 @@ import fr.neatmonster.nocheatplus.components.NoCheatPlusAPI;
import fr.neatmonster.nocheatplus.config.ConfPaths;
import fr.neatmonster.nocheatplus.config.ConfigManager;
import fr.neatmonster.nocheatplus.logging.StaticLog;
import fr.neatmonster.nocheatplus.stats.Counters;
import fr.neatmonster.nocheatplus.utilities.StringUtil;
/**
@ -28,6 +29,9 @@ import fr.neatmonster.nocheatplus.utilities.StringUtil;
*/
public class ProtocolLibComponent implements DisableListener, INotifyReload {
// TODO: Static reference is problematic (needs a static and accessible Counters instance?).
public static final int idNullPlayer = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Counters.class).registerKey("packet.flying.nullplayer");
private final List<PacketAdapter> registeredPacketAdapters = new LinkedList<PacketAdapter>();
public ProtocolLibComponent(Plugin plugin) {
@ -40,6 +44,9 @@ public class ProtocolLibComponent implements DisableListener, INotifyReload {
if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_FLYINGFREQUENCY_ACTIVE)) {
register("fr.neatmonster.nocheatplus.checks.net.protocollib.FlyingFrequency", plugin);
}
if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_KEEPALIVEFREQUENCY_ACTIVE)) {
register("fr.neatmonster.nocheatplus.checks.net.protocollib.KeepAliveFrequency", plugin);
}
if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_SOUNDDISTANCE_ACTIVE)) {
register("fr.neatmonster.nocheatplus.checks.net.protocollib.SoundDistance", plugin);
}
@ -91,7 +98,7 @@ public class ProtocolLibComponent implements DisableListener, INotifyReload {
@Override
public void onReload() {
unregister();
CheckType.NET.getDataFactory().removeAllData(); // Currently needed for FlyingFRequency.
CheckType.NET.getDataFactory().removeAllData(); // Currently needed for FlyingFrequency.
register(Bukkit.getPluginManager().getPlugin("NoCheatPlus")); // Store instead ?
}

View File

@ -100,6 +100,7 @@ public enum CheckType {
NET(new NetConfigCache(), new NetDataFactory(), Permissions.NET),
NET_FLYINGFREQUENCY(NET, Permissions.NET_FLYINGFREQUENCY),
NET_KEEPALIVEFREQUENCY(NET, Permissions.NET_KEEPALIVEFREQUENCY),
NET_SOUNDDISTANCE(NET), // Can not exempt players from this one.
UNKNOWN;

View File

@ -23,6 +23,9 @@ public class NetConfig extends ACheckConfig {
public final int flyingFrequencyRedundantSeconds;
public final ActionList flyingFrequencyRedundantActions;
public final boolean keepAliveFrequencyActive;
public final ActionList keepAliveFrequencyActions;
public final boolean soundDistanceActive;
/** Maximum distance for lightning effects (squared). */
public final double soundDistanceSq;
@ -40,6 +43,9 @@ public class NetConfig extends ACheckConfig {
// Same permission for "silent".
flyingFrequencyRedundantActions = config.getOptimizedActionList(ConfPaths.NET_FLYINGFREQUENCY_REDUNDANT_ACTIONS, Permissions.NET_FLYINGFREQUENCY);
keepAliveFrequencyActive = config.getBoolean(ConfPaths.NET_KEEPALIVEFREQUENCY_ACTIVE);
keepAliveFrequencyActions = config.getOptimizedActionList(ConfPaths.NET_KEEPALIVEFREQUENCY_ACTIONS, Permissions.NET_KEEPALIVEFREQUENCY);
soundDistanceActive = config.getBoolean(ConfPaths.NET_SOUNDDISTANCE_ACTIVE);
double dist = config.getDouble(ConfPaths.NET_SOUNDDISTANCE_MAXDISTANCE);
soundDistanceSq = dist * dist;
@ -53,6 +59,8 @@ public class NetConfig extends ACheckConfig {
return flyingFrequencyActive;
case NET_SOUNDDISTANCE:
return soundDistanceActive;
case NET_KEEPALIVEFREQUENCY:
return keepAliveFrequencyActive;
default:
return true;
}

View File

@ -4,23 +4,32 @@ import fr.neatmonster.nocheatplus.checks.access.ACheckData;
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
/**
* Primary thread only.
* Data for net checks. Some data structures may not be thread-safe, but
* accessing each checks data individually respecting the sequence of events
* should work.
*
* @author asofold
*
*/
public class NetData extends ACheckData {
/** All flying packets, use Monotonic.millis() for time. */
/** All flying packets, use System.currentTimeMillis() for time. */
public final ActionFrequency flyingFrequencyAll;
public boolean flyingFrequencyOnGround = false;
public long flyingFrequencyTimeOnGround = 0L;
public long flyingFrequencyTimeNotOnGround = 0L;
/**
* Monitors redundant packets, when more than 20 packets per second are
* sent. Use Monotonic.millis() for time.
* sent. Use System.currentTimeMillis() for time.
*/
public final ActionFrequency flyingFrequencyRedundantFreq;
/**
* Last 20 seconds keep alive packets counting. Use lastUpdate() for the
* time of the last event. System.currentTimeMillis() is used.
*/
public ActionFrequency keepAliveFreq = new ActionFrequency(20, 1000);
public NetData(final NetConfig config) {
super(config);
flyingFrequencyAll = new ActionFrequency(config.flyingFrequencySeconds, 1000L);

View File

@ -7,7 +7,7 @@ import fr.neatmonster.nocheatplus.checks.access.CheckDataFactory;
import fr.neatmonster.nocheatplus.utilities.ds.corw.LinkedHashMapCOW;
/**
* Currently primary thread only!
* Copy on write, right now.
* @author asofold
*
*/

View File

@ -600,10 +600,6 @@ public abstract class ConfPaths {
public static final String NET = CHECKS + "net.";
private static final String NET_SOUNDDISTANCE = NET + "sounddistance.";
public static final String NET_SOUNDDISTANCE_ACTIVE = NET_SOUNDDISTANCE + "active";
public static final String NET_SOUNDDISTANCE_MAXDISTANCE = NET_SOUNDDISTANCE + "maxdistance";
private static final String NET_FLYINGFREQUENCY = NET + "flyingfrequency.";
public static final String NET_FLYINGFREQUENCY_ACTIVE = NET_FLYINGFREQUENCY + "active";
@GlobalConfig
@ -613,9 +609,17 @@ public abstract class ConfPaths {
public static final String NET_FLYINGFREQUENCY_ACTIONS = NET_FLYINGFREQUENCY + "actions";
private static final String NET_FLYINGFREQUENCY_REDUNDANT = NET_FLYINGFREQUENCY + "reduceredundant.";
public static final String NET_FLYINGFREQUENCY_REDUNDANT_ACTIVE = NET_FLYINGFREQUENCY_REDUNDANT + "active";
@GlobalConfig
public static final String NET_FLYINGFREQUENCY_REDUNDANT_SECONDS = NET_FLYINGFREQUENCY_REDUNDANT + "seconds";
public static final String NET_FLYINGFREQUENCY_REDUNDANT_ACTIONS = NET_FLYINGFREQUENCY_REDUNDANT + "actions";
private static final String NET_KEEPALIVEFREQUENCY = NET + "keepalivefrequency.";
public static final String NET_KEEPALIVEFREQUENCY_ACTIVE = NET_KEEPALIVEFREQUENCY + "active";
public static final String NET_KEEPALIVEFREQUENCY_ACTIONS = NET_KEEPALIVEFREQUENCY + "actions";
private static final String NET_SOUNDDISTANCE = NET + "sounddistance.";
public static final String NET_SOUNDDISTANCE_ACTIVE = NET_SOUNDDISTANCE + "active";
public static final String NET_SOUNDDISTANCE_MAXDISTANCE = NET_SOUNDDISTANCE + "maxdistance";
public static final String STRINGS = "strings";

View File

@ -447,6 +447,10 @@ public class DefaultConfig extends ConfigFile {
set(ConfPaths.NET_FLYINGFREQUENCY_REDUNDANT_SECONDS, 3);
set(ConfPaths.NET_FLYINGFREQUENCY_REDUNDANT_ACTIONS, "cancel"); // TODO: Log actions.
// KeepAliveFrequency
set(ConfPaths.NET_KEEPALIVEFREQUENCY_ACTIVE, true);
set(ConfPaths.NET_KEEPALIVEFREQUENCY_ACTIONS, "cancel vl>10 cancel log:keepalive:0:10:if vl>40 cancel log:keepalive:0:10:icf vl>100 cancel log:keepalive:0:10:icf cmd:kickalive");
// SoundDistance
set(ConfPaths.NET_SOUNDDISTANCE_ACTIVE, true);
set(ConfPaths.NET_SOUNDDISTANCE_MAXDISTANCE, 320);
@ -493,7 +497,9 @@ public class DefaultConfig extends ConfigFile {
set(ConfPaths.STRINGS + ".improbable", start + "meets the improbable more than expected" + end);
set(ConfPaths.STRINGS + ".instantbow", start + "fires bow too fast" + end);
set(ConfPaths.STRINGS + ".instanteat", start + "eats food [food] too fast" + end);
set(ConfPaths.STRINGS + ".keepalive", start + "spams keep-alive packets (god/freecam?)" + end);
set(ConfPaths.STRINGS + ".kick", "kick [player]");
set(ConfPaths.STRINGS + ".kickalive", "ncp kick [player] Too many keep-alive packets.");
set(ConfPaths.STRINGS + ".kickbedleave", "ncp delay ncp kick [player] Go find a bed!");
set(ConfPaths.STRINGS + ".kickbspeed", "ncp kick [player] You interacted too fast!");
set(ConfPaths.STRINGS + ".kickcaptcha", "ncp kick [player] Enter the captcha!");

View File

@ -116,6 +116,7 @@ public class Permissions {
public static final String NET = CHECKS + ".net";
public static final String NET_FLYINGFREQUENCY = NET + ".flyingfrequency";
public static final String NET_KEEPALIVEFREQUENCY = NET + ".keepalivefrequency";
public static final String MOVING = CHECKS + ".moving";
public static final String MOVING_CREATIVEFLY = MOVING + ".creativefly";