13
0
geforkt von Mirrors/Velocity

Add PROXY protocol support (#108)

Dieser Commit ist enthalten in:
Alex Thomson 2018-10-05 07:33:27 +13:00 committet von Andrew Steinborn
Ursprung d6fb3a210e
Commit 6ed772ba14
8 geänderte Dateien mit 40 neuen und 5 gelöschten Zeilen

Datei anzeigen

@ -29,6 +29,7 @@ dependencies {
compile project(':velocity-native') compile project(':velocity-native')
compile "io.netty:netty-codec:${nettyVersion}" compile "io.netty:netty-codec:${nettyVersion}"
compile "io.netty:netty-codec-haproxy:${nettyVersion}"
compile "io.netty:netty-codec-http:${nettyVersion}" compile "io.netty:netty-codec-http:${nettyVersion}"
compile "io.netty:netty-handler:${nettyVersion}" compile "io.netty:netty-handler:${nettyVersion}"
compile "io.netty:netty-transport-native-epoll:${nettyVersion}" compile "io.netty:netty-transport-native-epoll:${nettyVersion}"

Datei anzeigen

@ -280,6 +280,10 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
return advanced.getReadTimeout(); return advanced.getReadTimeout();
} }
public boolean isProxyProtocol() {
return advanced.isProxyProtocol();
}
@Override @Override
public String toString() { public String toString() {
return MoreObjects.toStringHelper(this) return MoreObjects.toStringHelper(this)
@ -433,6 +437,9 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
@Comment({"Specify a read timeout for connections here. The default is 30 seconds."}) @Comment({"Specify a read timeout for connections here. The default is 30 seconds."})
@ConfigKey("read-timeout") @ConfigKey("read-timeout")
private int readTimeout = 30000; private int readTimeout = 30000;
@Comment("Enables compatibility with HAProxy.")
@ConfigKey("proxy-protocol")
private boolean proxyProtocol = false;
private Advanced() { private Advanced() {
} }
@ -444,6 +451,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
this.loginRatelimit = toml.getLong("login-ratelimit", 3000L).intValue(); this.loginRatelimit = toml.getLong("login-ratelimit", 3000L).intValue();
this.connectionTimeout = toml.getLong("connection-timeout", 5000L).intValue(); this.connectionTimeout = toml.getLong("connection-timeout", 5000L).intValue();
this.readTimeout = toml.getLong("read-timeout", 30000L).intValue(); this.readTimeout = toml.getLong("read-timeout", 30000L).intValue();
this.proxyProtocol = toml.getBoolean("proxy-protocol", false);
} }
} }
@ -467,6 +475,10 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
return readTimeout; return readTimeout;
} }
public boolean isProxyProtocol() {
return proxyProtocol;
}
@Override @Override
public String toString() { public String toString() {
return "Advanced{" + return "Advanced{" +
@ -475,6 +487,7 @@ public class VelocityConfiguration extends AnnotatedConfig implements ProxyConfi
", loginRatelimit=" + loginRatelimit + ", loginRatelimit=" + loginRatelimit +
", connectionTimeout=" + connectionTimeout + ", connectionTimeout=" + connectionTimeout +
", readTimeout=" + readTimeout + ", readTimeout=" + readTimeout +
", proxyProtocol=" + proxyProtocol +
'}'; '}';
} }
} }

Datei anzeigen

