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.
This commit is contained in:
P0nk
2023-08-06 15:48:49 +02:00
parent e9819fac87
commit 2686b2b02d
36 changed files with 180 additions and 106 deletions

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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)) {

View File

@@ -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++) {

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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<Socket
private static final ChannelHandler sendPacketLogger = new OutPacketLogger();
private static final ChannelHandler receivePacketLogger = new InPacketLogger();
private final DisconnectHandler disconnectingInboundHandler;
static final AtomicLong sessionId = new AtomicLong(7777);
public ServerChannelInitializer(CharacterSaver characterSaver) {
this.disconnectingInboundHandler = new DisconnectHandler(characterSaver);
}
String getRemoteAddress(Channel channel) {
String remoteAddress = "null";
try {
@@ -62,6 +69,7 @@ public abstract class ServerChannelInitializer extends ChannelInitializer<Socket
pipeline.addLast("IdleStateHandler", new IdleStateHandler(0, 0, IDLE_TIME_SECONDS));
pipeline.addLast("PacketCodec", new PacketCodec(ClientCyphers.of(sendIv, recvIv)));
pipeline.addLast("Client", client);
pipeline.addLast("Disconnect", disconnectingInboundHandler);
if (LOG_PACKETS) {
pipeline.addBefore("Client", "SendPacketLogger", sendPacketLogger);

View File

@@ -367,7 +367,7 @@ public class Server {
wldRLock.unlock();
}
Channel channel = new Channel(worldid, channelid, getCurrentTime(), channelDependencies.dropProvider());
Channel channel = new Channel(worldid, channelid, getCurrentTime(), channelDependencies);
channel.setServerMessage(YamlConfig.config.worlds.get(worldid).why_am_i_recommended);
if (world.addChannel(channel)) {
@@ -440,7 +440,7 @@ public class Server {
long bootTime = getCurrentTime();
for (int j = 1; j <= YamlConfig.config.worlds.get(i).channels; j++) {
int channelid = j;
Channel channel = new Channel(i, channelid, bootTime, channelDependencies.dropProvider());
Channel channel = new Channel(i, channelid, bootTime, channelDependencies);
world.addChannel(channel);
channelInfo.put(channelid, channel.getIP());
@@ -928,7 +928,7 @@ public class Server {
}
}
loginServer = initLoginServer(8484);
loginServer = initLoginServer(8484, channelDependencies.characterSaver());
log.info("Listening on port 8484");
@@ -999,8 +999,8 @@ public class Server {
return channelDependencies;
}
private LoginServer initLoginServer(int port) {
LoginServer loginServer = new LoginServer(port);
private LoginServer initLoginServer(int port, CharacterSaver characterSaver) {
LoginServer loginServer = new LoginServer(port, characterSaver);
loginServer.start();
return loginServer;
}

View File

@@ -24,7 +24,9 @@ package net.server.channel;
import client.Character;
import config.YamlConfig;
import constants.id.MapId;
import database.character.CharacterSaver;
import database.drop.DropProvider;
import net.ChannelDependencies;
import net.netty.ChannelServer;
import net.packet.Packet;
import net.server.PlayerStorage;
@@ -109,10 +111,10 @@ public final class Channel {
private final Lock merchRlock;
private final Lock merchWlock;
public Channel(final int world, final int channel, long startTime, DropProvider dropProvider) {
public Channel(final int world, final int channel, long startTime, ChannelDependencies channelDependencies) {
this.world = world;
this.channel = channel;
this.dropProvider = dropProvider;
this.dropProvider = channelDependencies.dropProvider();
this.ongoingStartTime = startTime + 10000; // rude approach to a world's last channel boot time, placeholder for the 1st wedding reservation ever
this.mapManager = new MapManager(null, world, channel, dropProvider);
@@ -124,7 +126,7 @@ public final class Channel {
this.merchWlock = rwLock.writeLock();
try {
this.channelServer = initServer(port, world, channel);
this.channelServer = initServer(port, world, channel, channelDependencies.characterSaver());
expedType.addAll(Arrays.asList(ExpeditionType.values()));
if (Server.getInstance().isOnline()) { // postpone event loading to improve boot time... thanks Riizade, daronhudson for noticing slow startup times
@@ -152,8 +154,8 @@ public final class Channel {
}
}
private ChannelServer initServer(int port, int world, int channel) {
ChannelServer channelServer = new ChannelServer(port, world, channel);
private ChannelServer initServer(int port, int world, int channel, CharacterSaver characterSaver) {
ChannelServer channelServer = new ChannelServer(port, world, channel, characterSaver);
channelServer.start();
return channelServer;
}

View File

@@ -33,6 +33,7 @@ import config.YamlConfig;
import constants.id.ItemId;
import constants.inventory.ItemConstants;
import net.AbstractPacketHandler;
import net.netty.GameViolationException;
import net.packet.InPacket;
import net.server.Server;
import org.slf4j.Logger;
@@ -287,8 +288,7 @@ public final class CashOperationHandler extends AbstractPacketHandler {
byte invType = p.readByte();
if (invType < 1 || invType > 5) {
c.disconnect(false, false);
return;
throw GameViolationException.inventoryType(invType);
}
Inventory mi = chr.getInventory(InventoryType.getByType(invType));

View File

@@ -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;
}

View File

@@ -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();
}
}
}
}

View File

@@ -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

View File

@@ -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)) {

View File

@@ -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));
}
}
}
}

View File

@@ -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());
}
}
}

View File

@@ -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<Item> itemarray = new ArrayList<>();

View File

@@ -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));
}

View File

@@ -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");
}
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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));
}

View File

@@ -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");
}
}

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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));
}
}
}
}