3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-12-24 23:30:26 +01:00

Consistently display disconnects.

Dieser Commit ist enthalten in:
Andrew Steinborn 2018-12-29 11:46:54 -05:00
Ursprung 256978fc15
Commit 10c440af83
6 geänderte Dateien mit 67 neuen und 47 gelöschten Zeilen

Datei anzeigen

@ -24,6 +24,7 @@ import com.velocitypowered.proxy.protocol.netty.MinecraftCompressDecoder;
import com.velocitypowered.proxy.protocol.netty.MinecraftCompressEncoder; import com.velocitypowered.proxy.protocol.netty.MinecraftCompressEncoder;
import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder;
import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
import com.velocitypowered.proxy.protocol.packet.Disconnect;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
@ -58,6 +59,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
private @Nullable MinecraftConnectionAssociation association; private @Nullable MinecraftConnectionAssociation association;
private final VelocityServer server; private final VelocityServer server;
private ConnectionType connectionType = ConnectionTypes.UNDETERMINED; private ConnectionType connectionType = ConnectionTypes.UNDETERMINED;
private boolean knownDisconnect = false;
/** /**
* Initializes a new {@link MinecraftConnection} instance. * Initializes a new {@link MinecraftConnection} instance.
@ -88,7 +90,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
sessionHandler.disconnected(); sessionHandler.disconnected();
} }
if (association != null) { if (association != null && !knownDisconnect) {
logger.info("{} has disconnected", association); logger.info("{} has disconnected", association);
} }
} }
@ -191,6 +193,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
*/ */
public void closeWith(Object msg) { public void closeWith(Object msg) {
if (channel.isActive()) { if (channel.isActive()) {
knownDisconnect = true;
channel.writeAndFlush(msg).addListener(ChannelFutureListener.CLOSE); channel.writeAndFlush(msg).addListener(ChannelFutureListener.CLOSE);
} }
} }

Datei anzeigen

