4. 显示过滤器:语法、运算符与协议过滤

抓包这活儿,说白了就是「先抓到,再过滤」。抓包阶段用捕获过滤器,那是为了给网卡减负;但真正到了分析阶段,你面对的可能是一大堆乱七八糟的流量——ARP、广播、背景噪声……这时候,显示过滤器才是你的主力工具。

我个人习惯,一打开 Wireshark 就先在显示过滤器栏敲几个条件。不是因为我记性好,而是因为不这么干,根本看不下去。你想想看,一个千兆网口上随便抓 10 秒,可能就是几万个包,手动翻?不现实。

4.1 显示过滤器语法基础

显示过滤器的语法,其实比捕获过滤器更接近编程语言。它的核心结构是:

<协议>.<字段> <运算符> <值>

举个例子:

ip.src == 192.168.1.1

这表示「只看源 IP 是 192.168.1.1 的包」。注意,这里用的是双等号,不是捕获过滤器里的单等号。很多新手在这里翻车,我刚开始用的时候也犯过这个错。

再比如:

tcp.port == 80

这个会匹配源端口或目标端口为 80 的 TCP 包。如果你想精确控制方向,可以写成:

tcp.srcport == 80

或者:

tcp.dstport == 80
小技巧: 在 Wireshark 的显示过滤器输入框里,你输入字段名时会有自动补全提示。比如你敲 tcp.,它会列出所有可用的 TCP 字段。这个功能很实用,我经常靠它来回忆某个字段的准确写法。

4.2 比较运算符

显示过滤器支持的运算符比捕获过滤器丰富得多。我把常用的整理成了表格,方便你对照:

运算符 含义 示例
== 等于 ip.src == 10.0.0.1
!= 不等于 ip.src != 10.0.0.1
> 大于 frame.len > 1500
< 小于 tcp.window_size < 65535
>= 大于等于 udp.length >= 100
<= 小于等于 ip.ttl <= 64
contains 包含子串 http.user_agent contains "Chrome"
matches 正则匹配 http.host matches "\.(com|cn)$"
in 属于集合 tcp.port in {80 443 8080}

这里我想特别说一下 contains 和 matches。这两个运算符非常强大,但很多人不太敢用。

contains 是子串匹配,不区分大小写。比如你想看所有 User-Agent 里带 "Windows" 的 HTTP 请求:

http.user_agent contains "windows"

这个在排查特定客户端问题时特别好用。我曾经帮一个同事定位某个老旧 POS 机的 HTTP 请求问题,就是用 contains 过滤出它的 User-Agent,然后发现它居然还在用 TLS 1.0。

matches 则支持 Perl 兼容的正则表达式。比如你想过滤出所有 .com 或 .cn 的 HTTP 请求:

http.host matches "\.(com|cn)$"
注意: matches 对性能有一定影响。如果你只是做简单的子串匹配,优先用 contains。正则表达式虽然灵活,但在大流量场景下会拖慢 Wireshark 的响应速度。

4.3 逻辑组合

单个条件往往不够用。实际排错时,你经常需要组合多个条件。显示过滤器支持三种逻辑运算符:

  • and(或 &&):两个条件同时满足
  • or(或 ||):满足其中一个条件
  • not(或 !):取反

举个例子,你想看从 192.168.1.1 发往 10.0.0.1 的 HTTP 流量:

ip.src == 192.168.1.1 and ip.dst == 10.0.0.1 and tcp.port == 80

或者你想排除所有广播和多播包:

not (eth.dst == ff:ff:ff:ff:ff:ff or ip.dst == 224.0.0.0/4)

这里有个坑:括号的使用。逻辑组合的优先级是 not > and > or。如果你不确定优先级,就加括号。我见过太多人因为少写括号,过滤出来的结果完全不是自己想要的。

实战经验: 我在排查一个 DNS 解析慢的问题时,用了这样的组合条件:
dns.flags.response == 0 and dns.qry.name contains "example.com"
这样只显示对 example.com 的 DNS 查询请求,不显示响应包。配合时间列,一眼就能看出哪个查询耗时异常。

4.4 协议过滤

协议过滤是显示过滤器最基础也最常用的功能。你直接在过滤器栏输入协议名,Wireshark 就会只显示该协议的包。

常用协议过滤示例:

过滤表达式 说明
arp 只显示 ARP 协议包
dns 只显示 DNS 协议包
http 只显示 HTTP 协议包
tcp 只显示 TCP 协议包
udp 只显示 UDP 协议包
icmp 只显示 ICMP 协议包
tls 只显示 TLS/SSL 协议包
dhcp 只显示 DHCP 协议包

但这里有个细节:协议过滤是递归的。比如你输入 tcp,它会显示所有 TCP 包,包括 TCP 之上的 HTTP、TLS、SSH 等。因为 Wireshark 认为 HTTP 是 TCP 的「子协议」,所以也会被包含在内。

如果你想只看「纯粹的」TCP 包(不含上层协议),可以这样:

tcp and not (http or tls or ssh)

嗯,这个技巧在分析 TCP 重传和窗口问题时特别有用。

4.5 知识体系总览

为了让你对本章内容有个整体印象,我画了一张结构图:

显示过滤器知识体系 显示过滤器知识体系 显示过滤器 语法基础 比较运算符 逻辑组合 协议过滤 协议.字段 运算符 值 示例: ip.src == 1.1.1.1 == != > < >= <= contains matches in and / or / not 括号控制优先级 tcp / udp / http / dns 递归包含子协议 核心原则:先过滤,再分析 组合使用语法、运算符和协议过滤,精准定位问题 多用自动补全 注意括号优先级 优先用 contains

4.6 实战中的几个小技巧

最后,分享几个我平时用得最多的显示过滤器技巧:

  1. 快速排除背景噪声:抓包时总会有 ARP、LLMNR、mDNS 等广播包。我一般上来就先过滤掉它们:
    !arp and !llmnr and !mdns
  2. 只看特定会话:分析 TCP 问题时,我常用 tcp.stream eq 0 来只看某个 TCP 流。这个 tcp.stream 是 Wireshark 自动分配的流编号,非常实用。
  3. 结合时间列:在显示过滤器中加上 frame.time_delta > 1,可以快速找出响应时间超过 1 秒的包。这个在排查「慢」的问题时特别好用。
  4. 保存常用过滤器:Wireshark 支持保存过滤器。我把自己常用的十几个过滤器都存了下来,比如「只看 TCP 重传」、「只看 HTTP 500 响应」等。省得每次重新敲。
我的习惯: 每次开始抓包前,我会先想清楚「我要看什么」。然后根据这个目标,提前写好显示过滤器。而不是等抓了一大堆包再慢慢翻。这个习惯帮我节省了大量时间。

显示过滤器这东西,说白了就是熟能生巧。你用得越多,就越能体会到它的强大。刚开始可能会觉得语法有点多,但别急,先记住最常用的几个——ip.src、tcp.port、http、and、or——剩下的,遇到具体问题再查也来得及。