前言

作为本系列的最后一篇,将来聊一聊NDIS有关的话题。当然本文的话题也仅限于过滤。

NDIS 作为整套网络协议的最底层,过滤上有着得天独厚的“地理”优势,同样的也会给它带来麻烦。
在NDIS层做过滤,主要是为了嗅探或修改数据包,而不适合去做与进程直接打交道的应用,如防火墙等。

NDIS

00.png

NDIS全称是网络驱动接口规范,其分为三个层

  • NDIS 协议驱动
  • NDIS 中间层驱动 (NDIS过滤层驱动,在 NDIS 6.0 引入)
  • NDIS 小端口驱动

NDIS协议驱动与TDI传输器相接,TDI传输器通过调用NDIS库函数来构造一个NDIS Packet,再将其发送给NDIS小端口驱动。

查了多份资料,NDIS协议驱动与TDI传输器看起来是一个整体的两个部分,上半部分负责和TDI层沟通,下半部分负责和NDIS层沟通。

NDIS中间层驱动是一个特殊的驱动程序,对于其上层模拟成小端口驱动,对其下层又模拟成协议驱动。
它必须同时满足上下两套驱动程序所要求的编程接口,以实现透明化。通常可以用它实现多适配器时的负载均衡,或是流量嗅探。

NDIS小端口驱动则负责管理网卡硬件及为上层提供接口。其不属于一个真正意义上的Windows 驱动程序,既不使用 Windows IO 管理器规范,也不接收处理 IRP,而是使用了一套自己实现的规范。

NDIS过滤层驱动,也称为 NDIS过滤驱动,为了与传统意义上的过滤驱动做区分,本文统一译为NDIS过滤层驱动,其在 NDIS 6.0 引入,与中间层驱动的作用相当,但拥有更高的效率及更简单的接口。

NDIS过滤驱动现状

由于NDIS过滤驱动在安装时会断一下网,这对于某些软件及某些环境都是是致命的。

例如在网吧无盘环境下,常规的 NDIS过滤驱动就不能正常工作。

折中方案又有 NDIS HOOK 等,但是 NDIS HOOK 存在明显的兼容性及稳定性问题,适用性不高。

而日常开发中,对于协议驱动和小端口驱动的开发需求及相关资料都相对较少,通常都有较为成熟的解决方案。

如果是自己通过NDIS中间层实现过滤驱动还涉及组包等问题,相对复杂。

本文没有信心能把中间层讲清楚,要实现一个中间层过滤驱动,还需要协议驱动和小端口驱动的相关知识,

NDIS中间层与NDIS过滤层的抉择

到底是该基于传统中间层驱动来写还是该基于新版的过滤层驱动来写。

传统的中间层驱动兼容性会相对好一点,但是复杂性会高出很多,要写一个传统的中间驱动,既要注册为小端口驱动,又要注册为协议驱动。
而过滤层驱动,只需要注册为过滤层驱动即可,从实现上要比中间层驱动简单一些。

在当前的微软驱动开发示例中,已经找不到中间层驱动了。

出于篇幅考虑,本文就结合 filter 简单介绍一下过滤层驱动的编写方式及相关知识。

filter

NDIS过滤层驱动初始化与卸载

  1. 构造 NDIS_FILTER_DRIVER_CHARACTERISTICS 结构
  2. NdisFRegisterFilterDriver 注册为中间层驱动
  3. NdisRegisterDeviceEx 添加用于通信的设备对象
  4. NdisDeregisterDeviceEx
  5. NdisFDeregisterFilterDriver

在 NDIS_FILTER_DRIVER_CHARACTERISTICS 结构中又需要注册一组接口,正是通过这组接口来实现过滤。

一般来说,可以直接在 filter 的基础上进行二次开发,原本的 filter 中提供的接口是什么都不做的,需要由开发者挑选需要关注的接口自行实现。

中间一些关于状态和操作的内容我就跳过了。

在 NDIS_FILTER_DRIVER_CHARACTERISTICS 中,较为关注与数据包有关的接口:

  • FilterReturnNetBufferLists
  • FilterReceiveNetBufferLists
  • FilterSendNetBufferListsComplete
  • FilterSendNetBufferLists

数据解析

1.png

在 NDIS过滤层中,数据包以NET_BUFFER的形式存在,它是构成数据包的基本结构。

在每一个 NET_BUFFER 中拥有一个 MDL 链表。MDL 可以把数据缓冲区的地址映射到 NET_BUFFER 结构所指向的数据空间中。
由多个 NET_BUFFER 结构可以构成一个 NET_BUFFER_LIST。
在过滤层驱动中,就是依靠 NET_BUFFER_LIST 进行数据的发送与接收。

在获取数据包时,会用到一些相关的宏
1. NET_BUFFER_FIRST_MDL // 获取第一个 MDL
2. NET_BUFFER_DATA_OFFSET // 网络数据包内容偏移

1. NET_BUFFER_CURRENT_MDL // 获取当前 MDL
2. NET_BUFFER_CURRENT_MDL_OFFSET // 获取当前 MDL 偏移以获取 Mac 帧的首地址

*. NdisQueryMdl //可用于获取相关信息

发送请求过滤

2.png
接收请求的行为过滤,主要是对 FilterReceiveNetBufferLists 的 ReceiveFlags 参数进行处理。

接收请求过滤

3.png
发送请求的行为过滤与接收请求的处理流程类似。

其它

在传递接收请求的时候,需要区分同步异步情况。针对这两种情况选择不同的处理方式。
略,可参考 《面向Win8操作系统的网络包过滤关键技术研究》。

总结

本文写的过于简单仓促,由于篇幅限制,不能铺开来写,只能提供一个宏观上的印象。

参考