gpt4 book ai didi

c - 如何捕获数据包(NPF; WinPcap)?

转载 作者:可可西里 更新时间:2023-11-01 11:23:12 24 4
gpt4 key购买 nike

我了解了WinPcap如何过滤数据包here,并从GitHub(Microsoft/Windows-driver-samples)检查了ndis/filter project。我在下面提供了WinPcap页面中的主要数据,因为它们与问题有关。

enter image description here

enter image description here

我的主要问题:如果 NPF 丢弃一个数据包(数据包),这意味着将不捕获数据包还是不发送/接收数据包?
例如(如我所见):

  • dumpcap开始在 eth0 上监听数据包。
  • Chrome发送DNS请求。
  • NDIS驱动程序处理此数据包。 (确切地说是NetBufferList;通过SendNetBufferListsHandler and SendNetBufferListsCompleteHandler函数)
  • 解析NBL:解析每个缓冲区并检查数据包特征;
  • 如果要丢弃数据包,则需要组装新的NBL(不包含不需要的数据包),并使用新的NBList调用SendNetBufferListsCompleteHandler。
  • 如果要从捕获中削减此数据包,则需要组装新的NBL(不包含不需要的数据包),并使用新的NBList调用NdisFIndicateReceiveNetBufferLists。

  • 接收数据包的情况相同(通过 ReceiveNetBufferListsHandler and ReturnNetBufferListsHandler函数)。

    我是否正确理解,是否有机会通过NPF丢弃数据包,将发送/接收到/从网络发送/接收,以及将其从“捕获数据包列表”中删除?

    是,如何正确丢包?

    我没有找到用于通过SendNetBufferListsHandler/SendNetBufferListsCompleteHandler和ReceiveNetBufferListsHandler/ReturnNetBufferListsHandler函数删除数据包的代码示例。

    最佳答案

    if NPF drops a packet (packets) it means that packets will not be captured or that packets will not be sent/received?


    该数据包将不会被捕获,但仍将其传递到网络堆栈的其余部分。我想这有两个原因:
  • 数据包捕获工具通常用于诊断,因此它们倾向于“不使事情变得更糟”。我知道的所有数据包捕获工具都会选择让数据包继续流过它们,即使它们无法跟上。
  • NPF(又名winpcap/wireshark)特别是在设计上可以防止其阻止/丢弃流量。即使您愿意对NPF进行一些修改,也无法做到。原因是NPF被实现为协议(protocol)驱动程序。作为协议(protocol)驱动程序,它是TCPIP的对等对象,不能直接干扰TCPIP的功能。 (这是NPF甚至可以看到TCPIP传输的一个小奇迹-这是通过第2层回送的魔力实现的。[与第3层回送无关,例如:: 1和127.0.0.1等。)

  • nmap项目有一个NPF分支,可将其实现为NDIS筛选器驱动程序。这种驱动程序能够阻止,延迟,重写或注入(inject)流量。因此,如果您对更改上面的#1哲学感兴趣,则应该从nmap的分支开始,而不是“官方” winpcap。
    (而且,总的来说,即使您不需要丢弃流量,我个人也会推荐nmap的fork。筛选器驱动程序比协议(protocol)驱动程序要快得多,后者使网络适配器进入第2层回送模式。)
    查看nmap-npf后,您将能够从NDIS示例过滤器驱动程序(如FilterReceiveNetBufferLists)中找到回调。
    丢弃数据包实际上非常简单;)不过,有一些陷阱,让我们来看一些示例。
    在传输路径上,我们有一个NBL链接列表,我们希望将其分为两个列表,一个丢弃,一个继续发送。单个NBL可以包含多个数据包,但是保证每个数据包都具有相同的“流”(例如TCP套接字)。因此,通常可以简化假设,即NBL中的每个数据包总是以相同的方式对待:如果要丢弃一个,则要全部丢弃。
    如果此假设不正确,即,如果您确实想从TCP套接字内选择性地丢弃某些数据包,而不是所有数据包,那么您需要做一些更复杂的事情。您不能直接从NET_BUFFER_LIST中删除单个N​​ET_BUFFER;相反,您必须克隆NET_BUFFER_LIST并复制要保留的NET_BUFFER。
    由于这是一个免费论坛,因此,我仅举一个简单而常见的示例;)
    void
    FilterSendNetBufferLists(NET_BUFFER_LIST *nblChain, ULONG sendFlags)
    {
    NET_BUFFER_LIST *drop = NULL;
    NET_BUFFER_LIST *keep = NULL;

    NET_BUFFER_LIST *next = NULL;
    NET_BUFFER_LIST *nbl = NULL;

    for (nbl = nblChain; nbl != NULL; nbl = next) {
    next = nbl->Next;

    // If the first NB in the NBL is drop-worthy, then all NBs are
    if (MyShouldDropPacket(nbl->FirstNetBuffer)) {
    nbl->Next = drop;
    drop = nbl;
    nbl->Status = NDIS_STATUS_FAILURE; // tell the protocol
    } else {
    nbl->Next = keep;
    keep = nbl;
    }
    }

    // Above would reverse the order of packets; let's undo that here.
    keep = ReverseNblChain(keep);

    . . . do something with the NBLs you want to keep. . .;

    // Send the keepers down the stack to be transmitted by the NIC.
    NdisFSendNetBufferLists(context, keep, portNumber, sendFlags);

    // Return the dropped packets back up to whoever tried to send them.
    NdisFSendCompleteNetBufferLists(context, drop, 0);
    }
    在接收路径上,可以确保每个NET_BUFFER_LIST仅一个NET_BUFFER。 (NIC无法完全知道哪些数据包是同一数据流的一部分,因此还没有完成分组。)因此,这个小难题已不复存在,但有一个新的难题:您必须检查NDIS_RECEIVE_FLAGS_RESOURCES标志。不检查该标志是浪费时间追逐筛选器驱动程序中的错误的第一大原因,因此我必须对此做很多事情。
    void
    FilterReceiveNetBufferLists(NET_BUFFER_LIST *nblChain, ULONG count, ULONG receiveFlags)
    {
    NET_BUFFER_LIST *drop = NULL;
    NET_BUFFER_LIST *keep = NULL;

    NET_BUFFER_LIST *next = NULL;
    NET_BUFFER_LIST *nbl = NULL;

    for (nbl = nblChain; nbl != NULL; nbl = next) {
    next = nbl->Next;

    // There's only one packet in the NBL
    if (MyShouldDropPacket(nbl->FirstNetBuffer)) {
    nbl->Next = drop;
    drop = nbl;
    count -= 1; // decrement the NumberOfNetBufferLists
    } else {
    nbl->Next = keep;
    keep = nbl;
    }
    }

    keep = ReverseNblChain(keep);

    . . . do something with the NBLs you want to keep. . .;

    // Pass the keepers up the stack to be processed by protocols.
    NdisFIndicateReceiveNetBufferLists(context, keep, portNumber, count, receiveFlags);

    // Checking this flag is critical; never ever call
    // NdisFReturnNetBufferLists if the flag is set.
    if (0 == (NDIS_RECEIVE_FLAGS_RESOURCES & receiveFlags)) {
    NdisFReturnNetBufferLists(context, keep, 0);
    }
    }
    请注意,我使用了一个名为 ReverseNblChain的辅助函数。颠倒数据包的顺序在技术上是合法的,但会降低性能。仅当数据包通常按顺序到达时,TCPIP才能达到其最佳性能。示例代码中的链表操作循环具有反转NBL列表的副作用,因此我们可以使用 ReverseNblChain消除损害。我们不需要颠倒丢弃链,因为没有人试图重组丢弃的数据包。您可以按任何顺序保留它们。
    NET_BUFFER_LIST * ReverseNblChain(NET_BUFFER_LIST *nblChain)
    {
    NET_BUFFER_LIST *head = NULL;
    NET_BUFFER_LIST *next = NULL;
    NET_BUFFER_LIST *nbl = NULL;

    for (nbl = nblChain; nbl != NULL; nbl = next) {
    next = nbl->Next;
    nbl->Next = head;
    head = nbl;
    }

    return head;
    }
    最后,如果您要在 future 的几年中阅读此书,建议您从Microsoft查找一个名为 nblutil.h的示例头文件。 (我们尚未发布它,但是我正在研究它。)它有一个非常漂亮的例程 ndisClassifyNblChain,它几乎可以为您完成所有工作。它具有较高的可扩展性,并使用了多种技巧来提高性能,而您所发现的结果已经塞满了已经很长的StackOverflow答案。
    从将来的更新: https://github.com/microsoft/ndis-driver-library具有 NdisClassifyNblChain2

    关于c - 如何捕获数据包(NPF; WinPcap)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55601283/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com