3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-11-17 05:20:14 +01:00

Finished the port to new session handler stuff

Dieser Commit ist enthalten in:
Andrew Steinborn 2018-09-29 02:55:52 -04:00
Ursprung c7bd0d100e
Commit 79d566bcee
10 geänderte Dateien mit 400 neuen und 328 gelöschten Zeilen

Datei anzeigen

@ -6,7 +6,6 @@ import com.velocitypowered.api.command.CommandManager;
import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.CommandSource;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
public class VelocityCommandManager implements CommandManager { public class VelocityCommandManager implements CommandManager {
private final Map<String, Command> commands = new HashMap<>(); private final Map<String, Command> commands = new HashMap<>();
@ -57,6 +56,10 @@ public class VelocityCommandManager implements CommandManager {
} }
} }
public boolean hasCommand(String command) {
return commands.containsKey(command);
}
public Optional<List<String>> offerSuggestions(CommandSource source, String cmdLine) { public Optional<List<String>> offerSuggestions(CommandSource source, String cmdLine) {
Preconditions.checkNotNull(source, "source"); Preconditions.checkNotNull(source, "source");
Preconditions.checkNotNull(cmdLine, "cmdLine"); Preconditions.checkNotNull(cmdLine, "cmdLine");

Datei anzeigen

@ -69,12 +69,19 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof MinecraftPacket) { if (msg instanceof MinecraftPacket) {
if (sessionHandler.beforeHandle()) {
return;
}
MinecraftPacket pkt = (MinecraftPacket) msg; MinecraftPacket pkt = (MinecraftPacket) msg;
if (!pkt.handle(sessionHandler)) { if (!pkt.handle(sessionHandler)) {
sessionHandler.handleGeneric((MinecraftPacket) msg); sessionHandler.handleGeneric((MinecraftPacket) msg);
} }
} else if (msg instanceof ByteBuf) { } else if (msg instanceof ByteBuf) {
try { try {
if (sessionHandler.beforeHandle()) {
return;
}
sessionHandler.handleUnknown((ByteBuf) msg); sessionHandler.handleUnknown((ByteBuf) msg);
} finally { } finally {
ReferenceCountUtil.release(msg); ReferenceCountUtil.release(msg);

Datei anzeigen

@ -5,10 +5,16 @@ import com.velocitypowered.proxy.protocol.packet.*;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
public interface MinecraftSessionHandler { public interface MinecraftSessionHandler {
void handleGeneric(MinecraftPacket packet); default boolean beforeHandle() {
return false;
}
default void handleGeneric(MinecraftPacket packet) {
}
default void handleUnknown(ByteBuf buf) { default void handleUnknown(ByteBuf buf) {
// No-op: we'll release the buffer later.
} }
default void connected() { default void connected() {

Datei anzeigen

@ -17,10 +17,12 @@ import io.netty.buffer.ByteBuf;
public class BackendPlaySessionHandler implements MinecraftSessionHandler { public class BackendPlaySessionHandler implements MinecraftSessionHandler {
private final VelocityServer server; private final VelocityServer server;
private final VelocityServerConnection serverConn; private final VelocityServerConnection serverConn;
private final ClientPlaySessionHandler playerSessionHandler;
public BackendPlaySessionHandler(VelocityServer server, VelocityServerConnection serverConn) { public BackendPlaySessionHandler(VelocityServer server, VelocityServerConnection serverConn) {
this.server = server; this.server = server;
this.serverConn = serverConn; this.serverConn = serverConn;
this.playerSessionHandler = (ClientPlaySessionHandler) serverConn.getPlayer().getConnection().getSessionHandler();
} }
@Override @Override
@ -29,6 +31,93 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
serverConn.getServer().addPlayer(serverConn.getPlayer()); serverConn.getServer().addPlayer(serverConn.getPlayer());
} }
@Override
public boolean beforeHandle() {
if (!serverConn.getPlayer().isActive()) {
// Obsolete connection
serverConn.disconnect();
return true;
}
return false;
}
@Override
public boolean handle(KeepAlive packet) {
serverConn.setLastPingId(packet.getRandomId());
return false; // forwards on
}
@Override
public boolean handle(Disconnect packet) {
serverConn.disconnect();
serverConn.getPlayer().handleConnectionException(serverConn.getServer(), packet);
return true;
}
@Override
public boolean handle(JoinGame packet) {
playerSessionHandler.handleBackendJoinGame(packet);
return true;
}
@Override
public boolean handle(BossBar packet) {
switch (packet.getAction()) {
case 0: // add
playerSessionHandler.getServerBossBars().add(packet.getUuid());
break;
case 1: // remove
playerSessionHandler.getServerBossBars().remove(packet.getUuid());
break;
}
return false; // forward
}
@Override
public boolean handle(PluginMessage packet) {
if (!canForwardPluginMessage(packet)) {
return true;
}
if (PluginMessageUtil.isMCBrand(packet)) {
serverConn.getPlayer().getConnection().write(PluginMessageUtil.rewriteMCBrand(packet));
return true;
}
if (!serverConn.hasCompletedJoin() && packet.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) {
if (!serverConn.isLegacyForge()) {
serverConn.setLegacyForge(true);
// We must always reset the handshake before a modded connection is established if
// we haven't done so already.
serverConn.getPlayer().sendLegacyForgeHandshakeResetPacket();
}
// Always forward these messages during login
return false;
}
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
if (id == null) {
serverConn.getPlayer().getConnection().write(packet);
} else {
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), id, packet.getData());
server.getEventManager().fire(event)
.thenAcceptAsync(pme -> {
if (pme.getResult().isAllowed()) {
serverConn.getPlayer().getConnection().write(packet);
}
}, serverConn.getConnection().eventLoop());
}
return true;
}
@Override
public boolean handle(TabCompleteResponse packet) {
playerSessionHandler.handleTabCompleteResponse(packet);
return true;
}
@Override @Override
public void handleGeneric(MinecraftPacket packet) { public void handleGeneric(MinecraftPacket packet) {
if (!serverConn.getPlayer().isActive()) { if (!serverConn.getPlayer().isActive()) {
@ -38,69 +127,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
return; return;
} }
ClientPlaySessionHandler playerHandler = if (serverConn.hasCompletedJoin()) {
(ClientPlaySessionHandler) serverConn.getPlayer().getConnection().getSessionHandler();
if (packet instanceof KeepAlive) {
// Forward onto the player
serverConn.setLastPingId(((KeepAlive) packet).getRandomId());
serverConn.getPlayer().getConnection().write(packet);
} else if (packet instanceof Disconnect) {
Disconnect original = (Disconnect) packet;
serverConn.disconnect();
serverConn.getPlayer().handleConnectionException(serverConn.getServer(), original);
} else if (packet instanceof JoinGame) {
playerHandler.handleBackendJoinGame((JoinGame) packet);
} else if (packet instanceof BossBar) {
BossBar bossBar = (BossBar) packet;
switch (bossBar.getAction()) {
case 0: // add
playerHandler.getServerBossBars().add(bossBar.getUuid());
break;
case 1: // remove
playerHandler.getServerBossBars().remove(bossBar.getUuid());
break;
}
serverConn.getPlayer().getConnection().write(packet);
} else if (packet instanceof PluginMessage) {
PluginMessage pm = (PluginMessage) packet;
if (!canForwardPluginMessage(pm)) {
return;
}
if (PluginMessageUtil.isMCBrand(pm)) {
serverConn.getPlayer().getConnection().write(PluginMessageUtil.rewriteMCBrand(pm));
return;
}
if (!serverConn.hasCompletedJoin() && pm.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) {
if (!serverConn.isLegacyForge()) {
serverConn.setLegacyForge(true);
// We must always reset the handshake before a modded connection is established if
// we haven't done so already.
serverConn.getPlayer().sendLegacyForgeHandshakeResetPacket();
}
// Always forward these messages during login
serverConn.getPlayer().getConnection().write(pm);
return;
}
ChannelIdentifier id = server.getChannelRegistrar().getFromId(pm.getChannel());
if (id == null) {
serverConn.getPlayer().getConnection().write(pm);
} else {
PluginMessageEvent event = new PluginMessageEvent(serverConn, serverConn.getPlayer(), id, pm.getData());
server.getEventManager().fire(event)
.thenAcceptAsync(pme -> {
if (pme.getResult().isAllowed()) {
serverConn.getPlayer().getConnection().write(pm);
}
}, serverConn.getConnection().eventLoop());
}
} else if (packet instanceof TabCompleteResponse) {
playerHandler.handleTabCompleteResponse((TabCompleteResponse) packet);
} else if (serverConn.hasCompletedJoin()) {
// Just forward the packet on. We don't have anything to handle at this time. // Just forward the packet on. We don't have anything to handle at this time.
serverConn.getPlayer().getConnection().write(packet); serverConn.getPlayer().getConnection().write(packet);
} }

Datei anzeigen

@ -36,65 +36,77 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
} }
@Override @Override
public void handleGeneric(MinecraftPacket packet) { public boolean handle(EncryptionRequest packet) {
if (packet instanceof EncryptionRequest) { throw new IllegalStateException("Backend server is online-mode!");
throw new IllegalStateException("Backend server is online-mode!"); }
} else if (packet instanceof LoginPluginMessage) {
LoginPluginMessage message = (LoginPluginMessage) packet;
VelocityConfiguration configuration = server.getConfiguration();
if (configuration.getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN &&
message.getChannel().equals(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL)) {
LoginPluginResponse response = new LoginPluginResponse();
response.setSuccess(true);
response.setId(message.getId());
response.setData(createForwardingData(configuration.getForwardingSecret(),
serverConn.getPlayer().getRemoteAddress().getHostString(),
serverConn.getPlayer().getProfile()));
serverConn.getConnection().write(response);
informationForwarded = true;
} else {
// Don't understand
LoginPluginResponse response = new LoginPluginResponse();
response.setSuccess(false);
response.setId(message.getId());
response.setData(Unpooled.EMPTY_BUFFER);
serverConn.getConnection().write(response);
}
} else if (packet instanceof Disconnect) {
Disconnect disconnect = (Disconnect) packet;
// Do we have an outstanding notification? If so, fulfill it.
doNotify(ConnectionRequestResults.forDisconnect(disconnect));
serverConn.disconnect();
} else if (packet instanceof SetCompression) {
SetCompression sc = (SetCompression) packet;
serverConn.getConnection().setCompressionThreshold(sc.getThreshold());
} else if (packet instanceof ServerLoginSuccess) {
if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN && !informationForwarded) {
doNotify(ConnectionRequestResults.forDisconnect(
TextComponent.of("Your server did not send a forwarding request to the proxy. Is it set up correctly?")));
serverConn.disconnect();
return;
}
// The player has been logged on to the backend server. @Override
serverConn.getConnection().setState(StateRegistry.PLAY); public boolean handle(LoginPluginMessage packet) {
VelocityServerConnection existingConnection = serverConn.getPlayer().getConnectedServer(); VelocityConfiguration configuration = server.getConfiguration();
if (existingConnection == null) { if (configuration.getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN && packet.getChannel()
// Strap on the play session handler .equals(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL)) {
serverConn.getPlayer().getConnection().setSessionHandler(new ClientPlaySessionHandler(server, serverConn.getPlayer())); LoginPluginResponse response = new LoginPluginResponse();
} else { response.setSuccess(true);
// The previous server connection should become obsolete. response.setId(packet.getId());
// Before we remove it, if the server we are departing is modded, we must always reset the client state. response.setData(createForwardingData(configuration.getForwardingSecret(),
if (existingConnection.isLegacyForge()) { serverConn.getPlayer().getRemoteAddress().getHostString(),
serverConn.getPlayer().sendLegacyForgeHandshakeResetPacket(); serverConn.getPlayer().getProfile()));
} serverConn.getConnection().write(response);
existingConnection.disconnect(); informationForwarded = true;
} } else {
// Don't understand
doNotify(ConnectionRequestResults.SUCCESSFUL); LoginPluginResponse response = new LoginPluginResponse();
serverConn.getConnection().setSessionHandler(new BackendPlaySessionHandler(server, serverConn)); response.setSuccess(false);
serverConn.getPlayer().setConnectedServer(serverConn); response.setId(packet.getId());
response.setData(Unpooled.EMPTY_BUFFER);
serverConn.getConnection().write(response);
} }
return true;
}
@Override
public boolean handle(Disconnect packet) {
Disconnect disconnect = (Disconnect) packet;
// Do we have an outstanding notification? If so, fulfill it.
doNotify(ConnectionRequestResults.forDisconnect(disconnect));
serverConn.disconnect();
return true;
}
@Override
public boolean handle(SetCompression packet) {
serverConn.getConnection().setCompressionThreshold(packet.getThreshold());
return true;
}
@Override
public boolean handle(ServerLoginSuccess packet) {
if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN && !informationForwarded) {
doNotify(ConnectionRequestResults.forDisconnect(
TextComponent.of("Your server did not send a forwarding request to the proxy. Is it set up correctly?")));
serverConn.disconnect();
return true;
}
// The player has been logged on to the backend server.
serverConn.getConnection().setState(StateRegistry.PLAY);
VelocityServerConnection existingConnection = serverConn.getPlayer().getConnectedServer();
if (existingConnection == null) {
// Strap on the play session handler
serverConn.getPlayer().getConnection().setSessionHandler(new ClientPlaySessionHandler(server, serverConn.getPlayer()));
} else {
// The previous server connection should become obsolete.
// Before we remove it, if the server we are departing is modded, we must always reset the client state.
if (existingConnection.isLegacyForge()) {
serverConn.getPlayer().sendLegacyForgeHandshakeResetPacket();
}
existingConnection.disconnect();
}
doNotify(ConnectionRequestResults.SUCCESSFUL);
serverConn.getConnection().setSessionHandler(new BackendPlaySessionHandler(server, serverConn));
serverConn.getPlayer().setConnectedServer(serverConn);
return true;
} }
@Override @Override

Datei anzeigen

@ -48,6 +48,128 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
player.getConnection().write(register); player.getConnection().write(register);
} }
@Override
public boolean handle(KeepAlive packet) {
VelocityServerConnection serverConnection = player.getConnectedServer();
if (serverConnection != null && packet.getRandomId() == serverConnection.getLastPingId()) {
player.setPing(System.currentTimeMillis() - serverConnection.getLastPingSent());
serverConnection.getConnection().write(packet);
serverConnection.resetLastPingId();
}
return true;
}
@Override
public boolean handle(ClientSettings packet) {
player.setPlayerSettings(packet);
return false; // will forward onto the handleGeneric below, which will write the packet to the remote server
}
@Override
public boolean handle(Chat packet) {
String msg = packet.getMessage();
if (msg.startsWith("/")) {
try {
if (!server.getCommandManager().execute(player, msg.substring(1))) {
return false;
}
} catch (Exception e) {
logger.info("Exception occurred while running command for {}", player.getProfile().getName(), e);
player.sendMessage(TextComponent.of("An error occurred while running this command.", TextColor.RED));
return true;
}
} else {
VelocityServerConnection serverConnection = player.getConnectedServer();
if (serverConnection == null) {
return true;
}
PlayerChatEvent event = new PlayerChatEvent(player, msg);
server.getEventManager().fire(event)
.thenAcceptAsync(pme -> {
if (pme.getResult().equals(PlayerChatEvent.ChatResult.allowed())){
serverConnection.getConnection().write(packet);
} else if (pme.getResult().isAllowed() && pme.getResult().getMessage().isPresent()){
serverConnection.getConnection().write(Chat.createServerbound(pme.getResult().getMessage().get()));
}
}, serverConnection.getConnection().eventLoop());
}
return true;
}
@Override
public boolean handle(TabCompleteRequest packet) {
// Record the request so that the outstanding request can be augmented later.
if (!packet.isAssumeCommand() && packet.getCommand().startsWith("/")) {
int spacePos = packet.getCommand().indexOf(' ');
if (spacePos > 0) {
String cmd = packet.getCommand().substring(1, spacePos);
if (server.getCommandManager().hasCommand(cmd)) {
Optional<List<String>> suggestions = server.getCommandManager().offerSuggestions(player, packet.getCommand().substring(1));
if (suggestions.isPresent()) {
TabCompleteResponse resp = new TabCompleteResponse();
resp.getOffers().addAll(suggestions.get());
player.getConnection().write(resp);
return true;
}
}
}
}
outstandingTabComplete = packet;
return false;
}
@Override
public boolean handle(PluginMessage packet) {
if (PluginMessageUtil.isMCRegister(packet)) {
List<String> actuallyRegistered = new ArrayList<>();
List<String> channels = PluginMessageUtil.getChannels(packet);
for (String channel : channels) {
if (clientPluginMsgChannels.size() >= MAX_PLUGIN_CHANNELS &&
!clientPluginMsgChannels.contains(channel)) {
throw new IllegalStateException("Too many plugin message channels registered");
}
if (clientPluginMsgChannels.add(channel)) {
actuallyRegistered.add(channel);
}
}
if (actuallyRegistered.size() > 0) {
PluginMessage newRegisterPacket = PluginMessageUtil.constructChannelsPacket(player.getProtocolVersion(), actuallyRegistered);
player.getConnectedServer().getConnection().write(newRegisterPacket);
}
} else if (PluginMessageUtil.isMCUnregister(packet)) {
List<String> channels = PluginMessageUtil.getChannels(packet);
clientPluginMsgChannels.removeAll(channels);
player.getConnectedServer().getConnection().write(packet);
} else if (PluginMessageUtil.isMCBrand(packet)) {
player.getConnectedServer().getConnection().write(PluginMessageUtil.rewriteMCBrand(packet));
} else if (player.getConnectedServer().isLegacyForge() && !player.getConnectedServer().hasCompletedJoin()) {
if (packet.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) {
// Always forward the FML handshake to the remote server.
player.getConnectedServer().getConnection().write(packet);
} else {
// The client is trying to send messages too early. This is primarily caused by mods, but it's further
// aggravated by Velocity. To work around these issues, we will queue any non-FML handshake messages to
// be sent once the JoinGame packet has been received by the proxy.
loginPluginMessages.add(packet);
}
} else {
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
if (id == null) {
player.getConnectedServer().getConnection().write(packet);
} else {
PluginMessageEvent event = new PluginMessageEvent(player, player.getConnectedServer(), id, packet.getData());
server.getEventManager().fire(event)
.thenAcceptAsync(pme -> {
if (pme.getResult().isAllowed()) {
player.getConnectedServer().getConnection().write(packet);
}
}, player.getConnectedServer().getConnection().eventLoop());
}
}
return true;
}
@Override @Override
public void handleGeneric(MinecraftPacket packet) { public void handleGeneric(MinecraftPacket packet) {
VelocityServerConnection serverConnection = player.getConnectedServer(); VelocityServerConnection serverConnection = player.getConnectedServer();
@ -56,65 +178,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
return; return;
} }
if (packet instanceof KeepAlive) {
KeepAlive keepAlive = (KeepAlive) packet;
if (keepAlive.getRandomId() != serverConnection.getLastPingId()) {
// The last keep alive we got was probably from a different server. Let's ignore it, and hope the next
// ping is alright.
return;
}
player.setPing(System.currentTimeMillis() - serverConnection.getLastPingSent());
serverConnection.getConnection().write(packet);
serverConnection.resetLastPingId();
return;
}
if (packet instanceof ClientSettings) {
player.setPlayerSettings((ClientSettings) packet);
// forward it on
}
if (packet instanceof Chat) {
// Try to handle any commands on the proxy. If that fails, send it onto the client.
Chat chat = (Chat) packet;
String msg = ((Chat) packet).getMessage();
if (msg.startsWith("/")) {
try {
if (!server.getCommandManager().execute(player, msg.substring(1))) {
player.getConnectedServer().getConnection().write(chat);
}
} catch (Exception e) {
logger.info("Exception occurred while running command for {}", player.getProfile().getName(), e);
player.sendMessage(TextComponent.of("An error occurred while running this command.", TextColor.RED));
return;
}
} else {
PlayerChatEvent event = new PlayerChatEvent(player, msg);
server.getEventManager().fire(event)
.thenAcceptAsync(pme -> {
if (pme.getResult().equals(PlayerChatEvent.ChatResult.allowed())){
serverConnection.getConnection().write(chat);
} else if (pme.getResult().isAllowed() && pme.getResult().getMessage().isPresent()){
serverConnection.getConnection().write(Chat.createServerbound(pme.getResult().getMessage().get()));
}
}, serverConnection.getConnection().eventLoop());
}
return;
}
if (packet instanceof TabCompleteRequest) {
// Record the request so that the outstanding request can be augmented later.
outstandingTabComplete = (TabCompleteRequest) packet;
serverConnection.getConnection().write(packet);
}
if (packet instanceof PluginMessage) {
handleClientPluginMessage((PluginMessage) packet);
return;
}
// If we don't want to handle this packet, just forward it on. // If we don't want to handle this packet, just forward it on.
if (serverConnection.hasCompletedJoin()) { if (serverConnection.hasCompletedJoin()) {
logger.info("Will write {}", packet);
serverConnection.getConnection().write(packet); serverConnection.getConnection().write(packet);
} }
} }
@ -245,62 +311,15 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
return serverBossBars; return serverBossBars;
} }
private void handleClientPluginMessage(PluginMessage packet) {
if (PluginMessageUtil.isMCRegister(packet)) {
List<String> actuallyRegistered = new ArrayList<>();
List<String> channels = PluginMessageUtil.getChannels(packet);
for (String channel : channels) {
if (clientPluginMsgChannels.size() >= MAX_PLUGIN_CHANNELS &&
!clientPluginMsgChannels.contains(channel)) {
throw new IllegalStateException("Too many plugin message channels registered");
}
if (clientPluginMsgChannels.add(channel)) {
actuallyRegistered.add(channel);
}
}
if (actuallyRegistered.size() > 0) {
PluginMessage newRegisterPacket = PluginMessageUtil.constructChannelsPacket(player.getProtocolVersion(), actuallyRegistered);
player.getConnectedServer().getConnection().write(newRegisterPacket);
}
} else if (PluginMessageUtil.isMCUnregister(packet)) {
List<String> channels = PluginMessageUtil.getChannels(packet);
clientPluginMsgChannels.removeAll(channels);
player.getConnectedServer().getConnection().write(packet);
} else if (PluginMessageUtil.isMCBrand(packet)) {
player.getConnectedServer().getConnection().write(PluginMessageUtil.rewriteMCBrand(packet));
} else if (player.getConnectedServer().isLegacyForge() && !player.getConnectedServer().hasCompletedJoin()) {
if (packet.getChannel().equals(VelocityConstants.FORGE_LEGACY_HANDSHAKE_CHANNEL)) {
// Always forward the FML handshake to the remote server.
player.getConnectedServer().getConnection().write(packet);
} else {
// The client is trying to send messages too early. This is primarily caused by mods, but it's further
// aggravated by Velocity. To work around these issues, we will queue any non-FML handshake messages to
// be sent once the JoinGame packet has been received by the proxy.
loginPluginMessages.add(packet);
}
} else {
ChannelIdentifier id = server.getChannelRegistrar().getFromId(packet.getChannel());
if (id == null) {
player.getConnectedServer().getConnection().write(packet);
} else {
PluginMessageEvent event = new PluginMessageEvent(player, player.getConnectedServer(), id, packet.getData());
server.getEventManager().fire(event)
.thenAcceptAsync(pme -> {
if (pme.getResult().isAllowed()) {
player.getConnectedServer().getConnection().write(packet);
}
}, player.getConnectedServer().getConnection().eventLoop());
}
}
}
public Set<String> getClientPluginMsgChannels() { public Set<String> getClientPluginMsgChannels() {
return clientPluginMsgChannels; return clientPluginMsgChannels;
} }
public void handleTabCompleteResponse(TabCompleteResponse response) { public void handleTabCompleteResponse(TabCompleteResponse response) {
logger.info("Got {}", response);
logger.info("Request {}", outstandingTabComplete);
if (outstandingTabComplete != null) { if (outstandingTabComplete != null) {
logger.info("HANDLING");
if (!outstandingTabComplete.isAssumeCommand()) { if (!outstandingTabComplete.isAssumeCommand()) {
String command = outstandingTabComplete.getCommand().substring(1); String command = outstandingTabComplete.getCommand().substring(1);
try { try {

Datei anzeigen

@ -117,7 +117,8 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
@Override @Override
public void handleUnknown(ByteBuf buf) { public void handleUnknown(ByteBuf buf) {
throw new IllegalStateException("Unknown data " + ByteBufUtil.hexDump(buf)); // what even is going on?
connection.close();
} }
private static class LegacyInboundConnection implements InboundConnection { private static class LegacyInboundConnection implements InboundConnection {

Datei anzeigen

@ -59,89 +59,94 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
} }
@Override @Override
public void handleGeneric(MinecraftPacket packet) { public boolean handle(ServerLogin packet) {
if (packet instanceof LoginPluginResponse) { this.login = packet;
LoginPluginResponse lpr = (LoginPluginResponse) packet; if (inbound.getProtocolVersion() >= ProtocolConstants.MINECRAFT_1_13) {
if (lpr.getId() == playerInfoId) { LoginPluginMessage message = new LoginPluginMessage();
if (lpr.isSuccess()) { playerInfoId = ThreadLocalRandom.current().nextInt();
// Uh oh, someone's trying to run Velocity behind Velocity. We don't want that happening. message.setId(playerInfoId);
inbound.closeWith(Disconnect.create( message.setChannel(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL);
TextComponent.of("Running Velocity behind Velocity isn't supported.", TextColor.RED) message.setData(Unpooled.EMPTY_BUFFER);
)); inbound.write(message);
} else { } else {
// Proceed with the regular login process. beginPreLogin();
beginPreLogin(); }
} return true;
} }
} else if (packet instanceof ServerLogin) {
this.login = (ServerLogin) packet;
if (inbound.getProtocolVersion() >= ProtocolConstants.MINECRAFT_1_13) { @Override
LoginPluginMessage message = new LoginPluginMessage(); public boolean handle(LoginPluginResponse packet) {
playerInfoId = ThreadLocalRandom.current().nextInt(); if (packet.getId() == playerInfoId) {
message.setId(playerInfoId); if (packet.isSuccess()) {
message.setChannel(VelocityConstants.VELOCITY_IP_FORWARDING_CHANNEL); // Uh oh, someone's trying to run Velocity behind Velocity. We don't want that happening.
message.setData(Unpooled.EMPTY_BUFFER); inbound.closeWith(Disconnect.create(
inbound.write(message); TextComponent.of("Running Velocity behind Velocity isn't supported.", TextColor.RED)
));
} else { } else {
// Proceed with the regular login process.
beginPreLogin(); beginPreLogin();
} }
} else if (packet instanceof EncryptionResponse) {
try {
KeyPair serverKeyPair = server.getServerKeyPair();
EncryptionResponse response = (EncryptionResponse) packet;
byte[] decryptedVerifyToken = EncryptionUtils.decryptRsa(serverKeyPair, response.getVerifyToken());
if (!Arrays.equals(verify, decryptedVerifyToken)) {
throw new IllegalStateException("Unable to successfully decrypt the verification token.");
}
byte[] decryptedSharedSecret = EncryptionUtils.decryptRsa(serverKeyPair, response.getSharedSecret());
String serverId = EncryptionUtils.generateServerId(decryptedSharedSecret, serverKeyPair.getPublic());
String playerIp = ((InetSocketAddress) inbound.getChannel().remoteAddress()).getHostString();
server.getHttpClient()
.get(new URL(String.format(MOJANG_SERVER_AUTH_URL, login.getUsername(), serverId, playerIp)))
.thenAcceptAsync(profileResponse -> {
if (inbound.isClosed()) {
// The player disconnected after we authenticated them.
return;
}
// Go ahead and enable encryption. Once the client sends EncryptionResponse, encryption is
// enabled.
try {
inbound.enableEncryption(decryptedSharedSecret);
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
if (profileResponse.getCode() == 200) {
// All went well, initialize the session.
initializePlayer(VelocityServer.GSON.fromJson(profileResponse.getBody(), GameProfile.class), true);
} else if (profileResponse.getCode() == 204) {
// Apparently an offline-mode user logged onto this online-mode proxy. The client has enabled
// encryption, so we need to do that as well.
logger.warn("An offline-mode client ({} from {}) tried to connect!", login.getUsername(), playerIp);
inbound.closeWith(Disconnect.create(TextComponent.of("This server only accepts connections from online-mode clients.")));
} else {
// Something else went wrong
logger.error("Got an unexpected error code {} whilst contacting Mojang to log in {} ({})",
profileResponse.getCode(), login.getUsername(), playerIp);
inbound.close();
}
}, inbound.eventLoop())
.exceptionally(exception -> {
logger.error("Unable to enable encryption", exception);
inbound.close();
return null;
});
} catch (GeneralSecurityException e) {
logger.error("Unable to enable encryption", e);
inbound.close();
} catch (MalformedURLException e) {
throw new AssertionError(e);
}
} }
return true;
}
@Override
public boolean handle(EncryptionResponse packet) {
try {
KeyPair serverKeyPair = server.getServerKeyPair();
EncryptionResponse response = (EncryptionResponse) packet;
byte[] decryptedVerifyToken = EncryptionUtils.decryptRsa(serverKeyPair, response.getVerifyToken());
if (!Arrays.equals(verify, decryptedVerifyToken)) {
throw new IllegalStateException("Unable to successfully decrypt the verification token.");
}
byte[] decryptedSharedSecret = EncryptionUtils.decryptRsa(serverKeyPair, response.getSharedSecret());
String serverId = EncryptionUtils.generateServerId(decryptedSharedSecret, serverKeyPair.getPublic());
String playerIp = ((InetSocketAddress) inbound.getChannel().remoteAddress()).getHostString();
server.getHttpClient()
.get(new URL(String.format(MOJANG_SERVER_AUTH_URL, login.getUsername(), serverId, playerIp)))
.thenAcceptAsync(profileResponse -> {
if (inbound.isClosed()) {
// The player disconnected after we authenticated them.
return;
}
// Go ahead and enable encryption. Once the client sends EncryptionResponse, encryption is
// enabled.
try {
inbound.enableEncryption(decryptedSharedSecret);
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
if (profileResponse.getCode() == 200) {
// All went well, initialize the session.
initializePlayer(VelocityServer.GSON.fromJson(profileResponse.getBody(), GameProfile.class), true);
} else if (profileResponse.getCode() == 204) {
// Apparently an offline-mode user logged onto this online-mode proxy. The client has enabled
// encryption, so we need to do that as well.
logger.warn("An offline-mode client ({} from {}) tried to connect!", login.getUsername(), playerIp);
inbound.closeWith(Disconnect.create(TextComponent.of("This server only accepts connections from online-mode clients.")));
} else {
// Something else went wrong
logger.error("Got an unexpected error code {} whilst contacting Mojang to log in {} ({})",
profileResponse.getCode(), login.getUsername(), playerIp);
inbound.close();
}
}, inbound.eventLoop())
.exceptionally(exception -> {
logger.error("Unable to enable encryption", exception);
inbound.close();
return null;
});
} catch (GeneralSecurityException e) {
logger.error("Unable to enable encryption", e);
inbound.close();
} catch (MalformedURLException e) {
throw new AssertionError(e);
}
return true;
} }
private void beginPreLogin() { private void beginPreLogin() {

Datei anzeigen

@ -1,6 +1,5 @@
package com.velocitypowered.proxy.connection.client; package com.velocitypowered.proxy.connection.client;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.event.proxy.ProxyPingEvent; import com.velocitypowered.api.event.proxy.ProxyPingEvent;
import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.InboundConnection;
@ -9,13 +8,11 @@ import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.config.VelocityConfiguration; import com.velocitypowered.proxy.config.VelocityConfiguration;
import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.ProtocolConstants;
import com.velocitypowered.proxy.protocol.packet.StatusPing; import com.velocitypowered.proxy.protocol.packet.StatusPing;
import com.velocitypowered.proxy.protocol.packet.StatusRequest; import com.velocitypowered.proxy.protocol.packet.StatusRequest;
import com.velocitypowered.proxy.protocol.packet.StatusResponse; import com.velocitypowered.proxy.protocol.packet.StatusResponse;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
public class StatusSessionHandler implements MinecraftSessionHandler { public class StatusSessionHandler implements MinecraftSessionHandler {
private final VelocityServer server; private final VelocityServer server;
@ -29,19 +26,15 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
} }
@Override @Override
public void handleGeneric(MinecraftPacket packet) { public boolean handle(StatusPing packet) {
Preconditions.checkArgument(packet instanceof StatusPing || packet instanceof StatusRequest, connection.closeWith(packet);
"Unrecognized packet type " + packet.getClass().getName()); return true;
}
if (packet instanceof StatusPing) {
// Just send back the client's packet, no processing to do here.
connection.closeWith(packet);
return;
}
@Override
public boolean handle(StatusRequest packet) {
VelocityConfiguration configuration = server.getConfiguration(); VelocityConfiguration configuration = server.getConfiguration();
// Status request
int shownVersion = ProtocolConstants.isSupported(connection.getProtocolVersion()) ? connection.getProtocolVersion() : int shownVersion = ProtocolConstants.isSupported(connection.getProtocolVersion()) ? connection.getProtocolVersion() :
ProtocolConstants.MAXIMUM_GENERIC_VERSION; ProtocolConstants.MAXIMUM_GENERIC_VERSION;
ServerPing initialPing = new ServerPing( ServerPing initialPing = new ServerPing(
@ -59,10 +52,12 @@ public class StatusSessionHandler implements MinecraftSessionHandler {
response.setStatus(VelocityServer.GSON.toJson(event.getPing())); response.setStatus(VelocityServer.GSON.toJson(event.getPing()));
connection.write(response); connection.write(response);
}, connection.eventLoop()); }, connection.eventLoop());
return true;
} }
@Override @Override
public void handleUnknown(ByteBuf buf) { public void handleUnknown(ByteBuf buf) {
throw new IllegalStateException("Unknown data " + ByteBufUtil.hexDump(buf)); // what even is going on?
connection.close();
} }
} }

Datei anzeigen

@ -1,12 +1,10 @@
package com.velocitypowered.proxy.server.ping; package com.velocitypowered.proxy.server.ping;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerPing; import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.ProtocolConstants;
import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.StateRegistry;
import com.velocitypowered.proxy.protocol.packet.Handshake; import com.velocitypowered.proxy.protocol.packet.Handshake;
@ -42,15 +40,14 @@ public class PingSessionHandler implements MinecraftSessionHandler {
} }
@Override @Override
public void handleGeneric(MinecraftPacket packet) { public boolean handle(StatusResponse packet) {
Preconditions.checkState(packet instanceof StatusResponse, "Did not get status response back from connection");
// All good! // All good!
completed = true; completed = true;
connection.close(); connection.close();
ServerPing ping = VelocityServer.GSON.fromJson(((StatusResponse) packet).getStatus(), ServerPing.class); ServerPing ping = VelocityServer.GSON.fromJson(((StatusResponse) packet).getStatus(), ServerPing.class);
result.complete(ping); result.complete(ping);
return true;
} }
@Override @Override