This commit is contained in:
catfoolyou 2025-02-25 12:32:58 -05:00
parent cf21caabb0
commit 415b09b03f
8 changed files with 131 additions and 191 deletions

View File

@ -18,14 +18,7 @@ public class ServerConnection implements Server
private final BungeeServerInfo info; private final BungeeServerInfo info;
private boolean isObsolete; private boolean isObsolete;
private Unsafe unsafe = new Unsafe() private final Connection.Unsafe unsafe;
{
@Override
public void sendPacket(DefinedPacket packet)
{
ch.write( packet );
}
};
@Override @Override
public void sendData(String channel, byte[] data) public void sendData(String channel, byte[] data)
@ -34,20 +27,15 @@ public class ServerConnection implements Server
} }
@Override @Override
public synchronized void disconnect(String reason) public synchronized void disconnect(final String reason) {
{ if (this.ch != null && !this.ch.isClosed()) {
if ( !ch.isClosed() ) this.unsafe().sendPacket(new PacketFFKick(reason));
{ this.ch.getHandle().eventLoop().schedule((Runnable) new Runnable() {
// TODO: Can we just use a future here?
unsafe().sendPacket( new PacketFFKick( reason ) );
ch.getHandle().eventLoop().schedule( new Runnable()
{
@Override @Override
public void run() public void run() {
{ ServerConnection.this.ch.getHandle().close();
ch.getHandle().close();
} }
}, 100, TimeUnit.MILLISECONDS ); }, 100L, TimeUnit.MILLISECONDS);
} }
} }

View File

