2

我正在尝试开发一个透明代理,它将来自客户端的不安全 http 流量作为安全的 https 流量转发到服务器,然后再返回。为了更好地说明我的观点,请看下图。

丰富的图片

假设由于各种原因客户端将仅使用 HTTP,它们不能将端口 443 用于 HTTPS。由于某些服务器不接受来自端口 80 的流量,因此我的代理需要将它们重新路由到端口 443。这是一种可能的情况:

  1. 从客户端接收数据,这些数据指向 www.google.com 的端口 80
  2. 初始化与https://www.google.com到端口 443 的连接(握手等)
  3. 加密来自客户端的数据并将它们发送到https://www.google.com到端口 443。
  4. 从https://www.google.com接收响应,解密它们并将它们发送回客户端到端口 80。

由于这是一个透明代理,因此客户端(在我的情况下是很多客户端)不需要任何额外的配置。网络已经配置好,以便他们的流量通过我的节点。目前,我的节点只是重新路由数据并阻止一些数据(如果它们包含病毒)。这是使用WinPcap访问低网络层完成的,但如果使用原始数据包(主要关注握手)太难完成,我愿意改变我的方法。

我试过的: 注意:www.google.com 可以是网络上的任何站点。它仅用作示例。

  1. 铱星的建议。这不起作用,因为 TcpListener 仅在另一个应用程序使用 TcpClient 连接到它时才接受新连接。由于这是一个透明代理,它不起作用。
  2. 改为使用 HttpListener。但是,这似乎不起作用,因为它只接受到我自己的 IP(而不是 www.google.com)的连接。
  3. 像以前一样使用 HttpListener 但这次我将数据包转发到我自己的 IP,以便 HttpListener 接受连接。由于某种原因,这似乎不起作用(通过wireshark和TCP SYN数据包检查不断重新发送,不知道为什么或如何修复它)。
  4. 使用 SslStream 连接到https://www.google.com,然后从客户端收到的原始数据包中获取内容并将它们写入流。这不起作用,因为 SslStream 自己处理 TCP 数据包(如 ACK 或 SYN)。流只需要 Http 请求。它不起作用的另一个原因是因为我无法从流中读取 TCP 数据包的内容,只能读取 HTTP 响应的内容(因此客户端坐在那里等待 ACK)。
  5. 将 TCP 数据包从客户端原样转发到端口 443,从服务器转发到端口 80(因为只有 HTTP 请求和响应使用 SSL 加密,所以没有区别)并使用 HttpRequest 类发出所有 http 请求和响应(因为类自己处理握手)。这不起作用,因为双方的 ACK 都是错误的。

开发这种代理的最佳方法是什么?

编辑:有什么方法可以让 TcpListener 或 HttpListener 充当透明代理?(无需在客户计算机上进行配置)。HttpListener 究竟何时能够识别出客户端正在尝试连接?

4

1 回答 1

0

我真的不明白为什么你需要从SslStream. 如果我正确阅读了您的描述,您应该只需要:

  • 等待客户端连接
  • 当客户端连接时,连接到服务器
  • 将服务器连接包装NetworkStream在一个SslStream和中AuthenticateAsClient
  • 一旦通过身份验证,并行:
    • 从客户端读取数据并将其写入SslStream
    • 从客户端读取数据SslStream并将其写入客户端

在此过程中,我看不到您需要从SslStream.

以下是一个非常基本的示例(尽管完全未经测试):

static void Main(string[] args)
{
    var listener = new TcpListener(IPAddress.Any, 11180);
    var clientConnection = listener.AcceptTcpClient();
    // When we get here, the client has connected, initiate the server connection
    var serverConnection = new TcpClient("your.server.name", 443);
    var serverStream = serverConnection.GetStream();
    var secureStream = new SslStream(serverStream);
    secureStream.AuthenticateAsClient("your.server.name");
    ConnectStreams(clientConnection.GetStream(), secureStream);
}

private static void ConnectStreams(Stream streamA, Stream streamB)
{
    ForwardStream(streamA, streamB, new byte[1024]);
    ForwardStream(streamB, streamA, new byte[1024]);
}

private static void ForwardStream(Stream source, Stream destination, byte[] buffer)
{
    source.BeginRead(buffer, 0, buffer.Length, r => Forward(source, destination, r, buffer), null);
}

private static void Forward(Stream source, Stream destination, IAsyncResult asyncResult, byte[] buffer)
{
    var bytesRead = source.EndRead(asyncResult);
    if (bytesRead == 0)
    {
        destination.Close();
        return;
    }
    destination.Write(buffer, 0, bytesRead);
    ForwardStream(source, destination, buffer);
}
于 2013-04-19T15:42:06.117 回答