using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; namespace AllocsFixes.NetConnections.Servers.Telnet { public class Telnet : IServer { private const int MAX_LOGIN_ATTEMPTS = 10; private const int BLOCK_TIME_SECONDS = 10; private class LoginAttempts { private int count = 0; private DateTime lastAttempt = new DateTime (0); public bool LogAttempt () { lastAttempt = DateTime.Now; count++; return count < MAX_LOGIN_ATTEMPTS; } public bool IsBanned () { if ((DateTime.Now - lastAttempt).TotalSeconds > BLOCK_TIME_SECONDS) count = 0; return count >= MAX_LOGIN_ATTEMPTS; } } private TcpListener listener = null; private bool authEnabled = false; private List connections = new List (); private Dictionary loginAttemptsPerIP = new Dictionary (); public Telnet () { try { if (!GamePrefs.GetBool (EnumGamePrefs.TelnetEnabled)) { return; } int port = GamePrefs.GetInt (EnumGamePrefs.TelnetPort); authEnabled = GamePrefs.GetString (EnumGamePrefs.TelnetPassword).Length != 0; if (authEnabled) listener = new TcpListener (IPAddress.Any, port); else listener = new TcpListener (IPAddress.Loopback, port); listener.Start (); listener.BeginAcceptTcpClient (new AsyncCallback (AcceptClient), null); NetTelnetServer.RegisterServer (this); Log.Out ("Started Telnet on " + port); } catch (Exception e) { Log.Out ("Error in Telnet.ctor: " + e); } } public bool RegisterFailedLogin (int addressHash) { lock (loginAttemptsPerIP) { LoginAttempts la = loginAttemptsPerIP [addressHash]; return la.LogAttempt (); } } private void AcceptClient (IAsyncResult asyncResult) { if (listener.Server.IsBound) { TcpClient client = listener.EndAcceptTcpClient (asyncResult); EndPoint endpoint = client.Client.RemoteEndPoint; int addressHash = -1; if (endpoint is IPEndPoint) { addressHash = ((IPEndPoint)endpoint).Address.GetHashCode (); //Log.Out ("Hash: " + endpointAddressHash); } else { Log.Out ("EndPoint is not an IPEndPoint but: " + endpoint.GetType ().ToString ()); } lock (loginAttemptsPerIP) { LoginAttempts la = null; if (loginAttemptsPerIP.ContainsKey(addressHash)) la = loginAttemptsPerIP [addressHash]; if (la == null) { la = new LoginAttempts (); loginAttemptsPerIP [addressHash] = la; } if (!la.IsBanned ()) { TelnetConnection con = new TelnetConnection (this, client, authEnabled); connections.Add (con); } else { client.Close (); Log.Out ("Telnet connection not accepted for too many login attempts: " + endpoint); } } listener.BeginAcceptTcpClient (new AsyncCallback (AcceptClient), null); } } public void Disconnect () { try { if (listener != null) { listener.Stop (); listener = null; } foreach (TelnetConnection c in connections) { c.Close (); } } catch (Exception e) { Log.Out ("Error in Telnet.Disconnect: " + e); } } private void RemoveClosedConnections () { try { List toRemove = new List (); foreach (TelnetConnection c in connections) { if (c.IsClosed ()) toRemove.Add (c); } foreach (TelnetConnection c in toRemove) { connections.Remove (c); } } catch (Exception e) { Log.Out ("Error in Telnet.RemoveClosedConnections: " + e); } } public void WriteToClient (string line) { if (line == null) { return; } RemoveClosedConnections (); foreach (TelnetConnection c in connections) { if (c.IsAuthenticated ()) c.WriteLine (line); } } public void WriteToClient_Single (string line, IConnection client) { if (line == null) { return; } RemoveClosedConnections (); foreach (TelnetConnection con in connections) { if (con == client) { if (con.IsAuthenticated ()) con.WriteLine (line); } } } } }