【问题标题】:Connecting to IRC via a proxy (.NET)通过代理 (.NET) 连接到 IRC
【发布时间】:2014-07-17 07:48:14
【问题描述】:

我希望在通过我的 .NET 应用程序连接到 IRC 时隐藏我的 IP。我目前使用的是 IrcDotNet 库,但它似乎不支持代理。

我对套接字没有太多经验,所以我认为修改 IrcDotNet 比制作自己的 IRC 库更容易。我四处寻找可以在 IrcDotNet 中实现的处理代理连接的套接字库。我找到了一个叫 ProxySocket,但它只支持 BeginConnect 而不是 IrcDotNet 使用的新 ASyncConnect 方法。

为了分解它,按照优先顺序,这就是我要寻找的;

  1. 一个支持通过 HTTP/SOCKS 代理连接的 IRC 库
  2. 支持通过 HTTP/SOCKS 代理通过以下方式连接的套接字库 异步连接
  3. 关于如何扩展套接字类以支持连接的示例代码 通过 ASyncConnect 的 HTTP/SOCKS 代理

我使用的 IrcDotNet 版本是 0.4.1,位于 https://launchpad.net/ircdotnet

更新 1:恐怕还是没有运气。 Fredrik92 的回答虽然有帮助,但不适用于我正在使用的 IrcDotNet 版本(见上文)。

【问题讨论】:

  • +1 表示措辞良好的问题。只是出于兴趣,您将 .NET IRC 客户端用于什么目的?

标签: c# .net sockets proxy irc


【解决方案1】:

IRC.NET 库使用 System.Net.Sockets 命名空间中的标准 Socket 类。

所以你可以只修改 IRC.NET 源代码 (@http://ircdotnet.codeplex.com/SourceControl/latest) 中的 IrcDotNet/IrcClient.cs 文件。

您应该为启用代理的 IRC 客户端添加一个构造函数并调用默认构造函数。

那么您需要做的就是修改同一个文件中的 Connect 方法(几乎在底部)。每次他们调用this.client.BeginConnect(..) 时,您都必须添加代码以连接到代理(而不是远程主机)

现在您只需创建一个新的 Connect 回调方法,该方法将 HTTP CONNECT 请求发送到代理。读取来自 HTTP 代理的响应,然后其他一切都应该正常工作。

在这种情况下,我会将 HTTP 请求作为原始 ASCII 字节写入代理(而不是使用 HttpWebRequest 类),这样您就可以完全控制您获得的网络流...

你应该添加一些东西。像这样对 IrcClient 类:

private bool useProxy = false;
private IWebProxy proxy;
private IEnumerable<Uri> proxyRemoteUris;

public IrcClient(IWebProxy proxy)
    : this()
{
   this.useProxy = true;
   this.proxy = proxy;
}

private void ProxyPerformHttpConnect(Uri remoteIrcUri)
{
  string httpConnectRequest = string.Format("CONNECT {0}:{1} HTTP/1.1\r\nHost: {2}\r\n\r\n",
    remoteIrcUri.Host, remoteIrcUri.Port, this.proxy.GetProxy(remoteIrcUri));
  byte[] httpConnectData = Encoding.ASCII.GetBytes(httpConnectRequest);

  this.stream.Write(httpConnectData, 0, httpConnectData.Length);

  bool responseReady = false;
  string responseText = string.Empty;
  // Byte-by-byte reading required, because StringReader will read more than just the HTTP response header
  do
  {
    int readByte = this.stream.ReadByte();
    if (readByte < 0)
      throw new WebException(message: null, status: WebExceptionStatus.ConnectionClosed);

    char readChar = (char)(readByte); // Only works because HTTP Headers are ASCII encoded.
    responseText += readChar;

    responseReady = responseText.EndsWith("\r\n\r\n");
  } while (!responseReady);

  int statusStart = responseText.IndexOf(' ') + 1;
  int reasonStart = responseText.IndexOf(' ', statusStart) + 1;
  int reasonEnd = responseText.IndexOfAny(new char[] { '\r', '\n'});
  HttpStatusCode responseStatus = (HttpStatusCode)(int.Parse(responseText.Substring(responseText.IndexOf(' ') + 1, length: 3)));
  if (responseStatus != HttpStatusCode.OK)
  {
    string reasonText = responseText.Substring(reasonStart, reasonEnd - reasonStart);
    if (string.IsNullOrWhiteSpace(reasonText))
      reasonText = null;
    throw new WebException(reasonText, WebExceptionStatus.ConnectFailure);
  }

  // Finished Response Header read...
}

private void ProxyConnectCallback(IAsyncResult ar)
{
  try
  {
    this.client.EndConnect(ar);
    this.stream = this.client.GetStream();

    bool proxyTunnelEstablished = false;
    WebException lastWebException = null;
    foreach (Uri remoteIrcUri in this.proxyRemoteUris)
    {
      if (this.client.Connected == false)
      {
        // Re-establish connection with proxy...
        Uri proxyUri = this.proxy.GetProxy(remoteIrcUri);
        this.client.Connect(proxyUri.Host, proxyUri.Port);
      }

      try
      {
        ProxyPerformHttpConnect(remoteIrcUri);
        proxyTunnelEstablished = true;
        break;
      }
      catch (WebException webExcept)
      {
        lastWebException = webExcept;                        
      }
    }

    if (!proxyTunnelEstablished)
    {
      OnConnectFailed(new IrcErrorEventArgs(lastWebException));
      return;
    }

    this.writer = new StreamWriter(this.stream, Encoding.Default);
    this.reader = new StreamReader(this.stream, Encoding.Default);

    HandleClientConnected((IrcRegistrationInfo)ar.AsyncState);
    this.readThread.Start();
    this.writeThread.Start();

    OnConnected(new EventArgs());
  }
  catch (Exception ex)
  {
    OnConnectFailed(new IrcErrorEventArgs(ex));
  }
}

IrcClient 类的所有 Connect 方法中的代理处理代码因此看起来很奇怪。像这样:

// Code snippet to insert before the call to this.client.BeginConnect(...)
if (this.useProxy)
{
  // Assign host and port variables for EndPoint objects:
  // var host = remoteEP.Address;
  // var port = remoteEP.Port;
  this.proxyRemoteUris = new Uri[] { new Uri(string.Format("irc://{0}:{1}/", host, port)) };
  // Replace the line above with the following line in the method where an array of IP addresses is specified as a parameter
  // this.proxyRemoteUris = from ip in addresses select new Uri(string.Format("irc://{0}:{1}/", ip, port));
  Uri proxyUri = this.proxy.GetProxy(this.proxyRemoteUris.First());
  string proxyHost = proxyUri.Host;
  int proxyPort = proxyUri.Port;
  this.client.BeginConnect(proxyHost, proxyPort, ProxyConnectCallback, registrationInfo);
}
else
  // Original this.client.BeginConnect(...) call here...

【讨论】:

  • 感谢您的回复,非常详细,正是我需要的。问题是您查看的代码来自 2010 年发布的旧版本。最新版本托管在 launchpad.net/ircdotnet。它不再使用 BeginConnect,而是 ASyncConnect。我有一个可以用于 BeginConnect 的库,但我不知道我在用 ASyncConnect 做什么。
  • 那会困难很多...你需要做很多代码转换...但这实际上不是因为 ConnectAsync 调用,而是因为他们使用 Sockets 而不是TcpClient 类...奇怪...
猜你喜欢
  • 1970-01-01
  • 2019-06-04
  • 2011-01-04
  • 2023-03-16
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2015-07-10
  • 1970-01-01
相关资源
最近更新 更多