第4章:显示过滤器——语法与使用技巧
显示过滤器,说白了就是你在Wireshark里输入的那串表达式。它能帮你从海量数据包里,精准揪出你想要的那几个。跟捕获过滤器不一样——那个是在抓包之前就决定要什么,而这个是抓完了以后,在结果里再筛选。
我个人习惯,抓包的时候尽量多抓,抓全了,等分析阶段再用显示过滤器慢慢“筛”。为什么呢?因为有时候原始数据里藏着意想不到的线索,你一开始就把它过滤掉,后面可能就找不回来了。这个教训,我是吃过亏的。
4.1 基本语法
显示过滤器的核心语法,其实就两样东西:协议 和 字段。
- 直接输入协议名:比如
http、tcp、dns。Wireshark就会把包含该协议的数据包显示出来。 - 字段引用:用点号访问协议内部的字段。比如
ip.src表示源IP地址,tcp.port表示TCP端口。 - 比较操作:
==(等于)、!=(不等于)、>(大于)、<(小于)、>=(大于等于)、<=(小于等于)。
简单吧?你试试在过滤器栏里输入 http,看看是不是只剩HTTP包了。
4.2 构建表达式——从入门到实战
光知道协议名不够,你得学会“精准定位”。比如我只想看某个IP的HTTP流量:
http and ip.addr == 192.168.1.100
这里 and 就是逻辑与。意思就是:满足是HTTP协议,同时IP地址是这个的包,都给我出来。
你可能会问:为什么用 ip.addr 而不是 ip.src 或 ip.dst?ip.addr 的意思是“源或目的任意一个匹配”,这个在排查双向通信时特别方便。我曾经遇到过一个场景:客户端向服务器发请求正常,服务器回包客户端收不到。用 ip.addr == 192.168.1.100 一把抓出来,再按响应时间排序,问题立马就定位到了——服务器回包被中间防火墙截了。
4.3 字段类型与匹配
Wireshark里的字段类型很多,用的最多的就这几种:
| 类型 | 示例 | 说明 |
|---|---|---|
| 整数 | tcp.port == 443 |
直接比较数值 |
| IP地址 | ip.addr == 10.0.0.1 |
自动解析为IPv4或IPv6 |
| 字符串 | http.host contains "example" |
模糊匹配,contains 是关键 |
| 布尔值 | tcp.flags.syn == 1 |
只显示SYN标志位为1的包 |
| 正则 | http.user_agent matches "Mozilla.*" |
用 matches 写正则 |
这里我特别想强调一下 contains 和 matches 的区别。contains 是“包含子串”,效率高;matches 是“正则匹配”,灵活但慢。如果你只是想看某个字段里有没有特定关键词,用 contains 就够了。我曾经遇到一个同事,查个简单的字符串非要用 matches,结果过滤一下等了好几分钟。那批数据包有十几个G,正则跑起来确实吃力。
4.4 逻辑运算符——组合你的条件
一个条件不够用?那就用逻辑运算符把它们串起来:
and(&&):两个条件同时满足or(||):满足其中一个就行not(!):取反xor:异或,少用,但有时候很巧妙
举个例子:我想看DNS请求,但是排除掉本地回环地址的查询:
dns and not ip.addr == 127.0.0.1
再比如,我想看局域网内两台机器之间的HTTP通信,不论谁是客户端:
http and (ip.addr == 192.168.1.10 or ip.addr == 192.168.1.20)
注意,括号很重要,它决定了运算的优先级。我见过不少新手把 or 和 and 搞混,结果过滤出来的包完全不是自己想要的。你想想看,没有括号的话,http and ip.addr == 192.168.1.10 or ip.addr == 192.168.1.20 会被理解成:(http and ip.addr == 192.168.1.10) or ip.addr == 192.168.1.20。这结果可不是你期望的吧?
4.5 函数与计算字段
Wireshark的显示过滤器其实支持一些简单的函数,这些在高级排查场景下非常实用:
| 函数 | 说明 | 示例 |
|---|---|---|
upper() |
将字符串转为大写后再比较 | upper(http.request.method) == "GET" |
lower() |
转为小写 | lower(http.host) contains "example" |
len() |
计算字段长度(字节数) | len(udp) > 100 |
count() |
统计满足条件的包数量 | 常用于统计视图,不过筛选也能用 |
举个实际场景:排查DNS响应过大的情况。正常情况下DNS响应很小,但如果有人用DNS隧道传输数据,响应包会很大。这时候:
dns and len(udp) > 500
就能帮你快速锁定异常的DNS流量。
len() 计算的是字段在协议层中的实际长度,不是应用层数据大小。比如 len(udp) 是整个UDP报文的长度,包含头部和数据。如果你只想要数据部分,得用 udp.length 这个字段。
4.6 常用显示过滤器模式速查
这些是我在实际工作中总结出来的“高频筛法”,你直接拿去用:
- 只看三次握手包:
tcp.flags.syn == 1 or tcp.flags.fin == 1 or tcp.flags.reset == 1 - 过滤特定MAC地址的广播:
eth.addr == ff:ff:ff:ff:ff:ff - 排除所有ARP包:
not arp(这个在分析网络问题时经常用) - 只看HTTP POST请求:
http.request.method == "POST" - 寻找重传包:
tcp.analysis.retransmission - 按端口过滤应用层:
tcp.port == 3306 or udp.port == 3306(MySQL)
4.7 避坑指南
好了,前面说了这么多技巧,现在我得跟你聊聊那些“看似简单但一用就翻车”的地方。
ip.addr 是个集合字段,包里有多个IP地址时(比如隧道包、VLAN包),一个条件可能会匹配到多个值。比如 ip.addr != 192.168.1.1 的意思是“包里的某个IP地址不等于192.168.1.1”,而不是“包里的所有IP地址都不等于192.168.1.1”。这俩差别可大了。
我曾经花了一整个下午查一个网络故障,怎么过滤都不对劲。后来发现就是这个坑——我想删除掉某个IP的包,结果因为包里有多个IP地址,条件永远为真,等于没过滤。
http.request.method == "get" 是匹配不到 GET 的。用 upper() 或者 lower() 可以解决。
坑三:协议嵌套。 比如你在一个IP隧道里又封装了IP,这时候 ip.addr 会同时匹配外层和内层的IP地址。如果你只想匹配内层,得用 ip.inner.addr 或者根据具体协议结构来。不过这种情况比较少见,一般只有在分析VPN或隧道流量时才会遇到。
嗯,说了这么多,其实核心就一句话:知道你想要的字段叫什么,然后用正确的逻辑把它们组织起来。Wireshark的显示过滤器虽然功能强大,但语法本身并不复杂,多练几次就熟了。
你可以用Wireshark自带的“表达式”对话框(在过滤器栏旁边那个“…”按钮)来辅助构建条件。我刚开始用的时候也是全靠它,后来慢慢记住了常用字段,就很少再去点了。