WFP防火墙在应用层的增删过滤器操作

WFP防火墙的作用

WFP防火墙是在Vista/Win2008之后的操作系统中才引入的一套流量管控平台。提供一套API接口供开发人员调用。应用层和驱动层都有不同的模块可以调用。用于取代之前的LSP过滤器、TDI过滤器、NDIS过滤器等。通过WFP API,可以实现防火墙、网络管控工具等流量管控服务。

使用WFP防火墙时注意的事项

  • WFP防火墙仅在Vista/Win 2008以后的系统中方可生效。
  • 在Vista/Win 2008中,过滤器的添加不支持"或"策略。如果需求中包含对个IP段、多个端口号、多个协议或多个进程同时存在时,在Vista/Win2008中,需要依次进行较为复杂的交叉匹配,依次添加。这一点需要注意。只有在Win7/Win2008 R2系统中,WFP防火墙才能直接添加策略运行。

基本概念以及决策逻辑

  • Layer(层):层是过滤器的容器,其功能是将过滤器组织成为集合,由层ID决定过滤器生效的位置。每一个层里面都包含一套内置的子层,用户可以添加自定义的子层。
  • SubLayer(子层):过滤器的容器,在对应的层中生效。
  • Filter(过滤器):过滤器是对出/入数据包进行匹配的规则。过滤器负责告诉过滤引擎如何处理数据包。添加过滤器时,使用FWPM_FILTER0结构体中的flags参数,可以指定过滤器的生效时间。

Layer(层)的过滤决策策略:

  1. 按照权重由高到低的顺序对每个子层进行决策匹配
  2. 即使有更高优先级的子层决定阻塞流量,下方的子层也会依次得到评估的机会。所以,每个子层都可以匹配到通过当前层的所有数据包
  3. 如果有一个子层明确返回阻断,当前层的决策即为阻断。(这里只谈应用层的决策策略,在Callout驱动层中,返回阻断,依然会被其它策略所修改,放在以后讨论。)

SubLayer(子层)的过滤决策策略:

  1. 按照权重从高到底的顺序对每个过滤器进行匹配
  2. 在匹配的过程中,如果有过滤器明确返回了"Permit"或"Block",则马上中断匹配,权重更低的过滤器不会收到数据包的信息。如果所有过滤器都返回"Continue",则会一直匹配到列表耗尽。
  3. 最后一个执行匹配的过滤器返回值,即为当前子层最终的过滤决策。

常用的随手便签

netsh wfp show state

该命令可以打印系统中当前存活的WFP防火墙层、子层、过滤器等。是在调试的过程中最实用的命令,也许没有之一。

调用流程

打开与关闭WFP防火墙

打开防火墙句柄

DWORD FwpmEngineOpen0( 
                    const wchar_t *serverName, 
                    UINT32 authnService, 
                    SEC_WINNT_AUTH_IDENTITY_W *authIdentity, 
                    const FWPM_SESSION0 *session, 
                    HANDLE *engineHandle 
                    );
  • 输入参数
    • serverName:必须为空。
    • authnService:身份验证方式,可选为RPC_C_AUTHN_WINNT和RPC_C_AUTHN_DEFAULT。
    • authIdentity:身份验证和授权凭证,可以为NULL。
    • session:会话指针,不使用的话可以为NULL。
    • engineHandle:用于输出防火墙引擎句柄,其它对防火墙操作的函数大都依赖此句柄。
  • 输出参数
    • ERROR_SUCCESS为成功,其它参考错误码

关闭防火墙句柄

DWORD FwpmEngineClose0( 
                        HANDLE engineHandle 
                        );
  • 输入参数
    • engineHandle:防火墙引擎句柄,由FwpmEngineOpen0参数返回
  • 输出参数
    • ERROR_SUCCESS为成功,其它参考错误码

枚举当前所有层

创建层枚举句柄

DWORD FwpmLayerCreateEnumHandle0( 
                HANDLE engineHandle, 
                const FWPM_LAYER_ENUM_TEMPLATE0 *enumTemplate,
                HANDLE *enumHandle 
        );
  • 输入参数
    • engineHandle:引擎句柄,由FwpmEngineOpen0创建。
    • enumTemplate:枚举参数,实际上内容保留使用,可以为NULL。
    • enumHandle:输出参数,用于传出枚举句柄
  • 输出参数
    • ERROR_SUCCESS为成功,其它参考错误码

执行枚举操作

DWORD FwpmLayerEnum0( 
                    HANDLE engineHandle, 
                    HANDLE enumHandle, 
                    UINT32 numEntriesRequested, 
                    FWPM_LAYER0 ***entries, 
                    UINT32 *numEntriesReturned 
        );
  • 输入参数
    • engineHandle:引擎句柄
    • enumHandle:枚举句柄,FwpmLayerCreateEnumHandle0创建
    • numEntriesRequested:请求的数目
    • entries:用于返回的层参数数组,需要FwpmFreeMemory0释放(这里需要注意,该参数定义为:FWPM_LAYER0** p=NULL,释放使用FwpmFreeMemory0((void**)&p))
    • numEntriesReturned:本次返回的结构体数目
  • 输出参数
    • ERROR_SUCCESS为成功

销毁层枚举句柄

DWORD FwpmLayerDestroyEnumHandle0( 
                        HANDLE engineHandle, 
                        HANDLE enumHandle 
            );
  • 输入参数
    • engineHandle:引擎句柄,由FwpmEngineOpen0创建
    • enumHandle:枚举句柄,由FwpmLayerCreateEnumHandle0创建
  • 输出参数
    • ERROR_SUCCESS为成功,其它参考错误码

参考代码

    #define SESSION_LAYER    L"session_layer";
    GUID SESSION_GUID = {
    0x2ec66da9, 0x2ae4, 0x4f83, {
    0x81, 0xc7, 0x34, 0x5d, 0x19, 
0x6a, 0xe3, 0xd7 } };

int main()
{
   
    HANDLE engineHandle = NULL;
    DWORD result = ERROR_SUCCESS;
    FWPM_SESSION0 fwpmSession;
    memset(&fwpmSession, 0, sizeof(FWPM_SESSION0));
    fwpmSession.flags = FWPM_SESSION_FLAG_DYNAMIC;

    result = FwpmEngineOpen0(NULL, RPC_C_AUTHN_DEFAULT, NULL, &fwpmSession, 
&engineHandle);
    if (result != ERROR_SUCCESS)
    {
   
        printf("[%s]FwpmEngineOpen0 failed;Return value:%d.\n", __FUNCTION__, 
result);
        return 0;
    }

    HANDLE enumHandle = NULL;
    result = FwpmLayerCreateEnumHandle0(engineHandle, NULL, &enumHandle);
    if (result != ERROR_SUCCESS)
    {
   
        printf("[%s]FwpmFilterCreateEnumHandle0, Return value:%d\n", __FUNCTION__, 
result);
        FwpmEngineClose0(engineHandle);
        return 0;
    }
    
    UINT32 numEntriesReturned = 0;
    do
    {
   
        FWPM_LAYER0** fwpmLayerList = NULL;
        numEntriesReturned = 0;
        result = FwpmLayerEnum0(engineHandle, enumHandle, 1, &fwpmLayerList, 
&numEntriesReturned);
        if (result != ERROR_SUCCESS || numEntriesReturned == 0)
        {
   
            break;
        }

        std::string strLayerName = boost::locale::conv::from_utf(fwpmLayerList[0]->displayData.name, "GBK");
        printf("layer name:%s\n"
  • 8
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值