抓包过滤器:捕获过滤器语法、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。

知识体系总览

下面这张图,把本章的核心逻辑串起来了:

捕获过滤器知识体系 捕获过滤器 BPF表达式语法 过滤条件类型 逻辑组合 protocol direction host port net and / or / not 括号分组 常见场景:Web排查 | DNS异常 | 数据库问题 | 网段监控 | 排除干扰 进阶:偏移量操作(tcp[13] & 2)

写在过滤器上的建议

最后,分享几个我自己的经验:

  • 先想清楚再抓。 别上来就抓。花30秒想清楚:我要排查什么问题?需要看哪些流量?然后写对应的过滤器。
  • 过滤器宁紧勿松。 条件写严一点,抓少了可以再抓。抓多了,文件太大,分析起来反而慢。
  • 保存常用过滤器。 Wireshark支持保存过滤器模板。我把常用的几个(Web、DNS、MySQL、ping)都存成了预设,用的时候直接选。
  • 测试过滤器。 不确定表达式对不对?在Wireshark的捕获过滤器输入框里敲完,点旁边的"Compile BPF"按钮,能编译通过就说明语法没问题。

一个小技巧:如果你在图形界面不方便,可以用命令行工具 tcpdump 先试过滤器。tcpdump和Wireshark的捕获过滤器语法完全一样。我在服务器上排查问题时,经常先用tcpdump抓几秒钟看看效果,确认过滤器对了,再开Wireshark做深度分析。