--- a/net/minecraft/server/network/HandshakeListener.java
+++ b/net/minecraft/server/network/HandshakeListener.java
@@ -11,8 +11,17 @@
 import net.minecraft.network.protocol.login.PacketLoginOutDisconnect;
 import net.minecraft.server.MinecraftServer;
 
+// CraftBukkit start
+import java.net.InetAddress;
+import java.util.HashMap;
+// CraftBukkit end
+
 public class HandshakeListener implements PacketHandshakingInListener {
 
+    // CraftBukkit start - add fields
+    private static final HashMap<InetAddress, Long> throttleTracker = new HashMap<InetAddress, Long>();
+    private static int throttleCounter = 0;
+    // CraftBukkit end
     private static final IChatBaseComponent IGNORE_STATUS_REASON = new ChatComponentText("Ignoring status request");
     private final MinecraftServer server;
     private final NetworkManager connection;
@@ -27,6 +36,40 @@
         switch (packethandshakinginsetprotocol.b()) {
             case LOGIN:
                 this.connection.setProtocol(EnumProtocol.LOGIN);
+                // CraftBukkit start - Connection throttle
+                try {
+                    long currentTime = System.currentTimeMillis();
+                    long connectionThrottle = this.server.server.getConnectionThrottle();
+                    InetAddress address = ((java.net.InetSocketAddress) this.connection.getSocketAddress()).getAddress();
+
+                    synchronized (throttleTracker) {
+                        if (throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - throttleTracker.get(address) < connectionThrottle) {
+                            throttleTracker.put(address, currentTime);
+                            ChatMessage chatmessage = new ChatMessage("Connection throttled! Please wait before reconnecting.");
+                            this.connection.sendPacket(new PacketLoginOutDisconnect(chatmessage));
+                            this.connection.close(chatmessage);
+                            return;
+                        }
+
+                        throttleTracker.put(address, currentTime);
+                        throttleCounter++;
+                        if (throttleCounter > 200) {
+                            throttleCounter = 0;
+
+                            // Cleanup stale entries
+                            java.util.Iterator iter = throttleTracker.entrySet().iterator();
+                            while (iter.hasNext()) {
+                                java.util.Map.Entry<InetAddress, Long> entry = (java.util.Map.Entry) iter.next();
+                                if (entry.getValue() > connectionThrottle) {
+                                    iter.remove();
+                                }
+                            }
+                        }
+                    }
+                } catch (Throwable t) {
+                    org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t);
+                }
+                // CraftBukkit end
                 if (packethandshakinginsetprotocol.c() != SharedConstants.getGameVersion().getProtocolVersion()) {
                     ChatMessage chatmessage;
 
@@ -40,6 +83,7 @@
                     this.connection.close(chatmessage);
                 } else {
                     this.connection.setPacketListener(new LoginListener(this.server, this.connection));
+                    ((LoginListener) this.connection.j()).hostname = packethandshakinginsetprotocol.hostName + ":" + packethandshakinginsetprotocol.port; // CraftBukkit - set hostname
                 }
                 break;
             case STATUS:
