8 Commits
25 changed files with 338 additions and 81 deletions

No files matched your search

+4 -1
View File
@@ -10,4 +10,7 @@ build/
.gradle/
gradle/
gradlew
gradlew.bat
gradlew.bat
libs/
+1
View File
@@ -28,6 +28,7 @@ See [Contact](https://tcpshield.com/#contact)
These wonderful contributors have helped TCPShield make this plugin better!
* [Dylan Keir](https://github.com/DylanKeir)
* [Paul Zhang](https://github.com/paulzhng)
* [RyanDeLap](https://github.com/RyanDeLap)
* [PlumpOrange](https://github.com/xPlumpOrange/)
+8 -8
View File
@@ -5,7 +5,6 @@ import org.yaml.snakeyaml.Yaml
import java.nio.charset.StandardCharsets
// --
// Building
// --
@@ -24,15 +23,13 @@ plugins {
id 'idea'
}
// --
// Variables
// --
version = '2.5.2'
version = '2.5.5'
group = 'net.tcpshield.tcpshield'
archivesBaseName = 'TCPShield'
// --
// Misc.
// --
@@ -63,11 +60,11 @@ sourceSets {
}
compileJava {
sourceCompatibility = targetCompatibility = '11' // Will switch to Java 16 in a future release
sourceCompatibility = "8"
targetCompatibility = "8"
options.encoding = 'UTF-8'
}
// --
// Dependencies
// --
@@ -90,10 +87,12 @@ repositories {
maven {
url = 'https://repo.velocitypowered.com/snapshots/'
}
maven {
url = "https://repo.opencollab.dev/maven-snapshots/"
}
}
dependencies {
// Bukkit
compileOnly group: 'org.spigotmc', name: 'spigot-api', version: '1.11-R0.1-SNAPSHOT'
compileOnly group: 'com.comphenix.protocol', name: 'ProtocolLib', version: '4.4.0'
@@ -110,6 +109,7 @@ dependencies {
// Testing
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.7.0-M1'
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.7.0-M1'
compileOnly 'org.geysermc.floodgate:api:2.0-SNAPSHOT'
}
processResources {
@@ -175,4 +175,4 @@ void updateJsons() {
}
}
build.dependsOn updateVersion
build.dependsOn updateVersion
@@ -1,11 +1,13 @@
package net.tcpshield.tcpshield;
import net.tcpshield.tcpshield.geyser.GeyserUtils;
import net.tcpshield.tcpshield.provider.PacketProvider;
import net.tcpshield.tcpshield.provider.PlayerProvider;
import net.tcpshield.tcpshield.util.exception.parse.InvalidPayloadException;
import net.tcpshield.tcpshield.util.exception.parse.SignatureValidationException;
import net.tcpshield.tcpshield.util.exception.parse.TimestampValidationException;
import net.tcpshield.tcpshield.util.exception.phase.HandshakeException;
import net.tcpshield.tcpshield.util.exception.phase.InvalidSecretException;
import net.tcpshield.tcpshield.util.validation.SignatureValidator;
import net.tcpshield.tcpshield.util.validation.cidr.CIDRValidator;
import net.tcpshield.tcpshield.util.validation.timestamp.TimestampValidator;
@@ -17,6 +19,7 @@ import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
/**
* Packet handler for TCPShield's plugins
@@ -31,6 +34,7 @@ public class TCPShieldPacketHandler {
/**
* Creates an instance of the TCPShieldPacketHandler
*
* @param plugin The TCPShield plugin
*/
public TCPShieldPacketHandler(TCPShieldPlugin plugin) throws NoSuchAlgorithmException, IOException, InvalidKeySpecException {
@@ -39,12 +43,12 @@ public class TCPShieldPacketHandler {
initValidators();
}
/**
* Initiates the validators
*
* @throws NoSuchAlgorithmException SignatureValidator exception
* @throws IOException SignatureValidator exception
* @throws InvalidKeySpecException SignatureValidator exception
* @throws IOException SignatureValidator exception
* @throws InvalidKeySpecException SignatureValidator exception
*/
private void initValidators() throws NoSuchAlgorithmException, IOException, InvalidKeySpecException {
signatureValidator = new SignatureValidator();
@@ -78,6 +82,7 @@ public class TCPShieldPacketHandler {
* Handles the packet and player manipulation
* for the initial handshake from TCPShield
* servers
*
* @param packet The handshake packet
* @param player The involved player
*/
@@ -86,43 +91,57 @@ public class TCPShieldPacketHandler {
InetAddress inetAddress = InetAddress.getByName(player.getIP());
String extraData = null;
String cleanedPayload;
int nullIndex;
if ((nullIndex = packet.getPayloadString().indexOf('\0')) != -1) { // FML tagged payload
cleanedPayload = packet.getPayloadString().substring(0, nullIndex);
extraData = packet.getPayloadString().substring(nullIndex);
} else // Standard payload
cleanedPayload = packet.getPayloadString();
String[] payload = cleanedPayload.split("///", 4);
String[] payload = packet.getPayloadString().split("///");
if (payload.length != 4)
if (cidrValidator.validate(inetAddress))
return; // Allow connection with no processing
else
throw new InvalidPayloadException();
throw new InvalidPayloadException("length: " + payload.length + ", payload: " + Arrays.toString(payload) + ", raw payload: " + packet.getPayloadString());
int nullIndex;
if ((nullIndex = payload[3].indexOf('\0')) != -1) { // FML tagged payload
String originalData = payload[3];
payload[3] = originalData.substring(0, nullIndex);
extraData = originalData.substring(nullIndex);
}
String hostname = payload[0];
String ipData = payload[1];
int timestamp = Integer.parseInt(payload[2]);
String signature = payload[3];
if (!timestampValidator.validate(timestamp))
throw new TimestampValidationException(timestampValidator, timestamp);
String[] ipParts;
String host;
int port;
if (timestamp == 0 && GeyserUtils.GEYSER_SUPPORT_ENABLED) {
// Remap the altered layout
ipData = payload[0];
signature = payload[1];
hostname = payload[3];
// This is annoying having to have this in both blocks but w/e
ipParts = ipData.split(":");
host = ipParts[0];
port = Integer.parseInt(ipParts[1]);
if (!signature.equals(GeyserUtils.SESSION_SECRET)) {
throw new InvalidSecretException("Invalid secret: " + signature);
}
} else {
ipParts = ipData.split(":");
host = ipParts[0];
port = Integer.parseInt(ipParts[1]);
String reconstructedPayload = hostname + "///" + host + ":" + port + "///" + timestamp;
if (!timestampValidator.validate(timestamp))
throw new TimestampValidationException(timestampValidator, timestamp);
String[] ipParts = ipData.split(":");
String host = ipParts[0];
int port = Integer.parseInt(ipParts[1]);
String reconstructedPayload = hostname + "///" + host + ":" + port + "///" + timestamp;
if (!signatureValidator.validate(reconstructedPayload, signature))
throw new SignatureValidationException();
if (!signatureValidator.validate(reconstructedPayload, signature))
throw new SignatureValidationException();
}
InetSocketAddress newIP = new InetSocketAddress(host, port);
player.setIP(newIP);
@@ -163,6 +182,14 @@ public class TCPShieldPacketHandler {
if (plugin.getConfigProvider().isOnlyProxy())
player.disconnect();
throw new HandshakeException(e);
} catch (InvalidSecretException e) {
plugin.getDebugger().warn(
"%s[%s/%s] provided an invalid session secret when authenticating a geyser connection.",
player.getName(), player.getUUID(), player.getIP());
if (plugin.getConfigProvider().isOnlyProxy())
player.disconnect();
throw new HandshakeException(e);
} catch (Exception e) {
if (plugin.getConfigProvider().isOnlyProxy())
@@ -12,24 +12,28 @@ public interface TCPShieldPlugin {
/**
* Gets the plugin's config provider
*
* @return The plugin's config provider
*/
ConfigProvider getConfigProvider();
/**
* Gets the plugin's logger
*
* @return The plugin's logger
*/
Logger getLogger();
/**
* Gets the packet handler
*
* @return The packet handler
*/
TCPShieldPacketHandler getPacketHandler();
/**
* Gets the plugin's debugger
*
* @return The plugin's debugger
*/
Debugger getDebugger();
@@ -40,12 +44,15 @@ public interface TCPShieldPlugin {
*/
default void initialization() {
String jvmVersion = System.getProperty("java.version");
// Java 11 check/warning (Will eventually force Java 16 without warning)
String[] versionParts = jvmVersion.split("\\.");
int baseVersion = Integer.parseInt(versionParts[0]);
if (baseVersion < 11) // Java 8, and below, starts with 1, but since we are using Java 11 we can ignore sub values
this.getDebugger().warn("The Java version you are running is outdated for TCPShield and may cause issues. Update to atleast Java 11. Your version: Java %s", jvmVersion);
try {
// Java 11 check/warning (Will eventually force Java 16 without warning)
String[] versionParts = jvmVersion.split("\\.");
int baseVersion = Integer.parseInt(versionParts[0]);
if (baseVersion < 11) // Java 8, and below, starts with 1, but since we are using Java 11 we can ignore sub values
this.getDebugger().warn("The Java version you are running is outdated for TCPShield and may cause issues. Update to atleast Java 11. Your version: Java %s", jvmVersion);
} catch (Throwable t) {
this.getDebugger().error("Failed to check java version for string: " + jvmVersion);
}
}
}
@@ -34,7 +34,6 @@ public class BukkitConfig extends ConfigProvider {
}
}
@Override
protected void checkNodes(String... nodes) {
for (String node : nodes) {
@@ -72,6 +71,7 @@ public class BukkitConfig extends ConfigProvider {
this.onlyProxy = loadedConfiguration.getBoolean("only-allow-proxy-connections");
this.timestampValidationMode = loadedConfiguration.getString("timestamp-validation");
this.doDebug = loadedConfiguration.getBoolean("debug-mode");
this.geyser = loadedConfiguration.getBoolean("enable-geyser-support");
} catch (Exception e) {
throw new ConfigLoadException(e);
}
@@ -5,6 +5,7 @@ import net.tcpshield.tcpshield.TCPShieldPlugin;
import net.tcpshield.tcpshield.bukkit.paper.BukkitPaper;
import net.tcpshield.tcpshield.bukkit.protocollib.BukkitProtocolLib;
import net.tcpshield.tcpshield.bukkit.provider.BukkitImplProvider;
import net.tcpshield.tcpshield.geyser.GeyserUtils;
import net.tcpshield.tcpshield.provider.ConfigProvider;
import net.tcpshield.tcpshield.util.Debugger;
import net.tcpshield.tcpshield.util.exception.phase.InitializationException;
@@ -21,7 +22,6 @@ public class TCPShieldBukkit extends JavaPlugin implements TCPShieldPlugin {
private BukkitImplProvider bukkitImpl;
@Override
public void onEnable() {
try {
@@ -42,6 +42,8 @@ public class TCPShieldBukkit extends JavaPlugin implements TCPShieldPlugin {
bukkitImpl.load();
GeyserUtils.initGeyser(this, configProvider);
initialization();
} catch (Exception e) {
throw new InitializationException(e);
@@ -37,7 +37,6 @@ public class BungeeConfig extends ConfigProvider {
}
}
@Override
protected void checkNodes(String... nodes) {
for (String node : nodes) {
@@ -76,6 +75,7 @@ public class BungeeConfig extends ConfigProvider {
this.onlyProxy = loadedConfiguration.getBoolean("only-allow-proxy-connections");
this.timestampValidationMode = loadedConfiguration.getString("timestamp-validation");
this.doDebug = loadedConfiguration.getBoolean("debug-mode");
this.geyser = loadedConfiguration.getBoolean("enable-geyser-support");
} catch (Exception e) {
throw new ConfigLoadException(e);
}
@@ -6,6 +6,7 @@ import net.md_5.bungee.api.plugin.PluginManager;
import net.tcpshield.tcpshield.TCPShieldPacketHandler;
import net.tcpshield.tcpshield.TCPShieldPlugin;
import net.tcpshield.tcpshield.bungee.handler.BungeeHandshakeHandler;
import net.tcpshield.tcpshield.geyser.GeyserUtils;
import net.tcpshield.tcpshield.provider.ConfigProvider;
import net.tcpshield.tcpshield.util.Debugger;
import net.tcpshield.tcpshield.util.exception.phase.InitializationException;
@@ -19,7 +20,6 @@ public class TCPShieldBungee extends Plugin implements TCPShieldPlugin, Listener
private TCPShieldPacketHandler packetHandler;
private Debugger debugger;
@Override
public void onEnable() {
try {
@@ -30,13 +30,14 @@ public class TCPShieldBungee extends Plugin implements TCPShieldPlugin, Listener
PluginManager pluginManager = this.getProxy().getPluginManager();
pluginManager.registerListener(this, new BungeeHandshakeHandler(this));
GeyserUtils.initGeyser(this, configProvider);
initialization();
} catch (Exception e) {
throw new InitializationException(e);
}
}
/*
* The provider's base methods
*/
@@ -35,6 +35,8 @@ public class BungeeHandshakeHandler implements Listener {
BungeePacket packet = new BungeePacket(e.getHandshake(), e.getConnection());
BungeePlayer player = new BungeePlayer(e.getConnection());
this.plugin.getDebugger().warn("BungeeCord: Raw player hostname: " + packet.getPayloadString());
try {
plugin.getPacketHandler().handleHandshake(packet, player);
} catch (HandshakeException exception) {
@@ -1,11 +1,9 @@
package net.tcpshield.tcpshield.bungee.handler;
import io.netty.channel.AbstractChannel;
import net.md_5.bungee.api.connection.PendingConnection;
import net.tcpshield.tcpshield.provider.PlayerProvider;
import net.tcpshield.tcpshield.util.ReflectionUtil;
import net.tcpshield.tcpshield.util.exception.manipulate.PlayerManipulationException;
import net.tcpshield.tcpshield.util.exception.phase.HandshakeException;
import java.lang.reflect.Field;
import java.net.InetSocketAddress;
@@ -28,6 +26,7 @@ public class BungeePlayer implements PlayerProvider {
/**
* Trys to grab the UUID of the handshake
*
* @return If found, the corrosponding uuid, if not, unknown
*/
@Override
@@ -64,8 +63,12 @@ public class BungeePlayer implements PlayerProvider {
// Some BungeeCord versions, notably those on 1.7 (e.g. zBungeeCord) don't have an SocketAddress field in the ChannelWrapper class
}
ReflectionUtil.setFinalField(channel, ReflectionUtil.getPrivateField(AbstractChannel.class, "remoteAddress"), ip);
ReflectionUtil.setFinalField(channel, ReflectionUtil.getPrivateField(AbstractChannel.class, "localAddress"), ip);
ReflectionUtil.setFinalField(channel, ReflectionUtil.getPrivateField(channel.getClass(), "remoteAddress"), ip);
try {
ReflectionUtil.setFinalField(channel, ReflectionUtil.getPrivateField(channel.getClass(), "localAddress"), ip);
} catch (Throwable t) {
// ChannelWrapper doesn't have a localAddress
}
} catch (Exception e) {
throw new PlayerManipulationException(e);
}
@@ -0,0 +1,49 @@
package net.tcpshield.tcpshield.geyser;
import net.tcpshield.tcpshield.TCPShieldPlugin;
import org.geysermc.floodgate.api.InstanceHolder;
import java.util.Arrays;
public class GeyserHandshakeHandler {
private final TCPShieldPlugin plugin;
public GeyserHandshakeHandler(TCPShieldPlugin plugin) {
this.plugin = plugin;
}
public void init() {
InstanceHolder.getHandshakeHandlers().addHandshakeHandler(data -> {
if (data.getIp() == null) {
// not bedrock
this.plugin.getDebugger().warn("Connection with no bedrock data joined and ignored: username = %s, hostname = %s", data.getCorrectUsername(), data.getHostname());
return;
}
this.plugin.getDebugger().warn("Bedrock connection joined and validated: username = %s, hostname = %s", data.getCorrectUsername(), data.getHostname());
String oldPayload = data.getHostname();
if (oldPayload.contains("///")) {
oldPayload = oldPayload.split("///")[0];
}
String hostname = oldPayload;
String realIp = data.getIp();
String timestamp = "0";
String signature = GeyserUtils.SESSION_SECRET;
// so floodgate likes to append "\0Floodgate\0" or something stupid to the hostname
// which just completely breaks this, so we have to pass these in a different
// order to stop bungeecord detecting it as FML data, thanks floodgate.
String newHostname = realIp + ":0///" + signature + "///" + timestamp + "///" + hostname;
if (hostname.contains("\0")) { // this is usually fine because FML, providing the hostname is first
this.plugin.getDebugger().warn("Hostname contains null byte: " + Arrays.toString(hostname.toCharArray()));
}
this.plugin.getDebugger().warn("Setting hostname to %s - %s", newHostname, Arrays.toString(newHostname.toCharArray()));
data.setHostname(newHostname);
});
}
}
@@ -0,0 +1,33 @@
package net.tcpshield.tcpshield.geyser;
import net.tcpshield.tcpshield.TCPShieldPlugin;
import net.tcpshield.tcpshield.provider.ConfigProvider;
import java.util.UUID;
public class GeyserUtils {
public static final String SESSION_SECRET = UUID.randomUUID().toString();
public static boolean GEYSER_SUPPORT_ENABLED = false;
public static void initGeyser(TCPShieldPlugin plugin, ConfigProvider config) {
if (!(GEYSER_SUPPORT_ENABLED = useGeyser(config))) {
return;
}
GeyserHandshakeHandler geyserHandler = new GeyserHandshakeHandler(plugin);
geyserHandler.init();
}
private static boolean useGeyser(ConfigProvider config) {
if (!config.isGeyser()) return false;
try {
Class.forName("org.geysermc.floodgate.api.InstanceHolder");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
@@ -18,15 +18,19 @@ public abstract class ConfigProvider {
protected boolean onlyProxy = true;
protected String timestampValidationMode = "htpdate";
protected boolean doDebug = true; // Fail-safe default set to true
protected boolean geyser = false;
protected File dataFolder;
protected File configFile;
public boolean isOnlyProxy() {
return onlyProxy;
}
public boolean isGeyser() {
return geyser;
}
public String getTimestampValidationMode() {
return this.timestampValidationMode;
}
@@ -53,7 +57,6 @@ public abstract class ConfigProvider {
return maxTimestampDifference;
}
/*
* Required methods
*/
@@ -0,0 +1,26 @@
package net.tcpshield.tcpshield.util.exception.phase;
import net.tcpshield.tcpshield.util.exception.TCPShieldException;
public class InvalidSecretException extends TCPShieldException {
public InvalidSecretException(Throwable throwable) {
super("An invalid secret was provided during the geyser handshake process", throwable);
}
public InvalidSecretException(String message) {
super(message);
}
public InvalidSecretException(String message, Throwable throwable) {
super(message, throwable);
}
public InvalidSecretException() {
super();
}
}
@@ -8,6 +8,7 @@ import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
import net.tcpshield.tcpshield.TCPShieldPacketHandler;
import net.tcpshield.tcpshield.TCPShieldPlugin;
import net.tcpshield.tcpshield.geyser.GeyserUtils;
import net.tcpshield.tcpshield.provider.ConfigProvider;
import net.tcpshield.tcpshield.util.Debugger;
import net.tcpshield.tcpshield.util.exception.phase.InitializationException;
@@ -41,7 +42,6 @@ public class TCPShieldVelocity implements TCPShieldPlugin {
this.dataFolder = dataFolder;
}
@Subscribe
public void onProxyInitialization(ProxyInitializeEvent e) {
try {
@@ -51,13 +51,14 @@ public class TCPShieldVelocity implements TCPShieldPlugin {
server.getEventManager().register(this, new VelocityHandshakeHandler(this));
GeyserUtils.initGeyser(this, configProvider);
initialization();
} catch (Exception exception) {
throw new InitializationException(exception);
}
}
/*
* The provider's base methods
*/
@@ -33,7 +33,6 @@ public class VelocityConfig extends ConfigProvider {
}
}
@Override
protected void checkNodes(String... nodes) {
for (String node : nodes) {
@@ -71,6 +70,7 @@ public class VelocityConfig extends ConfigProvider {
this.onlyProxy = loadedToml.getBoolean("only-allow-proxy-connections");
this.timestampValidationMode = loadedToml.getString("timestamp-validation");
this.doDebug = loadedToml.getBoolean("debug-mode");
this.geyser = loadedToml.getBoolean("enable-geyser-support");
} catch (Exception e) {
throw new ConfigLoadException(e);
}
@@ -20,35 +20,38 @@ public class VelocityHandshakeHandler {
this.plugin = plugin;
}
@Subscribe(order = PostOrder.FIRST)
public void onPreLogin(PreLoginEvent e) {
InboundConnection connection = e.getConnection();
handleEvent(connection);
}
// Turns out this event sometimes passes erroneous hostnames
// which have the null bytes terminated as FML data which causes
// issues with the verification process.
// @Subscribe(order = PostOrder.FIRST)
// public void onPreLogin(PreLoginEvent e) {
// InboundConnection connection = e.getConnection();
// handleEvent(connection, "onPreLogin");
// }
@Subscribe(order = PostOrder.FIRST)
public void onHandshake(ConnectionHandshakeEvent e) {
InboundConnection connection = e.getConnection();
handleEvent(connection);
handleEvent(connection, "onHandshake");
}
@Subscribe(order = PostOrder.FIRST)
public void onProxyPing(ProxyPingEvent e) {
InboundConnection connection = e.getConnection();
handleEvent(connection);
handleEvent(connection, "onProxyPing");
}
private void handleEvent(InboundConnection connection) {
private void handleEvent(InboundConnection connection, String debugSource) {
VelocityPlayer player = new VelocityPlayer(connection);
if (player.isLegacy()) {
if (player.getConnectionType() == VelocityPlayer.ConnectionType.LEGACY) {
player.disconnect();
return;
}
VelocityPacket packet = new VelocityPacket(connection);
this.plugin.getDebugger().warn("Velocity: " + debugSource + " Raw player hostname: " + packet.getPayloadString());
try {
plugin.getPacketHandler().handleHandshake(packet, player);
} catch (HandshakeException exception) {
@@ -22,6 +22,10 @@ public class VelocityPacket implements PacketProvider {
private static final Field HOSTNAME_FIELD;
private static final Field CLEANED_ADDRESS_FIELD;
// new velocity support
private static Class<?> LOGIN_INBOUND_CONNECTION_CLASS;
private static Field LOGIN_INBOUND_CONNECTION_DELEGATE_FIELD;
static {
try {
Class<?> inboundConnection = Class.forName("com.velocitypowered.proxy.connection.client.InitialInboundConnection");
@@ -32,6 +36,14 @@ public class VelocityPacket implements PacketProvider {
} catch (Exception e) {
throw new InitializationException(new ReflectionException(e));
}
// LoginInboundConnection support
try {
LOGIN_INBOUND_CONNECTION_CLASS = Class.forName("com.velocitypowered.proxy.connection.client.LoginInboundConnection");
LOGIN_INBOUND_CONNECTION_DELEGATE_FIELD = ReflectionUtil.getPrivateField(LOGIN_INBOUND_CONNECTION_CLASS, "delegate");
} catch (Exception e) {
// ignore for old versions of velocity
}
}
@@ -39,6 +51,15 @@ public class VelocityPacket implements PacketProvider {
private final String rawPayload;
public VelocityPacket(InboundConnection inboundConnection) {
// support new velocity connection type
if (inboundConnection.getClass() == LOGIN_INBOUND_CONNECTION_CLASS) {
try {
inboundConnection = (InboundConnection) LOGIN_INBOUND_CONNECTION_DELEGATE_FIELD.get(inboundConnection);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
this.inboundConnection = inboundConnection;
try {
this.rawPayload = (String) HOSTNAME_FIELD.get(HANDSHAKE_FIELD.get(inboundConnection));
@@ -26,6 +26,10 @@ public class VelocityPlayer implements PlayerProvider {
private static final Field REMOTE_ADDRESS_FIELD;
private static final Method CLOSE_CHANNEL_METHOD;
// new velocity support
private static Class<?> LOGIN_INBOUND_CONNECTION_CLASS;
private static Field LOGIN_INBOUND_CONNECTION_DELEGATE_FIELD;
static {
try {
INITIAL_INBOUND_CONNECTION_CLASS = Class.forName("com.velocitypowered.proxy.connection.client.InitialInboundConnection");
@@ -38,22 +42,39 @@ public class VelocityPlayer implements PlayerProvider {
} catch (Exception e) {
throw new InitializationException(new ReflectionException(e));
}
// LoginInboundConnection support
try {
LOGIN_INBOUND_CONNECTION_CLASS = Class.forName("com.velocitypowered.proxy.connection.client.LoginInboundConnection");
LOGIN_INBOUND_CONNECTION_DELEGATE_FIELD = ReflectionUtil.getPrivateField(LOGIN_INBOUND_CONNECTION_CLASS, "delegate");
} catch (Exception e) {
// ignore for old versions of velocity
}
}
private final InboundConnection inboundConnection;
private final boolean legacy;
// private final boolean legacy;
private final ConnectionType connectionType;
private String ip;
public VelocityPlayer(InboundConnection inboundConnection) {
this.inboundConnection = inboundConnection;
this.legacy = inboundConnection.getClass() != INITIAL_INBOUND_CONNECTION_CLASS;
// this.legacy = inboundConnection.getClass() != INITIAL_INBOUND_CONNECTION_CLASS && inboundConnection.getClass() != LOGIN_INBOUND_CONNECTION_CLASS;
this.ip = inboundConnection.getRemoteAddress().getAddress().getHostAddress();
}
if (this.inboundConnection.getClass() == INITIAL_INBOUND_CONNECTION_CLASS) {
this.connectionType = ConnectionType.INITIAL_INBOUND;
} else if (this.inboundConnection.getClass() == LOGIN_INBOUND_CONNECTION_CLASS) {
this.connectionType = ConnectionType.LOGIN_INBOUND;
} else {
this.connectionType = ConnectionType.LEGACY;
}
}
/**
* Unsupported with Velocity handshakes
*
* @return unknown
*/
@Override
@@ -63,6 +84,7 @@ public class VelocityPlayer implements PlayerProvider {
/**
* Unsupported with Velocity handshakes
*
* @return unknown
*/
@Override
@@ -75,26 +97,26 @@ public class VelocityPlayer implements PlayerProvider {
return ip;
}
public boolean isLegacy() {
return legacy;
}
@Override
public void setIP(InetSocketAddress ip) throws PlayerManipulationException {
try {
this.ip = ip.getAddress().getHostAddress();
Object minecraftConnection = MINECRAFT_CONNECTION_FIELD.get(inboundConnection);
Object minecraftConnection = this.getMinecraftConnection();
REMOTE_ADDRESS_FIELD.set(minecraftConnection, ip);
} catch (Exception e) {
throw new PlayerManipulationException(e);
}
}
// public boolean isLegacy() {
// return legacy;
// }
@Override
public void disconnect() {
try {
Object minecraftConnection = legacy ? LEGACY_MINECRAFT_CONNECTION_FIELD.get(inboundConnection) : MINECRAFT_CONNECTION_FIELD.get(inboundConnection);
Object minecraftConnection = this.getMinecraftConnection();
CLOSE_CHANNEL_METHOD.invoke(minecraftConnection);
} catch (Exception e) {
@@ -102,4 +124,32 @@ public class VelocityPlayer implements PlayerProvider {
}
}
private Object getMinecraftConnection() {
try {
switch (this.connectionType) {
case LEGACY:
return LEGACY_MINECRAFT_CONNECTION_FIELD.get(inboundConnection);
case INITIAL_INBOUND:
return MINECRAFT_CONNECTION_FIELD.get(inboundConnection);
case LOGIN_INBOUND: {
// starts as login_inbound, get delegate initial_inbound
Object initialInboundConnection = LOGIN_INBOUND_CONNECTION_DELEGATE_FIELD.get(this.inboundConnection);
return MINECRAFT_CONNECTION_FIELD.get(initialInboundConnection);
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public ConnectionType getConnectionType() {
return connectionType;
}
enum ConnectionType {
LOGIN_INBOUND, INITIAL_INBOUND, LEGACY;
}
}
+3 -1
View File
@@ -1,4 +1,6 @@
name: TCPShield
version: 2.5.2
version: 2.5.5
main: net.tcpshield.tcpshield.bungee.TCPShieldBungee
author: https://tcpshield.com
softdepends:
- floodgate
+4 -1
View File
@@ -5,4 +5,7 @@ only-allow-proxy-connections = true
timestamp-validation = 'htpdate'
# Turn on to diagnose connection issues
debug-mode = false
debug-mode = false
# Toggle to enable support for Geyser/Floodgate v2
enable-geyser-support = false
+4 -1
View File
@@ -5,4 +5,7 @@ only-allow-proxy-connections: true
timestamp-validation: 'htpdate'
# Turn on to diagnose connection issues
debug-mode: false
debug-mode: false
# Toggle to enable support for Geyser/Floodgate v2
enable-geyser-support: false
+3 -1
View File
@@ -1,7 +1,9 @@
name: TCPShield
version: 2.5.2
version: 2.5.5
main: net.tcpshield.tcpshield.bukkit.TCPShieldBukkit
softdepend:
- ProtocolLib
- floodgate
author: https://tcpshield.com
description: TCPShield IP parsing capabilities for Velocity
api-version: 1.16
+16 -1
View File
@@ -1 +1,16 @@
{"id":"tcpshield","name":"TCPShield","version":"2.5.2","description":"TCPShield IP parsing capabilities for Velocity","authors":["TCPShield"],"dependencies":[],"main":"net.tcpshield.tcpshield.velocity.TCPShieldVelocity"}
{
"id": "tcpshield",
"name": "TCPShield",
"version": "2.5.5",
"description": "TCPShield IP parsing capabilities for Velocity",
"authors": [
"TCPShield"
],
"dependencies": [
{
"id": "floodgate",
"optional": true
}
],
"main": "net.tcpshield.tcpshield.velocity.TCPShieldVelocity"
}