3. 显示过滤器:从入门到实战
抓包就像给网络做CT扫描。原始数据包是海量的,你不可能一个个翻。显示过滤器,就是帮你从这堆数据里精准捞出问题的那把手术刀。
我个人习惯,抓包时先全量抓,然后用显示过滤器慢慢筛。这比抓包前设一堆捕获过滤器要灵活得多。今天我们就把它彻底讲透。
3.1 显示过滤器语法基础
显示过滤器的核心语法其实很简单:协议.字段 运算符 值。就这么个结构,但组合起来威力巨大。
# 基本格式
协议.字段 运算符 值
# 实际例子
ip.src == 192.168.1.1
tcp.port == 80
http.request.method == "GET"
这里要注意,字段名是大小写敏感的。比如 tcp.port 写成 TCP.Port 就匹配不到。我曾经在排查一个DNS延迟问题时,就因为大小写写错,浪费了半小时。
| 运算符 | 含义 | 示例 |
|---|---|---|
| == | 等于 | ip.src == 10.0.0.1 |
| != | 不等于 | ip.src != 10.0.0.1 |
| > | 大于 | frame.len > 1500 |
| < | 小于 | tcp.window_size < 65535 |
| contains | 包含子串 | http.user_agent contains "Chrome" |
| matches | 正则匹配 | http.host matches "\.(com|cn)$" |
Ctrl+Space 可以自动补全字段名。这个快捷键我每天用几十次。
3.2 逻辑运算符:组合你的过滤条件
单个条件往往不够用。比如你想看「从192.168.1.1发往80端口」的包,就需要组合条件。逻辑运算符就是干这个的。
# 与运算 (and / &&)
ip.src == 192.168.1.1 and tcp.dstport == 80
# 或运算 (or / ||)
tcp.port == 80 or tcp.port == 443
# 非运算 (not / !)
not arp
# 括号分组
(ip.src == 192.168.1.1 or ip.src == 192.168.1.2) and tcp.port == 443
嗯,这里要注意优先级。括号的优先级最高,然后是 not,接着是 and,最后是 or。我建议你拿不准的时候,直接用括号把条件包起来,清晰又安全。
实战场景: 排查Web服务器慢的问题时,我经常这样用:
http.time > 1 and ip.dst == 10.0.0.10
这能快速找出所有响应时间超过1秒的HTTP请求,而且只关注目标服务器。
3.3 字段匹配:深入协议内部
显示过滤器真正的威力,在于它能匹配协议字段的任意层级。你想想看,从二层MAC地址,到七层HTTP的Cookie,都能直接过滤。
3.3.1 二层与三层过滤
# MAC地址过滤
eth.addr == 00:1a:2b:3c:4d:5e
eth.src == 00:1a:2b:3c:4d:5e
# IP地址过滤
ip.addr == 192.168.1.1 # 同时匹配源和目标
ip.src == 192.168.1.0/24 # CIDR掩码也支持
# VLAN过滤
vlan.id == 100
3.3.2 四层传输层过滤
# TCP标志位过滤
tcp.flags.syn == 1 # 只显示SYN包
tcp.flags.reset == 1 # 只显示RST包
tcp.analysis.retransmission # 显示重传包
# UDP过滤
udp.port == 53 # DNS查询
# 端口范围
tcp.port >= 1024 and tcp.port <= 65535
tcp.flags.reset == 1 过滤RST包,结果发现很多正常的连接关闭也会产生RST。后来才意识到,需要结合 tcp.flags.ack == 0 来区分是主动RST还是被动RST。细节决定成败。
3.3.3 七层应用层过滤
# HTTP
http.request.method == "POST"
http.response.code == 404
http.content_type contains "json"
# DNS
dns.qry.name contains "example.com"
dns.flags.response == 0 # 只显示查询请求
# TLS/SSL
tls.handshake.type == 1 # Client Hello
tls.handshake.extensions_server_name contains "api"
3.4 过滤表达式复用:别重复造轮子
实际工作中,有些过滤条件你会反复用。比如排查数据库慢查询时,我每次都要过滤MySQL的慢查询日志。每次都重新敲一遍?太傻了。
3.4.1 保存为过滤按钮
Wireshark允许你把常用的过滤表达式保存为按钮,一键切换。
- 点击过滤栏左侧的「书签」图标
- 选择「管理显示过滤器」
- 输入名称和表达式,点击「新建」
- 以后直接点击按钮就能应用
3.4.2 使用配置文件
更高级的做法,是把过滤表达式写在配置文件里。这样换电脑、换环境都能直接导入。
# 在 Wireshark 的配置文件目录下
# Windows: %APPDATA%\Wireshark\dfilter
# Linux/Mac: ~/.config/wireshark/dfilter
# 文件内容示例
# 名称: 数据库慢查询
# 表达式: mysql.time > 1
#
# 名称: HTTP错误
# 表达式: http.response.code >= 400
3.4.3 命令行复用
如果你用tshark(Wireshark的命令行版),可以把过滤表达式写在脚本里。
#!/bin/bash
# 分析TCP重传的脚本
FILTER="tcp.analysis.retransmission or tcp.analysis.fast_retransmission"
tshark -r capture.pcap -Y "$FILTER" -T fields -e ip.src -e ip.dst -e tcp.port
3.5 显示过滤器知识体系
下面这张图,是我自己总结的显示过滤器知识体系。你可以把它当作一个快速索引。
3.6 实战:一个完整的排查案例
最后,我分享一个真实案例。有一次线上告警,用户反馈页面加载慢。我抓包后,用显示过滤器一步步定位。
# 第一步:只看HTTP请求
http
# 第二步:过滤出响应时间超过2秒的
http.time > 2
# 第三步:看看是哪些资源慢
http.request.uri contains ".js" and http.time > 2
# 第四步:确认是哪个服务器
ip.dst == 10.0.0.20 and http.time > 2
# 第五步:检查是否有TCP重传
tcp.analysis.retransmission and ip.dst == 10.0.0.20
最终发现,是一个JS文件因为CDN回源超时,导致TCP重传不断。整个过程,从抓包到定位,用了不到10分钟。显示过滤器就是你的探照灯,照到哪里,问题就现形到哪里。