3、捕获过滤器实战:BPF语法基础、基于IP/端口/协议的捕获过滤、捕获过滤器的局限性
各位好,欢迎来到第三章。前两章我们把Wireshark界面和基础操作捋了一遍,从这章开始,咱们要真正动手抓“对”的包了。
你想想看,在一个繁忙的生产环境里,网卡每秒可能经过成千上万个数据包。如果不加筛选地全抓下来,Wireshark很快就会因为内存爆炸而卡死,你也会被海量无关数据淹没。这时候,捕获过滤器就是你最需要的工具。
3.1 BPF语法:捕获过滤器的灵魂
Wireshark的捕获过滤器,底层用的其实是伯克利包过滤(Berkeley Packet Filter,BPF)语法。说白了,这就是一套让网卡在数据包进入操作系统内存之前,就决定“要不要”的指令集。
我个人习惯把BPF语法拆成三部分来理解:原语(Primitive)、限定词(Qualifier)和逻辑运算符。
- 限定词:告诉过滤器你要看什么。比如
host、net、port、proto。 - ID(标识符):具体的值。比如
192.168.1.1、80、tcp。 - 逻辑运算符:组合多个条件。比如
and、or、not。
核心公式: [限定词] [ID] [逻辑运算符] [限定词] [ID]
举个例子,host 192.168.1.1 and port 80,意思就是“只抓取源或目标IP是192.168.1.1,并且端口是80的流量”。
嗯,这里要注意,BPF语法是大小写敏感的,而且必须用英文半角符号。我曾经见过有同事把 and 写成了 AND,结果过滤器直接报错,抓了半天空包。
3.2 基于IP地址的捕获过滤
这是最常用的场景。你想盯住某台服务器,或者排除某个IP的干扰。
| 需求 | BPF表达式 | 说明 |
|---|---|---|
| 抓取特定主机 | host 10.0.0.5 |
匹配源或目标IP为10.0.0.5 |
| 抓取源IP | src host 10.0.0.5 |
只抓从此IP发出的包 |
| 抓取目标IP | dst host 10.0.0.5 |
只抓发往此IP的包 |
| 排除某个IP | not host 10.0.0.5 |
抓取除了此IP以外的所有流量 |
| 抓取整个网段 | net 192.168.1.0/24 |
抓取该子网内的所有通信 |
我的经验: 在排查DDoS攻击时,我习惯先用 not host 我的管理IP 把自己排除掉,避免SSH会话本身的流量干扰分析。
3.3 基于端口和协议的捕获过滤
很多时候,你只关心某种应用层协议,比如HTTP或DNS。这时候端口过滤就派上用场了。
# 只抓HTTP流量(假设使用标准80端口)
port 80
# 抓取DNS查询和响应
port 53
# 抓取所有HTTPS流量
port 443
# 抓取非标准端口的HTTP(比如8080)
port 8080
你可能会问,为什么不用协议名直接过滤?比如 tcp 或 udp?
其实是可以的。BPF支持直接指定协议类型:
# 只抓TCP包
tcp
# 只抓UDP包
udp
# 只抓ICMP包(比如ping)
icmp
# 抓取非HTTP的TCP流量(排除80端口)
tcp and not port 80
我记得有一次,客户反馈某个应用间歇性断连。我直接用 tcp and port 8080 抓了五分钟,很快就发现了大量的TCP重传和零窗口通告——典型的服务器处理不过来,把客户端“噎住”了。
3.4 组合过滤:逻辑运算符的妙用
单个条件往往不够用。BPF支持 and、or、not 以及括号分组。
# 抓取从192.168.1.10发往任何主机的HTTP或HTTPS流量
src host 192.168.1.10 and (port 80 or port 443)
# 抓取除了DHCP(端口67/68)之外的所有UDP流量
udp and not (port 67 or port 68)
# 抓取两个特定主机之间的所有流量
host 10.0.0.1 and host 10.0.0.2
避坑指南: 我曾经在写复杂表达式时,忘了加括号,导致逻辑优先级出错。比如 host A and port 80 or port 443 会被解释为 (host A and port 80) or port 443,结果抓了一堆无关的443流量。记住,and 优先级高于 or,不确定时就加括号。
3.5 捕获过滤器的局限性
讲到这里,我得给你泼盆冷水。捕获过滤器虽然快,但它有很大的局限性。
第一,它只能做“粗粒度”过滤。 BPF工作在网卡驱动层,它只能看到L2到L4的信息(MAC、IP、端口、协议类型)。你没法用它过滤HTTP的URL、TCP的特定标志位组合,或者某个应用层关键字。
第二,语法表达能力有限。 比如你想抓“TCP SYN包”,用捕获过滤器是做不到的。你得用 tcp[tcpflags] & tcp-syn != 0 这种偏移量写法,但说实话,这已经超出BPF的舒适区了,而且容易写错。
第三,一旦设置错误,可能抓不到任何数据。 因为过滤器是在数据进入系统之前就丢弃了,你没法事后补救。我见过有人把 host 拼成 hose,结果抓了一整天空文件。
| 对比维度 | 捕获过滤器(BPF) | 显示过滤器 |
|---|---|---|
| 工作时机 | 数据包进入内存前 | 数据包已存入内存后 |
| 性能影响 | 极低(硬件/内核级) | 较高(用户态处理) |
| 过滤粒度 | L2-L4(MAC/IP/端口/协议) | L2-L7(可深入应用层) |
| 能否事后修改 | 不能,抓了就是抓了 | 能,随时调整过滤条件 |
| 典型用途 | 减少抓包文件体积,保护磁盘 | 精准定位问题,分析协议细节 |
我的建议: 在不确定该抓什么的时候,宁可用宽泛的捕获过滤器(比如只按IP过滤),也不要过度限制。抓大一点,事后用显示过滤器慢慢筛。磁盘空间比错过关键证据要便宜得多。
3.6 知识体系:BPF捕获过滤器全景图
为了帮你把这一章的知识点串起来,我画了一张图。你可以把它当作一个速查地图。
这张图把BPF的三大块——限定词、逻辑运算符、局限性——都串起来了。你可以把它当作一个速查地图。下次写过滤器之前,先看一眼,思路会清晰很多。