Skip to content
Wireshark Wiki 中文翻译整理专题首页原始页面

快速数据包过滤

这个补丁 fastfilter_rev27811.patch(在 Linux 上编译并测试)展示了一种可能用于加速 Wireshark 交互式数据包过滤的方法。以下各节将描述问题、解决方案和实现说明。

如果我对当前 Wireshark 实现的描述有误,请纠正我。

Wireshark 如何进行交互式数据包过滤?

  • 首先,Wireshark 从工具栏获取过滤器字符串。然后,Wireshark 将该过滤器字符串编译为语法树。随后,这棵语法树会被转换为 Display Filter Virtual Machine 指令。
  • 之后,Wireshark 遍历每个数据包,并调用 dissector 对其进行解析。借助解析获得的信息,Wireshark 将过滤器应用到该数据包上。如果数据包通过过滤器,它将显示在 GUI 中。
  • 每次用户应用过滤器时,都必须经历上述过程,即使同一个过滤器已经应用过两次也是如此。

如何提升过滤速度?

当前 Wireshark 实现并未利用过滤历史;也就是说,两次过滤不会共享关于过滤器字符串的知识。

下面的示例展示了过滤历史如何帮助我们加速过滤:

  • 假设一个捕获文件包含 100 个数据包,其中有 80 个 TCP 数据包、20 个 UDP 数据包。在这 20 个 UDP 数据包中有 10 个 DNS 数据包。在这种情况下,我们还假设这些 DNS 数据包都位于 UDP 之上(注意 DNS 也可能位于 TCP 之上)。

  • 第一个过滤器是 'udp',因此显示 20 个 UDP 数据包。我们以某种低成本方式保存该信息。

  • 第二个过滤器是 'tcp',因此显示 80 个 TCP 数据包。我们也保存该信息。

  • 第三个过滤器是 'udp && dns'。由于我们知道只有 20 个数据包通过了 'udp',因此只需要解析这 20 个数据包,并应用过滤器,即 'udp && dns',以找出 10 个 DNS 数据包。其他 80 个数据包会被直接跳过。

  • 第四个过滤器是 'tcp'。由于我们保存了显示历史,因此只需要解析这 80 个 TCP 数据包。

简而言之,借助此前已应用过滤器的知识,我们可以只解析一部分数据包,从而节省可观时间。在上面的示例中,'udp && dns' 过滤器大约可以节省 80% 的时间。

解决方案

在本节中,我们将以更抽象的方式描述这个问题的解决方案。

  • 假设一个新的显示过滤器,比如 F,包含此前应用过的过滤器 F1, ..., Fn。换句话说,F1, ..., Fn 是 F 的子树。F 中也有一些不是 F1, ..., Fn 的部分。
  • 每个显示过滤器都会被转换为语法树,F 的语法树是 S,Fi 的语法树是 Si(它是 F 中的一棵子树)。不属于 Fi、但属于 F 的语法树节点表示为 N1, ..., Nm。
  • 对于一个数据包,如果它通过 Fi,我们将子树 Si 的值设为 1;否则设为 0。然后,我们将修改后的 F 转换为一个布尔表达式,比如 EXP,它把 N1, ..., Nm 视为布尔变量。这样我们就可以将其作为布尔可满足性 [1] 问题(又称 SAT 问题)来求解:
  • 如果无论给 N1, ..., Nm 赋予什么值,EXP 都不可能为真,则该数据包永远不会通过 F。因此我们无需解析该数据包。
  • 如果无论给 N1, ..., Nm 赋予什么值,(!EXP) 都不可能为真,则该数据包总会通过 F。因此我们需要解析该数据包,但无需应用过滤器 F。
  • 在剩余情况下,基于当前信息,我们不知道该数据包是否会通过 F,因此应解析它并将 F 应用于它。

实现

以下是一些实现说明:

  • 过滤历史保存在每个数据包的 frame data 中,它是一个 64 位整数。如果第 i 位为 1,则表示该数据包通过了第 i 个已保存过滤器。
  • 此前应用过的过滤器保存为语法树。
  • 我们使用 limmat[2] SAT solver 和 limboole front end。主要原因是它们很轻量。

[1] http://en.wikipedia.org/wiki/Boolean_satisfiability_problem

[2] http://fmv.jku.at/limmat/

导入自 https://wiki.wireshark.org/Development/FastFiltering,时间为 2020-08-11 23:12:47 UTC

相关 Wireshark Wiki 页面

网络分析技术档案