diff --git a/api/src/main/java/net/md_5/bungee/api/event/ClientConnectEvent.java b/api/src/main/java/net/md_5/bungee/api/event/ClientConnectEvent.java
new file mode 100644
index 00000000..50ce034c
--- /dev/null
+++ b/api/src/main/java/net/md_5/bungee/api/event/ClientConnectEvent.java
@@ -0,0 +1,35 @@
+package net.md_5.bungee.api.event;
+
+import java.net.SocketAddress;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import net.md_5.bungee.api.config.ListenerInfo;
+import net.md_5.bungee.api.plugin.Cancellable;
+import net.md_5.bungee.api.plugin.Event;
+
+/**
+ * Event called to represent an initial client connection.
+ *
+ * Note: This event is called at an early stage of every connection, handling
+ * should be fast.
+ */
+@Data
+@ToString(callSuper = false)
+@EqualsAndHashCode(callSuper = false)
+public class ClientConnectEvent extends Event implements Cancellable
+{
+
+ /**
+ * Cancelled state.
+ */
+ private boolean cancelled;
+ /**
+ * Remote address of connection.
+ */
+ private final SocketAddress socketAddress;
+ /**
+ * Listener that accepted the connection.
+ */
+ private final ListenerInfo listener;
+}
diff --git a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java
index 44e28846..afc2c12a 100644
--- a/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java
+++ b/proxy/src/main/java/net/md_5/bungee/netty/PipelineUtils.java
@@ -36,6 +36,7 @@ import net.md_5.bungee.UserConnection;
import net.md_5.bungee.Util;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ListenerInfo;
+import net.md_5.bungee.api.event.ClientConnectEvent;
import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.protocol.KickStringWriter;
import net.md_5.bungee.protocol.LegacyDecoder;
@@ -56,7 +57,9 @@ public class PipelineUtils
@Override
protected void initChannel(Channel ch) throws Exception
{
- if ( BungeeCord.getInstance().getConnectionThrottle() != null && BungeeCord.getInstance().getConnectionThrottle().throttle( ch.remoteAddress() ) )
+ SocketAddress remoteAddress = ( ch.remoteAddress() == null ) ? ch.parent().localAddress() : ch.remoteAddress();
+
+ if ( BungeeCord.getInstance().getConnectionThrottle() != null && BungeeCord.getInstance().getConnectionThrottle().throttle( remoteAddress ) )
{
ch.close();
return;
@@ -64,6 +67,12 @@ public class PipelineUtils
ListenerInfo listener = ch.attr( LISTENER ).get();
+ if ( BungeeCord.getInstance().getPluginManager().callEvent( new ClientConnectEvent( remoteAddress, listener ) ).isCancelled() )
+ {
+ ch.close();
+ return;
+ }
+
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() ) );