发送在我的 NDIS 修改过滤器驱动程序中无法正常工作

Posted

技术标签:

【中文标题】发送在我的 NDIS 修改过滤器驱动程序中无法正常工作【英文标题】:Send doesn't work properly in my NDIS modifying filter driver 【发布时间】:2021-11-30 18:51:49 【问题描述】:

我正在尝试使用 NDIS 实现数据包修改过滤器。 我使用了丢弃数据包并从克隆的 NBL 发起发送/接收的方法。

msdn 上的文档说这是允许的: https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ndis/nc-ndis-filter_send_net_buffer_lists

对于每个提交给 FilterSendNetBufferLists 的 NET_BUFFER 结构,一个 过滤器驱动程序可以执行以下操作: ...

复制缓冲区并创建一个 发送请求与副本。发送操作类似于 过滤器驱动程序发起的发送请求。在这种情况下,驾驶员必须 通过调用 NdisFSendNetBufferListsComplete 函数。

我使用以下算法成功实现了 RX 路径:

    Filter 获取 FilterReceiveNetBufferLists 中的 NBL FilterReceiveNetBufferLists 创建 NBL 克隆和队列以供进一步处理 FilterReceiveNetBufferLists 调用 NdisFReturnNetBufferLists 用户连接到暴露的设备,将数据包出列并再次注入。 设备调用 NdisFIndicateReceiveNetBufferLists RX 路径正常,网络正常。

我在 TX 路径中做了同样的事情:

    Filter 获取 FilterSendNetBufferLists 中的 NBL FilterSendNetBufferLists 创建 NBL 克隆和队列以供进一步处理 FilterSendNetBufferLists 调用 NdisFSendNetBufferListsComplete。 用户连接到暴露的设备,将数据包出列并再次注入。 设备调用 NdisFSendNetBufferLists

TX 路径不起作用。 我正在通过发送 ICMP 数据包(仅 ping DNS 服务器 IP)对其进行测试。 我在路由器和我的测试机器之间安装了wireshark。 Wireshark 捕获由 TX 路径发出的传出 ICMP 数据包(步骤 5),但是没有响应数据包。

当我在我的 FilterSendNetBufferLists 中调用 NdisFSendNetBufferListsComplete 时究竟会发生什么? TCP/IP 驱动程序是否获得数据包已传输且没有任何错误的信息?

【问题讨论】:

您好,刚刚有一个问题:您是否使用 NdisAllocateCloneNetBufferList 来克隆 NBLs?如果是这样,您使用了哪些标志? 最初我是。我使用了零标志。但是后来我编写了自己的函数来复制 MDL。 您自己写的有什么特别的原因吗?考虑到 NdisAllocateCloneNetBufferList 有能力保留原始 MDL 或自己分配新的吗? 克隆的 NBL 引用原始 MDL。请参阅 msdn:“NDIS 不会将原始 MDL 描述的数据复制到新的数据缓冲区。相反,克隆的结构引用原始数据缓冲区。” 在我的场景中,我需要在将 NBL 返回到 NDIS 后触摸 MDL 数据。 【参考方案1】:

即兴发挥,我猜你没有在 TX 路径中调用 NdisCopySendNetBufferListInfo,这意味着校验和卸载元数据正在丢失。

如果 NIC 声称支持校验和卸载(即 NIC 硬件可以插入 IPv4、TCPv4 和/或 TCPv6 校验和),则 TCPIP 驱动程序不会尝试将有效校验和放入 IPv4/TCP标题。 (实际上,它明确地将部分校验和放在那里,这在软件中很容易计算,而在硬件中则更难计算。)然后 TCPIP 驱动程序将在 NBL 的 Info 字段中设置一些标志,指示硬件如何将校验和插入数据包负载中。

当您克隆 NBL 时,默认情况下,克隆不会继承任何元数据。因此,克隆的 NBL 在数据包负载中具有不完整的校验和,但缺少向 NIC 硬件插入校验和的指令。

