Fixed copied packets and compression using velocity forwarding

This commit is contained in:
themode 2020-11-10 21:14:24 +01:00
parent f2e52ff463
commit bcee5424dc
5 changed files with 55 additions and 25 deletions

View File

@ -1,10 +1,13 @@
package net.minestom.server.extras.velocity; package net.minestom.server.extras.velocity;
import com.google.common.net.InetAddresses;
import io.netty.buffer.ByteBuf;
import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryReader;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.crypto.Mac; import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import java.net.InetAddress;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -17,6 +20,7 @@ import java.security.NoSuchAlgorithmException;
public final class VelocityProxy { public final class VelocityProxy {
public static final String PLAYER_INFO_CHANNEL = "velocity:player_info"; public static final String PLAYER_INFO_CHANNEL = "velocity:player_info";
private static final int SUPPORTED_FORWARDING_VERSION = 1;
private static boolean enabled; private static boolean enabled;
private static byte[] secret; private static byte[] secret;
@ -48,7 +52,9 @@ public final class VelocityProxy {
final byte[] signature = reader.readBytes(32); final byte[] signature = reader.readBytes(32);
final byte[] data = reader.getRemainingBytes(); ByteBuf buf = reader.getBuffer();
final byte[] data = new byte[buf.readableBytes()];
buf.getBytes(buf.readerIndex(), data);
try { try {
final Mac mac = Mac.getInstance("HmacSHA256"); final Mac mac = Mac.getInstance("HmacSHA256");
@ -61,12 +67,12 @@ public final class VelocityProxy {
throw new AssertionError(e); throw new AssertionError(e);
} }
/*int version = buf.readVarInt(); final int version = reader.readVarInt();
if (version != SUPPORTED_FORWARDING_VERSION) { return version == SUPPORTED_FORWARDING_VERSION;
throw new IllegalStateException("Unsupported forwarding version " + version + ", wanted " + SUPPORTED_FORWARDING_VERSION); }
}*/
return true; public static InetAddress readAddress(@NotNull BinaryReader reader) {
return InetAddresses.forString(reader.readSizedString());
} }
} }

View File

@ -55,11 +55,6 @@ public class EncryptionResponsePacket implements ClientPreplayPacket {
final String string3 = new BigInteger(digestedData).toString(16); final String string3 = new BigInteger(digestedData).toString(16);
final GameProfile gameProfile = MinecraftServer.getSessionService().hasJoinedServer(new GameProfile(null, loginUsername), string3); final GameProfile gameProfile = MinecraftServer.getSessionService().hasJoinedServer(new GameProfile(null, loginUsername), string3);
nettyConnection.setEncryptionKey(getSecretKey()); nettyConnection.setEncryptionKey(getSecretKey());
final int threshold = MinecraftServer.getCompressionThreshold();
if (threshold > 0) {
nettyConnection.enableCompression(threshold);
}
MinecraftServer.getLOGGER().info("UUID of player {} is {}", loginUsername, gameProfile.getId()); MinecraftServer.getLOGGER().info("UUID of player {} is {}", loginUsername, gameProfile.getId());
CONNECTION_MANAGER.startPlayState(connection, gameProfile.getId(), gameProfile.getName()); CONNECTION_MANAGER.startPlayState(connection, gameProfile.getId(), gameProfile.getName());

View File

@ -12,6 +12,9 @@ import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryReader;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.UUID; import java.util.UUID;
public class LoginPluginResponsePacket implements ClientPreplayPacket { public class LoginPluginResponsePacket implements ClientPreplayPacket {
@ -34,16 +37,27 @@ public class LoginPluginResponsePacket implements ClientPreplayPacket {
if (channel != null) { if (channel != null) {
boolean success = false; boolean success = false;
SocketAddress socketAddress = null;
// Velocity // Velocity
if (VelocityProxy.isEnabled() && channel.equals(VelocityProxy.PLAYER_INFO_CHANNEL)) { if (VelocityProxy.isEnabled() && channel.equals(VelocityProxy.PLAYER_INFO_CHANNEL)) {
if (data != null) { if (data != null) {
BinaryReader reader = new BinaryReader(data); BinaryReader reader = new BinaryReader(data);
success = VelocityProxy.checkIntegrity(reader); success = VelocityProxy.checkIntegrity(reader);
if (success) {
// Get the real connection address
final InetAddress address = VelocityProxy.readAddress(reader);
final int port = ((java.net.InetSocketAddress) connection.getRemoteAddress()).getPort();
socketAddress = new InetSocketAddress(address, port);
}
} }
} }
if (success) { if (success) {
if (socketAddress != null) {
nettyPlayerConnection.setRemoteAddress(socketAddress);
}
// Proxy usage always mean that the server is in offline mode // Proxy usage always mean that the server is in offline mode
final String username = nettyPlayerConnection.getLoginUsername(); final String username = nettyPlayerConnection.getLoginUsername();
final UUID playerUuid = CONNECTION_MANAGER.getPlayerConnectionUuid(connection, username); final UUID playerUuid = CONNECTION_MANAGER.getPlayerConnectionUuid(connection, username);

View File

@ -27,9 +27,16 @@ public class LoginStartPacket implements ClientPreplayPacket {
@Override @Override
public void process(@NotNull PlayerConnection connection) { public void process(@NotNull PlayerConnection connection) {
// Cache the login username // Cache the login username and start compression if enabled
if (connection instanceof NettyPlayerConnection) { if (connection instanceof NettyPlayerConnection) {
((NettyPlayerConnection) connection).UNSAFE_setLoginUsername(username); NettyPlayerConnection nettyPlayerConnection = (NettyPlayerConnection) connection;
nettyPlayerConnection.UNSAFE_setLoginUsername(username);
// Compression
final int threshold = MinecraftServer.getCompressionThreshold();
if (threshold > 0) {
nettyPlayerConnection.enableCompression(threshold);
}
} }
// Proxy support (only for netty clients) // Proxy support (only for netty clients)
@ -75,12 +82,6 @@ public class LoginStartPacket implements ClientPreplayPacket {
// Offline // Offline
final UUID playerUuid = CONNECTION_MANAGER.getPlayerConnectionUuid(connection, username); final UUID playerUuid = CONNECTION_MANAGER.getPlayerConnectionUuid(connection, username);
final int threshold = MinecraftServer.getCompressionThreshold();
if (threshold > 0 && connection instanceof NettyPlayerConnection) {
((NettyPlayerConnection) connection).enableCompression(threshold);
}
CONNECTION_MANAGER.startPlayState(connection, playerUuid, username); CONNECTION_MANAGER.startPlayState(connection, playerUuid, username);
} }
} }

View File

@ -29,6 +29,8 @@ import java.util.concurrent.ConcurrentHashMap;
public class NettyPlayerConnection extends PlayerConnection { public class NettyPlayerConnection extends PlayerConnection {
private final SocketChannel channel; private final SocketChannel channel;
private SocketAddress remoteAddress;
@Getter @Getter
private boolean encrypted = false; private boolean encrypted = false;
@Getter @Getter
@ -50,6 +52,7 @@ public class NettyPlayerConnection extends PlayerConnection {
public NettyPlayerConnection(@NotNull SocketChannel channel) { public NettyPlayerConnection(@NotNull SocketChannel channel) {
super(); super();
this.channel = channel; this.channel = channel;
this.remoteAddress = channel.remoteAddress();
} }
/** /**
@ -80,25 +83,25 @@ public class NettyPlayerConnection extends PlayerConnection {
@Override @Override
public void sendPacket(@NotNull ByteBuf buffer, boolean copy) { public void sendPacket(@NotNull ByteBuf buffer, boolean copy) {
if ((encrypted || compressed) && copy) { if (copy) {
buffer = buffer.copy(); buffer = buffer.copy();
buffer.retain(); buffer.retain();
channel.writeAndFlush(buffer); channel.writeAndFlush(buffer);
buffer.release(); buffer.release();
} else { } else {
getChannel().writeAndFlush(buffer); channel.writeAndFlush(buffer);
} }
} }
@Override @Override
public void writePacket(@NotNull ByteBuf buffer, boolean copy) { public void writePacket(@NotNull ByteBuf buffer, boolean copy) {
if ((encrypted || compressed) && copy) { if (copy) {
buffer = buffer.copy(); buffer = buffer.copy();
buffer.retain(); buffer.retain();
channel.write(buffer); channel.write(buffer);
buffer.release(); buffer.release();
} else { } else {
getChannel().write(buffer); channel.write(buffer);
} }
} }
@ -115,7 +118,18 @@ public class NettyPlayerConnection extends PlayerConnection {
@NotNull @NotNull
@Override @Override
public SocketAddress getRemoteAddress() { public SocketAddress getRemoteAddress() {
return getChannel().remoteAddress(); return remoteAddress;
}
/**
* Changes the internal remote address field.
* <p>
* Mostly unsafe, used internally when interacting with a proxy.
*
* @param remoteAddress the new connection remote address
*/
public void setRemoteAddress(@NotNull SocketAddress remoteAddress) {
this.remoteAddress = remoteAddress;
} }
@Override @Override
@ -141,7 +155,7 @@ public class NettyPlayerConnection extends PlayerConnection {
} }
/** /**
* Sets the internal login username field * Sets the internal login username field.
* *
* @param loginUsername the new login username field * @param loginUsername the new login username field
*/ */