using System; using System.Net.Sockets; using System.Collections.Generic; using System.Threading; using SnowLight.Communication; using SnowLight.Storage; using SnowLight.Communication.Outgoing; using SnowLight.Game.Moderation; using System.IO; using System.Text; namespace SnowLight.Game.Sessions { public static class SessionManager { private static Dictionary mSessions; private static uint mCounter; private static List mSessionsToStop; private static Thread mMonitorThread; private static Thread mLatencyTestThread; private static object mSyncRoot; public static Dictionary Sessions { get { Dictionary Copy = new Dictionary(); lock (mSessions) { try { foreach (KeyValuePair Session in mSessions) { if (Session.Value.Stopped) { continue; } Copy.Add(Session.Key, Session.Value); } } catch (Exception) { Output.WriteLine("Ataque DDos detectado y caida evitada", OutputLevel.Warning); FileStream errWriter = new System.IO.FileStream(@"Logs\DDosing_Log.ini", System.IO.FileMode.Append, System.IO.FileAccess.Write); byte[] Msg = ASCIIEncoding.ASCII.GetBytes(Output.FormatTimestamp() + "Ataque DDosing detectado y Rechazado\r\n\r\n"); errWriter.Write(Msg, 0, Msg.Length); errWriter.Dispose(); Output.WriteLine("Ataque DDos guardado entre los Logs", OutputLevel.Warning); } } return new Dictionary(Copy); } } public static Dictionary ConnectedUserData { get { Dictionary ConnectedUsers = new Dictionary(); lock (mSessions) { try { foreach (Session Session in mSessions.Values) { if (!Session.Authenticated) { continue; } ConnectedUsers.Add(Session.CharacterId, Session.CharacterInfo.Username); } } catch (Exception) { Output.WriteLine("Ataque DDos detectado...", OutputLevel.Warning); FileStream errWriter = new System.IO.FileStream(@"Logs\DDosing_Log.ini", System.IO.FileMode.Append, System.IO.FileAccess.Write); byte[] Msg = ASCIIEncoding.ASCII.GetBytes(Output.FormatTimestamp() + "Ataque DDosing detectado y Rechazado\r\n\r\n"); errWriter.Write(Msg, 0, Msg.Length); errWriter.Dispose(); Output.WriteLine("Ataque DDos guardado entre los Logs", OutputLevel.Warning); } } return ConnectedUsers; } } public static int ActiveConnections { get { lock (mSessions) { return mSessions.Count; } } } public static void Initialize() { mSessions = new Dictionary(); mSessionsToStop = new List(); mCounter = 0; mMonitorThread = new Thread(new ThreadStart(ExecuteMonitor)); mMonitorThread.Priority = ThreadPriority.BelowNormal; mMonitorThread.Name = "GameClientMonitor"; mMonitorThread.Start(); mLatencyTestThread = new Thread(new ThreadStart(ExecuteLatencyMonitor)); mLatencyTestThread.Priority = ThreadPriority.Lowest; mLatencyTestThread.Name = "SessionLatencyTester"; mLatencyTestThread.Start(); mSyncRoot = new object(); } private static void ExecuteMonitor() { try { while (Program.Alive) { List ToDispose = new List(); List ToStop = new List(); lock (mSessions) { lock (mSessionsToStop) { foreach (uint SessionId in mSessionsToStop) { if (mSessions.ContainsKey(SessionId)) { ToStop.Add(mSessions[SessionId]); } } mSessionsToStop.Clear(); } try { foreach (Session Session in mSessions.Values) { if (ToStop.Contains(Session)) { continue; } if (Session.Stopped) { if (Session.TimeStopped > 15) { ToDispose.Add(Session); } continue; } } } catch (Exception) { Output.WriteLine("Intento de DDos Detectado...", OutputLevel.Warning); FileStream errWriter = new System.IO.FileStream(@"Logs\DDosing_Log.ini", System.IO.FileMode.Append, System.IO.FileAccess.Write); byte[] Msg = ASCIIEncoding.ASCII.GetBytes(Output.FormatTimestamp() + "Ataque DDosing detectado y Rechazado\r\n\r\n"); errWriter.Write(Msg, 0, Msg.Length); errWriter.Dispose(); Output.WriteLine("Ataque DDos guardado entre los Logs", OutputLevel.Warning); } } if (ToStop.Count > 0) { using (SqlDatabaseClient MySqlClient = SqlDatabaseManager.GetClient()) { foreach (Session SessionStop in ToStop) { SessionStop.Stop(MySqlClient); } } } foreach (Session SessionDispose in ToDispose) { SessionDispose.Dispose(); lock (mSessions) { if (mSessions.ContainsKey(SessionDispose.Id)) { mSessions.Remove(SessionDispose.Id); } } } Thread.Sleep(100); } } catch (ThreadAbortException) { } catch (ThreadInterruptedException) { } } private static void ExecuteLatencyMonitor() { try { while (Program.Alive) { ServerMessage PingMessage = PingComposer.Compose(); lock (mSessions) { lock (mSessionsToStop) { try { foreach (Session Session in mSessions.Values) { if (Session.Stopped || mSessionsToStop.Contains(Session.Id)) { continue; } if (!Session.LatencyTestOk) { mSessionsToStop.Add(Session.Id); continue; } Session.LatencyTestOk = false; Session.SendData(PingMessage); } } catch (Exception) { Output.WriteLine("Intento de DDos encontrado", OutputLevel.Warning); FileStream errWriter = new System.IO.FileStream(@"Logs\DDosing_Log.ini", System.IO.FileMode.Append, System.IO.FileAccess.Write); byte[] Msg = ASCIIEncoding.ASCII.GetBytes(Output.FormatTimestamp() + "Ataque DDosing detectado y Rechazado\r\n\r\n"); errWriter.Write(Msg, 0, Msg.Length); errWriter.Dispose(); Output.WriteLine("Ataque DDos guardado entre los Logs", OutputLevel.Warning); } } } Thread.Sleep(45000); } } catch (ThreadAbortException) { } catch (ThreadInterruptedException) { } } public static void StopSession(uint SessionId) { lock (mSessionsToStop) { mSessionsToStop.Add(SessionId); } } public static bool ContainsCharacterId(uint Uid) { lock (mSessions) { foreach (Session Session in mSessions.Values) { if (!Session.Stopped && Session.CharacterId == Uid) { return true; } } } return false; } public static Session GetSessionByCharacterId(uint Id) { lock (mSessions) { try { foreach (Session Session in mSessions.Values) { if (Session.Stopped) { continue; } if (Session.CharacterId == Id) { return Session; } } } catch (Exception) { Output.WriteLine("Ataque Ddosing detectado...", OutputLevel.Warning); FileStream errWriter = new System.IO.FileStream(@"Logs\DDosing_Log.ini", System.IO.FileMode.Append, System.IO.FileAccess.Write); byte[] Msg = ASCIIEncoding.ASCII.GetBytes(Output.FormatTimestamp() + "Ataque DDosing detectado y Rechazado\r\n\r\n"); errWriter.Write(Msg, 0, Msg.Length); errWriter.Dispose(); Output.WriteLine("Ataque DDos guardado entre los Logs", OutputLevel.Warning); } } return null; } public static void BroadcastPacket(ServerMessage Message) { BroadcastPacket(Message.GetBytes(), string.Empty); } public static void BroadcastPacket(byte[] Data) { BroadcastPacket(Data, string.Empty); } public static void BroadcastPacket(ServerMessage Message, string RequiredRight) { BroadcastPacket(Message.GetBytes(), RequiredRight); } public static void BroadcastPacket(byte[] Data, string RequiredRight) { lock (mSessions) { foreach (Session Session in mSessions.Values) { if (Session == null || Session.Stopped || !Session.Authenticated || (RequiredRight.Length > 0 && !Session.HasRight(RequiredRight))) { continue; } Session.SendData(Data); } } } public static void HandleIncomingConnection(Socket IncomingSocket) { bool Reject = ModerationBanManager.IsRemoteAddressBlacklisted(IncomingSocket.RemoteEndPoint.ToString().Split(':')[0]); Output.WriteLine((Reject ? "Rejected" : "Aceptada") + " conexión desde " + IncomingSocket.RemoteEndPoint.ToString() + ".", OutputLevel.Informational); if (Reject) { try { IncomingSocket.Close(); } catch (Exception) { } return; } lock (mSyncRoot) { uint Id = mCounter++; mSessions.Add(Id, new Session(Id, IncomingSocket)); } } } }