Beispiel #1
0
        /// <summary>
        ///     The establish method is used to connect to the server and try to request access to the specific address.
        /// </summary>
        /// <param name="address">
        ///     The requested address.
        /// </param>
        /// <param name="port">
        ///     The requested port.
        /// </param>
        /// <param name="client">
        ///     The client to connect with.
        /// </param>
        /// <param name="headerData">
        ///     The data to send after connecting.
        /// </param>
        /// <param name="sendDataDelegate">
        ///     The send callback.
        /// </param>
        /// <param name="receiveDataDelegate">
        ///     The receive callback.
        /// </param>
        /// <param name="connectionStatusCallback">
        ///     The connection status changed callback.
        /// </param>
        public override void Establish(
            string address,
            ushort port,
            ProxyClient client,
            byte[] headerData = null,
            DataCallbackDelegate sendDataDelegate               = null,
            DataCallbackDelegate receiveDataDelegate            = null,
            ConnectionCallbackDelegate connectionStatusCallback = null)
        {
            try
            {
                this.requestedAddress         = address;
                this.requestedPort            = port;
                this.ParentClient             = client;
                this.SendDataDelegate         = sendDataDelegate;
                this.ReceiveDataDelegate      = receiveDataDelegate;
                this.ConnectionStatusCallback = connectionStatusCallback;
                this.UnderlyingSocket         = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                this.UnderlyingSocket.BeginConnect(
                    this.ServerAddress,
                    this.ServerPort,
                    delegate(IAsyncResult ar)
                {
                    try
                    {
                        this.UnderlyingSocket.EndConnect(ar);
                        this.UnderlyingSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, true);
                        this.ParentClient.Controller.FailAttempts = 0;
                        HttpForger.SendRequest(
                            this.UnderlyingSocket,
                            string.IsNullOrWhiteSpace(this.ServerDomain) ? "~" : this.ServerDomain, "~",
                            this.ForgerCompatibility ? "LINK" : "GET");
                        if (new HttpForger(this.UnderlyingSocket).ReceiveResponse()
                            != HttpForger.CurrentState.ValidData)
                        {
                            this.Close(
                                "HTTPForger failed to validate server response.",
                                null,
                                ErrorRenderer.HttpHeaderCode.C417ExpectationFailed);
                            return;
                        }

                        this.Protocol = new PeaRoxyProtocol(
                            this.UnderlyingSocket,
                            this.encryptionType,
                            this.compressionTypes)
                        {
                            ReceivePacketSize = this.ParentClient.ReceivePacketSize,
                            SendPacketSize    = this.ParentClient.SendPacketSize,
                            CloseCallback     = this.Close
                        };

                        byte[] clientRequest;
                        if (this.Username.Trim() != string.Empty && this.Password != string.Empty)
                        {
                            byte[] username = Encoding.ASCII.GetBytes(this.Username.Trim());
                            byte[] password = Encoding.ASCII.GetBytes(this.Password);
                            password        = MD5.Create().ComputeHash(password);
                            if (username.Length > 255)
                            {
                                this.Close(
                                    "Username is too long.",
                                    null,
                                    ErrorRenderer.HttpHeaderCode.C417ExpectationFailed);
                                return;
                            }

                            clientRequest    = new byte[3 + username.Length + password.Length];
                            clientRequest[0] = (byte)Common.AuthenticationMethods.UserPass;
                            clientRequest[1] = (byte)username.Length;
                            clientRequest[username.Length + 2] = (byte)password.Length;

                            Array.Copy(username, 0, clientRequest, 2, username.Length);
                            Array.Copy(password, 0, clientRequest, username.Length + 3, password.Length);
                        }
                        else
                        {
                            clientRequest    = new byte[1];
                            clientRequest[0] = (byte)Common.AuthenticationMethods.None;
                        }

                        byte clientAddressType;
                        IPAddress clientIp;
                        byte[] clientAddressBytes;
                        if (IPAddress.TryParse(this.requestedAddress, out clientIp))
                        {
                            clientAddressBytes = clientIp.GetAddressBytes();
                            if (clientAddressBytes.Length == 16)
                            {
                                clientAddressType = 4;
                            }
                            else if (clientAddressBytes.Length == 4)
                            {
                                clientAddressType = 1;
                            }
                            else
                            {
                                this.Close(
                                    "Unknown IP Type.",
                                    null,
                                    ErrorRenderer.HttpHeaderCode.C417ExpectationFailed);
                                return;
                            }
                        }
                        else
                        {
                            clientAddressType  = 3;
                            clientAddressBytes = Encoding.ASCII.GetBytes(this.requestedAddress);
                        }

                        byte[] clientRequestAddress =
                            new byte[6 + clientAddressBytes.Length + ((clientAddressType == 3) ? 1 : 0)];
                        clientRequestAddress[0] = ProtocolVersion;
                        clientRequestAddress[1] = 0;
                        clientRequestAddress[2] = 0;
                        clientRequestAddress[3] = clientAddressType;
                        if (clientAddressType == 3)
                        {
                            if (clientAddressBytes.Length > 255)
                            {
                                this.Close(
                                    "Hostname is too long.",
                                    null,
                                    ErrorRenderer.HttpHeaderCode.C417ExpectationFailed);
                                return;
                            }

                            clientRequestAddress[4] = (byte)clientAddressBytes.Length;
                        }

                        Array.Copy(
                            clientAddressBytes,
                            0,
                            clientRequestAddress,
                            4 + ((clientAddressType == 3) ? 1 : 0),
                            clientAddressBytes.Length);
                        clientRequestAddress[clientRequestAddress.GetUpperBound(0) - 1] =
                            (byte)Math.Floor(this.requestedPort / 256d);
                        clientRequestAddress[clientRequestAddress.GetUpperBound(0)] =
                            (byte)(this.requestedPort % 256);
                        Array.Resize(ref clientRequest, clientRequestAddress.Length + clientRequest.Length);
                        Array.Copy(
                            clientRequestAddress,
                            0,
                            clientRequest,
                            clientRequest.Length - clientRequestAddress.Length,
                            clientRequestAddress.Length);

                        this.Protocol.Write(clientRequest, false);
                        byte[] serverResponse = this.Protocol.Read();
                        if (serverResponse == null)
                        {
                            this.Close(
                                "Connection closed by server or timed out.",
                                null,
                                ErrorRenderer.HttpHeaderCode.C504GatewayTimeout);
                            return;
                        }

                        if (serverResponse[0] != clientRequestAddress[0])
                        {
                            this.Close(
                                string.Format(
                                    "Server version is different from what we expect. Server's version: {0}, Expected: {1}",
                                    serverResponse[0],
                                    clientRequestAddress[0]),
                                null,
                                ErrorRenderer.HttpHeaderCode.C502BadGateway);
                            return;
                        }

                        if (serverResponse[1] == 99)
                        {
                            this.Close(
                                "Connection failed, Error Code: Authentication Failed.",
                                null,
                                ErrorRenderer.HttpHeaderCode.C417ExpectationFailed);
                            return;
                        }

                        if (serverResponse[1] != 0)
                        {
                            this.Close(
                                "Connection failed, Error Code: " + serverResponse[1],
                                null,
                                ErrorRenderer.HttpHeaderCode.C502BadGateway);
                            return;
                        }

                        if (this.Password != string.Empty)
                        {
                            this.Protocol.EncryptionKey = Encoding.ASCII.GetBytes(this.Password);
                        }

                        this.IsServerValid = true;
                        if (headerData != null && Common.IsSocketConnected(this.UnderlyingSocket))
                        {
                            this.Protocol.Write(headerData, true);
                        }

                        this.currentTimeout = this.NoDataTimeout * 1000;
                        client.Controller.ClientMoveToRouting(this);
                    }
                    catch (Exception ex)
                    {
                        this.ParentClient.Controller.FailAttempts++;
                        this.Close(ex.Message, ex.StackTrace, ErrorRenderer.HttpHeaderCode.C504GatewayTimeout);
                    }
                },
                    null);
            }
            catch (Exception e)
            {
                this.Close(e.Message, e.StackTrace);
            }
        }
