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.net.InetSocketAddress;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import lombok.AccessLevel; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.Getter;
/** /**
* Class representing the configuration of a server listener. Used for allowing * Class representing the configuration of a server listener. Used for allowing
* multiple listeners on different ports. * multiple listeners on different ports.
*/ */
@Data @Data
@AllArgsConstructor
public class ListenerInfo public class ListenerInfo
{ {
@ -67,6 +67,16 @@ public class ListenerInfo
* Whether to enable udp query. * Whether to enable udp query.
*/ */
private final boolean queryEnabled; 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. * Gets the highest priority server to join.

View File

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

View File

@ -296,6 +296,11 @@ public class BungeeCord extends ProxyServer
{ {
for ( final ListenerInfo info : config.getListeners() ) 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() ChannelFutureListener listener = new ChannelFutureListener()
{ {
@Override @Override

View File

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

View File

@ -247,6 +247,7 @@ public class YamlConfig implements ConfigurationAdapter
boolean query = get( "query_enabled", false, val ); boolean query = get( "query_enabled", false, val );
int queryPort = get( "query_port", 25577, 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 ) ); List<String> serverPriority = new ArrayList<>( get( "priorities", Collections.EMPTY_LIST, val ) );
// Default server list migration // Default server list migration
@ -271,7 +272,7 @@ public class YamlConfig implements ConfigurationAdapter
} }
set( "priorities", serverPriority, val ); 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 ); ret.add( info );
} }

View File

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

View File

@ -5,8 +5,10 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import net.md_5.bungee.compress.PacketCompressor; import net.md_5.bungee.compress.PacketCompressor;
import net.md_5.bungee.compress.PacketDecompressor; import net.md_5.bungee.compress.PacketDecompressor;
import net.md_5.bungee.protocol.MinecraftDecoder; import net.md_5.bungee.protocol.MinecraftDecoder;
@ -20,6 +22,9 @@ public class ChannelWrapper
private final Channel ch; private final Channel ch;
@Getter @Getter
@Setter
private InetSocketAddress remoteAddress;
@Getter
private volatile boolean closed; private volatile boolean closed;
@Getter @Getter
private volatile boolean closing; private volatile boolean closing;
@ -27,6 +32,7 @@ public class ChannelWrapper
public ChannelWrapper(ChannelHandlerContext ctx) public ChannelWrapper(ChannelHandlerContext ctx)
{ {
this.ch = ctx.channel(); this.ch = ctx.channel();
this.remoteAddress = (InetSocketAddress) this.ch.remoteAddress();
} }
public void setProtocol(Protocol protocol) 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.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.haproxy.HAProxyMessage;
import io.netty.handler.timeout.ReadTimeoutException; import io.netty.handler.timeout.ReadTimeoutException;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.logging.Level; import java.util.logging.Level;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.connection.CancelSendSignal; import net.md_5.bungee.connection.CancelSendSignal;
@ -65,6 +67,20 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter
@Override @Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception 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 ) if ( handler != null )
{ {
PacketWrapper packet = (PacketWrapper) msg; 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.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.haproxy.HAProxyMessageDecoder;
import io.netty.handler.timeout.ReadTimeoutHandler; import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.util.AttributeKey; import io.netty.util.AttributeKey;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
@ -48,12 +49,19 @@ public class PipelineUtils
@Override @Override
protected void initChannel(Channel ch) throws Exception protected void initChannel(Channel ch) throws Exception
{ {
ListenerInfo listener = ch.attr( LISTENER ).get();
BASE.initChannel( ch ); BASE.initChannel( ch );
ch.pipeline().addBefore( FRAME_DECODER, LEGACY_DECODER, new LegacyDecoder() ); 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_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().addAfter( FRAME_PREPENDER, PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, true, ProxyServer.getInstance().getProtocolVersion() ) );
ch.pipeline().addBefore( FRAME_PREPENDER, LEGACY_KICKER, new KickStringWriter() ); 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(); public static final Base BASE = new Base();