共用方式為


使用系結或連線重新導向

Windows 篩選平臺 (WFP) 的連線/系結重新導向功能可讓應用層強制執行 (ALE) 圖說文字驅動程式檢查,並視需要重新導向連線。

這項功能適用於 Windows 7 和更新版本。

注意 WFP 驅動程式範例中的ClassifyFunctions_ProxyCallouts.cpp模組包含示範連線/系結重新導向的程式代碼。

WFP 連線重新導向圖說文字會重新導向應用程式的連線要求,讓應用程式連線到 Proxy 服務,而不是原始目的地。 Proxy 服務有兩個套接字:一個用於重新導向的原始連線,另一個用於新的 Proxy 輸出連線。

WFP 重新導向記錄是一個不透明數據的緩衝區,糧食計劃署必須在FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V4FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V6層的輸出 Proxy 連線上設定,以便重新導向的連線和原始連線在邏輯上相關。

只有在系結-重新導向層中才支持變更流程的本機位址和埠。 線上-重新導向層不支援此功能。

用於重新導向的圖層

圖說驅動程式可以在下列層預先格式化重新導向,這稱為「重新導向層」:

  • FWPM_LAYER_ALE_BIND_REDIRECT_V4 (FWPS_LAYER_ALE_BIND_REDIRECT_V4)

  • FWPM_LAYER_ALE_BIND_REDIRECT_V6 (FWPS_LAYER_ALE_BIND_REDIRECT_V6)

  • FWPM_LAYER_ALE_CONNECT_REDIRECT_V4 (FWPS_LAYER_ALE_CONNECT_REDIRECT_V4)

  • FWPM_LAYER_ALE_CONNECT_REDIRECT_V6 (FWPS_LAYER_ALE_CONNECT_REDIRECT_V6)

執行重新導向的圖層會決定變更的效果。 聯機層的變更只會影響所連接的流程。 系結層的變更會影響使用該套接字的所有連線。

重新導向層僅適用於 Windows 7 和更新版本的 Windows。 支援 這些層分類的圖說文字驅動程序必須使用 FwpsCalloutRegister1 或更新版本進行註冊,而不是舊版 FwpsCalloutRegister0 函式。

重要

 重新導向不適用於所有類型的網路流量。 下列清單中顯示支援重新導向的封包型態:

  • TCP
  • UDP
  • 沒有標頭 include 選項的原始 UDPv4
  • 原始ICMP

執行重新導向

若要重新導向連線,圖說驅動程序必須取得 TCP 4 元組資訊的可寫入複本、視需要進行變更,並套用變更。 提供一組新的函式,以取得可寫入的圖層數據,並透過引擎加以套用。 圖說文字驅動程式可以選擇在分類Fn 函式中內嵌變更,或以異步方式在另一個函式中進行變更。

實作重新導向的圖說文字驅動程序必須使用 classificationFn1 或更新版本,而不是將Fn0 分類為分類圖說文字函式。 若要使用 classifyFn1 或更新版本,必須呼叫 FwpsCalloutRegister1 或更新版本來註冊圖說文字,而不是舊版 FwpsCalloutRegister0。

