diff --git a/src/main/java/net/raphimc/viaproxy/protocoltranslator/viaproxy/ViaProxyConfig.java b/src/main/java/net/raphimc/viaproxy/protocoltranslator/viaproxy/ViaProxyConfig.java index 7882d12..bd2effd 100644 --- a/src/main/java/net/raphimc/viaproxy/protocoltranslator/viaproxy/ViaProxyConfig.java +++ b/src/main/java/net/raphimc/viaproxy/protocoltranslator/viaproxy/ViaProxyConfig.java @@ -58,6 +58,7 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. private final OptionSpec optionBetacraftAuth; private final OptionSpec optionBackendProxyUrl; private final OptionSpec optionBackendHaProxy; + private final OptionSpec optionFrontendHaProxy; private final OptionSpec optionChatSigning; private final OptionSpec optionCompressionThreshold; private final OptionSpec optionAllowBetaPinging; @@ -75,6 +76,7 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. private boolean betacraftAuth = false; private URI backendProxyUrl = null; private boolean backendHaProxy = false; + private boolean frontendHaProxy = false; private boolean chatSigning = true; private int compressionThreshold = 256; private boolean allowBetaPinging = false; @@ -97,6 +99,7 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. this.optionBetacraftAuth = this.optionParser.accepts("betacraft-auth").withRequiredArg().ofType(Boolean.class).defaultsTo(this.betacraftAuth); this.optionBackendProxyUrl = this.optionParser.accepts("backend-proxy-url").withRequiredArg().ofType(String.class).defaultsTo(""); this.optionBackendHaProxy = this.optionParser.accepts("backend-haproxy").withRequiredArg().ofType(Boolean.class).defaultsTo(this.backendHaProxy); + this.optionFrontendHaProxy = this.optionParser.accepts("frontend-haproxy").withRequiredArg().ofType(Boolean.class).defaultsTo(this.frontendHaProxy); this.optionChatSigning = this.optionParser.accepts("chat-signing").withRequiredArg().ofType(Boolean.class).defaultsTo(this.chatSigning); this.optionCompressionThreshold = this.optionParser.accepts("compression-threshold").withRequiredArg().ofType(Integer.class).defaultsTo(this.compressionThreshold); this.optionAllowBetaPinging = this.optionParser.accepts("allow-beta-pinging").withRequiredArg().ofType(Boolean.class).defaultsTo(this.allowBetaPinging); @@ -126,6 +129,7 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. this.betacraftAuth = this.getBoolean("betacraft-auth", this.betacraftAuth); this.backendProxyUrl = this.parseProxyUrl(this.getString("backend-proxy-url", "")); this.backendHaProxy = this.getBoolean("backend-haproxy", this.backendHaProxy); + this.frontendHaProxy = this.getBoolean("frontend-haproxy", this.frontendHaProxy); this.chatSigning = this.getBoolean("chat-signing", this.chatSigning); this.compressionThreshold = this.getInt("compression-threshold", this.compressionThreshold); this.allowBetaPinging = this.getBoolean("allow-beta-pinging", this.allowBetaPinging); @@ -159,6 +163,7 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. this.betacraftAuth = options.valueOf(this.optionBetacraftAuth); this.backendProxyUrl = this.parseProxyUrl(options.valueOf(this.optionBackendProxyUrl)); this.backendHaProxy = options.valueOf(this.optionBackendHaProxy); + this.frontendHaProxy = options.valueOf(this.optionFrontendHaProxy); this.chatSigning = options.valueOf(this.optionChatSigning); this.compressionThreshold = options.valueOf(this.optionCompressionThreshold); this.allowBetaPinging = options.valueOf(this.optionAllowBetaPinging); @@ -283,6 +288,15 @@ public class ViaProxyConfig extends Config implements com.viaversion.viaversion. this.set("backend-haproxy", backendHaProxy); } + public boolean useFrontendHaProxy() { + return this.frontendHaProxy; + } + + public void setFrontendHaProxy(final boolean frontendHaProxy) { + this.frontendHaProxy = frontendHaProxy; + this.set("frontend-haproxy", frontendHaProxy); + } + public boolean shouldSignChat() { return this.chatSigning; } diff --git a/src/main/java/net/raphimc/viaproxy/proxy/client2proxy/Client2ProxyChannelInitializer.java b/src/main/java/net/raphimc/viaproxy/proxy/client2proxy/Client2ProxyChannelInitializer.java index 0fd55b6..2c87d04 100644 --- a/src/main/java/net/raphimc/viaproxy/proxy/client2proxy/Client2ProxyChannelInitializer.java +++ b/src/main/java/net/raphimc/viaproxy/proxy/client2proxy/Client2ProxyChannelInitializer.java @@ -19,6 +19,7 @@ package net.raphimc.viaproxy.proxy.client2proxy; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; +import io.netty.handler.codec.haproxy.HAProxyMessageDecoder; import net.raphimc.netminecraft.constants.MCPipeline; import net.raphimc.netminecraft.netty.connection.MinecraftChannelInitializer; import net.raphimc.netminecraft.packet.registry.PacketRegistryUtil; @@ -31,6 +32,8 @@ import java.util.function.Supplier; public class Client2ProxyChannelInitializer extends MinecraftChannelInitializer { + public static final String VIAPROXY_HAPROXY_DECODER_NAME = "viaproxy-haproxy-decoder"; + public static final String VIAPROXY_HAPROXY_HANDLER_NAME = "viaproxy-haproxy-handler"; public static final String LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME = "legacy-passthrough-initial-handler"; public Client2ProxyChannelInitializer(final Supplier handlerSupplier) { @@ -44,6 +47,10 @@ public class Client2ProxyChannelInitializer extends MinecraftChannelInitializer return; } + if (ViaProxy.getConfig().useFrontendHaProxy()) { + channel.pipeline().addLast(VIAPROXY_HAPROXY_DECODER_NAME, new HAProxyMessageDecoder()); + channel.pipeline().addLast(VIAPROXY_HAPROXY_HANDLER_NAME, new HAProxyHandler()); + } if (ViaProxy.getConfig().shouldAllowLegacyClientPassthrough()) { channel.pipeline().addLast(LEGACY_PASSTHROUGH_INITIAL_HANDLER_NAME, new LegacyPassthroughInitialHandler()); } diff --git a/src/main/java/net/raphimc/viaproxy/proxy/client2proxy/HAProxyHandler.java b/src/main/java/net/raphimc/viaproxy/proxy/client2proxy/HAProxyHandler.java new file mode 100644 index 0000000..670b8d6 --- /dev/null +++ b/src/main/java/net/raphimc/viaproxy/proxy/client2proxy/HAProxyHandler.java @@ -0,0 +1,51 @@ +/* + * This file is part of ViaProxy - https://github.com/RaphiMC/ViaProxy + * Copyright (C) 2021-2024 RK_01/RaphiMC and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.raphimc.viaproxy.proxy.client2proxy; + +import io.netty.channel.AbstractChannel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.haproxy.HAProxyCommand; +import io.netty.handler.codec.haproxy.HAProxyMessage; +import net.lenni0451.reflect.stream.RStream; + +import java.net.InetSocketAddress; + +public class HAProxyHandler extends SimpleChannelInboundHandler { + + @Override + public void channelActive(ChannelHandlerContext ctx) { + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, HAProxyMessage message) throws Exception { + if (message.command() != HAProxyCommand.PROXY) { + throw new UnsupportedOperationException("Unsupported HAProxy command: " + message.command()); + } + if (message.sourceAddress() != null) { + final InetSocketAddress sourceAddress = new InetSocketAddress(message.sourceAddress(), message.sourcePort()); + if (ctx.channel() instanceof AbstractChannel) { + RStream.of(AbstractChannel.class, ctx.channel()).fields().by("remoteAddress").set(sourceAddress); + } + } + + ctx.pipeline().remove(this); + super.channelActive(ctx); + } + +} diff --git a/src/main/resources/assets/viaproxy/viaproxy.yml b/src/main/resources/assets/viaproxy/viaproxy.yml index 9628208..b7a083f 100644 --- a/src/main/resources/assets/viaproxy/viaproxy.yml +++ b/src/main/resources/assets/viaproxy/viaproxy.yml @@ -36,6 +36,9 @@ backend-proxy-url: "" # Send HAProxy protocol messages to the target server. backend-haproxy: false # +# Read HAProxy protocol messages from client connections. +frontend-haproxy: false +# # Enables sending signed chat messages on >= 1.19 servers. chat-signing: true #