@ -10,6 +10,8 @@ import java.util.Objects;
import java.util.Queue; import java.util.Queue;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import io.netty.channel.ChannelHandler;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.config.ServerInfo;
@ -51,6 +53,8 @@ public class ServerConnector extends PacketHandler
private SecretKey secretkey; private SecretKey secretkey;
private boolean sentMessages; private boolean sentMessages;
private boolean protocolSupport = BungeeCord.getInstance().config.getProtocolSupport();
public ServerConnector(ProxyServer bungee, UserConnection user, BungeeServerInfo target){ public ServerConnector(ProxyServer bungee, UserConnection user, BungeeServerInfo target){
this.bungee = bungee; this.bungee = bungee;
this.user = user; this.user = user;
@ -79,177 +83,135 @@ public class ServerConnector extends PacketHandler
@Override @Override
public void connected(ChannelWrapper channel) throws Exception public void connected(ChannelWrapper channel) throws Exception
{ {
System.out.println("[ServerConnector] - connected");
this.ch = channel; this.ch = channel;
channel.write(this.user.getPendingConnection().getHandshake());
ByteArrayDataOutput out = ByteStreams.newDataOutput(); if (!protocolSupport) {
out.writeUTF( "Login" ); final ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF( user.getAddress().getHostString() ); out.writeUTF("Login");
out.writeInt( user.getAddress().getPort() ); out.writeUTF(this.user.getAddress().getHostString());
channel.write( new PacketFAPluginMessage( "BungeeCord", out.toByteArray() ) ); out.writeInt(this.user.getAddress().getPort());
channel.write(new PacketFAPluginMessage("BungeeCord", out.toByteArray()));
channel.write( user.getPendingConnection().getHandshake() ); if (this.user.getPendingConnection().getForgeLogin() == null) {
channel.write(PacketConstants.CLIENT_LOGIN);
// Skip encryption if we are not using Forge }
if ( user.getPendingConnection().getForgeLogin() == null )
{
channel.write( PacketConstants.CLIENT_LOGIN );
} }
} }
@Override @Override
public void disconnected(ChannelWrapper channel) throws Exception public void disconnected(ChannelWrapper channel) throws Exception
{ {
user.getPendingConnects().remove( target ); user.getPendingConnects().remove(this.target);
} }
@Override @Override
public void handle(Packet1Login login) throws Exception public void handle(final Packet1Login login) throws Exception {
{ System.out.println("[ServerConnector] - Handling LOGIN");
Preconditions.checkState( thisState == State.LOGIN, "Not exepcting LOGIN" ); Preconditions.checkState(this.thisState == State.LOGIN || this.thisState == State.ENCRYPT_REQUEST, (Object)"Not expecting LOGIN/ENCRYPT_REQUEST");
if (this.thisState == State.ENCRYPT_REQUEST) {
ServerConnection server = new ServerConnection( ch, target ); this.thisState = State.LOGIN;
ServerConnectedEvent event = new ServerConnectedEvent( user, server ); }
bungee.getPluginManager().callEvent( event ); final ServerConnection server = new ServerConnection(this.ch, this.target);
final ServerConnectedEvent event = new ServerConnectedEvent(this.user, server);
ch.write( BungeeCord.getInstance().registerChannels() ); this.bungee.getPluginManager().callEvent(event);
Queue<DefinedPacket> packetQueue = target.getPacketQueue(); this.ch.write(BungeeCord.getInstance().registerChannels());
synchronized ( packetQueue ) final Queue<DefinedPacket> packetQueue = this.target.getPacketQueue();
{ synchronized (packetQueue) {
while ( !packetQueue.isEmpty() ) while (!packetQueue.isEmpty()) {
{ this.ch.write(packetQueue.poll());
ch.write( packetQueue.poll() );
} }
} }
for (final PacketFAPluginMessage message : this.user.getPendingConnection().getRegisterMessages()) {
for ( PacketFAPluginMessage message : user.getPendingConnection().getRegisterMessages() ) this.ch.write(message);
{
ch.write( message );
} }
if ( !sentMessages ) if (!this.sentMessages) {
{ for (final PacketFAPluginMessage message : this.user.getPendingConnection().getLoginMessages()) {
for ( PacketFAPluginMessage message : user.getPendingConnection().getLoginMessages() ) this.ch.write(message);
{
ch.write( message );
} }
} }
if (this.user.getSettings() != null) {
if ( user.getSettings() != null ) this.ch.write(this.user.getSettings());
{
ch.write( user.getSettings() );
} }
synchronized (this.user.getSwitchMutex()) {
synchronized ( user.getSwitchMutex() ) if (this.user.getServer() == null) {
{ this.user.setClientEntityId(login.getEntityId());
if ( user.getServer() == null ) this.user.setServerEntityId(login.getEntityId());
{
// Once again, first connection
user.setClientEntityId( login.getEntityId() );
user.setServerEntityId( login.getEntityId() );
// Set tab list size, this sucks balls, TODO: what shall we do about packet mutability
Packet1Login modLogin; Packet1Login modLogin;
if ( ch.getHandle().pipeline().get( PacketDecoder.class ).getProtocol() == Forge.getInstance() ) if (((PacketDecoder)this.ch.getHandle().pipeline().get((Class)PacketDecoder.class)).getProtocol() == Forge.getInstance()) {
{ modLogin = new Forge1Login(login.getEntityId(), login.getLevelType(), login.getGameMode(), login.getDimension(), login.getDifficulty(), login.getUnused(), (byte)this.user.getPendingConnection().getListener().getTabListSize());
modLogin = new Forge1Login( login.getEntityId(), login.getLevelType(), login.getGameMode(), login.getDimension(), login.getDifficulty(), login.getUnused(),
(byte) user.getPendingConnection().getListener().getTabListSize() );
} else
{
modLogin = new Packet1Login( login.getEntityId(), login.getLevelType(), login.getGameMode(), (byte) login.getDimension(), login.getDifficulty(), login.getUnused(),
(byte) user.getPendingConnection().getListener().getTabListSize() );
} }
user.unsafe().sendPacket( modLogin ); else {
modLogin = new Packet1Login(login.getEntityId(), login.getLevelType(), login.getGameMode(), (byte)login.getDimension(), login.getDifficulty(), login.getUnused(), (byte)this.user.getPendingConnection().getListener().getTabListSize());
MinecraftOutput out = new MinecraftOutput();
out.writeStringUTF8WithoutLengthHeaderBecauseDinnerboneStuffedUpTheMCBrandPacket( ProxyServer.getInstance().getName() + " (" + ProxyServer.getInstance().getVersion() + ")" );
user.unsafe().sendPacket( new PacketFAPluginMessage( "MC|Brand", out.toArray() ) );
} else
{
user.getTabList().onServerChange();
Scoreboard serverScoreboard = user.getServerSentScoreboard();
for ( Objective objective : serverScoreboard.getObjectives() )
{
user.unsafe().sendPacket( new PacketCEScoreboardObjective( objective.getName(), objective.getValue(), (byte) 1 ) );
} }
for ( Team team : serverScoreboard.getTeams() ) this.user.unsafe().sendPacket(modLogin);
{ }
user.unsafe().sendPacket( new PacketD1Team( team.getName() ) ); else {
this.user.getTabList().onServerChange();
final Scoreboard serverScoreboard = this.user.getServerSentScoreboard();
for (final Objective objective : serverScoreboard.getObjectives()) {
this.user.unsafe().sendPacket(new PacketCEScoreboardObjective(objective.getName(), objective.getValue(), (byte)1));
}
for (final Team team : serverScoreboard.getTeams()) {
this.user.unsafe().sendPacket(new PacketD1Team(team.getName()));
} }
serverScoreboard.clear(); serverScoreboard.clear();
this.user.sendDimensionSwitch();
user.sendDimensionSwitch(); this.user.setServerEntityId(login.getEntityId());
this.user.unsafe().sendPacket(new Packet9Respawn(login.getDimension(), login.getDifficulty(), login.getGameMode(), (short)256, login.getLevelType()));
user.setServerEntityId( login.getEntityId() ); this.user.getServer().setObsolete(true);
user.unsafe().sendPacket( new Packet9Respawn( login.getDimension(), login.getDifficulty(), login.getGameMode(), (short) 256, login.getLevelType() ) ); this.user.getServer().disconnect("Quitting");
// Remove from old servers
user.getServer().setObsolete( true );
user.getServer().disconnect( "Quitting" );
} }
if (!this.user.isActive()) {
// TODO: Fix this? server.disconnect("Quitting");
if ( !user.isActive() ) this.bungee.getLogger().warning("No client connected for pending server!");
{
server.disconnect( "Quitting" );
// Silly server admins see stack trace and die
bungee.getLogger().warning( "No client connected for pending server!" );
return; return;
} }
this.target.addPlayer(this.user);
// Add to new server this.user.getPendingConnects().remove(this.target);
// TODO: Move this to the connected() method of DownstreamBridge this.user.setServer(server);
target.addPlayer( user ); ((HandlerBoss)this.ch.getHandle().pipeline().get((Class)HandlerBoss.class)).setHandler(new DownstreamBridge(this.bungee, this.user, server));
user.getPendingConnects().remove( target );
user.setServer( server );
ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new DownstreamBridge( bungee, user, server ) );
} }
this.bungee.getPluginManager().callEvent(new ServerSwitchEvent(this.user));
bungee.getPluginManager().callEvent( new ServerSwitchEvent( user ) ); this.thisState = State.FINISHED;
thisState = State.FINISHED;
throw new CancelSendSignal(); throw new CancelSendSignal();
} }
@Override @Override
public void handle(PacketFDEncryptionRequest encryptRequest) throws Exception public void handle(final PacketFDEncryptionRequest encryptRequest) throws Exception {
{ Preconditions.checkState(this.thisState == State.ENCRYPT_REQUEST, (Object)"Not expecting ENCRYPT_REQUEST");
Preconditions.checkState( thisState == State.ENCRYPT_REQUEST, "Not expecting ENCRYPT_REQUEST" ); if (protocolSupport) {
final ByteArrayDataOutput out = ByteStreams.newDataOutput();
// Only need to handle this if we want to use encryption out.writeUTF("Login");
if ( user.getPendingConnection().getForgeLogin() != null ) out.writeUTF(this.user.getAddress().getHostString());
{ out.writeInt(this.user.getAddress().getPort());
PublicKey publickey = EncryptionUtil.getPubkey( encryptRequest ); this.user.unsafe().sendPacket(new PacketFAPluginMessage("BungeeCord", out.toByteArray()));
if (this.user.getPendingConnection().getForgeLogin() == null) {
this.user.unsafe().sendPacket(PacketConstants.CLIENT_LOGIN);
}
}
if (this.user.getPendingConnection().getForgeLogin() != null) {
final PublicKey publickey = EncryptionUtil.getPubkey(encryptRequest);
this.secretkey = EncryptionUtil.getSecret(); this.secretkey = EncryptionUtil.getSecret();
final byte[] shared = EncryptionUtil.encrypt(publickey, this.secretkey.getEncoded());
byte[] shared = EncryptionUtil.encrypt( publickey, secretkey.getEncoded() ); final byte[] token = EncryptionUtil.encrypt(publickey, encryptRequest.getVerifyToken());
byte[] token = EncryptionUtil.encrypt( publickey, encryptRequest.getVerifyToken() ); this.ch.write(new PacketFCEncryptionResponse(shared, token));
final Cipher encrypt = EncryptionUtil.getCipher(1, this.secretkey);
ch.write( new PacketFCEncryptionResponse( shared, token ) ); this.ch.getHandle().pipeline().addBefore(PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.ENCRYPT_HANDLER, (ChannelHandler)new CipherEncoder(encrypt));
this.thisState = State.ENCRYPT_RESPONSE;
Cipher encrypt = EncryptionUtil.getCipher( Cipher.ENCRYPT_MODE, secretkey ); }
ch.addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) ); else {
this.thisState = State.LOGIN;
thisState = State.ENCRYPT_RESPONSE;
} else
{
thisState = State.LOGIN;
} }
} }
@Override @Override
public void handle(PacketFCEncryptionResponse encryptResponse) throws Exception public void handle(final PacketFCEncryptionResponse encryptResponse) throws Exception {
{ Preconditions.checkState(this.thisState == State.ENCRYPT_RESPONSE, (Object)"Not expecting ENCRYPT_RESPONSE");
Preconditions.checkState( thisState == State.ENCRYPT_RESPONSE, "Not expecting ENCRYPT_RESPONSE" ); final Cipher decrypt = EncryptionUtil.getCipher(2, this.secretkey);
this.ch.getHandle().pipeline().addBefore(PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, (ChannelHandler)new CipherDecoder(decrypt));
Cipher decrypt = EncryptionUtil.getCipher( Cipher.DECRYPT_MODE, secretkey ); this.ch.write(this.user.getPendingConnection().getForgeLogin());
ch.addBefore( PipelineUtils.PACKET_DECODE_HANDLER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) ); this.ch.write(PacketConstants.CLIENT_LOGIN);
this.thisState = State.LOGIN;
ch.write( user.getPendingConnection().getForgeLogin() );
ch.write( PacketConstants.CLIENT_LOGIN );
thisState = State.LOGIN;
} }
@Override @Override

