protected override void Execute()
        {
            try {
                // Handle non-proxy connections
                using (WebSocketConnection UserConnection = new WebSocketConnection(true, Config.Default.Certificate)) {
                    if (UserConnection.Open(_Socket))
                    {
                        _RemoteIP = UserConnection.GetRemoteIP();

                        RMLog.Debug("{" + _ConnectionId.ToString() + "} Opened connection from " + UserConnection.GetRemoteIP() + ":" + UserConnection.GetRemotePort());
                        if (UserConnection.Header["Path"] == "/ping")
                        {
                            // Handle ping requests (from proxy.ftelnet.ca most likely)
                            string Ping = UserConnection.ReadLn(1000);
                            if (UserConnection.ReadTimedOut)
                            {
                                RMLog.Debug("Answering a /ping (no time received) from " + UserConnection.GetRemoteIP() + ":" + UserConnection.GetRemotePort());
                            }
                            else
                            {
                                RMLog.Debug("Answering a /ping (" + Ping + ") from " + UserConnection.GetRemoteIP() + ":" + UserConnection.GetRemotePort());
                                UserConnection.Write(Ping);
                            }
                            return;
                        }
                    }
                    else
                    {
                        if (UserConnection.FlashPolicyFileRequest)
                        {
                            RMLog.Info("{" + _ConnectionId.ToString() + "} Answered flash policy file request from " + UserConnection.GetRemoteIP() + ":" + UserConnection.GetRemotePort().ToString());
                        }
                        else
                        {
                            RMLog.Debug("{" + _ConnectionId.ToString() + "} Invalid WebSocket connection from " + UserConnection.GetRemoteIP() + ":" + UserConnection.GetRemotePort().ToString());
                        }
                        return;
                    }

                    // If we get here it's a proxy connection, so handle it
                    RMLog.Info("{" + _ConnectionId.ToString() + "} Connection accepted from " + UserConnection.GetRemoteIP() + ":" + UserConnection.GetRemotePort());

                    string MessageText = string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\r\n",
                                                       DateTime.Now.ToString(),
                                                       UserConnection.GetRemoteIP(),
                                                       UserConnection.GetRemotePort(),
                                                       UserConnection.Header["Path"],
                                                       UserConnection.Protocol,
                                                       UserConnection.SubProtocol);
                    FileUtils.FileAppendAllText(Path.Combine(ProcessUtils.StartupPath, "fTelnetProxy-Connections.log"), MessageText, Encoding.ASCII);

                    // Defaults for redirect location
                    _Hostname = Config.Default.TargetHostname;
                    _Port     = Config.Default.TargetPort;

                    // Check if user is requesting a custom target
                    if (UserConnection.Header["Path"] != "/")
                    {
                        bool CanRelay = false;

                        // Extract the requested host and port
                        string[] HostAndPort = UserConnection.Header["Path"].Split('/');
                        if ((HostAndPort.Length == 3) && (int.TryParse(HostAndPort[2], out _Port)))
                        {
                            _Hostname = HostAndPort[1];
                            if (Config.Default.TargetHostname.ToLower().Trim() == _Hostname.ToLower().Trim())
                            {
                                // User is requesting the target defined by the proxy admin, so check if it's to an allowed port
                                CanRelay = ((_Port > 0) && (_Port == Config.Default.TargetPort) || (_Port == Config.Default.RLoginPort));
                            }
                            else if (!string.IsNullOrEmpty(Config.Default.RelayFilename))
                            {
                                // proxy admin has relaying enabled, so check against the relay.cfg file
                                try {
                                    // Read relay file
                                    if (File.Exists(Config.Default.RelayFilename))
                                    {
                                        string[] AllowedHosts = File.ReadAllLines(Config.Default.RelayFilename);
                                        if (AllowedHosts.Length > 0)
                                        {
                                            // Check for a whitelisted port
                                            string[] AllowedPorts = AllowedHosts[0].Split(',');
                                            foreach (string AllowedPort in AllowedPorts)
                                            {
                                                if (AllowedPort == _Port.ToString())
                                                {
                                                    CanRelay = true;
                                                    break;
                                                }
                                            }

                                            // Not a whitelisted port, check for a whitelisted host
                                            if (!CanRelay)
                                            {
                                                string RequestedHostPort = _Hostname.ToLower() + ":" + _Port.ToString();
                                                foreach (string AllowedHost in AllowedHosts)
                                                {
                                                    if (AllowedHost.Trim().ToLower() == RequestedHostPort)
                                                    {
                                                        CanRelay = true;
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        {
                                            RMLog.Error("{" + _ConnectionId.ToString() + "} Relay file is empty: '" + Config.Default.RelayFilename + "'");
                                        }
                                    }
                                    else
                                    {
                                        RMLog.Error("{" + _ConnectionId.ToString() + "} Relay file does not exist: '" + Config.Default.RelayFilename + "'");
                                    }
                                } catch (Exception ex) {
                                    RMLog.Exception(ex, "{" + _ConnectionId.ToString() + "} Error reading relay file: '" + Config.Default.RelayFilename + "'");
                                }
                            }
                        }

                        if (!CanRelay)
                        {
                            RMLog.Info("{" + _ConnectionId.ToString() + "} Rejecting request for " + _Hostname + ":" + _Port.ToString());
                            UserConnection.WriteLn("Sorry, for security reasons this proxy won't connect to " + _Hostname + ":" + _Port.ToString());
                            UserConnection.WriteLn("unless you contact me via the contact form on www.fTelnet.ca.  Just let me");
                            UserConnection.WriteLn("know the hostname and port you're trying to connect to, and I'll add it to");
                            UserConnection.WriteLn("the whitelist for you.");
                            Thread.Sleep(2500);
                            return;
                        }
                    }

                    // Try to connect to the desired Host and Port
                    UserConnection.Write(Ansi.ClrScr() + "Connecting to " + _Hostname + ":" + _Port.ToString() + "...");
                    using (TcpConnection ServerConnection = new TcpConnection()) {
                        if (ServerConnection.Connect(_Hostname, _Port))
                        {
                            RMLog.Info("{" + _ConnectionId.ToString() + "} Connected to " + _Hostname + ":" + _Port.ToString());
                            UserConnection.WriteLn("connected!");

                            // Repeatedly move data around until a connection is closed (or a stop is requested)
                            bool DoSleep = true;
                            while (!_Stop && UserConnection.Connected && ServerConnection.Connected)
                            {
                                DoSleep = true;

                                if (UserConnection.CanRead())
                                {
                                    ServerConnection.WriteBytes(UserConnection.ReadBytes());
                                    _DateLastTX = DateTime.Now;
                                    DoSleep     = false;
                                }

                                if (ServerConnection.CanRead())
                                {
                                    UserConnection.WriteBytes(ServerConnection.ReadBytes(1024)); // 1k at a time to allow non-stop screens to be aborted by user input
                                    _DateLastRX = DateTime.Now;
                                    DoSleep     = false;
                                }

                                if (DoSleep)
                                {
                                    Thread.Sleep(1);
                                }

                                // Check if we should abort due to idle times
                                // TODOX Allow to be customized
                                if (SecondsSinceLastRX > 600)
                                {
                                    // 10 minutes of no server activity
                                    RMLog.Info("{" + _ConnectionId.ToString() + "} Disconnecting after 10 minutes of no activity from server");
                                    UserConnection.Write(Ansi.GotoXY(1, 1) + Ansi.CursorDown(255) + "\r\nDisconnecting after 10 minutes of no activity from server...");
                                    Thread.Sleep(2500);
                                    break;
                                }
                                else if (SecondsSinceLastTX > 600)
                                {
                                    // 10 minutes of no user activity
                                    RMLog.Info("{" + _ConnectionId.ToString() + "} Disconnecting after 10 minutes of no activity from user");
                                    UserConnection.Write(Ansi.GotoXY(1, 1) + Ansi.CursorDown(255) + "\r\nDisconnecting after 10 minutes of no activity from user...");
                                    Thread.Sleep(2500);
                                    break;
                                }
                                else if (SecondsSinceConnecting > 21600)
                                {
                                    // 6 hours since connecting
                                    RMLog.Info("{" + _ConnectionId.ToString() + "} Disconnecting after 6 hours");
                                    UserConnection.Write(Ansi.GotoXY(1, 1) + Ansi.CursorDown(255) + "\r\nDisconnecting after 6 hours...");
                                    Thread.Sleep(2500);
                                    break;
                                }
                            }

                            // Check why we exited the loop
                            if (_Stop)
                            {
                                RMLog.Info("{" + _ConnectionId.ToString() + "} Stop requested");
                                UserConnection.Write(Ansi.GotoXY(1, 1) + Ansi.CursorDown(255) + "\r\nProxy server shutting down...");
                                Thread.Sleep(2500);
                            }
                            else if (!UserConnection.Connected)
                            {
                                RMLog.Info("{" + _ConnectionId.ToString() + "} Client closed connection");
                            }
                            else if (!ServerConnection.Connected)
                            {
                                RMLog.Info("{" + _ConnectionId.ToString() + "} Server closed connection");
                                UserConnection.Write(Ansi.GotoXY(1, 1) + Ansi.CursorDown(255) + "\r\nServer closed connection...");
                                Thread.Sleep(2500);
                            }
                        }
                        else
                        {
                            RMLog.Info("{" + _ConnectionId.ToString() + "} Unable to connect to " + _Hostname + ":" + _Port.ToString());
                            UserConnection.WriteLn("unable to connect!");
                            Thread.Sleep(2500);
                        }
                    }

                    // Display info about the connection we're closing
                    DisplayConnectionInformation();
                }
            } catch (Exception ex) {
                RMLog.Exception(ex, "{" + _ConnectionId.ToString() + "} Exception in client thread");
            }
        }
Esempio n. 2
0
        protected override void Execute()
        {
            try {
                // Handle non-proxy connections
                using (WebSocketConnection NewConnection = new WebSocketConnection(true, Config.Default.Certificate)) {
                    if (NewConnection.Open(_Socket))
                    {
                        RMLog.Debug("{" + _ConnectionId.ToString() + "} Opened connection from " + NewConnection.GetRemoteIP() + ":" + NewConnection.GetRemotePort());
                        if (NewConnection.Header["Path"] == "/ping")
                        {
                            // Handle ping requests (from proxy.ftelnet.ca most likely)
                            string Ping = NewConnection.ReadLn(1000);
                            if (NewConnection.ReadTimedOut)
                            {
                                RMLog.Debug("Answering a /ping (no time received) from " + NewConnection.GetRemoteIP() + ":" + NewConnection.GetRemotePort());
                            }
                            else
                            {
                                RMLog.Debug("Answering a /ping (" + Ping + ") from " + NewConnection.GetRemoteIP() + ":" + NewConnection.GetRemotePort());
                                NewConnection.Write(Ping);
                            }
                            return;
                        }
                    }
                    else
                    {
                        if (NewConnection.FlashPolicyFileRequest)
                        {
                            RMLog.Info("{" + _ConnectionId.ToString() + "} Answered flash policy file request from " + NewConnection.GetRemoteIP() + ":" + NewConnection.GetRemotePort().ToString());
                        }
                        else
                        {
                            RMLog.Debug("{" + _ConnectionId.ToString() + "} Invalid WebSocket connection from " + NewConnection.GetRemoteIP() + ":" + NewConnection.GetRemotePort().ToString());
                        }
                        return;
                    }

                    // If we get here it's a proxy connection, so handle it
                    RMLog.Info("{" + _ConnectionId.ToString() + "} Connection accepted from " + NewConnection.GetRemoteIP() + ":" + NewConnection.GetRemotePort());

                    string MessageText = string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\r\n",
                                                       DateTime.Now.ToString(),
                                                       NewConnection.GetRemoteIP(),
                                                       NewConnection.GetRemotePort(),
                                                       NewConnection.Header["Path"],
                                                       NewConnection.Protocol,
                                                       NewConnection.SubProtocol);
                    FileUtils.FileAppendAllText(Path.Combine(ProcessUtils.StartupPath, "fTelnetProxy-Connections.log"), MessageText, Encoding.ASCII);

                    // Defaults for redirect location
                    string Hostname = Config.Default.TargetHostname;
                    int    Port     = Config.Default.TargetPort;

                    // Check if user is requesting a custom target
                    if (NewConnection.Header["Path"] != "/")
                    {
                        bool CanRelay = false;

                        // Extract the requested host and port
                        string[] HostAndPort = NewConnection.Header["Path"].Split('/');
                        if ((HostAndPort.Length == 3) && (int.TryParse(HostAndPort[2], out Port)))
                        {
                            Hostname = HostAndPort[1];
                            if (Config.Default.TargetHostname.ToLower().Trim() == Hostname.ToLower().Trim())
                            {
                                // User is requesting the target defined by the proxy admin, so check if it's to an allowed port
                                CanRelay = ((Port > 0) && (Port == Config.Default.TargetPort) || (Port == Config.Default.RLoginPort));
                            }
                            else if (!string.IsNullOrEmpty(Config.Default.RelayFilename))
                            {
                                // proxy admin has relaying enabled, so check against the relay.cfg file
                                try {
                                    // Read relay file
                                    if (File.Exists(Config.Default.RelayFilename))
                                    {
                                        string[] AllowedHosts = File.ReadAllLines(Config.Default.RelayFilename);
                                        if (AllowedHosts.Length > 0)
                                        {
                                            // Check for a whitelisted port
                                            string[] AllowedPorts = AllowedHosts[0].Split(',');
                                            foreach (string AllowedPort in AllowedPorts)
                                            {
                                                if (AllowedPort == Port.ToString())
                                                {
                                                    CanRelay = true;
                                                    break;
                                                }
                                            }

                                            // Not a whitelisted port, check for a whitelisted host
                                            if (!CanRelay)
                                            {
                                                string RequestedHostPort = Hostname.ToLower() + ":" + Port.ToString();
                                                foreach (string AllowedHost in AllowedHosts)
                                                {
                                                    if (AllowedHost.Trim().ToLower() == RequestedHostPort)
                                                    {
                                                        CanRelay = true;
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        else
                                        {
                                            RMLog.Error("{" + _ConnectionId.ToString() + "} Relay file is empty: '" + Config.Default.RelayFilename + "'");
                                        }
                                    }
                                    else
                                    {
                                        RMLog.Error("{" + _ConnectionId.ToString() + "} Relay file does not exist: '" + Config.Default.RelayFilename + "'");
                                    }
                                } catch (Exception ex) {
                                    RMLog.Exception(ex, "{" + _ConnectionId.ToString() + "} Error reading relay file: '" + Config.Default.RelayFilename + "'");
                                }
                            }
                        }

                        if (!CanRelay)
                        {
                            RMLog.Info("{" + _ConnectionId.ToString() + "} Rejecting request for " + Hostname + ":" + Port.ToString());
                            NewConnection.WriteLn("Sorry, for security reasons this proxy won't connect to " + Hostname + ":" + Port.ToString());
                            Thread.Sleep(2500);
                            return;
                        }
                    }

                    // Try to connect to the desired Host and Port
                    NewConnection.Write(Ansi.ClrScr() + "Connecting to " + Hostname + ":" + Port.ToString() + "...");
                    using (TcpConnection _TcpConnection = new TcpConnection()) {
                        if (_TcpConnection.Connect(Hostname, Port))
                        {
                            RMLog.Info("{" + _ConnectionId.ToString() + "} Connected to " + Hostname + ":" + Port.ToString());
                            NewConnection.WriteLn("connected!");

                            // Repeatedly move data around until a connection is closed (or a stop is requested)
                            bool DoSleep = true;
                            while (!_Stop && NewConnection.Connected && _TcpConnection.Connected)
                            {
                                DoSleep = true;

                                if (NewConnection.CanRead())
                                {
                                    _TcpConnection.WriteBytes(NewConnection.ReadBytes());
                                    DoSleep = false;
                                }

                                if (_TcpConnection.CanRead())
                                {
                                    NewConnection.WriteBytes(_TcpConnection.ReadBytes());
                                    DoSleep = false;
                                }

                                if (DoSleep)
                                {
                                    Thread.Sleep(1);
                                }
                            }

                            // Check why we exited the loop
                            if (_Stop)
                            {
                                RMLog.Info("{" + _ConnectionId.ToString() + "} Stop requested");
                                NewConnection.Write(Ansi.GotoXY(1, 1) + Ansi.CursorDown(255) + "\r\nProxy server shutting down...");
                                Thread.Sleep(2500);
                            }
                            else if (!NewConnection.Connected)
                            {
                                RMLog.Info("{" + _ConnectionId.ToString() + "} Client closed connection");
                            }
                            else if (!_TcpConnection.Connected)
                            {
                                RMLog.Info("{" + _ConnectionId.ToString() + "} Server closed connection");
                                NewConnection.Write(Ansi.GotoXY(1, 1) + Ansi.CursorDown(255) + "\r\nServer closed connection...");
                                Thread.Sleep(2500);
                            }
                        }
                        else
                        {
                            RMLog.Info("{" + _ConnectionId.ToString() + "} Unable to connect to " + Hostname + ":" + Port.ToString());
                            NewConnection.WriteLn("unable to connect!");
                            Thread.Sleep(2500);
                        }
                    }
                }
            } catch (Exception ex) {
                RMLog.Exception(ex, "{" + _ConnectionId.ToString() + "} Exception in client thread");
            }
        }