4. 显示过滤器:语法、运算符与实战技巧

抓包只是第一步,真正有价值的是从海量数据里捞出你想要的流量。显示过滤器就是干这个的。它不像捕获过滤器那样在抓包前就做取舍,而是等所有数据都抓下来之后,你再像用 SQL 查数据库一样,把关心的包筛出来。

我个人习惯把显示过滤器叫做 Wireshark 的「灵魂功能」。你想想看,一个 pcap 文件里可能有几十万甚至上百万个包,没有过滤器,你只能对着屏幕发呆。

核心认知:显示过滤器只影响「显示」,不影响原始抓包数据。你随时可以清空过滤器,所有包都会回来。这一点和捕获过滤器有本质区别。

4.1 显示过滤器语法基础

显示过滤器的语法其实不复杂,核心就一句话:「协议.字段 运算符 值」。比如:

ip.src == 192.168.1.1
tcp.port == 80
http.request.method == "GET"

每个表达式由三部分组成:

  • 协议:小写,如 ip、tcp、udp、http、dns
  • 字段:点号连接,如 src、dst、port、request.method
  • 值:IP 地址、端口号、字符串(加引号)、十六进制等

我记得刚学的时候,总记不住字段名。后来发现一个窍门:在 Wireshark 里点开一个包,展开协议树,右键点击你想过滤的字段,选择「作为过滤器应用」→「选中」。Wireshark 会自动帮你生成正确的语法。这招我到现在还在用。

小技巧:在过滤器输入框里打字时,Wireshark 会自动弹出字段补全提示。输入 tcp. 就会列出所有 tcp 相关字段,省得你死记硬背。

4.2 比较运算符

显示过滤器支持多种比较方式,我整理了一张常用表:

运算符 含义 示例
== 等于 ip.src == 10.0.0.1
!= 不等于 ip.src != 10.0.0.1
> < 大于 / 小于 frame.len > 1500
>= <= 大于等于 / 小于等于 tcp.window_size >= 65535
contains 包含子串 http.host contains "baidu"
matches 正则匹配 http.request.uri matches "\.php$"
in 属于集合 tcp.port in {80 443 8080}

这里有个坑我要提醒你:字符串比较要加双引号,数字和 IP 不用。我曾经见过有人写 http.request.method == GET(没加引号),结果过滤器死活不生效,排查了半天才发现是语法问题。

避坑指南:我曾经在排查一个 HTTP 403 问题时,用 http.response.code == 403 死活筛不出包。后来发现响应码字段其实是 http.response.code,但有些版本里它叫 http.response.status_code。遇到这种情况,右键点开协议树看字段名最靠谱。

4.3 逻辑运算符

单个条件往往不够用,你需要把多个条件组合起来。逻辑运算符就是干这个的:

  • and(或 &&):两个条件都满足
  • or(或 ||):满足其中一个
  • not(或 !):取反
  • ():括号改变优先级

举个例子,我想看从 192.168.1.100 发往 10.0.0.1 的 HTTP 请求:

ip.src == 192.168.1.100 and ip.dst == 10.0.0.1 and http.request

或者排除掉 SSH 和 RDP 流量:

not (tcp.port == 22 or tcp.port == 3389)

我个人习惯用英文单词(and/or/not),因为更直观。但如果你喜欢符号(&&/||/!),也没问题,Wireshark 都支持。

4.4 常用过滤表达式

下面这些是我在日常工作中几乎每天都会用到的表达式,我按场景分了个类:

4.4.1 地址过滤

ip.addr == 192.168.1.1          # 只看某个 IP 的所有流量
ip.src == 192.168.1.0/24        # 只看某个网段的源地址
ip.dst == 10.0.0.1              # 只看目的地址
eth.addr == 00:1a:2b:3c:4d:5e   # 按 MAC 地址过滤

4.4.2 端口与协议过滤

tcp.port == 443                 # 只看 HTTPS
udp.port == 53                  # 只看 DNS
tcp.port in {80 443 8080}       # 多个端口
http                           # 只看 HTTP 协议(所有 HTTP 包)
dns                            # 只看 DNS 协议

4.4.3 应用层过滤

http.request.method == "POST"   # 只看 POST 请求
http.response.code == 404       # 只看 404 响应
dns.qry.name contains "google"  # DNS 查询中包含 google
tcp.flags.syn == 1              # 只看 SYN 包
tcp.flags.reset == 1            # 只看 RST 包

4.4.4 长度与时间过滤

frame.len > 1400               # 大包(可能含数据)
frame.len < 64                 # 小包(可能为控制包)
tcp.analysis.retransmission     # 只看重传包
tcp.analysis.fast_retransmission # 快速重传
tcp.analysis.duplicate_ack      # 重复确认

实战经验:排查网络慢的问题时,我通常会先输入 tcp.analysis.retransmission or tcp.analysis.fast_retransmission。如果重传包占比超过 1%,基本可以断定网络有问题。这个经验值是我在好几个项目里验证过的。

4.5 过滤表达式保存与加载

有些过滤条件你可能会反复用到。比如每次排查 DNS 问题都要写 dns.flags.response == 0,每次都重新打字太麻烦了。Wireshark 提供了保存功能。

4.5.1 保存过滤器

  1. 在过滤器输入框旁边,点击那个「书签」图标(或者叫「过滤器管理」按钮)
  2. 选择「管理过滤器」
  3. 点击「新建」,输入名称和表达式
  4. 点击「确定」保存

保存之后,下次你点那个书签图标,就能直接选之前保存的过滤器了。我个人习惯按场景命名,比如「DNS 查询」「HTTP 4xx」「TCP 重传」这样,找起来方便。

4.5.2 加载与导入导出

Wireshark 的过滤器配置保存在 cfilters 和 dfilters 文件里(Windows 在 %APPDATA%\Wireshark\,Linux/Mac 在 ~/.config/wireshark/)。你可以直接复制这些文件到另一台机器上,实现过滤器的迁移。

我记得有一次帮同事排查问题,他那台机器上没配任何过滤器。我直接把我本地的 dfilters 文件发给他,覆盖之后重启 Wireshark,所有过滤器就都出现了。省得他一个个重新配。

注意:不同版本的 Wireshark 之间,过滤器文件格式可能略有差异。跨版本迁移时,建议先备份原文件。我曾经从 3.x 升级到 4.x 时,过滤器文件直接复制过去报错了,后来重新配了一遍才搞定。

4.6 知识体系总览

下面这张图把显示过滤器的核心知识点串起来了,你可以对照着回顾一下:

显示过滤器知识体系 显示过滤器知识体系 显示过滤器 语法基础 运算符 实战应用 协议.字段 == 值 字段自动补全 右键应用过滤器 比较:== != > < contains 逻辑:and or not () 集合:in {80 443} 地址/端口过滤 应用层过滤 重传/异常分析 保存与加载:书签管理 / 文件迁移 核心原则:显示过滤器只影响「显示」,不改变原始抓包数据 清空过滤器 = 所有包恢复显示

4.7 本章小结

显示过滤器是 Wireshark 里最常用的功能,没有之一。你只要记住「协议.字段 运算符 值」这个基本结构,再配合逻辑运算符组合条件,就能应对绝大多数场景。

我建议你平时多积累自己的过滤器库。遇到好用的表达式就保存下来,时间长了就是一笔宝贵的财富。下次排查问题时,直接调出来用,效率翻倍。