Skip to content

Commit

Permalink
Support velocity forward protocol 2
Browse files Browse the repository at this point in the history
  • Loading branch information
james58899 committed Jun 8, 2022
1 parent 85d2cdc commit 88531cc
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 7 deletions.
29 changes: 26 additions & 3 deletions src/main/java/one/oktw/PacketHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,38 @@
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.encryption.PlayerPublicKey;
import net.minecraft.network.packet.c2s.login.LoginHelloC2SPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerLoginNetworkHandler;
import net.minecraft.text.Text;
import one.oktw.mixin.ServerLoginNetworkHandler_DelayHello;
import one.oktw.mixin.core.ClientConnection_AddressAccessor;
import one.oktw.mixin.core.ServerLoginNetworkHandler_ProfileAccessor;
import org.apache.logging.log4j.LogManager;

import java.util.Optional;

class PacketHandler {
private final ModConfig config;

PacketHandler(ModConfig config) {
this.config = config;
}

void handleVelocityPacket(MinecraftServer server, ServerLoginNetworkHandler handler, boolean understood, PacketByteBuf buf, ServerLoginNetworking.LoginSynchronizer synchronizer, PacketSender responseSender) {
void handleVelocityPacket(MinecraftServer server, ServerLoginNetworkHandler handler, boolean understood, PacketByteBuf buf, ServerLoginNetworking.LoginSynchronizer synchronizer, PacketSender ignored) {
if (!understood) {
handler.disconnect(Text.of("This server requires you to connect with Velocity."));
return;
}

synchronizer.waitFor(server.submit(() -> {
int forwardVersion;
try {
if (!VelocityLib.checkIntegrity(buf)) {
handler.disconnect(Text.of("Unable to verify player details"));
return;
}
forwardVersion = VelocityLib.checkVersion(buf);
} catch (Throwable e) {
LogManager.getLogger().error("Secret check failed.", e);
handler.disconnect(Text.of("Unable to verify player details"));
Expand All @@ -48,11 +53,29 @@ void handleVelocityPacket(MinecraftServer server, ServerLoginNetworkHandler hand
return;
}

// Public key
boolean keyEnforce = server.shouldEnforceSecureProfile();
Optional<PlayerPublicKey> publicKey = Optional.empty();
try {
if (forwardVersion >= VelocityLib.MODERN_FORWARDING_WITH_KEY) publicKey = VelocityLib.readKey(buf);
if (keyEnforce && publicKey.isEmpty()) {
handler.disconnect(Text.translatable("multiplayer.disconnect.missing_public_key"));
return;
}
} catch (Exception e) {
LogManager.getLogger().error("Public key read failed.", e);
if (keyEnforce) {
handler.disconnect(Text.translatable("multiplayer.disconnect.invalid_public_key"));
return;
}
}

if (config.getHackEarlySend()) {
handler.onHello(((ServerLoginNetworkHandler_DelayHello) handler).delayedHelloPacket());
handler.onHello(new LoginHelloC2SPacket(profile.getName(), publicKey.map(PlayerPublicKey::data)));
}

((ServerLoginNetworkHandler_ProfileAccessor) handler).setProfile(profile);
publicKey.ifPresent(((ServerLoginNetworkHandler_ProfileAccessor) handler)::setPublicKey);
}));
}
}
33 changes: 29 additions & 4 deletions src/main/java/one/oktw/VelocityLib.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.encryption.NetworkEncryptionException;
import net.minecraft.network.encryption.PlayerPublicKey;
import net.minecraft.util.Identifier;

import javax.crypto.Mac;
Expand All @@ -12,10 +14,20 @@
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.time.Instant;
import java.util.Arrays;
import java.util.Optional;

import static java.util.Arrays.binarySearch;
import static net.minecraft.network.encryption.NetworkEncryptionUtils.decodeEncodedRsaPublicKey;

public class VelocityLib {
public static final Identifier PLAYER_INFO_CHANNEL = new Identifier("velocity", "player_info");
private static final int SUPPORTED_FORWARDING_VERSION = 1;

public static final int MODERN_FORWARDING_DEFAULT = 1;
public static final int MODERN_FORWARDING_WITH_KEY = 2;
private static final int[] SUPPORTED_FORWARDING_VERSION = {MODERN_FORWARDING_DEFAULT, MODERN_FORWARDING_WITH_KEY};

public static boolean checkIntegrity(final PacketByteBuf buf) {
final byte[] signature = new byte[32];
Expand All @@ -35,15 +47,20 @@ public static boolean checkIntegrity(final PacketByteBuf buf) {
throw new AssertionError(e);
}

return true;
}

public static int checkVersion(final PacketByteBuf buf) {
int version = buf.readVarInt();
if (version != SUPPORTED_FORWARDING_VERSION) {
throw new IllegalStateException("Unsupported forwarding version " + version + ", wanted " + SUPPORTED_FORWARDING_VERSION);
if (binarySearch(SUPPORTED_FORWARDING_VERSION, version) < 0) {
throw new IllegalStateException("Unsupported forwarding version " + version + ", supported " + Arrays.toString(SUPPORTED_FORWARDING_VERSION));
}

return true;
return version;
}

public static InetAddress readAddress(final PacketByteBuf buf) {
//noinspection UnstableApiUsage
return InetAddresses.forString(buf.readString(Short.MAX_VALUE));
}

Expand All @@ -53,6 +70,14 @@ public static GameProfile createProfile(final PacketByteBuf buf) {
return profile;
}

public static Optional<PlayerPublicKey> readKey(final PacketByteBuf buf) throws NetworkEncryptionException {
Instant expiry = Instant.ofEpochMilli(buf.readLong());
PublicKey key = decodeEncodedRsaPublicKey(buf.readByteArray(512));
byte[] signature = buf.readByteArray(4096);

return Optional.of(new PlayerPublicKey(new PlayerPublicKey.PublicKeyData(expiry, key, signature)));
}

private static void readProperties(final PacketByteBuf buf, final GameProfile profile) {
final int properties = buf.readVarInt();
for (int i1 = 0; i1 < properties; i1++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package one.oktw.mixin.core;

import com.mojang.authlib.GameProfile;
import net.minecraft.network.encryption.PlayerPublicKey;
import net.minecraft.server.network.ServerLoginNetworkHandler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
Expand All @@ -9,4 +10,7 @@
public interface ServerLoginNetworkHandler_ProfileAccessor {
@Accessor
void setProfile(GameProfile profile);

@Accessor
void setPublicKey(PlayerPublicKey publicKey);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,9 @@ public class ServerLoginNetworkHandler_SkipKeyPacket {
private boolean skipKeyPacket(MinecraftServer minecraftServer) {
return false;
}

@Redirect(method = "onHello", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;shouldEnforceSecureProfile()Z"))
private boolean skipCheckKey(MinecraftServer minecraftServer) {
return false;
}
}

0 comments on commit 88531cc

Please sign in to comment.