Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
396 changes: 396 additions & 0 deletions BungeeCord-Patches/0067-Rework-information-forwarding.patch.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,396 @@
From 2b48760148e5ef1812f4e6b6fb5f9cdaef1bc560 Mon Sep 17 00:00:00 2001
From: Ismael Hanbel <[email protected]>
Date: Sat, 8 Jul 2023 20:36:35 +0200
Subject: [PATCH] Rework-information-forwarding.patch


diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/forwarding/ForwardingMode.java b/api/src/main/java/io/github/waterfallmc/waterfall/forwarding/ForwardingMode.java
new file mode 100644
index 00000000..d6c17460
--- /dev/null
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/forwarding/ForwardingMode.java
@@ -0,0 +1,12 @@
+package io.github.waterfallmc.waterfall.forwarding;
+
+/**
+ * + * This enum represents the forwarding modes supported by Waterfall.
+ * +
+ */
+
+public enum ForwardingMode {
+ BUNGEECORD_LEGACY,
+ BUNGEEGUARD,
+ VELOCITY_MODERN
+}
\ No newline at end of file
diff --git a/api/src/main/java/net/md_5/bungee/Util.java b/api/src/main/java/net/md_5/bungee/Util.java
index 91efc0a6..8d83f41c 100644
--- a/api/src/main/java/net/md_5/bungee/Util.java
+++ b/api/src/main/java/net/md_5/bungee/Util.java
@@ -8,7 +8,9 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
+import java.security.SecureRandom;
import java.util.Locale;
+import java.util.Random;
import java.util.UUID;

import io.github.waterfallmc.waterfall.utils.Hex;
@@ -141,4 +143,22 @@ public class Util
{
return new UUID( UnsignedLongs.parseUnsignedLong( uuid.substring( 0, 16 ), 16 ), UnsignedLongs.parseUnsignedLong( uuid.substring( 16 ), 16 ) );
}
+
+ // Waterfall start: Forwarding rework
+ /**
+ * Generates an alphanumeric A-Z,a-z,0-9 byte-sequence.
+ *
+ * @param len the length of the sequence
+ * @return a UTF/ASCII compatible alphanumeric byte-sequence
+ */
+ public static byte[] randomAlphanumericSequence(int len) {
+ Random random = new SecureRandom();
+ byte[] ret = new byte[len];
+ for (int i = 0; i < len; i++) {
+ int seq = random.nextInt(62);
+ ret[i] = (byte) (seq < 10 ? seq + 48 : seq < 36 ? seq + 55 : seq + 61);
+ }
+ return ret;
+ }
+ // Waterfall end: Forwarding rework
}
diff --git a/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java b/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java
index 469fe0e1..b78c0d5f 100644
--- a/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java
+++ b/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java
@@ -2,6 +2,8 @@ package net.md_5.bungee.api;

import java.util.Collection;
import java.util.Map;
+
+import io.github.waterfallmc.waterfall.forwarding.ForwardingMode;
import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.config.ServerInfo;

@@ -275,4 +277,11 @@ public interface ProxyConfig
* @return the configured limit
*/
int getPluginChannelNameLimit();
+
+ /**
+ * Represents the forwarding mode as configured.
+ *
+ * @return the mode set in the config
+ */
+ ForwardingMode getForwardingMode();
}
diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java
index 1ba5b249..c0797a4a 100644
--- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java
+++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java
@@ -49,7 +49,7 @@ import org.yaml.snakeyaml.introspector.PropertyUtils;
* example event handling and plugin management.
*/
@RequiredArgsConstructor
-public final class PluginManager
+public final class PluginManager
{

/*========================================================================*/
@@ -440,6 +440,14 @@ public final class PluginManager
Preconditions.checkNotNull( desc.getName(), "Plugin from %s has no name", file );
Preconditions.checkNotNull( desc.getMain(), "Plugin from %s has no main", file );

+ // Waterfall start: Forwarding rework
+ if (desc.getName().equals("BungeeGuard")) {
+ proxy.getLogger().warning("Detected the plugin BungeeGuard. " +
+ "Waterfall now supports the functionality this plugin provides natively. " +
+ "Please refer to the Waterfall documentation for more information.");
+ }
+ // Waterfall end: Forwarding rework
+
desc.setFile( file );
toLoad.put( desc.getName(), desc );
}
diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java
index da0efa36..03c628f4 100644
--- a/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java
+++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/conf/WaterfallConfiguration.java
@@ -1,11 +1,16 @@
package io.github.waterfallmc.waterfall.conf;

