C# 如何在两个网络流之间正确地隧道SSL连接?

C# 如何在两个网络流之间正确地隧道SSL连接?,c#,ssl,tcp,httpwebrequest,socks,C#,Ssl,Tcp,Httpwebrequest,Socks,HttpWebRequest不支持SOCKS代理,因此经过长期研究,我确定为WebRequest和WebClient添加SOCKS支持的最佳方法是创建一个临时HTTP代理,将任何传入的请求转发给SOCKS代理 转发HTTP请求很容易,而且工作起来很有魅力 转发HTTPS请求在理论上也应该很容易: HttpWebRequest连接到我们的HTTP代理,并发送以下内容: CONNECT google.com:443 HTTP/1.0 Host: google.com 我们通过SOCKS代理连接到

HttpWebRequest
不支持SOCKS代理,因此经过长期研究,我确定为
WebRequest
WebClient
添加SOCKS支持的最佳方法是创建一个临时HTTP代理,将任何传入的请求转发给SOCKS代理

转发HTTP请求很容易,而且工作起来很有魅力

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

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

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

    HTTP/1.0 200 Tunnel established
    
  • 根据,在这一点上,我们复制流之间的所有字节,当一个关闭连接时,我们也关闭另一个

  • 然而,从一个
    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();
        }
    }
    
    完整课程可在以下位置获得:

    我被这段代码困了好几天了。这项任务很简单,但就是不起作用。。。请帮我恢复理智

    EDIT:我知道
    while(true)
    不是我最擅长的一行,但是经过很多变化后,它保留在代码中,以确保它不会过早退出,这就是为什么我会出现证书错误


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

    你说的“它不工作”是什么意思?能否创建system.net跟踪日志()?它应该向您显示网络层数据包交换,您可以使用它来调试您的问题。谢谢,我已经修复了它!通过查看生成的日志,我看到WebClient在启动SSL会话时试图打开多个到代理的连接,但是HttpToSocks被设计为只接受一个连接。