簡體   English   中英

透明代理-從端口80到443

[英]Transparent proxy - from port 80 to 443

我正在嘗試開發一個透明的代理,該代理將來自客戶端的不安全的HTTP流量作為安全的https流量轉發到服務器,然后再次返回。 為了更好地說明我的觀點,請看以下圖片。

豐富的圖片

讓我們假設由於各種原因,客戶端將僅使用HTTP,而不能將端口443用於HTTPS。 由於某些服務器不接受來自端口80的流量,因此我的代理服務器需要將它們重新路由到端口443。這是一種可能的情況:

  1. 從客戶端接收數據,該數據將通過80端口訪問www.google.com。
  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接受連接。 由於某些原因,這似乎不起作用(通過wirehark和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何時准確識別出客戶端正在嘗試連接?

我真的不明白為什么您需要從SslStream讀取加密的數據。 如果我正確閱讀了您的描述,則只需要:

  • 等待客戶端連接
  • 客戶端連接后,連接到服務器
  • 將服務器連接的NetworkStream包裝在SslStreamAuthenticateAsClient
  • 身份驗證后,並行執行:
    • 從客戶端讀取數據並將其寫入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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM