Add check: net/AttackFrequency (without improbable).

This commit is contained in:
asofold 2015-11-16 12:29:39 +01:00
parent d899334d8f
commit 8ff29c2575
8 changed files with 206 additions and 7 deletions

View File

@ -0,0 +1,94 @@
package fr.neatmonster.nocheatplus.checks.net.protocollib;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.checks.net.NetConfig;
import fr.neatmonster.nocheatplus.checks.net.NetData;
public class AttackFrequency extends Check {
public AttackFrequency() {
super(CheckType.NET_ATTACKFREQUENCY);
}
public boolean check(final Player player, final long time, final NetData data, final NetConfig cc) {
// Update frequency.
data.attackFrequencySeconds.add(time, 1f);
double maxVL = 0.0;
float maxLimit = 0f;
String tags = null;
// TODO: option to normalize the vl / stats to per second?
// HALF
float sum = data.attackFrequencySeconds.bucketScore(0); // HALF
float limit = cc.attackFrequencyLimitSecondsHalf;
if (sum - limit > maxVL) {
maxVL = sum - limit;
maxLimit = limit;
tags = "sec_half";
}
// ONE (update sum).
sum += data.attackFrequencySeconds.bucketScore(1);
limit = cc.attackFrequencyLimitSecondsOne;
if (sum - limit > maxVL) {
maxVL = sum - limit;
maxLimit = limit;
tags = "sec_one";
}
// TWO (update sum).
sum += data.attackFrequencySeconds.sliceScore(2, 4, 1f);
limit = cc.attackFrequencyLimitSecondsTwo;
if (sum - limit > maxVL) {
maxVL = sum - limit;
maxLimit = limit;
tags = "sec_two";
}
// FOUR (update sum).
sum += data.attackFrequencySeconds.sliceScore(4, 8, 1f);
limit = cc.attackFrequencyLimitSecondsFour;
if (sum - limit > maxVL) {
maxVL = sum - limit;
maxLimit = limit;
tags = "sec_four";
}
// EIGHT (update sum).
sum += data.attackFrequencySeconds.sliceScore(8, 16, 1f);
limit = cc.attackFrequencyLimitSecondsEight;
if (sum - limit > maxVL) {
maxVL = sum - limit;
maxLimit = limit;
tags = "sec_eight";
}
// if (data.debug) {
// player.sendMessage("AttackFrequency: " + data.attackFrequencySeconds.toLine());
// }
boolean cancel = false;
if (maxVL > 0.0) {
// Trigger a violation.
final ViolationData vd = new ViolationData(this, player, maxVL, 1.0, cc.attackFrequencyActions);
if (data.debug || vd.needsParameters()) {
vd.setParameter(ParameterName.PACKETS, Integer.toString((int) sum));
vd.setParameter(ParameterName.LIMIT, Integer.toString((int) maxLimit));
vd.setParameter(ParameterName.TAGS, tags);
}
if (executeActions(vd)) {
cancel = true;
}
// // TODO: Still feed the improbable (needs TickTask extension ...)
// if (data.speedVL > 50){
// Improbable.check(player, 2f, now, "fight.speed");
// }
// else{
// Improbable.feed(player, 2f, now);
// }
}
return cancel;
}
}

View File

