Skip to content

Commit

Permalink
Add KeepAliveFrequency check, add missing @GlobalConfig.
Browse files Browse the repository at this point in the history
Limit the number of keep-alive packets to one per second.
  • Loading branch information
asofold committed Feb 9, 2015
1 parent c4b6845 commit 85dcb33
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 32 deletions.
@@ -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);
}

}
Expand Up @@ -7,7 +7,6 @@

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;

Expand All @@ -16,12 +15,8 @@
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;

Expand All @@ -32,7 +27,7 @@
* @author dev1mc
*
*/
public class FlyingFrequency extends PacketAdapter {
public class FlyingFrequency extends BaseAdapter {

// Setup for flying packets.
public static final int numBooleans = 3;
Expand All @@ -44,48 +39,39 @@ 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;
}

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);
Expand Down Expand Up @@ -141,7 +127,7 @@ private boolean checkRedundantPackets(final Player player, final PacketEvent eve
lastTime = data.flyingFrequencyTimeNotOnGround;
data.flyingFrequencyTimeNotOnGround = time;
}
if (time - lastTime > 1000) {
if (time < lastTime || time - lastTime > 1000) {
// Override
onGroundSkip = true;
}
Expand Down
@@ -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.
}

}
Expand Up @@ -19,6 +19,7 @@
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;

/**
Expand All @@ -28,6 +29,9 @@
*/
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) {
Expand All @@ -40,6 +44,9 @@ private void register(Plugin plugin) {
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);
}
Expand Down Expand Up @@ -91,7 +98,7 @@ public void onDisable() {
@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 ?
}

Expand Down
Expand Up @@ -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;
Expand Down
Expand Up @@ -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;
Expand All @@ -40,6 +43,9 @@ public NetConfig(final ConfigFile config) {
// 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;
Expand All @@ -53,6 +59,8 @@ public boolean isEnabled(final CheckType checkType) {
return flyingFrequencyActive;
case NET_SOUNDDISTANCE:
return soundDistanceActive;
case NET_KEEPALIVEFREQUENCY:
return keepAliveFrequencyActive;
default:
return true;
}
Expand Down
Expand Up @@ -4,23 +4,32 @@
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);
Expand Down
Expand Up @@ -7,7 +7,7 @@
import fr.neatmonster.nocheatplus.utilities.ds.corw.LinkedHashMapCOW;

/**
* Currently primary thread only!
* Copy on write, right now.
* @author asofold
*
*/
Expand Down
Expand Up @@ -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
Expand All @@ -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";

Expand Down
Expand Up @@ -447,6 +447,10 @@ public DefaultConfig() {
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);
Expand Down Expand Up @@ -493,7 +497,9 @@ public DefaultConfig() {
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!");
Expand Down
Expand Up @@ -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";
Expand Down

0 comments on commit 85dcb33

Please sign in to comment.