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
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.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 知识体系总览
为了让你对本章内容有个整体印象,我画了一张结构图:
4.6 实战中的几个小技巧
最后,分享几个我平时用得最多的显示过滤器技巧:
- 快速排除背景噪声:抓包时总会有 ARP、LLMNR、mDNS 等广播包。我一般上来就先过滤掉它们:
!arp and !llmnr and !mdns - 只看特定会话:分析 TCP 问题时,我常用
tcp.stream eq 0来只看某个 TCP 流。这个tcp.stream是 Wireshark 自动分配的流编号,非常实用。 - 结合时间列:在显示过滤器中加上
frame.time_delta > 1,可以快速找出响应时间超过 1 秒的包。这个在排查「慢」的问题时特别好用。 - 保存常用过滤器:Wireshark 支持保存过滤器。我把自己常用的十几个过滤器都存了下来,比如「只看 TCP 重传」、「只看 HTTP 500 响应」等。省得每次重新敲。
显示过滤器这东西,说白了就是熟能生巧。你用得越多,就越能体会到它的强大。刚开始可能会觉得语法有点多,但别急,先记住最常用的几个——ip.src、tcp.port、http、and、or——剩下的,遇到具体问题再查也来得及。