对象管理

本部分介绍如何正确使用 Windows 筛选平台 (WFP) API 对象类型。

会话

WFP API 面向会话,大多数函数调用是在会话上下文中进行的。 通过调用 FwpmEngineOpen0 创建新的客户端会话。 当客户端调用 FwpmEngineClose0 或客户端进程终止时,会话结束。 当会话被故意或 RPC 破坏时,基本筛选引擎 (BFE) 首先中止任何现有事务。

创建新会话时,调用方可以通过将 FWPM_SESSION_FLAG_DYNAMIC 标志传递给 FwpmEngineOpen0 来创建动态会话。 在动态会话期间添加的任何对象将在会话结束时自动删除。

事务

WFP API 是事务性的,大多数函数调用是在事务的上下文中进行的。 调用方可以使用 FwpmTransactionBegin0FwpmTransactionCommit0FwpmTransactionAbort0 显式控制事务。 但是,如果函数调用是在显式事务外部进行的,它将在隐式事务中执行。 如果事务正在进行中,则会话终止时会自动中止。 从不强制中止隐式事务。

事务可以是只读的,也可以是读/写的,并强制实施严格的原子一致性隔离持久 (ACID) 语义。

每个客户端会话一次只能有一个正在进行的事务。 如果调用方尝试在提交或中止第一个事务之前启动第二个事务,BFE 将返回错误。

如果操作在事务过程中失败,则不会影响事务的整体状态。 例如,假设客户端启动一个事务,并在第四次调用失败之前成功调用 FwpmFilterAdd0 三次。 客户端现在可以选择:

  • 中止事务,在这种情况下,不会添加任何筛选器。
  • 提交事务,在这种情况下,将添加前三个筛选器。
  • 继续执行更多操作,包括可能重试失败的 FwpmFilterAdd0

启动事务时,BFE 将等到会话的 txnWaitTimeoutInMSec 过期才能获取锁。 如果在此时间内未获取锁,则锁获取 (并且 FwpmTransactionBegin0 调用) 将失败。 这可以防止客户端无限期地无法响应。 如果客户端未指定锁超时,则默认为 15 秒。

每个事务还有一个锁超时。 这是它可以拥有锁的最长时间。 如果所有者在此时间内未释放锁,则会强制中止事务,从而导致释放锁。 锁超时不可配置。 对于内核模式调用方,它是无限的,对于用户模式调用方为 1 小时。 如果某个事务被强行中止,在该事务中进行的下一次调用将失败 并FWP_E_TXN_ABORTED

对象生存期

对象可以有四个可能的生存期之一:

  • 动态 - 仅当使用动态会话句柄添加对象时,该对象才为动态对象。 动态对象一直存在,直到它们被删除或拥有的会话终止。
  • 静态 - 默认情况下,对象是静态的。 静态对象在删除、BFE 停止或系统关闭之前一直存在。
  • 持久 — 持久对象是通过将相应的 FWPM_*_FLAG_PERSISTENT 标志传递给 Fwpm*Add0 函数来创建的。 永久性对象一直存在,直到它们被删除。
  • 内置 - 内置对象由 BFE 预定义,不能添加或删除。 他们永远活着。

内核模式层中的筛选器可以通过将相应的标志传递给 FwpmFilterAdd0 来标记为启动时筛选器。 启动时筛选器会在 TCP/IP 驱动程序启动时添加到系统,并在 BFE 完成初始化时删除。 在 BFE 启动时添加永久性对象。

在许多情况下,如果禁用了策略提供程序,则策略提供程序可能不希望强制执行其永久性策略。 添加提供程序时,调用方可以指定可选的 Windows 服务名称。 添加永久性对象时,调用方可以选择指定“拥有”该对象的提供程序。 在服务启动时,如果永久性对象未与提供程序关联,或者关联的提供程序没有 Windows 服务名称,或者关联的 Windows 服务设置为自动启动,则 BFE 只会将永久性对象添加到系统。

对象关联

某些对象具有对其他对象的引用。 例如,筛选器始终引用层,并可能引用标注和提供程序上下文。 对象不能引用可能具有较短生存期的对象。 因此,动态对象不能引用不同会话中的动态对象。 静态对象不能引用动态对象。 永久性对象不能引用动态对象、静态对象或由其他提供程序拥有的持久对象。

必须先删除引用该对象的所有对象,否则无法删除该对象。

LUID 和 GUID

FWPM) (所有用户模式 WFP API 对象均由全局唯一标识符 (GUID) 标识,并通过 其 GUID引用其他对象。 GUID 只需在对象类型中是唯一的。 例如,筛选器和提供程序上下文可以具有相同的 GUID,但两个筛选器不能。 添加新对象时,调用方可以分配对象的 GUID 或将其保留为零初始化,并让 BFE 分配 GUID

FWPS) (所有内核模式 WFP API 对象均由本地唯一标识符标识 (LUID) ,并通过其 LUID 引用其他对象。 从 GUID 切换到 LUID 使 WFP 能够节省非分页池并优化运行时处理。 LUID 的宽度取决于对象类型和范围(从 UINT16UINT64)。 LUID始终由 BFE 分配。