流检查

内联流检查

内联流修饰符可以通过在从分类Fn 标注函数返回FWP_ACTION_PERMITFWP_ACTION_BLOCK时,通过设置FWPS_STREAM_CALLOUT_IO_PACKET0结构的 countBytesEnforced 成员的值来允许或阻止部分指示的数据来编辑流数据。 他们还可以调用 FwpsStreamInjectAsync0 函数向流添加新内容。 此内容可以是新的,也可以替换阻止的数据。

若要替换在指示段 (中间找到的模式,例如 ,n 个字节后跟 p 字节的模式,后跟 m 个字节) ,标注将遵循以下步骤:

  1. 标注的分类Fn 函数使用 n + p m + 字节调用。

  2. 标注返回将 countBytesEnforced 成员设置为 n的FWP_ACTION_PERMIT

  3. 标注的 分类Fn 函数再次调用 p + m 字节。 如果 countBytesEnforced 小于指示的数量,WFP 将再次调用分类Fn

  4. 分类Fn 函数中,标注调用 FwpsStreamInjectAsync0 函数来注入替换模式 p'。 然后,标注返回 countBytesEnforced 设置为 p的FWP_ACTION_BLOCK

  5. 标注的 分类Fn 函数再次调用 m 字节。

  6. 标注返回 countBytesEnforced 设置为 m的FWP_ACTION_PERMIT

如果指示的数据不足以使标注做出检查决策,它可以将FWPS_STREAM_CALLOUT_IO_PACKET0结构的 streamAction 成员设置为FWPS_STREAM_ACTION_NEED_MORE_DATA,并将 countBytesRequired 成员设置为在再次指示数据之前 WFP 应累积的最小数量。 设置 streamAction 时,标注应从分类Fn 函数返回FWP_ACTION_NONE

设置 FWPS_STREAM_ACTION_NEED_MORE_DATA 时,WFP 最多可累积 8 MB 的流数据。 当 WFP 调用标注的分类Fn 函数且缓冲区空间耗尽时,将设置FWPS_CLASSIFY_OUT_FLAG_BUFFER_LIMIT_REACHED标志。 设置后一个标志时,标注必须完全接受指示的数据。 设置 FWPS_CLASSIFY_OUT_FLAG_NO_MORE_DATA 标志时,标注不得返回 FWPS_STREAM_ACTION_NEED_MORE_DATA

为了方便从平面缓冲区扫描流模式,WFP 提供了 FwpsCopyStreamDataToBuffer0 实用工具函数,可将指示的流数据复制到连续缓冲区中。

带外流检查

对于带外检查或修改,流标注将遵循与数据包检查标注类似的模式:它首先克隆所有指示的流段以供延迟处理,然后阻止这些段。 检查或修改的数据稍后注入回数据流。 在带外注入数据时,标注必须在所有指示的段上返回 FWP_ACTION_BLOCK ,以确保结果流的完整性。 带外检测模块不得任意将 FIN (指示发送方不再) 数据注入传出数据流。 如果模块必须删除连接,则其分类Fn 标注函数必须将FWPS_STREAM_CALLOUT_IO_PACKET0结构的 streamAction 成员设置为FWPS_STREAM_ACTION_DROP_CONNECTION

注意 标注从带外切换到内联是 违反协定 的,并可能导致意外行为。 确保带外标注满足每个指定条件。

由于流数据可以指示为 NET_BUFFER_LIST 链,因此 FWP 提供在 net 缓冲区列表链上运行的 FwpsCloneStreamData0FwpsDiscardClonedStreamData0 实用工具函数。

WFP 还支持针对传入方向进行流数据限制。 如果标注无法跟上传入数据速率的步伐,它可以返回 FWPS_STREAM_ACTION_DEFER 以“暂停”流。 然后,可以通过调用 FwpsStreamContinue0 函数来“恢复”流。 使用此函数延迟流会导致 TCP/IP 堆栈停止 ACK 处理传入数据。 这会导致 TCP 滑动窗口减小到 0。

对于带外流检查标注,在调用 FwpsStreamInjectAsync0 函数时,不得调用 FwpsStreamContinue0

注入的流数据不会重新指示到标注,但它将可用于从较低权重的子层流式传输标注。

GitHub 上 Windows 驱动程序示例存储库中的 Windows 筛选平台流编辑示例展示了如何在流层上执行内联和带外编辑。

注意 Windows Server 2008 及更高版本不支持在以下过程中删除流筛选器:

  • 标注正在执行带外数据包注入。

  • 标注通过将 FWPS_STREAM_CALLOUT_IO_PACKET0 结构的 streamAction 成员设置为 FWPS_STREAM_ACTION_NEED_MORE_DATA 来请求更多数据。

  • 标注通过将 FWPS_STREAM_CALLOUT_IO_PACKET0 结构的 streamAction 成员设置为 FWPS_STREAM_ACTION_DEFER 来延迟

动态流检查

Windows 7 及更高版本支持动态流检查。 动态流检查对现有流数据流进行操作,而不是创建和拆除新数据流。 可以执行动态流检查的标注驱动程序应在 FWPS_CALLOUT1 或 FWPS_CALLOUT2 结构的 Flags 成员中设置FWP_CALLOUT_FLAG_ALLOW_MID_STREAM_INSPECTION标志。

避免不必要的检查

若要仅对驱动程序感兴趣的连接执行流检查,标注可以在 FWPS_CALLOUT0 结构的 Flags 成员中设置 FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW 标志。 所有其他连接将忽略此标注。 性能将得到改进,驱动程序将不必维护不必要的状态数据。

流层瀑布模型

WFP 中的流层遵循严格的瀑布模型:也就是说,仅当上一个标注 (任何) 显式允许时,才允许此层中的标注检查流段。 如果标注阻止指示的段,该段将永久从流中取出,并且不允许任何标注来检查它。

此外:

  1. 流层上的每个非检查标注都必须显式为 classifyOut 参数的 actionType 成员赋值,而不考虑以前在该参数中设置的值。
  2. 分类输出参数的权限成员中的FWPS_RIGHT_ACTION_WRITE标志在 WFP 流层中没有意义。 此层的标注不应检查此标志的存在。 标注可以处理指示的 layerData 参数,而不考虑 classifyOut-rights> 的值。