3

HttpWebRequest不支持 SOCKS 代理,所以经过长时间的研究,我已经确定,添加 SOCKS 支持的最佳方法WebRequestWebClient(而不像SocksHttpWebRequest那样重新发明轮子)是创建一个临时 HTTP 代理,它将任何传入请求转发到SOCKS 代理。

转发一个 HTTP 请求很简单,而且很有效。

转发 HTTPS 请求在理论上也应该很容易:

  1. 连接到我们的HttpWebRequestHTTP 代理,并发送以下内容:

    CONNECT google.com:443 HTTP/1.0
    Host: google.com
    
  2. 我们google.com:443通过 SOCKS 代理连接,然后将以下内容发送回客户端:

    HTTP/1.0 200 Tunnel established
    
  3. 根据这个文档,此时,我们复制流之间的所有字节,当一个连接关闭时,我们也关闭另一个。

但是,从一个复制NetworkStream到另一个似乎并不像我预期的那样工作。在某一时刻,Read()似乎没有明显的原因挂起。如果我设置超时,无论有多大,我都会收到证书错误。

我现在使用的代码的精简版本:

/// <summary>
/// In theory, forwards any incoming bytes from one stream to another.
/// </summary>
/// <param name="httpProxyStream">The HTTP proxy, which we opened for <code>HttpWebRequest</code>.</param>
/// <param name="socksProxyStream">The SOCKS proxy, which we connect to and forward the traffic from the HTTP proxy.</param>
private void TunnelRequest(NetworkStream httpProxyStream, NetworkStream socksProxyStream)
{
    while (true)
    {
        try
        {
            if (httpProxyStream.DataAvailable)
            {
                CopyStreamToStream(httpProxyStream, socksProxyStream);
            }

            if (socksProxyStream.DataAvailable)
            {
                CopyStreamToStream(socksProxyStream, httpProxyStream);
            }
        }
        catch
        {
            break;
        }
    }
}

/// <summary>
/// Copies the first stream's content from the current position to the second stream.
/// </summary>
/// <param name="source">The source stream.</param>
/// <param name="destionation">The destionation stream.</param>
/// <param name="flush">if set to <c>true</c>, <c>Flush()</c> will be called on the destination stream after finish.</param>
/// <param name="bufferLength">Length of the buffer.</param>
public static void CopyStreamToStream(Stream source, Stream destionation, bool flush = true, int bufferLength = 4096)
{
    var buffer = new byte[bufferLength];

    while (true)
    {
        int i;

        try
        {
            i = source.Read(buffer, 0, bufferLength);
        }
        catch
        {
            break;
        }

        if (i == 0)
        {
            break;
        }

        destionation.Write(buffer, 0, i);
    }

    if (flush)
    {
        destionation.Flush();
    }
}

完整课程可在此处获得:HttpToSocks.cs

我被困在这段代码上好几天了。任务如此简单,但它根本行不通……请帮助我恢复理智。

编辑:我知道这while(true)不是我最棒的线路,但经过大量变化后,它保留在代码中以确保它不会过早退出,这就是我收到证书错误的原因。

编辑2:问题已解决。如果有人感兴趣,可以在git 存储库中找到完整的课程。

4

0 回答 0