2013-08-19 29 views
2

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

我正在使用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侦听器。谢谢!

+0

你指的是草案过时,因为CONNECT命令是HTTP 1.1的一部分。建议您检查HTTP 1.1的相应RFC。 –

回答

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); 
      } 
     } 
    }