// Decompiled with JetBrains decompiler
// Type: Starksoft.Net.Proxy.HttpProxyClient
// 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.Sockets;
using System.Text;
using System.Threading;

namespace Starksoft.Net.Proxy
{
  public class HttpProxyClient : IProxyClient
  {
    private const int HTTP_PROXY_DEFAULT_PORT = 8080;
    private const string HTTP_PROXY_CONNECT_CMD = "CONNECT {0}:{1} HTTP/1.0\r\nHOST {0}:{1}\r\n\r\n";
    private const int WAIT_FOR_DATA_INTERVAL = 50;
    private const int WAIT_FOR_DATA_TIMEOUT = 15000;
    private const string PROXY_NAME = "HTTP";
    private string _proxyHost;
    private int _proxyPort;
    private HttpProxyClient.HttpResponseCodes _respCode;
    private string _respText;
    private TcpClient _tcpClient;
    private BackgroundWorker _asyncWorker;
    private Exception _asyncException;
    private bool _asyncCancelled;

    public HttpProxyClient()
    {
    }

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

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

    public HttpProxyClient(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 string ProxyName => "HTTP";

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

    public TcpClient CreateConnection(string destinationHost, int destinationPort)
    {
      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.SendConnectionCommand(destinationHost, destinationPort);
        return this._tcpClient;
      }
      catch (SocketException 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)
        }), (Exception) ex);
      }
    }

    private void SendConnectionCommand(string host, int port)
    {
      NetworkStream stream = this._tcpClient.GetStream();
      byte[] bytes = Encoding.ASCII.GetBytes(string.Format((IFormatProvider) CultureInfo.InvariantCulture, "CONNECT {0}:{1} HTTP/1.0\r\nHOST {0}:{1}\r\n\r\n", new object[2]
      {
        (object) host,
        (object) port.ToString((IFormatProvider) CultureInfo.InvariantCulture)
      }));
      stream.Write(bytes, 0, bytes.Length);
      this.WaitForData(stream);
      byte[] numArray = new byte[this._tcpClient.ReceiveBufferSize];
      StringBuilder stringBuilder = new StringBuilder();
      long num = 0;
      do
      {
        int count = stream.Read(numArray, 0, this._tcpClient.ReceiveBufferSize);
        num += (long) count;
        stringBuilder.Append(Encoding.UTF8.GetString(numArray, 0, count));
      }
      while (stream.DataAvailable);
      this.ParseResponse(stringBuilder.ToString());
      if (this._respCode == HttpProxyClient.HttpResponseCodes.OK)
        return;
      this.HandleProxyCommandError(host, port);
    }

    private void HandleProxyCommandError(string host, int port)
    {
      string message;
      switch (this._respCode)
      {
        case HttpProxyClient.HttpResponseCodes.None:
          message = string.Format((IFormatProvider) CultureInfo.InvariantCulture, "Proxy destination {0} on port {1} failed to return a recognized HTTP response code.  Server response: {2}", new object[3]
          {
            (object) Utils.GetHost(this._tcpClient),
            (object) Utils.GetPort(this._tcpClient),
            (object) this._respText
          });
          break;
        case HttpProxyClient.HttpResponseCodes.BadGateway:
          message = string.Format((IFormatProvider) CultureInfo.InvariantCulture, "Proxy destination {0} on port {1} responded with a 502 code - Bad Gateway.  If you are connecting to a Microsoft ISA destination please refer to knowledge based article Q283284 for more information.  Server response: {2}", new object[3]
          {
            (object) Utils.GetHost(this._tcpClient),
            (object) Utils.GetPort(this._tcpClient),
            (object) this._respText
          });
          break;
        default:
          message = string.Format((IFormatProvider) CultureInfo.InvariantCulture, "Proxy destination {0} on port {1} responded with a {2} code - {3}", (object) Utils.GetHost(this._tcpClient), (object) Utils.GetPort(this._tcpClient), (object) ((int) this._respCode).ToString((IFormatProvider) CultureInfo.InvariantCulture), (object) this._respText);
          break;
      }
      throw new ProxyException(message);
    }

    private void WaitForData(NetworkStream stream)
    {
      int num = 0;
      while (!stream.DataAvailable)
      {
        Thread.Sleep(50);
        num += 50;
        if (num > 15000)
          throw new ProxyException(string.Format("A timeout while waiting for the proxy server at {0} on port {1} to respond.", (object) Utils.GetHost(this._tcpClient), (object) Utils.GetPort(this._tcpClient)));
      }
    }

    private void ParseResponse(string response) => this.ParseCodeAndText(response.Replace('\n', ' ').Split('\r')[0]);

    private void ParseCodeAndText(string line)
    {
      if (line.IndexOf("HTTP") == -1)
        throw new ProxyException(string.Format("No HTTP response received from proxy destination.  Server response: {0}.", (object) line));
      int startIndex = line.IndexOf(" ") + 1;
      int num = line.IndexOf(" ", startIndex);
      string s = line.Substring(startIndex, num - startIndex);
      int result = 0;
      if (!int.TryParse(s, out result))
        throw new ProxyException(string.Format("An invalid response code was received from proxy destination.  Server response: {0}.", (object) line));
      this._respCode = (HttpProxyClient.HttpResponseCodes) result;
      this._respText = line.Substring(num + 1).Trim();
    }

    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 HttpProxy 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));
    }

    private enum HttpResponseCodes
    {
      None = 0,
      Continue = 100, // 0x00000064
      SwitchingProtocols = 101, // 0x00000065
      OK = 200, // 0x000000C8
      Created = 201, // 0x000000C9
      Accepted = 202, // 0x000000CA
      NonAuthoritiveInformation = 203, // 0x000000CB
      NoContent = 204, // 0x000000CC
      ResetContent = 205, // 0x000000CD
      PartialContent = 206, // 0x000000CE
      MultipleChoices = 300, // 0x0000012C
      MovedPermanetly = 301, // 0x0000012D
      Found = 302, // 0x0000012E
      SeeOther = 303, // 0x0000012F
      NotModified = 304, // 0x00000130
      UserProxy = 305, // 0x00000131
      TemporaryRedirect = 307, // 0x00000133
      BadRequest = 400, // 0x00000190
      Unauthorized = 401, // 0x00000191
      PaymentRequired = 402, // 0x00000192
      Forbidden = 403, // 0x00000193
      NotFound = 404, // 0x00000194
      MethodNotAllowed = 405, // 0x00000195
      NotAcceptable = 406, // 0x00000196
      ProxyAuthenticantionRequired = 407, // 0x00000197
      RequestTimeout = 408, // 0x00000198
      Conflict = 409, // 0x00000199
      Gone = 410, // 0x0000019A
      PreconditionFailed = 411, // 0x0000019B
      RequestEntityTooLarge = 413, // 0x0000019D
      RequestURITooLong = 414, // 0x0000019E
      UnsupportedMediaType = 415, // 0x0000019F
      RequestedRangeNotSatisfied = 416, // 0x000001A0
      ExpectationFailed = 417, // 0x000001A1
      InternalServerError = 500, // 0x000001F4
      NotImplemented = 501, // 0x000001F5
      BadGateway = 502, // 0x000001F6
      ServiceUnavailable = 503, // 0x000001F7
      GatewayTimeout = 504, // 0x000001F8
      HTTPVersionNotSupported = 505, // 0x000001F9
    }
  }
}
