如何在两个NetworkStream之间正确隧道连接SSL?

时间:2011-08-09 19:28:53

标签: c# ssl tcp httpwebrequest socks

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

转发HTTP请求很简单,就像魅力一样。

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

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

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

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

  4. 然而,从一个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 repository中找到完整的课程。

0 个答案:

没有答案