修复很简单:NdisCopySendNetBufferListInfo 复制与 TX 路径相关的所有数据包元数据。 (RX 路径有一个类似的 NdisCopyRecieveNetBufferListInfo `,您还应该考虑从驱动程序调用它。)每当您克隆 NBL 时,您都应该调用这些例程之一,并且克隆最终将属于同一个数据包“流”作为原版NBL。

为什么调用 NdisAllocateCloneNetBufferList 时 NDIS 不自动复制元数据?表面问题是 NDIS 不知道我们是在做 TX 还是 RX 路径。但更深层次的问题是 NDIS 不知道您计划破坏数据包的严重程度。例如,如果您的驱动程序重写了 RX 数据包上的 TCP 标头,那么简单地复制 NIC 的 TCP 校验和计算和 RSS 哈希可能是不合适的。

所以调用NdisCopySendNetBufferListInfo 实际上意味着您声称您没有过多地破坏数据包,以至于它们看起来与任何硬件卸载都不同。例如,您没有插入协议标头、更改 TCP 端口号等(如果您正在做这些事情,那么您要么必须另外编写一些代码来平滑卸载,要么禁用它们完全。)

顺便说一句,这是一个有趣而微妙的问题,每个人的直觉都会出错:

TCP/IP 驱动程序是否获得数据包已传输且没有任何错误的信息?

Ndis[F|M]SendNetBufferListsComplete not 表示数据包已经传送,没有任何错误。这意味着一件事:数据包有效负载、MDL(s)、NB(s) 和 NBL 不再使用,协议驱动程序可以重新调整它们的用途。

当传输到典型的 PCIe 硬件时,这意味着对 NIC 的板载 RAM 的 DMA 已完成,并且 NIC 承诺不再接触数据包负载缓冲区。

这是一个简单的答案,但它立即引发了一个后续问题:如果 SendComplete 并不意味着数据包已成功传输,那么协议如何确定数据包是否已传输成功了吗?

答案是协议不关心数据包是否被传输到下一跳。他们真正关心的是远程端点是否收到了数据包。找出答案的唯一方法是某种 ACK 系统。因此,没有人真正费心去构建一个信号,表明 NIC 硬件实际上已经将 NBL 传输到了下一跳,因为无论如何协议都无法处理这些信息。

(数据包时间戳 (IEEE15888/PTP/NTP) 是上述讨论的一个例外。但即使在这种情况下,我们实际上也不想知道数据包何时离开localhost。我们实际上想知道数据包何时到达远程端点。但是物理定律是什么,后者是不可知的,所以我们必须满足于知道 TX 数据包何时离开本地主机。)

请注意,如果您确定数据包没有传输,那么您可以在NET_BUFFER_LIST::Status 中写下错误代码,并且某些协议(例如 UDP + winsock)会将该错误冒泡到应用程序。但在这种情况下,您只是在优化更快的错误路径——应用程序本质上仍然有义务构建网络级反馈机制(例如 ACK),以了解数据包是否一直到达目的地。

【讨论】:

没有问题。谢谢你的详细解释。你完全正确。我只是错过了复制 NBL 信息。现在它工作正常,我更好地理解 NBL 通过 NDIS 堆栈会发生什么。 MSDN 在 NdisAllocateCloneNetBufferList 中说“NDIS 不会将原始 MDL 描述的数据复制到新的数据缓冲区。相反,克隆的结构引用原始数据缓冲区”。在我们返回/指示 NBL 并使用克隆的 NBL 后,这会导致问题吗?例如,堆栈中的任何驱动程序都可以在此之后释放原始 MDL 缓冲区吗? @OneAndOnly - 我在写作方面不够熟练,无法将对该问题的全面答案压缩到***评论的字符限制中。如果您将此作为一个单独的问题提出并用 [ndis] 标记它,我将有更多空间。非常简短的总结是,如果您返回/完成 NBL,NBL 本身及其 NB(s)、MDL(s) 和有效负载缓冲区都将消失;退还 NBL 后,您将无法继续使用它们。 嗨,杰弗里,想在这里问一个后续问题,但由于时间太长,我为此打开了另一个线程。如果您有空闲时间,如果您可以看一下,对我将非常有帮助。 ***.com/questions/69632074/…

以上是关于发送在我的 NDIS 修改过滤器驱动程序中无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

使用 EtherType 0x88A4 (EtherCat) 时,WriteFile 函数 (NDIS) 中出现错误 87

NDIS LWF 驱动程序导致网络堆栈中的 WFP 驱动程序出现问题?

过滤数组时JS过滤器无法正常工作

在zuul过滤器中修改请求正文无法正常工作

搜索和过滤功能仍然无法正常工作(Vue JS)

Rails API - 无法创建用户,密码是FILTERED并返回所有验证错误