Compare commits

...

7 Commits

Author SHA1 Message Date
9249c1ea8c Fix equality null test 2022-07-28 13:30:42 +02:00
fd33523189 Perform equality check 2022-07-28 13:25:13 +02:00
5af43170da Try to skip filtering 2022-07-28 13:16:25 +02:00
eb51f0c83c Debug sending fake packet out 2022-07-28 13:05:46 +02:00
5bdf2f4c9e Move debug message up 2022-07-27 15:08:03 +02:00
155c98d601 Fix using asynchronous manager in synchronous mode 2022-07-27 14:56:59 +02:00
a8f3155fc5 Add experimental synchronous processing 2022-07-27 14:56:59 +02:00
5 changed files with 65 additions and 46 deletions

View File

@ -25,7 +25,6 @@
*/ */
package com.github.games647.fastlogin.bukkit; package com.github.games647.fastlogin.bukkit;
import com.comphenix.protocol.ProtocolLibrary;
import com.github.games647.fastlogin.bukkit.command.CrackedCommand; import com.github.games647.fastlogin.bukkit.command.CrackedCommand;
import com.github.games647.fastlogin.bukkit.command.PremiumCommand; import com.github.games647.fastlogin.bukkit.command.PremiumCommand;
import com.github.games647.fastlogin.bukkit.listener.ConnectionListener; import com.github.games647.fastlogin.bukkit.listener.ConnectionListener;
@ -164,9 +163,9 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
} else { } else {
logger.warn("We have detected that you are running FastLogin alongside Floodgate and ProtocolLib."); logger.warn("We have detected that you are running FastLogin alongside Floodgate and ProtocolLib.");
logger.warn("Currently there is an issue with FastLogin that prevents Floodgate name prefixes from " logger.warn("Currently there is an issue with FastLogin that prevents Floodgate name prefixes from "
+ "showing up when it is together used with ProtocolLib."); + "showing up when it is together used with ProtocolLib.");
logger.warn("If you would like to use Floodgate name prefixes, you can enable an experimental " logger.warn("If you would like to use Floodgate name prefixes, you can enable an experimental "
+ "workaround by changing the value 'floodgatePrefixWorkaround' to true in config.yml."); + "workaround by changing the value 'floodgatePrefixWorkaround' to true in config.yml.");
logger.warn("For more information visit https://github.com/games647/FastLogin/issues/493"); logger.warn("For more information visit https://github.com/games647/FastLogin/issues/493");
} }
} }
@ -208,9 +207,9 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
} }
} }
if (isPluginInstalled("ProtocolLib")) { // if (isPluginInstalled("ProtocolLib")) {
ProtocolLibrary.getProtocolManager().getAsynchronousManager().unregisterAsyncHandlers(this); // ProtocolLibrary.getProtocolManager().getAsynchronousManager().unregisterAsyncHandlers(this);
} // }
} }
public FastLoginCore<Player, CommandSender, FastLoginBukkit> getCore() { public FastLoginCore<Player, CommandSender, FastLoginBukkit> getCore() {

View File

@ -25,7 +25,6 @@
*/ */
package com.github.games647.fastlogin.bukkit.listener.protocollib; package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
@ -62,10 +61,10 @@ public class ManualNameChange extends PacketAdapter {
public static void register(FastLoginBukkit plugin, FloodgateService floodgate) { public static void register(FastLoginBukkit plugin, FloodgateService floodgate) {
// they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError // they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError
ProtocolLibrary.getProtocolManager() // ProtocolLibrary.getProtocolManager()
.getAsynchronousManager() // .getAsynchronousManager()
.registerAsyncHandler(new ManualNameChange(plugin, floodgate)) // .registerAsyncHandler(new ManualNameChange(plugin, floodgate))
.start(); // .start();
} }
@Override @Override

View File

@ -25,7 +25,6 @@
*/ */
package com.github.games647.fastlogin.bukkit.listener.protocollib; package com.github.games647.fastlogin.bukkit.listener.protocollib;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.github.games647.fastlogin.bukkit.BukkitLoginSession; import com.github.games647.fastlogin.bukkit.BukkitLoginSession;
import com.github.games647.fastlogin.bukkit.FastLoginBukkit; import com.github.games647.fastlogin.bukkit.FastLoginBukkit;
@ -42,7 +41,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class NameCheckTask extends JoinManagement<Player, CommandSender, ProtocolLibLoginSource> public class NameCheckTask extends JoinManagement<Player, CommandSender, ProtocolLibLoginSource>
implements Runnable { implements Runnable {
private final FastLoginBukkit plugin; private final FastLoginBukkit plugin;
private final PacketEvent packetEvent; private final PacketEvent packetEvent;
@ -70,11 +69,11 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
@Override @Override
public void run() { public void run() {
try { // try {
super.onLogin(username, new ProtocolLibLoginSource(player, random, serverKey, clientKey)); super.onLogin(username, new ProtocolLibLoginSource(player, random, serverKey, clientKey));
} finally { // } finally {
ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent); // ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent);
} // }
} }
@Override @Override
@ -106,9 +105,9 @@ public class NameCheckTask extends JoinManagement<Player, CommandSender, Protoco
BukkitLoginSession playerSession = new BukkitLoginSession(username, verify, clientKey, registered, profile); BukkitLoginSession playerSession = new BukkitLoginSession(username, verify, clientKey, registered, profile);
plugin.putSession(player.getAddress(), playerSession); plugin.putSession(player.getAddress(), playerSession);
//cancel only if the player has a paid account otherwise login as normal offline player //cancel only if the player has a paid account otherwise login as normal offline player
synchronized (packetEvent.getAsyncMarker().getProcessingLock()) { // synchronized (packetEvent.getAsyncMarker().getProcessingLock()) {
packetEvent.setCancelled(true); packetEvent.setCancelled(true);
} // }
} }
@Override @Override

View File

@ -50,6 +50,7 @@ import java.security.PublicKey;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.SignatureException; import java.security.SignatureException;
import java.time.Instant; import java.time.Instant;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;
@ -58,6 +59,7 @@ import javax.crypto.NoSuchPaddingException;
import lombok.var; import lombok.var;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import static com.comphenix.protocol.PacketType.Login.Client.ENCRYPTION_BEGIN; import static com.comphenix.protocol.PacketType.Login.Client.ENCRYPTION_BEGIN;
import static com.comphenix.protocol.PacketType.Login.Client.START; import static com.comphenix.protocol.PacketType.Login.Client.START;
@ -75,12 +77,14 @@ public class ProtocolLibListener extends PacketAdapter {
private final boolean verifyClientKeys; private final boolean verifyClientKeys;
@Nullable
private PacketContainer lastStartPacket;
public ProtocolLibListener(FastLoginBukkit plugin, AntiBotService antiBotService, boolean verifyClientKeys) { public ProtocolLibListener(FastLoginBukkit plugin, AntiBotService antiBotService, boolean verifyClientKeys) {
//run async in order to not block the server, because we are making api calls to Mojang //run async in order to not block the server, because we are making api calls to Mojang
super(params() super(params()
.plugin(plugin) .plugin(plugin)
.types(START, ENCRYPTION_BEGIN) .types(START, ENCRYPTION_BEGIN));
.optionAsync());
this.plugin = plugin; this.plugin = plugin;
this.antiBotService = antiBotService; this.antiBotService = antiBotService;
@ -91,13 +95,30 @@ public class ProtocolLibListener extends PacketAdapter {
// they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError // they will be created with a static builder, because otherwise it will throw a NoClassDefFoundError
// TODO: make synchronous processing, but do web or database requests async // TODO: make synchronous processing, but do web or database requests async
ProtocolLibrary.getProtocolManager() ProtocolLibrary.getProtocolManager()
.getAsynchronousManager() .addPacketListener(new ProtocolLibListener(plugin, antiBotService, verifyClientKeys));
.registerAsyncHandler(new ProtocolLibListener(plugin, antiBotService, verifyClientKeys))
.start();
} }
@Override @Override
public void onPacketReceiving(PacketEvent packetEvent) { public void onPacketReceiving(PacketEvent packetEvent) {
PacketContainer packet = packetEvent.getPacket();
plugin.getLog().info("New packet {} from {}; Cancellation: {}, Meta: {}",
packetEvent.getPacketType(), packetEvent.getPlayer(), packetEvent.isCancelled(),
packet.getMeta(SOURCE_META_KEY)
);
if (packetEvent.getPacketType() == START) {
if (lastStartPacket != null) {
plugin.getLog().info("Start-packet equality (Last/New): {}/{}, {}",
lastStartPacket.getHandle().hashCode(), packet.getHandle().hashCode(),
Objects.equals(lastStartPacket.getHandle(), packet.getHandle())
);
plugin.getLog().info("Content: {}, {}", lastStartPacket.getHandle(), packet.getHandle());
}
lastStartPacket = packet;
}
if (packetEvent.isCancelled() if (packetEvent.isCancelled()
|| plugin.getCore().getAuthPluginHook() == null || plugin.getCore().getAuthPluginHook() == null
|| !plugin.isServerFullyStarted()) { || !plugin.isServerFullyStarted()) {
@ -109,12 +130,10 @@ public class ProtocolLibListener extends PacketAdapter {
return; return;
} }
plugin.getLog().info("New packet {} from {}", packetEvent.getPacketType(), packetEvent.getPlayer());
Player sender = packetEvent.getPlayer(); Player sender = packetEvent.getPlayer();
PacketType packetType = packetEvent.getPacketType(); PacketType packetType = packetEvent.getPacketType();
if (packetType == START) { if (packetType == START) {
PacketContainer packet = packetEvent.getPacket(); // PacketContainer packet = packet;
InetSocketAddress address = sender.getAddress(); InetSocketAddress address = sender.getAddress();
String username = getUsername(packet); String username = getUsername(packet);
@ -155,12 +174,13 @@ public class ProtocolLibListener extends PacketAdapter {
} else { } else {
byte[] expectedVerifyToken = session.getVerifyToken(); byte[] expectedVerifyToken = session.getVerifyToken();
if (verifyNonce(sender, packetEvent.getPacket(), session.getClientPublicKey(), expectedVerifyToken)) { if (verifyNonce(sender, packetEvent.getPacket(), session.getClientPublicKey(), expectedVerifyToken)) {
packetEvent.getAsyncMarker().incrementProcessingDelay(); // packetEvent.getAsyncMarker().incrementProcessingDelay();
Runnable verifyTask = new VerifyResponseTask( Runnable verifyTask = new VerifyResponseTask(
plugin, packetEvent, sender, session, sharedSecret, keyPair plugin, packetEvent, sender, session, sharedSecret, keyPair
); );
plugin.getScheduler().runAsync(verifyTask); verifyTask.run();
// plugin.getScheduler().runAsync(verifyTask);
} else { } else {
sender.kickPlayer(plugin.getCore().getMessage("invalid-verify-token")); sender.kickPlayer(plugin.getCore().getMessage("invalid-verify-token"));
} }
@ -232,11 +252,12 @@ public class ProtocolLibListener extends PacketAdapter {
plugin.getLog().trace("GameProfile {} with {} connecting", sessionKey, username); plugin.getLog().trace("GameProfile {} with {} connecting", sessionKey, username);
packetEvent.getAsyncMarker().incrementProcessingDelay(); // packetEvent.getAsyncMarker().incrementProcessingDelay();
Runnable nameCheckTask = new NameCheckTask( Runnable nameCheckTask = new NameCheckTask(
plugin, random, player, packetEvent, username, clientKey.orElse(null), keyPair.getPublic() plugin, random, player, packetEvent, username, clientKey.orElse(null), keyPair.getPublic()
); );
plugin.getScheduler().runAsync(nameCheckTask); // plugin.getScheduler().runAsync(nameCheckTask);
nameCheckTask.run();
} }
private Optional<ClientPublicKey> verifyPublicKey(WrappedProfileKeyData profileKey) { private Optional<ClientPublicKey> verifyPublicKey(WrappedProfileKeyData profileKey) {

View File

@ -74,7 +74,7 @@ public class VerifyResponseTask implements Runnable {
static { static {
ENCRYPTION_CLASS = MinecraftReflection.getMinecraftClass( ENCRYPTION_CLASS = MinecraftReflection.getMinecraftClass(
"util." + ENCRYPTION_CLASS_NAME, ENCRYPTION_CLASS_NAME "util." + ENCRYPTION_CLASS_NAME, ENCRYPTION_CLASS_NAME
); );
} }
@ -108,11 +108,11 @@ public class VerifyResponseTask implements Runnable {
verifyResponse(session); verifyResponse(session);
} finally { } finally {
//this is a fake packet; it shouldn't be sent to the server //this is a fake packet; it shouldn't be sent to the server
synchronized (packetEvent.getAsyncMarker().getProcessingLock()) { // synchronized (packetEvent.getAsyncMarker().getProcessingLock()) {
packetEvent.setCancelled(true); packetEvent.setCancelled(true);
} // }
ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent); // ProtocolLibrary.getProtocolManager().getAsynchronousManager().signalPacketTransmission(packetEvent);
} }
} }
@ -149,9 +149,9 @@ public class VerifyResponseTask implements Runnable {
} else { } else {
//user tried to fake an authentication //user tried to fake an authentication
disconnect( disconnect(
"invalid-session", "invalid-session",
"GameProfile {} ({}) tried to log in with an invalid session. ServerId: {}", "GameProfile {} ({}) tried to log in with an invalid session. ServerId: {}",
session.getRequestUsername(), socketAddress, serverId session.getRequestUsername(), socketAddress, serverId
); );
} }
} catch (IOException ioEx) { } catch (IOException ioEx) {
@ -196,7 +196,7 @@ public class VerifyResponseTask implements Runnable {
} }
//try to get the networkManager from ProtocolLib //try to get the networkManager from ProtocolLib
private Object getNetworkManager() throws IllegalAccessException, ClassNotFoundException { private Object getNetworkManager() throws ClassNotFoundException {
Object injectorContainer = TemporaryPlayerFactory.getInjectorFromPlayer(player); Object injectorContainer = TemporaryPlayerFactory.getInjectorFromPlayer(player);
// ChannelInjector // ChannelInjector
@ -217,15 +217,15 @@ public class VerifyResponseTask implements Runnable {
try { try {
// Try to get the old (pre MC 1.16.4) encryption method // Try to get the old (pre MC 1.16.4) encryption method
encryptMethod = FuzzyReflection.fromClass(networkManagerClass) encryptMethod = FuzzyReflection.fromClass(networkManagerClass)
.getMethodByParameters("a", SecretKey.class); .getMethodByParameters("a", SecretKey.class);
} catch (IllegalArgumentException exception) { } catch (IllegalArgumentException exception) {
// Get the new encryption method // Get the new encryption method
encryptMethod = FuzzyReflection.fromClass(networkManagerClass) encryptMethod = FuzzyReflection.fromClass(networkManagerClass)
.getMethodByParameters("a", Cipher.class, Cipher.class); .getMethodByParameters("a", Cipher.class, Cipher.class);
// Get the needed Cipher helper method (used to generate ciphers from login key) // Get the needed Cipher helper method (used to generate ciphers from login key)
cipherMethod = FuzzyReflection.fromClass(ENCRYPTION_CLASS) cipherMethod = FuzzyReflection.fromClass(ENCRYPTION_CLASS)
.getMethodByParameters("a", int.class, Key.class); .getMethodByParameters("a", int.class, Key.class);
} }
} }
@ -277,7 +277,7 @@ public class VerifyResponseTask implements Runnable {
EquivalentConverter<WrappedProfileKeyData> converter = BukkitConverters.getWrappedPublicKeyDataConverter(); EquivalentConverter<WrappedProfileKeyData> converter = BukkitConverters.getWrappedPublicKeyDataConverter();
val wrappedKey = Optional.ofNullable(clientKey).map(key -> val wrappedKey = Optional.ofNullable(clientKey).map(key ->
new WrappedProfileKeyData(clientKey.expiry(), clientKey.key(), clientKey.signature()) new WrappedProfileKeyData(clientKey.expiry(), clientKey.key(), clientKey.signature())
); );
startPacket.getOptionals(converter).write(0, wrappedKey); startPacket.getOptionals(converter).write(0, wrappedKey);
@ -290,5 +290,6 @@ public class VerifyResponseTask implements Runnable {
//we don't want to handle our own packets so ignore filters //we don't want to handle our own packets so ignore filters
startPacket.setMeta(ProtocolLibListener.SOURCE_META_KEY, plugin.getName()); startPacket.setMeta(ProtocolLibListener.SOURCE_META_KEY, plugin.getName());
ProtocolLibrary.getProtocolManager().receiveClientPacket(player, startPacket, true); ProtocolLibrary.getProtocolManager().receiveClientPacket(player, startPacket, true);
plugin.getLog().info("Sending new fake login start packet to {}-{}", player, username);
} }
} }