Beispiel #2
0
        /// <summary>
        ///     The method to handle the accepting process, should call repeatedly
        /// </summary>
        public void Accepting()
        {
            try
            {
                if (Common.IsSocketConnected(this.UnderlyingSocket) && this.currentTimeout > 0)
                {
                    switch (this.CurrentStage)
                    {
                    case RequestStages.JustConnected:
                        string clientAddress = this.UnderlyingSocket.RemoteEndPoint.ToString();
                        if (
                            this.Controller.Settings.BlackListedAddresses.Any(
                                blacklist => Common.DoesMatchWildCard(clientAddress, blacklist)))
                        {
                            this.Close("Blacklisted Client: " + clientAddress);
                            return;
                        }
                        this.currentTimeout = this.NoDataTimeout * 1000;
                        this.forger         = new HttpForger(
                            this.UnderlyingSocket,
                            this.Controller.Settings.PeaRoxyDomain,
                            false);
                        this.CurrentStage = RequestStages.WaitingForForger;
                        break;

                    case RequestStages.WaitingForForger:
                        var result = this.forger.ReceiveRequest();
                        if (result == HttpForger.CurrentState.ValidData)
                        {
                            HttpForger.SendResponse(this.UnderlyingSocket);
                            this.Protocol = new PeaRoxyProtocol(
                                this.UnderlyingSocket,
                                this.underlyingClientEncryption,
                                this.underlyingClientCompression)
                            {
                                ReceivePacketSize =
                                    this.underlyingClientReceivePacketSize,
                                SendPacketSize =
                                    this.underlyingClientSendPacketSize,
                                CloseCallback = this.Close,
                                ClientSupportedCompressionType =
                                    this.ClientSupportedCompressionType,
                                ClientSupportedEncryptionType =
                                    this.ClientSupportedEncryptionType
                            };
                            this.Id = Screen.ClientConnected(
                                this.Username,
                                "C." + this.Protocol.UnderlyingSocket.RemoteEndPoint);

                            // Report that a new client connected
                            this.currentTimeout = this.NoDataTimeout * 1000;
                            this.CurrentStage   = RequestStages.WaitingForWelcomeMessage;
                        }
                        else if (result == HttpForger.CurrentState.InvalidData)
                        {
                            System.IO.File.WriteAllBytes(
                                System.IO.Path.GetRandomFileName(),
                                this.forger.HeaderBytes);
                            if (this.Controller.Settings.HttpForwardingPort == 0 || !Common.IsSocketConnected(this.UnderlyingSocket))
                            {
                                this.Close();
                            }
                            else
                            {
                                this.isForwarded  = true;
                                this.CurrentStage = RequestStages.ResolvingLocalServer;
                                this.Id           = Screen.ClientConnected(
                                    this.Username,
                                    "F." + this.UnderlyingSocket.RemoteEndPoint);
                            }
                        }
                        break;

                    case RequestStages.WaitingForWelcomeMessage:
                        if (this.Protocol.IsDataAvailable())
                        {
                            byte   serverErrorCode = 0;
                            byte[] clientRequest   = this.Protocol.Read();   // Read data from client
                            if (clientRequest == null || clientRequest.Length <= 0)
                            {
                                // Check if data is correct
                                this.Close("8. " + "No data received. Connection Timeout.");
                                return;
                            }

                            ConfigUser acceptedUser = null;

                            // Select Authentication Type
                            if ((byte)this.SelectedAuthMode != clientRequest[0])
                            {
                                serverErrorCode = 99;
                            }
                            else
                            {
                                switch (this.SelectedAuthMode)
                                {
                                case Common.AuthenticationMethods.None:
                                    Array.Copy(clientRequest, 1, clientRequest, 0, clientRequest.Length - 1);
                                    break;

                                case Common.AuthenticationMethods.UserPass:
                                {
                                    // Authentication using user name and password hash
                                    string username = Encoding.ASCII.GetString(
                                        clientRequest,
                                        2,
                                        clientRequest[1]);

                                    // Read UserName
                                    byte[] passwordHash = new byte[clientRequest[clientRequest[1] + 2]];

                                    // Initialize Password Hash Byte Array
                                    Array.Copy(
                                        clientRequest,
                                        clientRequest[1] + 3,
                                        passwordHash,
                                        0,
                                        passwordHash.Length);             // Read Password Hash

                                    acceptedUser =
                                        this.Controller.Settings.AthorizedUsers.FirstOrDefault(
                                            user =>
                                            user.Username.Equals(
                                                username,
                                                StringComparison.OrdinalIgnoreCase) &&
                                            user.Hash.SequenceEqual(passwordHash));

                                    if (acceptedUser == null)
                                    {
                                        // Let check if we have a fail result with authentication, If so, Close Connection
                                        serverErrorCode = 99;
                                    }
                                    else
                                    {
                                        Screen.ChangeUser(this.Username, acceptedUser.Username, this.Id);

                                        // Let inform that user is changed, We are not "Anonymous" anymore
                                        this.Username = acceptedUser.Username;

                                        // Save user name in userId field for later access to screen
                                        Array.Copy(
                                            clientRequest,
                                            clientRequest[1] + passwordHash.Length + 3,
                                            clientRequest,
                                            0,
                                            clientRequest.Length
                                            - (clientRequest[1] + passwordHash.Length + 3));
                                    }
                                }
                                break;
                                }
                            }

                            string clientRequestedAddress = null;
                            ushort clientRequestedPort    = 0;
                            if (serverErrorCode == 0)
                            {
                                // Authentication OK
                                if (clientRequest[0] != ServerPeaRoxyVersion)
                                {
                                    // Check again if client use same version as we are
                                    this.Close();     // "6. " + "Unknown version, Expected " + version.ToString());
                                    return;
                                }

                                byte clientAddressType = clientRequest[3];

                                // Read address type client want to connect
                                byte[] clientPlainRequestedAddress;
                                switch (clientAddressType)
                                {
                                // Getting request address and port depending to address type
                                case 1:         // IPv4
                                    clientPlainRequestedAddress = new byte[4];
                                    Array.Copy(clientRequest, 4, clientPlainRequestedAddress, 0, 4);
                                    clientRequestedAddress =
                                        new IPAddress(clientPlainRequestedAddress).ToString();
                                    clientRequestedPort =
                                        (ushort)((ushort)(clientRequest[8] * 256) + clientRequest[9]);
                                    break;

                                case 3:         // Domain Name
                                    clientPlainRequestedAddress = new byte[clientRequest[4]];
                                    Array.Copy(
                                        clientRequest,
                                        5,
                                        clientPlainRequestedAddress,
                                        0,
                                        clientRequest[4]);
                                    clientRequestedAddress =
                                        Encoding.ASCII.GetString(clientPlainRequestedAddress);
                                    clientRequestedPort =
                                        (ushort)
                                        ((ushort)(clientRequest[5 + clientRequest[4]] * 256)
                                         + clientRequest[5 + clientRequest[4] + 1]);
                                    break;

                                case 4:         // IPv6
                                    clientPlainRequestedAddress = new byte[16];
                                    Array.Copy(clientRequest, 4, clientPlainRequestedAddress, 0, 16);
                                    clientRequestedAddress =
                                        new IPAddress(clientPlainRequestedAddress).ToString();
                                    clientRequestedPort =
                                        (ushort)((ushort)(clientRequest[20] * 256) + clientRequest[21]);
                                    break;

                                default:
                                    serverErrorCode = 8;         // This type of address is not supported
                                    break;
                                }

                                if (clientRequestedAddress != null)
                                {
                                    string clientRequestedConnectionString = clientRequestedAddress.ToLower().Trim()
                                                                             + ":" + clientRequestedPort;

                                    if (
                                        this.Controller.Settings.BlackListedAddresses.Any(
                                            blacklist =>
                                            Common.DoesMatchWildCard(clientRequestedConnectionString, blacklist)))
                                    {
                                        this.Close("Blacklisted Request: " + clientRequestedAddress);
                                        return;
                                    }
                                }
                            }

                            // Initialize server response to this request
                            byte[] serverResponse = new byte[2];
                            serverResponse[0] = ServerPeaRoxyVersion;
                            serverResponse[1] = serverErrorCode;
                            this.Protocol.Write(serverResponse, true);     // Send response to client

                            if (serverErrorCode != 0 || clientRequestedAddress == null)
                            {
                                // Check if we have any problem with request
                                this.Close("5. " + "Response Error, Code: " + serverErrorCode);
                                return;
                            }

                            if (acceptedUser != null)
                            {
                                this.Protocol.EncryptionKey = Encoding.ASCII.GetBytes(acceptedUser.Password);
                            }

                            Screen.SetRequestIpAddress(
                                this.Username,
                                this.Id,
                                clientRequestedAddress + ":" + clientRequestedPort);

                            // Inform that we have a request for an address
                            this.destinationSocket = new Socket(
                                AddressFamily.InterNetwork,
                                SocketType.Stream,
                                ProtocolType.Tcp);
                            this.destinationSocket.BeginConnect(
                                clientRequestedAddress,
                                clientRequestedPort,
                                delegate(IAsyncResult ar)
                            {
                                try
                                {
                                    this.destinationSocket.EndConnect(ar);
                                    this.destinationSocket.Blocking = false;
                                    this.destinationSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, true);
                                    this.currentTimeout = this.NoDataTimeout * 1000;
                                    this.Controller.ClientMoveToRouting(this);
                                    this.CurrentStage = RequestStages.Routing;
                                }
                                catch (Exception)
                                {
                                    this.Close();
                                }
                            },
                                null);

                            this.currentTimeout = this.NoDataTimeout * 1000;
                            this.CurrentStage   = RequestStages.ConnectingToTheServer;
                        }

                        break;

                    case RequestStages.ResolvingLocalServer:
                        Screen.ChangeUser(this.Username, "Forwarder", this.Id);
                        this.Username = "******";
                        Screen.SetRequestIpAddress(
                            this.Username,
                            this.Id,
                            this.Controller.Settings.HttpForwardingIp + ":"
                            + this.Controller.Settings.HttpForwardingPort);

                        // Inform that we have a request for an address
                        this.destinationSocket = new Socket(
                            AddressFamily.InterNetwork,
                            SocketType.Stream,
                            ProtocolType.Tcp);
                        this.destinationSocket.BeginConnect(
                            this.Controller.Settings.HttpForwardingIp,
                            this.Controller.Settings.HttpForwardingPort,
                            delegate(IAsyncResult ar)
                        {
                            try
                            {
                                this.destinationSocket.EndConnect(ar);
                                this.forwarder = new Forwarder(
                                    this.destinationSocket,
                                    this.underlyingClientReceivePacketSize);
                                this.forwarder.Write(this.forger.HeaderBytes);
                                this.currentTimeout = this.NoDataTimeout * 1000;
                                this.Controller.ClientMoveToRouting(this);
                                this.CurrentStage = RequestStages.Routing;
                            }
                            catch (Exception e)
                            {
                                this.Close("9. " + e.Message + "\r\n" + e.StackTrace);
                            }
                        },
                            null);

                        this.currentTimeout = this.NoDataTimeout * 1000;
                        this.CurrentStage   = RequestStages.ConnectingToTheServer;
                        break;

                    case RequestStages.ConnectingToTheServer:
                        break;
                    }

                    this.currentTimeout--;
                }
                else
                {
                    this.Close();
                }
            }
            catch (Exception e)
            {
                if (e.TargetSite.Name == "Receive")
                {
                    this.Close();
                }
                else
                {
                    this.Close("4. " + e.Message + "\r\n" + e.StackTrace);
                }
            }
        }