4. Wireshark 过滤表达式入门归纳总结

抓包不难,难的是从成千上万个包里找到你要的那几个。

我的经验是,刚入门的同事常常盯着满屏的绿色、蓝色数据包发愣——这跟大海捞针没区别。其实 Wireshark 提供了两套过滤器:捕获过滤器和显示过滤器。搞懂它们,你才算真正入了门。

4.1 两类过滤器的核心区别

先别急着背语法。我先问一个问题:你是想在抓包之前就丢掉不关心的流量,还是抓完包之后再用条件筛选?

前者叫捕获过滤器,后者叫显示过滤器。我在项目里见过不少人把两者混着用,结果要么漏包,要么机器卡死。咱们用一张表说清楚:

对比维度 捕获过滤器 显示过滤器
作用时机 抓包前,网卡一侧就开始过滤 抓包后,对已保存的包过滤显示
丢弃的包 直接丢弃,不可恢复 包仍在文件里,只是隐藏
语法风格 类 BPF (Berkeley Packet Filter) 类 C 语言表达式
性能 高,适合高流量环境 中等,取决于文件大小
典型场景 抓 TLS 握手时排除其他流量 从已有文件里定位特定握手失败
我的习惯:在现网环境做长时间抓包时,我会先用捕获过滤器只保留 TCP 443 端口,免得抓出几十 GB 的文件把自己搞崩溃。离线分析时再用显示过滤器慢慢抠细节。

4.2 显示过滤器的基本功

坦白讲,显示过滤器才是我们日常用得最多的。你只要在 Wireshark 顶部那个带绿色/红色背景的输入框里敲表达式,回车就能看到结果。

4.2.1 协议层过滤

最直接的写法:直接输协议名。

tls
http
dns
arp

注意,输入 tls 会显示所有携带 TLS 协议的数据包,但不限于握手包。如果你只想看握手包,可以加条件:

tls.handshake.type == 1   // Client Hello
tls.handshake.type == 2   // Server Hello
tls.handshake.type == 11  // Certificate
tls.handshake.type == 16  // Encrypted Extensions

4.2.2 IP 和端口过滤

这个太常用了。比如你想看某个服务器跟客户端的交互:

ip.addr == 192.168.1.100
ip.src == 10.0.0.1 && ip.dst == 10.0.0.2
tcp.port eq 443
udp.portrange 8000-8100

坑:ip.addr == 192.168.1.100 匹配源或目标任一地址。如果你只想要源地址,必须写 ip.src。我曾经因为这个写错,把服务器回包误认为客户端流量,排查了半天才发现。

4.2.3 组合条件与逻辑运算

Wireshark 支持 and、or、not、() 括号分组:

tls and ip.addr == 192.168.1.1
tcp.port == 443 or tcp.port == 80
not icmp
(tls.handshake.type == 1) and (tls.handshake.cipher_suites contains 0x1301)

这里 contains 操作符非常实用,能匹配字节序列或字符串。比如想找特定密码套件:

tls.handshake.cipher_suites contains 0x1301   // TLS_AES_128_GCM_SHA256

避坑指南:我曾经用 tls.handshake.cipher_suites == 0x1301 想找单个套件,结果没反应。为什么?因为 cipher_suites 字段是个列表,不是单值。必须用 contains 或 == 配合位置索引。细节决定成败。

4.3 捕获过滤器的实战用法

捕获过滤器用的是 BPF 语法,写在 Wireshark 捕获选项的输入框里。它的写法更精简,但限制也更多——不能深入协议字段。

host 192.168.1.1
port 443
tcp port 443 and host 10.0.0.1
not arp and not icmp
ether host aa:bb:cc:dd:ee:ff

我以前遇到过一个问题:在交换机镜像端口抓包时,流量里混杂了大量 LLDP 和 STP 包。只加一条 not stp and not lldp,捕获文件体积立刻缩小 70%。

注意:捕获过滤器不支持 tls.handshake.type 这种高层字段。它只工作在二层到四层。如果你需要针对 TLS 握手阶段做精准捕获,只能用显示过滤器或者先用捕获过滤器缩小范围,再慢慢分析。

4.4 过滤表达式核心逻辑一览

我把两种过滤器的关系画成一张图,方便你整体记忆:

Wireshark 过滤器分类与表达式核心逻辑 捕获过滤器 (Capture Filter) 显示过滤器 (Display Filter) BPF 语法 主机/端口/协议 表达式语法 字段/逻辑符 host 10.0.0.1 tcp port 443 tls.handshake.type ip.addr == ... 选择原则:高流量场景优先用捕获过滤器缩小范围, 定位细节时使用显示过滤器精确匹配。 高手会用 && 替代 and,用 || 替代 or,但并不推荐——可读性太差,队友看不懂 提示:在过滤器输入框按 Tab 可自动补全字段名,绿色背景表示语法正确,红色表示错误

4.5 快速定位 TLS 握手故障的过滤套路

说到具体场景,我分享几个我常用的“组合拳”:

  1. 只看完整的握手过程:
    tls.handshake.type and tcp.stream eq 42
    先用 tcp.stream 找到一条 TCP 连接,再过滤出握手包。
  2. 找握手失败:
    tls.alert_message and tcp.stream eq 42
    Alert 消息往往紧接着握手失败出现,一眼就能看到差错原因。
  3. 查看服务器证书链:
    tls.handshake.type == 11 and ip.addr == 服务器IP
    只看 Certificate 消息,右键 → Follow TLS Stream 可以导出证书。
  4. 分析密码套件协商:
    tls.handshake.type == 2 and tls.handshake.cipher_suite
    在 Server Hello 里查看服务端最终选定的套件。

我的小技巧:别死记硬背字段名。在 Wireshark 里随便点开一个 TLS 包,展开每一层,右键你想过滤的字段,选择“Apply as Filter → Selected”,表达式会自动生成。非常省力。

4.6 常见错误与调试方法

你想想看,输入表达式后显示红色背景,是不是很烦?别慌,多半是以下几种情况:

  • 字段名拼错了。比如把 tls.handshake 写成 tls.hanshake。Wireshark 不会自动纠错,它会认为这是一个不存在的字段。
  • 类型不匹配。字符串字段不能用 == 跟数字比,反之亦然。比如 tls.handshake.cipher_suite == "0x1301" 就错了,数字不用加引号。
  • 忘记括号优先级。tls and ip.src == 1.1.1.1 or ip.dst == 2.2.2.2 会被解析成 (tls and ip.src == 1.1.1.1) or ip.dst == 2.2.2.2。如果你希望括号是 tls and (ip.src == 1.1.1.1 or ip.dst == 2.2.2.2),必须自己加括号。

调试方法很简单:把你要过滤的字段单独拎出来测试。比如先输 tls.handshake.type == 1,确认能出包,再慢慢加上其他条件。

注意:捕获过滤器一旦写成,无法修改正在进行的抓包。你必须停止捕获,修改语法,再重新开始。显示过滤器可以随时改,随时看结果。所以除非你很确定自己要抓什么,否则我建议先用显示过滤器。

4.7 小结

过滤表达式是 Wireshark 技能树里的基本功,也是最高频使用的功能。我个人觉得,只要把捕获和显示两套体系分清楚,再记住几个常用字段和逻辑符,日常抓包分析基本够用了。

你后续在分析 TLS 握手故障时,第一个动作一定是:打开过滤器,输入 tls.handshake.type,按回车。然后慢慢加条件缩小范围。