View File

@ -177,14 +177,7 @@ public final class UserConnection implements ProxiedPlayer
return displayName; return displayName;
} }
private Unsafe unsafe = new Unsafe() private final Connection.Unsafe unsafe;
{
@Override
public void sendPacket(DefinedPacket packet)
{
ch.write( packet );
}
};
@ConstructorProperties({ "bungee", "ch", "name", "pendingConnection" }) @ConstructorProperties({ "bungee", "ch", "name", "pendingConnection" })
public UserConnection(final ProxyServer bungee, final ChannelWrapper ch, final String name, final InitialHandler pendingConnection) { public UserConnection(final ProxyServer bungee, final ChannelWrapper ch, final String name, final InitialHandler pendingConnection) {

View File

@ -111,7 +111,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection {
boolean skipEncryption = false; boolean skipEncryption = false;
if (handshake.getProcolVersion() == 78) { if (handshake.getProcolVersion() == 78) {
skipEncryption = true; skipEncryption = true;
this.handshake.swapProtocol((byte) 78); System.out.println("Skipping encryption...");
//this.handshake.swapProtocol((byte) 78);
}else if(handshake.getProcolVersion() > 78) { }else if(handshake.getProcolVersion() > 78) {
this.disconnect("this server does not support microsoft accounts"); this.disconnect("this server does not support microsoft accounts");
return; return;
@ -212,6 +213,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection {
@Override @Override
public void handle(final PacketFCEncryptionResponse encryptResponse) throws Exception { public void handle(final PacketFCEncryptionResponse encryptResponse) throws Exception {
System.out.println("Handle PacketFCEncryptionResponse");
Preconditions.checkState(this.thisState == State.ENCRYPT, (Object) "Not expecting ENCRYPT"); Preconditions.checkState(this.thisState == State.ENCRYPT, (Object) "Not expecting ENCRYPT");
this.sharedKey = EncryptionUtil.getSecret(encryptResponse, this.request); this.sharedKey = EncryptionUtil.getSecret(encryptResponse, this.request);
final Cipher decrypt = EncryptionUtil.getCipher(2, this.sharedKey); final Cipher decrypt = EncryptionUtil.getCipher(2, this.sharedKey);
@ -220,6 +222,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection {
} }
private void finish() throws GeneralSecurityException { private void finish() throws GeneralSecurityException {
System.out.println("Finish");
final ProxiedPlayer old = this.bungee.getPlayer(this.handshake.getUsername()); final ProxiedPlayer old = this.bungee.getPlayer(this.handshake.getUsername());
if (old != null) { if (old != null) {
old.disconnect(this.bungee.getTranslation("already_connected")); old.disconnect(this.bungee.getTranslation("already_connected"));
@ -254,6 +257,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection {
@Override @Override
public void handle(final PacketCDClientStatus clientStatus) throws Exception { public void handle(final PacketCDClientStatus clientStatus) throws Exception {
System.out.println("[InitialHandler] - PacketCDClientStatus");
Preconditions.checkState(this.thisState == State.LOGIN, (Object) "Not expecting LOGIN"); Preconditions.checkState(this.thisState == State.LOGIN, (Object) "Not expecting LOGIN");
final UserConnection userCon = new UserConnection(this.bungee, this.ch, this.getName(), this); final UserConnection userCon = new UserConnection(this.bungee, this.ch, this.getName(), this);
InetAddress ins = WebSocketProxy.localToRemote.get(this.ch.getHandle().remoteAddress()); InetAddress ins = WebSocketProxy.localToRemote.get(this.ch.getHandle().remoteAddress());

View File

@ -61,14 +61,14 @@ public class UpstreamBridge extends PacketHandler
public void handle(final byte[] buf) throws Exception { public void handle(final byte[] buf) throws Exception {
EntityMap.rewrite(Unpooled.wrappedBuffer(buf), this.con.getClientEntityId(), this.con.getServerEntityId()); EntityMap.rewrite(Unpooled.wrappedBuffer(buf), this.con.getClientEntityId(), this.con.getServerEntityId());
if (this.con.getServer() != null && this.con.getServer().getCh() != null) { if (this.con.getServer() != null && this.con.getServer().getCh() != null) {
this.con.getServer().getCh().write(buf); // Change to buf if its a problem this.con.getServer().getCh().write(buf);
} }
} }
@Override @Override
public void handle(Packet0KeepAlive alive) throws Exception public void handle(Packet0KeepAlive alive) throws Exception
{ {
if ( alive.getRandomId() == con.getSentPingId() ) if (alive.getRandomId() == con.getSentPingId())
{ {
int newPing = (int) ( System.currentTimeMillis() - con.getSentPingTime() ); int newPing = (int) ( System.currentTimeMillis() - con.getSentPingTime() );
con.getTabList().onPingChange( newPing ); con.getTabList().onPingChange( newPing );

View File

@ -177,7 +177,6 @@ public class WebSocketListener extends WebSocketServer {
@Override @Override
public void onMessage(WebSocket arg0, ByteBuffer arg1) { public void onMessage(WebSocket arg0, ByteBuffer arg1) {
System.out.println("[WebsocketListener] - onMessage called");
Object o = arg0.getAttachment(); Object o = arg0.getAttachment();
if(o == null || (o instanceof PendingSocket)) { if(o == null || (o instanceof PendingSocket)) {
InetAddress realAddr; InetAddress realAddr;
@ -210,7 +209,6 @@ public class WebSocketListener extends WebSocketServer {
} }
if(o != null) { if(o != null) {
if(o instanceof WebSocketProxy) { if(o instanceof WebSocketProxy) {
System.out.println("Instance of WebSocketProxy, sending packet");
((WebSocketProxy)o).sendPacket(arg1); ((WebSocketProxy)o).sendPacket(arg1);
}else { }else {
System.out.println("Closing websocket"); System.out.println("Closing websocket");

View File

@ -1,28 +1,23 @@
//
// Decompiled by Procyon v0.5.36
//
package net.md_5.bungee.netty; package net.md_5.bungee.netty;
import com.google.common.base.Preconditions;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
public class ChannelWrapper public class ChannelWrapper {
{
private final Channel ch; private final Channel ch;
public boolean isClosed() {
return closed;
}
private volatile boolean closed; private volatile boolean closed;
public ChannelWrapper(ChannelHandlerContext ctx) public ChannelWrapper(final ChannelHandlerContext ctx) {
{
this.ch = ctx.channel(); this.ch = ctx.channel();
} }
public synchronized void write(final Object packet) { public synchronized void write(final Object packet) { // This is a problem, the packets ARE being sent but arent coming to client
if (!this.closed) { if (!this.closed) {
System.out.println("[ChannelWrapper] - trying to send packet");
this.ch.write(packet); this.ch.write(packet);
} }
} }
@ -34,15 +29,11 @@ public class ChannelWrapper
} }
} }
public void addBefore(String baseName, String name, ChannelHandler handler) public Channel getHandle() {
{ return this.ch;
Preconditions.checkState( ch.eventLoop().inEventLoop(), "cannot add handler outside of event loop" );
//ch.pipeline().flush();
ch.pipeline().addBefore( baseName, name, handler );
} }
public Channel getHandle() public boolean isClosed() {
{ return this.closed;
return ch;
} }
} }

View File

@ -47,6 +47,7 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter {
} }
public void messageReceived(final ChannelHandlerContext ctx, final MessageList<Object> msgs) throws Exception { public void messageReceived(final ChannelHandlerContext ctx, final MessageList<Object> msgs) throws Exception {
System.out.println("[HandlerBoss] - Message (packet?) received");
for (final Object msg : msgs) { for (final Object msg : msgs) {
if (this.handler != null && ctx.channel().isActive()) { if (this.handler != null && ctx.channel().isActive()) {
if (msg instanceof PacketWrapper) { if (msg instanceof PacketWrapper) {
@ -64,6 +65,9 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter {
this.handler.handle((byte[]) msg); this.handler.handle((byte[]) msg);
} }
} }
else {
System.out.println("Handler null or channel down");
}
} }
} }