From 2686b2b02d49c3afe9b813d41e39b4472e2bf451 Mon Sep 17 00:00:00 2001 From: P0nk Date: Sun, 6 Aug 2023 15:48:49 +0200 Subject: [PATCH] Disconnect client by throwing exception in handler This makes it easier to add checks in handlers, which should improve security over time. I think this approach is more readable and testable than calling Client#disconnect straight up, while it also decentralizes the handling. --- src/main/java/client/Client.java | 8 +++++- .../client/processor/npc/DueyProcessor.java | 11 ++++---- .../processor/npc/StorageProcessor.java | 7 +++-- .../processor/stat/AssignAPProcessor.java | 5 ++-- .../processor/stat/AssignSPProcessor.java | 5 ++-- src/main/java/net/netty/ChannelServer.java | 7 +++-- .../net/netty/ChannelServerInitializer.java | 4 ++- .../java/net/netty/DisconnectException.java | 16 ++++++++++++ .../java/net/netty/DisconnectHandler.java | 26 +++++++++++++++++++ .../net/netty/GameViolationException.java | 17 ++++++++++++ src/main/java/net/netty/LoginServer.java | 8 ++++-- .../net/netty/LoginServerInitializer.java | 5 ++++ .../net/netty/ServerChannelInitializer.java | 8 ++++++ src/main/java/net/server/Server.java | 10 +++---- src/main/java/net/server/channel/Channel.java | 12 +++++---- .../handlers/CashOperationHandler.java | 4 +-- .../handlers/ChangeChannelHandler.java | 4 +-- .../channel/handlers/ChangeMapHandler.java | 9 +++---- .../handlers/CloseRangeDamageHandler.java | 9 +++---- .../channel/handlers/GeneralChatHandler.java | 4 +-- .../channel/handlers/GiveFameHandler.java | 6 ++--- .../handlers/InventoryMergeHandler.java | 6 ++--- .../handlers/InventorySortHandler.java | 4 +-- .../channel/handlers/KeymapChangeHandler.java | 7 +++-- .../channel/handlers/MagicDamageHandler.java | 5 ++-- .../channel/handlers/MultiChatHandler.java | 5 ++-- .../channel/handlers/NPCShopHandler.java | 4 +-- .../channel/handlers/PetChatHandler.java | 5 ++-- .../handlers/PlayerInteractionHandler.java | 11 ++++---- .../handlers/PlayerLoggedinHandler.java | 18 +++++-------- .../channel/handlers/RangedAttackHandler.java | 5 ++-- .../handlers/RemoteGachaponHandler.java | 10 +++---- .../channel/handlers/SkillMacroHandler.java | 4 +-- .../channel/handlers/WhisperHandler.java | 4 +-- .../handlers/login/AcceptToSHandler.java | 7 ++--- .../handlers/login/CreateCharHandler.java | 6 ++--- 36 files changed, 180 insertions(+), 106 deletions(-) create mode 100644 src/main/java/net/netty/DisconnectException.java create mode 100644 src/main/java/net/netty/DisconnectHandler.java create mode 100644 src/main/java/net/netty/GameViolationException.java diff --git a/src/main/java/client/Client.java b/src/main/java/client/Client.java index a8b6aeb0e2..363d2b3b90 100644 --- a/src/main/java/client/Client.java +++ b/src/main/java/client/Client.java @@ -29,6 +29,8 @@ import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.handler.timeout.IdleStateEvent; import net.PacketHandler; import net.PacketProcessor; +import net.netty.DisconnectException; +import net.netty.GameViolationException; import net.netty.InvalidPacketHeaderException; import net.packet.InPacket; import net.packet.Packet; @@ -201,6 +203,8 @@ public class Client extends ChannelInboundHandlerAdapter { try { MonitoredChrLogger.logPacketIfMonitored(this, opcode, packet.getBytes()); handler.handlePacket(packet, this); + } catch (GameViolationException gve) { + throw new DisconnectException(this, gve.getMessage()); } catch (final Throwable t) { final String chrInfo = player != null ? player.getName() + " on map " + player.getMapId() : "?"; log.warn("Error in packet handler {}. Chr {}, account {}. Packet: {}", handler.getClass().getSimpleName(), @@ -229,6 +233,8 @@ public class Client extends ChannelInboundHandlerAdapter { SessionCoordinator.getInstance().closeSession(this, true); } else if (cause instanceof IOException) { closeMapleSession(); + } else { + ctx.fireExceptionCaught(cause); } } @@ -1018,7 +1024,7 @@ public class Client extends ChannelInboundHandlerAdapter { //getChannelServer().removePlayer(player); already being done player.cancelAllDebuffs(); - player.saveCharToDB(true); + player.saveCharToDB(); player.logOff(); if (YamlConfig.config.server.INSTANT_NAME_CHANGE) { diff --git a/src/main/java/client/processor/npc/DueyProcessor.java b/src/main/java/client/processor/npc/DueyProcessor.java index 8a8615985b..dfb11729f4 100644 --- a/src/main/java/client/processor/npc/DueyProcessor.java +++ b/src/main/java/client/processor/npc/DueyProcessor.java @@ -35,6 +35,7 @@ import client.inventory.manipulator.KarmaManipulator; import config.YamlConfig; import constants.id.ItemId; import constants.inventory.ItemConstants; +import net.netty.GameViolationException; import net.server.channel.Channel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -296,24 +297,22 @@ public class DueyProcessor { if (sendMessage != null && sendMessage.length() > 100) { AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with Quick Delivery on duey."); log.warn("Chr {} tried to use duey with too long of a text", c.getPlayer().getName()); - c.disconnect(true, false); - return; + throw GameViolationException.textLength(sendMessage); } + if (!quick) { fee += 5000; } else if (!c.getPlayer().haveItem(ItemId.QUICK_DELIVERY_TICKET)) { AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with Quick Delivery on duey."); log.warn("Chr {} tried to use duey with Quick Delivery without a ticket, mesos {} and amount {}", c.getPlayer().getName(), sendMesos, amount); - c.disconnect(true, false); - return; + throw new GameViolationException("Send Duey quick delivery without having a ticket"); } long finalcost = (long) sendMesos + fee; if (finalcost < 0 || finalcost > Integer.MAX_VALUE || (amount < 1 && sendMesos == 0)) { AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with duey."); log.warn("Chr {} tried to use duey with mesos {} and amount {}", c.getPlayer().getName(), sendMesos, amount); - c.disconnect(true, false); - return; + throw new GameViolationException("Send invalid mesos with duey"); } if(c.getPlayer().getMeso() < finalcost) { diff --git a/src/main/java/client/processor/npc/StorageProcessor.java b/src/main/java/client/processor/npc/StorageProcessor.java index 6fa24a7399..85b153163e 100644 --- a/src/main/java/client/processor/npc/StorageProcessor.java +++ b/src/main/java/client/processor/npc/StorageProcessor.java @@ -32,6 +32,7 @@ import client.inventory.manipulator.KarmaManipulator; import config.YamlConfig; import constants.id.ItemId; import constants.inventory.ItemConstants; +import net.netty.GameViolationException; import net.packet.InPacket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,8 +70,7 @@ public class StorageProcessor { if (slot < 0 || slot > storage.getSlots()) { // removal starts at zero AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with storage."); log.warn("Chr {} tried to work with storage slot {}", c.getPlayer().getName(), slot); - c.disconnect(true, false); - return; + throw new GameViolationException("Withdraw item from invalid slot"); } slot = storage.getSlot(InventoryType.getByType(type), slot); @@ -128,8 +128,7 @@ public class StorageProcessor { AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with storage."); log.warn("Chr {} tried to store item at slot {}", c.getPlayer().getName(), slot); - c.disconnect(true, false); - return; + throw new GameViolationException("Store item at invalid slot"); } if (hasGMRestrictions(chr)) { diff --git a/src/main/java/client/processor/stat/AssignAPProcessor.java b/src/main/java/client/processor/stat/AssignAPProcessor.java index 8f33ac3b55..f5915ab507 100644 --- a/src/main/java/client/processor/stat/AssignAPProcessor.java +++ b/src/main/java/client/processor/stat/AssignAPProcessor.java @@ -31,6 +31,7 @@ import client.inventory.InventoryType; import client.inventory.Item; import config.YamlConfig; import constants.skills.*; +import net.netty.GameViolationException; import net.packet.InPacket; import tools.PacketCreator; import tools.Randomizer; @@ -385,9 +386,7 @@ public class AssignAPProcessor { } else { if (inPacket.available() < 16) { AutobanFactory.PACKET_EDIT.alert(chr, "Didn't send full packet for Auto Assign."); - - c.disconnect(true, false); - return; + throw new GameViolationException("Auto Assign packet is too small"); } for (int i = 0; i < 2; i++) { diff --git a/src/main/java/client/processor/stat/AssignSPProcessor.java b/src/main/java/client/processor/stat/AssignSPProcessor.java index e3f648263f..24b2ebbb38 100644 --- a/src/main/java/client/processor/stat/AssignSPProcessor.java +++ b/src/main/java/client/processor/stat/AssignSPProcessor.java @@ -30,6 +30,7 @@ import client.SkillFactory; import client.autoban.AutobanFactory; import constants.game.GameConstants; import constants.skills.Aran; +import net.netty.GameViolationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import tools.PacketCreator; @@ -50,9 +51,7 @@ public class AssignSPProcessor { if ((!GameConstants.isPqSkillMap(player.getMapId()) && GameConstants.isPqSkill(skillid)) || (!player.isGM() && GameConstants.isGMSkills(skillid)) || (!GameConstants.isInJobTree(skillid, player.getJob().getId()) && !player.isGM())) { AutobanFactory.PACKET_EDIT.alert(player, "tried to packet edit in distributing sp."); log.warn("Chr {} tried to use skill {} without it being in their job.", c.getPlayer().getName(), skillid); - - c.disconnect(true, false); - return false; + throw new GameViolationException("Assign SP into invalid skill"); } return true; diff --git a/src/main/java/net/netty/ChannelServer.java b/src/main/java/net/netty/ChannelServer.java index cd620db608..4e10a775e6 100644 --- a/src/main/java/net/netty/ChannelServer.java +++ b/src/main/java/net/netty/ChannelServer.java @@ -1,5 +1,6 @@ package net.netty; +import database.character.CharacterSaver; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; @@ -9,12 +10,14 @@ import io.netty.channel.socket.nio.NioServerSocketChannel; public class ChannelServer extends AbstractServer { private final int world; private final int channel; + private final CharacterSaver characterSaver; private Channel nettyChannel; - public ChannelServer(int port, int world, int channel) { + public ChannelServer(int port, int world, int channel, CharacterSaver characterSaver) { super(port); this.world = world; this.channel = channel; + this.characterSaver = characterSaver; } @Override @@ -24,7 +27,7 @@ public class ChannelServer extends AbstractServer { ServerBootstrap bootstrap = new ServerBootstrap() .group(parentGroup, childGroup) .channel(NioServerSocketChannel.class) - .childHandler(new ChannelServerInitializer(world, channel)); + .childHandler(new ChannelServerInitializer(world, channel, characterSaver)); this.nettyChannel = bootstrap.bind(port).syncUninterruptibly().channel(); } diff --git a/src/main/java/net/netty/ChannelServerInitializer.java b/src/main/java/net/netty/ChannelServerInitializer.java index 0c87ed5ca3..4de7a3cfaa 100644 --- a/src/main/java/net/netty/ChannelServerInitializer.java +++ b/src/main/java/net/netty/ChannelServerInitializer.java @@ -1,6 +1,7 @@ package net.netty; import client.Client; +import database.character.CharacterSaver; import io.netty.channel.socket.SocketChannel; import net.PacketProcessor; import net.server.Server; @@ -14,7 +15,8 @@ public class ChannelServerInitializer extends ServerChannelInitializer { private final int world; private final int channel; - public ChannelServerInitializer(int world, int channel) { + public ChannelServerInitializer(int world, int channel, CharacterSaver characterSaver) { + super(characterSaver); this.world = world; this.channel = channel; } diff --git a/src/main/java/net/netty/DisconnectException.java b/src/main/java/net/netty/DisconnectException.java new file mode 100644 index 0000000000..3a840260f7 --- /dev/null +++ b/src/main/java/net/netty/DisconnectException.java @@ -0,0 +1,16 @@ +package net.netty; + +import client.Client; + +public class DisconnectException extends RuntimeException { + private final Client client; + + public DisconnectException(Client client, String message) { + super(message); + this.client = client; + } + + public Client getClient() { + return client; + } +} diff --git a/src/main/java/net/netty/DisconnectHandler.java b/src/main/java/net/netty/DisconnectHandler.java new file mode 100644 index 0000000000..2339d18cfe --- /dev/null +++ b/src/main/java/net/netty/DisconnectHandler.java @@ -0,0 +1,26 @@ +package net.netty; + +import database.character.CharacterSaver; +import io.netty.channel.ChannelHandler.Sharable; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; + +@Sharable +public class DisconnectHandler extends ChannelInboundHandlerAdapter { + private final CharacterSaver characterSaver; + + public DisconnectHandler(CharacterSaver characterSaver) { + this.characterSaver = characterSaver; + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + if (cause instanceof DisconnectException de) { + var client = de.getClient(); + client.disconnect(true, false); + } else { + ctx.fireExceptionCaught(cause); + } + } + +} diff --git a/src/main/java/net/netty/GameViolationException.java b/src/main/java/net/netty/GameViolationException.java new file mode 100644 index 0000000000..1e8c602ad8 --- /dev/null +++ b/src/main/java/net/netty/GameViolationException.java @@ -0,0 +1,17 @@ +package net.netty; + +public class GameViolationException extends RuntimeException { + + public GameViolationException(String message) { + super(message); + } + + public static GameViolationException inventoryType(int type) { + return new GameViolationException("Invalid inventory type: " + type); + } + + public static GameViolationException textLength(String text) { + int length = text != null ? text.length() : 0; + return new GameViolationException("Text too long: " + length); + } +} diff --git a/src/main/java/net/netty/LoginServer.java b/src/main/java/net/netty/LoginServer.java index a34145f3f2..131b82c4ee 100644 --- a/src/main/java/net/netty/LoginServer.java +++ b/src/main/java/net/netty/LoginServer.java @@ -1,5 +1,6 @@ package net.netty; +import database.character.CharacterSaver; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; @@ -9,10 +10,13 @@ import io.netty.channel.socket.nio.NioServerSocketChannel; public class LoginServer extends AbstractServer { public static final int WORLD_ID = -1; public static final int CHANNEL_ID = -1; + + private final CharacterSaver characterSaver; private Channel channel; - public LoginServer(int port) { + public LoginServer(int port, CharacterSaver characterSaver) { super(port); + this.characterSaver = characterSaver; } @Override @@ -22,7 +26,7 @@ public class LoginServer extends AbstractServer { ServerBootstrap bootstrap = new ServerBootstrap() .group(parentGroup, childGroup) .channel(NioServerSocketChannel.class) - .childHandler(new LoginServerInitializer()); + .childHandler(new LoginServerInitializer(characterSaver)); this.channel = bootstrap.bind(port).syncUninterruptibly().channel(); } diff --git a/src/main/java/net/netty/LoginServerInitializer.java b/src/main/java/net/netty/LoginServerInitializer.java index 621f843cc5..671c1d3ebd 100644 --- a/src/main/java/net/netty/LoginServerInitializer.java +++ b/src/main/java/net/netty/LoginServerInitializer.java @@ -1,6 +1,7 @@ package net.netty; import client.Client; +import database.character.CharacterSaver; import io.netty.channel.socket.SocketChannel; import net.PacketProcessor; import net.server.coordinator.session.SessionCoordinator; @@ -10,6 +11,10 @@ import org.slf4j.LoggerFactory; public class LoginServerInitializer extends ServerChannelInitializer { private static final Logger log = LoggerFactory.getLogger(LoginServerInitializer.class); + public LoginServerInitializer(CharacterSaver characterSaver) { + super(characterSaver); + } + @Override public void initChannel(SocketChannel socketChannel) { final String clientIp = socketChannel.remoteAddress().getHostString(); diff --git a/src/main/java/net/netty/ServerChannelInitializer.java b/src/main/java/net/netty/ServerChannelInitializer.java index 874e84d1a6..737bc39b39 100644 --- a/src/main/java/net/netty/ServerChannelInitializer.java +++ b/src/main/java/net/netty/ServerChannelInitializer.java @@ -3,6 +3,7 @@ package net.netty; import client.Client; import config.YamlConfig; import constants.net.ServerConstants; +import database.character.CharacterSaver; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; @@ -30,8 +31,14 @@ public abstract class ServerChannelInitializer extends ChannelInitializer 5) { - c.disconnect(false, false); - return; + throw GameViolationException.inventoryType(invType); } Inventory mi = chr.getInventory(InventoryType.getByType(invType)); diff --git a/src/main/java/net/server/channel/handlers/ChangeChannelHandler.java b/src/main/java/net/server/channel/handlers/ChangeChannelHandler.java index ffa92e4086..c8ee0b9cc1 100644 --- a/src/main/java/net/server/channel/handlers/ChangeChannelHandler.java +++ b/src/main/java/net/server/channel/handlers/ChangeChannelHandler.java @@ -24,6 +24,7 @@ package net.server.channel.handlers; import client.Client; import client.autoban.AutobanFactory; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import net.server.Server; import service.ChannelService; @@ -45,8 +46,7 @@ public final class ChangeChannelHandler extends AbstractPacketHandler { c.getPlayer().getAutobanManager().setTimestamp(6, Server.getInstance().getCurrentTimestamp(), 3); if (c.getChannel() == channel) { AutobanFactory.GENERAL.alert(c.getPlayer(), "CCing to same channel."); - c.disconnect(false, false); - return; + throw new GameViolationException("Change to same channel"); } else if (c.getPlayer().getCashShop().isOpened() || c.getPlayer().getMiniGame() != null || c.getPlayer().getPlayerShop() != null) { return; } diff --git a/src/main/java/net/server/channel/handlers/ChangeMapHandler.java b/src/main/java/net/server/channel/handlers/ChangeMapHandler.java index 9a8648735a..3137432669 100644 --- a/src/main/java/net/server/channel/handlers/ChangeMapHandler.java +++ b/src/main/java/net/server/channel/handlers/ChangeMapHandler.java @@ -28,6 +28,7 @@ import client.inventory.manipulator.InventoryManipulator; import constants.id.ItemId; import constants.id.MapId; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,8 +67,7 @@ public final class ChangeMapHandler extends AbstractPacketHandler { } if (chr.getCashShop().isOpened()) { - c.disconnect(false, false); - return; + throw new GameViolationException("Changing channel inside cash shop"); } try { @@ -178,8 +178,7 @@ public final class ChangeMapHandler extends AbstractPacketHandler { final Character chr = c.getPlayer(); if (!chr.getCashShop().isOpened()) { - c.disconnect(false, false); - return; + throw new GameViolationException("Enter map from cash shop, but is not in cash shop"); } String[] socket = c.getChannelServer().getIP().split(":"); chr.getCashShop().open(false); @@ -191,4 +190,4 @@ public final class ChangeMapHandler extends AbstractPacketHandler { ex.printStackTrace(); } } -} \ No newline at end of file +} diff --git a/src/main/java/net/server/channel/handlers/CloseRangeDamageHandler.java b/src/main/java/net/server/channel/handlers/CloseRangeDamageHandler.java index f374c98794..25d88b4bb8 100644 --- a/src/main/java/net/server/channel/handlers/CloseRangeDamageHandler.java +++ b/src/main/java/net/server/channel/handlers/CloseRangeDamageHandler.java @@ -28,6 +28,7 @@ import constants.game.GameConstants; import constants.id.MapId; import constants.skills.*; import database.drop.DropProvider; +import net.netty.GameViolationException; import net.packet.InPacket; import server.StatEffect; import tools.PacketCreator; @@ -56,12 +57,8 @@ public final class CloseRangeDamageHandler extends AbstractDealDamageHandler { chr.getAutobanManager().spam(8);*/ AttackInfo attack = parseDamage(p, chr, false, false); - if (chr.getBuffEffect(BuffStat.MORPH) != null) { - if (chr.getBuffEffect(BuffStat.MORPH).isMorphWithoutAttack()) { - // How are they attacking when the client won't let them? - chr.getClient().disconnect(false, false); - return; - } + if (chr.getBuffEffect(BuffStat.MORPH) != null && chr.getBuffEffect(BuffStat.MORPH).isMorphWithoutAttack()) { + throw new GameViolationException("Attempt to attack with morph skill that disallows attacking"); } if (chr.getDojoEnergy() < 10000 && (attack.skill == 1009 || attack.skill == 10001009 || attack.skill == 20001009)) // PE hacking or maybe just lagging diff --git a/src/main/java/net/server/channel/handlers/GeneralChatHandler.java b/src/main/java/net/server/channel/handlers/GeneralChatHandler.java index 71f295dbcd..2aefe6ba7c 100644 --- a/src/main/java/net/server/channel/handlers/GeneralChatHandler.java +++ b/src/main/java/net/server/channel/handlers/GeneralChatHandler.java @@ -26,6 +26,7 @@ import client.Client; import client.autoban.AutobanFactory; import client.command.CommandsExecutor; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,8 +52,7 @@ public final class GeneralChatHandler extends AbstractPacketHandler { if (s.length() > Byte.MAX_VALUE && !chr.isGM()) { AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit in General Chat."); log.warn("Chr {} tried to send text with length of {}", c.getPlayer().getName(), s.length()); - c.disconnect(true, false); - return; + throw GameViolationException.textLength(s); } char heading = s.charAt(0); if (CommandsExecutor.isCommand(c, s)) { diff --git a/src/main/java/net/server/channel/handlers/GiveFameHandler.java b/src/main/java/net/server/channel/handlers/GiveFameHandler.java index 4b1804cc5d..0ac60f2b27 100644 --- a/src/main/java/net/server/channel/handlers/GiveFameHandler.java +++ b/src/main/java/net/server/channel/handlers/GiveFameHandler.java @@ -26,6 +26,7 @@ import client.Character.FameStatus; import client.Client; import client.autoban.AutobanFactory; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,8 +46,7 @@ public final class GiveFameHandler extends AbstractPacketHandler { } else if (famechange != 1 && famechange != -1) { AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit fame."); log.warn("Chr {} tried to fame hack with famechange {}", c.getPlayer().getName(), famechange); - c.disconnect(true, false); - return; + throw new GameViolationException("Give too much fame"); } FameStatus status = player.canGiveFame(target); @@ -62,4 +62,4 @@ public final class GiveFameHandler extends AbstractPacketHandler { c.sendPacket(PacketCreator.giveFameErrorResponse(status == FameStatus.NOT_TODAY ? 3 : 4)); } } -} \ No newline at end of file +} diff --git a/src/main/java/net/server/channel/handlers/InventoryMergeHandler.java b/src/main/java/net/server/channel/handlers/InventoryMergeHandler.java index dc20cd9f0a..18fbfb0c1a 100644 --- a/src/main/java/net/server/channel/handlers/InventoryMergeHandler.java +++ b/src/main/java/net/server/channel/handlers/InventoryMergeHandler.java @@ -29,6 +29,7 @@ import client.inventory.Item; import client.inventory.manipulator.InventoryManipulator; import config.YamlConfig; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import net.server.Server; import server.ItemInformationProvider; @@ -49,8 +50,7 @@ public final class InventoryMergeHandler extends AbstractPacketHandler { byte invType = p.readByte(); if (invType < 1 || invType > 5) { - c.disconnect(false, false); - return; + throw GameViolationException.inventoryType(invType); } InventoryType inventoryType = InventoryType.getByType(invType); @@ -117,4 +117,4 @@ public final class InventoryMergeHandler extends AbstractPacketHandler { c.sendPacket(PacketCreator.finishedSort(inventoryType.getType())); c.sendPacket(PacketCreator.enableActions()); } -} \ No newline at end of file +} diff --git a/src/main/java/net/server/channel/handlers/InventorySortHandler.java b/src/main/java/net/server/channel/handlers/InventorySortHandler.java index e6721569bf..fd6298c5ac 100644 --- a/src/main/java/net/server/channel/handlers/InventorySortHandler.java +++ b/src/main/java/net/server/channel/handlers/InventorySortHandler.java @@ -26,6 +26,7 @@ import client.Client; import client.inventory.*; import config.YamlConfig; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import net.server.Server; import server.ItemInformationProvider; @@ -298,8 +299,7 @@ public final class InventorySortHandler extends AbstractPacketHandler { byte invType = p.readByte(); if (invType < 1 || invType > 5) { - c.disconnect(false, false); - return; + throw GameViolationException.inventoryType(invType); } ArrayList itemarray = new ArrayList<>(); diff --git a/src/main/java/net/server/channel/handlers/KeymapChangeHandler.java b/src/main/java/net/server/channel/handlers/KeymapChangeHandler.java index e13599cfac..4194bb62cb 100644 --- a/src/main/java/net/server/channel/handlers/KeymapChangeHandler.java +++ b/src/main/java/net/server/channel/handlers/KeymapChangeHandler.java @@ -28,6 +28,7 @@ import client.inventory.InventoryType; import client.keybind.KeyBinding; import constants.game.GameConstants; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; public final class KeymapChangeHandler extends AbstractPacketHandler { @@ -66,15 +67,13 @@ public final class KeymapChangeHandler extends AbstractPacketHandler { } else if (mode == 1) { // Auto HP Potion int itemID = p.readInt(); if (itemID != 0 && c.getPlayer().getInventory(InventoryType.USE).findById(itemID) == null) { - c.disconnect(false, false); // Don't let them send a packet with a use item they dont have. - return; + throw new GameViolationException("Set auto hp potion without owning the item"); } c.getPlayer().changeKeybinding(91, new KeyBinding(7, itemID)); } else if (mode == 2) { // Auto MP Potion int itemID = p.readInt(); if (itemID != 0 && c.getPlayer().getInventory(InventoryType.USE).findById(itemID) == null) { - c.disconnect(false, false); // Don't let them send a packet with a use item they dont have. - return; + throw new GameViolationException("Set auto mp potion without owning the item"); } c.getPlayer().changeKeybinding(92, new KeyBinding(7, itemID)); } diff --git a/src/main/java/net/server/channel/handlers/MagicDamageHandler.java b/src/main/java/net/server/channel/handlers/MagicDamageHandler.java index 714fb1cadb..f89deb82be 100644 --- a/src/main/java/net/server/channel/handlers/MagicDamageHandler.java +++ b/src/main/java/net/server/channel/handlers/MagicDamageHandler.java @@ -30,6 +30,7 @@ import constants.skills.Evan; import constants.skills.FPArchMage; import constants.skills.ILArchMage; import database.drop.DropProvider; +import net.netty.GameViolationException; import net.packet.InPacket; import net.packet.Packet; import server.StatEffect; @@ -56,9 +57,7 @@ public final class MagicDamageHandler extends AbstractDealDamageHandler { if (chr.getBuffEffect(BuffStat.MORPH) != null) { if (chr.getBuffEffect(BuffStat.MORPH).isMorphWithoutAttack()) { - // How are they attacking when the client won't let them? - chr.getClient().disconnect(false, false); - return; + throw new GameViolationException("Attempt to attack with morph skill that disallows attacking"); } } diff --git a/src/main/java/net/server/channel/handlers/MultiChatHandler.java b/src/main/java/net/server/channel/handlers/MultiChatHandler.java index 99564a36ce..bb1c930bb3 100644 --- a/src/main/java/net/server/channel/handlers/MultiChatHandler.java +++ b/src/main/java/net/server/channel/handlers/MultiChatHandler.java @@ -25,6 +25,7 @@ import client.Character; import client.Client; import client.autoban.AutobanFactory; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import net.server.Server; import net.server.world.World; @@ -53,9 +54,9 @@ public final class MultiChatHandler extends AbstractPacketHandler { if (chattext.length() > Byte.MAX_VALUE && !player.isGM()) { AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit chats."); log.warn("Chr {} tried to send text with length of {}", c.getPlayer().getName(), chattext.length()); - c.disconnect(true, false); - return; + throw GameViolationException.textLength(chattext); } + World world = c.getWorldServer(); if (type == 0) { world.buddyChat(recipients, player.getId(), player.getName(), chattext); diff --git a/src/main/java/net/server/channel/handlers/NPCShopHandler.java b/src/main/java/net/server/channel/handlers/NPCShopHandler.java index 6d92169d74..a98e85b413 100644 --- a/src/main/java/net/server/channel/handlers/NPCShopHandler.java +++ b/src/main/java/net/server/channel/handlers/NPCShopHandler.java @@ -25,6 +25,7 @@ import client.Client; import client.autoban.AutobanFactory; import constants.inventory.ItemConstants; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,8 +48,7 @@ public final class NPCShopHandler extends AbstractPacketHandler { AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit a npc shop."); log.warn("Chr {} tried to buy quantity {} of itemid {}", c.getPlayer().getName(), quantity, itemId); - c.disconnect(true, false); - return; + throw new GameViolationException("Buy invalid amount of items"); } c.getPlayer().getShop().buy(c, slot, itemId, quantity); break; diff --git a/src/main/java/net/server/channel/handlers/PetChatHandler.java b/src/main/java/net/server/channel/handlers/PetChatHandler.java index b4863ae962..a6e66c62c8 100644 --- a/src/main/java/net/server/channel/handlers/PetChatHandler.java +++ b/src/main/java/net/server/channel/handlers/PetChatHandler.java @@ -24,6 +24,7 @@ package net.server.channel.handlers; import client.Client; import client.autoban.AutobanFactory; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,9 +48,9 @@ public final class PetChatHandler extends AbstractPacketHandler { if (text.length() > Byte.MAX_VALUE) { AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with pets."); log.warn("Chr {} tried to send text with length of {}", c.getPlayer().getName(), text.length()); - c.disconnect(true, false); - return; + throw GameViolationException.textLength(text); } + c.getPlayer().getMap().broadcastMessage(c.getPlayer(), PacketCreator.petChat(c.getPlayer().getId(), pet, act, text), true); ChatLogger.log(c, "Pet", text); } diff --git a/src/main/java/net/server/channel/handlers/PlayerInteractionHandler.java b/src/main/java/net/server/channel/handlers/PlayerInteractionHandler.java index dfdd2983fe..e7e729256b 100644 --- a/src/main/java/net/server/channel/handlers/PlayerInteractionHandler.java +++ b/src/main/java/net/server/channel/handlers/PlayerInteractionHandler.java @@ -35,6 +35,7 @@ import constants.id.ItemId; import constants.inventory.ItemConstants; import database.character.CharacterSaver; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -674,8 +675,7 @@ public final class PlayerInteractionHandler extends AbstractPacketHandler { if (slot >= shop.getItems().size() || slot < 0) { AutobanFactory.PACKET_EDIT.alert(chr, chr.getName() + " tried to packet edit with a player shop."); log.warn("Chr {} tried to remove item at slot {}", chr.getName(), slot); - c.disconnect(true, false); - return; + throw new GameViolationException("Remove item from invalid slot in shop"); } shop.takeItemBack(slot, chr); @@ -740,9 +740,9 @@ public final class PlayerInteractionHandler extends AbstractPacketHandler { if (quantity < 1) { AutobanFactory.PACKET_EDIT.alert(chr, chr.getName() + " tried to packet edit with a hired merchant and or player shop."); log.warn("Chr {} tried to buy item {} with quantity {}", chr.getName(), itemid, quantity); - c.disconnect(true, false); - return; + throw new GameViolationException("Buy item with invalid quantity"); } + PlayerShop shop = chr.getPlayerShop(); HiredMerchant merchant = chr.getHiredMerchant(); if (shop != null && shop.isVisitor(chr)) { @@ -769,8 +769,7 @@ public final class PlayerInteractionHandler extends AbstractPacketHandler { if (slot >= merchant.getItems().size() || slot < 0) { AutobanFactory.PACKET_EDIT.alert(chr, chr.getName() + " tried to packet edit with a hired merchant."); log.warn("Chr {} tried to remove item at slot {}", chr.getName(), slot); - c.disconnect(true, false); - return; + throw new GameViolationException("Withdraw item from merchant with invalid slot"); } merchant.takeItemBack(slot, chr, chrSaver); diff --git a/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java b/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java index 23e55e150c..f378131c88 100644 --- a/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java +++ b/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java @@ -29,6 +29,7 @@ import config.YamlConfig; import constants.game.GameConstants; import database.character.CharacterLoader; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import net.server.PlayerBuffValueHolder; import net.server.Server; @@ -108,8 +109,7 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler { try { World wserv = server.getWorld(c.getWorld()); if (wserv == null) { - c.disconnect(true, false); - return; + throw new GameViolationException("World not found"); } Channel cserv = wserv.getChannel(c.getChannel()); @@ -118,8 +118,7 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler { cserv = wserv.getChannel(c.getChannel()); if (cserv == null) { - c.disconnect(true, false); - return; + throw new GameViolationException("Channel not found"); } } @@ -129,8 +128,7 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler { if (player == null) { hwid = SessionCoordinator.getInstance().pickLoginSessionHwid(c); if (hwid == null) { - c.disconnect(true, false); - return; + throw new GameViolationException("Unable to pick hwid"); } } else { hwid = player.getClient().getHwid(); @@ -139,8 +137,7 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler { c.setHwid(hwid); if (!server.validateCharacteridInTransition(c, chrId)) { - c.disconnect(true, false); - return; + throw new GameViolationException("Attempt to enter game without chr id in transition"); } boolean newcomer = false; @@ -150,8 +147,7 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler { player = loadedChr.get(); newcomer = true; } else { - c.disconnect(true, false); - return; + throw new GameViolationException("Unable to load chr"); } } c.setPlayer(player); @@ -184,7 +180,7 @@ public final class PlayerLoggedinHandler extends AbstractPacketHandler { c.setAccID(0); if (state == Client.LOGIN_LOGGEDIN) { - c.disconnect(true, false); + throw new GameViolationException("Attempt to log in when already logged in"); } else { c.sendPacket(PacketCreator.getAfterLoginError(7)); } diff --git a/src/main/java/net/server/channel/handlers/RangedAttackHandler.java b/src/main/java/net/server/channel/handlers/RangedAttackHandler.java index 9018383116..fd26177603 100644 --- a/src/main/java/net/server/channel/handlers/RangedAttackHandler.java +++ b/src/main/java/net/server/channel/handlers/RangedAttackHandler.java @@ -34,6 +34,7 @@ import constants.id.MapId; import constants.inventory.ItemConstants; import constants.skills.*; import database.drop.DropProvider; +import net.netty.GameViolationException; import net.packet.InPacket; import net.packet.Packet; import org.slf4j.Logger; @@ -67,9 +68,7 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler { if (chr.getBuffEffect(BuffStat.MORPH) != null) { if (chr.getBuffEffect(BuffStat.MORPH).isMorphWithoutAttack()) { - // How are they attacking when the client won't let them? - chr.getClient().disconnect(false, false); - return; + throw new GameViolationException("Attempt to attack with morph skill that disallows attacking"); } } diff --git a/src/main/java/net/server/channel/handlers/RemoteGachaponHandler.java b/src/main/java/net/server/channel/handlers/RemoteGachaponHandler.java index dcdfe4e2ae..73c1e127ce 100644 --- a/src/main/java/net/server/channel/handlers/RemoteGachaponHandler.java +++ b/src/main/java/net/server/channel/handlers/RemoteGachaponHandler.java @@ -27,6 +27,7 @@ import constants.id.ItemId; import constants.id.NpcId; import constants.inventory.ItemConstants; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import scripting.npc.NPCScriptManager; @@ -40,16 +41,13 @@ public final class RemoteGachaponHandler extends AbstractPacketHandler { int gacha = p.readInt(); if (ticket != ItemId.REMOTE_GACHAPON_TICKET) { AutobanFactory.GENERAL.alert(c.getPlayer(), " Tried to use RemoteGachaponHandler with item id: " + ticket); - c.disconnect(false, false); - return; + throw new GameViolationException("Use Remote gachapon without owning the item"); } else if (gacha < 0 || gacha > 11) { AutobanFactory.GENERAL.alert(c.getPlayer(), " Tried to use RemoteGachaponHandler with mode: " + gacha); - c.disconnect(false, false); - return; + throw new GameViolationException("Use Remote gachapon with invalid mode"); } else if (c.getPlayer().getInventory(ItemConstants.getInventoryType(ticket)).countById(ticket) < 1) { AutobanFactory.GENERAL.alert(c.getPlayer(), " Tried to use RemoteGachaponHandler without a ticket."); - c.disconnect(false, false); - return; + throw new GameViolationException("Use Remote gachapon without a ticket"); } int npcId = NpcId.GACHAPON_HENESYS; if (gacha != 8 && gacha != 9) { diff --git a/src/main/java/net/server/channel/handlers/SkillMacroHandler.java b/src/main/java/net/server/channel/handlers/SkillMacroHandler.java index c8adafdd8e..454bfe8989 100644 --- a/src/main/java/net/server/channel/handlers/SkillMacroHandler.java +++ b/src/main/java/net/server/channel/handlers/SkillMacroHandler.java @@ -26,6 +26,7 @@ import client.Client; import client.SkillMacro; import client.autoban.AutobanFactory; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; public final class SkillMacroHandler extends AbstractPacketHandler { @@ -42,8 +43,7 @@ public final class SkillMacroHandler extends AbstractPacketHandler { String name = p.readString(); if (name.length() > 12) { AutobanFactory.PACKET_EDIT.alert(chr, "Invalid name length " + name + " (" + name.length() + ") for skill macro."); - c.disconnect(false, false); - break; + throw GameViolationException.textLength(name); } int shout = p.readByte(); diff --git a/src/main/java/net/server/channel/handlers/WhisperHandler.java b/src/main/java/net/server/channel/handlers/WhisperHandler.java index 9b0b743e2d..eb7960a044 100644 --- a/src/main/java/net/server/channel/handlers/WhisperHandler.java +++ b/src/main/java/net/server/channel/handlers/WhisperHandler.java @@ -25,6 +25,7 @@ import client.Character; import client.Client; import client.autoban.AutobanFactory; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -96,8 +97,7 @@ public final class WhisperHandler extends AbstractPacketHandler { if (message.length() > Byte.MAX_VALUE) { AutobanFactory.PACKET_EDIT.alert(user, user.getName() + " tried to packet edit with whispers."); log.warn("Chr {} tried to send text with length of {}", user.getName(), message.length()); - user.getClient().disconnect(true, false); - return; + throw GameViolationException.textLength(message); } ChatLogger.log(user.getClient(), "Whisper To " + target.getName(), message); diff --git a/src/main/java/net/server/handlers/login/AcceptToSHandler.java b/src/main/java/net/server/handlers/login/AcceptToSHandler.java index 4f44319da3..c00171ca0c 100644 --- a/src/main/java/net/server/handlers/login/AcceptToSHandler.java +++ b/src/main/java/net/server/handlers/login/AcceptToSHandler.java @@ -2,6 +2,7 @@ package net.server.handlers.login; import client.Client; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import tools.PacketCreator; @@ -16,11 +17,11 @@ public final class AcceptToSHandler extends AbstractPacketHandler { } @Override - public final void handlePacket(InPacket p, Client c) { + public void handlePacket(InPacket p, Client c) { if (p.available() == 0 || p.readByte() != 1 || c.acceptToS()) { - c.disconnect(false, false);//Client dc's but just because I am cool I do this (: - return; + throw new GameViolationException("ToS not accepted"); } + if (c.finishLogin() == 0) { c.sendPacket(PacketCreator.getAuthSuccess(c)); } else { diff --git a/src/main/java/net/server/handlers/login/CreateCharHandler.java b/src/main/java/net/server/handlers/login/CreateCharHandler.java index 9a62af04ed..dd511d5618 100644 --- a/src/main/java/net/server/handlers/login/CreateCharHandler.java +++ b/src/main/java/net/server/handlers/login/CreateCharHandler.java @@ -27,6 +27,7 @@ import client.creator.novice.LegendCreator; import client.creator.novice.NoblesseCreator; import constants.id.ItemId; import net.AbstractPacketHandler; +import net.netty.GameViolationException; import net.packet.InPacket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -80,8 +81,7 @@ public final class CreateCharHandler extends AbstractPacketHandler { for (int item : items) { if (!isLegal(item)) { log.warn("Owner from account {} tried to packet edit in chr creation", c.getAccountName()); - c.disconnect(true, false); - return; + throw new GameViolationException("Create character with invalid equip"); } } @@ -105,4 +105,4 @@ public final class CreateCharHandler extends AbstractPacketHandler { c.sendPacket(PacketCreator.deleteCharResponse(0, 9)); } } -} \ No newline at end of file +}