对象管理
本部分介绍正确使用 Windows 筛选平台 (WFP) API 对象类型。
会话
WFP API 是面向会话的,大多数函数调用是在会话上下文中进行的。 通过调用 FwpmEngineOpen0创建新的客户端会话。 当客户端调用 FwpmEngineClose0 或客户端进程终止时,会话将结束。 当会话被销毁时,无论是出于目的还是由 RPC 运行,基本筛选引擎(BFE)首先中止任何现有事务。
创建新会话时,调用方可以通过将 FWPM_SESSION_FLAG_DYNAMIC 标志传递给 FwpmEngineOpen0来创建动态会话。 在动态会话期间添加的任何对象都会在会话结束时自动删除。
交易
WFP API 是事务性的,大多数函数调用是在事务的上下文中进行的。 调用方可以使用 FwpmTransactionBegin0、FwpmTransactionCommit0和 FwpmTransactionAbort0 显式控制事务。 但是,如果在显式事务之外进行函数调用,则会在隐式事务中执行该调用。 如果事务正在进行中,则会话终止时会自动中止事务。 隐式事务永远不会强行中止。
事务为只读或读/写,并强制实施严格的原子一致性隔离持久(ACID) 语义。
每个客户端会话一次只能有一个事务正在进行。 如果调用方在提交或中止第一个事务之前尝试开始第二个事务,BFE 将返回错误。
如果在事务过程中作失败,则不会影响事务的总体状态。 例如,假设客户端开始事务,并在第四次调用失败前三次成功调用 FwpmFilterAdd0。 客户端现在可以选择:
- 中止事务,在这种情况下,不会添加任何筛选器。
- 提交事务,在这种情况下,将添加前三个筛选器。
- 继续执行更多作,包括可能重试失败的 FwpmFilterAdd0。
启动事务时,BFE 将等待会话的 txnWaitTimeoutInMSec 过期以获取锁。 如果未在此时间内获取锁,则锁定获取(并且 FwpmTransactionBegin0 调用)将失败。 这可以防止客户端无限期地无法响应。 如果客户端未指定锁定超时,则默认为 15 秒。
每个事务也有一个锁定超时。 这是它可以拥有锁的最大时间。 如果所有者在此时间内未释放锁,则事务将被强行中止,导致锁被释放。 锁超时不可配置。 对于内核模式调用方,对于用户模式调用方,这是无限的。 如果事务被强行中止,则在该事务中进行的下一次调用将失败,并 FWP_E_TXN_ABORTED。
对象生存期
对象可以有四个可能的生存期之一:
- 动态 - 仅当使用动态会话句柄添加对象时,对象才是动态的。 动态对象在删除或拥有会话终止之前保持活动状态。
- 静态 — 对象默认为静态对象。 静态对象在删除、BFE 停止或系统关闭之前保持活动状态。
- 持久性 — 持久对象是通过将适当的 FWPM_*_FLAG_PERSISTENT 标志传递给 Fwpm*Add0 函数来创建的。 持久对象一直存在,直到删除它们。
- 内置 - 内置对象由 BFE 预定义,不能添加或删除。 他们永远活着。
内核模式层中的筛选器可以通过将相应的标志传递给 FwpmFilterAdd0,将内核模式层中的筛选器标记为启动时间筛选器。 启动时筛选器会在 TCP/IP 驱动程序启动时添加到系统,并在 BFE 完成初始化时删除。 在 BFE 启动时添加持久性对象。
在许多情况下,如果禁用了提供程序,则策略提供程序可能不希望强制实施其持久策略。 添加提供程序时,调用方可以指定可选的 Windows 服务名称。 添加持久性对象时,调用方可以选择指定“拥有”该对象的提供程序。 在服务启动时,如果 BFE 未与提供程序关联,或者关联的提供程序没有 Windows 服务名称,或者关联的 Windows 服务设置为自动启动,则仅向系统添加永久性对象。
对象关联
某些对象具有对其他对象的引用。 例如,筛选器始终引用一个层,并且可以引用标注和提供程序上下文。 对象不能引用可能具有较短生存期的对象。 因此,动态对象不能引用不同会话中的动态对象。 静态对象不能引用动态对象。 永久性对象不能引用其他提供程序拥有的动态对象、静态对象或永久性对象。
必须先删除引用该对象的所有对象,否则无法删除该对象。
LUID 和 GUID
所有用户模式 WFP API 对象(FWPM)均由全局唯一标识符(GUID)标识,并通过其 GUID引用其他对象。 GUID 仅在对象类型中是唯一的。 例如,筛选器和提供程序上下文可以具有相同 GUID,但两个筛选器不能。 添加新对象时,调用方可以分配对象的 GUID 或将其保留为零初始化,并允许 BFE 分配 GUID。
所有内核模式 WFP API 对象(FWPS)都由本地唯一标识符(LUID)标识,并按 LUID 引用其他对象。 从 GUID 切换到 LUID 使 WFP 能够节省非分页池并优化运行时处理。 LUID 的宽度取决于对象类型和范围,从 UINT16 到 UINT64。 LUID始终由 BFE 分配。