4. 显示过滤器进阶:过滤表达式语法、逻辑组合、按字段过滤、按时间/长度过滤

上一章我们聊了基础过滤,说白了就是点几下鼠标。但真正的高并发分析,靠鼠标点选是搞不定的。你得学会跟 Wireshark 的显示过滤器「对话」——用表达式精准地告诉它:我要看什么,不要看什么。

我个人习惯,80% 的日常分析工作都靠显示过滤器完成。它不会丢包,只是隐藏你不关心的数据。这一点很重要,你想想看,在高并发场景下,几万甚至几十万个包涌进来,眼睛看是看不过来的,必须靠过滤器把范围缩小到可分析的级别。

核心认知:显示过滤器(Display Filter)只改变视图,不改变抓取结果。你随时可以清除过滤器,所有数据都还在。

4.1 过滤表达式语法:从简单到复杂

Wireshark 的过滤语法,其实是一种领域特定语言(DSL)。它由三部分组成:字段名、比较操作符、值。

最基本的格式长这样:

字段名 操作符 值

举个例子:

tcp.port == 443

这表示「只看源端口或目的端口为 443 的 TCP 包」。注意,这里用的是双等号 ==,不是单等号。单等号在 Wireshark 里是赋值,不是比较。

常用的比较操作符有这些:

操作符 含义 示例
== 等于 ip.src == 192.168.1.1
!= 不等于 tcp.port != 80
> 大于 frame.len > 1000
< 小于 tcp.window_size < 65535
>= 大于等于 frame.time_relative >= 5.0
<= 小于等于 tcp.analysis.ack_rtt <= 0.1
contains 包含子串 http.host contains "api"
matches 正则匹配 http.request.uri matches "^/v[0-9]/"

我的小技巧:如果你不确定某个字段名怎么写,直接在包详情面板里右键点击字段,选择「作为过滤器应用」→「选中」。Wireshark 会自动帮你生成正确的表达式。我刚开始学的时候,全靠这个功能反推字段名。

4.2 逻辑组合:and、or、not

单个条件往往不够用。高并发场景下,你得同时满足多个条件。这时候就需要逻辑操作符出场了。

三个核心操作符:

  • and(&&):两个条件都满足
  • or(||):满足其中一个条件
  • not(!):取反,排除某个条件

看几个实战例子:

# 只看从 10.0.0.1 发往 443 端口的包
ip.src == 10.0.0.1 and tcp.dstport == 443

# 只看 192.168.1.0/24 网段内,且长度大于 1500 的包
ip.addr == 192.168.1.0/24 and frame.len > 1500

# 排除所有广播包和组播包
not (eth.dst == ff:ff:ff:ff:ff:ff or eth.dst[0:1] == 01:00:5e)

# 看 HTTP 或 DNS 流量
http or dns

这里有个坑,我踩过好几次。你注意看 ip.addr 这个字段——它同时包含了源地址和目的地址。所以 ip.addr == 10.0.0.1 的意思是「源地址或目的地址任意一个是 10.0.0.1」。如果你只想看源地址,必须用 ip.src。

我曾经犯过的错:有一次排查一个高并发连接池问题,我用了 ip.addr == 10.0.0.1 and tcp.port == 8080。结果发现过滤出来的包比预期多了一倍。后来才意识到,tcp.port 也是同时匹配源端口和目的端口。正确的写法应该是 ip.addr == 10.0.0.1 and (tcp.srcport == 8080 or tcp.dstport == 8080)。

4.3 按字段过滤:tcp.port、ip.addr 的深层用法

字段过滤是显示过滤器的核心能力。Wireshark 支持数千个协议字段,每个字段都可以作为过滤条件。我挑几个高并发场景下最常用的来讲。

4.3.1 tcp.port 的微妙之处

tcp.port 是一个「合成字段」,它等价于 tcp.srcport or tcp.dstport。这意味着:

# 这两个表达式是等价的
tcp.port == 443
tcp.srcport == 443 or tcp.dstport == 443

但如果你只想看客户端发往服务器的包,必须明确指定方向:

# 客户端发往 443
tcp.dstport == 443

# 服务器从 443 发出
tcp.srcport == 443

4.3.2 ip.addr 的网段过滤

高并发场景下,经常要过滤整个网段。Wireshark 支持 CIDR 表示法:

# 只看 10.0.0.0/8 网段的流量
ip.addr == 10.0.0.0/8

# 排除 192.168.0.0/16 的内网流量
not ip.addr == 192.168.0.0/16

嗯,这里要注意:CIDR 过滤只能用在 ip.addr、ip.src、ip.dst 这类地址字段上,不能用在端口上。