@ -235,6 +235,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
@Override @Override
public void disconnect(Component reason) { public void disconnect(Component reason) {
logger.info("{} has disconnected: {}", this, ComponentSerializers.LEGACY.serialize(reason));
connection.closeWith(Disconnect.create(reason)); connection.closeWith(Disconnect.create(reason));
} }
@ -351,7 +352,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
if (nextServer.isPresent()) { if (nextServer.isPresent()) {
createConnectionRequest(nextServer.get()).fireAndForget(); createConnectionRequest(nextServer.get()).fireAndForget();
} else { } else {
connection.closeWith(Disconnect.create(friendlyReason)); disconnect(friendlyReason);
} }
} else { } else {
KickedFromServerEvent originalEvent = new KickedFromServerEvent(this, rs, kickReason, KickedFromServerEvent originalEvent = new KickedFromServerEvent(this, rs, kickReason,
@ -360,7 +361,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
.thenAcceptAsync(event -> { .thenAcceptAsync(event -> {
if (event.getResult() instanceof DisconnectPlayer) { if (event.getResult() instanceof DisconnectPlayer) {
DisconnectPlayer res = (DisconnectPlayer) event.getResult(); DisconnectPlayer res = (DisconnectPlayer) event.getResult();
connection.closeWith(Disconnect.create(res.getReason())); disconnect(res.getReason());
} else if (event.getResult() instanceof RedirectPlayer) { } else if (event.getResult() instanceof RedirectPlayer) {
RedirectPlayer res = (RedirectPlayer) event.getResult(); RedirectPlayer res = (RedirectPlayer) event.getResult();
createConnectionRequest(res.getServer()).fireAndForget(); createConnectionRequest(res.getServer()).fireAndForget();
@ -369,11 +370,11 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
if (event.kickedDuringServerConnect()) { if (event.kickedDuringServerConnect()) {
sendMessage(res.getMessage()); sendMessage(res.getMessage());
} else { } else {
connection.closeWith(Disconnect.create(res.getMessage())); disconnect(res.getMessage());
} }
} else { } else {
// In case someone gets creative, assume we want to disconnect the player. // In case someone gets creative, assume we want to disconnect the player.
connection.closeWith(Disconnect.create(friendlyReason)); disconnect(friendlyReason);
} }
}, connection.eventLoop()); }, connection.eventLoop());
} }

Datei anzeigen

@ -4,9 +4,9 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.velocitypowered.api.event.connection.ConnectionHandshakeEvent; import com.velocitypowered.api.event.connection.ConnectionHandshakeEvent;
import com.velocitypowered.api.event.proxy.ProxyPingEvent; import com.velocitypowered.api.event.proxy.ProxyPingEvent;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.server.ServerPing; import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.config.PlayerInfoForwarding; import com.velocitypowered.proxy.config.PlayerInfoForwarding;
import com.velocitypowered.proxy.config.VelocityConfiguration; import com.velocitypowered.proxy.config.VelocityConfiguration;
@ -75,6 +75,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
public boolean handle(Handshake handshake) { public boolean handle(Handshake handshake) {
InitialInboundConnection ic = new InitialInboundConnection(connection, InitialInboundConnection ic = new InitialInboundConnection(connection,
cleanVhost(handshake.getServerAddress()), handshake); cleanVhost(handshake.getServerAddress()), handshake);
connection.setAssociation(ic);
switch (handshake.getNextStatus()) { switch (handshake.getNextStatus()) {
case StateRegistry.STATUS_ID: case StateRegistry.STATUS_ID:
connection.setState(StateRegistry.STATUS); connection.setState(StateRegistry.STATUS);

Datei anzeigen

@ -3,11 +3,19 @@ package com.velocitypowered.proxy.connection.client;
import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
import com.velocitypowered.proxy.protocol.packet.Disconnect;
import com.velocitypowered.proxy.protocol.packet.Handshake; import com.velocitypowered.proxy.protocol.packet.Handshake;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.Optional; import java.util.Optional;
import net.kyori.text.Component;
import net.kyori.text.serializer.ComponentSerializers;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
class InitialInboundConnection implements InboundConnection { class InitialInboundConnection implements InboundConnection, MinecraftConnectionAssociation {
private static final Logger logger = LogManager.getLogger(InitialInboundConnection.class);
private final MinecraftConnection connection; private final MinecraftConnection connection;
private final String cleanedAddress; private final String cleanedAddress;
@ -39,4 +47,14 @@ class InitialInboundConnection implements InboundConnection {
public ProtocolVersion getProtocolVersion() { public ProtocolVersion getProtocolVersion() {
return connection.getProtocolVersion(); return connection.getProtocolVersion();
} }
@Override
public String toString() {
return "[initial connection] " + connection.getRemoteAddress().toString();
}
public void disconnect(Component reason) {
logger.info("{} has disconnected: {}", this, ComponentSerializers.LEGACY.serialize(reason));
connection.closeWith(Disconnect.create(reason));
}
} }

Datei anzeigen

@ -31,7 +31,6 @@ import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
import com.velocitypowered.proxy.protocol.packet.ServerLogin; import com.velocitypowered.proxy.protocol.packet.ServerLogin;
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess; import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
import com.velocitypowered.proxy.protocol.packet.SetCompression; import com.velocitypowered.proxy.protocol.packet.SetCompression;
import com.velocitypowered.proxy.util.EncryptionUtils;
import com.velocitypowered.proxy.util.VelocityMessages; import com.velocitypowered.proxy.util.VelocityMessages;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil; import io.netty.buffer.ByteBufUtil;
@ -57,26 +56,26 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
"https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s&ip=%s"; "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=%s&serverId=%s&ip=%s";
private final VelocityServer server; private final VelocityServer server;
private final MinecraftConnection inbound; private final MinecraftConnection mcConnection;
private final InboundConnection apiInbound; private final InitialInboundConnection inbound;
private @MonotonicNonNull ServerLogin login; private @MonotonicNonNull ServerLogin login;
private byte[] verify = EMPTY_BYTE_ARRAY; private byte[] verify = EMPTY_BYTE_ARRAY;
private int playerInfoId; private int playerInfoId;
private @MonotonicNonNull ConnectedPlayer connectedPlayer; private @MonotonicNonNull ConnectedPlayer connectedPlayer;
LoginSessionHandler(VelocityServer server, MinecraftConnection inbound, LoginSessionHandler(VelocityServer server, MinecraftConnection mcConnection,
InboundConnection apiInbound) { InitialInboundConnection inbound) {
this.server = Preconditions.checkNotNull(server, "server"); this.server = Preconditions.checkNotNull(server, "server");
this.mcConnection = Preconditions.checkNotNull(mcConnection, "mcConnection");
this.inbound = Preconditions.checkNotNull(inbound, "inbound"); this.inbound = Preconditions.checkNotNull(inbound, "inbound");
this.apiInbound = Preconditions.checkNotNull(apiInbound, "apiInbound");
} }
@Override @Override
public boolean handle(ServerLogin packet) { public boolean handle(ServerLogin packet) {
this.login = packet; this.login = packet;
if (inbound.getProtocolVersion().compareTo(MINECRAFT_1_13) >= 0) { if (mcConnection.getProtocolVersion().compareTo(MINECRAFT_1_13) >= 0) {
playerInfoId = ThreadLocalRandom.current().nextInt(); playerInfoId = ThreadLocalRandom.current().nextInt();
inbound.write(new LoginPluginMessage(playerInfoId, VELOCITY_IP_FORWARDING_CHANNEL, mcConnection.write(new LoginPluginMessage(playerInfoId, VELOCITY_IP_FORWARDING_CHANNEL,
Unpooled.EMPTY_BUFFER)); Unpooled.EMPTY_BUFFER));
} else { } else {
beginPreLogin(); beginPreLogin();
@ -89,7 +88,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
if (packet.getId() == playerInfoId) { if (packet.getId() == playerInfoId) {
if (packet.isSuccess()) { if (packet.isSuccess()) {
// Uh oh, someone's trying to run Velocity behind Velocity. We don't want that happening. // Uh oh, someone's trying to run Velocity behind Velocity. We don't want that happening.
inbound.closeWith(Disconnect.create(VelocityMessages.NO_PROXY_BEHIND_PROXY)); inbound.disconnect(VelocityMessages.NO_PROXY_BEHIND_PROXY);
} else { } else {
// Proceed with the regular login process. // Proceed with the regular login process.
beginPreLogin(); beginPreLogin();
@ -119,14 +118,14 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
byte[] decryptedSharedSecret = decryptRsa(serverKeyPair, packet.getSharedSecret()); byte[] decryptedSharedSecret = decryptRsa(serverKeyPair, packet.getSharedSecret());
String serverId = generateServerId(decryptedSharedSecret, serverKeyPair.getPublic()); String serverId = generateServerId(decryptedSharedSecret, serverKeyPair.getPublic());
String playerIp = ((InetSocketAddress) inbound.getRemoteAddress()).getHostString(); String playerIp = ((InetSocketAddress) mcConnection.getRemoteAddress()).getHostString();
String url = String.format(MOJANG_HASJOINED_URL, String url = String.format(MOJANG_HASJOINED_URL,
UrlEscapers.urlFormParameterEscaper().escape(login.getUsername()), serverId, UrlEscapers.urlFormParameterEscaper().escape(login.getUsername()), serverId,
UrlEscapers.urlFormParameterEscaper().escape(playerIp)); UrlEscapers.urlFormParameterEscaper().escape(playerIp));
server.getHttpClient() server.getHttpClient()
.get(new URL(url)) .get(new URL(url))
.thenAcceptAsync(profileResponse -> { .thenAcceptAsync(profileResponse -> {
if (inbound.isClosed()) { if (mcConnection.isClosed()) {
// The player disconnected after we authenticated them. // The player disconnected after we authenticated them.
return; return;
} }
@ -134,7 +133,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
// Go ahead and enable encryption. Once the client sends EncryptionResponse, encryption // Go ahead and enable encryption. Once the client sends EncryptionResponse, encryption
// is enabled. // is enabled.
try { try {
inbound.enableEncryption(decryptedSharedSecret); mcConnection.enableEncryption(decryptedSharedSecret);
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -144,25 +143,23 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
initializePlayer(GSON.fromJson(profileResponse.getBody(), GameProfile.class), true); initializePlayer(GSON.fromJson(profileResponse.getBody(), GameProfile.class), true);
} else if (profileResponse.getCode() == 204) { } else if (profileResponse.getCode() == 204) {
// Apparently an offline-mode user logged onto this online-mode proxy. // Apparently an offline-mode user logged onto this online-mode proxy.
logger.warn("An offline-mode client ({} from {}) tried to connect!", inbound.disconnect(VelocityMessages.ONLINE_MODE_ONLY);
login.getUsername(), playerIp);
inbound.closeWith(Disconnect.create(VelocityMessages.ONLINE_MODE_ONLY));
} else { } else {
// Something else went wrong // Something else went wrong
logger.error( logger.error(
"Got an unexpected error code {} whilst contacting Mojang to log in {} ({})", "Got an unexpected error code {} whilst contacting Mojang to log in {} ({})",
profileResponse.getCode(), login.getUsername(), playerIp); profileResponse.getCode(), login.getUsername(), playerIp);
inbound.close(); mcConnection.close();
} }
}, inbound.eventLoop()) }, mcConnection.eventLoop())
.exceptionally(exception -> { .exceptionally(exception -> {
logger.error("Unable to enable encryption", exception); logger.error("Unable to enable encryption", exception);
inbound.close(); mcConnection.close();
return null; return null;
}); });
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
logger.error("Unable to enable encryption", e); logger.error("Unable to enable encryption", e);
inbound.close(); mcConnection.close();
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
@ -174,10 +171,10 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
if (login == null) { if (login == null) {
throw new IllegalStateException("No ServerLogin packet received yet."); throw new IllegalStateException("No ServerLogin packet received yet.");
} }
PreLoginEvent event = new PreLoginEvent(apiInbound, login.getUsername()); PreLoginEvent event = new PreLoginEvent(inbound, login.getUsername());
server.getEventManager().fire(event) server.getEventManager().fire(event)
.thenRunAsync(() -> { .thenRunAsync(() -> {
if (inbound.isClosed()) { if (mcConnection.isClosed()) {
// The player was disconnected // The player was disconnected
return; return;
} }
@ -185,7 +182,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
Optional<Component> disconnectReason = result.getReason(); Optional<Component> disconnectReason = result.getReason();
if (disconnectReason.isPresent()) { if (disconnectReason.isPresent()) {
// The component is guaranteed to be provided if the connection was denied. // The component is guaranteed to be provided if the connection was denied.
inbound.closeWith(Disconnect.create(disconnectReason.get())); mcConnection.closeWith(Disconnect.create(disconnectReason.get()));
return; return;
} }
@ -194,11 +191,11 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
// Request encryption. // Request encryption.
EncryptionRequest request = generateEncryptionRequest(); EncryptionRequest request = generateEncryptionRequest();
this.verify = Arrays.copyOf(request.getVerifyToken(), 4); this.verify = Arrays.copyOf(request.getVerifyToken(), 4);
inbound.write(request); mcConnection.write(request);
} else { } else {
initializePlayer(GameProfile.forOfflinePlayer(login.getUsername()), false); initializePlayer(GameProfile.forOfflinePlayer(login.getUsername()), false);
} }
}, inbound.eventLoop()); }, mcConnection.eventLoop());
} }
private EncryptionRequest generateEncryptionRequest() { private EncryptionRequest generateEncryptionRequest() {
@ -213,15 +210,16 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
private void initializePlayer(GameProfile profile, boolean onlineMode) { private void initializePlayer(GameProfile profile, boolean onlineMode) {
// Some connection types may need to alter the game profile. // Some connection types may need to alter the game profile.
profile = inbound.getType().addGameProfileTokensIfRequired(profile, profile = mcConnection.getType().addGameProfileTokensIfRequired(profile,
server.getConfiguration().getPlayerInfoForwardingMode()); server.getConfiguration().getPlayerInfoForwardingMode());
GameProfileRequestEvent profileRequestEvent = new GameProfileRequestEvent(apiInbound, profile, GameProfileRequestEvent profileRequestEvent = new GameProfileRequestEvent(inbound, profile,
onlineMode); onlineMode);
server.getEventManager().fire(profileRequestEvent).thenCompose(profileEvent -> { server.getEventManager().fire(profileRequestEvent).thenCompose(profileEvent -> {
// Initiate a regular connection and move over to it. // Initiate a regular connection and move over to it.
ConnectedPlayer player = new ConnectedPlayer(server, profileEvent.getGameProfile(), inbound, ConnectedPlayer player = new ConnectedPlayer(server, profileEvent.getGameProfile(),
apiInbound.getVirtualHost().orElse(null)); mcConnection,
inbound.getVirtualHost().orElse(null));
this.connectedPlayer = player; this.connectedPlayer = player;
if (!server.registerConnection(player)) { if (!server.registerConnection(player)) {
@ -229,6 +227,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
logger.info("{} has connected", player);
return server.getEventManager() return server.getEventManager()
.fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS)) .fire(new PermissionsSetupEvent(player, ConnectedPlayer.DEFAULT_PERMISSIONS))
.thenCompose(event -> { .thenCompose(event -> {
@ -239,7 +239,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
}) })
// then complete the connection // then complete the connection
.thenAcceptAsync(event -> { .thenAcceptAsync(event -> {
if (inbound.isClosed()) { if (mcConnection.isClosed()) {
// The player was disconnected // The player was disconnected
return; return;
} }
@ -250,7 +250,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
} else { } else {
finishLogin(player); finishLogin(player);
} }
}, inbound.eventLoop()); }, mcConnection.eventLoop());
}); });
} }
@ -264,27 +264,26 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
int threshold = server.getConfiguration().getCompressionThreshold(); int threshold = server.getConfiguration().getCompressionThreshold();
if (threshold >= 0) { if (threshold >= 0) {
inbound.write(new SetCompression(threshold)); mcConnection.write(new SetCompression(threshold));
inbound.setCompressionThreshold(threshold); mcConnection.setCompressionThreshold(threshold);
} }
ServerLoginSuccess success = new ServerLoginSuccess(); ServerLoginSuccess success = new ServerLoginSuccess();
success.setUsername(player.getUsername()); success.setUsername(player.getUsername());
success.setUuid(player.getUniqueId()); success.setUuid(player.getUniqueId());
inbound.write(success); mcConnection.write(success);
inbound.setAssociation(player); mcConnection.setAssociation(player);
inbound.setState(StateRegistry.PLAY); mcConnection.setState(StateRegistry.PLAY);
logger.info("{} has connected", player); mcConnection.setSessionHandler(new InitialConnectSessionHandler(player));
inbound.setSessionHandler(new InitialConnectSessionHandler(player));
server.getEventManager().fire(new PostLoginEvent(player)) server.getEventManager().fire(new PostLoginEvent(player))
.thenRun(() -> player.createConnectionRequest(toTry.get()).fireAndForget()); .thenRun(() -> player.createConnectionRequest(toTry.get()).fireAndForget());
} }
@Override @Override
public void handleUnknown(ByteBuf buf) { public void handleUnknown(ByteBuf buf) {
throw new IllegalStateException("Unknown data " + ByteBufUtil.hexDump(buf)); mcConnection.close();
} }
@Override @Override

Datei anzeigen

@ -14,8 +14,6 @@ public class VelocityMessages {
.of("No available servers", TextColor.RED); .of("No available servers", TextColor.RED);
public static final Component ALREADY_CONNECTED = TextComponent public static final Component ALREADY_CONNECTED = TextComponent
.of("You are already connected to this proxy!", TextColor.RED); .of("You are already connected to this proxy!", TextColor.RED);
public static final Component INVALID_USERNAME = TextComponent
.of("Trying to login with invalid username", TextColor.RED);
private VelocityMessages() { private VelocityMessages() {
throw new AssertionError(); throw new AssertionError();