2

C# を使用して HTTPS プロキシを実装しようとしています。プロキシは、HTTP ではなく、HTTPS のみをサポートする必要があります。私の知る限り、HTTPListener は適切な選択ではありません。プロキシが通常提供しない HTTPS をサポートするには SSL 証明書が必要だからです。

TcpListener と TcpClients を使用しています。これまでに得たコードは次のとおりです。

   protected void HandleTCPRequest(object clientObject)
    {
        TcpClient inClient = clientObject as TcpClient;
        TcpClient outClient = null;

        try
        {
            NetworkStream clientStream = inClient.GetStream();
            StreamReader clientReader = new StreamReader(clientStream);
            StreamWriter clientWriter = new StreamWriter(clientStream);

            // Read initial request.
            List<String> connectRequest = new List<string>();
            string line;
            while (!String.IsNullOrEmpty(line = clientReader.ReadLine()))
            {
                connectRequest.Add(line);
            }
            if (connectRequest.Count == 0)
            {
                return;
            }

            string[] requestLine0Split = connectRequest[0].Split(' ');
            if (requestLine0Split.Length < 3)
            {
                return;
            }
            // Check if it is CONNECT
            string method = requestLine0Split[0];
            if (!method.Equals("CONNECT"))
            {
                return;
            }
            // Get host and port
            string requestUri = requestLine0Split[1];
            string[] uriSplit = requestUri.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
            if (uriSplit.Length < 2)
            {
                return;
            }
            string host = uriSplit[0];
            int port = Int32.Parse(uriSplit[1]);

            // Connect to server
            outClient = new TcpClient(host, port);
            NetworkStream serverStream = outClient.GetStream();
            StreamWriter serverWriter = new StreamWriter(serverStream);
            StreamReader serverReader = new StreamReader(serverStream);

            // Send 200 Connection Established to Client
            clientWriter.WriteLine("HTTP/1.0 200 Connection established\r\n\r\n");
            clientWriter.Flush();

            Logger.Debug("Established TCP connection for " + host);

            while (true)
            {
                line = clientReader.ReadLine();
                if (line != null)
                {
                    Logger.Debug("->Server: " + line);
                    serverWriter.WriteLine(line);
                }
                line = serverReader.ReadLine();
                if (line != null)
                {
                    Logger.Debug("->Client: " + line);
                    clientWriter.WriteLine(line);
                }
            }
        }
        catch(Exception)
        {
            // Disconnent if connections still alive
            try
            {
                if (inClient.Connected)
                {
                    inClient.Close();
                }
                if (outClient != null && outClient.Connected)
                {
                    outClient.Close();
                }
            }
            catch (Exception e)
            {
                Logger.Warn("Could not close the tcp connection: ", e);
            }
        }
    }

着信接続は別の方法で受け入れられます。

編集:いくつかの変更を加えました。ここで、クライアントは SSL データの送信を開始しますが、サーバーは応答しません。しばらくすると、クライアントは新しい接続を開いて再試行します。私が得る出力:

Established TCP connection for www.google.de
->Server: ▬♥☺ ?☺  ?♥☺R'"??????#☼}~??♣|]?
->Server: ??_5OL(??  H ??
->Server: ?¶ ? ? 9 8?☼?♣ ? 5??      ?◄?‼ E D 3 2?♀?♫?☻?♦ ? A ♣ ♦ /?↕ ▬ ‼?
->Server: ?♥??
->Server: ☺  0   ↕ ►
->Server: www.google.de
->Server: ♠ ↨ ↑ ↓ ♂ ☻☺  #  3t

TCP リスナー以外の提案も受け付けています。ありがとう!

4

1 に答える 1

4

動作しました。StreamReader/StreamWriter での SSL データの処理が間違っていました。データが文字列に変換されたため、エラーが発生しました(推測)。NetworkStream.ReadNetworkStream.Writeメソッドを使用してそれをbyte[]行いました。

コードは次のとおりです。

    /// <summary>
    /// Handles a TCP request.
    /// </summary>
    /// <param name="clientObject">The tcp client from the accepted connection.</param>
    protected void HandleTCPRequest(object clientObject)
    {
        TcpClient inClient = clientObject as TcpClient;
        TcpClient outClient = null;

        try
        {
            NetworkStream clientStream = inClient.GetStream();
            StreamReader clientReader = new StreamReader(clientStream);
            StreamWriter clientWriter = new StreamWriter(clientStream);

            // Read initial request.
            List<String> connectRequest = new List<string>();
            string line;
            while (!String.IsNullOrEmpty(line = clientReader.ReadLine()))
            {
                connectRequest.Add(line);
            }
            if (connectRequest.Count == 0)
            {
                throw new Exception();
            }

            string[] requestLine0Split = connectRequest[0].Split(' ');
            if (requestLine0Split.Length < 3)
            {
                throw new Exception();
            }
            // Check if it is CONNECT
            string method = requestLine0Split[0];
            if (!method.Equals("CONNECT"))
            {
                throw new Exception();
            }
            // Get host and port
            string requestUri = requestLine0Split[1];
            string[] uriSplit = requestUri.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
            if (uriSplit.Length < 2)
            {
                throw new Exception();
            }
            string host = uriSplit[0];
            int port = Int32.Parse(uriSplit[1]);

            // Connect to server
            outClient = new TcpClient(host, port);

            // Send 200 Connection Established to Client
            clientWriter.WriteLine("HTTP/1.0 200 Connection established\r\n\r\n");
            clientWriter.Flush();

            Logger.Debug("Established TCP connection for " + host + ":" + port);

            Thread clientThread =  new Thread(() => TunnelTCP(inClient, outClient));
            Thread serverThread = new Thread(() => TunnelTCP(outClient, inClient));

            clientThread.Start();
            serverThread.Start();
        }
        catch(Exception)
        {
            // Disconnent if connections still alive
            Logger.Debug("Closing TCP connection.");
            try
            {
                if (inClient.Connected)
                {
                    inClient.Close();
                }
                if (outClient != null && outClient.Connected)
                {
                    outClient.Close();
                }
            }
            catch (Exception e)
            {
                Logger.Warn("Could not close the tcp connection: ", e);
            }
        }
    }

    /// <summary>
    /// Tunnels a TCP connection.
    /// </summary>
    /// <param name="inClient">The client to read from.</param>
    /// <param name="outClient">The client to write to.</param>
    public void TunnelTCP(TcpClient inClient, TcpClient outClient)
    {
        NetworkStream inStream = inClient.GetStream();
        NetworkStream outStream = outClient.GetStream();
        byte[] buffer = new byte[1024];
        int read;
        try
        {
            while (inClient.Connected && outClient.Connected)
            {
                if (inStream.DataAvailable && (read = inStream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    outStream.Write(buffer, 0, read);
                }
            }
        }
        catch (Exception e)
        {
            Logger.Debug("TCP connection error: ", e);
        }
        finally
        {
            Logger.Debug("Closing TCP connection.");
            // Disconnent if connections still alive
            try
            {
                if (inClient.Connected)
                {
                    inClient.Close();
                }
                if (outClient.Connected)
                {
                    outClient.Close();
                }
            }
            catch (Exception e1)
            {
                Logger.Warn("Could not close the tcp connection: ", e1);
            }
        }
    }
于 2013-09-08T11:04:00.713 に答える