4.3.3 其他高并发常用字段

字段 含义 高并发场景用途
tcp.analysis.ack_rtt ACK 往返时间 排查延迟抖动
tcp.analysis.retransmission 重传标记 定位丢包
tcp.window_size 接收窗口大小 判断接收端瓶颈
tcp.stream TCP 流编号 追踪单条连接
http.response.code HTTP 响应码 过滤 5xx 错误

4.4 按时间/长度过滤:精准定位异常

高并发连接分析中,时间和长度是两个极其重要的维度。异常往往就藏在「不该出现的时间点」和「不该出现的大小」里。

4.4.1 按时间过滤

Wireshark 提供了几个时间相关的字段:

  • frame.time_relative:相对于抓包开始的时间(秒)
  • frame.time_delta:与前一个包的间隔(秒)
  • frame.time_delta_displayed:与上一个显示出来的包的间隔

实战例子:

# 只看抓包开始后 5 到 10 秒之间的包
frame.time_relative >= 5 and frame.time_relative <= 10

# 看间隔超过 1 秒的包(可能是超时)
frame.time_delta > 1.0

# 结合场景:看 5 秒后出现的重传
frame.time_relative > 5 and tcp.analysis.retransmission

我的经验:分析高并发连接池泄漏时,我经常用 frame.time_relative 配合 tcp.stream 来看一条连接的生命周期。如果一条连接在抓包开始后 30 秒还在发数据,但其他同类连接早就结束了,那这条连接很可能有问题。

4.4.2 按长度过滤

包长度是另一个重要指标。高并发场景下,异常的包大小往往意味着问题。

# 只看大于 1500 字节的包(可能涉及分片)
frame.len > 1500

# 只看小于 64 字节的包(可能是控制包或攻击包)
frame.len < 64

# 看特定长度的 TCP 载荷
tcp.len == 0  # 纯 ACK 包
tcp.len > 1000  # 大数据包

这里有个容易混淆的点:frame.len 是整个帧的长度(包含以太网头部),ip.len 是 IP 包的长度(包含 IP 头部),tcp.len 是 TCP 载荷的长度(不包含 TCP 头部)。

举个例子,一个典型的 HTTP 响应包:

  • frame.len = 1514(以太网帧)
  • ip.len = 1500(IP 包)
  • tcp.len = 1460(TCP 载荷,去掉了 IP 头部 20 字节和 TCP 头部 20 字节)

4.5 知识体系总览

下面这张图把本章的核心知识点串起来了。你可以把它当作一个快速参考地图。

显示过滤器进阶知识体系 显示过滤器进阶 表达式语法 字段名 操作符 值 tcp.port == 443 ip.src != 10.0.0.1 逻辑组合 and (&&) 且 or (||) 或 not (!) 非 ip.src==A and tcp.dst==443 按字段过滤 tcp.port / tcp.srcport ip.addr / ip.src / ip.dst tcp.stream / http.response.code 支持 CIDR 网段过滤 时间/长度过滤 frame.time_relative frame.time_delta frame.len / tcp.len 定位超时与异常包 核心原则:先缩小范围,再精确匹配 高并发分析 = 逻辑组合 + 字段过滤 + 时间/长度维度

4.6 实战组合:一个高并发场景的过滤链

最后,我拿一个真实场景来演示怎么把这些知识串起来。

假设你在分析一个高并发 Web 服务,怀疑有客户端在疯狂重试导致服务器负载飙升。你想找出那些「在短时间内发起大量连接、且频繁重试」的客户端。

过滤链可以这样构建:

# 第一步:只看 TCP 握手包(SYN 包)
tcp.flags.syn == 1 and tcp.flags.ack == 0

# 第二步:加上时间窗口,只看最近 10 秒
frame.time_relative > 10 and frame.time_relative < 20

# 第三步:排除内网健康检查
not ip.src == 10.0.0.0/8

# 第四步:只看目标端口 443
tcp.dstport == 443

# 最终组合
frame.time_relative > 10 and frame.time_relative < 20
and tcp.flags.syn == 1 and tcp.flags.ack == 0
and tcp.dstport == 443
and not ip.src == 10.0.0.0/8

这个过滤器会帮你精准定位到「在 10-20 秒之间,从外网发往 443 端口的所有 SYN 包」。如果某个源 IP 出现了几十次,那它大概率就是问题客户端。

我的习惯:我会把这个长表达式保存成一个过滤按钮(点击过滤器栏左侧的「+」号),下次直接点一下就能用。高并发场景下,时间就是命,能省一秒是一秒。