/// <summary> /// Request an ssl connection to the server. /// </summary> /// <param name="sender">The current server to client connection channel.</param> /// <param name="data">The data from the client.</param> private void SslConnection(Pop3TlsProxyConnection sender, string data) { try { // Create an ssl connection from the socket. // Reply to the client that a ssl connection // is being created. sender.InitializingSSLConnection("OK Begin TLS negotiation now"); sender.TlsNegotiated = true; } catch (Exception e) { // Detect a thread abort exception. if (e is ThreadAbortException) { Thread.ResetAbort(); } base.Write("Pop3TlsProxyServer", "SslConnection", e.Message, 382, WriteTo.EventLog, LogType.Error); // Reply to client internal server error command. ReplyToSender(sender, "500 -ERROR"); } }
/// <summary> /// Connect the client to the server. /// </summary> /// <param name="sender">The current server to client connection channel.</param> /// <param name="data">The data from the client.</param> /// <param name="command">The command sent.</param> private void Connect(Pop3TlsProxyConnection sender, string data, string command) { try { // Is the command user. if (command.Equals("USER")) { sender.ConnectionName = data; } // Is the command pass then connected if (command.Equals("PASS")) { sender.Connected = true; } // Send the command to the pop3 server. sender.SendSocketCommand(data); } catch (Exception e) { // Detect a thread abort exception. if (e is ThreadAbortException) { Thread.ResetAbort(); } base.Write("Pop3TlsProxyServer", "Connect", e.Message, 382, WriteTo.EventLog, LogType.Error); // Reply to client internal server error command. ReplyToSender(sender, "500 Error"); } }
/// <summary> /// Ends the current client connection. /// </summary> /// <param name="sender">The current server to client connection channel.</param> private void EndConnection(Pop3TlsProxyConnection sender) { // Release the current client connection // resources and make avaliable a new connection. if (_client[sender.ClientIndex] != null) { _client[sender.ClientIndex].Dispose(); _client[sender.ClientIndex] = null; // Decrement the count. Interlocked.Decrement(ref _clientCount); // Signal to the blocking handler // to un-block. _connAvailable.Set(); } }
/// <summary> /// Unknown command received. /// </summary> /// <param name="sender">The current server to client connection channel.</param> private void Unknown(Pop3TlsProxyConnection sender) { if (sender.Connected) { // Reply to client with unknown command. ReplyToSender(sender, "-ERR Unknown command"); } else { // If an unknown command is sent when the channel is opened // but the user has not supplied valid credentials then close // the socket channel to the client. This is needed when a // client opens a socket channel and starts sending a DOS // attack. Disconnect(sender); } }
/// <summary> /// Disconnect the client from the server, close the channel. /// </summary> /// <param name="sender">The current server to client connection channel.</param> private void Disconnect(Pop3TlsProxyConnection sender) { sender.Connected = false; sender.Disconnect(); sender = null; }
/// <summary> /// Reply to the current client. /// </summary> /// <param name="sender">The current server to client connection channel.</param> /// <param name="command">The command to send to the client.</param> private void ReplyToSender(Pop3TlsProxyConnection sender, string command) { sender.SendCommand(command); }
/// <summary> /// Processes all in-comming client command requests. /// </summary> /// <param name="sender">The current server to client connection channel.</param> /// <param name="dataReceived">The data received from the client.</param> private void client_OnDataReceived(Pop3TlsProxyConnection sender, string dataReceived) { try { // Decrypt the data recived from the client. string receivedData = dataReceived.Trim(); string command = string.Empty; // Get specific commands from the client. if (receivedData.ToUpper().IndexOf("QUIT") > -1) { command = "QUIT"; } else if (receivedData.ToUpper().IndexOf("USER") > -1) { command = "USER"; } else if (receivedData.ToUpper().IndexOf("STARTTLS") > -1) { command = "STARTTLS"; } else if (receivedData.ToUpper().IndexOf("CAPABILITY") > -1) { command = "CAPABILITY"; } else if (receivedData.ToUpper().IndexOf("PASS") > -1) { command = "PASS"; } else if (receivedData.ToUpper().IndexOf("ENDC") > -1) { command = "ENDC"; } else { command = receivedData; } // Delay. System.Threading.Thread.Sleep(10); // Process the command. switch (command.ToUpper()) { case "QUIT": // Close the client connection. Disconnect(sender); break; case "USER": // User name. Connect(sender, receivedData, command); break; case "PASS": // User password. Connect(sender, receivedData, command); break; case "CAPABILITY": if (!sender.TlsNegotiated) { sender.SendNonSSLClientCommand("* CAPABILITY POP3 STARTTLS LOGINDISABLED"); sender.SendNonSSLClientCommand("OK CAPABILITY completed"); } else { // Send the command to the pop3 server. sender.SendSocketCommand(receivedData); } break; case "STARTTLS": // Start a TLS connection. SslConnection(sender, receivedData); break; case "ENDC": // End the client connection. EndConnection(sender); break; default: // An unknown command sent. //Unknown(sender); sender.SendSocketCommand(receivedData); break; } } catch (Exception e) { // Detect a thread abort exception. if (e is ThreadAbortException) { Thread.ResetAbort(); } base.Write("Pop3TlsProxyServer", "OnDataReceived", e.Message, 292, WriteTo.EventLog, LogType.Error); // Reply to client internal server error command. ReplyToSender(sender, "500 Error"); } }
/// <summary> /// Starts listening on the specified port. /// </summary> public void StartListen() { try { // Get the pop3 server information from // the configuration file, the host and // port of the pop3 server is located in // the default section, this data is used // to connect to the pop3 server. GetPop3ServerHost(); // Get the listening port from the configuration // file, if no port specified then default or // the current port set will be used. GetListeningPort(); // Get the maximum number of clients from the configuration // file, if no value is specified then default or // the current value will be used. GetMaxNumClients(); // Get the client idle time out from the configuration // file, if no value is specified then default or // the current value will be used. GetClientTimeOut(); // Get the local end point, the server will listen // on only the first IP address assigned. //IPEndPoint endPoint = new IPEndPoint(Dns.GetHostEntry(remoteHost).AddressList[0], listenPort); // Create a new tcp listener server, // and start the server. _listener = new TcpListener(System.Net.IPAddress.Any, _listenPort); _listener.Start(); // While the server is alive accept in-comming client // connections. do { // Do not allow any more clients // if maximum is reached. if (_clientCount < (_maxNumClients - 1)) { // Find the next available // connection within the list. for (int i = 0; i < _client.Count(); i++) { if (_client[i] == null) { _clientIndex = i; break; } } // Create a new client connection handler for the current // tcp client attempting to connect to the server. Creates // a new channel from the client to the server. _client[_clientIndex] = new Pop3TlsProxyConnection(_listener.AcceptTcpClient(), _connection); // Assign the current index. _client[_clientIndex].ClientIndex = _clientIndex; // if a time out has been set. if (_timeOut > 0) { _client[_clientIndex].TimeOut = _timeOut; } // Create a new client data receive handler, this event // handles commands from the current client. _client[_clientIndex].OnDataReceived += new TlsProxyPop3ReceiveHandler(client_OnDataReceived); // Increment the count. Interlocked.Increment(ref _clientCount); } else { base.Write("Pop3TlsProxyServer", "StartListen", "Maximum number of client connections has been reached.", 120, WriteTo.EventLog, LogType.Error); // Blocks the current thread until a // connection becomes available. _connAvailable.WaitOne(); } } while (true); } catch (SocketException see) { base.Write("Pop3TlsProxyServer", "StartListen", see.Message, 121, WriteTo.EventLog, LogType.Error); } catch (Exception e) { // Detect a thread abort exception. if (e is ThreadAbortException) { Thread.ResetAbort(); } base.Write("Pop3TlsProxyServer", "StartListen", e.Message, 121, WriteTo.EventLog, LogType.Error); } finally { if (_listener != null) { _listener.Stop(); } _listener = null; } }