@ -12,12 +12,15 @@ import com.velocitypowered.proxy.protocol.StateRegistry;
import com.velocitypowered.proxy.protocol.netty.*; import com.velocitypowered.proxy.protocol.netty.*;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.*; import io.netty.channel.*;
import io.netty.handler.codec.haproxy.HAProxyMessage;
import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCountUtil;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import static com.velocitypowered.proxy.network.Connections.*; import static com.velocitypowered.proxy.network.Connections.*;
@ -30,6 +33,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
private static final Logger logger = LogManager.getLogger(MinecraftConnection.class); private static final Logger logger = LogManager.getLogger(MinecraftConnection.class);
private final Channel channel; private final Channel channel;
private SocketAddress remoteAddress;
private StateRegistry state; private StateRegistry state;
private MinecraftSessionHandler sessionHandler; private MinecraftSessionHandler sessionHandler;
private int protocolVersion; private int protocolVersion;
@ -40,6 +44,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
public MinecraftConnection(Channel channel, VelocityServer server) { public MinecraftConnection(Channel channel, VelocityServer server) {
this.channel = channel; this.channel = channel;
this.remoteAddress = channel.remoteAddress();
this.server = server; this.server = server;
this.state = StateRegistry.HANDSHAKE; this.state = StateRegistry.HANDSHAKE;
} }
@ -77,6 +82,13 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
if (!pkt.handle(sessionHandler)) { if (!pkt.handle(sessionHandler)) {
sessionHandler.handleGeneric((MinecraftPacket) msg); sessionHandler.handleGeneric((MinecraftPacket) msg);
} }
} else if (msg instanceof HAProxyMessage) {
if (sessionHandler.beforeHandle()) {
return;
}
HAProxyMessage proxyMessage = (HAProxyMessage) msg;
this.remoteAddress = new InetSocketAddress(proxyMessage.sourceAddress(), proxyMessage.sourcePort());
} else if (msg instanceof ByteBuf) { } else if (msg instanceof ByteBuf) {
try { try {
if (sessionHandler.beforeHandle()) { if (sessionHandler.beforeHandle()) {
@ -153,6 +165,10 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter {
return !channel.isActive(); return !channel.isActive();
} }
public SocketAddress getRemoteAddress() {
return remoteAddress;
}
public StateRegistry getState() { public StateRegistry getState() {
return state; return state;
} }

Datei anzeigen

@ -122,7 +122,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player {
@Override @Override
public InetSocketAddress getRemoteAddress() { public InetSocketAddress getRemoteAddress() {
return (InetSocketAddress) connection.getChannel().remoteAddress(); return (InetSocketAddress) connection.getRemoteAddress();
} }
@Override @Override

Datei anzeigen

@ -77,7 +77,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
return true; return true;
} }
InetAddress address = ((InetSocketAddress) connection.getChannel().remoteAddress()).getAddress(); InetAddress address = ((InetSocketAddress) connection.getRemoteAddress()).getAddress();
if (!server.getIpAttemptLimiter().attempt(address)) { if (!server.getIpAttemptLimiter().attempt(address)) {
connection.closeWith(Disconnect.create(TextComponent.of("You are logging in too fast, try again later."))); connection.closeWith(Disconnect.create(TextComponent.of("You are logging in too fast, try again later.")));
return true; return true;
@ -129,7 +129,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler {
@Override @Override
public InetSocketAddress getRemoteAddress() { public InetSocketAddress getRemoteAddress() {
return (InetSocketAddress) connection.getChannel().remoteAddress(); return (InetSocketAddress) connection.getRemoteAddress();
} }
@Override @Override

Datei anzeigen

@ -18,7 +18,7 @@ class InitialInboundConnection implements InboundConnection {
@Override @Override
public InetSocketAddress getRemoteAddress() { public InetSocketAddress getRemoteAddress() {
return (InetSocketAddress) connection.getChannel().remoteAddress(); return (InetSocketAddress) connection.getRemoteAddress();
} }
@Override @Override

Datei anzeigen

@ -101,7 +101,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
byte[] decryptedSharedSecret = EncryptionUtils.decryptRsa(serverKeyPair, packet.getSharedSecret()); byte[] decryptedSharedSecret = EncryptionUtils.decryptRsa(serverKeyPair, packet.getSharedSecret());
String serverId = EncryptionUtils.generateServerId(decryptedSharedSecret, serverKeyPair.getPublic()); String serverId = EncryptionUtils.generateServerId(decryptedSharedSecret, serverKeyPair.getPublic());
String playerIp = ((InetSocketAddress) inbound.getChannel().remoteAddress()).getHostString(); String playerIp = ((InetSocketAddress) inbound.getRemoteAddress()).getHostString();
server.getHttpClient() server.getHttpClient()
.get(new URL(String.format(MOJANG_SERVER_AUTH_URL, login.getUsername(), serverId, playerIp))) .get(new URL(String.format(MOJANG_SERVER_AUTH_URL, login.getUsername(), serverId, playerIp)))
.thenAcceptAsync(profileResponse -> { .thenAcceptAsync(profileResponse -> {

Datei anzeigen

@ -20,6 +20,7 @@ import io.netty.channel.socket.SocketChannel;
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 org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -77,6 +78,10 @@ public final class ConnectionManager {
connection.setState(StateRegistry.HANDSHAKE); connection.setState(StateRegistry.HANDSHAKE);
connection.setSessionHandler(new HandshakeSessionHandler(connection, server)); connection.setSessionHandler(new HandshakeSessionHandler(connection, server));
ch.pipeline().addLast(Connections.HANDLER, connection); ch.pipeline().addLast(Connections.HANDLER, connection);
if (server.getConfiguration().isProxyProtocol()) {
ch.pipeline().addFirst(new HAProxyMessageDecoder());
}
} }
}) })
.childOption(ChannelOption.TCP_NODELAY, true) .childOption(ChannelOption.TCP_NODELAY, true)