抓包过滤器:捕获过滤器语法、BPF表达式、常见过滤场景
好,咱们进入第二章。上一章我们聊了Wireshark能干什么,这一章直接上手——怎么只抓你想要的数据。
你想想看,一个线上服务器,每秒几千上万个包。全抓下来?别说分析,光存盘就能把磁盘撑爆。我见过不少新手,一上来就点"Start",结果抓了10秒,文件几个G,然后对着茫茫多的包发呆。
所以,抓包之前,先学会过滤。
捕获过滤器 vs 显示过滤器
很多人搞混这两个概念。我简单说清楚:
| 对比项 | 捕获过滤器 | 显示过滤器 |
|---|---|---|
| 作用时机 | 抓包之前,决定哪些包进内存 | 抓包之后,从已抓到的包中筛选 |
| 语法 | BPF(Berkeley Packet Filter) | Wireshark专有语法(更丰富) |
| 性能影响 | 直接减少抓包量,节省CPU和磁盘 | 只影响显示,不减少已抓数据 |
| 典型场景 | 只抓某IP、某端口、某协议 | 深入分析时按字段过滤 |
核心原则:捕获过滤器是"守门员",显示过滤器是"筛子"。能用捕获过滤器挡掉的流量,就别让它进门。
BPF表达式——捕获过滤器的灵魂
捕获过滤器用的是BPF语法。说白了,就是一套简洁的表达式,告诉内核:哪些包我要,哪些包扔掉。
BPF表达式的基本结构:
[protocol] [direction] [host/port/net] [logical operator] [expression]
嗯,看着有点抽象。咱们直接看例子。
最常用的几个BPF表达式
- 按主机过滤
host 192.168.1.100—— 只抓这个IP的流量
src host 10.0.0.1—— 只抓源IP为10.0.0.1的包
dst host 172.16.0.1—— 只抓目的IP为172.16.0.1的包 - 按端口过滤
port 80—— 抓所有80端口的流量
src port 443—— 源端口443
dst port 53—— 目的端口53(DNS查询) - 按协议过滤
arp—— 只抓ARP包
icmp—— 只抓ICMP包(ping)
tcp—— 只抓TCP包
udp—— 只抓UDP包 - 按网络段过滤
net 192.168.0.0/16—— 抓整个C类网段
src net 10.0.0.0/8—— 源地址在10.0.0.0/8内
逻辑组合
单个条件不够用?组合起来:
host 192.168.1.100 and port 80
src host 10.0.0.1 or src host 10.0.0.2
tcp and not port 22
(host 192.168.1.100 or host 192.168.1.101) and port 443
我的习惯:复杂表达式一定要加括号。BPF的优先级有时候跟你想的不一样。我曾经在线上排查问题时,写了个 host 10.0.0.1 or host 10.0.0.2 and port 80,结果抓了半天发现少了数据——因为 and 优先级高于 or,实际生效的是 host 10.0.0.1 or (host 10.0.0.2 and port 80)。从那以后,我所有组合表达式都加括号。
常见过滤场景实战
理论说完了,咱们直接上场景。这些都是我工作中反复用到的。
场景一:排查Web服务器慢
用户反馈网站加载慢,你想看HTTP请求和响应:
tcp port 80 or tcp port 443
如果只想看某个客户端的请求:
host 203.0.113.50 and tcp port 80
场景二:DNS解析异常
域名解析失败,只看DNS流量:
udp port 53
或者连TCP的DNS也一起抓(大响应会走TCP):
port 53
场景三:数据库连接问题
MySQL默认端口3306,只看数据库流量:
tcp port 3306
如果是PostgreSQL(5432)或Redis(6379),换端口号就行。
场景四:抓某个网段的全部流量
公司内网192.168.1.0/24段有异常广播,全抓:
net 192.168.1.0/24
场景五:排除干扰流量
服务器上SSH连接很多,你不想抓SSH的包:
not port 22
或者排除所有远程管理端口:
not (port 22 or port 3389 or port 5900)
BPF进阶:直接操作包偏移量
有些场景,标准的关键字不够用。比如你想抓TCP SYN包(三次握手的第一个包),标准BPF没有"syn"关键字。怎么办?
直接操作包偏移量:
tcp[13] & 2 != 0
解释一下:TCP头部第13个字节是标志位,SYN对应的bit是第2位(从0开始数)。tcp[13] & 2 != 0 的意思是:取TCP头第13字节,与2做按位与,结果不为0——说明SYN位被置1。
类似的:
tcp[13] & 16 != 0—— ACK包tcp[13] & 1 != 0—— FIN包tcp[13] & 18 != 0—— SYN+ACK包(16+2)
注意:偏移量表达式写起来灵活,但可读性差。我建议只在标准关键字搞不定的时候才用。另外,不同协议头部长度不同,算偏移量之前一定要确认协议头结构。
捕获过滤器的常见坑
我踩过的坑,列出来给你避雷:
- 坑一:忘了写协议
port 80默认匹配TCP和UDP。如果你只想抓TCP的80端口,写成tcp port 80。 - 坑二:大小写敏感
BPF关键字是小写的。TCP不行,必须tcp。AND不行,必须and。 - 坑三:VLAN标签影响偏移量
如果网络中有VLAN,包头部会多4个字节。这时候tcp[13]就不准了。需要写成vlan and tcp[13]或者用tcp[17]。 - 坑四:捕获过滤器不支持"或"的简写
不能写port 80 or 443,必须写port 80 or port 443。
知识体系总览
下面这张图,把本章的核心逻辑串起来了:
写在过滤器上的建议
最后,分享几个我自己的经验:
- 先想清楚再抓。 别上来就抓。花30秒想清楚:我要排查什么问题?需要看哪些流量?然后写对应的过滤器。
- 过滤器宁紧勿松。 条件写严一点,抓少了可以再抓。抓多了,文件太大,分析起来反而慢。
- 保存常用过滤器。 Wireshark支持保存过滤器模板。我把常用的几个(Web、DNS、MySQL、ping)都存成了预设,用的时候直接选。
- 测试过滤器。 不确定表达式对不对?在Wireshark的捕获过滤器输入框里敲完,点旁边的"Compile BPF"按钮,能编译通过就说明语法没问题。
一个小技巧:如果你在图形界面不方便,可以用命令行工具 tcpdump 先试过滤器。tcpdump和Wireshark的捕获过滤器语法完全一样。我在服务器上排查问题时,经常先用tcpdump抓几秒钟看看效果,确认过滤器对了,再开Wireshark做深度分析。