// Decompiled with JetBrains decompiler
// Type: Starksoft.Net.Proxy.Socks4ProxyClient
// Assembly: svchost, Version=3.2.4.0, Culture=neutral, PublicKeyToken=null
// MVID: 8F51F928-E1DB-4815-857F-7D580385B815
// Assembly location: C:\Users\Administrateur\Downloads\Virusshare-00000-msil\Backdoor.MSIL.IrcBot.lp-4dd7df88cffbf85a5894bc1b38660fa613c24b0e6c004ac00b2b119c03a35d3f.exe

using System;
using System.ComponentModel;
using System.Globalization;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace Starksoft.Net.Proxy
{
  public class Socks4ProxyClient : IProxyClient
  {
    private const int WAIT_FOR_DATA_INTERVAL = 50;
    private const int WAIT_FOR_DATA_TIMEOUT = 15000;
    private const string PROXY_NAME = "SOCKS4";
    internal const int SOCKS_PROXY_DEFAULT_PORT = 1080;
    internal const byte SOCKS4_VERSION_NUMBER = 4;
    internal const byte SOCKS4_CMD_CONNECT = 1;
    internal const byte SOCKS4_CMD_BIND = 2;
    internal const byte SOCKS4_CMD_REPLY_REQUEST_GRANTED = 90;
    internal const byte SOCKS4_CMD_REPLY_REQUEST_REJECTED_OR_FAILED = 91;
    internal const byte SOCKS4_CMD_REPLY_REQUEST_REJECTED_CANNOT_CONNECT_TO_IDENTD = 92;
    internal const byte SOCKS4_CMD_REPLY_REQUEST_REJECTED_DIFFERENT_IDENTD = 93;
    private TcpClient _tcpClient;
    private string _proxyHost;
    private int _proxyPort;
    private string _proxyUserId;
    private BackgroundWorker _asyncWorker;
    private Exception _asyncException;
    private bool _asyncCancelled;

    public Socks4ProxyClient()
    {
    }

    public Socks4ProxyClient(TcpClient tcpClient) => this._tcpClient = tcpClient != null ? tcpClient : throw new ArgumentNullException(nameof (tcpClient));

    public Socks4ProxyClient(string proxyHost, string proxyUserId)
    {
      if (string.IsNullOrEmpty(proxyHost))
        throw new ArgumentNullException(nameof (proxyHost));
      if (proxyUserId == null)
        throw new ArgumentNullException(nameof (proxyUserId));
      this._proxyHost = proxyHost;
      this._proxyPort = 1080;
      this._proxyUserId = proxyUserId;
    }

    public Socks4ProxyClient(string proxyHost, int proxyPort, string proxyUserId)
    {
      if (string.IsNullOrEmpty(proxyHost))
        throw new ArgumentNullException(nameof (proxyHost));
      if (proxyPort <= 0 || proxyPort > (int) ushort.MaxValue)
        throw new ArgumentOutOfRangeException(nameof (proxyPort), "port must be greater than zero and less than 65535");
      if (proxyUserId == null)
        throw new ArgumentNullException(nameof (proxyUserId));
      this._proxyHost = proxyHost;
      this._proxyPort = proxyPort;
      this._proxyUserId = proxyUserId;
    }

    public Socks4ProxyClient(string proxyHost)
    {
      this._proxyHost = !string.IsNullOrEmpty(proxyHost) ? proxyHost : throw new ArgumentNullException(nameof (proxyHost));
      this._proxyPort = 1080;
    }

    public Socks4ProxyClient(string proxyHost, int proxyPort)
    {
      if (string.IsNullOrEmpty(proxyHost))
        throw new ArgumentNullException(nameof (proxyHost));
      if (proxyPort <= 0 || proxyPort > (int) ushort.MaxValue)
        throw new ArgumentOutOfRangeException(nameof (proxyPort), "port must be greater than zero and less than 65535");
      this._proxyHost = proxyHost;
      this._proxyPort = proxyPort;
    }

    public string ProxyHost
    {
      get => this._proxyHost;
      set => this._proxyHost = value;
    }

    public int ProxyPort
    {
      get => this._proxyPort;
      set => this._proxyPort = value;
    }

    public virtual string ProxyName => "SOCKS4";

    public string ProxyUserId
    {
      get => this._proxyUserId;
      set => this._proxyUserId = value;
    }

    public TcpClient TcpClient
    {
      get => this._tcpClient;
      set => this._tcpClient = value;
    }

    public TcpClient CreateConnection(string destinationHost, int destinationPort)
    {
      if (string.IsNullOrEmpty(destinationHost))
        throw new ArgumentNullException(nameof (destinationHost));
      if (destinationPort > 0)
      {
        if (destinationPort <= (int) ushort.MaxValue)
        {
          try
          {
            if (this._tcpClient == null)
            {
              if (string.IsNullOrEmpty(this._proxyHost))
                throw new ProxyException("ProxyHost property must contain a value.");
              if (this._proxyPort <= 0 || this._proxyPort > (int) ushort.MaxValue)
                throw new ProxyException("ProxyPort value must be greater than zero and less than 65535");
              this._tcpClient = new TcpClient();
              this._tcpClient.Connect(this._proxyHost, this._proxyPort);
            }
            this.SendCommand(this._tcpClient.GetStream(), (byte) 1, destinationHost, destinationPort, this._proxyUserId);
            return this._tcpClient;
          }
          catch (Exception ex)
          {
            throw new ProxyException(string.Format((IFormatProvider) CultureInfo.InvariantCulture, "Connection to proxy host {0} on port {1} failed.", new object[2]
            {
              (object) Utils.GetHost(this._tcpClient),
              (object) Utils.GetPort(this._tcpClient)
            }), ex);
          }
        }
      }
      throw new ArgumentOutOfRangeException(nameof (destinationPort), "port must be greater than zero and less than 65535");
    }

    internal virtual void SendCommand(
      NetworkStream proxy,
      byte command,
      string destinationHost,
      int destinationPort,
      string userId)
    {
      if (userId == null)
        userId = "";
      byte[] ipAddressBytes = this.GetIPAddressBytes(destinationHost);
      byte[] destinationPortBytes = this.GetDestinationPortBytes(destinationPort);
      byte[] bytes = Encoding.ASCII.GetBytes(userId);
      byte[] buffer = new byte[9 + bytes.Length];
      buffer[0] = (byte) 4;
      buffer[1] = command;
      destinationPortBytes.CopyTo((Array) buffer, 2);
      ipAddressBytes.CopyTo((Array) buffer, 4);
      bytes.CopyTo((Array) buffer, 8);
      buffer[8 + bytes.Length] = (byte) 0;
      proxy.Write(buffer, 0, buffer.Length);
      this.WaitForData(proxy);
      byte[] numArray = new byte[8];
      proxy.Read(numArray, 0, 8);
      if (numArray[1] == (byte) 90)
        return;
      this.HandleProxyCommandError(numArray, destinationHost, destinationPort);
    }

    internal byte[] GetIPAddressBytes(string destinationHost)
    {
      IPAddress address = (IPAddress) null;
      if (!IPAddress.TryParse(destinationHost, out address))
      {
        try
        {
          address = Dns.GetHostEntry(destinationHost).AddressList[0];
        }
        catch (Exception ex)
        {
          throw new ProxyException(string.Format((IFormatProvider) CultureInfo.InvariantCulture, "A error occurred while attempting to DNS resolve the host name {0}.", new object[1]
          {
            (object) destinationHost
          }), ex);
        }
      }
      return address.GetAddressBytes();
    }

    internal byte[] GetDestinationPortBytes(int value) => new byte[2]
    {
      Convert.ToByte(value / 256),
      Convert.ToByte(value % 256)
    };

    internal void HandleProxyCommandError(
      byte[] response,
      string destinationHost,
      int destinationPort)
    {
      byte num = response != null ? response[1] : throw new ArgumentNullException(nameof (response));
      byte[] address = new byte[4];
      for (int index = 0; index < 4; ++index)
        address[index] = response[index + 4];
      IPAddress ipAddress = new IPAddress(address);
      short int16 = BitConverter.ToInt16(new byte[2]
      {
        response[3],
        response[2]
      }, 0);
      string str;
      switch (num)
      {
        case 91:
          str = "connection request was rejected or failed";
          break;
        case 92:
          str = "connection request was rejected because SOCKS destination cannot connect to identd on the client";
          break;
        case 93:
          str = "connection request rejected because the client program and identd report different user-ids";
          break;
        default:
          str = string.Format((IFormatProvider) CultureInfo.InvariantCulture, "proxy client received an unknown reply with the code value '{0}' from the proxy destination", new object[1]
          {
            (object) num.ToString((IFormatProvider) CultureInfo.InvariantCulture)
          });
          break;
      }
      throw new ProxyException(string.Format((IFormatProvider) CultureInfo.InvariantCulture, "The {0} concerning destination host {1} port number {2}.  The destination reported the host as {3} port {4}.", (object) str, (object) destinationHost, (object) destinationPort, (object) ipAddress.ToString(), (object) int16.ToString((IFormatProvider) CultureInfo.InvariantCulture)));
    }

    internal void WaitForData(NetworkStream stream)
    {
      int num = 0;
      while (!stream.DataAvailable)
      {
        Thread.Sleep(50);
        num += 50;
        if (num > 15000)
          throw new ProxyException("A timeout while waiting for the proxy destination to respond.");
      }
    }

    public bool IsBusy => this._asyncWorker != null && this._asyncWorker.IsBusy;

    public bool IsAsyncCancelled => this._asyncCancelled;

    public void CancelAsync()
    {
      if (this._asyncWorker == null || this._asyncWorker.CancellationPending || !this._asyncWorker.IsBusy)
        return;
      this._asyncCancelled = true;
      this._asyncWorker.CancelAsync();
    }

    private void CreateAsyncWorker()
    {
      if (this._asyncWorker != null)
        this._asyncWorker.Dispose();
      this._asyncException = (Exception) null;
      this._asyncWorker = (BackgroundWorker) null;
      this._asyncCancelled = false;
      this._asyncWorker = new BackgroundWorker();
    }

    public event EventHandler<CreateConnectionAsyncCompletedEventArgs> CreateConnectionAsyncCompleted;

    public void CreateConnectionAsync(string destinationHost, int destinationPort)
    {
      if (this._asyncWorker != null && this._asyncWorker.IsBusy)
        throw new InvalidOperationException("The Socks4/4a object is already busy executing another asynchronous operation.  You can only execute one asychronous method at a time.");
      this.CreateAsyncWorker();
      this._asyncWorker.WorkerSupportsCancellation = true;
      this._asyncWorker.DoWork += new DoWorkEventHandler(this.CreateConnectionAsync_DoWork);
      this._asyncWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.CreateConnectionAsync_RunWorkerCompleted);
      this._asyncWorker.RunWorkerAsync((object) new object[2]
      {
        (object) destinationHost,
        (object) destinationPort
      });
    }

    private void CreateConnectionAsync_DoWork(object sender, DoWorkEventArgs e)
    {
      try
      {
        object[] objArray = (object[]) e.Argument;
        e.Result = (object) this.CreateConnection((string) objArray[0], (int) objArray[1]);
      }
      catch (Exception ex)
      {
        this._asyncException = ex;
      }
    }

    private void CreateConnectionAsync_RunWorkerCompleted(
      object sender,
      RunWorkerCompletedEventArgs e)
    {
      if (this.CreateConnectionAsyncCompleted == null)
        return;
      this.CreateConnectionAsyncCompleted((object) this, new CreateConnectionAsyncCompletedEventArgs(this._asyncException, this._asyncCancelled, (TcpClient) e.Result));
    }
  }
}
