设为首页 加入收藏

TOP

用VC开发Win2000/XP下的防火墙(二)
2012-11-04 15:16:27 来源: 作者: 【 】 浏览:344
Tags:开发 Win2000/XP 防火墙
  注册过滤函数

  在上面的代码中,你已经看到了SetFilterFunction(..)函数。我在IP Filter Driver中执行这个函数来注册过滤函数,步骤如下:

  1) 首先,我们必须得到IP Filter Driver的指针,这要求驱动已经安装并执行。为了保证IP Filter Driver已经安装并执行,在我的用户程序中,在加载本驱动前加载并启动IP Filter Driver。

  2) 第二步,我们必须建立用IOCTL_PF_SET_EXTENSION_POINTER作为控制代码的IRP。我们必须传递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");

//首先我们要得到IpFilterDriver Device的指针
RtlInitUnicodeString(&filterName, DD_IPFLTRDRVR_DEVICE_NAME);
status = IoGetDeviceObjectPointer(&filterName,STANDARD_RIGHTS_ALL,
&ipFileObject, &ipDeviceObject);

if(NT_SUCCESS(status))
{
//用过滤函数作为参数初始化PF_SET_EXTENSION_HOOK_INFO结构
filterData.ExtensionPointer = filterFunction;

//我们需要初始化事件,用于在完成工作后通知我们
KeInitializeEvent(&event, NotificationEvent, FALSE);

//创建用于设立过滤函数的IRP
irp = IoBuildDeviceIoControlRequest(IOCTL_PF_SET_EXTENSION_POINTER,
ipDeviceObject,
if(irp != NULL)
{
// 发送 IRP
status = IoCallDriver(ipDeviceObject, irp);

// 然后我们等待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
{
//如果不能分配空间,返回相应的错误代码
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 Driver 已经完成了IRP处理。

  过滤函数

  我们已经知道了如何开发驱动并安装过滤函数,但还不知道该过滤函数中的任何东西。当主机接收或发送一个数据包,该过滤函数总会被调用,系统会根据函数的返回值决定如何处理这个数据包。

  函数的原型是这样的:

typedef PF_FORWARD_ACTION
(*PacketFilterExtensionPtr)(
// Ip数据包的包头
IN unsigned char *PacketHeader,
// 不包括头的数据包
IN unsigned char *Packet,
// 包长度。不包括IP头的长度
IN unsigned int PacketLength,
// 接收数据的接口适配器编号
IN unsigned int RecvInterfaceIndex,
// 发送数据的接口适配器编号
IN unsigned int SendInterfaceIndex,
//接收数据包的适配器IP地址
IN IPAddr RecvLinkNextHop,
//发送数据包的适配器IP地址
IN IPAddr SendLinkNextHop
);

  PF_FORWARD_ACTION 是枚举类型,可能的值有:

  PF_FORWARD 指示IP filter Driver立即向IP栈传递数据。对于本地数据包,IP向上送入栈。如果目标是另外的机器并且允许路由,将通过IP路由发送。

  PF_DROP 指示IP filter Driver丢弃IP包。

  PF_PASS 指示IP filter Driver去过滤该数据包,IP filter Driver如果处理该数据包取决于包过滤API的设置。过滤钩子返回pass的回应,表明它没有处理该数据包而让IP filter Driver去过滤该数据包。

  虽然DDK文档只包含了这三个值,如果你查看pfhook.h(Filter-Hook Driver需要的头文件)你可以发现还有一个PF_ICMP_ON_DROP,我猜这个值是用于对ICMP包进行丢弃。

  在过滤函数的定义中,传递进来指向数据包头的指针。因此,你可以修改数据头然后发送。这对于进行NAT转换是非常有用的,你可以修改数据包的目标地址,选择IP路由。

  在我的实现里,过滤函数根据用户程序的要求将每个包与规则列表进行比较,这个列表是连接列表,是在运行期间用START_IP_HOOK 的IOCTL创建的。在代码里可以看到这些。

  源代码

  在第一个版本中我只包含了简单的示例,由于许多朋友要求我帮他们开发实际应用,我完善了这个例子。新的示例是数据包的过滤程序,在这个新程序里你可以像商业防火墙一样添加你的过滤规则。

  第一个版本中,应用程序由两部分组成:

  (一)用户应用程序:这是管理过滤规则的MFC应用程序。程序发送规则给驱动并决定何时启动过滤,有三个步骤:

  1) 定义所需的规则。可以通过添加、删除定制规则。

  2) 安装规则。定义好规则后,点install按钮将他们发送给驱动

  3) 启动过滤。你可以单击start按钮启动过滤

  (二)Filter-Hook Driver: 根据从用户应用程序中接收到的过滤规则对数据包进行过滤。 Filter-Hook Driver必须与用户应用程序在相同的目录中。

  为什么使用该方法开发防火墙

  在Windows中这不是开发防火墙的唯一方法,其它的有诸如 NDIS防火墙,TDI防火墙,Winsock分层防火墙,包过滤API,...因此我将说明Filter-Hook Driver的优缺点使你在以后开发防火墙时决定是否采用这种驱动。

  1) 这种方法所拥有的弹性可以使你过滤所有IP层(或以上)的通讯。但你不能过滤更低层的头部数据,例如:你不能过滤以太帧数据。你需要用NDIS过滤器来做,虽然开发困难但弹性更大。

  2) 这是一种简单的方法。安装防火墙和执行过滤功能非常简单。但包过滤API(Packet Filtering API)更加容易使用,尽管它缺少弹性,例如你不能处理包的内容,你不能用包过滤API修改内容。

  结论:

  Filter-Hook Driver不是最好但也不坏。但为什么商业产品中并不使用它呢?

  答案是简单的:尽管这种驱动并不糟糕但却有巨大的缺点:像我刚才所说的,每次只能有一个过滤函数可以安装。我们开发了强大的防火墙,它可以被成千上万个用户下载,如果其它应用程序已经使用了过滤器(安装了过滤函数)那么我们的程序将不会正常工作。

  这种方法的另外一个缺点是不被微软官方明文支持。虽然DDK文档上说你可以在过滤函数中处理包的内容, 但事实并非如此。你可以在接收数据包的时候处理包的内容,但在发送包的时候你仅能读IP、TCP、UDP或ICMP数据包头。我不知道这是为什么....

  微软介绍在Windows XP中另外一种驱动没有这样的限制,那就是firewall hook driver。但微软不推荐使用它,因为"it ran too high in the network stack"。或许这种驱动在以后的WINDOWS版本中会消失。

  结束:

  好的,我知道这不是开发防火墙的最好的方法(我刚才已经提及了它巨大的缺点),但我想这对于在研究这个或对这个有所兴趣的人们是一个好的开始。希望你能够读明白,并开发出一款强大的防火墙。




首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇利用Visual C++设计真彩色工具条 下一篇用VC++设计一个可编辑的表格控件

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: