|  | @@ -1301,7 +1301,7 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |              _sshMessageFactory.DisableNonKeyExchangeMessages();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              _keyExchange = _serviceFactory.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms,
 | 
	
		
			
				|  |  | -                message.KeyExchangeAlgorithms);
 | 
	
		
			
				|  |  | +                                                             message.KeyExchangeAlgorithms);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              ConnectionInfo.CurrentKeyExchangeAlgorithm = _keyExchange.Name;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1726,7 +1726,7 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |                  // SshConnectionException will interrupt the message listener loop (if not already interrupted)
 | 
	
		
			
				|  |  |                  // and the exception itself will be ignored (in RaiseError)
 | 
	
		
			
				|  |  |                  throw new SshConnectionException("An established connection was aborted by the server.",
 | 
	
		
			
				|  |  | -                    DisconnectReason.ConnectionLost);
 | 
	
		
			
				|  |  | +                                                 DisconnectReason.ConnectionLost);
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              return bytesRead;
 | 
	
		
			
				|  |  |          }
 | 
	
	
		
			
				|  | @@ -1772,16 +1772,16 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |          /// </para>
 | 
	
		
			
				|  |  |          /// </remarks>
 | 
	
		
			
				|  |  |  #else
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        /// Gets a value indicating whether the socket is connected.
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <returns>
 | 
	
		
			
				|  |  | -        /// <c>true</c> if the socket is connected; otherwise, <c>false</c>.
 | 
	
		
			
				|  |  | -        /// </returns>
 | 
	
		
			
				|  |  | -        /// <remarks>
 | 
	
		
			
				|  |  | -        /// We verify whether <see cref="Socket.Connected"/> is <c>true</c>. However, this only returns the state
 | 
	
		
			
				|  |  | -        /// of the socket as of the last I/O operation.
 | 
	
		
			
				|  |  | -        /// </remarks>
 | 
	
		
			
				|  |  | +/// <summary>
 | 
	
		
			
				|  |  | +/// Gets a value indicating whether the socket is connected.
 | 
	
		
			
				|  |  | +/// </summary>
 | 
	
		
			
				|  |  | +/// <returns>
 | 
	
		
			
				|  |  | +/// <c>true</c> if the socket is connected; otherwise, <c>false</c>.
 | 
	
		
			
				|  |  | +/// </returns>
 | 
	
		
			
				|  |  | +/// <remarks>
 | 
	
		
			
				|  |  | +/// We verify whether <see cref="Socket.Connected"/> is <c>true</c>. However, this only returns the state
 | 
	
		
			
				|  |  | +/// of the socket as of the last I/O operation.
 | 
	
		
			
				|  |  | +/// </remarks>
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |          private bool IsSocketConnected()
 | 
	
		
			
				|  |  |          {
 | 
	
	
		
			
				|  | @@ -1952,9 +1952,9 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |                          break;
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |  #elif FEATURE_SOCKET_POLL
 | 
	
		
			
				|  |  | -                    // when Socket.Select(IList, IList, IList, Int32) is not available or is buggy, we use
 | 
	
		
			
				|  |  | -                    // Socket.Poll(Int, SelectMode) to block until either data is available or the socket
 | 
	
		
			
				|  |  | -                    // is closed
 | 
	
		
			
				|  |  | +// when Socket.Select(IList, IList, IList, Int32) is not available or is buggy, we use
 | 
	
		
			
				|  |  | +// Socket.Poll(Int, SelectMode) to block until either data is available or the socket
 | 
	
		
			
				|  |  | +// is closed
 | 
	
		
			
				|  |  |                      _socket.Poll(-1, SelectMode.SelectRead);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                      if (!_socket.IsConnected())
 | 
	
	
		
			
				|  | @@ -2002,33 +2002,12 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |              return buffer[0];
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private void SocketWriteByte(byte data)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            SocketAbstraction.Send(_socket, new[] {data});
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          private void ConnectSocks4()
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            //  Send socks version number
 | 
	
		
			
				|  |  | -            SocketWriteByte(0x04);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //  Send command code
 | 
	
		
			
				|  |  | -            SocketWriteByte(0x01);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //  Send port
 | 
	
		
			
				|  |  | -            SocketWriteByte((byte)(ConnectionInfo.Port / 0xFF));
 | 
	
		
			
				|  |  | -            SocketWriteByte((byte)(ConnectionInfo.Port % 0xFF));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //  Send IP
 | 
	
		
			
				|  |  | -            var ipAddress = DnsAbstraction.GetHostAddresses(ConnectionInfo.Host)[0];
 | 
	
		
			
				|  |  | -            SocketAbstraction.Send(_socket, ipAddress.GetAddressBytes());
 | 
	
		
			
				|  |  | +            var connectionRequest = CreateSocks4ConnectionRequest(ConnectionInfo.Host, (ushort) ConnectionInfo.Port, ConnectionInfo.ProxyUsername);
 | 
	
		
			
				|  |  | +            SocketAbstraction.Send(_socket, connectionRequest);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            //  Send username
 | 
	
		
			
				|  |  | -            var username = SshData.Ascii.GetBytes(ConnectionInfo.ProxyUsername);
 | 
	
		
			
				|  |  | -            SocketAbstraction.Send(_socket, username);
 | 
	
		
			
				|  |  | -            SocketWriteByte(0x00);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //  Read 0
 | 
	
		
			
				|  |  | +            //  Read null byte
 | 
	
		
			
				|  |  |              if (SocketReadByte() != 0)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  throw new ProxyException("SOCKS4: Null is expected.");
 | 
	
	
		
			
				|  | @@ -2057,15 +2036,18 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private void ConnectSocks5()
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            //  Send socks version number
 | 
	
		
			
				|  |  | -            SocketWriteByte(0x05);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //  Send number of supported authentication methods
 | 
	
		
			
				|  |  | -            SocketWriteByte(0x02);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //  Send supported authentication methods
 | 
	
		
			
				|  |  | -            SocketWriteByte(0x00); //  No authentication
 | 
	
		
			
				|  |  | -            SocketWriteByte(0x02); //  Username/Password
 | 
	
		
			
				|  |  | +            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();
 | 
	
		
			
				|  |  |              if (socksVersion != 0x05)
 | 
	
	
		
			
				|  | @@ -2077,78 +2059,24 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |                  case 0x00:
 | 
	
		
			
				|  |  |                      break;
 | 
	
		
			
				|  |  |                  case 0x02:
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    //  Send version
 | 
	
		
			
				|  |  | -                    SocketWriteByte(0x01);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    var username = SshData.Ascii.GetBytes(ConnectionInfo.ProxyUsername);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    if (username.Length > byte.MaxValue)
 | 
	
		
			
				|  |  | -                        throw new ProxyException("Proxy username is too long.");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    //  Send username length
 | 
	
		
			
				|  |  | -                    SocketWriteByte((byte)username.Length);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    //  Send username
 | 
	
		
			
				|  |  | -                    SocketAbstraction.Send(_socket, username);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    var password = SshData.Ascii.GetBytes(ConnectionInfo.ProxyPassword);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    if (password.Length > byte.MaxValue)
 | 
	
		
			
				|  |  | -                        throw new ProxyException("Proxy password is too long.");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    //  Send username length
 | 
	
		
			
				|  |  | -                    SocketWriteByte((byte)password.Length);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    //  Send username
 | 
	
		
			
				|  |  | -                    SocketAbstraction.Send(_socket, password);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    var serverVersion = SocketReadByte();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    if (serverVersion != 1)
 | 
	
		
			
				|  |  | +                    // 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.");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    var statusCode = SocketReadByte();
 | 
	
		
			
				|  |  | -                    if (statusCode != 0)
 | 
	
		
			
				|  |  | +                    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.");
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            //  Send socks version number
 | 
	
		
			
				|  |  | -            SocketWriteByte(0x05);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //  Send command code
 | 
	
		
			
				|  |  | -            SocketWriteByte(0x01); //  establish a TCP/IP stream connection
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //  Send reserved, must be 0x00
 | 
	
		
			
				|  |  | -            SocketWriteByte(0x00);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            var ip = DnsAbstraction.GetHostAddresses(ConnectionInfo.Host)[0];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //  Send address type and address
 | 
	
		
			
				|  |  | -            if (ip.AddressFamily == AddressFamily.InterNetwork)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                SocketWriteByte(0x01);
 | 
	
		
			
				|  |  | -                var address = ip.GetAddressBytes();
 | 
	
		
			
				|  |  | -                SocketAbstraction.Send(_socket, address);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            else if (ip.AddressFamily == AddressFamily.InterNetworkV6)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                SocketWriteByte(0x04);
 | 
	
		
			
				|  |  | -                var address = ip.GetAddressBytes();
 | 
	
		
			
				|  |  | -                SocketAbstraction.Send(_socket, address);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            else
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                throw new ProxyException(string.Format("SOCKS5: IP address '{0}' is not supported.", ip));
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            //  Send port
 | 
	
		
			
				|  |  | -            SocketWriteByte((byte)(ConnectionInfo.Port / 0xFF));
 | 
	
		
			
				|  |  | -            SocketWriteByte((byte)(ConnectionInfo.Port % 0xFF));
 | 
	
		
			
				|  |  | +            var connectionRequest = CreateSocks5ConnectionRequest(ConnectionInfo.Host, (ushort) ConnectionInfo.Port);
 | 
	
		
			
				|  |  | +            SocketAbstraction.Send(_socket, connectionRequest);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              //  Read Server SOCKS5 version
 | 
	
		
			
				|  |  |              if (SocketReadByte() != 5)
 | 
	
	
		
			
				|  | @@ -2183,22 +2111,22 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |                      throw new ProxyException("SOCKS5: Not valid response.");
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            //  Read 0
 | 
	
		
			
				|  |  | +            //  Read reserved byte
 | 
	
		
			
				|  |  |              if (SocketReadByte() != 0)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  throw new ProxyException("SOCKS5: 0 byte is expected.");
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var addressType = SocketReadByte();
 | 
	
		
			
				|  |  | -            var responseIp = new byte[16];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |              switch (addressType)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  case 0x01:
 | 
	
		
			
				|  |  | -                    SocketRead(responseIp, 0, 4);
 | 
	
		
			
				|  |  | +                    var ipv4 = new byte[4];
 | 
	
		
			
				|  |  | +                    SocketRead(ipv4, 0, 4);
 | 
	
		
			
				|  |  |                      break;
 | 
	
		
			
				|  |  |                  case 0x04:
 | 
	
		
			
				|  |  | -                    SocketRead(responseIp, 0, 16);
 | 
	
		
			
				|  |  | +                    var ipv6 = new byte[16];
 | 
	
		
			
				|  |  | +                    SocketRead(ipv6, 0, 16);
 | 
	
		
			
				|  |  |                      break;
 | 
	
		
			
				|  |  |                  default:
 | 
	
		
			
				|  |  |                      throw new ProxyException(string.Format("Address type '{0}' is not supported.", addressType));
 | 
	
	
		
			
				|  | @@ -2210,6 +2138,173 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |              SocketRead(port, 0, 2);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        /// <summary>
 | 
	
		
			
				|  |  | +        /// https://tools.ietf.org/html/rfc1929
 | 
	
		
			
				|  |  | +        /// </summary>
 | 
	
		
			
				|  |  | +        private static byte[] CreateSocks5UserNameAndPasswordAuthenticationRequest(string username, string password)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if (username.Length > byte.MaxValue)
 | 
	
		
			
				|  |  | +                throw new ProxyException("Proxy username is too long.");
 | 
	
		
			
				|  |  | +            if (password.Length > byte.MaxValue)
 | 
	
		
			
				|  |  | +                throw new ProxyException("Proxy password is too long.");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var authenticationRequest = new byte
 | 
	
		
			
				|  |  | +                [
 | 
	
		
			
				|  |  | +                    // Version of the negotiation
 | 
	
		
			
				|  |  | +                    1 +
 | 
	
		
			
				|  |  | +                    // Length of the username
 | 
	
		
			
				|  |  | +                    1 +
 | 
	
		
			
				|  |  | +                    // Username
 | 
	
		
			
				|  |  | +                    username.Length +
 | 
	
		
			
				|  |  | +                    // Length of the password
 | 
	
		
			
				|  |  | +                    1 +
 | 
	
		
			
				|  |  | +                    // Password
 | 
	
		
			
				|  |  | +                    password.Length
 | 
	
		
			
				|  |  | +                ];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var index = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Version of the negiotiation
 | 
	
		
			
				|  |  | +            authenticationRequest[index++] = 0x01;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Length of the username
 | 
	
		
			
				|  |  | +            authenticationRequest[index++] = (byte) username.Length;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Username
 | 
	
		
			
				|  |  | +            SshData.Ascii.GetBytes(username, 0, username.Length, authenticationRequest, index);
 | 
	
		
			
				|  |  | +            index += username.Length;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Length of the password
 | 
	
		
			
				|  |  | +            authenticationRequest[index++] = (byte) password.Length;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Password
 | 
	
		
			
				|  |  | +            SshData.Ascii.GetBytes(password, 0, password.Length, authenticationRequest, index);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return authenticationRequest;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private static byte[] CreateSocks4ConnectionRequest(string hostname, ushort port, string username)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var addressBytes = GetSocks4DestinationAddress(hostname);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var connectionRequest = new byte
 | 
	
		
			
				|  |  | +                [
 | 
	
		
			
				|  |  | +                    // SOCKS version number
 | 
	
		
			
				|  |  | +                    1 +
 | 
	
		
			
				|  |  | +                    // Command code
 | 
	
		
			
				|  |  | +                    1 +
 | 
	
		
			
				|  |  | +                    // Port number
 | 
	
		
			
				|  |  | +                    2 +
 | 
	
		
			
				|  |  | +                    // IP address
 | 
	
		
			
				|  |  | +                    addressBytes.Length +
 | 
	
		
			
				|  |  | +                    // Username
 | 
	
		
			
				|  |  | +                    username.Length +
 | 
	
		
			
				|  |  | +                    // Null terminator
 | 
	
		
			
				|  |  | +                    1
 | 
	
		
			
				|  |  | +                ];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var index = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // SOCKS version number
 | 
	
		
			
				|  |  | +            connectionRequest[index++] = 0x04;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Command code
 | 
	
		
			
				|  |  | +            connectionRequest[index++] = 0x01; // establish a TCP/IP stream connection
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Port number
 | 
	
		
			
				|  |  | +            Pack.UInt16ToBigEndian(port, connectionRequest, index);
 | 
	
		
			
				|  |  | +            index += 2;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Address
 | 
	
		
			
				|  |  | +            Buffer.BlockCopy(addressBytes, 0, connectionRequest, index, addressBytes.Length);
 | 
	
		
			
				|  |  | +            index += addressBytes.Length;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            connectionRequest[index] = 0x00;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return connectionRequest;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private static byte[] CreateSocks5ConnectionRequest(string hostname, ushort port)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            byte addressType;
 | 
	
		
			
				|  |  | +            var addressBytes = GetSocks5DestinationAddress(hostname, out addressType);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var connectionRequest = new byte
 | 
	
		
			
				|  |  | +                [
 | 
	
		
			
				|  |  | +                    // SOCKS version number
 | 
	
		
			
				|  |  | +                    1 +
 | 
	
		
			
				|  |  | +                    // Command code
 | 
	
		
			
				|  |  | +                    1 +
 | 
	
		
			
				|  |  | +                    // Reserved
 | 
	
		
			
				|  |  | +                    1 +
 | 
	
		
			
				|  |  | +                    // Address type
 | 
	
		
			
				|  |  | +                    1 +
 | 
	
		
			
				|  |  | +                    // Address
 | 
	
		
			
				|  |  | +                    addressBytes.Length +
 | 
	
		
			
				|  |  | +                    // Port number
 | 
	
		
			
				|  |  | +                    2
 | 
	
		
			
				|  |  | +                ];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var index = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // SOCKS version number
 | 
	
		
			
				|  |  | +            connectionRequest[index++] = 0x05;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Command code
 | 
	
		
			
				|  |  | +            connectionRequest[index++] = 0x01; // establish a TCP/IP stream connection
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Reserved
 | 
	
		
			
				|  |  | +            connectionRequest[index++] = 0x00;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Address type
 | 
	
		
			
				|  |  | +            connectionRequest[index++] = addressType;
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            // Address
 | 
	
		
			
				|  |  | +            Buffer.BlockCopy(addressBytes, 0, connectionRequest, index, addressBytes.Length);
 | 
	
		
			
				|  |  | +            index += addressBytes.Length;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Port number
 | 
	
		
			
				|  |  | +            Pack.UInt16ToBigEndian(port, connectionRequest, index);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return connectionRequest;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private static byte[] GetSocks4DestinationAddress(string hostname)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var ip = DnsAbstraction.GetHostAddresses(hostname)[0];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (ip.AddressFamily != AddressFamily.InterNetwork)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                throw new ProxyException("SOCKS4 only supports IPv4.");
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return ip.GetAddressBytes();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private static byte[] GetSocks5DestinationAddress(string hostname, out byte addressType)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var ip = DnsAbstraction.GetHostAddresses(hostname)[0];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            byte[] address;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (ip.AddressFamily == AddressFamily.InterNetwork)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                addressType = 0x01; // IPv4
 | 
	
		
			
				|  |  | +                address = ip.GetAddressBytes();
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else if (ip.AddressFamily == AddressFamily.InterNetworkV6)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                addressType = 0x04; // IPv6
 | 
	
		
			
				|  |  | +                address = ip.GetAddressBytes();
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            else
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                throw new ProxyException(string.Format("SOCKS5: IP address '{0}' is not supported.", ip));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return address;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          private void ConnectHttp()
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              var httpResponseRe = new Regex(@"HTTP/(?<version>\d[.]\d) (?<statusCode>\d{3}) (?<reasonPhrase>.+)$");
 |