分享
 
 
 

开发基于Windows2000/XP的防火墙

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

下载 DownLoadSource DownLoadFireWallApplication

介绍

如果你决定为Linux系统开发一个防火墙,你将会找到好多相关的信息及各式免费代码。但当人们想要

在Windows平台上开发防火墙时可就有点困难了,就那么可怜的一点点资料信息,至于免费代码,几乎是不

可能的。

所以我决定写这篇关于在Windows 2000/XP平台上开发一个简单功能的防火墙文章去帮助那些个对这方

面有兴趣的人。

背景

微软公司在它发布的Windows 2000 DDK中,已经包含了一个新的网络驱动类:Filter-Hook Driver。

用它你可以建立过滤所有通信的接口。

Filter-Hook Driver

正如我刚才所说的,Filter-Hook Driver是在微软的Windows 2000 DDK中被引入进来。但实际上它并

不是一个新的网络驱动类,它只是一个IP过滤功能的驱动。

事实上Filter-Hook Driver不是一个网络驱动类,它是属于核心驱模型。在这个Filter-Hook Driver

中我们只实现了一个回调函数,我们只是在Filter-Hook Driver中注册这个回调函数。当我们实现并注册

好回调函数后,IP过滤驱动就会在数据包到达和发送的时候调用它。

我们把实现步骤归纳为如下几步:

1、建立一个Filter-Hook Driver。在这里你必须建立一个核心模式驱动,你将任选名字,DOS名字以及其

它一些个属性,不一定是必须的,但我建议你这样做。

2、如果我们想安装过滤功能,首先我们必须得到一个IP过滤驱动的指针。这便是第二步。

3、我们已经得到了指针,现在我们能正确的安装我们的过滤功能函数。我们将发送一个特定的IPR,里面

将包括我们的过滤函数的指针。

4、过滤包!!!

5、当我们完成过滤后,我们必须注销过滤功能函数。我们可以注册一个空指针来替换我们的过滤函数指针

哦,就上面五个步骤,看起来似乎很简单,但是我如何生成一个核心模式驱动呢?如何得到IP过滤驱动的

指针呢?如何…………,稍等一下,我将会解释上面所有的步骤并列出源码例子。

建立核心模式驱动

Filter-Hook Driver是一个核心模式驱动,因此我们将要建立一个核心模式的驱动程序。但这篇文章

不是“教你在5分钟内如何开发核心驱动程序”的指南,所以我将假设读者已据有以上知识。

Filter-Hook驱动据有一个典型的核心驱动结构。

1、我们将为驱动程序建立一个典型的驱动入口(DriverEntry),为IRP设置标准分发例程(Dispatch, load,

unload, Create...),为方便与应用程序通讯建立一个符号连接。

2、标准分发例程将管理IRP。在你开使编写代码前,我建议你先建立IOCTL以便应用程序来操纵驱动。在我

的例子里,我实现了4个IOCTL编码:START_IP_HOOK(注册一个过滤功能函数),STOP_IP_HOOK(注销过滤功

能函数),ADD_FILTER(安装一个新的过滤规则),CLEAR_FILTER(清空所有过滤规则)

3、为了我们的驱动,我们必须实现一个或更多的过滤功能函数。

我建议你用一个程序来生成典型的核心驱动程序框架,因此你只须在里面填上你的功能代码既可,比

如我就用了 QuickSYS 来生成我的例子工程。

你将看到我自己产现的驱动结构,如下代码所示:

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,

IN PUNICODE_STRING RegistryPath)

