3
0
Mirror von https://github.com/PaperMC/Velocity.git synchronisiert 2024-09-29 14:40:21 +02:00

Merge pull request #498 from VelocityPowered/feature/extended-connection-handshake-event

Reimplement #434 but aligned to the Velocity 2.0.0 API
Dieser Commit ist enthalten in:
Andrew Steinborn 2021-05-12 10:10:07 -04:00 committet von GitHub
Commit 100a930502
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 4AEE18F83AFDEB23
7 geänderte Dateien mit 136 neuen und 25 gelöschten Zeilen

Datei anzeigen

@ -7,12 +7,27 @@
package com.velocitypowered.api.event.connection; package com.velocitypowered.api.event.connection;
import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.event.ResultedEvent.ComponentResult;
import com.velocitypowered.api.proxy.connection.InboundConnection; import com.velocitypowered.api.proxy.connection.InboundConnection;
import java.net.InetAddress;
import java.net.SocketAddress;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* This event is fired when a handshake is established between a client and the proxy. * This event is fired when a handshake is established between a client and the proxy.
*/ */
public interface ConnectionHandshakeEvent { public interface ConnectionHandshakeEvent extends ResultedEvent<ComponentResult> {
InboundConnection connection(); InboundConnection connection();
String currentHostname();
String originalHostname();
void setCurrentHostname(String hostname);
@Nullable SocketAddress currentRemoteHostAddress();
void setCurrentRemoteHostAddress(@Nullable SocketAddress address);
} }

Datei anzeigen

