3

HttpWebRequestは SOCKS プロキシをサポートしていないため、長い調査の結果、WebRequest( SocksHttpWebRequestWebClientのように車輪を再発明することなく) SOCKS サポートを追加する最良の方法は、着信要求をに転送する一時的な HTTP プロキシを作成することであると判断しました。 SOCKS プロキシ。

HTTP リクエストの転送は簡単で、魅力的に機能します。

HTTPS リクエストの転送も、理論的には簡単です。

  1. HttpWebRequestHTTP プロキシに接続し、以下を送信します。

    CONNECT google.com:443 HTTP/1.0
    Host: google.com
    
  2. SOCKS プロキシ経由で接続しgoogle.com:443、クライアントに以下を送り返します。

    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