{

//....

dprintf("DrvFltIp.SYS: entering DriverEntry\n");

//we have to create the device

RtlInitUnicodeString(&deviceNameUnicodeString, NT_DEVICE_NAME);

ntStatus = IoCreateDevice(DriverObject,

0,

&deviceNameUnicodeString,

FILE_DEVICE_DRVFLTIP,

0,

FALSE,

&deviceObject);

if ( NT_SUCCESS(ntStatus) )

{

// Create a symbolic link that Win32 apps can specify to gain access

// to this driver/device

RtlInitUnicodeString(&deviceLinkUnicodeString, DOS_DEVICE_NAME);

ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString,

&deviceNameUnicodeString);

//....

// Create dispatch points for device control, create, close.

DriverObject->MajorFunction[IRP_MJ_CREATE] =

DriverObject->MajorFunction[IRP_MJ_CLOSE] =

DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;

DriverObject->DriverUnload = DrvUnload;

}

if ( !NT_SUCCESS(ntStatus) )

{

dprintf("Error in initialization. Unloading...");

DrvUnload(DriverObject);

}

return ntStatus;

}

NTSTATUS DrvDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

{

// ....

switch (irpStack->MajorFunction)

{

case IRP_MJ_CREATE:

dprintf("DrvFltIp.SYS: IRP_MJ_CREATE\n");

break;

case IRP_MJ_CLOSE:

dprintf("DrvFltIp.SYS: IRP_MJ_CLOSE\n");

break;

case IRP_MJ_DEVICE_CONTROL:

dprintf("DrvFltIp.SYS: IRP_MJ_DEVICE_CONTROL\n");

ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

switch (ioControlCode)

{

// ioctl code to start filtering

case START_IP_HOOK:

{

SetFilterFunction(cbFilterFunction);

break;

}

// ioctl to stop filtering

case STOP_IP_HOOK:

{

SetFilterFunction(NULL);

break;

}

// ioctl to add a filter rule

case ADD_FILTER:

{

if(inputBufferLength == sizeof(IPFilter))

{

IPFilter *nf;

nf = (IPFilter *)ioBuffer;

AddFilterToList(nf);

}

break;

}

// ioctl to free filter rule list

case CLEAR_FILTER:

{

ClearFilterList();

break;

}

default:

Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;

dprintf("DrvFltIp.SYS: unknown IRP_MJ_DEVICE_CONTROL\n");

break;

}

break;

}

ntStatus = Irp->IoStatus.Status;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

// We never have pending operation so always return the status code.

return ntStatus;

}

VOID DrvUnload(IN PDRIVER_OBJECT DriverObject)

{

UNICODE_STRING deviceLinkUnicodeString;

dprintf("DrvFltIp.SYS: Unloading\n");

SetFilterFunction(NULL);

// Free any resources

ClearFilterList();

// Delete the symbolic link

RtlInitUnicodeString(&deviceLinkUnicodeString, DOS_DEVICE_NAME);

IoDeleteSymbolicLink(&deviceLinkUnicodeString);

// Delete the device object

IoDeleteDevice(DriverObject->DeviceObject);

}

我们已经完成驱动程序主体代码,接下来将是过滤钩子代码。

注册过滤功能函数

在上面的代码中,我们已经看到了调用SetFilterFunction(...)函数,现在我们将实现这个注册IP过

虑功能函数,他将分以下几步实现。

1、首先,我们必须得到一个IP过滤驱动的指针,那需要驱动已正确安装且已经运行起来。现在假设在加载

这个驱动之前我的用户应用程序将加载并起动IP过滤驱动。

2、我们必须建立一个特定的IRP包含IOCTL_PF_SET_EXTENSION_POINTER的控制码。我们还得必须传送参数

如PF_SET_EXTENSION_HOOK_INFO结构来包含过滤函数指针。如果你要卸载函数,你得采取同样的步骤传送

一个NULL指针来取代过滤函数。

3、传送刚建立的IRP到设备驱动程序。

这里关于驱动的大问题,就是一次只能安装一个过滤功能函数。因此如果其它应用程序已安装了一个,那

么你的将不能被安装上。

接下来的代码我将出示该函数。

NTSTATUS SetFilterFunction

(PacketFilterExtensionPtr filterFunction)

