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

Implement bungee-style IP forwarding.

Dieser Commit ist enthalten in:
Andrew Steinborn 2018-07-26 13:38:25 -04:00
Ursprung 302df0299e
Commit 76e7ac5afc
5 geänderte Dateien mit 52 neuen und 7 gelöschten Zeilen

Datei anzeigen

@ -8,6 +8,7 @@ import com.velocitypowered.proxy.data.ServerInfo;
import com.velocitypowered.proxy.protocol.netty.MinecraftPipelineUtils; import com.velocitypowered.proxy.protocol.netty.MinecraftPipelineUtils;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.util.UuidUtils;
import io.netty.channel.*; import io.netty.channel.*;
public class ServerConnection { public class ServerConnection {
@ -51,12 +52,23 @@ public class ServerConnection {
}); });
} }
private String createBungeeForwardingAddress() {
// BungeeCord IP forwarding is simply a special injection after the "address" in the handshake,
// separated by \0 (the null byte). In order, you send the original host, the player's IP, their
// UUID (undashed), and if you are in online-mode, their login properties (retrieved from Mojang).
//
// Velocity doesn't yet support online-mode, unfortunately. That will come soon.
return serverInfo.getAddress().getHostString() + "\0" +
proxyPlayer.getRemoteAddress().getHostString() + "\0" +
UuidUtils.toUndashed(proxyPlayer.getUniqueId());
}
private void startHandshake() { private void startHandshake() {
// Initiate a handshake. // Initiate a handshake.
Handshake handshake = new Handshake(); Handshake handshake = new Handshake();
handshake.setNextStatus(2); // login handshake.setNextStatus(2); // login
handshake.setProtocolVersion(proxyPlayer.getConnection().getProtocolVersion()); handshake.setProtocolVersion(proxyPlayer.getConnection().getProtocolVersion());
handshake.setServerAddress(serverInfo.getAddress().getHostString()); handshake.setServerAddress(createBungeeForwardingAddress());
handshake.setPort(serverInfo.getAddress().getPort()); handshake.setPort(serverInfo.getAddress().getPort());
channel.write(handshake); channel.write(handshake);

Datei anzeigen

@ -10,6 +10,7 @@ import net.kyori.text.TextComponent;
import net.kyori.text.format.TextColor; import net.kyori.text.format.TextColor;
import net.kyori.text.serializer.ComponentSerializers; import net.kyori.text.serializer.ComponentSerializers;
import java.net.InetSocketAddress;
import java.util.UUID; import java.util.UUID;
public class ConnectedPlayer { public class ConnectedPlayer {
@ -36,6 +37,10 @@ public class ConnectedPlayer {
return connection; return connection;
} }
public InetSocketAddress getRemoteAddress() {
return (InetSocketAddress) connection.getChannel().remoteAddress();
}
public ServerConnection getConnectedServer() { public ServerConnection getConnectedServer() {
return connectedServer; return connectedServer;
} }
@ -57,9 +62,7 @@ public class ConnectedPlayer {
// The player isn't yet connected to a server - we should disconnect them. // The player isn't yet connected to a server - we should disconnect them.
connection.closeWith(Disconnect.create(component)); connection.closeWith(Disconnect.create(component));
} else { } else {
Chat chat = new Chat(); connection.write(Chat.create(component));
chat.setMessage(ComponentSerializers.JSON.serialize(component));
connection.write(chat);
} }
} }

Datei anzeigen

@ -1,14 +1,25 @@
package com.velocitypowered.proxy.protocol.packets; package com.velocitypowered.proxy.protocol.packets;
import com.google.common.base.Preconditions;
import com.velocitypowered.proxy.protocol.ProtocolConstants; import com.velocitypowered.proxy.protocol.ProtocolConstants;
import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import net.kyori.text.TextComponent;
import net.kyori.text.serializer.ComponentSerializers;
public class Chat implements MinecraftPacket { public class Chat implements MinecraftPacket {
private String message; private String message;
private byte position; private byte position;
public Chat() {
}
public Chat(String message, byte position) {
this.message = message;
this.position = position;
}
public String getMessage() { public String getMessage() {
return message; return message;
} }
@ -48,4 +59,13 @@ public class Chat implements MinecraftPacket {
buf.writeByte(position); buf.writeByte(position);
} }
} }
public static Chat create(TextComponent component) {
return create(component, (byte) 0);
}
public static Chat create(TextComponent component, byte pos) {
Preconditions.checkNotNull(component, "component");
return new Chat(ComponentSerializers.JSON.serialize(component), pos);
}
} }

Datei anzeigen

@ -18,6 +18,11 @@ public enum UuidUtils {
); );
} }
public static String toUndashed(final UUID uuid) {
Preconditions.checkNotNull(uuid, "uuid");
return Long.toUnsignedString(uuid.getMostSignificantBits(), 16) + Long.toUnsignedString(uuid.getLeastSignificantBits(), 16);
}
public static UUID generateOfflinePlayerUuid(String username) { public static UUID generateOfflinePlayerUuid(String username) {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8)); return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(StandardCharsets.UTF_8));
} }

Datei anzeigen

@ -14,12 +14,17 @@ class UuidUtilsTest {
private static final String TEST_OFFLINE_PLAYER = "tuxed"; private static final String TEST_OFFLINE_PLAYER = "tuxed";
@Test @Test
void testFromUndashed() { void generateOfflinePlayerUuid() {
assertEquals(TEST_OFFLINE_PLAYER_UUID, UuidUtils.generateOfflinePlayerUuid(TEST_OFFLINE_PLAYER), "UUIDs do not match");
}
@Test
void fromUndashed() {
assertEquals(EXPECTED_DASHED_UUID, UuidUtils.fromUndashed(ACTUAL_UNDASHED_UUID), "UUIDs do not match"); assertEquals(EXPECTED_DASHED_UUID, UuidUtils.fromUndashed(ACTUAL_UNDASHED_UUID), "UUIDs do not match");
} }
@Test @Test
void generateOfflinePlayerUuid() { void toUndashed() {
assertEquals(TEST_OFFLINE_PLAYER_UUID, UuidUtils.generateOfflinePlayerUuid(TEST_OFFLINE_PLAYER), "UUIDs do not match"); assertEquals(ACTUAL_UNDASHED_UUID, UuidUtils.toUndashed(EXPECTED_DASHED_UUID), "UUIDs do not match");
} }
} }