@ -62,10 +62,10 @@ public class ProtocolLibComponent implements DisableListener, INotifyReload, Joi
register("fr.neatmonster.nocheatplus.checks.net.protocollib.DebugAdapter", plugin);
}
// Actual checks.
// if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_ATTACKFREQUENCY_ACTIVE)) {
// // (Also sets lastKeepAliveTime, if enabled.)
// register("fr.neatmonster.nocheatplus.checks.net.protocollib.UseEntityAdapter", plugin);
// }
if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_ATTACKFREQUENCY_ACTIVE)) {
// (Also sets lastKeepAliveTime, if enabled.)
register("fr.neatmonster.nocheatplus.checks.net.protocollib.UseEntityAdapter", plugin);
}
if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_FLYINGFREQUENCY_ACTIVE)) {
// (Also sets lastKeepAliveTime, if enabled.)
register("fr.neatmonster.nocheatplus.checks.net.protocollib.FlyingFrequency", plugin);

View File

@ -0,0 +1,70 @@
package fr.neatmonster.nocheatplus.checks.net.protocollib;
import java.util.Arrays;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
import fr.neatmonster.nocheatplus.NCPAPIProvider;
import fr.neatmonster.nocheatplus.checks.net.NetConfig;
import fr.neatmonster.nocheatplus.checks.net.NetData;
import fr.neatmonster.nocheatplus.config.ConfPaths;
import fr.neatmonster.nocheatplus.config.ConfigManager;
public class UseEntityAdapter extends BaseAdapter {
private final AttackFrequency attackFrequency;
public UseEntityAdapter(Plugin plugin) {
super(plugin, PacketType.Play.Client.USE_ENTITY);
// Add feature tags for checks.
if (ConfigManager.isTrueForAnyConfig(ConfPaths.NET_ATTACKFREQUENCY_ACTIVE)) {
NCPAPIProvider.getNoCheatPlusAPI().addFeatureTags("checks", Arrays.asList(AttackFrequency.class.getSimpleName()));
}
attackFrequency = new AttackFrequency();
NCPAPIProvider.getNoCheatPlusAPI().addComponent(attackFrequency);
}
@Override
public void onPacketReceiving(final PacketEvent event) {
final long time = System.currentTimeMillis();
final Player player = event.getPlayer();
final NetConfig cc = configFactory.getConfig(player);
final NetData data = dataFactory.getData(player);
// Always set last received time.
data.lastKeepAliveTime = time;
// Quick return, if no checks are active.
if (!cc.attackFrequencyActive) {
return;
}
final PacketContainer packet = event.getPacket();
final StructureModifier<EntityUseAction> actions = packet.getEntityUseActions();
if (actions.size() != 1) {
// TODO: Log warning once.
return;
}
final EntityUseAction action = actions.read(0);
boolean cancel = false;
if (action == EntityUseAction.ATTACK && attackFrequency.isEnabled(player, data, cc) && attackFrequency.check(player, time, data, cc)) {
cancel = true;
}
// MIGHT: use entity, use block both on packet level?
if (cancel) {
event.setCancelled(true);
}
}
}

View File

@ -213,6 +213,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
cancelled = true;
}
}
// TODO: Consider to always check improbable (first?). At least if config.always or speed or net.attackfrequency are enabled.
if (!cancelled && critical.isEnabled(player) && critical.check(player, loc, data, cc)) {
cancelled = true;

View File

@ -16,6 +16,12 @@ import fr.neatmonster.nocheatplus.permissions.Permissions;
public class NetConfig extends ACheckConfig {
public final boolean attackFrequencyActive;
public final float attackFrequencyLimitSecondsHalf;
public final float attackFrequencyLimitSecondsOne;
public final float attackFrequencyLimitSecondsTwo;
public final float attackFrequencyLimitSecondsFour;
public final float attackFrequencyLimitSecondsEight;
public final ActionList attackFrequencyActions;
public final boolean flyingFrequencyActive;
public final int flyingFrequencySeconds;
@ -43,7 +49,12 @@ public class NetConfig extends ACheckConfig {
final ConfigFile globalConfig = ConfigManager.getConfigFile();
attackFrequencyActive = config.getBoolean(ConfPaths.NET_ATTACKFREQUENCY_ACTIVE);
// TODO: Others.
attackFrequencyLimitSecondsHalf = config.getInt(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_HALF);
attackFrequencyLimitSecondsOne = config.getInt(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_ONE);
attackFrequencyLimitSecondsTwo = config.getInt(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_TWO);
attackFrequencyLimitSecondsFour= config.getInt(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_FOUR);
attackFrequencyLimitSecondsEight = config.getInt(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_EIGHT);
attackFrequencyActions = config.getOptimizedActionList(ConfPaths.NET_ATTACKFREQUENCY_ACTIONS, Permissions.NET_ATTACKFREQUENCY);
flyingFrequencyActive = config.getBoolean(ConfPaths.NET_FLYINGFREQUENCY_ACTIVE);
flyingFrequencySeconds = Math.max(1, globalConfig.getInt(ConfPaths.NET_FLYINGFREQUENCY_SECONDS));

View File

@ -16,6 +16,10 @@ import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
*/
public class NetData extends ACheckData {
// AttackFrequency
public ActionFrequency attackFrequencySeconds = new ActionFrequency(16, 500);
// FlyingFrequency
/** All flying packets, use System.currentTimeMillis() for time. */
public final ActionFrequency flyingFrequencyAll;
public boolean flyingFrequencyOnGround = false;
@ -27,6 +31,7 @@ public class NetData extends ACheckData {
*/
public final ActionFrequency flyingFrequencyRedundantFreq;
// KeepAliveFrequency
/**
* Last 20 seconds keep alive packets counting. Use lastUpdate() for the
* time of the last event. System.currentTimeMillis() is used.
@ -34,7 +39,10 @@ public class NetData extends ACheckData {
public ActionFrequency keepAliveFreq = new ActionFrequency(20, 1000);
// Shared.
/** Last time some action was received (keep alive or flying). Also maintained for fight.godmode. */
/**
* Last time some action was received (keep alive/flying/interaction). Also
* maintained for fight.godmode.
*/
public long lastKeepAliveTime = 0L;
public final TeleportQueue teleportQueue = new TeleportQueue(); // TODO: Consider using one lock per data instance and pass here.

View File

@ -614,7 +614,14 @@ public abstract class ConfPaths {
private static final String NET_ATTACKFREQUENCY = NET + "attackfrequency.";
public static final String NET_ATTACKFREQUENCY_ACTIVE = NET_ATTACKFREQUENCY + "active";
// TODO: Parameters / concept.
// TODO: Generic config for seconds.
public static final String NET_ATTACKFREQUENCY_SECONDS = NET_ATTACKFREQUENCY + "limitforseconds.";
public static final String NET_ATTACKFREQUENCY_SECONDS_HALF = NET_ATTACKFREQUENCY_SECONDS + "half";
public static final String NET_ATTACKFREQUENCY_SECONDS_ONE = NET_ATTACKFREQUENCY_SECONDS + "one";
public static final String NET_ATTACKFREQUENCY_SECONDS_TWO = NET_ATTACKFREQUENCY_SECONDS + "two";
public static final String NET_ATTACKFREQUENCY_SECONDS_FOUR = NET_ATTACKFREQUENCY_SECONDS + "four";
public static final String NET_ATTACKFREQUENCY_SECONDS_EIGHT = NET_ATTACKFREQUENCY_SECONDS + "eight";
public static final String NET_ATTACKFREQUENCY_ACTIONS = NET_ATTACKFREQUENCY + "actions";
private static final String NET_FLYINGFREQUENCY = NET + "flyingfrequency.";
public static final String NET_FLYINGFREQUENCY_ACTIVE = NET_FLYINGFREQUENCY + "active";

View File

@ -447,6 +447,12 @@ public class DefaultConfig extends ConfigFile {
// AttackFrequency
set(ConfPaths.NET_ATTACKFREQUENCY_ACTIVE, true);
set(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_HALF, 10);
set(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_ONE, 15);
set(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_TWO, 30);
set(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_FOUR, 60);
set(ConfPaths.NET_ATTACKFREQUENCY_SECONDS_EIGHT, 100);
set(ConfPaths.NET_ATTACKFREQUENCY_ACTIONS, "cancel vl>30 cancel log:attackfrequency:0:5:if vl>160 cancel log:attackfrequency:0:0:cif cmd:kickattackfrequency");
// FlyingFrequency
set(ConfPaths.NET_FLYINGFREQUENCY_ACTIVE, true);
@ -472,6 +478,7 @@ public class DefaultConfig extends ConfigFile {
final String end = ". VL [violations].";
final String tell = "ncp tell [player] ";
set(ConfPaths.STRINGS + ".angle", start + "tried to hit multiple entities at the same time" + end);
set(ConfPaths.STRINGS + ".attackfrequency", start + "attacks with too high a frequency ([packets]/[limit], [tags])" + end);
set(ConfPaths.STRINGS + ".ban", "ban [player]");
set(ConfPaths.STRINGS + ".ban-ip", "ban-ip [ip]");
set(ConfPaths.STRINGS + ".bautosign", start + "failed autosign with [tags]" + end);
@ -511,6 +518,7 @@ public class DefaultConfig extends ConfigFile {
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 + ".kickattackfrequency", "ncp kick [player] Unlikely fast clicking.");
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!");