Exemplo n.º 1
0
        /// <summary>
        /// Binds the channel to the specified endpoint.
        /// </summary>
        /// <param name="remoteEndpoint">The endpoint to connect to.</param>
        /// <param name="forwardedPort">The forwarded port for which the channel is opened.</param>
        public void Bind(IPEndPoint remoteEndpoint, IForwardedPort forwardedPort)
        {
            if (!IsConnected)
            {
                throw new SshException("Session is not connected.");
            }

            _forwardedPort          = forwardedPort;
            _forwardedPort.Closing += ForwardedPort_Closing;

            //  Try to connect to the socket
            try
            {
                _socket = SocketAbstraction.Connect(remoteEndpoint, ConnectionInfo.Timeout);

                // send channel open confirmation message
                SendMessage(new ChannelOpenConfirmationMessage(RemoteChannelNumber, LocalWindowSize, LocalPacketSize, LocalChannelNumber));
            }
            catch (Exception exp)
            {
                // send channel open failure message
                SendMessage(new ChannelOpenFailureMessage(RemoteChannelNumber, exp.ToString(), ChannelOpenFailureMessage.ConnectFailed, "en"));

                throw;
            }

            var buffer = new byte[RemotePacketSize];

            SocketAbstraction.ReadContinuous(_socket, buffer, 0, buffer.Length, SendData);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Reads a null terminated string from a socket.
        /// </summary>
        /// <param name="socket">The <see cref="Socket"/> to read from.</param>
        /// <param name="timeout">The timeout to apply to individual reads.</param>
        /// <returns>
        /// The <see cref="string"/> read, or <c>null</c> when the socket was closed.
        /// </returns>
        private static string ReadString(Socket socket, TimeSpan timeout)
        {
            var text   = new StringBuilder();
            var buffer = new byte[1];

            while (true)
            {
                if (SocketAbstraction.Read(socket, buffer, 0, 1, timeout) == 0)
                {
                    // SOCKS client closed connection
                    return(null);
                }

                var byteRead = buffer[0];
                if (byteRead == 0)
                {
                    // end of the string
                    break;
                }

                var c = (char)byteRead;
                text.Append(c);
            }
            return(text.ToString());
        }
Exemplo n.º 3
0
        private void EstablishSocks4Connection(Socket client)
        {
            var userNameBytes = Encoding.ASCII.GetBytes(_userName);
            var addressBytes  = _remoteEndpoint.Address.GetAddressBytes();
            var portBytes     = BitConverter.GetBytes((ushort)_remoteEndpoint.Port).Reverse().ToArray();

            _client.Connect(_endpoint);

            // send SOCKS version
            client.Send(new byte[] { 0x04 }, 0, 1, SocketFlags.None);
            // send command byte
            client.Send(new byte[] { 0x00 }, 0, 1, SocketFlags.None);
            // send port
            client.Send(portBytes, 0, portBytes.Length, SocketFlags.None);
            // send address
            client.Send(addressBytes, 0, addressBytes.Length, SocketFlags.None);
            // send user name
            client.Send(userNameBytes, 0, userNameBytes.Length, SocketFlags.None);
            // terminate user name with null
            client.Send(new byte[] { 0x00 }, 0, 1, SocketFlags.None);

            var buffer    = new byte[8];
            var bytesRead = SocketAbstraction.Read(client, buffer, 0, buffer.Length, TimeSpan.FromMilliseconds(500));

            Assert.AreEqual(buffer.Length, bytesRead);

            // wait until SOCKS client is bound to channel
            Assert.IsTrue(_channelBindStarted.WaitOne(TimeSpan.FromMilliseconds(200)));
        }
Exemplo n.º 4
0
        private bool HandleSocks4(Socket socket, IChannelDirectTcpip channel, TimeSpan timeout)
        {
            var commandCode = SocketAbstraction.ReadByte(socket, timeout);

            if (commandCode == 0)
            {
                // SOCKS client closed connection
                return(false);
            }

            //  TODO:   See what need to be done depends on the code

            var portBuffer = new byte[2];

            if (SocketAbstraction.Read(socket, portBuffer, 0, portBuffer.Length, timeout) == 0)
            {
                // SOCKS client closed connection
                return(false);
            }

            var port = (uint)(portBuffer[0] * 256 + portBuffer[1]);

            var ipBuffer = new byte[4];

            if (SocketAbstraction.Read(socket, ipBuffer, 0, ipBuffer.Length, timeout) == 0)
            {
                // SOCKS client closed connection
                return(false);
            }

            var ipAddress = new IPAddress(ipBuffer);

            var username = ReadString(socket, timeout);

            if (username == null)
            {
                // SOCKS client closed connection
                return(false);
            }

            var host = ipAddress.ToString();

            RaiseRequestReceived(host, port);

            channel.Open(host, port, this, socket);

            SocketAbstraction.SendByte(socket, 0x00);

            if (channel.IsOpen)
            {
                SocketAbstraction.SendByte(socket, 0x5a);
                SocketAbstraction.Send(socket, portBuffer, 0, portBuffer.Length);
                SocketAbstraction.Send(socket, ipBuffer, 0, ipBuffer.Length);
                return(true);
            }

            // signal that request was rejected or failed
            SocketAbstraction.SendByte(socket, 0x5b);
            return(false);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Performs a blocking read on the socket until a line is read.
        /// </summary>
        /// <param name="socket">The <see cref="Socket"/> to read from.</param>
        /// <param name="readTimeout">A <see cref="TimeSpan"/> that represents the time to wait until a line is read.</param>
        /// <exception cref="SshOperationTimeoutException">The read has timed-out.</exception>
        /// <exception cref="SocketException">An error occurred when trying to access the socket.</exception>
        /// <returns>
        /// The line read from the socket, or <c>null</c> when the remote server has shutdown and all data has been received.
        /// </returns>
        private static string SocketReadLine(Socket socket, TimeSpan readTimeout)
        {
            var encoding = SshData.Ascii;
            var buffer   = new List <byte>();
            var data     = new byte[1];

            // read data one byte at a time to find end of line and leave any unhandled information in the buffer
            // to be processed by subsequent invocations
            do
            {
                var bytesRead = SocketAbstraction.Read(socket, data, 0, data.Length, readTimeout);
                if (bytesRead == 0)
                {
                    // the remote server shut down the socket
                    break;
                }

                var b = data[0];
                buffer.Add(b);

                if (b == Session.LineFeed && buffer.Count > 1 && buffer[buffer.Count - 2] == Session.CarriageReturn)
                {
                    // Return line without CRLF
                    return(encoding.GetString(buffer.ToArray(), 0, buffer.Count - 2));
                }
            }while (true);

            if (buffer.Count == 0)
            {
                return(null);
            }

            return(encoding.GetString(buffer.ToArray(), 0, buffer.Count));
        }
        public void ShouldReturnFalseWhenSocketIsNull()
        {
            const Socket socket = null;

            var actual = SocketAbstraction.CanWrite(socket);

            Assert.IsFalse(actual);
        }
Exemplo n.º 7
0
        /// <summary>
        /// Called when channel data is received.
        /// </summary>
        /// <param name="data">The data.</param>
        protected override void OnData(byte[] data)
        {
            base.OnData(data);

            var socket = _socket;

            if (socket != null && socket.Connected)
            {
                SocketAbstraction.Send(socket, data, 0, data.Length);
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Performs a blocking read on the socket until <paramref name="length"/> bytes are received.
        /// </summary>
        /// <param name="socket">The <see cref="Socket"/> to read from.</param>
        /// <param name="buffer">An array of type <see cref="byte"/> that is the storage location for the received data.</param>
        /// <param name="offset">The position in <paramref name="buffer"/> parameter to store the received data.</param>
        /// <param name="length">The number of bytes to read.</param>
        /// <param name="readTimeout">The maximum time to wait until <paramref name="length"/> bytes have been received.</param>
        /// <returns>
        /// The number of bytes read.
        /// </returns>
        /// <exception cref="SshConnectionException">The socket is closed.</exception>
        /// <exception cref="SshOperationTimeoutException">The read has timed-out.</exception>
        /// <exception cref="SocketException">The read failed.</exception>
        protected static int SocketRead(Socket socket, byte[] buffer, int offset, int length, TimeSpan readTimeout)
        {
            var bytesRead = SocketAbstraction.Read(socket, buffer, offset, length, readTimeout);

            if (bytesRead == 0)
            {
                throw new SshConnectionException("An established connection was aborted by the server.",
                                                 DisconnectReason.ConnectionLost);
            }
            return(bytesRead);
        }
        private static string GetSocks5Host(int addressType, Socket socket, TimeSpan timeout)
        {
            switch (addressType)
            {
            case 0x01:     // IPv4
            {
                var addressBuffer = new byte[4];
                if (SocketAbstraction.Read(socket, addressBuffer, 0, 4, timeout) == 0)
                {
                    // SOCKS client closed connection
                    return(null);
                }

                var ipv4 = new IPAddress(addressBuffer);
                return(ipv4.ToString());
            }

            case 0x03:     // Domain name
            {
                var length = SocketAbstraction.ReadByte(socket, timeout);
                if (length == -1)
                {
                    // SOCKS client closed connection
                    return(null);
                }
                var addressBuffer = new byte[length];
                if (SocketAbstraction.Read(socket, addressBuffer, 0, addressBuffer.Length, timeout) == 0)
                {
                    // SOCKS client closed connection
                    return(null);
                }

                var hostName = SshData.Ascii.GetString(addressBuffer, 0, addressBuffer.Length);
                return(hostName);
            }

            case 0x04:     // IPv6
            {
                var addressBuffer = new byte[16];
                if (SocketAbstraction.Read(socket, addressBuffer, 0, 16, timeout) == 0)
                {
                    // SOCKS client closed connection
                    return(null);
                }

                var ipv6 = new IPAddress(addressBuffer);
                return(ipv6.ToString());
            }

            default:
                throw new ProxyException(string.Format("SOCKS5: Address type '{0}' is not supported.", addressType));
            }
        }
Exemplo n.º 10
0
        /// <summary>
        /// Performs a blocking read on the socket until a line is read.
        /// </summary>
        /// <param name="socket">The <see cref="Socket"/> to read from.</param>
        /// <param name="timeout">A <see cref="TimeSpan"/> that represents the time to wait until a line is read.</param>
        /// <param name="buffer">A <see cref="List{Byte}"/> to which read bytes will be added.</param>
        /// <exception cref="SshOperationTimeoutException">The read has timed-out.</exception>
        /// <exception cref="SocketException">An error occurred when trying to access the socket.</exception>
        /// <returns>
        /// The line read from the socket, or <c>null</c> when the remote server has shutdown and all data has been received.
        /// </returns>
        private static string SocketReadLine(Socket socket, TimeSpan timeout, List <byte> buffer)
        {
            var data = new byte[1];

            var startPosition = buffer.Count;

            // Read data one byte at a time to find end of line and leave any unhandled information in the buffer
            // to be processed by subsequent invocations.
            while (true)
            {
                var bytesRead = SocketAbstraction.Read(socket, data, 0, data.Length, timeout);
                if (bytesRead == 0)
                {
                    // The remote server shut down the socket.
                    break;
                }

                var byteRead = data[0];
                buffer.Add(byteRead);

                // The null character MUST NOT be sent
                if (byteRead == Null)
                {
                    throw new SshConnectionException(string.Format(CultureInfo.InvariantCulture,
                                                                   "The server response contains a null character at position 0x{0:X8}:{1}{1}{2}{1}{1}" +
                                                                   "A server must not send a null character before the Protocol Version Exchange is complete.{1}{1}" +
                                                                   "More information is available here:{1}" +
                                                                   "https://tools.ietf.org/html/rfc4253#section-4.2",
                                                                   buffer.Count,
                                                                   Environment.NewLine,
                                                                   PacketDump.Create(buffer.ToArray(), 2)));
                }

                if (byteRead == Session.LineFeed)
                {
                    if (buffer.Count > startPosition + 1 && buffer[buffer.Count - 2] == Session.CarriageReturn)
                    {
                        // Return current line without CRLF
                        return(Encoding.UTF8.GetString(buffer.ToArray(), startPosition, buffer.Count - (startPosition + 2)));
                    }
                    else
                    {
                        // Even though RFC4253 clearly indicates that the identification string should be terminated
                        // by a CR LF we also support banners and identification strings that are terminated by a LF

                        // Return current line without LF
                        return(Encoding.UTF8.GetString(buffer.ToArray(), startPosition, buffer.Count - (startPosition + 1)));
                    }
                }
            }

            return(null);
        }
Exemplo n.º 11
0
        /// <summary>
        /// Called when channel data is received.
        /// </summary>
        /// <param name="data">The data.</param>
        protected override void OnData(byte[] data)
        {
            base.OnData(data);

            if (_socket != null)
            {
                lock (_socketLock)
                {
                    if (_socket.IsConnected())
                    {
                        SocketAbstraction.Send(_socket, data, 0, data.Length);
                    }
                }
            }
        }
Exemplo n.º 12
0
        private bool HandleSocks(IChannelDirectTcpip channel, Socket clientSocket, TimeSpan timeout)
        {
            // create eventhandler which is to be invoked to interrupt a blocking receive
            // when we're closing the forwarded port
            EventHandler closeClientSocket = (_, args) => CloseClientSocket(clientSocket);

            Closing += closeClientSocket;

            try
            {
                var version = SocketAbstraction.ReadByte(clientSocket, timeout);
                switch (version)
                {
                case -1:
                    // SOCKS client closed connection
                    return(false);

                case 4:
                    return(HandleSocks4(clientSocket, channel, timeout));

                case 5:
                    return(HandleSocks5(clientSocket, channel, timeout));

                default:
                    throw new NotSupportedException(string.Format("SOCKS version {0} is not supported.", version));
                }
            }
            catch (SocketException ex)
            {
                // ignore exception thrown by interrupting the blocking receive as part of closing
                // the forwarded port
                if (ex.SocketErrorCode != SocketError.Interrupted)
                {
                    RaiseExceptionEvent(ex);
                }
                return(false);
            }
            finally
            {
                // interrupt of blocking receive is now handled by channel (SOCKS4 and SOCKS5)
                // or no longer necessary
                Closing -= closeClientSocket;
            }
        }
Exemplo n.º 13
0
        private bool HandleSocks(IChannelDirectTcpip channel, Socket remoteSocket, TimeSpan timeout)
        {
            // create eventhandler which is to be invoked to interrupt a blocking receive
            // when we're closing the forwarded port
            EventHandler closeClientSocket = (_, args) => CloseSocket(remoteSocket);

            Closing += closeClientSocket;

            try
            {
#if DEBUG_GERT
                Console.WriteLine("ID: " + Thread.CurrentThread.ManagedThreadId + " | Before ReadByte for version | " + DateTime.Now.ToString("hh:mm:ss.fff"));
#endif // DEBUG_GERT

                var version = SocketAbstraction.ReadByte(remoteSocket, timeout);
                if (version == -1)
                {
                    return(false);
                }

#if DEBUG_GERT
                Console.WriteLine("ID: " + Thread.CurrentThread.ManagedThreadId + " | After ReadByte for version | " + DateTime.Now.ToString("hh:mm:ss.fff"));
#endif // DEBUG_GERT

                if (version == 4)
                {
                    return(HandleSocks4(remoteSocket, channel, timeout));
                }
                else if (version == 5)
                {
                    return(HandleSocks5(remoteSocket, channel, timeout));
                }
                else
                {
                    throw new NotSupportedException(string.Format("SOCKS version {0} is not supported.", version));
                }
            }
            finally
            {
                // interrupt of blocking receive is now handled by channel (SOCKS4 and SOCKS5)
                // or no longer necessary
                Closing -= closeClientSocket;
            }
        }
Exemplo n.º 14
0
        /// <summary>
        /// Binds channel to remote host.
        /// </summary>
        public void Bind()
        {
            //  Cannot bind if channel is not open
            if (!IsOpen)
            {
                return;
            }

            var buffer = new byte[RemotePacketSize];

            SocketAbstraction.ReadContinuous(_socket, buffer, 0, buffer.Length, SendData);

            // even though the client has disconnected, we still want to properly close the
            // channel
            //
            // we'll do this in in Close() - invoked through Dispose(bool) - that way we have
            // a single place from which we send an SSH_MSG_CHANNEL_EOF message and wait for
            // the SSH_MSG_CHANNEL_CLOSE message
        }
Exemplo n.º 15
0
        /// <summary>
        /// Performs the SSH protocol version exchange.
        /// </summary>
        /// <param name="clientVersion">The identification string of the SSH client.</param>
        /// <param name="socket">A <see cref="Socket"/> connected to the server.</param>
        /// <param name="timeout">The maximum time to wait for the server to respond.</param>
        /// <returns>
        /// The SSH identification of the server.
        /// </returns>
        public SshIdentification Start(string clientVersion, Socket socket, TimeSpan timeout)
        {
            // Immediately send the identification string since the spec states both sides MUST send an identification string
            // when the connection has been established
            SocketAbstraction.Send(socket, Encoding.UTF8.GetBytes(clientVersion + "\x0D\x0A"));

            var bytesReceived = new List <byte>();

            // Get server version from the server,
            // ignore text lines which are sent before if any
            while (true)
            {
                var line = SocketReadLine(socket, timeout, bytesReceived);
                if (line == null)
                {
                    if (bytesReceived.Count == 0)
                    {
                        throw new SshConnectionException(string.Format("The server response does not contain an SSH identification string.{0}" +
                                                                       "The connection to the remote server was closed before any data was received.{0}{0}" +
                                                                       "More information on the Protocol Version Exchange is available here:{0}" +
                                                                       "https://tools.ietf.org/html/rfc4253#section-4.2",
                                                                       Environment.NewLine),
                                                         DisconnectReason.ConnectionLost);
                    }

                    throw new SshConnectionException(string.Format("The server response does not contain an SSH identification string:{0}{0}{1}{0}{0}" +
                                                                   "More information on the Protocol Version Exchange is available here:{0}" +
                                                                   "https://tools.ietf.org/html/rfc4253#section-4.2",
                                                                   Environment.NewLine,
                                                                   PacketDump.Create(bytesReceived, 2)),
                                                     DisconnectReason.ProtocolError);
                }

                var identificationMatch = ServerVersionRe.Match(line);
                if (identificationMatch.Success)
                {
                    return(new SshIdentification(GetGroupValue(identificationMatch, "protoversion"),
                                                 GetGroupValue(identificationMatch, "softwareversion"),
                                                 GetGroupValue(identificationMatch, "comments")));
                }
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Binds channel to remote host.
        /// </summary>
        public void Bind()
        {
            //  Cannot bind if channel is not open
            if (!IsOpen)
            {
                return;
            }

            var buffer = new byte[RemotePacketSize];

            SocketAbstraction.ReadContinuous(_socket, buffer, 0, buffer.Length, SendData);

#if DEBUG_GERT
            Console.WriteLine("ID: " + Thread.CurrentThread.ManagedThreadId + " | ChannelDirectTcpip.Bind (after) '" + LocalChannelNumber + "' | " + DateTime.Now.ToString("hh:mm:ss.fff"));
#endif // DEBUG_GERT

            // even though the client has disconnected, we still want to properly close the
            // channel
            //
            // we'll do this in in Close(bool) that way we have a single place from which we
            // send an SSH_MSG_CHANNEL_EOF message and wait for the SSH_MSG_CHANNEL_CLOSE
            // message
        }
Exemplo n.º 17
0
        /// <summary>
        /// Establishes a connection to the server via a SOCKS5 proxy.
        /// </summary>
        /// <param name="connectionInfo">The connection information.</param>
        /// <param name="socket">The <see cref="Socket"/>.</param>
        private void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket)
        {
            var connectionRequest = CreateSocks4ConnectionRequest(connectionInfo.Host, (ushort)connectionInfo.Port, connectionInfo.ProxyUsername);

            SocketAbstraction.Send(socket, connectionRequest);

            //  Read reply version
            if (SocketReadByte(socket, connectionInfo.Timeout) != 0x00)
            {
                throw new ProxyException("SOCKS4: Null is expected.");
            }

            //  Read response code
            var code = SocketReadByte(socket, connectionInfo.Timeout);

            switch (code)
            {
            case 0x5a:
                break;

            case 0x5b:
                throw new ProxyException("SOCKS4: Connection rejected.");

            case 0x5c:
                throw new ProxyException("SOCKS4: Client is not running identd or not reachable from the server.");

            case 0x5d:
                throw new ProxyException("SOCKS4: Client's identd could not confirm the user ID string in the request.");

            default:
                throw new ProxyException("SOCKS4: Not valid response.");
            }

            var destBuffer = new byte[6]; // destination port and IP address should be ignored

            SocketRead(socket, destBuffer, 0, destBuffer.Length, connectionInfo.Timeout);
        }
Exemplo n.º 18
0
        /// <summary>
        /// Establishes a socket connection to the specified host and port.
        /// </summary>
        /// <param name="host">The host name of the server to connect to.</param>
        /// <param name="port">The port to connect to.</param>
        /// <param name="timeout">The maximum time to wait for the connection to be established.</param>
        /// <exception cref="SshOperationTimeoutException">The connection failed to establish within the configured <see cref="ConnectionInfo.Timeout"/>.</exception>
        /// <exception cref="SocketException">An error occurred trying to establish the connection.</exception>
        protected Socket SocketConnect(string host, int port, TimeSpan timeout)
        {
            var ipAddress = DnsAbstraction.GetHostAddresses(host)[0];
            var ep        = new IPEndPoint(ipAddress, port);

            DiagnosticAbstraction.Log(string.Format("Initiating connection to '{0}:{1}'.", host, port));

            var socket = SocketFactory.Create(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            try
            {
                SocketAbstraction.Connect(socket, ep, timeout);

                const int socketBufferSize = 2 * Session.MaximumSshPacketSize;
                socket.SendBufferSize    = socketBufferSize;
                socket.ReceiveBufferSize = socketBufferSize;
                return(socket);
            }
            catch (Exception)
            {
                socket.Dispose();
                throw;
            }
        }
Exemplo n.º 19
0
        private bool HandleSocks5(Socket socket, IChannelDirectTcpip channel, TimeSpan timeout)
        {
#if DEBUG_GERT
            Console.WriteLine("ID: " + Thread.CurrentThread.ManagedThreadId + " |  Handling Socks5: " + socket.LocalEndPoint + " | " + socket.RemoteEndPoint + " | " + DateTime.Now.ToString("hh:mm:ss.fff"));
#endif // DEBUG_GERT

            var authenticationMethodsCount = SocketAbstraction.ReadByte(socket, timeout);
            if (authenticationMethodsCount == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

#if DEBUG_GERT
            Console.WriteLine("ID: " + Thread.CurrentThread.ManagedThreadId + " |  After ReadByte for authenticationMethodsCount | " + DateTime.Now.ToString("hh:mm:ss.fff"));
#endif // DEBUG_GERT

            var authenticationMethods = new byte[authenticationMethodsCount];
            if (SocketAbstraction.Read(socket, authenticationMethods, 0, authenticationMethods.Length, timeout) == 0)
            {
                // SOCKS client closed connection
                return(false);
            }

#if DEBUG_GERT
            Console.WriteLine("ID: " + Thread.CurrentThread.ManagedThreadId + " |  After Read for authenticationMethods | " + DateTime.Now.ToString("hh:mm:ss.fff"));
#endif // DEBUG_GERT

            if (authenticationMethods.Min() == 0)
            {
                // no user authentication is one of the authentication methods supported
                // by the SOCKS client
                SocketAbstraction.Send(socket, new byte[] { 0x05, 0x00 }, 0, 2);

#if DEBUG_GERT
                Console.WriteLine("ID: " + Thread.CurrentThread.ManagedThreadId + " |  After Send for authenticationMethods 0 | " + DateTime.Now.ToString("hh:mm:ss.fff"));
#endif // DEBUG_GERT
            }
            else
            {
                // the SOCKS client requires authentication, which we currently do not support
                SocketAbstraction.Send(socket, new byte[] { 0x05, 0xFF }, 0, 2);

                // we continue business as usual but expect the client to close the connection
                // so one of the subsequent reads should return -1 signaling that the client
                // has effectively closed the connection
#if DEBUG_GERT
                Console.WriteLine("ID: " + Thread.CurrentThread.ManagedThreadId + " |  After Send for authenticationMethods 2 | " + DateTime.Now.ToString("hh:mm:ss.fff"));
#endif // DEBUG_GERT
            }

            var version = SocketAbstraction.ReadByte(socket, timeout);
            if (version == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            if (version != 5)
            {
                throw new ProxyException("SOCKS5: Version 5 is expected.");
            }

            var commandCode = SocketAbstraction.ReadByte(socket, timeout);
            if (commandCode == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            var reserved = SocketAbstraction.ReadByte(socket, timeout);
            if (reserved == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            if (reserved != 0)
            {
                throw new ProxyException("SOCKS5: 0 is expected for reserved byte.");
            }

            var addressType = SocketAbstraction.ReadByte(socket, timeout);
            if (addressType == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            IPAddress ipAddress;
            byte[]    addressBuffer;
            switch (addressType)
            {
            case 0x01:
            {
                addressBuffer = new byte[4];
                if (SocketAbstraction.Read(socket, addressBuffer, 0, 4, timeout) == 0)
                {
                    // SOCKS client closed connection
                    return(false);
                }

                ipAddress = new IPAddress(addressBuffer);
            }
            break;

            case 0x03:
            {
                var length = SocketAbstraction.ReadByte(socket, timeout);
                addressBuffer = new byte[length];
                if (SocketAbstraction.Read(socket, addressBuffer, 0, addressBuffer.Length, timeout) == 0)
                {
                    // SOCKS client closed connection
                    return(false);
                }

                ipAddress = IPAddress.Parse(SshData.Ascii.GetString(addressBuffer));

                //var hostName = new Common.ASCIIEncoding().GetString(addressBuffer);

                //ipAddress = Dns.GetHostEntry(hostName).AddressList[0];
            }
            break;

            case 0x04:
            {
                addressBuffer = new byte[16];
                if (SocketAbstraction.Read(socket, addressBuffer, 0, 16, timeout) == 0)
                {
                    // SOCKS client closed connection
                    return(false);
                }

                ipAddress = new IPAddress(addressBuffer);
            }
            break;

            default:
                throw new ProxyException(string.Format("SOCKS5: Address type '{0}' is not supported.", addressType));
            }

            var portBuffer = new byte[2];
            if (SocketAbstraction.Read(socket, portBuffer, 0, portBuffer.Length, timeout) == 0)
            {
                // SOCKS client closed connection
                return(false);
            }

            var port = (uint)(portBuffer[0] * 256 + portBuffer[1]);
            var host = ipAddress.ToString();

            RaiseRequestReceived(host, port);

#if DEBUG_GERT
            Console.WriteLine("ID: " + Thread.CurrentThread.ManagedThreadId + " |  Before channel open | " + DateTime.Now.ToString("hh:mm:ss.fff"));

            var stopWatch = new Stopwatch();
            stopWatch.Start();
#endif // DEBUG_GERT

            channel.Open(host, port, this, socket);

#if DEBUG_GERT
            stopWatch.Stop();

            Console.WriteLine("ID: " + Thread.CurrentThread.ManagedThreadId + " |  After channel open | " + DateTime.Now.ToString("hh:mm:ss.fff") + " => " + stopWatch.ElapsedMilliseconds);
#endif // DEBUG_GERT

            SocketAbstraction.SendByte(socket, 0x05);


            if (channel.IsOpen)
            {
                SocketAbstraction.SendByte(socket, 0x00);
            }
            else
            {
                SocketAbstraction.SendByte(socket, 0x01);
            }

            // reserved
            SocketAbstraction.SendByte(socket, 0x00);

            if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
            {
                SocketAbstraction.SendByte(socket, 0x01);
            }
            else if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
            {
                SocketAbstraction.SendByte(socket, 0x04);
            }
            else
            {
                throw new NotSupportedException("Not supported address family.");
            }

            var addressBytes = ipAddress.GetAddressBytes();
            SocketAbstraction.Send(socket, addressBytes, 0, addressBytes.Length);
            SocketAbstraction.Send(socket, portBuffer, 0, portBuffer.Length);

            return(true);
        }
Exemplo n.º 20
0
        /// <summary>
        /// Establishes a connection to the server via a SOCKS5 proxy.
        /// </summary>
        /// <param name="connectionInfo">The connection information.</param>
        /// <param name="socket">The <see cref="Socket"/>.</param>
        private void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket)
        {
            var greeting = new byte[]
            {
                // SOCKS version number
                0x05,
                // Number of supported authentication methods
                0x02,
                // No authentication
                0x00,
                // Username/Password authentication
                0x02
            };

            SocketAbstraction.Send(socket, greeting);

            var socksVersion = SocketReadByte(socket);

            if (socksVersion != 0x05)
            {
                throw new ProxyException(string.Format("SOCKS Version '{0}' is not supported.", socksVersion));
            }

            var authenticationMethod = SocketReadByte(socket);

            switch (authenticationMethod)
            {
            case 0x00:
                break;

            case 0x02:
                // Create username/password authentication request
                var authenticationRequest = CreateSocks5UserNameAndPasswordAuthenticationRequest(connectionInfo.ProxyUsername, connectionInfo.ProxyPassword);
                // Send authentication request
                SocketAbstraction.Send(socket, authenticationRequest);
                // Read authentication result
                var authenticationResult = SocketAbstraction.Read(socket, 2, connectionInfo.Timeout);

                if (authenticationResult[0] != 0x01)
                {
                    throw new ProxyException("SOCKS5: Server authentication version is not valid.");
                }
                if (authenticationResult[1] != 0x00)
                {
                    throw new ProxyException("SOCKS5: Username/Password authentication failed.");
                }
                break;

            case 0xFF:
                throw new ProxyException("SOCKS5: No acceptable authentication methods were offered.");
            }

            var connectionRequest = CreateSocks5ConnectionRequest(connectionInfo.Host, (ushort)connectionInfo.Port);

            SocketAbstraction.Send(socket, connectionRequest);

            //  Read Server SOCKS5 version
            if (SocketReadByte(socket) != 5)
            {
                throw new ProxyException("SOCKS5: Version 5 is expected.");
            }

            //  Read response code
            var status = SocketReadByte(socket);

            switch (status)
            {
            case 0x00:
                break;

            case 0x01:
                throw new ProxyException("SOCKS5: General failure.");

            case 0x02:
                throw new ProxyException("SOCKS5: Connection not allowed by ruleset.");

            case 0x03:
                throw new ProxyException("SOCKS5: Network unreachable.");

            case 0x04:
                throw new ProxyException("SOCKS5: Host unreachable.");

            case 0x05:
                throw new ProxyException("SOCKS5: Connection refused by destination host.");

            case 0x06:
                throw new ProxyException("SOCKS5: TTL expired.");

            case 0x07:
                throw new ProxyException("SOCKS5: Command not supported or protocol error.");

            case 0x08:
                throw new ProxyException("SOCKS5: Address type not supported.");

            default:
                throw new ProxyException("SOCKS5: Not valid response.");
            }

            //  Read reserved byte
            if (SocketReadByte(socket) != 0)
            {
                throw new ProxyException("SOCKS5: 0 byte is expected.");
            }

            var addressType = SocketReadByte(socket);

            switch (addressType)
            {
            case 0x01:
                var ipv4 = new byte[4];
                SocketRead(socket, ipv4, 0, 4);
                break;

            case 0x04:
                var ipv6 = new byte[16];
                SocketRead(socket, ipv6, 0, 16);
                break;

            default:
                throw new ProxyException(string.Format("Address type '{0}' is not supported.", addressType));
            }

            var port = new byte[2];

            //  Read 2 bytes to be ignored
            SocketRead(socket, port, 0, 2);
        }
Exemplo n.º 21
0
 internal static bool CanWrite(this Socket socket)
 {
     return(SocketAbstraction.CanWrite(socket));
 }
        private bool HandleSocks5(Socket socket, IChannelDirectTcpip channel, TimeSpan timeout)
        {
            var authenticationMethodsCount = SocketAbstraction.ReadByte(socket, timeout);

            if (authenticationMethodsCount == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            var authenticationMethods = new byte[authenticationMethodsCount];

            if (SocketAbstraction.Read(socket, authenticationMethods, 0, authenticationMethods.Length, timeout) == 0)
            {
                // SOCKS client closed connection
                return(false);
            }

            if (authenticationMethods.Min() == 0)
            {
                // no user authentication is one of the authentication methods supported
                // by the SOCKS client
                SocketAbstraction.Send(socket, new byte[] { 0x05, 0x00 }, 0, 2);
            }
            else
            {
                // the SOCKS client requires authentication, which we currently do not support
                SocketAbstraction.Send(socket, new byte[] { 0x05, 0xFF }, 0, 2);

                // we continue business as usual but expect the client to close the connection
                // so one of the subsequent reads should return -1 signaling that the client
                // has effectively closed the connection
            }

            var version = SocketAbstraction.ReadByte(socket, timeout);

            if (version == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            if (version != 5)
            {
                throw new ProxyException("SOCKS5: Version 5 is expected.");
            }

            var commandCode = SocketAbstraction.ReadByte(socket, timeout);

            if (commandCode == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            var reserved = SocketAbstraction.ReadByte(socket, timeout);

            if (reserved == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            if (reserved != 0)
            {
                throw new ProxyException("SOCKS5: 0 is expected for reserved byte.");
            }

            var addressType = SocketAbstraction.ReadByte(socket, timeout);

            if (addressType == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            var host = GetSocks5Host(addressType, socket, timeout);

            if (host == null)
            {
                // SOCKS client closed connection
                return(false);
            }

            var portBuffer = new byte[2];

            if (SocketAbstraction.Read(socket, portBuffer, 0, portBuffer.Length, timeout) == 0)
            {
                // SOCKS client closed connection
                return(false);
            }

            var port = Pack.BigEndianToUInt16(portBuffer);

            RaiseRequestReceived(host, port);

            channel.Open(host, port, this, socket);

            var socksReply = CreateSocks5Reply(channel.IsOpen);

            SocketAbstraction.Send(socket, socksReply, 0, socksReply.Length);

            return(true);
        }
Exemplo n.º 23
0
        private bool HandleSocks5(Socket socket, IChannelDirectTcpip channel, TimeSpan timeout)
        {
            var authenticationMethodsCount = SocketAbstraction.ReadByte(socket, timeout);

            if (authenticationMethodsCount == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            var authenticationMethods = new byte[authenticationMethodsCount];

            if (SocketAbstraction.Read(socket, authenticationMethods, 0, authenticationMethods.Length, timeout) == 0)
            {
                // SOCKS client closed connection
                return(false);
            }

            if (authenticationMethods.Min() == 0)
            {
                // no user authentication is one of the authentication methods supported
                // by the SOCKS client
                SocketAbstraction.Send(socket, new byte[] { 0x05, 0x00 }, 0, 2);
            }
            else
            {
                // the SOCKS client requires authentication, which we currently do not support
                SocketAbstraction.Send(socket, new byte[] { 0x05, 0xFF }, 0, 2);

                // we continue business as usual but expect the client to close the connection
                // so one of the subsequent reads should return -1 signaling that the client
                // has effectively closed the connection
            }

            var version = SocketAbstraction.ReadByte(socket, timeout);

            if (version == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            if (version != 5)
            {
                throw new ProxyException("SOCKS5: Version 5 is expected.");
            }

            var commandCode = SocketAbstraction.ReadByte(socket, timeout);

            if (commandCode == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            var reserved = SocketAbstraction.ReadByte(socket, timeout);

            if (reserved == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            if (reserved != 0)
            {
                throw new ProxyException("SOCKS5: 0 is expected for reserved byte.");
            }

            var addressType = SocketAbstraction.ReadByte(socket, timeout);

            if (addressType == -1)
            {
                // SOCKS client closed connection
                return(false);
            }

            IPAddress ipAddress;

            byte[] addressBuffer;
            switch (addressType)
            {
            case 0x01:
            {
                addressBuffer = new byte[4];
                if (SocketAbstraction.Read(socket, addressBuffer, 0, 4, timeout) == 0)
                {
                    // SOCKS client closed connection
                    return(false);
                }

                ipAddress = new IPAddress(addressBuffer);
            }
            break;

            case 0x03:
            {
                var length = SocketAbstraction.ReadByte(socket, timeout);
                if (length == -1)
                {
                    // SOCKS client closed connection
                    return(false);
                }
                addressBuffer = new byte[length];
                if (SocketAbstraction.Read(socket, addressBuffer, 0, addressBuffer.Length, timeout) == 0)
                {
                    // SOCKS client closed connection
                    return(false);
                }

                ipAddress = IPAddress.Parse(SshData.Ascii.GetString(addressBuffer, 0, addressBuffer.Length));

                //var hostName = new Common.ASCIIEncoding().GetString(addressBuffer);

                //ipAddress = Dns.GetHostEntry(hostName).AddressList[0];
            }
            break;

            case 0x04:
            {
                addressBuffer = new byte[16];
                if (SocketAbstraction.Read(socket, addressBuffer, 0, 16, timeout) == 0)
                {
                    // SOCKS client closed connection
                    return(false);
                }

                ipAddress = new IPAddress(addressBuffer);
            }
            break;

            default:
                throw new ProxyException(string.Format("SOCKS5: Address type '{0}' is not supported.", addressType));
            }

            var portBuffer = new byte[2];

            if (SocketAbstraction.Read(socket, portBuffer, 0, portBuffer.Length, timeout) == 0)
            {
                // SOCKS client closed connection
                return(false);
            }

            var port = (uint)(portBuffer[0] * 256 + portBuffer[1]);
            var host = ipAddress.ToString();

            RaiseRequestReceived(host, port);

            channel.Open(host, port, this, socket);

            SocketAbstraction.SendByte(socket, 0x05);

            if (channel.IsOpen)
            {
                SocketAbstraction.SendByte(socket, 0x00);
            }
            else
            {
                SocketAbstraction.SendByte(socket, 0x01);
            }

            // reserved
            SocketAbstraction.SendByte(socket, 0x00);

            if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
            {
                SocketAbstraction.SendByte(socket, 0x01);
            }
            else if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
            {
                SocketAbstraction.SendByte(socket, 0x04);
            }
            else
            {
                throw new NotSupportedException("Not supported address family.");
            }

            var addressBytes = ipAddress.GetAddressBytes();

            SocketAbstraction.Send(socket, addressBytes, 0, addressBytes.Length);
            SocketAbstraction.Send(socket, portBuffer, 0, portBuffer.Length);

            return(true);
        }
Exemplo n.º 24
0
        private void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket)
        {
            var httpResponseRe = new Regex(@"HTTP/(?<version>\d[.]\d) (?<statusCode>\d{3}) (?<reasonPhrase>.+)$");
            var httpHeaderRe   = new Regex(@"(?<fieldName>[^\[\]()<>@,;:\""/?={} \t]+):(?<fieldValue>.+)?");

            SocketAbstraction.Send(socket, SshData.Ascii.GetBytes(string.Format("CONNECT {0}:{1} HTTP/1.0\r\n", connectionInfo.Host, connectionInfo.Port)));

            //  Sent proxy authorization if specified
            if (!string.IsNullOrEmpty(connectionInfo.ProxyUsername))
            {
                var authorization = string.Format("Proxy-Authorization: Basic {0}\r\n",
                                                  Convert.ToBase64String(SshData.Ascii.GetBytes(string.Format("{0}:{1}", connectionInfo.ProxyUsername, connectionInfo.ProxyPassword))));
                SocketAbstraction.Send(socket, SshData.Ascii.GetBytes(authorization));
            }

            SocketAbstraction.Send(socket, SshData.Ascii.GetBytes("\r\n"));

            HttpStatusCode?statusCode    = null;
            var            contentLength = 0;

            while (true)
            {
                var response = SocketReadLine(socket, connectionInfo.Timeout);
                if (response == null)
                {
                    // server shut down socket
                    break;
                }

                if (statusCode == null)
                {
                    var statusMatch = httpResponseRe.Match(response);
                    if (statusMatch.Success)
                    {
                        var httpStatusCode = statusMatch.Result("${statusCode}");
                        statusCode = (HttpStatusCode)int.Parse(httpStatusCode);
                        if (statusCode != HttpStatusCode.OK)
                        {
                            throw new ProxyException(string.Format("HTTP: Status code {0}, \"{1}\"",
                                                                   httpStatusCode,
                                                                   statusMatch.Result("${reasonPhrase}")));
                        }
                    }

                    continue;
                }

                // continue on parsing message headers coming from the server
                var headerMatch = httpHeaderRe.Match(response);
                if (headerMatch.Success)
                {
                    var fieldName = headerMatch.Result("${fieldName}");
                    if (fieldName.Equals("Content-Length", StringComparison.OrdinalIgnoreCase))
                    {
                        contentLength = int.Parse(headerMatch.Result("${fieldValue}"));
                    }
                    continue;
                }

                // check if we've reached the CRLF which separates request line and headers from the message body
                if (response.Length == 0)
                {
                    //  read response body if specified
                    if (contentLength > 0)
                    {
                        var contentBody = new byte[contentLength];
                        SocketRead(socket, contentBody, 0, contentLength, connectionInfo.Timeout);
                    }
                    break;
                }
            }

            if (statusCode == null)
            {
                throw new ProxyException("HTTP response does not contain status line.");
            }
        }