mirror of
https://github.com/ViaVersion/ViaProxy.git
synced 2024-11-25 12:25:41 +01:00
Added support for 23w32a clients and servers, Refactored packet handler code
This commit is contained in:
parent
512ce30ffe
commit
94baa38e7f
@ -9,13 +9,13 @@ For a full user guide go to the [Usage for Players](#usage-for-players-gui) sect
|
||||
- Classic (c0.0.15 - c0.30 including [CPE](https://wiki.vg/Classic_Protocol_Extension))
|
||||
- Alpha (a1.0.15 - a1.2.6)
|
||||
- Beta (b1.0 - b1.8.1)
|
||||
- Release (1.0.0 - 1.20)
|
||||
- Release (1.0.0 - 1.20.2)
|
||||
- April Fools (3D Shareware, 20w14infinite)
|
||||
- Combat Snapshots (Combat Test 8c)
|
||||
- Bedrock Edition 1.20.0 (In development)
|
||||
|
||||
## Supported Client versions
|
||||
- Release (1.7.2 - 1.20)
|
||||
- Release (1.7.2 - 1.20.2)
|
||||
- Bedrock Edition (Needs the [Geyser plugin](https://github.com/RaphiMC/ViaProxyGeyserPlugin))
|
||||
- Classic, Alpha, Beta, Release 1.0 - 1.6.4 (Only passthrough)
|
||||
|
||||
|
14
build.gradle
14
build.gradle
@ -76,21 +76,21 @@ repositories {
|
||||
dependencies {
|
||||
compileOnly sourceSets.java17compat.output
|
||||
|
||||
include "com.viaversion:viaversion:4.7.1-SNAPSHOT"
|
||||
include("com.viaversion:viabackwards-common:4.7.1-SNAPSHOT") {
|
||||
include "com.viaversion:viaversion:4.8.0-23w32a-SNAPSHOT"
|
||||
include("com.viaversion:viabackwards-common:4.8.0-23w32a-SNAPSHOT") {
|
||||
exclude group: "com.viaversion", module: "viaversion"
|
||||
exclude group: "io.netty", module: "netty-all"
|
||||
exclude group: "com.google.guava", module: "guava"
|
||||
}
|
||||
include "com.viaversion:viarewind-core:2.0.4-SNAPSHOT"
|
||||
include "net.raphimc:ViaLegacy:2.2.18-SNAPSHOT"
|
||||
include "net.raphimc:ViaAprilFools:2.0.7"
|
||||
include "com.viaversion:viarewind-core:3.0.0-SNAPSHOT"
|
||||
include "net.raphimc:ViaLegacy:2.2.19-SNAPSHOT"
|
||||
include "net.raphimc:ViaAprilFools:2.0.9-SNAPSHOT"
|
||||
include("net.raphimc:ViaBedrock:0.0.2-SNAPSHOT") {
|
||||
exclude group: "io.netty", module: "netty-codec-http"
|
||||
exclude group: "io.jsonwebtoken", module: "jjwt-impl"
|
||||
exclude group: "io.jsonwebtoken", module: "jjwt-gson"
|
||||
}
|
||||
include("net.raphimc:ViaLoader:2.2.7") {
|
||||
include("net.raphimc:ViaLoader:2.2.9-SNAPSHOT") {
|
||||
exclude group: "org.slf4j", module: "slf4j-api"
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@ dependencies {
|
||||
include "net.lenni0451.classtransform:additionalclassprovider:1.10.1"
|
||||
include "net.lenni0451:Reflect:1.2.2"
|
||||
include "net.lenni0451:LambdaEvents:2.2.0"
|
||||
include "net.raphimc.netminecraft:all:2.3.4"
|
||||
include "net.raphimc.netminecraft:all:2.3.6-SNAPSHOT"
|
||||
include("net.raphimc:MinecraftAuth:2.1.5-SNAPSHOT") {
|
||||
exclude group: "com.google.code.gson", module: "gson"
|
||||
exclude group: "org.slf4j", module: "slf4j-api"
|
||||
|
@ -51,6 +51,7 @@ public abstract class MixinProtocolVersion {
|
||||
remaps.put("1.18/1.18.1", new Pair<>("1.18-1.18.1", null));
|
||||
remaps.put("1.19.1/2", new Pair<>("1.19.1-1.19.2", null));
|
||||
remaps.put("1.20/1.20.1", new Pair<>("1.20-1.20.1", null));
|
||||
remaps.put("1.20.2", new Pair<>("23w32a", null));
|
||||
}
|
||||
|
||||
@Redirect(method = "<clinit>", at = @At(value = "INVOKE", target = "Lcom/viaversion/viaversion/api/protocol/version/ProtocolVersion;register(ILjava/lang/String;)Lcom/viaversion/viaversion/api/protocol/version/ProtocolVersion;"))
|
||||
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2023 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.plugins.events;
|
||||
|
||||
import net.raphimc.viaproxy.plugins.events.types.EventCancellable;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
|
||||
public class ConnectEvent extends EventCancellable {
|
||||
|
||||
private final ProxyConnection proxyConnection;
|
||||
|
||||
public ConnectEvent(final ProxyConnection proxyConnection) {
|
||||
this.proxyConnection = proxyConnection;
|
||||
}
|
||||
|
||||
public ProxyConnection getProxyConnection() {
|
||||
return this.proxyConnection;
|
||||
}
|
||||
|
||||
}
|
@ -17,9 +17,8 @@
|
||||
*/
|
||||
package net.raphimc.viaproxy.proxy.client2proxy;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
@ -27,28 +26,19 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.haproxy.*;
|
||||
import net.raphimc.netminecraft.constants.ConnectionState;
|
||||
import net.raphimc.netminecraft.constants.MCPackets;
|
||||
import net.raphimc.netminecraft.constants.MCPipeline;
|
||||
import net.raphimc.netminecraft.netty.crypto.AESEncryption;
|
||||
import net.raphimc.netminecraft.netty.crypto.CryptUtil;
|
||||
import net.raphimc.netminecraft.packet.IPacket;
|
||||
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||
import net.raphimc.netminecraft.packet.UnknownPacket;
|
||||
import net.raphimc.netminecraft.packet.impl.handshake.C2SHandshakePacket;
|
||||
import net.raphimc.netminecraft.packet.impl.login.*;
|
||||
import net.raphimc.netminecraft.util.ServerAddress;
|
||||
import net.raphimc.vialoader.util.VersionEnum;
|
||||
import net.raphimc.viaproxy.ViaProxy;
|
||||
import net.raphimc.viaproxy.cli.options.Options;
|
||||
import net.raphimc.viaproxy.plugins.PluginManager;
|
||||
import net.raphimc.viaproxy.plugins.events.ConnectEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.PreConnectEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.Proxy2ServerHandlerCreationEvent;
|
||||
import net.raphimc.viaproxy.plugins.events.ResolveSrvEvent;
|
||||
import net.raphimc.viaproxy.protocolhack.viaproxy.ViaBedrockTransferHolder;
|
||||
import net.raphimc.viaproxy.proxy.LoginState;
|
||||
import net.raphimc.viaproxy.proxy.external_interface.AuthLibServices;
|
||||
import net.raphimc.viaproxy.proxy.external_interface.ExternalInterface;
|
||||
import net.raphimc.viaproxy.proxy.external_interface.OpenAuthModConstants;
|
||||
import net.raphimc.viaproxy.proxy.packethandler.*;
|
||||
import net.raphimc.viaproxy.proxy.proxy2server.Proxy2ServerChannelInitializer;
|
||||
import net.raphimc.viaproxy.proxy.proxy2server.Proxy2ServerHandler;
|
||||
import net.raphimc.viaproxy.proxy.session.BedrockProxyConnection;
|
||||
@ -59,41 +49,24 @@ import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
||||
import net.raphimc.viaproxy.util.ArrayHelper;
|
||||
import net.raphimc.viaproxy.util.logging.Logger;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.math.BigInteger;
|
||||
import java.net.ConnectException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.channels.UnresolvedAddressException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyPair;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Random;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Client2ProxyHandler extends SimpleChannelInboundHandler<IPacket> {
|
||||
|
||||
private static final KeyPair KEY_PAIR = CryptUtil.generateKeyPair();
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
private ProxyConnection proxyConnection;
|
||||
private LoginState loginState = LoginState.FIRST_PACKET;
|
||||
|
||||
private final byte[] verifyToken = new byte[4];
|
||||
private int customPayloadPacketId = -1;
|
||||
private int chatSessionUpdatePacketId = -1;
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelActive(ctx);
|
||||
|
||||
RANDOM.nextBytes(this.verifyToken);
|
||||
this.proxyConnection = new DummyProxyConnection(ctx.channel());
|
||||
|
||||
ViaProxy.c2pChannels.add(ctx.channel());
|
||||
}
|
||||
|
||||
@ -112,30 +85,19 @@ public class Client2ProxyHandler extends SimpleChannelInboundHandler<IPacket> {
|
||||
protected void channelRead0(ChannelHandlerContext ctx, IPacket packet) throws Exception {
|
||||
if (this.proxyConnection.isClosed()) return;
|
||||
|
||||
switch (this.proxyConnection.getConnectionState()) {
|
||||
case HANDSHAKING:
|
||||
if (packet instanceof C2SHandshakePacket) this.handleHandshake((C2SHandshakePacket) packet);
|
||||
else throw new IllegalStateException("Unexpected packet in HANDSHAKING state");
|
||||
|
||||
return;
|
||||
case LOGIN:
|
||||
if (packet instanceof C2SLoginHelloPacket1_7) this.handleLoginHello((C2SLoginHelloPacket1_7) packet);
|
||||
else if (packet instanceof C2SLoginKeyPacket1_7) this.handleLoginKey((C2SLoginKeyPacket1_7) packet);
|
||||
else if (packet instanceof C2SLoginCustomPayloadPacket) this.handleLoginCustomPayload((C2SLoginCustomPayloadPacket) packet);
|
||||
else throw new IllegalStateException("Unexpected packet in LOGIN state");
|
||||
|
||||
return;
|
||||
case PLAY:
|
||||
final UnknownPacket unknownPacket = (UnknownPacket) packet;
|
||||
if (unknownPacket.packetId == this.customPayloadPacketId) {
|
||||
if (this.handlePlayCustomPayload(Unpooled.wrappedBuffer(unknownPacket.data))) return;
|
||||
} else if (unknownPacket.packetId == this.chatSessionUpdatePacketId && this.proxyConnection.getChannel().attr(MCPipeline.ENCRYPTION_ATTRIBUTE_KEY).get() == null) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
if (this.proxyConnection.getConnectionState() == ConnectionState.HANDSHAKING) {
|
||||
if (packet instanceof C2SHandshakePacket) this.handleHandshake((C2SHandshakePacket) packet);
|
||||
else throw new IllegalStateException("Unexpected packet in HANDSHAKING state");
|
||||
return;
|
||||
}
|
||||
|
||||
this.proxyConnection.getChannel().writeAndFlush(packet).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
final List<ChannelFutureListener> listeners = Lists.newArrayList(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
for (PacketHandler packetHandler : this.proxyConnection.getPacketHandlers()) {
|
||||
if (!packetHandler.handleC2P(packet, listeners)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.proxyConnection.getChannel().writeAndFlush(packet).addListeners(listeners.toArray(new ChannelFutureListener[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -157,9 +119,6 @@ public class Client2ProxyHandler extends SimpleChannelInboundHandler<IPacket> {
|
||||
this.proxyConnection.kickClient("§cYour client version is not supported by ViaProxy!");
|
||||
}
|
||||
|
||||
this.customPayloadPacketId = MCPackets.C2S_PLUGIN_MESSAGE.getId(clientVersion.getVersion());
|
||||
this.chatSessionUpdatePacketId = MCPackets.C2S_CHAT_SESSION_UPDATE.getId(clientVersion.getVersion());
|
||||
|
||||
String[] handshakeParts = new String[]{packet.address};
|
||||
if (Options.PLAYER_INFO_FORWARDING) {
|
||||
handshakeParts = new String[3];
|
||||
@ -256,9 +215,16 @@ public class Client2ProxyHandler extends SimpleChannelInboundHandler<IPacket> {
|
||||
this.proxyConnection.setClientVersion(clientVersion);
|
||||
this.proxyConnection.setConnectionState(packet.intendedState);
|
||||
this.proxyConnection.setClassicMpPass(classicMpPass);
|
||||
this.proxyConnection.getPacketHandlers().add(new StatusPacketHandler(this.proxyConnection));
|
||||
this.proxyConnection.getPacketHandlers().add(new CustomPayloadPacketHandler(this.proxyConnection));
|
||||
this.proxyConnection.getPacketHandlers().add(new LoginPacketHandler(this.proxyConnection));
|
||||
this.proxyConnection.getPacketHandlers().add(new ConfigurationPacketHandler(this.proxyConnection));
|
||||
this.proxyConnection.getPacketHandlers().add(new ResourcePackPacketHandler(this.proxyConnection));
|
||||
this.proxyConnection.getPacketHandlers().add(new UnexpectedPacketHandler(this.proxyConnection));
|
||||
|
||||
Logger.u_info("connect", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "[" + clientVersion.getName() + " <-> " + serverVersion.getName() + "] Connecting to " + serverAddress.getAddress() + ":" + serverAddress.getPort());
|
||||
try {
|
||||
PluginManager.EVENT_MANAGER.call(new ConnectEvent(this.proxyConnection));
|
||||
this.proxyConnection.connectToServer(serverAddress, serverVersion);
|
||||
} catch (Throwable e) {
|
||||
if (e instanceof ConnectException || e instanceof UnresolvedAddressException) { // Trust me, this is not always false
|
||||
@ -284,91 +250,4 @@ public class Client2ProxyHandler extends SimpleChannelInboundHandler<IPacket> {
|
||||
this.proxyConnection.setConnectionState(packet.intendedState);
|
||||
}
|
||||
|
||||
private void handleLoginHello(C2SLoginHelloPacket1_7 packet) {
|
||||
if (this.loginState != LoginState.FIRST_PACKET) throw CloseAndReturn.INSTANCE;
|
||||
this.loginState = LoginState.SENT_HELLO;
|
||||
|
||||
if (packet instanceof C2SLoginHelloPacket1_19) {
|
||||
final C2SLoginHelloPacket1_19 packet1_19 = (C2SLoginHelloPacket1_19) packet;
|
||||
if (packet1_19.expiresAt != null && packet1_19.expiresAt.isBefore(Instant.now())) {
|
||||
throw new IllegalStateException("Expired public key");
|
||||
}
|
||||
}
|
||||
|
||||
proxyConnection.setLoginHelloPacket(packet);
|
||||
if (packet instanceof C2SLoginHelloPacket1_19_3) {
|
||||
proxyConnection.setGameProfile(new GameProfile(((C2SLoginHelloPacket1_19_3) packet).uuid, packet.name));
|
||||
} else {
|
||||
proxyConnection.setGameProfile(new GameProfile(null, packet.name));
|
||||
}
|
||||
|
||||
if (Options.ONLINE_MODE) {
|
||||
this.proxyConnection.getC2P().writeAndFlush(new S2CLoginKeyPacket1_8("", KEY_PAIR.getPublic().getEncoded(), this.verifyToken)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
} else {
|
||||
ExternalInterface.fillPlayerData(this.proxyConnection);
|
||||
this.proxyConnection.getChannel().writeAndFlush(this.proxyConnection.getLoginHelloPacket()).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLoginKey(final C2SLoginKeyPacket1_7 packet) throws GeneralSecurityException {
|
||||
if (this.proxyConnection.getClientVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2) && new String(packet.encryptedNonce, StandardCharsets.UTF_8).equals(OpenAuthModConstants.DATA_CHANNEL)) { // 1.8-1.12.2 OpenAuthMod response handling
|
||||
final ByteBuf byteBuf = Unpooled.wrappedBuffer(packet.encryptedSecretKey);
|
||||
this.proxyConnection.handleCustomPayload(PacketTypes.readVarInt(byteBuf), byteBuf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.loginState != LoginState.SENT_HELLO) throw CloseAndReturn.INSTANCE;
|
||||
this.loginState = LoginState.SENT_KEY;
|
||||
|
||||
if (packet.encryptedNonce != null) {
|
||||
if (!Arrays.equals(this.verifyToken, CryptUtil.decryptData(KEY_PAIR.getPrivate(), packet.encryptedNonce))) {
|
||||
Logger.u_err("auth", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Invalid verify token");
|
||||
this.proxyConnection.kickClient("§cInvalid verify token!");
|
||||
}
|
||||
} else {
|
||||
final C2SLoginKeyPacket1_19 keyPacket = (C2SLoginKeyPacket1_19) packet;
|
||||
final C2SLoginHelloPacket1_19 helloPacket = (C2SLoginHelloPacket1_19) this.proxyConnection.getLoginHelloPacket();
|
||||
if (helloPacket.key == null || !CryptUtil.verifySignedNonce(helloPacket.key, this.verifyToken, keyPacket.salt, keyPacket.signature)) {
|
||||
Logger.u_err("auth", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Invalid verify token");
|
||||
this.proxyConnection.kickClient("§cInvalid verify token!");
|
||||
}
|
||||
}
|
||||
|
||||
final SecretKey secretKey = CryptUtil.decryptSecretKey(KEY_PAIR.getPrivate(), packet.encryptedSecretKey);
|
||||
this.proxyConnection.getC2P().attr(MCPipeline.ENCRYPTION_ATTRIBUTE_KEY).set(new AESEncryption(secretKey));
|
||||
|
||||
final String userName = this.proxyConnection.getGameProfile().getName();
|
||||
|
||||
try {
|
||||
final String serverHash = new BigInteger(CryptUtil.computeServerIdHash("", KEY_PAIR.getPublic(), secretKey)).toString(16);
|
||||
final GameProfile mojangProfile = AuthLibServices.SESSION_SERVICE.hasJoinedServer(this.proxyConnection.getGameProfile(), serverHash, null);
|
||||
if (mojangProfile == null) {
|
||||
Logger.u_err("auth", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Invalid session");
|
||||
this.proxyConnection.kickClient("§cInvalid session! Please restart minecraft (and the launcher) and try again.");
|
||||
} else {
|
||||
this.proxyConnection.setGameProfile(mojangProfile);
|
||||
}
|
||||
Logger.u_info("auth", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Authenticated as " + this.proxyConnection.getGameProfile().getId().toString());
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Failed to make session request for user '" + userName + "'!", e);
|
||||
}
|
||||
|
||||
ExternalInterface.fillPlayerData(this.proxyConnection);
|
||||
this.proxyConnection.getChannel().writeAndFlush(this.proxyConnection.getLoginHelloPacket()).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
|
||||
private void handleLoginCustomPayload(final C2SLoginCustomPayloadPacket packet) {
|
||||
if (packet.response == null || !this.proxyConnection.handleCustomPayload(packet.queryId, Unpooled.wrappedBuffer(packet.response))) {
|
||||
this.proxyConnection.getChannel().writeAndFlush(packet).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handlePlayCustomPayload(final ByteBuf packet) {
|
||||
final String channel = PacketTypes.readString(packet, Short.MAX_VALUE); // channel
|
||||
if (channel.equals(OpenAuthModConstants.DATA_CHANNEL)) {
|
||||
return this.proxyConnection.handleCustomPayload(PacketTypes.readVarInt(packet), packet);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import net.raphimc.mcauth.step.bedrock.StepMCChain;
|
||||
import net.raphimc.mcauth.step.java.StepPlayerCertificates;
|
||||
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||
import net.raphimc.netminecraft.packet.impl.login.C2SLoginHelloPacket1_19_3;
|
||||
import net.raphimc.netminecraft.packet.impl.login.C2SLoginHelloPacket1_20_2;
|
||||
import net.raphimc.netminecraft.packet.impl.login.C2SLoginKeyPacket1_19;
|
||||
import net.raphimc.viabedrock.protocol.storage.AuthChainData;
|
||||
import net.raphimc.vialoader.util.VersionEnum;
|
||||
@ -78,7 +79,7 @@ public class ExternalInterface {
|
||||
if (proxyConnection.getClientVersion().equals(VersionEnum.r1_19)) {
|
||||
loginHelloKeySignature = playerCertificates.legacyPublicKeySignature();
|
||||
}
|
||||
proxyConnection.setLoginHelloPacket(new C2SLoginHelloPacket1_19_3(proxyConnection.getGameProfile().getName(), expiresAt, publicKey, loginHelloKeySignature, proxyConnection.getGameProfile().getId()));
|
||||
proxyConnection.setLoginHelloPacket(new C2SLoginHelloPacket1_20_2(proxyConnection.getGameProfile().getName(), expiresAt, publicKey, loginHelloKeySignature, proxyConnection.getGameProfile().getId()));
|
||||
|
||||
user.put(new ChatSession1_19_0(user, uuid, privateKey, new ProfileKey(expiresAtMillis, publicKeyBytes, playerCertificates.legacyPublicKeySignature())));
|
||||
user.put(new ChatSession1_19_1(user, uuid, privateKey, new ProfileKey(expiresAtMillis, publicKeyBytes, keySignature)));
|
||||
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2023 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.proxy.packethandler;
|
||||
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import net.raphimc.netminecraft.constants.ConnectionState;
|
||||
import net.raphimc.netminecraft.constants.MCPackets;
|
||||
import net.raphimc.netminecraft.packet.IPacket;
|
||||
import net.raphimc.netminecraft.packet.UnknownPacket;
|
||||
import net.raphimc.netminecraft.packet.impl.configuration.C2SConfigFinishConfiguration1_20_2;
|
||||
import net.raphimc.netminecraft.packet.impl.configuration.S2CConfigFinishConfiguration1_20_2;
|
||||
import net.raphimc.netminecraft.packet.impl.login.C2SLoginStartConfiguration1_20_2;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
import net.raphimc.viaproxy.util.logging.Logger;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ConfigurationPacketHandler extends PacketHandler {
|
||||
|
||||
private final int configurationAcknowledgedId;
|
||||
private final int startConfigurationId;
|
||||
|
||||
public ConfigurationPacketHandler(ProxyConnection proxyConnection) {
|
||||
super(proxyConnection);
|
||||
|
||||
this.configurationAcknowledgedId = MCPackets.C2S_CONFIGURATION_ACKNOWLEDGED.getId(proxyConnection.getClientVersion().getVersion());
|
||||
this.startConfigurationId = MCPackets.S2C_START_CONFIGURATION.getId(proxyConnection.getClientVersion().getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleC2P(IPacket packet, List<ChannelFutureListener> listeners) {
|
||||
if (packet instanceof UnknownPacket) {
|
||||
final UnknownPacket unknownPacket = (UnknownPacket) packet;
|
||||
if (unknownPacket.packetId == this.configurationAcknowledgedId) {
|
||||
listeners.add(f -> {
|
||||
if (f.isSuccess()) {
|
||||
Logger.u_info("session", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Switching to CONFIGURATION state");
|
||||
this.proxyConnection.setConnectionState(ConnectionState.CONFIGURATION);
|
||||
this.proxyConnection.getChannel().config().setAutoRead(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (packet instanceof C2SLoginStartConfiguration1_20_2) {
|
||||
this.proxyConnection.getC2P().config().setAutoRead(false);
|
||||
listeners.add(f -> {
|
||||
if (f.isSuccess()) {
|
||||
this.proxyConnection.setConnectionState(ConnectionState.CONFIGURATION);
|
||||
this.proxyConnection.getChannel().config().setAutoRead(true);
|
||||
this.proxyConnection.getC2P().config().setAutoRead(true);
|
||||
}
|
||||
});
|
||||
} else if (packet instanceof C2SConfigFinishConfiguration1_20_2) {
|
||||
listeners.add(f -> {
|
||||
if (f.isSuccess()) {
|
||||
Logger.u_info("session", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Configuration finished! Switching to PLAY state");
|
||||
this.proxyConnection.setConnectionState(ConnectionState.PLAY);
|
||||
this.proxyConnection.getChannel().config().setAutoRead(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleP2S(IPacket packet, List<ChannelFutureListener> listeners) {
|
||||
if (packet instanceof UnknownPacket) {
|
||||
final UnknownPacket unknownPacket = (UnknownPacket) packet;
|
||||
if (unknownPacket.packetId == this.startConfigurationId) {
|
||||
this.proxyConnection.getChannel().config().setAutoRead(false);
|
||||
}
|
||||
} else if (packet instanceof S2CConfigFinishConfiguration1_20_2) {
|
||||
this.proxyConnection.getChannel().config().setAutoRead(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2023 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.proxy.packethandler;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import net.raphimc.netminecraft.constants.MCPackets;
|
||||
import net.raphimc.netminecraft.packet.IPacket;
|
||||
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||
import net.raphimc.netminecraft.packet.UnknownPacket;
|
||||
import net.raphimc.netminecraft.packet.impl.login.C2SLoginCustomPayloadPacket;
|
||||
import net.raphimc.netminecraft.packet.impl.login.C2SLoginKeyPacket1_7;
|
||||
import net.raphimc.vialoader.util.VersionEnum;
|
||||
import net.raphimc.viaproxy.proxy.external_interface.OpenAuthModConstants;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
public class CustomPayloadPacketHandler extends PacketHandler {
|
||||
|
||||
private final int customPayloadId;
|
||||
|
||||
public CustomPayloadPacketHandler(ProxyConnection proxyConnection) {
|
||||
super(proxyConnection);
|
||||
|
||||
this.customPayloadId = MCPackets.C2S_PLUGIN_MESSAGE.getId(proxyConnection.getClientVersion().getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleC2P(IPacket packet, List<ChannelFutureListener> listeners) {
|
||||
if (packet instanceof UnknownPacket) {
|
||||
final UnknownPacket unknownPacket = (UnknownPacket) packet;
|
||||
if (unknownPacket.packetId == this.customPayloadId) {
|
||||
final ByteBuf data = Unpooled.wrappedBuffer(unknownPacket.data);
|
||||
final String channel = PacketTypes.readString(data, Short.MAX_VALUE); // channel
|
||||
if (channel.equals(OpenAuthModConstants.DATA_CHANNEL) && this.proxyConnection.handleCustomPayload(PacketTypes.readVarInt(data), data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (packet instanceof C2SLoginCustomPayloadPacket) {
|
||||
final C2SLoginCustomPayloadPacket loginCustomPayload = (C2SLoginCustomPayloadPacket) packet;
|
||||
if (loginCustomPayload.response != null && this.proxyConnection.handleCustomPayload(loginCustomPayload.queryId, Unpooled.wrappedBuffer(loginCustomPayload.response))) {
|
||||
return false;
|
||||
}
|
||||
} else if (packet instanceof C2SLoginKeyPacket1_7) {
|
||||
final C2SLoginKeyPacket1_7 loginKeyPacket = (C2SLoginKeyPacket1_7) packet;
|
||||
|
||||
if (this.proxyConnection.getClientVersion().isOlderThanOrEqualTo(VersionEnum.r1_12_2) && new String(loginKeyPacket.encryptedNonce, StandardCharsets.UTF_8).equals(OpenAuthModConstants.DATA_CHANNEL)) { // 1.8-1.12.2 OpenAuthMod response handling
|
||||
final ByteBuf byteBuf = Unpooled.wrappedBuffer(loginKeyPacket.encryptedSecretKey);
|
||||
this.proxyConnection.handleCustomPayload(PacketTypes.readVarInt(byteBuf), byteBuf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2023 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.proxy.packethandler;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import net.raphimc.netminecraft.constants.ConnectionState;
|
||||
import net.raphimc.netminecraft.constants.MCPackets;
|
||||
import net.raphimc.netminecraft.constants.MCPipeline;
|
||||
import net.raphimc.netminecraft.netty.crypto.AESEncryption;
|
||||
import net.raphimc.netminecraft.netty.crypto.CryptUtil;
|
||||
import net.raphimc.netminecraft.packet.IPacket;
|
||||
import net.raphimc.netminecraft.packet.UnknownPacket;
|
||||
import net.raphimc.netminecraft.packet.impl.login.*;
|
||||
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.storage.ProtocolMetadataStorage;
|
||||
import net.raphimc.vialoader.util.VersionEnum;
|
||||
import net.raphimc.viaproxy.cli.options.Options;
|
||||
import net.raphimc.viaproxy.proxy.LoginState;
|
||||
import net.raphimc.viaproxy.proxy.external_interface.AuthLibServices;
|
||||
import net.raphimc.viaproxy.proxy.external_interface.ExternalInterface;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
import net.raphimc.viaproxy.proxy.util.CloseAndReturn;
|
||||
import net.raphimc.viaproxy.util.logging.Logger;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PublicKey;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class LoginPacketHandler extends PacketHandler {
|
||||
|
||||
private static final KeyPair KEY_PAIR = CryptUtil.generateKeyPair();
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
private final byte[] verifyToken = new byte[4];
|
||||
private LoginState loginState = LoginState.FIRST_PACKET;
|
||||
|
||||
private final int chatSessionUpdateId;
|
||||
|
||||
public LoginPacketHandler(ProxyConnection proxyConnection) {
|
||||
super(proxyConnection);
|
||||
|
||||
RANDOM.nextBytes(this.verifyToken);
|
||||
this.chatSessionUpdateId = MCPackets.C2S_CHAT_SESSION_UPDATE.getId(proxyConnection.getClientVersion().getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleC2P(IPacket packet, List<ChannelFutureListener> listeners) throws GeneralSecurityException {
|
||||
if (packet instanceof UnknownPacket) {
|
||||
final UnknownPacket unknownPacket = (UnknownPacket) packet;
|
||||
if (unknownPacket.packetId == this.chatSessionUpdateId && this.proxyConnection.getChannel().attr(MCPipeline.ENCRYPTION_ATTRIBUTE_KEY).get() == null) {
|
||||
return false;
|
||||
}
|
||||
} else if (packet instanceof C2SLoginHelloPacket1_7) {
|
||||
if (this.loginState != LoginState.FIRST_PACKET) throw CloseAndReturn.INSTANCE;
|
||||
this.loginState = LoginState.SENT_HELLO;
|
||||
final C2SLoginHelloPacket1_7 loginHelloPacket = (C2SLoginHelloPacket1_7) packet;
|
||||
|
||||
if (packet instanceof C2SLoginHelloPacket1_19) {
|
||||
final C2SLoginHelloPacket1_19 packet1_19 = (C2SLoginHelloPacket1_19) packet;
|
||||
if (packet1_19.expiresAt != null && packet1_19.expiresAt.isBefore(Instant.now())) {
|
||||
throw new IllegalStateException("Expired public key");
|
||||
}
|
||||
}
|
||||
|
||||
proxyConnection.setLoginHelloPacket(loginHelloPacket);
|
||||
if (packet instanceof C2SLoginHelloPacket1_19_3) {
|
||||
proxyConnection.setGameProfile(new GameProfile(((C2SLoginHelloPacket1_19_3) packet).uuid, loginHelloPacket.name));
|
||||
} else {
|
||||
proxyConnection.setGameProfile(new GameProfile(null, loginHelloPacket.name));
|
||||
}
|
||||
|
||||
if (Options.ONLINE_MODE) {
|
||||
this.proxyConnection.getC2P().writeAndFlush(new S2CLoginKeyPacket1_8("", KEY_PAIR.getPublic().getEncoded(), this.verifyToken)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
} else {
|
||||
ExternalInterface.fillPlayerData(this.proxyConnection);
|
||||
this.proxyConnection.getChannel().writeAndFlush(this.proxyConnection.getLoginHelloPacket()).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
|
||||
return false;
|
||||
} else if (packet instanceof C2SLoginKeyPacket1_7) {
|
||||
if (this.loginState != LoginState.SENT_HELLO) throw CloseAndReturn.INSTANCE;
|
||||
this.loginState = LoginState.SENT_KEY;
|
||||
final C2SLoginKeyPacket1_7 loginKeyPacket = (C2SLoginKeyPacket1_7) packet;
|
||||
|
||||
if (loginKeyPacket.encryptedNonce != null) {
|
||||
if (!Arrays.equals(this.verifyToken, CryptUtil.decryptData(KEY_PAIR.getPrivate(), loginKeyPacket.encryptedNonce))) {
|
||||
Logger.u_err("auth", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Invalid verify token");
|
||||
this.proxyConnection.kickClient("§cInvalid verify token!");
|
||||
}
|
||||
} else {
|
||||
final C2SLoginKeyPacket1_19 keyPacket = (C2SLoginKeyPacket1_19) packet;
|
||||
final C2SLoginHelloPacket1_19 helloPacket = (C2SLoginHelloPacket1_19) this.proxyConnection.getLoginHelloPacket();
|
||||
if (helloPacket.key == null || !CryptUtil.verifySignedNonce(helloPacket.key, this.verifyToken, keyPacket.salt, keyPacket.signature)) {
|
||||
Logger.u_err("auth", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Invalid verify token");
|
||||
this.proxyConnection.kickClient("§cInvalid verify token!");
|
||||
}
|
||||
}
|
||||
|
||||
final SecretKey secretKey = CryptUtil.decryptSecretKey(KEY_PAIR.getPrivate(), loginKeyPacket.encryptedSecretKey);
|
||||
this.proxyConnection.getC2P().attr(MCPipeline.ENCRYPTION_ATTRIBUTE_KEY).set(new AESEncryption(secretKey));
|
||||
|
||||
final String userName = this.proxyConnection.getGameProfile().getName();
|
||||
|
||||
try {
|
||||
final String serverHash = new BigInteger(CryptUtil.computeServerIdHash("", KEY_PAIR.getPublic(), secretKey)).toString(16);
|
||||
final GameProfile mojangProfile = AuthLibServices.SESSION_SERVICE.hasJoinedServer(this.proxyConnection.getGameProfile(), serverHash, null);
|
||||
if (mojangProfile == null) {
|
||||
Logger.u_err("auth", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Invalid session");
|
||||
this.proxyConnection.kickClient("§cInvalid session! Please restart minecraft (and the launcher) and try again.");
|
||||
} else {
|
||||
this.proxyConnection.setGameProfile(mojangProfile);
|
||||
}
|
||||
Logger.u_info("auth", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Authenticated as " + this.proxyConnection.getGameProfile().getId().toString());
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Failed to make session request for user '" + userName + "'!", e);
|
||||
}
|
||||
|
||||
ExternalInterface.fillPlayerData(this.proxyConnection);
|
||||
this.proxyConnection.getChannel().writeAndFlush(this.proxyConnection.getLoginHelloPacket()).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleP2S(IPacket packet, List<ChannelFutureListener> listeners) throws GeneralSecurityException, ExecutionException, InterruptedException {
|
||||
if (packet instanceof S2CLoginKeyPacket1_7) {
|
||||
final S2CLoginKeyPacket1_7 loginKeyPacket = (S2CLoginKeyPacket1_7) packet;
|
||||
|
||||
final PublicKey publicKey = CryptUtil.decodeRsaPublicKey(loginKeyPacket.publicKey);
|
||||
final SecretKey secretKey = CryptUtil.generateSecretKey();
|
||||
final String serverHash = new BigInteger(CryptUtil.computeServerIdHash(loginKeyPacket.serverId, publicKey, secretKey)).toString(16);
|
||||
|
||||
boolean auth = true;
|
||||
if (this.proxyConnection.getServerVersion().isOlderThanOrEqualTo(VersionEnum.r1_6_4)) {
|
||||
auth = this.proxyConnection.getUserConnection().get(ProtocolMetadataStorage.class).authenticate;
|
||||
}
|
||||
if (auth) {
|
||||
ExternalInterface.joinServer(serverHash, this.proxyConnection);
|
||||
}
|
||||
|
||||
final byte[] encryptedSecretKey = CryptUtil.encryptData(publicKey, secretKey.getEncoded());
|
||||
final byte[] encryptedNonce = CryptUtil.encryptData(publicKey, loginKeyPacket.nonce);
|
||||
|
||||
final C2SLoginKeyPacket1_19_3 loginKey = new C2SLoginKeyPacket1_19_3(encryptedSecretKey, encryptedNonce);
|
||||
if (this.proxyConnection.getServerVersion().isNewerThanOrEqualTo(VersionEnum.r1_19) && this.proxyConnection.getLoginHelloPacket() instanceof C2SLoginHelloPacket1_19 && ((C2SLoginHelloPacket1_19) this.proxyConnection.getLoginHelloPacket()).key != null) {
|
||||
ExternalInterface.signNonce(loginKeyPacket.nonce, loginKey, this.proxyConnection);
|
||||
}
|
||||
this.proxyConnection.getChannel().writeAndFlush(loginKey).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
|
||||
if (this.proxyConnection.getServerVersion().isNewerThanOrEqualTo(VersionEnum.r1_7_2tor1_7_5)) {
|
||||
this.proxyConnection.getChannel().attr(MCPipeline.ENCRYPTION_ATTRIBUTE_KEY).set(new AESEncryption(secretKey));
|
||||
} else {
|
||||
this.proxyConnection.setKeyForPreNettyEncryption(secretKey);
|
||||
}
|
||||
|
||||
return false;
|
||||
} else if (packet instanceof S2CLoginSuccessPacket1_7) {
|
||||
final S2CLoginSuccessPacket1_7 loginSuccessPacket = (S2CLoginSuccessPacket1_7) packet;
|
||||
|
||||
if (this.proxyConnection.getClientVersion().isNewerThanOrEqualTo(VersionEnum.r1_8)) {
|
||||
if (Options.COMPRESSION_THRESHOLD > -1 && this.proxyConnection.getC2P().attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).get() == -1) {
|
||||
this.proxyConnection.getChannel().config().setAutoRead(false);
|
||||
this.proxyConnection.getC2P().writeAndFlush(new S2CLoginCompressionPacket(Options.COMPRESSION_THRESHOLD)).addListeners(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE, (ChannelFutureListener) f -> {
|
||||
if (f.isSuccess()) {
|
||||
this.proxyConnection.getC2P().attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(Options.COMPRESSION_THRESHOLD);
|
||||
this.proxyConnection.getChannel().config().setAutoRead(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
final ConnectionState nextState = this.proxyConnection.getClientVersion().isNewerThanOrEqualTo(VersionEnum.r1_20_2) ? ConnectionState.CONFIGURATION : ConnectionState.PLAY;
|
||||
|
||||
this.proxyConnection.setGameProfile(new GameProfile(loginSuccessPacket.uuid, loginSuccessPacket.name));
|
||||
Logger.u_info("session", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Connected successfully! Switching to " + nextState + " state");
|
||||
|
||||
this.proxyConnection.getChannel().config().setAutoRead(false);
|
||||
listeners.add(f -> {
|
||||
if (f.isSuccess() && nextState != ConnectionState.CONFIGURATION) {
|
||||
this.proxyConnection.setConnectionState(nextState);
|
||||
this.proxyConnection.getChannel().config().setAutoRead(true);
|
||||
}
|
||||
});
|
||||
} else if (packet instanceof S2CLoginCompressionPacket) {
|
||||
final S2CLoginCompressionPacket loginCompressionPacket = (S2CLoginCompressionPacket) packet;
|
||||
|
||||
this.proxyConnection.getChannel().attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(loginCompressionPacket.compressionThreshold);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2023 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.proxy.packethandler;
|
||||
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import net.raphimc.netminecraft.packet.IPacket;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class PacketHandler {
|
||||
|
||||
protected final ProxyConnection proxyConnection;
|
||||
|
||||
public PacketHandler(final ProxyConnection proxyConnection) {
|
||||
this.proxyConnection = proxyConnection;
|
||||
}
|
||||
|
||||
public boolean handleC2P(final IPacket packet, final List<ChannelFutureListener> listeners) throws Exception {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean handleP2S(final IPacket packet, final List<ChannelFutureListener> listeners) throws Exception {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2023 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.proxy.packethandler;
|
||||
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.libs.gson.JsonElement;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import net.raphimc.netminecraft.constants.MCPackets;
|
||||
import net.raphimc.netminecraft.packet.IPacket;
|
||||
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||
import net.raphimc.netminecraft.packet.UnknownPacket;
|
||||
import net.raphimc.vialoader.util.VersionEnum;
|
||||
import net.raphimc.viaproxy.cli.options.Options;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ResourcePackPacketHandler extends PacketHandler {
|
||||
|
||||
private final int joinGameId;
|
||||
|
||||
public ResourcePackPacketHandler(ProxyConnection proxyConnection) {
|
||||
super(proxyConnection);
|
||||
|
||||
this.joinGameId = MCPackets.S2C_JOIN_GAME.getId(this.proxyConnection.getClientVersion().getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleP2S(IPacket packet, List<ChannelFutureListener> listeners) {
|
||||
if (packet instanceof UnknownPacket) {
|
||||
final UnknownPacket unknownPacket = (UnknownPacket) packet;
|
||||
if (unknownPacket.packetId == this.joinGameId) {
|
||||
listeners.add(f -> {
|
||||
if (f.isSuccess()) {
|
||||
this.sendResourcePack();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void sendResourcePack() {
|
||||
if (Options.RESOURCE_PACK_URL != null) {
|
||||
this.proxyConnection.getChannel().eventLoop().schedule(() -> {
|
||||
if (this.proxyConnection.getClientVersion().isNewerThanOrEqualTo(VersionEnum.r1_8)) {
|
||||
final ByteBuf resourcePackPacket = Unpooled.buffer();
|
||||
PacketTypes.writeVarInt(resourcePackPacket, MCPackets.S2C_RESOURCE_PACK.getId(this.proxyConnection.getClientVersion().getVersion()));
|
||||
PacketTypes.writeString(resourcePackPacket, Options.RESOURCE_PACK_URL); // url
|
||||
PacketTypes.writeString(resourcePackPacket, ""); // hash
|
||||
if (this.proxyConnection.getClientVersion().isNewerThanOrEqualTo(VersionEnum.r1_17)) {
|
||||
resourcePackPacket.writeBoolean(Via.getConfig().isForcedUse1_17ResourcePack()); // required
|
||||
final JsonElement promptMessage = Via.getConfig().get1_17ResourcePackPrompt();
|
||||
if (promptMessage != null) {
|
||||
resourcePackPacket.writeBoolean(true); // has message
|
||||
PacketTypes.writeString(resourcePackPacket, promptMessage.toString()); // message
|
||||
} else {
|
||||
resourcePackPacket.writeBoolean(false); // has message
|
||||
}
|
||||
}
|
||||
this.proxyConnection.getC2P().writeAndFlush(resourcePackPacket).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
} else if (this.proxyConnection.getClientVersion().isNewerThanOrEqualTo(VersionEnum.r1_7_2tor1_7_5)) {
|
||||
final byte[] data = Options.RESOURCE_PACK_URL.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
final ByteBuf customPayloadPacket = Unpooled.buffer();
|
||||
PacketTypes.writeVarInt(customPayloadPacket, MCPackets.S2C_PLUGIN_MESSAGE.getId(this.proxyConnection.getClientVersion().getVersion()));
|
||||
PacketTypes.writeString(customPayloadPacket, "MC|RPack"); // channel
|
||||
customPayloadPacket.writeShort(data.length); // length
|
||||
customPayloadPacket.writeBytes(data); // data
|
||||
this.proxyConnection.getC2P().writeAndFlush(customPayloadPacket).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
}, 250, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2023 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.proxy.packethandler;
|
||||
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import net.raphimc.netminecraft.packet.IPacket;
|
||||
import net.raphimc.netminecraft.packet.impl.status.S2CStatusPongPacket;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class StatusPacketHandler extends PacketHandler {
|
||||
|
||||
public StatusPacketHandler(ProxyConnection proxyConnection) {
|
||||
super(proxyConnection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleP2S(IPacket packet, List<ChannelFutureListener> listeners) {
|
||||
if (packet instanceof S2CStatusPongPacket) {
|
||||
listeners.add(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy
|
||||
* Copyright (C) 2023 RK_01/RaphiMC and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.raphimc.viaproxy.proxy.packethandler;
|
||||
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import net.raphimc.netminecraft.constants.ConnectionState;
|
||||
import net.raphimc.netminecraft.packet.IPacket;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class UnexpectedPacketHandler extends PacketHandler {
|
||||
|
||||
public UnexpectedPacketHandler(ProxyConnection proxyConnection) {
|
||||
super(proxyConnection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleC2P(IPacket packet, List<ChannelFutureListener> listeners) {
|
||||
final ConnectionState connectionState = this.proxyConnection.getConnectionState();
|
||||
if (connectionState.equals(ConnectionState.HANDSHAKING)) {
|
||||
throw new IllegalStateException("Unexpected packet in " + connectionState + " state");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -17,53 +17,27 @@
|
||||
*/
|
||||
package net.raphimc.viaproxy.proxy.proxy2server;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import com.viaversion.viaversion.libs.gson.JsonElement;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import com.google.common.collect.Lists;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import net.raphimc.netminecraft.constants.ConnectionState;
|
||||
import net.raphimc.netminecraft.constants.MCPackets;
|
||||
import net.raphimc.netminecraft.constants.MCPipeline;
|
||||
import net.raphimc.netminecraft.netty.crypto.AESEncryption;
|
||||
import net.raphimc.netminecraft.netty.crypto.CryptUtil;
|
||||
import net.raphimc.netminecraft.packet.IPacket;
|
||||
import net.raphimc.netminecraft.packet.PacketTypes;
|
||||
import net.raphimc.netminecraft.packet.UnknownPacket;
|
||||
import net.raphimc.netminecraft.packet.impl.login.*;
|
||||
import net.raphimc.netminecraft.packet.impl.status.S2CPingResponsePacket;
|
||||
import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.storage.ProtocolMetadataStorage;
|
||||
import net.raphimc.vialoader.util.VersionEnum;
|
||||
import net.raphimc.viaproxy.cli.options.Options;
|
||||
import net.raphimc.viaproxy.proxy.external_interface.ExternalInterface;
|
||||
import net.raphimc.viaproxy.proxy.packethandler.PacketHandler;
|
||||
import net.raphimc.viaproxy.proxy.session.ProxyConnection;
|
||||
import net.raphimc.viaproxy.proxy.util.ExceptionUtil;
|
||||
import net.raphimc.viaproxy.util.logging.Logger;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PublicKey;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.List;
|
||||
|
||||
public class Proxy2ServerHandler extends SimpleChannelInboundHandler<IPacket> {
|
||||
|
||||
private ProxyConnection proxyConnection;
|
||||
|
||||
private int joinGamePacketId = -1;
|
||||
|
||||
@Override
|
||||
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelRegistered(ctx);
|
||||
|
||||
this.proxyConnection = ProxyConnection.fromChannel(ctx.channel());
|
||||
|
||||
this.joinGamePacketId = MCPackets.S2C_JOIN_GAME.getId(this.proxyConnection.getClientVersion().getVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -81,31 +55,13 @@ public class Proxy2ServerHandler extends SimpleChannelInboundHandler<IPacket> {
|
||||
protected void channelRead0(ChannelHandlerContext ctx, IPacket packet) throws Exception {
|
||||
if (this.proxyConnection.isClosed()) return;
|
||||
|
||||
switch (this.proxyConnection.getConnectionState()) {
|
||||
case LOGIN:
|
||||
if (packet instanceof S2CLoginKeyPacket1_7) this.handleLoginKey((S2CLoginKeyPacket1_7) packet);
|
||||
else if (packet instanceof S2CLoginSuccessPacket1_7) this.handleLoginSuccess((S2CLoginSuccessPacket1_7) packet);
|
||||
else if (packet instanceof S2CLoginCompressionPacket) this.handleLoginCompression((S2CLoginCompressionPacket) packet);
|
||||
else break;
|
||||
|
||||
final List<ChannelFutureListener> listeners = Lists.newArrayList(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
for (PacketHandler packetHandler : this.proxyConnection.getPacketHandlers()) {
|
||||
if (!packetHandler.handleP2S(packet, listeners)) {
|
||||
return;
|
||||
case STATUS:
|
||||
if (packet instanceof S2CPingResponsePacket) {
|
||||
this.proxyConnection.getC2P().writeAndFlush(packet).addListeners(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE, ChannelFutureListener.CLOSE);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case PLAY:
|
||||
final UnknownPacket unknownPacket = (UnknownPacket) packet;
|
||||
if (unknownPacket.packetId == this.joinGamePacketId) {
|
||||
this.proxyConnection.getC2P().writeAndFlush(packet).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
this.sendResourcePack();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.proxyConnection.getC2P().writeAndFlush(packet).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
this.proxyConnection.getC2P().writeAndFlush(packet).addListeners(listeners.toArray(new ChannelFutureListener[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -113,95 +69,4 @@ public class Proxy2ServerHandler extends SimpleChannelInboundHandler<IPacket> {
|
||||
ExceptionUtil.handleNettyException(ctx, cause, this.proxyConnection);
|
||||
}
|
||||
|
||||
private void handleLoginKey(final S2CLoginKeyPacket1_7 packet) throws InterruptedException, GeneralSecurityException, ExecutionException {
|
||||
final PublicKey publicKey = CryptUtil.decodeRsaPublicKey(packet.publicKey);
|
||||
final SecretKey secretKey = CryptUtil.generateSecretKey();
|
||||
final String serverHash = new BigInteger(CryptUtil.computeServerIdHash(packet.serverId, publicKey, secretKey)).toString(16);
|
||||
|
||||
boolean auth = true;
|
||||
if (this.proxyConnection.getServerVersion().isOlderThanOrEqualTo(VersionEnum.r1_6_4)) {
|
||||
auth = this.proxyConnection.getUserConnection().get(ProtocolMetadataStorage.class).authenticate;
|
||||
}
|
||||
if (auth) {
|
||||
ExternalInterface.joinServer(serverHash, this.proxyConnection);
|
||||
}
|
||||
|
||||
final byte[] encryptedSecretKey = CryptUtil.encryptData(publicKey, secretKey.getEncoded());
|
||||
final byte[] encryptedNonce = CryptUtil.encryptData(publicKey, packet.nonce);
|
||||
|
||||
final C2SLoginKeyPacket1_19_3 loginKey = new C2SLoginKeyPacket1_19_3(encryptedSecretKey, encryptedNonce);
|
||||
if (this.proxyConnection.getServerVersion().isNewerThanOrEqualTo(VersionEnum.r1_19) && this.proxyConnection.getLoginHelloPacket() instanceof C2SLoginHelloPacket1_19 && ((C2SLoginHelloPacket1_19) this.proxyConnection.getLoginHelloPacket()).key != null) {
|
||||
ExternalInterface.signNonce(packet.nonce, loginKey, this.proxyConnection);
|
||||
}
|
||||
this.proxyConnection.getChannel().writeAndFlush(loginKey).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
|
||||
if (this.proxyConnection.getServerVersion().isNewerThanOrEqualTo(VersionEnum.r1_7_2tor1_7_5)) {
|
||||
this.proxyConnection.getChannel().attr(MCPipeline.ENCRYPTION_ATTRIBUTE_KEY).set(new AESEncryption(secretKey));
|
||||
} else {
|
||||
this.proxyConnection.setKeyForPreNettyEncryption(secretKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLoginSuccess(final S2CLoginSuccessPacket1_7 packet) {
|
||||
if (this.proxyConnection.getClientVersion().isNewerThanOrEqualTo(VersionEnum.r1_8)) {
|
||||
if (Options.COMPRESSION_THRESHOLD > -1 && this.proxyConnection.getC2P().attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).get() == -1) {
|
||||
this.proxyConnection.getChannel().config().setAutoRead(false);
|
||||
this.proxyConnection.getC2P().writeAndFlush(new S2CLoginCompressionPacket(Options.COMPRESSION_THRESHOLD)).addListeners(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE, (ChannelFutureListener) f -> {
|
||||
if (f.isSuccess()) {
|
||||
this.proxyConnection.getC2P().attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(Options.COMPRESSION_THRESHOLD);
|
||||
this.proxyConnection.getChannel().config().setAutoRead(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.proxyConnection.setGameProfile(new GameProfile(packet.uuid, packet.name));
|
||||
Logger.u_info("connect", this.proxyConnection.getC2P().remoteAddress(), this.proxyConnection.getGameProfile(), "Connected successfully! Switching to PLAY state");
|
||||
|
||||
this.proxyConnection.getChannel().config().setAutoRead(false);
|
||||
this.proxyConnection.getC2P().writeAndFlush(packet).addListeners(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE, (ChannelFutureListener) f -> {
|
||||
if (f.isSuccess()) {
|
||||
this.proxyConnection.setConnectionState(ConnectionState.PLAY);
|
||||
this.proxyConnection.getChannel().config().setAutoRead(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleLoginCompression(final S2CLoginCompressionPacket packet) {
|
||||
this.proxyConnection.getChannel().attr(MCPipeline.COMPRESSION_THRESHOLD_ATTRIBUTE_KEY).set(packet.compressionThreshold);
|
||||
}
|
||||
|
||||
private void sendResourcePack() {
|
||||
if (Options.RESOURCE_PACK_URL != null) {
|
||||
this.proxyConnection.getChannel().eventLoop().schedule(() -> {
|
||||
if (this.proxyConnection.getClientVersion().isNewerThanOrEqualTo(VersionEnum.r1_8)) {
|
||||
final ByteBuf resourcePackPacket = Unpooled.buffer();
|
||||
PacketTypes.writeVarInt(resourcePackPacket, MCPackets.S2C_RESOURCE_PACK.getId(this.proxyConnection.getClientVersion().getVersion()));
|
||||
PacketTypes.writeString(resourcePackPacket, Options.RESOURCE_PACK_URL); // url
|
||||
PacketTypes.writeString(resourcePackPacket, ""); // hash
|
||||
if (this.proxyConnection.getClientVersion().isNewerThanOrEqualTo(VersionEnum.r1_17)) {
|
||||
resourcePackPacket.writeBoolean(Via.getConfig().isForcedUse1_17ResourcePack()); // required
|
||||
final JsonElement promptMessage = Via.getConfig().get1_17ResourcePackPrompt();
|
||||
if (promptMessage != null) {
|
||||
resourcePackPacket.writeBoolean(true); // has message
|
||||
PacketTypes.writeString(resourcePackPacket, promptMessage.toString()); // message
|
||||
} else {
|
||||
resourcePackPacket.writeBoolean(false); // has message
|
||||
}
|
||||
}
|
||||
this.proxyConnection.getC2P().writeAndFlush(resourcePackPacket).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
} else if (this.proxyConnection.getClientVersion().isNewerThanOrEqualTo(VersionEnum.r1_7_2tor1_7_5)) {
|
||||
final byte[] data = Options.RESOURCE_PACK_URL.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
final ByteBuf customPayloadPacket = Unpooled.buffer();
|
||||
PacketTypes.writeVarInt(customPayloadPacket, MCPackets.S2C_PLUGIN_MESSAGE.getId(this.proxyConnection.getClientVersion().getVersion()));
|
||||
PacketTypes.writeString(customPayloadPacket, "MC|RPack"); // channel
|
||||
customPayloadPacket.writeShort(data.length); // length
|
||||
customPayloadPacket.writeBytes(data); // data
|
||||
this.proxyConnection.getC2P().writeAndFlush(customPayloadPacket).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
}
|
||||
}, 250, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -41,12 +41,15 @@ import net.raphimc.netminecraft.packet.registry.PacketRegistryUtil;
|
||||
import net.raphimc.netminecraft.util.ServerAddress;
|
||||
import net.raphimc.vialoader.util.VersionEnum;
|
||||
import net.raphimc.viaproxy.proxy.external_interface.OpenAuthModConstants;
|
||||
import net.raphimc.viaproxy.proxy.packethandler.PacketHandler;
|
||||
import net.raphimc.viaproxy.proxy.util.CloseAndReturn;
|
||||
import net.raphimc.viaproxy.util.logging.Logger;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.Key;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@ -59,6 +62,8 @@ public class ProxyConnection extends NetClient {
|
||||
public static final AttributeKey<ProxyConnection> PROXY_CONNECTION_ATTRIBUTE_KEY = AttributeKey.valueOf("proxy_connection");
|
||||
|
||||
private final Channel c2p;
|
||||
private final List<PacketHandler> packetHandlers = new ArrayList<>();
|
||||
|
||||
private final AtomicInteger customPayloadId = new AtomicInteger(0);
|
||||
private final Map<Integer, CompletableFuture<ByteBuf>> customPayloadListener = new ConcurrentHashMap<>();
|
||||
|
||||
@ -110,6 +115,10 @@ public class ProxyConnection extends NetClient {
|
||||
return this.c2p;
|
||||
}
|
||||
|
||||
public List<PacketHandler> getPacketHandlers() {
|
||||
return this.packetHandlers;
|
||||
}
|
||||
|
||||
public ServerAddress getServerAddress() {
|
||||
return this.serverAddress;
|
||||
}
|
||||
@ -176,6 +185,11 @@ public class ProxyConnection extends NetClient {
|
||||
this.getChannel().attr(MCPipeline.PACKET_REGISTRY_ATTRIBUTE_KEY).set(PacketRegistryUtil.getLoginRegistry(true, this.clientVersion.getVersion()));
|
||||
this.c2p.attr(MCPipeline.PACKET_REGISTRY_ATTRIBUTE_KEY).set(PacketRegistryUtil.getLoginRegistry(false, this.clientVersion.getVersion()));
|
||||
break;
|
||||
case CONFIGURATION:
|
||||
if (this.getChannel() != null)
|
||||
this.getChannel().attr(MCPipeline.PACKET_REGISTRY_ATTRIBUTE_KEY).set(PacketRegistryUtil.getConfigurationRegistry(true, this.clientVersion.getVersion()));
|
||||
this.c2p.attr(MCPipeline.PACKET_REGISTRY_ATTRIBUTE_KEY).set(PacketRegistryUtil.getConfigurationRegistry(false, this.clientVersion.getVersion()));
|
||||
break;
|
||||
case PLAY:
|
||||
if (this.getChannel() != null)
|
||||
this.getChannel().attr(MCPipeline.PACKET_REGISTRY_ATTRIBUTE_KEY).set(PacketRegistryUtil.getPlayRegistry(true, this.clientVersion.getVersion()));
|
||||
@ -241,15 +255,20 @@ public class ProxyConnection extends NetClient {
|
||||
Logger.u_err("kick", this.c2p.remoteAddress(), this.getGameProfile(), message.replaceAll("§.", ""));
|
||||
|
||||
final ChannelFuture future;
|
||||
if (this.connectionState == ConnectionState.LOGIN) {
|
||||
if (this.connectionState == ConnectionState.STATUS) {
|
||||
future = this.c2p.writeAndFlush(new S2CStatusResponsePacket("{\"players\":{\"max\":0,\"online\":0},\"description\":" + new JsonPrimitive(message) + ",\"version\":{\"protocol\":-1,\"name\":\"ViaProxy\"}}"));
|
||||
} else if (this.connectionState == ConnectionState.LOGIN) {
|
||||
future = this.c2p.writeAndFlush(new S2CLoginDisconnectPacket(messageToJson(message)));
|
||||
} else if (this.connectionState == ConnectionState.CONFIGURATION) {
|
||||
final ByteBuf disconnectPacket = Unpooled.buffer();
|
||||
PacketTypes.writeVarInt(disconnectPacket, MCPackets.S2C_CONFIG_DISCONNECT.getId(this.clientVersion.getVersion()));
|
||||
PacketTypes.writeString(disconnectPacket, messageToJson(message));
|
||||
future = this.c2p.writeAndFlush(disconnectPacket);
|
||||
} else if (this.connectionState == ConnectionState.PLAY) {
|
||||
final ByteBuf disconnectPacket = Unpooled.buffer();
|
||||
PacketTypes.writeVarInt(disconnectPacket, MCPackets.S2C_DISCONNECT.getId(this.clientVersion.getVersion()));
|
||||
PacketTypes.writeString(disconnectPacket, messageToJson(message));
|
||||
future = this.c2p.writeAndFlush(disconnectPacket);
|
||||
} else if (this.connectionState == ConnectionState.STATUS) {
|
||||
future = this.c2p.writeAndFlush(new S2CStatusResponsePacket("{\"players\":{\"max\":0,\"online\":0},\"description\":" + new JsonPrimitive(message) + ",\"version\":{\"protocol\":-1,\"name\":\"ViaProxy\"}}"));
|
||||
} else {
|
||||
future = this.c2p.newSucceededFuture();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user