import com.google.common.base.Joiner;
+import io.github.waterfallmc.waterfall.forwarding.ForwardingMode;
+import net.md_5.bungee.BungeeCord;
+import net.md_5.bungee.Util;
import net.md_5.bungee.conf.Configuration;
import net.md_5.bungee.conf.YamlConfig;
import net.md_5.bungee.protocol.ProtocolConstants;

import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.util.logging.Logger;

public class WaterfallConfiguration extends Configuration {

@@ -45,6 +50,9 @@ public class WaterfallConfiguration extends Configuration {
private boolean disableEntityMetadataRewrite = false;
private boolean disableTabListRewrite = true;

+ private ForwardingMode forwardingMode = ForwardingMode.BUNGEECORD_LEGACY;
+ private byte[] forwardingSecret = Util.randomAlphanumericSequence(12);
+
/*
* Plugin Message limiting options
* Allows for more control over server-client communication
@@ -77,6 +85,25 @@ public class WaterfallConfiguration extends Configuration {
disableTabListRewrite = config.getBoolean("disable_tab_list_rewrite", disableTabListRewrite);
pluginChannelLimit = config.getInt("registered_plugin_channels_limit", pluginChannelLimit);
pluginChannelNameLimit = config.getInt("plugin_channel_name_limit", pluginChannelNameLimit);
+ // Forwarding options
+ forwardingMode = ForwardingMode.valueOf(config.getString("forwarding_mode", ForwardingMode.BUNGEECORD_LEGACY.toString()).toUpperCase());
+ Logger logger = BungeeCord.getInstance().getLogger();
+ if (super.isIpForward()) {
+ if ((forwardingMode) == ForwardingMode.BUNGEECORD_LEGACY) {
+ logger.warning("The forwarding mode is set as BungeeCord legacy, it is recommended that you use another mode to avoid spoofing information attacks.");
+ }
+
+ } else {
+ logger.warning("Information forwarding (ip-forwarding) is disabled. " +
+ "Player UUIDs may not be consistent across the servers. " +
+ "For the optimal experience please enable ip_forward in the config.yml and " +
+ "configure forwarding and on your servers.");
+ }
+
+ if (config.getString("forwarding_secret", "").isEmpty()) {
+ config.regenerateForwardingSecret();
+ logger.warning("A new forwarding secret has been generated. If this was the " +
+ "first start of the proxy please configure forwarding for your network.");
+ }
+ forwardingSecret = config.getString("forwarding_secret", "").getBytes(StandardCharsets.UTF_8);
+ }

@Override
@@ -123,4 +150,13 @@ public class WaterfallConfiguration extends Configuration {
public int getPluginChannelNameLimit() {
return pluginChannelNameLimit;
}
+
+ @Override
+ public ForwardingMode getForwardingMode() {
+ return forwardingMode;
+ }
+
+ public byte[] getForwardingSecret() {
+ return forwardingSecret;
+ }
}
diff --git a/proxy/src/main/java/io/github/waterfallmc/waterfall/forwarding/VelocityForwardingUtil.java b/proxy/src/main/java/io/github/waterfallmc/waterfall/forwarding/VelocityForwardingUtil.java
new file mode 100644
index 00000000..b9990f92
--- /dev/null
+++ b/proxy/src/main/java/io/github/waterfallmc/waterfall/forwarding/VelocityForwardingUtil.java
@@ -0,0 +1,69 @@
+package io.github.waterfallmc.waterfall.forwarding;
+
+import io.github.waterfallmc.waterfall.conf.WaterfallConfiguration;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.buffer.Unpooled;
+import lombok.experimental.UtilityClass;
+import net.md_5.bungee.BungeeCord;
+import net.md_5.bungee.protocol.DefinedPacket;
+import net.md_5.bungee.protocol.Property;
+
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.UUID;
+
+@UtilityClass
+public class VelocityForwardingUtil {
+
+ public static final String VELOCITY_IP_FORWARDING_CHANNEL = "velocity:player_info";
+ public static final int FORWARDING_VERSION = 1;
+
+ public static final String MODERN_IP_FORWARDING_FAILURE = "Your server did not send a forwarding request to the proxy. Is it set up correctly?";
+
+ public static byte[] writeForwardingData(String address, String name, UUID playerUUID, Property[] properties) {
+
+ ByteBuf buf = Unpooled.buffer(2048);
+
+ try {
+ DefinedPacket.writeVarInt(FORWARDING_VERSION, buf);
+ DefinedPacket.writeString(address, buf);
+ DefinedPacket.writeUUID(playerUUID, buf);
+ DefinedPacket.writeString(name, buf);
+ DefinedPacket.writeVarInt(properties.length, buf);
+ for (Property property : properties) {
+ DefinedPacket.writeString(property.getName(), buf);
+ DefinedPacket.writeString(property.getValue(), buf);
+ String signature = property.getSignature();
+ if (signature != null && !signature.isEmpty()) {
+ buf.writeBoolean(true);
+ DefinedPacket.writeString(signature, buf);
+ } else {
+ buf.writeBoolean(false);
+ }
+ }
+
+ byte[] forwardingSecret = ((WaterfallConfiguration) BungeeCord.getInstance().config).getForwardingSecret();
+ SecretKey key = new SecretKeySpec(forwardingSecret, "HmacSHA256");
+ Mac mac = Mac.getInstance("HmacSHA256");
+ mac.init(key);
+ mac.update(buf.array(), buf.arrayOffset(), buf.readableBytes());
+ byte[] sig = mac.doFinal();
+
+ ByteBuf finished = Unpooled.wrappedBuffer(Unpooled.wrappedBuffer(sig), buf);
+ byte[] encoded = ByteBufUtil.getBytes(finished);
+ finished.release();
+ return encoded;
+ } catch (InvalidKeyException e) {
+ buf.release();
+ throw new RuntimeException("Unable to authenticate data", e);
+ } catch (NoSuchAlgorithmException e) {
+ // Should never happen
+ buf.release();
+ throw new AssertionError(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java
index 60232e52..dfde3535 100644
--- a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java
+++ b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java
@@ -2,15 +2,15 @@ package net.md_5.bungee;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
+import io.github.waterfallmc.waterfall.conf.WaterfallConfiguration;
+import io.github.waterfallmc.waterfall.forwarding.ForwardingMode;
+import io.github.waterfallmc.waterfall.forwarding.VelocityForwardingUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
-import java.util.Locale;
-import java.util.Arrays; // Waterfall
-import java.util.Queue;
-import java.util.Set;
-import java.util.UUID;
+import java.util.*;
+
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.api.ChatColor;
@@ -35,11 +35,7 @@ import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.netty.HandlerBoss;
import net.md_5.bungee.netty.PacketHandler;
import net.md_5.bungee.netty.PipelineUtils;
-import net.md_5.bungee.protocol.DefinedPacket;
-import net.md_5.bungee.protocol.MinecraftDecoder;
-import net.md_5.bungee.protocol.PacketWrapper;
-import net.md_5.bungee.protocol.Protocol;
-import net.md_5.bungee.protocol.ProtocolConstants;
+import net.md_5.bungee.protocol.*;
import net.md_5.bungee.protocol.packet.EncryptionRequest;
import net.md_5.bungee.protocol.packet.EntityStatus;
import net.md_5.bungee.protocol.packet.GameState;
@@ -73,6 +69,8 @@ public class ServerConnector extends PacketHandler
private ForgeServerHandler handshakeHandler;
private boolean obsolete;

+ private boolean didForwardInformation = false; // Waterfall: Forwarding rework
+
private enum State
{

@@ -106,6 +104,8 @@ public class ServerConnector extends PacketHandler
Handshake originalHandshake = user.getPendingConnection().getHandshake();
Handshake copiedHandshake = new Handshake( originalHandshake.getProtocolVersion(), originalHandshake.getHost(), originalHandshake.getPort(), 2 );

+ if(BungeeCord.getInstance().config.getForwardingMode() != ForwardingMode.VELOCITY_MODERN) // Waterfall: Forwarding rework
+
if ( BungeeCord.getInstance().config.isIpForward() && user.getSocketAddress() instanceof InetSocketAddress )
{
String newHost = copiedHandshake.getHost() + "\00" + AddressUtil.sanitizeAddress( user.getAddress() ) + "\00" + user.getUUID();
@@ -120,6 +120,15 @@ public class ServerConnector extends PacketHandler
properties = profile.getProperties();
}

+ // Waterfall start: Forwarding rework
+ if (BungeeCord.getInstance().config.getForwardingMode() == ForwardingMode.BUNGEEGUARD) {
+ List<Property> temp = new ArrayList<>(Arrays.asList(properties));
+ String token = new String(((WaterfallConfiguration) BungeeCord.getInstance().config).getForwardingSecret(), StandardCharsets.UTF_8);
+ temp.add(new Property("bungeeguard-token", token, null));
+ properties = temp.toArray(new Property[0]);
+ }
+ // Waterfall end: Forwarding rework
+
if ( user.getForgeClientHandler().isFmlTokenInHandshake() )
{
// Get the current properties and copy them into a slightly bigger array.
@@ -171,6 +180,12 @@ public class ServerConnector extends PacketHandler
@Override
public void handle(LoginSuccess loginSuccess) throws Exception
{
+ // Waterfall start: Forwarding rework
+ if (!didForwardInformation && BungeeCord.getInstance().config.isIpForward()
+ && BungeeCord.getInstance().config.getForwardingMode() == ForwardingMode.VELOCITY_MODERN) {
+ throw new QuietException(VelocityForwardingUtil.MODERN_IP_FORWARDING_FAILURE);
+ }
+ // Waterfall end: Forwarding rework
Preconditions.checkState( thisState == State.LOGIN_SUCCESS, "Not expecting LOGIN_SUCCESS" );
ch.setProtocol( Protocol.GAME );
thisState = State.LOGIN;
@@ -480,6 +495,20 @@ public class ServerConnector extends PacketHandler
@Override
public void handle(LoginPayloadRequest loginPayloadRequest)
{
+ // Waterfall start: Forwarding rework
+ if (!didForwardInformation && BungeeCord.getInstance().config.isIpForward()
+ && BungeeCord.getInstance().config.getForwardingMode() == ForwardingMode.VELOCITY_MODERN
+ && loginPayloadRequest.getChannel().equals(VelocityForwardingUtil.VELOCITY_IP_FORWARDING_CHANNEL)) {
+
+ byte[] forwardingData = VelocityForwardingUtil
+ .writeForwardingData(user.getAddress().getAddress().getHostAddress(),
+ user.getName(), user.getUniqueId(),
+ user.getPendingConnection().getLoginProfile().getProperties());
+ ch.write(new LoginPayloadResponse(loginPayloadRequest.getId(), forwardingData));
+ didForwardInformation = true;
+ return;
+ }
+ // Waterfall end: Forwarding rework
ch.write( new LoginPayloadResponse( loginPayloadRequest.getId(), null ) );
}

diff --git a/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java b/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java
index 0dd69778..e3220e08 100644
--- a/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java
+++ b/proxy/src/main/java/net/md_5/bungee/conf/YamlConfig.java
@@ -10,6 +10,7 @@ import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -332,4 +333,10 @@ public class YamlConfig implements ConfigurationAdapter
Collection<String> permissions = get( "permissions." + group, null );
return ( permissions == null ) ? Collections.EMPTY_SET : permissions;
}
+
+ // Waterfall start: Forwarding rework
+ public void regenerateForwardingSecret() {
+ set("forwarding_secret", new String(Util.randomAlphanumericSequence(12), StandardCharsets.UTF_8));
+ }
+ // Waterfall end: Forwarding rework
}
--
2.41.0.windows.1