using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; using Server; using Server.Network; namespace Server.Accounting { public class AccountAttackLimiter { public static bool Enabled = true; public static void Initialize() { if ( !Enabled ) return; PacketHandlers.RegisterThrottler( 0x80, new ThrottlePacketCallback( Throttle_Callback ) ); PacketHandlers.RegisterThrottler( 0x91, new ThrottlePacketCallback( Throttle_Callback ) ); PacketHandlers.RegisterThrottler( 0xCF, new ThrottlePacketCallback( Throttle_Callback ) ); } public static bool Throttle_Callback( NetState ns ) { InvalidAccountAccessLog accessLog = FindAccessLog( ns ); if ( accessLog == null ) return true; return ( DateTime.Now >= (accessLog.LastAccessTime + ComputeThrottle( accessLog.Counts )) ); } private static List m_List = new List(); public static InvalidAccountAccessLog FindAccessLog( NetState ns ) { if ( ns == null ) return null; IPAddress ipAddress = ns.Address; for ( int i = 0; i < m_List.Count; ++i ) { InvalidAccountAccessLog accessLog = m_List[i]; if ( accessLog.HasExpired ) m_List.RemoveAt( i-- ); else if ( accessLog.Address.Equals( ipAddress ) ) return accessLog; } return null; } public static void RegisterInvalidAccess( NetState ns ) { if ( ns == null || !Enabled ) return; InvalidAccountAccessLog accessLog = FindAccessLog( ns ); if ( accessLog == null ) m_List.Add( accessLog = new InvalidAccountAccessLog( ns.Address ) ); accessLog.Counts += 1; accessLog.RefreshAccessTime(); if ( accessLog.Counts >= 3 ) { try { using ( StreamWriter op = new StreamWriter( "throttle.log", true ) ) { op.WriteLine( "{0}\t{1}\t{2}", DateTime.Now, ns, accessLog.Counts ); } } catch { } } } public static TimeSpan ComputeThrottle( int counts ) { if ( counts >= 15 ) return TimeSpan.FromMinutes( 5.0 ); if ( counts >= 10 ) return TimeSpan.FromMinutes( 1.0 ); if ( counts >= 5 ) return TimeSpan.FromSeconds( 20.0 ); if ( counts >= 3 ) return TimeSpan.FromSeconds( 10.0 ); if ( counts >= 1 ) return TimeSpan.FromSeconds( 2.0 ); return TimeSpan.Zero; } } public class InvalidAccountAccessLog { private IPAddress m_Address; private DateTime m_LastAccessTime; private int m_Counts; public IPAddress Address { get{ return m_Address; } set{ m_Address = value; } } public DateTime LastAccessTime { get{ return m_LastAccessTime; } set{ m_LastAccessTime = value; } } public bool HasExpired { get{ return ( DateTime.Now >= ( m_LastAccessTime + TimeSpan.FromHours( 1.0 ) ) ); } } public int Counts { get{ return m_Counts; } set{ m_Counts = value; } } public void RefreshAccessTime() { m_LastAccessTime = DateTime.Now; } public InvalidAccountAccessLog( IPAddress address ) { m_Address = address; RefreshAccessTime(); } } }