使用 TCP 的 C# HTTPS 代理

Sat*_*ert 2 .net c# https proxy

我正在尝试使用 C# 实现 HTTPS 代理。代理应仅支持 HTTPS,而不支持 HTTP。据我所知,HTTPListener 不是一个好的选择,因为您需要 SSL 证书才能支持 HTTPS,而代理通常不提供该证书。

\n\n

我正在使用 TcpListener 和 TcpClients。这是我到目前为止得到的代码:

\n\n
   protected void HandleTCPRequest(object clientObject)\n    {\n        TcpClient inClient = clientObject as TcpClient;\n        TcpClient outClient = null;\n\n        try\n        {\n            NetworkStream clientStream = inClient.GetStream();\n            StreamReader clientReader = new StreamReader(clientStream);\n            StreamWriter clientWriter = new StreamWriter(clientStream);\n\n            // Read initial request.\n            List<String> connectRequest = new List<string>();\n            string line;\n            while (!String.IsNullOrEmpty(line = clientReader.ReadLine()))\n            {\n                connectRequest.Add(line);\n            }\n            if (connectRequest.Count == 0)\n            {\n                return;\n            }\n\n            string[] requestLine0Split = connectRequest[0].Split(\' \');\n            if (requestLine0Split.Length < 3)\n            {\n                return;\n            }\n            // Check if it is CONNECT\n            string method = requestLine0Split[0];\n            if (!method.Equals("CONNECT"))\n            {\n                return;\n            }\n            // Get host and port\n            string requestUri = requestLine0Split[1];\n            string[] uriSplit = requestUri.Split(new char[] { \':\' }, StringSplitOptions.RemoveEmptyEntries);\n            if (uriSplit.Length < 2)\n            {\n                return;\n            }\n            string host = uriSplit[0];\n            int port = Int32.Parse(uriSplit[1]);\n\n            // Connect to server\n            outClient = new TcpClient(host, port);\n            NetworkStream serverStream = outClient.GetStream();\n            StreamWriter serverWriter = new StreamWriter(serverStream);\n            StreamReader serverReader = new StreamReader(serverStream);\n\n            // Send 200 Connection Established to Client\n            clientWriter.WriteLine("HTTP/1.0 200 Connection established\\r\\n\\r\\n");\n            clientWriter.Flush();\n\n            Logger.Debug("Established TCP connection for " + host);\n\n            while (true)\n            {\n                line = clientReader.ReadLine();\n                if (line != null)\n                {\n                    Logger.Debug("->Server: " + line);\n                    serverWriter.WriteLine(line);\n                }\n                line = serverReader.ReadLine();\n                if (line != null)\n                {\n                    Logger.Debug("->Client: " + line);\n                    clientWriter.WriteLine(line);\n                }\n            }\n        }\n        catch(Exception)\n        {\n            // Disconnent if connections still alive\n            try\n            {\n                if (inClient.Connected)\n                {\n                    inClient.Close();\n                }\n                if (outClient != null && outClient.Connected)\n                {\n                    outClient.Close();\n                }\n            }\n            catch (Exception e)\n            {\n                Logger.Warn("Could not close the tcp connection: ", e);\n            }\n        }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

传入的连接以另一种方法接受。

\n\n

编辑:我做了一些更改。现在,客户端开始发送 SSL 数据,但服务器从未响应。一段时间后,客户端打开一个新连接并重试。我得到的输出:

\n\n
Established TCP connection for www.google.de\n->Server: \xe2\x96\xac\xe2\x99\xa5\xe2\x98\xba ?\xe2\x98\xba  ?\xe2\x99\xa5\xe2\x98\xbaR\'"??????#\xe2\x98\xbc}~??\xe2\x99\xa3|]?\n->Server: ??_5OL(??  H ??\n->Server: ?\xc2\xb6 ? ? 9 8?\xe2\x98\xbc?\xe2\x99\xa3 ? 5??      ?\xe2\x97\x84?\xe2\x80\xbc E D 3 2?\xe2\x99\x80?\xe2\x99\xab?\xe2\x98\xbb?\xe2\x99\xa6 ? A \xe2\x99\xa3 \xe2\x99\xa6 /?\xe2\x86\x95 \xe2\x96\xac \xe2\x80\xbc?\n->Server: ?\xe2\x99\xa5??\n->Server: \xe2\x98\xba  0   \xe2\x86\x95 \xe2\x96\xba\n->Server: www.google.de\n->Server: \xe2\x99\xa0 \xe2\x86\xa8 \xe2\x86\x91 \xe2\x86\x93 \xe2\x99\x82 \xe2\x98\xbb\xe2\x98\xba  #  3t\n
Run Code Online (Sandbox Code Playgroud)\n\n

除了 TCP 侦听器之外,我愿意接受其他建议。谢谢!

\n

Sat*_*ert 5

成功了。使用 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);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)