使用系結或連線重新導向
Windows 篩選平臺 (WFP) 的連線/系結重新導向功能可讓應用層強制執行 (ALE) 圖說文字驅動程式檢查,並視需要重新導向連線。
這項功能適用於 Windows 7 和更新版本。
注意 WFP 驅動程式範例中的ClassifyFunctions_ProxyCallouts.cpp模組包含示範連線/系結重新導向的程式代碼。
WFP 連線重新導向圖說文字會重新導向應用程式的連線要求,讓應用程式連線到 Proxy 服務,而不是原始目的地。 Proxy 服務有兩個套接字:一個用於重新導向的原始連線,另一個用於新的 Proxy 輸出連線。
WFP 重新導向記錄是一個不透明數據的緩衝區,糧食計劃署必須在FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V4和FWPM_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 的實作中執行下列步驟:
呼叫 FwpsRedirectHandleCreate0 以取得可用來重新導向 TCP 連線的句柄。 此句柄應該快取並用於所有重新導向。 (Windows 7 和更早版本省略此步驟。
在 Windows 8 和更新版本中,您必須在圖說驅動程式中使用 FwpsQueryConnectionRedirectState0 函式來查詢連線的重新導向狀態。 這必須完成才能防止無限重新導向。
呼叫 FwpsAcquireClassifyHandle0 以取得將用於後續函數呼叫的句柄。
呼叫 FwpsAcquireWritableLayerDataPointer0 以取得呼叫 classifyFn 之圖層的可寫入數據結構。 將 writableLayerData out 參數轉換成對應至層次的結構,FWPS_BIND_REQUEST0或FWPS_CONNECT_REQUEST0。
從 Windows 8 開始,如果您的圖說驅動程式重新導向至本地服務,您必須呼叫 FwpsRedirectHandleCreate0 以填入FWPS_CONNECT_REQUEST0結構的 localRedirectHandle 成員,才能讓本機 Proxy 運作。
視需要變更層次數據:
將原始目的地儲存在本機重新導向內容中,如下列範例所示:
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(…);
修改遠端位址,如下列範例所示:
// 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));
如果您的圖說文字驅動程式重新導向至本機服務,它應該在FWPS_CONNECT_REQUEST0結構的localRedirectTargetPID成員中設定本機 Proxy PID。
如果您的圖說驅動程式重新導向至本機服務,它應該會在 FWPS_CONNECT_REQUEST0 結構的localRedirectHandle成員中設定 FwpsRedirectHandleCreate0 所傳回的重新導向句柄。
呼叫 FwpsApplyModifiedLayerData0 以套用對數據所做的變更。
在您的 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
在您的 Proxy 服務中(可能處於使用者模式或核心模式),您必須在 Proxy 連線套接字上設定重新導向記錄,如下列範例所示,才能建立新的輸出套接字:
proxySock = WSASocket(…); result = WSAIoctl( proxySock, SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS, redirectRecords, …);
呼叫 FwpsReleaseClassifyHandle0 以釋放步驟 2 中取得的分類句柄。
呼叫 FwpsRedirectHandleDestroy0 以終結步驟 1 中取得的句柄。
若要以異步方式執行重新導向,圖說驅動程式必須執行下列步驟:
呼叫 FwpsRedirectHandleCreate0 以取得可用來重新導向 TCP 連線的句柄。 (Windows 7 和更早版本省略此步驟。
在 Windows 8 和更新版本中,您必須在圖說驅動程式中使用 FwpsQueryConnectionRedirectState0 函式來查詢連線的重新導向狀態。
呼叫 FwpsAcquireClassifyHandle0 以取得將用於後續函數呼叫的句柄。 此步驟和步驟 2 和 3 會在圖說驅動程式的 classifyFn 圖說文字函式中執行。
呼叫 FwpsPendClassify0 以將分類置於擱置狀態,如下列範例所示:
FwpsPendClassify( redirectContext->classifyHandle, 0, &redirectContext->classifyOut); classifyOut->actionType = FWP_ACTION_BLOCK; classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
注意
如果您的目標是 Windows 7,您必須在個別的背景工作角色函式中執行下列步驟。 如果您的目標是 Windows 8 或更新版本,您可以從 classifyFn 內執行異步重新導向的所有步驟,並忽略步驟 5。
將分類句柄和可寫入層數據傳送至另一個函式以進行異步處理。 其餘步驟會在該函式中執行,而不是在圖說驅動程式的classifyFn實作中執行。
呼叫 FwpsAcquireWritableLayerDataPointer0 以取得呼叫 classifyFn 之圖層的可寫入數據結構。 將 writableLayerData out 參數轉換成對應至層次的結構,FWPS_BIND_REQUEST0或FWPS_CONNECT_REQUEST0。
從 Windows 8 開始,如果您的圖說驅動程式在本機重新導向,您必須呼叫 FwpsRedirectHandleCreate0 以填入 FWPS_CONNECT_REQUEST0 結構的 localRedirectHandle 成員,才能讓 Proxy 運作。
將任何圖說文字特定內容資訊儲存在私人內容結構中,如下列範例所示:
redirectContext->classifyHandle = classifyHandle; redirectContext->connectRequest = connectRequest; redirectContext->classifyOut = *classifyOut; // deep copy // store original destination IP, port
視需要變更圖層數據。
呼叫 FwpsApplyModifiedLayerData0 以套用對數據所做的變更。 如果您想要在另一個圖說文字進一步修改數據時重新授權,請設定FWPS_CLASSIFY_FLAG_REAUTHORIZE_IF_MODIFIED_BY_OTHERS旗標。
呼叫 FwpsCompleteClassify0 以異步方式完成分類作業,如下列範例所示:
FwpsCompleteClassify( redirectContext->classifyHandle, 0, &redirectContext->classifyOut); classifyOut->actionType = FWP_ACTION_PERMIT; classifyOut->rights |= FWPS_RIGHT_ACTION_WRITE;
呼叫 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_V4或FWPS_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。