Skip to content
This repository has been archived by the owner on Apr 24, 2024. It is now read-only.

Commit

Permalink
Rewritten the detection system, which works now way better than before.
Browse files Browse the repository at this point in the history
Former-commit-id: ed8ced7
  • Loading branch information
PolskiStevek committed May 29, 2020
1 parent f3782e1 commit 0c9a35b
Show file tree
Hide file tree
Showing 14 changed files with 145 additions and 92 deletions.
7 changes: 4 additions & 3 deletions src/main/java/me/ishift/epicguard/bukkit/EpicGuardBukkit.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,17 @@ public void onEnable() {
final PluginManager pm = Bukkit.getPluginManager();
pm.registerEvents(new PlayerPreLoginListener(this.manager), this);
pm.registerEvents(new PlayerJoinListener(this.manager), this);
pm.registerEvents(new PlayerQuitListener(), this);
pm.registerEvents(new PlayerQuitListener(this.manager), this);
pm.registerEvents(new ServerListPingListener(), this);
pm.registerEvents(new PlayerCommandListener(), this);
pm.registerEvents(new ConsoleCommandListener(), this);
pm.registerEvents(new PlayerBuildListener(), this);
pm.registerEvents(new PlayerChatListener(), this);

final BukkitScheduler scheduler = this.getServer().getScheduler();
scheduler.runTaskTimerAsynchronously(this, new AttackToggleTask(this.manager), 20L, Configuration.checkConditionsDelay * 2L);
scheduler.runTaskTimerAsynchronously(this, new AttackToggleTask(this.manager), 20L, Configuration.checkConditionsDelay * 20L);
scheduler.runTaskTimerAsynchronously(this, new CounterTask(this.manager), 20L, 20L);
scheduler.runTaskTimerAsynchronously(this, new MonitorTask(this.manager, Platform.BUKKIT), 20L, 20L);
scheduler.runTaskTimerAsynchronously(this, new MonitorTask(this.manager, Platform.BUKKIT), 20L, 5L);

if (pm.isPluginEnabled("ProtocolLib")) {
new TabCompletePacketListener(this);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package me.ishift.epicguard.bukkit.listener;

import me.ishift.epicguard.bukkit.EpicGuardBukkit;
import me.ishift.epicguard.common.types.Reason;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;

public class PlayerChatListener implements Listener {
@EventHandler
public void onChat(AsyncPlayerChatEvent event) {
// MCSpam bots sends these messages to the chat after connect.
final String message = event.getMessage();
if (message.equals("'Attack") || message.equals("'/login") || message.equals("'/register")) {
event.setCancelled(true);
// Bukkit can't kick player in the async thread...
Bukkit.getScheduler().runTask(EpicGuardBukkit.getInstance(), () -> event.getPlayer().kickPlayer(Reason.BOT_BEHAVIOUR.getMessage()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ public class PlayerJoinListener implements Listener {

@EventHandler(priority = EventPriority.HIGHEST)
public void onJoin(PlayerJoinEvent event) {
// Hiding join message from bots that may have bypassed.
if (this.manager.isAttackMode()) {
event.setJoinMessage(null);
}

final Player player = event.getPlayer();
EpicGuardBukkit.getInstance().getUserManager().createUser(player);
final User user = EpicGuardBukkit.getInstance().getUserManager().getUser(player);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import lombok.AllArgsConstructor;
import me.ishift.epicguard.common.AttackManager;
import me.ishift.epicguard.common.antibot.Detection;
import me.ishift.epicguard.common.types.Reason;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
Expand All @@ -31,9 +31,9 @@ public void onPreLogin(AsyncPlayerPreLoginEvent event) {
final String address = event.getAddress().getHostAddress();
final String name = event.getName();

final Detection detection = this.manager.check(address, name);
if (detection.isDetected()) {
event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, detection.getReason().getMessage());
final Reason reason = this.manager.check(address, name);
if (reason != null) {
event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, reason.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,21 @@

import lombok.AllArgsConstructor;
import me.ishift.epicguard.bukkit.EpicGuardBukkit;
import me.ishift.epicguard.common.AttackManager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;

@AllArgsConstructor
public class PlayerQuitListener implements Listener {
private final AttackManager manager;

@EventHandler
public void onQuit(PlayerQuitEvent event) {
// Hiding quit message from bots that may have bypassed.
if (this.manager.isAttackMode()) {
event.setQuitMessage(null);
}
EpicGuardBukkit.getInstance().getUserManager().removeUser(event.getPlayer());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void onEnable() {

this.getProxy().getScheduler().schedule(this, new AttackToggleTask(this.manager), 1L, Configuration.checkConditionsDelay, TimeUnit.SECONDS);
this.getProxy().getScheduler().schedule(this, new CounterTask(this.manager), 1L, 1L, TimeUnit.SECONDS);
this.getProxy().getScheduler().schedule(this, new MonitorTask(this.manager, Platform.BUNGEE), 1L, 100L, TimeUnit.MILLISECONDS);
this.getProxy().getScheduler().schedule(this, new MonitorTask(this.manager, Platform.BUNGEE), 1L, 200L, TimeUnit.MILLISECONDS);

new BungeeMetrics(this, 5956);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
package me.ishift.epicguard.bungee.listener;

import me.ishift.epicguard.common.AttackManager;
import me.ishift.epicguard.common.antibot.Detection;
import net.md_5.bungee.api.chat.BaseComponent;
import me.ishift.epicguard.common.types.Reason;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.event.PreLoginEvent;
Expand All @@ -37,12 +36,10 @@ public void onPreLogin(PreLoginEvent event) {
final String address = connection.getAddress().getAddress().getHostAddress();
final String name = connection.getName();

final Detection detection = this.manager.check(address, name);
if (detection.isDetected()) {
final BaseComponent[] reason = TextComponent.fromLegacyText(detection.getReason().getMessage());
final Reason reason = this.manager.check(address, name);
if (reason != null) {
event.setCancelled(true);
event.setCancelReason(reason);
connection.disconnect(reason);
event.setCancelReason(TextComponent.fromLegacyText(reason.getMessage()));
}
}
}
82 changes: 72 additions & 10 deletions src/main/java/me/ishift/epicguard/common/AttackManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@

import lombok.Getter;
import lombok.Setter;
import me.ishift.epicguard.common.antibot.Detection;
import me.ishift.epicguard.common.antibot.ProxyService;
import me.ishift.epicguard.common.antibot.checks.*;
import me.ishift.epicguard.common.data.StorageManager;
import me.ishift.epicguard.common.data.config.Configuration;
import me.ishift.epicguard.common.data.config.Messages;
import me.ishift.epicguard.common.types.Reason;
import me.ishift.epicguard.common.util.LibraryLoader;

import java.util.Collection;
Expand All @@ -41,12 +41,10 @@ public class AttackManager {
private final ReJoinCheck reJoinCheck;
private final ServerListCheck serverListCheck;

@Setter
private int connectPerSecond = 0;
@Setter
private int totalBots = 0;
@Setter
private boolean attackMode = false;
@Setter private int connectPerSecond;
@Setter private int detectionsPerSecond;
@Setter private int totalBots;
@Setter private boolean attackMode;

/**
* Creating new AttackManager object.
Expand Down Expand Up @@ -85,16 +83,79 @@ public AttackManager() {
*
* @param address Address of the user.
* @param nickname Nickname of the user.
* @return Detection object with prepared checks.
* @return Reason enum if detected, null if not.
*/
public Detection check(String address, String nickname) {
return new Detection(address, nickname, this);
public Reason check(String address, String nickname) {
final Reason reason = this.performChecks(address, nickname);
if (reason == null) {
return null;
}

this.increaseBots();
if (reason.isBlacklist()) {
StorageManager.getStorage().blacklist(address);
}
return reason;
}

/**
* Performing the bot-check.
* This method performs the check for
* the detections. The method above
* need to be used in the listeners.
*
* @param address Address of the user.
* @param nickname Nickname of the user.
* @return Reason enum if detected, null if not.
*/
private Reason performChecks(String address, String nickname) {
this.increaseConnectPerSecond();
if (StorageManager.getStorage().getWhitelist().contains(address)) {
return null;
}

/* After testing, looks like this check is useless.
for some reason, block are blocked better without this.
it may be restored in the future, so i have commented it for now.
if (this.isAttackMode()) {
return Reason.ATTACK;
}
*/

if (this.getBlacklistCheck().execute(address, nickname)) {
return Reason.BLACKLIST;
}

if (this.getNicknameCheck().execute(address, nickname)) {
return Reason.NAME_CONTAINS;
}

if (this.getServerListCheck().execute(address, nickname)) {
return Reason.SERVER_LIST;
}

if (this.getReJoinCheck().execute(address, nickname)) {
return Reason.REJOIN;
}

if (this.getGeographicalCheck().execute(address, nickname)) {
return Reason.GEO;
}

if (this.getProxyCheck().execute(address, nickname)) {
return Reason.PROXY;
}
return null;
}

/**
* Increase connections per second by one.
*/
public void increaseConnectPerSecond() {
if (this.getConnectPerSecond() > Configuration.connectSpeed || this.getDetectionsPerSecond() > Configuration.detections) {
this.setAttackMode(true);
}

this.connectPerSecond++;
}

Expand All @@ -103,5 +164,6 @@ public void increaseConnectPerSecond() {
*/
public void increaseBots() {
this.totalBots++;
this.detectionsPerSecond++;
}
}
57 changes: 1 addition & 56 deletions src/main/java/me/ishift/epicguard/common/antibot/Detection.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ public Detection(String address, String nickname, AttackManager manager) {
this.address = address;
this.nickname = nickname;
this.detected = true;
this.blacklist = false;
this.perform();
}

Expand Down Expand Up @@ -70,61 +69,7 @@ public boolean isDetected() {
* Performing the checks.
*/
public void perform() {
final GuardLogger logger = this.manager.getLogger();
logger.debug(" ");
logger.debug("------- * ANTIBOT CHECK * -------");
logger.debug("Performing check on: " + this.nickname + " (" + this.address + ")");
logger.debug("Current CPS: " + this.manager.getConnectPerSecond() + " (Attack: " + this.manager.isAttackMode() + ")");
// Checking if player is whitelisted.
if (StorageManager.getStorage().getWhitelist().contains(address)) {
this.detected = false;
logger.debug("User is whitelisted, skipping check.");
return;
}

// Increasing CPS/activating attack mode.
this.manager.increaseConnectPerSecond();
if (this.manager.getConnectPerSecond() > Configuration.connectSpeed) {
this.manager.setAttackMode(true);
}

// Performing checks.
if (this.manager.getBlacklistCheck().execute(address, nickname)) {
this.reason = Reason.BLACKLIST;
}
else if (this.manager.getNicknameCheck().execute(address, nickname)) {
this.reason = Reason.NAME_CONTAINS;
this.blacklist = true;
}
else if (this.manager.getServerListCheck().execute(address, nickname)) {
this.reason = Reason.SERVER_LIST;
}
else if (this.manager.getReJoinCheck().execute(address, nickname)) {
this.reason = Reason.REJOIN;
}
else if (this.manager.getGeographicalCheck().execute(address, nickname)) {
this.reason = Reason.GEO;
this.blacklist = true;
}
else if (this.manager.getProxyCheck().execute(address, nickname)) {
this.reason = Reason.PROXY;
this.blacklist = true;
}
else {
this.detected = false;
logger.debug("User has been not detected.");
}

// Increasing bots if detection is positive.
if (this.detected) {
this.manager.increaseBots();
logger.debug("User has been detected for: " + this.reason);
}

// Blacklisting addres if it should be.
if (this.blacklist) {
StorageManager.getStorage().blacklist(this.address);
logger.debug("The user has been blacklisted.");
}
this.detected = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package me.ishift.epicguard.common.data.config;

import de.leonhard.storage.Yaml;
import de.leonhard.storage.internal.settings.ConfigSettings;
import me.ishift.epicguard.common.antibot.ProxyService;
import me.ishift.epicguard.common.types.GeoMode;

Expand All @@ -26,6 +27,7 @@

public class Configuration {
public static int connectSpeed;
public static int detections;
public static int pingSpeed;

public static long checkConditionsDelay;
Expand Down Expand Up @@ -57,6 +59,7 @@ public static void load() {
final Yaml config = new Yaml("config.yml", "plugins/EpicGuard");

connectSpeed = config.getInt("antibot.additional-protection.conditions.connections-per-second");
detections = config.getInt("antibot.additional-protection.conditions.detections-per-second");
pingSpeed = config.getInt("antibot.additional-protection.conditions.ping-per-second");

checkConditionsDelay = config.getInt("antibot.additional-protection.check-conditions-delay");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class Messages {
public static List<String> messageKickBlacklist;
public static List<String> messageKickVerify;
public static List<String> messageKickNamecontains;
public static List<String> messageKickBotBehaviour;

public static String noPermission;
public static String prefix;
Expand Down Expand Up @@ -58,6 +59,7 @@ public static void load() {
messageKickBlacklist = config.getOrSetDefault("kick-messages.blacklist", Collections.singletonList("&8[&6EpicGuard&8] &cYou have been detected for: &6IP Blacklist."));
messageKickVerify = config.getOrSetDefault("kick-messages.rejoin", Collections.singletonList("&8[&6EpicGuard&8] &cPlease join our server &6again &cto verify that you are not a bot."));
messageKickNamecontains = config.getOrSetDefault("kick-messages.namecontains", Collections.singletonList("&8[&6EpicGuard&8] &cYou have been detected for: &6NameContains (Change nickname or contact server admin)"));
messageKickBotBehaviour = config.getOrSetDefault("kick-messages.bot-behaviour", Collections.singletonList("&8[&6EpicGuard&8] &cYou have been detected for: &6BotBehaviour (Please join again)"));

noPermission = config.getOrSetDefault("other.no-permission", "&cYou don't have permission to access this command!");
notAllowedCommand = config.getOrSetDefault("other.not-allowed-command", "&fUnknown command. Type '/help' for help.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ public class CounterTask implements Runnable {
@Override
public void run() {
this.manager.setConnectPerSecond(0);
this.manager.setDetectionsPerSecond(0);
}
}
Loading

0 comments on commit 0c9a35b

Please sign in to comment.