Add support for PROXY protocol

This commit is contained in:
md_5 2017-07-01 09:38:27 +10:00
parent a5ffeae757
commit daac8d85e2
9 changed files with 58 additions and 6 deletions

View File

@ -3,15 +3,15 @@ package net.md_5.bungee.api.config;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
/**
* Class representing the configuration of a server listener. Used for allowing
* multiple listeners on different ports.
*/
@Data
@AllArgsConstructor
public class ListenerInfo
{
@ -67,6 +67,16 @@ public class ListenerInfo
* Whether to enable udp query.
*/
private final boolean queryEnabled;
/**
* Whether to support HAProxy PROXY protocol.
*/
private final boolean proxyProtocol;
@Deprecated
public ListenerInfo(InetSocketAddress host, String motd, int maxPlayers, int tabListSize, List<String> serverPriority, boolean forceDefault, Map<String, String> forcedHosts, String tabListType, boolean setLocalAddress, boolean pingPassthrough, int queryPort, boolean queryEnabled)
{
this( host, motd, maxPlayers, tabListSize, serverPriority, forceDefault, forcedHosts, tabListType, setLocalAddress, pingPassthrough, queryPort, queryEnabled, false );
}
/**
* Gets the highest priority server to join.

View File

@ -29,6 +29,12 @@
<version>1.0.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-haproxy</artifactId>
<version>${netty.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>

View File

@ -296,6 +296,11 @@ public class BungeeCord extends ProxyServer
{
for ( final ListenerInfo info : config.getListeners() )
{
if ( info.isProxyProtocol() )
{
getLogger().log( Level.WARNING, "Using PROXY protocol for listener {0}, please ensure this listener is adequately firewalled.", info.getHost() );
}
ChannelFutureListener listener = new ChannelFutureListener()
{
@Override

View File

@ -452,7 +452,7 @@ public final class UserConnection implements ProxiedPlayer
@Override
public InetSocketAddress getAddress()
{
return (InetSocketAddress) ch.getHandle().remoteAddress();
return ch.getRemoteAddress();
}
@Override

View File

@ -247,6 +247,7 @@ public class YamlConfig implements ConfigurationAdapter
boolean query = get( "query_enabled", false, val );
int queryPort = get( "query_port", 25577, val );
boolean proxyProtocol = get( "proxy_protocol", false, val );
List<String> serverPriority = new ArrayList<>( get( "priorities", Collections.EMPTY_LIST, val ) );
// Default server list migration
@ -271,7 +272,7 @@ public class YamlConfig implements ConfigurationAdapter
}
set( "priorities", serverPriority, val );
ListenerInfo info = new ListenerInfo( address, motd, maxPlayers, tabListSize, serverPriority, forceDefault, forced, value.toString(), setLocalAddress, pingPassthrough, queryPort, query );
ListenerInfo info = new ListenerInfo( address, motd, maxPlayers, tabListSize, serverPriority, forceDefault, forced, value.toString(), setLocalAddress, pingPassthrough, queryPort, query, proxyProtocol );
ret.add( info );
}

View File

@ -574,7 +574,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
@Override
public InetSocketAddress getAddress()
{
return (InetSocketAddress) ch.getHandle().remoteAddress();
return ch.getRemoteAddress();
}
@Override

View File

@ -5,8 +5,10 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
import lombok.Getter;
import lombok.Setter;
import net.md_5.bungee.compress.PacketCompressor;
import net.md_5.bungee.compress.PacketDecompressor;
import net.md_5.bungee.protocol.MinecraftDecoder;
@ -20,6 +22,9 @@ public class ChannelWrapper
private final Channel ch;
@Getter
@Setter
private InetSocketAddress remoteAddress;
@Getter
private volatile boolean closed;
@Getter
private volatile boolean closing;
@ -27,6 +32,7 @@ public class ChannelWrapper
public ChannelWrapper(ChannelHandlerContext ctx)
{
this.ch = ctx.channel();
this.remoteAddress = (InetSocketAddress) this.ch.remoteAddress();
}
public void setProtocol(Protocol protocol)

View File

@ -4,8 +4,10 @@ import com.google.common.base.Preconditions;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.haproxy.HAProxyMessage;
import io.netty.handler.timeout.ReadTimeoutException;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.logging.Level;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.connection.CancelSendSignal;
@ -65,6 +67,20 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
{
if ( msg instanceof HAProxyMessage )
{
HAProxyMessage proxy = (HAProxyMessage) msg;
InetSocketAddress newAddress = new InetSocketAddress( proxy.sourceAddress(), proxy.sourcePort() );
ProxyServer.getInstance().getLogger().log( Level.FINE, "Set remote address via PROXY {0} -> {1}", new Object[]
{
channel.getRemoteAddress(), newAddress
} );
channel.setRemoteAddress( newAddress );
return;
}
if ( handler != null )
{
PacketWrapper packet = (PacketWrapper) msg;

View File

@ -16,6 +16,7 @@ import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.haproxy.HAProxyMessageDecoder;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.util.AttributeKey;
import io.netty.util.internal.PlatformDependent;
@ -48,12 +49,19 @@ public class PipelineUtils
@Override
protected void initChannel(Channel ch) throws Exception
{
ListenerInfo listener = ch.attr( LISTENER ).get();
BASE.initChannel( ch );
ch.pipeline().addBefore( FRAME_DECODER, LEGACY_DECODER, new LegacyDecoder() );
ch.pipeline().addAfter( FRAME_DECODER, PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, true, ProxyServer.getInstance().getProtocolVersion() ) );
ch.pipeline().addAfter( FRAME_PREPENDER, PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, true, ProxyServer.getInstance().getProtocolVersion() ) );
ch.pipeline().addBefore( FRAME_PREPENDER, LEGACY_KICKER, new KickStringWriter() );
ch.pipeline().get( HandlerBoss.class ).setHandler( new InitialHandler( BungeeCord.getInstance(), ch.attr( LISTENER ).get() ) );
ch.pipeline().get( HandlerBoss.class ).setHandler( new InitialHandler( BungeeCord.getInstance(), listener ) );
if ( listener.isProxyProtocol() )
{
ch.pipeline().addFirst( new HAProxyMessageDecoder() );
}
}
};
public static final Base BASE = new Base();