使用绑定或连接重定向
Windows 筛选平台 (WFP) 的连接/绑定重定向功能使应用程序层强制 (ALE) 标注驱动程序来检查连接,并根据需要重定向连接。
此功能在 Windows 7 及更高版本中可用。
注意WFP 驱动程序示例中的 ClassifyFunctions_ProxyCallouts.cpp 模块包含演示连接/绑定重定向的代码。
WFP 连接重定向标注会重定向应用程序的连接请求,以便应用程序连接到代理服务而不是原始目标。 代理服务有两个套接字:一个用于重定向的原始连接,一个用于新的代理出站连接。
WFP 重定向记录是 WFP 必须在 FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V4 层和 FWPM_LAYER_ALE_AUTH_CONNECT_REDIRECT_V6 层的出站代理连接上设置的不透明数据的缓冲区,以便重定向连接与原始连接在逻辑上相关。
仅在绑定重定向层中支持更改流的本地地址和端口。 连接重定向层不支持此操作。
用于重定向的层
可在以下层(称为“重定向层”)由标注驱动程序执行重定向:
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
- 没有标头包含选项的原始 UDPv4
- 原始 ICMP
执行重定向
若要重定向连接,标注驱动程序必须获取 TCP 4 元组信息的可写副本,根据需要对其进行更改,并应用更改。 提供了一组新函数来获取可写层数据并通过引擎应用这些数据。 标注驱动程序可以选择在其 classifyFn 函数中以内联方式或在另一个函数中异步进行更改。
实现重定向的标注驱动程序必须使用 classificationFn1 或更高版本,而不是 classificationFn0 作为其分类标注函数。 若要使用 classifyFn1 或更高版本,必须通过调用 FwpsCalloutRegister1 或更高版本(而不是旧版 FwpsCalloutRegister0)注册标注。
若要执行内联重定向,标注驱动程序必须在实现 classifyFn 时执行以下步骤:
调用 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 成员,以便使本地代理正常工作。
根据需要更改层数据:
在本地重定向上下文中保存原始目标,如以下示例所示:
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 成员中设置本地代理 PID。
如果标注驱动程序重定向到本地服务,则应在 FWPS_CONNECT_REQUEST0 结构的 localRedirectHandle 成员中设置 FwpsRedirectHandleCreate0 返回的重定向句柄。
调用 FwpsApplyModifiedLayerData0 以应用对数据所做的更改。
在代理服务 ((可能处于用户模式或内核模式) )中,必须查询重定向记录和上下文,如以下示例所示:
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
在代理服务 ((可能处于用户模式或内核模式) )中,必须在代理连接套接字上设置重定向记录,如以下示例所示,以创建新的出站套接字:
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 成员,以便使代理正常工作。
将任何标注特定的上下文信息存储在专用上下文结构中,如以下示例所示:
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);
}
}
如果连接到本地代理,则标注驱动程序不应尝试重定向它。
使用连接重定向的标注驱动程序应在 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 开始,代理服务需要使用 WSAIoctl 针对代理服务的原始终结点发出SIO_QUERY_WFP_CONNECTION_REDIRECT_RECORDS和SIO_QUERY_WFP_CONNECTION_REDIRECT_CONTEXT IOCTL。 此外,必须在新的 (代理) 套接字上使用 WSAIoctl 颁发SIO_SET_WFP_CONNECTION_REDIRECT_RECORDS IOCTL。
相关主题
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