4. 显示过滤器:从入门到实战

抓包抓了一大堆,怎么找到你关心的那几条?这就是显示过滤器要解决的问题。捕获过滤器是「抓之前过滤」,显示过滤器是「抓之后筛选」——两者完全不同,别搞混了。

我个人习惯是:先全量抓个几秒,再用显示过滤器慢慢筛。为什么?因为你永远不知道漏掉什么。有一次我排查一个间歇性断连的问题,如果一开始就用捕获过滤器只抓特定端口,那个关键的重传包就永远看不到了。

4.1 显示过滤器语法与操作符

显示过滤器的核心语法很简单:字段 操作符 值。比如:

ip.addr == 192.168.1.1
tcp.port == 443
dns.flags.response == 1

常用的比较操作符:

操作符含义示例
==等于ip.src == 10.0.0.1
!=不等于ip.src != 10.0.0.1
>大于frame.len > 1000
<小于tcp.window_size < 65535
contains包含子串http.host contains "baidu"
matches正则匹配http.request.uri matches "\.php$"
in属于集合tcp.port in {80,443,8080}
小技巧:Wireshark 的过滤输入框有自动补全。你输入 ip. 就会弹出所有 ip 相关的字段。我建议你多利用这个功能,比死记硬背字段名快得多。

4.2 基于 IP 的过滤

IP 过滤是最常用的。记住这几个就够了:

  • ip.addr == 192.168.1.1 — 源或目标 IP 等于该地址
  • ip.src == 192.168.1.1 — 只看源 IP
  • ip.dst == 192.168.1.1 — 只看目标 IP
  • ip.addr == 10.0.0.0/24 — 过滤整个网段

这里有个坑:ip.addr 匹配的是「源或目标任意一个」。如果你只想看「从 A 到 B」的流量,得写成:

ip.src == 192.168.1.1 and ip.dst == 10.0.0.2

我曾经见过有人用 ip.addr == 192.168.1.1 and ip.addr == 10.0.0.2,结果发现根本筛不出东西——因为同一个包不可能同时源和目标都是同一个 IP。嗯,逻辑上就错了。

4.3 基于端口的过滤

端口过滤也很直接:

  • tcp.port == 443 — 源或目标端口为 443
  • tcp.srcport == 443 — 只看源端口
  • udp.port == 53 — DNS 查询通常用 UDP 53
  • tcp.port in {80,443,8080} — 多个端口
注意:HTTP 和 HTTPS 混用时,别只写 tcp.port == 80 or tcp.port == 443。你想想看,如果服务器返回了 302 重定向,从 443 跳到 80,你只筛一个端口就会漏掉关键跳转。

4.4 基于协议的过滤

Wireshark 能识别几百种协议。直接输入协议名就行:

dns
http
arp
icmp
tcp
udp
tls

你还可以组合协议和字段:

dns.flags.response == 0    # 只看 DNS 查询请求
dns.flags.response == 1    # 只看 DNS 响应
http.response.code == 404  # 只看 404 响应
icmp.type == 8             # 只看 ping 请求

4.5 逻辑组合过滤

单个条件不够用?用逻辑操作符组合:

操作符含义示例
and / &&与ip.src == 192.168.1.1 and tcp.port == 80
or / ||或tcp.port == 80 or tcp.port == 443
not / !非not arp
()分组(ip.src == 10.0.0.1 or ip.src == 10.0.0.2) and dns

举个例子。你想看「来自 192.168.1.100 或 192.168.1.101 的 DNS 查询,但排除 .local 域名的请求」:

(ip.src == 192.168.1.100 or ip.src == 192.168.1.101) and dns and not dns.qry.name contains ".local"
核心原则:括号决定优先级。我见过太多人写 ip.src == A or ip.src == B and dns,结果发现只筛出了 B 的 DNS 流量——因为 and 优先级高于 or。记住:拿不准就加括号。

4.6 实战案例:快速定位 DNS 查询失败

好了,理论说完了。咱们来点实际的。

假设用户反馈「网页打不开」。你抓了包,怎么快速定位是不是 DNS 的问题?

第一步,先筛出所有 DNS 流量:

dns

第二步,只看 DNS 响应,找到那些「有问题」的:

dns.flags.response == 1 and dns.flags.rcode != 0

rcode 是 DNS 响应码。0 表示成功,非 0 表示有错误。常见的:

rcode含义说明
0NoError查询成功
1FormatError查询格式错误
2ServerFailure服务器内部故障
3NXDOMAIN域名不存在(最常见)
4NotImplemented服务器不支持该查询类型
5Refused服务器拒绝查询

第三步,如果响应码是 3(NXDOMAIN),说明域名根本不存在。这时候你要检查:用户是不是输错了域名?或者 DNS 服务器是不是返回了错误的 NXDOMAIN(比如某些运营商劫持)?

第四步,还有一种情况:DNS 请求发出去了,但一直没有响应。怎么筛?

dns.flags.response == 0 and !dns.flags.truncated

然后看这些请求有没有对应的响应。Wireshark 有个好用的功能:右键点击一个 DNS 请求包 → Follow → UDP Stream,就能看到完整的请求-响应对话。

我曾经遇到过一个案例:用户访问某个网站时快时慢。抓包发现 DNS 查询有时要 3 秒才返回,有时直接超时。后来排查发现是 DNS 服务器配置了多个上游,其中一个上游响应极慢。用 dns.time > 1 筛出所有响应时间超过 1 秒的查询,问题一目了然。

最后,给你一个我常用的「DNS 故障快速诊断」过滤组合:

dns and (dns.flags.rcode != 0 or dns.time > 1 or dns.flags.truncated == 1)

这个表达式能一次性筛出:查询失败的、响应慢的、被截断的。你想想看,是不是比一条条翻包快多了?

避坑指南:我曾经在排查 DNS 问题时,发现有些包显示 dns.flags.rcode == 0,但响应里却没有答案记录。后来才注意到 dns.count.answers == 0。所以别只看 rcode,还要看答案数量。完整的过滤应该是:dns.flags.response == 1 and (dns.flags.rcode != 0 or dns.count.answers == 0)。

4.7 本章知识体系

下面这张图帮你梳理了显示过滤器的核心逻辑:

显示过滤器知识体系 显示过滤器 语法结构 过滤维度 逻辑组合 字段 操作符 值 IP 过滤 端口过滤 协议过滤 and / && or / || not / ! ( ) 分组 实战核心:DNS 故障快速定位 dns.flags.rcode != 0 | dns.time > 1 | dns.count.answers == 0

这张图把显示过滤器的三大核心——语法结构、过滤维度、逻辑组合——串在了一起。你写过滤表达式的时候,脑子里过一遍这个结构,基本不会出错。