若要執行內嵌重新導向,圖說驅動程序必須在其分類Fn 的實作中執行下列步驟:

  1. 呼叫 FwpsRedirectHandleCreate0 以取得可用來重新導向 TCP 連線的句柄。 此句柄應該快取並用於所有重新導向。 (Windows 7 和更早版本省略此步驟。

  2. 在 Windows 8 和更新版本中,您必須在圖說驅動程式中使用 FwpsQueryConnectionRedirectState0 函式來查詢連線的重新導向狀態。 這必須完成才能防止無限重新導向。

  3. 呼叫 FwpsAcquireClassifyHandle0 以取得將用於後續函數呼叫的句柄。

  4. 呼叫 FwpsAcquireWritableLayerDataPointer0 以取得呼叫 classifyFn 之圖層的可寫入數據結構。 將 writableLayerData out 參數轉換成對應至層次的結構,FWPS_BIND_REQUEST0FWPS_CONNECT_REQUEST0。

    從 Windows 8 開始,如果您的圖說驅動程式重新導向至本地服務,您必須呼叫 FwpsRedirectHandleCreate0 以填入FWPS_CONNECT_REQUEST0結構的 localRedirectHandle 成員,才能讓本機 Proxy 運作。

  5. 視需要變更層次數據:

    1. 將原始目的地儲存在本機重新導向內容中,如下列範例所示:

      FWPS_CONNECT_REQUEST* connectRequest = redirectContext->connectRequest;
      // Replace "..." with your own redirect context size
      connectRequest->localRedirectContextSize = ...;
      // Store original destination IP/Port information in the localRedirectContext member
      connectRequest->localRedirectContext =    ExAllocatePoolWithTag(…);
      
    2. 修改遠端位址,如下列範例所示:

      // Ensure we don't need to worry about crossing any of the TCP/IP stack's zones
      if(INETADDR_ISANY((PSOCKADDR)&(connectRequest->localAddressAndPort)))
      {
         INETADDR_SETLOOPBACK((PSOCKADDR)&(connectRequest->remoteAddressAndPort));
      }
      else
      {
         INETADDR_SET_ADDRESS((PSOCKADDR)&(connectRequest->remoteAddressAndPort),
                               INETADDR_ADDRESS((PSOCKADDR)&(connectRequest->localAddressAndPort)));
      }
      INETADDR_SET_PORT((PSOCKADDR)&connectRequest->remoteAddressAndPort,
                        RtlUshortByteSwap(params->proxyPort));
      
    3. 如果您的圖說文字驅動程式重新導向至本機服務,它應該在FWPS_CONNECT_REQUEST0結構的localRedirectTargetPID成員設定本機 Proxy PID。

    4. 如果您的圖說驅動程式重新導向至本機服務,它應該會在 FWPS_CONNECT_REQUEST0 結構的localRedirectHandle成員中設定 FwpsRedirectHandleCreate0 所傳回的重新導向句柄。

  6. 呼叫 FwpsApplyModifiedLayerData0 以套用對數據所做的變更。

  7. 在您的 Proxy 服務中(可能處於使用者模式或核心模式),您必須查詢重新導向記錄和內容,如下列範例所示:

    BYTE* redirectRecords;
    BYTE redirectContext[CONTEXT_SIZE];
    listenSock = WSASocket(…);
    result = bind(listenSock, …);
    result = listen(listenSock, …);
    clientSock = WSAAccept(listenSock, …);
    // opaque data to be set on proxy connection
    result = WSAIoctl(clientSock,
                      SIO_QUERY_WFP_CONNECTION_REDIRECT_RECORDS,
                      redirectRecords, …);
    // callout allocated data, contains original destination information
    result = WSAIoctl(clientSock,
                      SIO_QUERY_WFP_CONNECTION_REDIRECT_CONTEXT,
                      redirectContext, …);
    // extract original destination IP and port from above context
    
  8. 在您的 Proxy 服務中(可能處於使用者模式或核心模式),您必須在 Proxy 連線套接字上設定重新導向記錄,如下列範例所示,才能建立新的輸出套接字:

    proxySock = WSASocket(…);
    result = WSAIoctl(
                 proxySock,
                 SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS,
                 redirectRecords, …);
    
  9. 呼叫 FwpsReleaseClassifyHandle0 以釋放步驟 2 中取得的分類句柄。

  10. 呼叫 FwpsRedirectHandleDestroy0 以終結步驟 1 中取得的句柄。

若要以異步方式執行重新導向,圖說驅動程式必須執行下列步驟:

  1. 呼叫 FwpsRedirectHandleCreate0 以取得可用來重新導向 TCP 連線的句柄。 (Windows 7 和更早版本省略此步驟。

  2. 在 Windows 8 和更新版本中,您必須在圖說驅動程式中使用 FwpsQueryConnectionRedirectState0 函式來查詢連線的重新導向狀態。

  3. 呼叫 FwpsAcquireClassifyHandle0 以取得將用於後續函數呼叫的句柄。 此步驟和步驟 2 和 3 會在圖說驅動程式的 classifyFn 圖說文字函式中執行。

  4. 呼叫 FwpsPendClassify0 以將分類置於擱置狀態,如下列範例所示:

    FwpsPendClassify(
            redirectContext->classifyHandle,
            0,
            &redirectContext->classifyOut);
    classifyOut->actionType = FWP_ACTION_BLOCK;
    classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
    

注意

如果您的目標是 Windows 7,您必須在個別的背景工作角色函式中執行下列步驟。 如果您的目標是 Windows 8 或更新版本,您可以從 classifyFn執行異步重新導向的所有步驟,並忽略步驟 5。

  1. 將分類句柄和可寫入層數據傳送至另一個函式以進行異步處理。 其餘步驟會在該函式中執行,而不是在圖說驅動程式的classifyFn作中執行。

  2. 呼叫 FwpsAcquireWritableLayerDataPointer0 以取得呼叫 classifyFn 之圖層的可寫入數據結構。 將 writableLayerData out 參數轉換成對應至層次的結構,FWPS_BIND_REQUEST0FWPS_CONNECT_REQUEST0。

    從 Windows 8 開始,如果您的圖說驅動程式在本機重新導向,您必須呼叫 FwpsRedirectHandleCreate0 以填入 FWPS_CONNECT_REQUEST0 結構的 localRedirectHandle 成員,才能讓 Proxy 運作。

  3. 將任何圖說文字特定內容資訊儲存在私人內容結構中,如下列範例所示:

    redirectContext->classifyHandle = classifyHandle;
    redirectContext->connectRequest = connectRequest;
    redirectContext->classifyOut = *classifyOut; // deep copy
    // store original destination IP, port
    
  4. 視需要變更圖層數據。

  5. 呼叫 FwpsApplyModifiedLayerData0 以套用對數據所做的變更。 如果您想要在另一個圖說文字進一步修改數據時重新授權,請設定FWPS_CLASSIFY_FLAG_REAUTHORIZE_IF_MODIFIED_BY_OTHERS旗標。

  6. 呼叫 FwpsCompleteClassify0 以異步方式完成分類作業,如下列範例所示:

    FwpsCompleteClassify(
            redirectContext->classifyHandle,
            0,
            &redirectContext->classifyOut);
    classifyOut->actionType = FWP_ACTION_PERMIT;
    classifyOut->rights |= FWPS_RIGHT_ACTION_WRITE;
    
  7. 呼叫 FwpsReleaseClassifyHandle0 以釋放步驟 1 中取得的分類句柄。

處理從多個圖說文字連線重新導向

一個以上的圖說文字驅動程式可能會起始相同流程的連線重新導向。 執行連線重新導向的圖說文字應該注意其他要求並適當地回應。

每當圖說文字畫上分類時,應該設定FWPS_RIGHT_ACTION_WRITE旗標。 您的圖說文字應該測試 FWPS_RIGHT_ACTION_WRITE 旗標,以檢查圖說文字傳回動作的許可權。 如果未設定此旗標,您的圖說文字仍然可以傳回 FWP_ACTION_BLOCK 動作,以否決 先前圖說文字傳回的FWP_ACTION_PERMIT 動作。

在 Windows 8 和更新版本中,您的圖說文字驅動程式必須使用 FwpsQueryConnectionRedirectState0 函式來查詢連線的重新導向狀態(查看圖說文字驅動程式或其他圖說文字驅動程式是否已修改它)。 如果圖說驅動程式重新導向連線,或先前由圖說驅動程式重新導向,圖說驅動程式應該不會執行任何動作。 否則,它也應該檢查本機重新導向,如下列範例所示:

FwpsAcquireWritableLayerDataPointer(...,(PVOID*)&connectRequest), ...);
if(connectRequest->previousVersion->modifierFilterId != filterId)
{
    if(connectRequest->previousVersion->localRedirectHandle)
    {
        classifyOut->actionType = FWP_ACTION_PERMIT;
        classifyOut->rights &= FWPS_RIGHT_ACTION_WRITE;
        FwpsApplyModifiedLayerData(
                classifyHandle,
                (PVOID)connectRequest,
                FWPS_CLASSIFY_FLAG_REAUTHORIZE_IF_MODIFIED_BY_OTHERS);
    }
}

如果連線是本機 Proxy,則您的圖說文字驅動程式不應該嘗試重新導向它。

使用連線重新導向的圖說驅動程式應該在 ALE 授權連接層註冊(FWPS_LAYER_ALE_AUTH_CONNECT_V4FWPS_LAYER_ALE_AUTH_CONNECT_V6),並檢查下列兩個元數據值,以取得設定FWP_CONDITION_FLAG_IS_CONNECTION_REDIRECTED旗標的指示:

  • FWPS_METADATA_FIELD_LOCAL_REDIRECT_TARGET_PID包含負責重新導向流程之進程的進程標識碼。

  • FWPS_METADATA_FIELD_ORIGINAL_DESTINATION包含流程原始目的地的位址。

FWPS_CONNECT_REQUEST0 結構包含名為localRedirectTargetPID的成員。 若要讓任何回送連線重新導向有效,此字段必須填入將負責重新導向流程之程式的 PID。 這是引擎在 ALE 授權連接層時傳遞的相同數據,FWPS_METADATA_FIELD_LOCAL_REDIRECT_TARGET_ID

從 Windows 8 開始,Proxy 服務必須針對 Proxy 服務的原始端點發出SIO_QUERY_WFP_CONNECTION_REDIRECT_RECORDS,並使用 WSAIoctl SIO_QUERY_WFP_CONNECTION_REDIRECT_CONTEXT IOCTL。 此外,必須在新的 (proxied) 套接字上使用 WSAIoctl 發出SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS IOCTL

WFP 版本無關的名稱和以特定 Windows 版本為目標