@ -9,6 +9,9 @@ package com.velocitypowered.api.event.connection;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import com.velocitypowered.api.proxy.connection.InboundConnection; import com.velocitypowered.api.proxy.connection.InboundConnection;
import java.net.InetAddress;
import java.net.SocketAddress;
import org.checkerframework.checker.nullness.qual.Nullable;
/** /**
* This event is fired when a handshake is established between a client and the proxy. * This event is fired when a handshake is established between a client and the proxy.
@ -16,9 +19,18 @@ import com.velocitypowered.api.proxy.connection.InboundConnection;
public final class ConnectionHandshakeEventImpl implements ConnectionHandshakeEvent { public final class ConnectionHandshakeEventImpl implements ConnectionHandshakeEvent {
private final InboundConnection connection; private final InboundConnection connection;
private final String originalHostname;
private String currentHostname;
private ComponentResult result;
private SocketAddress currentRemoteAddress;
public ConnectionHandshakeEventImpl(InboundConnection connection) { public ConnectionHandshakeEventImpl(InboundConnection connection,
String originalHostname) {
this.connection = Preconditions.checkNotNull(connection, "connection"); this.connection = Preconditions.checkNotNull(connection, "connection");
this.originalHostname = Preconditions.checkNotNull(originalHostname, "originalHostname");
this.currentHostname = originalHostname;
this.result = ComponentResult.allowed();
this.currentRemoteAddress = connection.remoteAddress();
} }
@Override @Override
@ -26,10 +38,49 @@ public final class ConnectionHandshakeEventImpl implements ConnectionHandshakeEv
return connection; return connection;
} }
@Override
public String currentHostname() {
return currentHostname;
}
@Override
public String originalHostname() {
return originalHostname;
}
@Override
public void setCurrentHostname(String hostname) {
currentHostname = Preconditions.checkNotNull(hostname, "hostname");
}
@Override
public @Nullable SocketAddress currentRemoteHostAddress() {
return currentRemoteAddress;
}
@Override
public void setCurrentRemoteHostAddress(SocketAddress address) {
currentRemoteAddress = address;
}
@Override
public ComponentResult result() {
return result;
}
@Override
public void setResult(ComponentResult result) {
this.result = Preconditions.checkNotNull(result, "result");
}
@Override @Override
public String toString() { public String toString() {
return "ConnectionHandshakeEvent{" return "ConnectionHandshakeEventImpl{"
+ "connection=" + connection + "connection=" + connection
+ ", originalHostname='" + originalHostname + '\''
+ ", currentHostname='" + currentHostname + '\''
+ ", result=" + result
+ ", currentRemoteAddress=" + currentRemoteAddress
+ '}'; + '}';
} }
} }

Datei anzeigen

@ -75,7 +75,7 @@ dependencies {
runtimeOnly 'com.lmax:disruptor:3.4.2' // Async loggers runtimeOnly 'com.lmax:disruptor:3.4.2' // Async loggers
implementation 'it.unimi.dsi:fastutil:8.4.1' implementation 'it.unimi.dsi:fastutil:8.4.1'
implementation 'net.kyori:adventure-nbt:4.0.0-SNAPSHOT' implementation "net.kyori:adventure-nbt:${adventureVersion}"
implementation 'org.asynchttpclient:async-http-client:2.12.1' implementation 'org.asynchttpclient:async-http-client:2.12.1'

Datei anzeigen

@ -75,7 +75,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
private static final Logger logger = LogManager.getLogger(MinecraftConnection.class); private static final Logger logger = LogManager.getLogger(MinecraftConnection.class);
private final Channel channel; private final Channel channel;
private SocketAddress remoteAddress; private @Nullable SocketAddress remoteAddress;
private ProtocolRegistry state; private ProtocolRegistry state;
private @Nullable MinecraftSessionHandler sessionHandler; private @Nullable MinecraftSessionHandler sessionHandler;
private ProtocolVersion protocolVersion; private ProtocolVersion protocolVersion;
@ -304,10 +304,16 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
return !channel.isActive(); return !channel.isActive();
} }
public SocketAddress getRemoteAddress() { public @Nullable SocketAddress getRemoteAddress() {
return remoteAddress; return remoteAddress;
} }
public void setRemoteAddress(@Nullable SocketAddress address) {
ensureOpen();
ensureInEventLoop();
this.remoteAddress = address;
}
public ProtocolRegistry getState() { public ProtocolRegistry getState() {
return state; return state;
} }

Datei anzeigen

@ -39,6 +39,7 @@ import com.velocitypowered.proxy.network.registry.state.ProtocolStates;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
@ -121,12 +122,6 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
return; return;
} }
InetAddress address = ((InetSocketAddress) connection.getRemoteAddress()).getAddress();
if (!server.getIpAttemptLimiter().attempt(address)) {
ic.disconnectQuietly(Component.translatable("velocity.error.logging-in-too-fast"));
return;
}
connection.setType(getHandshakeConnectionType(handshake)); connection.setType(getHandshakeConnectionType(handshake));
// If the proxy is configured for modern forwarding, we must deny connections from 1.12.2 // If the proxy is configured for modern forwarding, we must deny connections from 1.12.2
@ -138,9 +133,37 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
return; return;
} }
server.eventManager().fireAndForget(new ConnectionHandshakeEventImpl(ic)); connection.setAutoReading(false);
server.eventManager().fire(new ConnectionHandshakeEventImpl(ic, handshake.getServerAddress()))
.thenAcceptAsync(event -> {
connection.setAutoReading(true);
if (!event.result().isAllowed()) {
ic.disconnectQuietly(event.result().reason().get());
} else {
// if the handshake is changed, propagate the change
if (!event.currentHostname().equals(event.originalHostname())) {
ic.setCleanedHostname(cleanVhost(event.currentHostname()));
}
if (!Objects.equals(event.currentRemoteHostAddress(), ic.remoteAddress())) {
ic.setRemoteAddress(event.currentRemoteHostAddress());
}
if (connection.getRemoteAddress() instanceof InetSocketAddress) {
InetAddress address = ((InetSocketAddress) connection.getRemoteAddress())
.getAddress();
if (!server.getIpAttemptLimiter().attempt(address)) {
ic.disconnectQuietly(
Component.translatable("velocity.error.logging-in-too-fast"));
return;
}
}
connection.setSessionHandler(new LoginSessionHandler(server, connection, ic)); connection.setSessionHandler(new LoginSessionHandler(server, connection, ic));
} }
}, connection.eventLoop());
}
private ConnectionType getHandshakeConnectionType(ServerboundHandshakePacket handshake) { private ConnectionType getHandshakeConnectionType(ServerboundHandshakePacket handshake) {
// Determine if we're using Forge (1.8 to 1.12, may not be the case in 1.13). // Determine if we're using Forge (1.8 to 1.12, may not be the case in 1.13).

Datei anzeigen

@ -17,6 +17,7 @@
package com.velocitypowered.proxy.connection.client; package com.velocitypowered.proxy.connection.client;
import com.google.common.base.Preconditions;
import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.connection.InboundConnection; import com.velocitypowered.api.proxy.connection.InboundConnection;
import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftConnection;
@ -24,13 +25,16 @@ import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
import com.velocitypowered.proxy.network.packet.clientbound.ClientboundDisconnectPacket; import com.velocitypowered.proxy.network.packet.clientbound.ClientboundDisconnectPacket;
import com.velocitypowered.proxy.network.packet.serverbound.ServerboundHandshakePacket; import com.velocitypowered.proxy.network.packet.serverbound.ServerboundHandshakePacket;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Locale; import java.util.Locale;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.kyori.adventure.translation.GlobalTranslator; import net.kyori.adventure.translation.GlobalTranslator;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class InitialInboundConnection implements InboundConnection, public final class InitialInboundConnection implements InboundConnection,
MinecraftConnectionAssociation { MinecraftConnectionAssociation {
@ -38,24 +42,24 @@ public final class InitialInboundConnection implements InboundConnection,
private static final Logger logger = LogManager.getLogger(InitialInboundConnection.class); private static final Logger logger = LogManager.getLogger(InitialInboundConnection.class);
private final MinecraftConnection connection; private final MinecraftConnection connection;
private final String cleanedAddress; private String cleanedHostname;
private final ServerboundHandshakePacket handshake; private final ServerboundHandshakePacket handshake;
InitialInboundConnection(MinecraftConnection connection, String cleanedAddress, InitialInboundConnection(MinecraftConnection connection, String cleanedHostname,
ServerboundHandshakePacket handshake) { ServerboundHandshakePacket handshake) {
this.connection = connection; this.connection = connection;
this.cleanedAddress = cleanedAddress; this.cleanedHostname = cleanedHostname;
this.handshake = handshake; this.handshake = handshake;
} }
@Override @Override
public InetSocketAddress remoteAddress() { public SocketAddress remoteAddress() {
return (InetSocketAddress) connection.getRemoteAddress(); return connection.getRemoteAddress();
} }
@Override @Override
public Optional<InetSocketAddress> connectedHostname() { public Optional<InetSocketAddress> connectedHostname() {
return Optional.of(InetSocketAddress.createUnresolved(cleanedAddress, handshake.getPort())); return Optional.of(InetSocketAddress.createUnresolved(cleanedHostname, handshake.getPort()));
} }
@Override @Override
@ -70,7 +74,11 @@ public final class InitialInboundConnection implements InboundConnection,
@Override @Override
public String toString() { public String toString() {
return "[initial connection] " + connection.getRemoteAddress().toString(); return "[initial connection] " + connection.getRemoteAddress();
}
public void setCleanedHostname(String hostname) {
this.cleanedHostname = Preconditions.checkNotNull(hostname, "hostname");
} }
/** /**
@ -93,4 +101,8 @@ public final class InitialInboundConnection implements InboundConnection,
Component translated = GlobalTranslator.render(reason, Locale.getDefault()); Component translated = GlobalTranslator.render(reason, Locale.getDefault());
connection.closeWith(ClientboundDisconnectPacket.create(translated, protocolVersion())); connection.closeWith(ClientboundDisconnectPacket.create(translated, protocolVersion()));
} }
public void setRemoteAddress(@Nullable SocketAddress currentRemoteHostAddress) {
connection.setRemoteAddress(currentRemoteHostAddress);
}
} }

Datei anzeigen

@ -54,6 +54,7 @@ import com.velocitypowered.proxy.network.packet.serverbound.ServerboundServerLog
import com.velocitypowered.proxy.network.registry.state.ProtocolStates; import com.velocitypowered.proxy.network.registry.state.ProtocolStates;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.MessageDigest; import java.security.MessageDigest;
@ -119,12 +120,15 @@ 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) mcConnection.getRemoteAddress()).getHostString();
String url = String.format(MOJANG_HASJOINED_URL, String url = String.format(MOJANG_HASJOINED_URL,
urlFormParameterEscaper().escape(login.getUsername()), serverId); urlFormParameterEscaper().escape(login.getUsername()), serverId);
if (server.configuration().shouldPreventClientProxyConnections()) { if (server.configuration().shouldPreventClientProxyConnections()) {
url += "&ip=" + urlFormParameterEscaper().escape(playerIp); SocketAddress playerRemoteAddress = mcConnection.getRemoteAddress();
if (playerRemoteAddress instanceof InetSocketAddress) {
url += "&ip=" + urlFormParameterEscaper().escape(
((InetSocketAddress) playerRemoteAddress).getHostString());
}
} }
ListenableFuture<Response> hasJoinedResponse = server.getAsyncHttpClient().prepareGet(url) ListenableFuture<Response> hasJoinedResponse = server.getAsyncHttpClient().prepareGet(url)
@ -156,8 +160,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
} 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.getStatusCode(), login.getUsername(), playerIp); profileResponse.getStatusCode(), login.getUsername());
mcConnection.close(true); mcConnection.close(true);
} }
} catch (ExecutionException e) { } catch (ExecutionException e) {