第4章 Wireshark高级过滤表达式归纳总结
说实话,过滤表达式才是Wireshark的核心战斗力。你想想看,抓包谁都会,但要从成千上万个报文里精准定位问题,靠的就是过滤表达式。我刚开始用Wireshark那会儿,觉得界面花哨就行,后来才发现——嗯,过滤表达式玩得转,才算真正入门。
4.1 显示过滤器 vs 捕获过滤器
这两个东西,说白了就是「抓的时候过滤」和「抓完之后过滤」的区别。很多人一开始搞混它们的位置:捕获过滤器写在抓包界面顶部的输入框里,显示过滤器写在报文列表上方的输入框里。
| 对比维度 | 捕获过滤器 | 显示过滤器 |
|---|---|---|
| 语法基础 | BPF (Berkeley Packet Filter) | Wireshark Display Filter |
| 作用时机 | 抓包时,丢弃不匹配的包 | 抓包后,隐藏不匹配的包 |
| 性能开销 | 低(内核级过滤) | 高(用户级过滤) |
| 是否可逆 | 不可逆,丢弃的包无法恢复 | 可逆,只是隐藏 |
| 支持函数 | 不支持 | 支持 |
| 示例 | host 10.0.0.1 and port 80 | ip.addr == 10.0.0.1 and tcp.port == 80 |
我个人习惯是:抓包时用捕获过滤器,只抓我关心的流量,减少文件体积;分析时用显示过滤器,反复调整条件深挖细节。我记得有一次抓生产环境的问题,没用捕获过滤器,结果抓了1GB的包,光打开就卡了半天——从那以后我就学乖了。
4.2 逻辑运算符与比较表达式
过滤表达式离不开逻辑组合。Wireshark支持三种基本逻辑,也可以用符号表达:
- and (&&):同时满足两个条件
- or (||):满足其中一个条件
- not (!):取反,排除某些条件
- 括号 ():改变优先级,让表达式更清晰
比较运算符速查
== 等于 · != 不等于 · > 大于 · < 小于 · >= 大于等于 · <= 小于等于 · contains 包含 · matches 正则匹配
举个实际例子:(tcp.port == 80 or tcp.port == 443) and ip.src == 192.168.1.1。我个人习惯用括号把条件分组,可读性会好很多。你想想看,一长串表达式如果不加括号,优先级搞混了,结果就完全不对了。
4.3 协议专用过滤表达式
每个协议都有自己的专用过滤字段。我整理了几个最常用的:
| 协议 | 过滤表达式 | 说明 |
|---|---|---|
| HTTP | http.host == "example.com" | 按主机名过滤HTTP请求 |
| HTTP | http.request.uri contains "/api" | 过滤API接口请求 |
| TCP | tcp.port == 443 | 过滤HTTPS流量 |
| TCP | tcp.flags.syn == 1 | 只看SYN包(三次握手第一步) |
| IP | ip.addr == 10.0.0.1 | 过滤某个IP的所有流量 |
| DNS | dns.qry.name contains "google" | 过滤包含特定域名的DNS查询 |
之前排查一个OAuth登录问题,我就是用 http.host == "login.example.com" and http.request.method == "POST" 精准定位到认证请求的。如果没有协议专用字段,想在几千个包里找到那个请求,真的很痛苦。
4.4 过滤函数与计算操作
Wireshark提供了一些内置函数,用来对字段做变换或统计:
- upper(field) / lower(field):大小写转换,解决大小写敏感问题
- len(field):取字段长度,比如过滤超长URL
- count(field):统计字段出现次数
- string(field):将字段转为字符串
比如你要过滤URL路径超过100个字符的请求:len(http.request.uri) > 100。我记得有一次分析恶意软件的网络行为,就是用 len(http.host) > 50 找到那些随机生成的长域名请求——正常网站哪有那么长的域名,对吧?
4.5 实战过滤组合案例
光讲语法太枯燥,直接上实战场景。这些组合表达式,我建议你自己动手敲一遍——嗯,光看是记不住的。
- 查找某个IP所有的HTTP 500错误
http.response.code >= 500 and ip.addr == 10.0.0.1 - 分析TCP三次握手失败
tcp.flags.syn == 1 and tcp.flags.ack == 0 and not tcp.flags.syn == 0 - 过滤非HTTPS的明文HTTP请求
http and not tcp.port == 443 - 查找DNS查询中返回NXDOMAIN的域名
dns.flags.rcode == 3(3表示域名不存在) - 定位某个时间段内的TCP重传
tcp.analysis.retransmission and ip.addr == 192.168.1.100
小技巧: 在Wireshark里输入过滤表达式时,按下 Tab 键可以自动补全字段名。这个功能很多人不知道,但真的很省时间。
4.6 常见陷阱与避坑指南
过滤表达式看起来简单,实际用起来坑不少。我总结几个最常见的:
- ip.addr 的陷阱:很多人以为
ip.addr == 10.0.0.1只过滤源IP或目的IP,实际上它同时匹配两者。如果你只想过滤源IP,用ip.src == 10.0.0.1;只想过滤目的IP,用ip.dst == 10.0.0.1。我在项目中被这个坑过一次,查了半天才发现过滤结果里多了一堆不相关的包。 - tcp.port 同理:
tcp.port == 80同时匹配源端口和目的端口。严格区分的话,用tcp.srcport和tcp.dstport。 - 大小写敏感:字段名是大小写敏感的。
http.host是对的,HTTP.HOST就不行。不过字段值是否敏感取决于协议本身。 - 引号的使用:字符串值要用双引号引起来,比如
http.host == "www.example.com"。数字和布尔值不用引号。
避坑提醒: 我曾经因为大小写问题折腾了半小时——写了个