一、WFP简介
Windows过滤平台(Windows Filtering Platform, WFP)是为网络数据包过滤提供的一套框架,其包含相应的API和服务。通过WFP框架,我们可以实现防火墙、入侵检测系统、网络监控等软件。
WFP是windows推出来的新一代对网络数据进行操作的框架,用于取代TDI框架,基于WFP编程相对更加简单(我没接触过TDI…),WFP适用于windows 2000和 Windows vista以及其以后的系统;
WFP的优劣点总结可以参考一下链接:
http://www.komodia.com/wfp_hl
二、WFP框架
1. WFP框架与系统的交互方式
首先看WFP框架与系统的交互方式,以及其工作方式的图
WFP框架的主要部分是图中的Filte Engine(过滤引擎),该过滤引擎与操作系统的Network Stack进行交互和操作,能够对系统网络栈中的数据进行处理,实现数据的过滤等功能。
过滤引擎内部能够和七层网络模型中的每一层进行交互,实现在不同层对网络数据进行处理。
图中右边的Callout就是具体对网络数据进行操作部分,使用WFP提供的API,我们可以定义自己的Callout,并向Filter Engine注册。每个Callout可以理解为一个对网络数据包处理的集合,其中包含其处于的网络层、过滤函数(执行需要处理哪些数据包)、处理方法等等。
2. WFP框架内部结构
WFP的主要内部框架图如下图所示:
图中上半部分为用户态,下半部分为内核态。
WFP主要分为两大层次模块:用户态基础过滤引擎(BFE)、内核态过滤引擎(KM Filtering Engine)。实际工作的是内核态的过滤引擎,用户可以在用户层通过其提供的API与BFE交互(BFE会与KM FE交互),或直接在内核层KM FE交互。
三、与WFP开发相关的主要概念
1. 过滤引擎
WFP的过滤引擎包括BFE(用户态)和KM FE(内核态),其与系统的网络栈进行交互,我们可以向过滤引擎注册过滤规则或对数据的操作,过滤引擎最终完成相应的操作。
2. 垫片
这个概念主要是有关WFP的运行原理,和WFP开发目前没有太大关联。
垫片是一种特殊的内核模块,被安插在系统的网络协议栈的不同层中,将不同层的数据传给WFP过滤引擎,并将过滤引擎的反馈操作传回到网络协议栈中。
3. Callout
Callout是WFP中非常重要的数据结构,其中包括对数据的具体操作函数,以及一个唯一标识符GUID,我们主要是通过向过滤引擎注册自己定义的Callout来实现对数据的操作,后面的具体开发会详细介绍。
4. 分层
系统的网络协议栈是分为多层的,WFP的过滤引擎也是分开为多层(Layer),我们在注册自己的Callout时需要制定网络的具体哪一层,对该层的数据进行操作。
5. 子层
在前面的WFP分层的基础上,WFP提供了子层的概率。分层是针对网络协议栈的分层,是固定的,在这个分层的基础上,WFP在每一层上进一步提供了子层。在每一个网络协议栈的层次上,开发者可以定义多个子层,并赋予其权重值,网路数据会按照子层的权重值顺序执行子层的操作。
6. 过滤器
WFP提供了过滤器(Filter)的概率,其实现对数据的过滤。例如我们注册了一个对网络数据操作的Callout,但是我们只想对目标IP地址为A的数据包进行操作,这时就可以通过定义和注册相应的Filter,过滤出目标地址为A的数据包,Callout则只会对经过过滤后的数据包进行处理。
四、WFP开发步骤
这里仅介绍在内核层的操作,微软提供的例子里有内核层以及用户层的例子;
1. 开启WFP过滤引擎,创建句柄
调用WfpmEngineOpen()开启过滤引擎。
2. 开启过滤设置
调用FwpmTracsactionBegin()。
3. 注册Callout
(a) 定义FWPS_CALLOUT结构的变量
该结构中主要包含一下3个函数:
(1) classifyFn
当一个过滤器关联了Callout,并且规则被命中时(过滤器内的条件全部成立),过滤引擎会调用相应Callout中的classifyFn函数。开发者可以在classifyFn函数内获取网络数据包的相关信息,具体信息取决于过滤器所在分层,classifyFn也可以设置对网络数据包的“允许/拦截”操作。
与classifyFn相关的参数非常多,这里就不详细介绍,找个例子看一下或者看一下官网的说明就行。这里就说一下context这个参数。因为Callout中的classifyFn、notifyFn和flowDeleteFn这3个函数的调用顺序和环境不一样,它们各自能获取到的信息类型也不一样,例如与数据包相关的进程信息就只能在notifyFn中获取,这样的话如果我想在notifyFn中获取某些信息,将其传入到classifyFn中,对其操作进行一些配置或指导,这时就需要用到context, notifyFn将获取到的信息存储到context中,然后classifyFn通过其context取出相应的数据即可。
(2) notifyFn
当过滤器被添加到过滤引擎中或者从过滤引擎中移除时,WFP会调用这个过滤器对应的Callout的notifyFn函数。notifyFn函数中可以获取到与网络数据相关的一些信息,例如进程信息等。也可以在notifyFn中进行一些初始化的操作。
(3) flowDeleteFn
当一个网络数据要被终止时,WFP会调用flowDeleteFn函数。
(b) 定义一个GUID,唯一标识这个Callout
(c) 调用FwpsCalloutRegister()函数注册该FWPS_CALLOUT变量。
4. 添加相应的Callout到WFP的过滤引擎
前面一步是想WFP的过滤引擎注册了Callout,这里需要将其添加到WFP的过滤引擎,通过前面的GUID唯一定位这个Callout。
5. 添加子层
调用FwpmSubLayerAdd向WFP添加子层,子层的权重值决定了数据在进过各个子层的顺序。
6. 添加Filter
定义FWPM_FILTER变量,调用FwpmFilterAdd函数添加该Filter。
7. 提交所有操作,使上面的操作生效。
调用FwpmTransactionCommit()函数提交上面的操作,使对数据的操作生效。
8. 销毁过滤引擎句柄
在不使用该句柄时,调用FwpmEngineClose()函数将其销毁。