{

NTSTATUS status = STATUS_SUCCESS, waitStatus=STATUS_SUCCESS;

UNICODE_STRING filterName;

PDEVICE_OBJECT ipDeviceObject=NULL;

PFILE_OBJECT ipFileObject=NULL;

PF_SET_EXTENSION_HOOK_INFO filterData;

KEVENT event;

IO_STATUS_BLOCK ioStatus;

PIRP irp;

dprintf("Getting pointer to IpFilterDriver\n");

//first of all, we have to get a pointer to IpFilterDriver Device

RtlInitUnicodeString(&filterName, DD_IPFLTRDRVR_DEVICE_NAME);

status = IoGetDeviceObjectPointer(&filterName,STANDARD_RIGHTS_ALL,

&ipFileObject, &ipDeviceObject);

if(NT_SUCCESS(status))

{

//initialize the struct with functions parameters

filterData.ExtensionPointer = filterFunction;

//we need initialize the event used later by

//the IpFilterDriver to signal us

//when it finished its work

KeInitializeEvent(&event, NotificationEvent, FALSE);

//we build the irp needed to establish fitler function

irp = IoBuildDeviceIoControlRequest(IOCTL_PF_SET_EXTENSION_POINTER,

ipDeviceObject,

if(irp != NULL)

{

// we send the IRP

status = IoCallDriver(ipDeviceObject, irp);

//and finally, we wait for

//"acknowledge" of IpFilter Driver

if (status == STATUS_PENDING)

{

waitStatus = KeWaitForSingleObject(&event,

Executive, KernelMode, FALSE, NULL);

if (waitStatus != STATUS_SUCCESS )

dprintf("Error waiting for IpFilterDriver response.");

}

status = ioStatus.Status;

if(!NT_SUCCESS(status))

dprintf("Error, IO error with ipFilterDriver\n");

}

else

{

//if we cant allocate the space,

//we return the corresponding code error

status = STATUS_INSUFFICIENT_RESOURCES;

dprintf("Error building IpFilterDriver IRP\n");

}

if(ipFileObject != NULL)

ObDereferenceObject(ipFileObject);

ipFileObject = NULL;

ipDeviceObject = NULL;

}

else

dprintf("Error while getting the pointer\n");

return status;

}

当我们完成处理过滤功能函数后你能看到,我们必须引用文件对象来获取设备驱动指针。当IpFilter

驱动完成IRP处理时我使用了一个事件来通知。

过滤函数

我们明白了如何开发驱动以及如何安装过滤函数,但我们还不知道过滤函数呢。

早先我已经说过这个函数总是当传出或发送数据包时被调用。系统跟据它的返回值来决定如何处理数

据包。

下面是函数的申明

typedef PF_FORWARD_ACTION

(*PacketFilterExtensionPtr)(

// Ip Packet Header

IN unsigned char *PacketHeader,

// Packet. Don't include Header

IN unsigned char *Packet,

// Packet length. Don't Include length of ip header

IN unsigned int PacketLength,

// Index number for the interface adapter

//over which the packet arrived

IN unsigned int RecvInterfaceIndex,

// Index number for the interface adapter

//over which the packet will be transmitted

IN unsigned int SendInterfaceIndex,

//IP address for the interface

//adapter that received the packet

IN IPAddr RecvLinkNextHop,

//IP address for the interface adapter

//that will transmit the packet

IN IPAddr SendLinkNextHop

);

PF_FORWARD_ACTION是一个枚举类型

PF_FORWARD:指定IP过滤驱动立即将数据包返回到IP栈。对于送到本地的包,IP将被送到栈顶。如果

是要发送到其他机算机,IP包也将会被立即发送走。

PF_DROP:指定IP过滤驱动立即将该数据包从IP栈里丢弃掉。该IP数据包将会被丢失。

PF_PASS:指定IP过滤驱动过滤该包并返回响应结果到IP栈。IP过滤驱动如何处理该数据包取决于他对

包过滤API的设置。当过滤钩子发觉他不能处理该数据包就得交给IP过滤驱动去处理此包时就返回该参数。

虽然DDK的文只介绍了上面三个返回值,但当你查看pfhook.h文件时会发现还有另一个供返回的数值。

那就是PF_ICMP_NO_DROP。我猜想这个值与丢弃包相似并提供ICMP包错误信息。

正如你在过滤功能函数的定义中所看到的,包和他的包头都是以指针方式传递的。因此你可以修改包

头或内容然后再将其传送走。这在写比如NAT程序时是非常有用的。如果我们更改其目标地址,那么数据包

将向你所更改的方向传送。

在我的实现在,过滤功能函数会与规则链表中的每个过滤规则函数所定义的规则进行比对。这个规则

链表会在运行时收到START_IP_HOOK控制码时创建。这个你会在源码中看到它。

代码

在我的第一个版本中,我只实现了一个相对简单的版本,因此好多人都在询问我是否能帮助他们开发

一个更为实用的应用。所以我现在升级了一个相对复杂的版本。在这个新的例子中有一个小的包过滤应用

。在这个新的应用程序中,你可以加入你的一些通用防火墙的规则。

在第一个版本中,这个应用有两个部分组成。

用户应用程序:它是一个MFC应用程序来管理各种过滤规则。这个应用程序发送各种过滤规则到应用中

并决定何时开始起动过滤。过滤动作分三步

按照你的需要定一个过滤规则。发送添加或删除命令来增加或删除这个过滤规则。

安装规则。当你定义好一个过滤规则后,按下安装按扭来发送他到驱动中。

开始过滤。你只需要按下开始按扭就可以开始过滤了。

过滤驱动程序:驱动程序按照用户应用程序发来的过滤规则来过滤发送和收到的各数据包。

过滤钩子驱动程序必须和用户应用程序在同一目录中。

为什么要用这种方法来开发防火墙?

当然,它并不是Windows下开发防火墙的唯一方法,还有其它NDIS防火墙、TDI防火墙、WinSock层防火

墙、包过滤API等等从多方法。因此我将说明用过滤钩子驱动开发防火墙的一些优缺点。

基于过滤钩子方法来开发防火墙程序有较好的弹性。你可以在进入到IP栈前过滤所有的IP包。当然了

,你不能再过滤更底层的数的数据,例如网卡硬件帧。那么你需要写NDIS驱动去过滤它,那你将获得更好

的灵活性但也更难开发。

基于过滤钩子方法来开发防火墙程序不失为一个简单有效的方法。安装及实现防火墙只需几个简单的

过程。当然,包过滤API将更简单,但那样你将失去更多的灵活性,你再不能随意更改包内容了。

结论:过滤钩子驱动算不上开发防火墙的最好方法,但也不是最差的。那么为什么不能把它列为开发

商业软件的一部分呢?

回答是简单的,但这个驱动算不上最好的,但也不是最差的。我再次提及它只因为过滤钩子驱动只能

一次安装一个。我们可以开发一个更好的,它可以任意装载来为成百上千的应用程序过滤包并不会与其它

过滤程序相冲突。

在微软件的文档中,该方法还有另一个缺点。那就是虽然DDK文档说你可以对所有发送和收到的数据包

为所欲为但那并不是真的。你能任意更改所有收到的数据包,但只能对IP、TCP、UDP以及ICMP包头时行更

改。我也不知道那是为什么?

微软公司还为WindowsXP系统引入了另一个无限制的防火墙钩子驱动。它的装载非常的简单,但微软并

不建议你去用它来开发。因为它运行在网络栈的上层,太高了。可能这个驱动将会在下一版本的Windows中

消失。

结论

OK,所有的都讲完了。我知道这不是开发防火墙的最佳方法(我已经提及它的优缺点)。但我想这是为

所有对防火墙开发感性趣的朋友一个很好的起点,或是因为看了这篇文章对防火墙开发更感性趣了。

我希望你现已经有些明白了Filter-Hook Driver,并准备开发一个功能更为强大的防火墙了。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有