总体概述
上篇文章在简介windows驱动开发时以及到的WFP可应用层编程,从而完成防火墙功能。本文从WFP应用编程流程和API介绍开始,最后给出具体简单编码样例,带入WFP的应用编码大门。
WFP和应用API
Windows Filtering Platform (WFP) 是一个网络流量处理平台,旨在取代Windows XP 和Windows Server 2003 网络流量过滤接口。 WFP 由一组网络堆栈挂钩和一个协调网络堆栈交互的过滤引擎组成。WFP提供了应用层API和驱动层API。
编码主要流程为:
1.建一个WFP会话句柄(会话设置FWPM_SESSION_FLAG_DYNAMIC保障变量生命结束销毁注册的条件)
HANDLE engineHandle = NULL;
FWPM_SESSION session = { 0 };
session.flags = FWPM_SESSION_FLAG_DYNAMIC;
FwpmEngineOpen(NULL,RPC_C_AUTHN_WINNT,NULL,&session,&engineHandle);
2.开始事务(可选,默认会隐性开启)
FwpmTransactionBegin(engineHandle, 0);
3.设置过滤条件和注册
FWPM_FILTER_CONDITION condition;
condition.fieldKey = FWPM_CONDITION_IP_PROTOCOL;
condition.matchType = FWP_MATCH_EQUAL;
condition.conditionValue.type = FWP_UINT8;
condition.conditionValue.uint8 = IPPROTO_ICMP;
filter.layerKey = FWPM_LAYER_INBOUND_TRANSPORT_V4;
filter.action.type = FWP_ACTION_BLOCK;
filter.filterCondition = &condition;
filter.numFilterConditions = 1;
filter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL;
filter.weight.type = FWP_EMPTY;
FwpmFilterAdd(engineHandle, &filter, NULL, NULL);
4.提交事务(可选,默认会隐性开启)
FwpmTransactionCommit(engineHandle);
以上完成便可生产一条防火墙规则:限制外部ping本机。不过由于是动态会话,session变量一旦销毁,对应规则就失效。可以不设置FWPM_SESSION_FLAG_DYNAMIC,但是需要手动删除规则或重启系统才导致规则失效。
完整代码示例
#include <windows.h>
#include <fwpmu.h>
#include <stdio.h>
#pragma comment(lib, "fwpuclnt.lib")
#pragma comment(lib,"ws2_32.lib")
#define CHECK_ERROR(result, msg) \
if (result != ERROR_SUCCESS) { \
wchar_t error_str[256]; \
error_str[0] = L'\0'; \
DWORD errCode = GetLastError(); \
::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errCode, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), error_str, sizeof(error_str) / sizeof(wchar_t), NULL); \
printf("%s failed with error: (%u)(%ls)\n", msg, result, error_str); \
goto cleanup; \
}
int addWfpFilter()
{
DWORD ret = -1;
DWORD result;
HANDLE engineHandle = NULL;
FWPM_SESSION session = { 0 };
session.flags = FWPM_SESSION_FLAG_DYNAMIC;
FWPM_FILTER filter = { 0 };
FWPM_FILTER_CONDITION condition;
const wchar_t* constName = L"Block ICMP from specific IP";
wchar_t* dstName = NULL;
const wchar_t* constDesc = L"Block ping requests from a specific IP address";
wchar_t* dstDesc = NULL;
result = FwpmEngineOpen(
NULL,
RPC_C_AUTHN_WINNT,
NULL,
&session,
&engineHandle
);
CHECK_ERROR(result, "FwpmEngineOpen");
result = FwpmTransactionBegin(engineHandle, 0);
CHECK_ERROR(result, "FwpmTransactionBegin");
condition.fieldKey = FWPM_CONDITION_IP_PROTOCOL;
condition.matchType = FWP_MATCH_EQUAL;
condition.conditionValue.type = FWP_UINT8;
condition.conditionValue.uint8 = IPPROTO_ICMP;
filter.layerKey = FWPM_LAYER_INBOUND_TRANSPORT_V4;
dstName = new wchar_t[wcslen(constName) + 1];
wcscpy_s(dstName, wcslen(constName) + 1, constName);
filter.displayData.name = dstName;
dstDesc = new wchar_t[wcslen(constDesc) + 1];
wcscpy_s(dstDesc, wcslen(constDesc) + 1, constDesc);
filter.displayData.description = dstDesc;
filter.action.type = FWP_ACTION_BLOCK;
filter.filterCondition = &condition;
filter.numFilterConditions = 1;
filter.subLayerKey = FWPM_SUBLAYER_UNIVERSAL;
filter.weight.type = FWP_EMPTY;
result = FwpmFilterAdd(engineHandle, &filter, NULL, NULL);
CHECK_ERROR(result, "FwpmFilterAdd");
result = FwpmTransactionCommit(engineHandle);
CHECK_ERROR(result, "FwpmTransactionCommit");
printf("Filter added successfully.\n");
ret = 0;
printf("add WFP successfully...");
while (true)
{
Sleep(1000);
}
cleanup:
if (engineHandle != NULL) {
FwpmEngineClose(engineHandle);
}
return ret;
}
int main()
{
DWORD ret = addWfpFilter();
if (ret)
{
printf("add WFP failed, exit.");
return ret;
}
return 0;
}
参考文献
[1] 微软#About Windows Filtering Platform#
[2] 微软#windows/win32/api/fwpmtypes#