3. 显示过滤器精讲:语法、运算符与实战过滤
显示过滤器,说白了就是Wireshark的灵魂。抓包谁都会,但能从几千个包里快速揪出问题,靠的就是这玩意儿。我刚开始用Wireshark那会儿,也只会点一下菜单栏的“HTTP”过滤,后来发现根本不够用——你想想看,生产环境上流量那么杂,光靠预设按钮哪行?
这一章,咱们就把显示过滤器的底裤扒干净。语法、逻辑运算符、比较运算符,最后拿HTTP、DNS、TCP三个最常见的协议练手。学完这章,你再看那些复杂的过滤表达式,心里就有底了。
核心要点:显示过滤器只改变视图,不改变抓包数据。它就像个筛子,帮你把不关心的流量暂时藏起来。
3.1 显示过滤器语法基础
显示过滤器的语法,其实就三部分:协议、字段、值。写出来大概长这样:
protocol.field operator value
举个例子:
http.request.method == "GET"
这行代码的意思是:只看HTTP协议里,请求方法等于GET的那些包。嗯,就这么简单。
我个人习惯把过滤器分成两类:
- 协议级过滤:直接写协议名,比如
http、dns、tcp。这种过滤会显示该协议的所有包。 - 字段级过滤:精确到某个字段,比如
tcp.port == 80、ip.src == 192.168.1.1。
小技巧:在Wireshark的过滤栏里输入时,它会自动弹出字段提示。你输个“tcp.”,后面所有可用的字段就都列出来了。这功能我天天用,省得去背字段名。
3.2 比较运算符
比较运算符,就是用来做判断的。Wireshark支持下面这些:
| 运算符 | 含义 | 示例 |
|---|---|---|
== |
等于 | ip.src == 10.0.0.1 |
!= |
不等于 | tcp.port != 443 |
> |
大于 | frame.len > 1000 |
< |
小于 | tcp.window_size < 65535 |
>= |
大于等于 | udp.length >= 500 |
<= |
小于等于 | dns.count.queries <= 3 |
contains |
包含子串 | http.user_agent contains "Chrome" |
matches |
正则匹配 | http.host matches "\.(com|cn)$" |
这里我要特别说一下 contains 和 matches。这两个是字符串专用的,不能用在数字上。我曾经排查过一个奇怪的问题——某个客户端发HTTP请求时,User-Agent字段里总带个乱码。用 http.user_agent contains "\x00" 一下子就筛出来了。
注意:字符串值要用双引号包起来,数字不用。另外,matches 用的是Perl兼容正则,性能开销比 contains 大,能不用就别用。
3.3 逻辑运算符
单个条件往往不够用。比如你想看“来自192.168.1.1的HTTP流量”,那就得把两个条件组合起来。逻辑运算符就是干这个的:
| 运算符 | 含义 | 示例 |
|---|---|---|
and 或 && |
与(两个条件都满足) | http and ip.src == 192.168.1.1 |
or 或 || |
或(满足其一即可) | tcp.port == 80 or tcp.port == 443 |
not 或 ! |
非(取反) | not arp |
组合使用时,我建议加括号明确优先级。比如:
(http or dns) and ip.src == 10.0.0.1
这行代码的意思是:只看源IP是10.0.0.1的HTTP或DNS流量。不加括号的话,逻辑顺序可能会乱——Wireshark里 and 的优先级比 or 高,跟大多数编程语言一样。
我的习惯:写复杂过滤时,我会先在记事本里把逻辑理清楚,再贴到Wireshark里。尤其是那种三四层嵌套的,直接在过滤栏里写容易手滑。
3.4 实战过滤:HTTP流量
HTTP是排查Web问题的主力。下面这几个过滤表达式,我几乎每天都会用到:
3.4.1 只看HTTP请求或响应
http.request // 只看请求包
http.response // 只看响应包
3.4.2 过滤特定状态码
http.response.code == 404
http.response.code >= 500
我记得有一次,客户反馈网站间歇性打不开。我抓了包,用 http.response.code >= 500 一筛,发现每隔几分钟就蹦一个502。顺着时间戳往前查,发现是后端代理超时了。
3.4.3 过滤特定URL
http.request.uri contains "/api/v1/login"
http.host == "www.example.com"
3.4.4 过滤请求方法
http.request.method == "POST"
http.request.method in {"GET" "POST"}
in 运算符是Wireshark 2.0之后加的,可以一次匹配多个值。这个我特别喜欢,写起来干净多了。
3.5 实战过滤:DNS流量
DNS排查,说白了就是看域名能不能解析、解析到哪个IP。常用的过滤:
3.5.1 只看DNS查询或响应
dns.flags.response == 0 // 查询包
dns.flags.response == 1 // 响应包
3.5.2 过滤特定域名
dns.qry.name == "www.google.com"
dns.qry.name contains "google"
3.5.3 过滤DNS响应码
dns.flags.rcode != 0 // 非正常响应的DNS包
这里有个坑:DNS响应码为0表示成功,非0表示有错误。比如NXDOMAIN(域名不存在)的响应码是3。我曾经排查过一个DNS劫持问题,用 dns.flags.rcode != 0 筛出来一堆异常响应,发现是内网DNS服务器被篡改了。
3.5.4 只看特定类型的DNS记录
dns.qry.type == 1 // A记录
dns.qry.type == 28 // AAAA记录
dns.qry.type == 15 // MX记录
避坑指南:DNS的字段名容易搞混。dns.qry.name 是查询的域名,dns.resp.name 是响应里的域名。我刚开始就老弄反,后来干脆记成“qry=问什么,resp=答什么”。
3.6 实战过滤:TCP流量
TCP过滤是网络排查的硬功夫。连接建立、数据传输、连接关闭,每一步都可能出问题。
3.6.1 过滤TCP标志位
tcp.flags.syn == 1 // 只含SYN标志的包
tcp.flags.reset == 1 // RST包(连接重置)
tcp.flags.fin == 1 // FIN包(连接关闭)
3.6.2 过滤特定端口
tcp.port == 3306 // MySQL端口
tcp.srcport == 443 // 源端口443
tcp.dstport == 22 // 目标端口22
3.6.3 过滤重传和重复ACK
tcp.analysis.retransmission // 重传包
tcp.analysis.duplicate_ack // 重复ACK
tcp.analysis.fast_retransmission // 快速重传
这些 tcp.analysis 开头的字段,是Wireshark自己分析出来的,不是TCP协议本身带的。它们特别有用——网络有丢包、延迟、乱序,这些字段会直接标出来。
我记得有一次,客户说数据库查询特别慢。我抓了包,用 tcp.analysis.retransmission 一筛,发现重传率高达15%。再查时间线,发现每几秒就有一波重传。最后定位到是中间交换机的一个端口有CRC错误。
3.6.4 过滤TCP流
tcp.stream eq 0 // 只看第0号TCP流
这个 tcp.stream 是Wireshark给每个TCP连接分配的编号。右键一个包 → Follow → TCP Stream,就能看到整个会话的内容。用 tcp.stream eq 0 可以快速定位到某个流。
3.7 本章知识体系
下面这张图,把显示过滤器的核心逻辑串起来了。你可以把它当成一张速查地图:
3.8 避坑总结
最后,把我这些年踩过的坑总结一下:
- 字段名大小写:Wireshark的字段名是大小写敏感的。
http.request.method是对的,HTTP.Request.Method就不行。我建议全部小写。 - 字符串引号:字符串值必须用双引号。单引号不行,不加引号也不行。
- 逻辑优先级:
and比or优先级高。不确定时就加括号。 - 性能问题:
matches和contains比==慢。在大流量环境下,能用==就别用正则。 - tcp.analysis 字段:这些是Wireshark分析出来的,不是协议自带的。如果抓包文件不完整,这些字段可能不准确。
嗯,显示过滤器这块,说白了就是多练。你可以在自己的电脑上抓个包,把今天学的表达式挨个试一遍。试完你就会发现——原来排查网络问题,可以这么爽。