过滤的艺术:Wireshark显示过滤器语法详解
说实话,抓包这件事,百分之八十的功夫不在抓,而在过滤。你想想看,一个线上故障,网卡上每秒几千个包,眼睛看花了也找不到问题。我刚开始用Wireshark那会儿,就吃过这个亏——抓了一大堆数据,结果在列表里翻来翻去,啥也没看出来。
后来我明白了,显示过滤器就是你的第二双眼睛。用好了,几秒钟就能锁定目标。今天我就把这套过滤的功夫,掰开了揉碎了讲给你听。
核心认知:捕获过滤器是“拦路虎”,在数据进门之前就筛掉;显示过滤器是“显微镜”,在已捕获的数据中精准定位。排错时,我几乎只用显示过滤器——因为你不确定哪些包有用,先全抓下来再说。
4.1 基础过滤:从地址和端口开始
先讲最常用的几个过滤字段。这些你每天都会用到,记牢了能省一半时间。
ip.addr —— 只看某个IP的通信
这个字段最常用,也最容易踩坑。我直接说结论:
ip.addr == 192.168.1.100
这条过滤会显示所有包含该IP的包——不管它是源地址还是目标地址。我个人习惯用这个,因为排错时我关心的是“这个IP参与的所有通信”。
但如果你只想看某个方向,就得用更精确的写法:
ip.src == 192.168.1.100 # 只看这个IP发出的包
ip.dst == 192.168.1.100 # 只看发给这个IP的包
我曾经踩过的坑:有一次排查DNS问题,我用 ip.addr == 8.8.8.8 过滤,结果发现包特别少。折腾了半天才发现,DNS请求是发往8.8.8.8没错,但响应包是从另一个IP回来的(用了DNS转发)。所以记住:ip.addr 匹配的是“包含”,不是“等于两端”。
tcp.port —— 锁定应用层协议
端口过滤是定位应用层问题的利器。比如看HTTP:
tcp.port == 80 || tcp.port == 443
嗯,这里要注意,tcp.port 同样匹配源端口和目标端口。如果你想精确控制方向:
tcp.srcport == 80 # 源端口是80(通常是服务端响应)
tcp.dstport == 80 # 目标端口是80(通常是客户端请求)
我一般在排错时这么用:先 tcp.port == 3306 看MySQL通信,再根据情况细化。说白了,端口过滤是快速缩小范围的第一刀。
4.2 应用层过滤:直击问题本质
基础过滤只能看到“谁在和谁说话”,应用层过滤才能看到“他们在说什么”。
http.request —— 只看HTTP请求
这个字段特别实用。比如你想看某个URL的请求:
http.request.uri contains "/api/login"
或者只看GET请求:
http.request.method == "GET"
我在项目中遇到过一个问题:前端说接口返回慢,后端说没收到请求。我抓包后用 http.request 过滤,发现请求确实发出了,但TCP层有重传——原来是中间某个交换机丢了包。如果没有这个过滤,我可能还在那翻几百个包呢。
dns.qry.name —— 精准定位DNS查询
DNS问题排查,这个字段是王牌:
dns.qry.name == "www.example.com"
如果你想看某个域名的所有DNS记录:
dns.qry.name contains "example.com"
小技巧:用 dns.flags.response == 0 只看查询请求,dns.flags.response == 1 只看响应。配合 dns.qry.name 使用,效果翻倍。
4.3 逻辑运算符:把过滤条件串起来
单个条件往往不够用。你需要把多个条件组合起来,才能精准定位。
| 运算符 | 写法 | 含义 | 示例 |
|---|---|---|---|
| 与 | and 或 && |
两个条件都满足 | ip.addr == 10.0.0.1 and tcp.port == 80 |
| 或 | or 或 || |
满足任一条件 | tcp.port == 80 or tcp.port == 443 |
| 非 | not 或 ! |
排除满足条件的包 | not arp |
举个例子,我想看 192.168.1.100 的HTTP通信,但排除健康检查的请求:
ip.addr == 192.168.1.100 and tcp.port == 80 and not http.request.uri contains "/health"
你看,三个条件串起来,一下子就精确了。
4.4 过滤链构建:从模糊到精确
真正的排错高手,不会一上来就写复杂的过滤条件。我一般分三步走:
- 粗筛:用
ip.addr或tcp.port锁定通信双方 - 细筛:用应用层字段缩小范围
- 精筛:用逻辑运算符组合条件,排除干扰
比如排查一个“网页加载慢”的问题:
# 第一步:看这个IP的所有通信
ip.addr == 10.0.0.5
# 第二步:只看HTTP
ip.addr == 10.0.0.5 and tcp.port == 80
# 第三步:只看某个资源的请求,排除图片等静态资源
ip.addr == 10.0.0.5 and tcp.port == 80 and http.request.uri contains "/api" and not http.request.uri contains ".jpg"
我的习惯:在Wireshark的显示过滤器栏里,我从来不会一次性输入长串条件。我会先在脑子里想清楚“我要看什么”,然后从粗到细逐步添加。每加一个条件,看一眼结果,确认方向对不对。
下面这张图,是我自己总结的过滤链构建逻辑:
4.5 避坑指南:我踩过的那些坑
最后分享几个实战中容易犯的错误:
- 大小写问题:Wireshark的字段名是大小写敏感的。
http.request是对的,HTTP.Request就不行。我刚开始时经常在这上面浪费时间。 - 引号的使用:字符串值必须用双引号,比如
http.request.method == "GET"。数字和布尔值不用,比如tcp.port == 80。 - contains vs ==:
==是精确匹配,contains是包含匹配。比如dns.qry.name contains "google"会匹配所有包含google的域名,而==只匹配完全一致的。 - 括号的使用:多个逻辑条件组合时,用括号明确优先级。比如
(ip.addr == 10.0.0.1 or ip.addr == 10.0.0.2) and tcp.port == 80,不加括号结果可能完全不一样。
我的建议:在Wireshark的过滤栏里输入时,每输入一个字段,留意一下语法高亮。如果字段名变成红色,说明写错了。这个功能很贴心,别忽略它。