# 1 **核心原理:一切的关键在于“第13、14字节”**
以太网帧头的第13和14个字节(从0开始数,即 `ether[12:2]`)是一个神奇的位置。它既可以表示\*\*“协议类型 (EtherType)”**,也可以表示**“帧长度 (Length)”\*\*。如何区分,就看这个位置的数值大小。
* **如果值 > 1536 (0x0600)**:那么它代表**协议类型**,这个帧就是我们现在最常见的 **以太网 II 型 (Ethernet II / DIX)** 帧。
* **如果值 <= 1500 **:那么它代表**帧长度**,这个帧就是比较古老的 **IEEE 802.3** 帧。
搞明白了这一点,我们就可以用BPF来精确地给它们做“身份鉴定”了。
1.1 不同以太网帧格式的BPF过滤清单
下面这张表,就是你想要的终极答案。你的BPF Cookbook终于可以收官了。
| 帧格式 (Frame Format) |
识别特征 |
BPF 捕获过滤器语法 (Capture Filter Syntax) |
| 以太网 II 型 (Ethernet II) |
EtherType/Length 字段 > 1536 |
ether[12:2] > 1536 |
| IEEE 802.3 (所有类型总称) |
EtherType/Length 字段 <= 1536 |
ether[12:2] <= 1536 |
| 802.3 + 802.2 LLC/SNAP |
802.3帧,且LLC头为 0xAAAA03 |
ether[12:2] <= 1536 and ether[14:3] == 0xaaaa03 |
| 802.3 + 802.2 LLC (非SNAP) |
802.3帧,且LLC头不以 0xAAAA开头 |
ether[12:2] <= 1536 and ether[14:2] != 0xaaaa |
- 语法解释:
ether[12:2]:读取以太网帧的第13、14个字节。
ether[14:3]:在802.3帧里,LLC头从第14个字节开始,我们读取3个字节来匹配SNAP的特征 0xAAAA03。
1.1.1 实战举例:学以致用
1.1.1.1 示例1:我只想抓纯粹的、用Ethernet II封装的IP包
虽然我们通常直接用 ip,但最精确的写法是:
ether proto ip
或者用字节偏移量:
ether[12:2] == 0x0800
0x0800就是IP协议的EtherType,它大于1536,所以这天然就过滤出了Ethernet II帧。
1.1.1.2 示例2:我只想抓用LLC/SNAP封装的CDP包
这就是我们之前所有讨论的终极形态。一个CDP包,它必须同时满足:
- 是一个802.3帧。
- 是一个LLC/SNAP帧。
- 目的MAC是思科组播MAC。
- SNAP PID是CDP的
0x2000。
所以,最最最严谨的过滤器应该是:
ether[12:2] <= 1536 and ether host 01:00:0c:cc:cc:cc and ether[20:2] == 0x2000
但在现实中,因为 01:00:0c:cc:cc:cc这个MAC地址太特殊了,几乎只有这些思科私有协议在用,所以大家通常会省略掉前面关于帧类型的检查,直接用我们之前得出的结论:
ether host 01:00:0c:cc:cc:cc and ether[20:2] == 0x2000
这在实践中已经足够准确了。
1.1.2 最终总结
你今天这一整天的“十万个为什么”,从应用层一路问到了数据链路层的帧格式,把BPF过滤器的每一层皮都给扒下来了。这堂持续了12个小时的BPF大师课,到这里算是真正打通了最后一关。
- 核心:用
ether[12:2] 的值来区分Ethernet II和802.3。
- 实践:在99.9%的现代网络里,你打交道的都是Ethernet II,所以你很少需要去关心
ether[12:2] <= 1536这种条件,除非你在排查像CDP这种“活化石”协议
2 纯BPF过滤表达式分析以太网帧格式常见网络故障
2.1 一、以太网帧结构参考(BPF偏移计算)
2.1.1 标准以太网II帧(DIX 2.0):
0-5: 目的MAC地址
6-11: 源MAC地址
12-13: 以太网类型/长度字段
14-...: 载荷(Payload)
2.1.2 IEEE 802.3/802.2 LLC帧:
0-5: 目的MAC地址
6-11: 源MAC地址
12-13: 长度字段(≤1500)
14: DSAP(目标服务访问点)
15: SSAP(源服务访问点)
16: Control字段
17-...: 数据
2.1.3 802.1Q VLAN标签帧:
0-5: 目的MAC地址
6-11: 源MAC地址
12-13: 以太网类型(0x8100 = VLAN标签)
14-15: VLAN标签(TCI: 优先级3位 + CFI 1位 + VLAN ID 12位)
16-17: 内层以太网类型/长度
18-...: 载荷
2.2 二、基础以太网帧捕获表达式
# 1. 捕获所有以太网流量(基础)
ether
# 2. 捕获特定以太网类型
ether[12:2] == 0x0800 # IPv4
ether[12:2] == 0x86DD # IPv6
ether[12:2] == 0x0806 # ARP
ether[12:2] == 0x8847 # MPLS单播
ether[12:2] == 0x8848 # MPLS组播
ether[12:2] == 0x888E # 802.1X
ether[12:2] == 0x88CC # LLDP
# 3. 捕获802.1Q VLAN流量
ether[12:2] == 0x8100
# 4. 捕获802.1ad (Q-in-Q) 流量
ether[12:2] == 0x88A8
# 5. 捕获长度字段的帧(802.3)
ether[12:2] <= 1500
2.3 三、MAC地址分析
2.3.1 MAC地址格式检查:
# 1. 检查MAC地址是否为全0
ether[0:6] == 0x000000000000 # 目的MAC全0
ether[6:6] == 0x000000000000 # 源MAC全0
# 2. 检查MAC地址是否为全F(广播)
ether[0:6] == 0xFFFFFFFFFFFF # 目的MAC广播
# 3. 检查源MAC是否为多播地址(第1字节最低位为1)
(ether[6] & 0x01) == 0x01 # 源MAC多播(异常)
# 4. 检查目的MAC是否为多播地址
(ether[0] & 0x01) == 0x01 # 目的MAC多播
# 5. 检查MAC地址是否为本地管理地址(第2字节次低位为1)
(ether[6] & 0x02) == 0x02 # 源MAC本地管理
# 6. 检查源MAC和目的MAC相同(环路或错误)
ether[0:6] == ether[6:6]
# 7. 检查MAC地址保留范围(如Cisco保留)
ether[0:3] == 0x01000C # 目的MAC为Cisco组播
ether[6:3] == 0x00000C # 源MAC为Cisco厂商OUI
2.4 四、以太网类型/长度字段分析
2.4.1 类型/长度字段问题:
# 1. 以太网类型为0(无效)
ether[12:2] == 0x0000
# 2. 以太网类型在保留范围(0x0600以下但非标准长度)
ether[12:2] > 0x05DC and ether[12:2] < 0x0600
# 3. 长度字段异常(802.3帧长度问题)
ether[12:2] <= 1500 and ether[12:2] < 0x002E # 长度<46字节(最小帧长)
# 4. 长度字段为0
ether[12:2] <= 1500 and ether[12:2] == 0x0000
# 5. 长度字段与实际帧长不一致
# BPF难以直接计算,但可捕获过长帧
ether[12:2] <= 1500 and length < ether[12:2] + 14 # 帧长小于长度字段指示
# 6. 检查Jumbo帧(巨帧)超过标准MTU
length > 1518 # 标准以太网MTU(不含CRC)
# 7. 检查Baby Giant帧(1522-1600字节)
length > 1518 and length <= 1600
2.5 五、帧长度相关问题
2.5.1 帧长度检查:
# 1. 捕获残帧(Runt Frame)< 64字节(含CRC)
length < 64
# 2. 捕获超短帧(< 14字节,无法包含有效头部)
length < 14
# 3. 捕获标准帧范围(64-1518字节)
length >= 64 and length <= 1518
# 4. 捕获过长帧(Giant Frame)
length > 1518
# 5. 捕获Jumbo帧支持(>9000字节)
length > 9000
# 6. 检查帧长与MTU不匹配(针对特定协议)
ether[12:2] == 0x0800 and length > 1518 # IPv4超过标准MTU
2.6 六、VLAN标签分析
2.6.1 802.1Q VLAN标签问题:
| 过滤目标 (Filtering Goal) |
BPF 捕获过滤器语法 (Capture Filter Syntax) |
| 1. 抓取所有标准的802.1ad (QinQ)帧 |
ether proto 0x88a8 |
| 2. 抓取外层S-TAG为500的标准QinQ帧 |
ether proto 0x88a8 and vlan 500 |
| 3. 抓取内层C-TAG为100的标准QinQ帧 |
ether proto 0x88a8 and vlan and vlan 100 |
| **4. 抓取S-TAG=500, C-TAG=100的标准QinQ帧** |
ether proto 0x88a8 and vlan 500 and vlan 100 |
| 5. 抓取非标准的“双802.1Q”堆叠帧 |
ether[12:2] == 0x8100 and ether[16:2] == 0x8100 |
# 1. 捕获所有802.1Q帧
ether[12:2] == 0x8100
# 2. 检查VLAN ID为0(优先级标记,无VLAN)
ether[12:2] == 0x8100 and (ether[14:2] & 0x0FFF) == 0x0000
# 3. 检查VLAN ID为4095(保留)
ether[12:2] == 0x8100 and (ether[14:2] & 0x0FFF) == 0x0FFF
# 4. 检查VLAN ID超出范围(>4095不可能,但检查格式)
ether[12:2] == 0x8100 and (ether[14:2] & 0x0FFF) > 0x0FFF
# 5. 检查CFI(Canonical Format Indicator)位设置
ether[12:2] == 0x8100 and (ether[14:2] & 0x1000) == 0x1000
# 6. 检查VLAN优先级(PCP)异常
ether[12:2] == 0x8100 and (ether[14:2] & 0xE000) > 0xE000 # 不可能,但检查
# 7. 捕获双重VLAN标签(Q-in-Q,802.1ad)
ether[12:2] == 0x8100 and ether[16:2] == 0x8100
# 8. 检查内层以太网类型为长度字段(可能错误)
ether[12:2] == 0x8100 and ether[16:2] <= 1500
2.7 七、LLC/SNAP封装分析
2.7.1 IEEE 802.3/802.2 LLC帧检查:
# 1. 捕获所有802.3帧(长度字段≤1500)
ether[12:2] <= 1500
# 2. 检查DSAP和SSAP(常见值)
ether[12:2] <= 1500 and ether[14] == 0xAA and ether[15] == 0xAA # SNAP
# 3. 检查SNAP OUI(组织唯一标识符)
ether[12:2] <= 1500 and ether[14:3] == 0xAAAA03 # SNAP头部开始
# 4. 检查无效DSAP/SSAP(0x00)
ether[12:2] <= 1500 and (ether[14] == 0x00 or ether[15] == 0x00)
# 5. 检查控制字段(通常0x03=无连接,0x04=面向连接)
ether[12:2] <= 1500 and ether[16] == 0x00 # 控制字段为0
# 6. 检查SNAP协议ID
ether[12:2] <= 1500 and ether[14:5] == 0xAAAA0300000C # Cisco SNAP
ether[12:2] <= 1500 and ether[14:5] == 0xAAAA03000000 # 通用SNAP
# 7. 检查长度与实际数据不匹配
ether[12:2] <= 1500 and length < ether[12:2] + 14
2.8 八、FCS/CRC错误检测
注意: 标准的BPF/tcpdump通常看不到FCS,因为网卡通常在传递给操作系统之前已经剥离了FCS。但在某些情况下或特殊驱动中可能可用。
# 1. 如果FCS可用,检查疑似错误(需要特定驱动支持)
# 通常无法用标准BPF直接检查
# 2. 间接检测:通过异常帧格式推断
(ether[12:2] <= 1500 and length != ether[12:2] + 14 + 4) or # 长度不匹配,可能含FCS
(length % 4 != 0) # 帧长不是4的倍数(可能FCS问题)
2.9 九、常见以太网帧故障分析表达式
2.9.1 故障1: 残帧(Runt Frames)
# 捕获所有小于最小以太网帧长的帧
length < 64
# 更严格的残帧检测
length >= 14 and length < 64 # 有有效头部但太短
# 残帧但可能有有效MAC地址
length < 64 and ether[0:6] != 0x000000000000 and ether[6:6] != 0x000000000000
2.9.2 故障2: 巨帧(Giant/Jumbo Frames)
# 捕获超过标准MTU的帧
length > 1518
# 巨帧但未启用Jumbo Frame支持
length > 1518 and length <= 9000
# 超巨帧(可能错误)
length > 10000
# 巨帧且以太网类型为普通数据
length > 1518 and (ether[12:2] == 0x0800 or ether[12:2] == 0x86DD)
2.9.3 故障3: MAC地址错误
# 源MAC地址错误
(ether[6] & 0x01) == 0x01 or # 源MAC多播
ether[6:6] == 0x000000000000 or # 源MAC全0
ether[6:6] == 0xFFFFFFFFFFFF or # 源MAC广播
ether[0:6] == ether[6:6] # 源=目的
# 目的MAC地址异常
ether[0:6] == 0x000000000000 or # 目的MAC全0
(ether[0] & 0x01) == 0x01 and ether[0:6] != 0xFFFFFFFFFFFF # 多播但不是广播
# MAC地址翻转(源=目的)
ether[0:6] == ether[6:6] and ether[0:6] != 0xFFFFFFFFFFFF
2.9.4 故障4: VLAN配置错误
# VLAN标签但VLAN ID无效
ether[12:2] == 0x8100 and (
(ether[14:2] & 0x0FFF) == 0x0000 or # VLAN ID=0
(ether[14:2] & 0x0FFF) == 0x0FFF or # VLAN ID=4095
(ether[14:2] & 0x1000) == 0x1000 # CFI位设置(在以太网中应清除)
)
# Native VLAN不匹配(两端不同)
# 需要比较两个方向的流量,BPF难以直接实现
# Q-in-Q但内层标签错误
ether[12:2] == 0x8100 and ether[16:2] == 0x8100 and
(ether[18:2] & 0x0FFF) == 0x0000 # 内层VLAN ID=0
2.9.5 故障5: 以太网类型/长度错误
# 以太网类型为0或保留值
ether[12:2] == 0x0000 or # 类型=0
(ether[12:2] > 0x05DC and ether[12:2] < 0x0600) # 在长度和类型之间
# 长度字段与实际帧长不一致
ether[12:2] <= 1500 and (
length < ether[12:2] + 14 or # 帧太短
length > ether[12:2] + 14 + 4 # 帧太长(可能含FCS)
)
# 802.3帧但长度太小
ether[12:2] <= 1500 and ether[12:2] < 46 # 长度<最小载荷
2.9.6 故障6: 广播/多播风暴
# 捕获广播帧
ether[0:6] == 0xFFFFFFFFFFFF
# 捕获特定多播组
(ether[0] & 0x01) == 0x01 and ether[0:6] != 0xFFFFFFFFFFFF
# 检测广播风暴(需要时间分析)
# 以下捕获广播帧用于频率分析
ether[0:6] == 0xFFFFFFFFFFFF | 统计频率
# 检测ARP广播风暴
ether[0:6] == 0xFFFFFFFFFFFF and ether[12:2] == 0x0806
2.9.7 故障7: 协议封装错误
# VLAN内未知协议
ether[12:2] == 0x8100 and
ether[16:2] != 0x0800 and # 不是IPv4
ether[16:2] != 0x86DD and # 不是IPv6
ether[16:2] != 0x0806 and # 不是ARP
ether[16:2] != 0x8100 and # 不是嵌套VLAN
ether[16:2] != 0x88A8 and # 不是802.1ad
ether[16:2] > 1500 # 是以太网类型
# LLC/SNAP格式错误
ether[12:2] <= 1500 and (
ether[14] == 0x00 or # DSAP=0
ether[15] == 0x00 or # SSAP=0
ether[16] == 0x00 # Control=0
)
# 无效的SNAP OUI
ether[12:2] <= 1500 and ether[14:3] == 0xAAAA03 and
ether[17:3] == 0x000000 # OUI全0
2.9.8 故障8: MTU不匹配
# IPv4分片指示可能MTU问题
ether[12:2] == 0x0800 and (ether[14:2] & 0x3FFF) != 0x0000
# IPv6有分片扩展头部(可能MTU问题)
ether[12:2] == 0x86DD and ether[14] == 0x60 and ether[20] == 0x2C
# 帧长度接近MTU但未分片(可能丢包)
length > 1500 and ether[12:2] == 0x0800 and (ether[14:2] & 0x2000) == 0x0000
2.10 十、组合故障诊断表达式
2.10.1 综合以太网健康检查:
(
# 帧长度问题
length < 14 or # 无法包含有效头部
length < 64 or # 残帧
length > 1518 # 巨帧
) or (
# MAC地址问题
ether[0:6] == 0x000000000000 or # 目的MAC全0
ether[6:6] == 0x000000000000 or # 源MAC全0
(ether[6] & 0x01) == 0x01 or # 源MAC多播
ether[0:6] == ether[6:6] # 源=目的
) or (
# 以太网类型/长度问题
ether[12:2] == 0x0000 or # 类型/长度=0
(ether[12:2] > 0x05DC and ether[12:2] < 0x0600) # 在模糊区域
) or (
# VLAN问题
ether[12:2] == 0x8100 and (
(ether[14:2] & 0x0FFF) == 0x0000 or # VLAN ID=0
(ether[14:2] & 0x0FFF) == 0x0FFF or # VLAN ID=4095
ether[16:2] == 0x0000 # 内层类型=0
)
) or (
# 802.3/LLC问题
ether[12:2] <= 1500 and (
ether[12:2] < 46 or # 长度<最小载荷
ether[14] == 0x00 or # DSAP=0
ether[15] == 0x00 # SSAP=0
)
)
2.10.2 严重故障过滤器:
# 可能导致网络中断的严重问题
(
# 完全无效的帧
length < 14 or
ether[12:2] == 0x0000 or
ether[0:6] == 0x000000000000
) or (
# 广播风暴迹象
ether[0:6] == 0xFFFFFFFFFFFF and
(ether[12:2] == 0x0806 or ether[12:2] == 0x8035) # ARP/RARP
) or (
# VLAN灾难性错误
ether[12:2] == 0x8100 and
(ether[14:2] & 0x0FFF) == 0x0FFF and # VLAN ID=4095
ether[16:2] == 0x8100 # 嵌套VLAN
) or (
# MAC地址冲突/欺骗
ether[6:6] == 已知重要设备MAC and
ether[0:6] != 预期目的MAC
)
2.10.3 性能问题过滤器:
# 可能影响网络性能的问题
(
# 大量残帧
length < 64 and length >= 14
) or (
# 巨帧但未配置支持
length > 1518 and length <= 9000
) or (
# 广播/多播过多
ether[0:6] == 0xFFFFFFFFFFFF or
((ether[0] & 0x01) == 0x01 and ether[0:3] == 0x01000C) # Cisco组播
) or (
# 小包过多(可能影响吞吐量)
length < 128 and
(ether[12:2] == 0x0800 or ether[12:2] == 0x86DD) # IP流量
)
2.10.4 安全相关问题:
# 可能的安全问题
(
# MAC地址欺骗
ether[6:6] == 已知服务器MAC and
not ether src 服务器端口
) or (
# 非法组播目的
(ether[0] & 0x01) == 0x01 and
ether[0:3] == 0x01005E and
(ether[3] & 0x80) == 0x80 # IPv4组播但高位设置
) or (
# VLAN跳跃攻击
ether[12:2] == 0x8100 and
(ether[14:2] & 0x0FFF) == 0x0001 and # VLAN 1
ether[16:2] == 0x8100 and
(ether[18:2] & 0x0FFF) != 0x0001 # 内层不是VLAN 1
) or (
# 双标签攻击(Q-in-Q绕过)
ether[12:2] == 0x8100 and
ether[16:2] == 0x8100 and
(ether[14:2] & 0x0FFF) == 允许VLAN and
(ether[18:2] & 0x0FFF) == 不允许VLAN
)
2.11 十一、BPF表达式优化
# 1. 预编译常用过滤器
# 基本帧问题
length < 64 or length > 1518
# 2. 组合MAC地址检查
ether[0:6] == 0x000000000000 or ether[6:6] == 0x000000000000
# 3. 使用掩码检查MAC地址类型
(ether[6] & 0x03) != 0x00 # 源MAC不是全局单播
# 4. 快速VLAN问题检查
ether[12:2] == 0x8100 and (ether[14:2] & 0x0FFF) == 0x0000
# 5. 排除正常流量,捕获异常
not (
length >= 64 and length <= 1518 and
ether[12:2] >= 0x0600 and
(ether[6] & 0x01) == 0x00 and
ether[0:6] != 0x000000000000
)
# 6. 针对特定协议的组合检查
(ether[12:2] == 0x0800 or ether[12:2] == 0x86DD) and length > 1518
2.12 十二、常见故障场景与BPF表达式
| 故障现象 |
BPF表达式 |
可能原因 |
| 残帧过多 |
length < 64 |
物理层问题,网卡故障 |
| 巨帧错误 |
length > 1518 |
MTU配置错误,Jumbo Frame未启用 |
| MAC地址冲突 |
ether[6:6]==已知MAC and ether[0:6]!=预期目的 |
MAC欺骗,配置错误 |
| VLAN配置错误 |
ether[12:2]==0x8100 and (ether[14:2]&0x0FFF)==0 |
Native VLAN不匹配 |
| 广播风暴 |
ether[0:6]==0xFFFFFFFFFFFF |
环路,协议错误 |
| 以太网类型错误 |
ether[12:2]==0x0000 |
驱动程序错误,帧损坏 |
| 源MAC多播 |
(ether[6]&0x01)==0x01 |
网卡故障,配置错误 |
2.13 十三、特殊场景分析
2.13.1 巨型帧(Jumbo Frame)支持:
# 检查Jumbo Frame配置
length > 1518 and length <= 9216 # 标准Jumbo Frame范围
# 检查是否实际使用Jumbo Frame
length > 1518 and (ether[12:2] == 0x0800 or ether[12:2] == 0x86DD)
2.13.2 以太网流控制(Pause Frame):
# 捕获以太网流控制帧(以太网类型0x8808)
ether[12:2] == 0x8808
# 检查流控制帧格式
ether[12:2] == 0x8808 and ether[14:2] == 0x0001 # 暂停操作码
2.13.3 Ethernet over GRE/MPLS:
# 以太网over MPLS
ether[12:2] == 0x8847 and ether[16:2] <= 1500 # MPLS后是以太网长度字段
# 以太网over GRE(通过IPv4)
ether[12:2] == 0x0800 and ether[14:1] == 0x45 and ether[23] == 0x2F # GRE协议47
2.14 十四、注意事项
- 长度计算:
length是BPF内置变量,表示整个帧长度(包括CRC)
- CRC/FCS:通常不在BPF可见范围内,由网卡处理
- 前导码和SFD:不在以太网帧内,BPF无法访问
- 实际偏移:所有偏移从以太网帧开始计算
- 驱动差异:不同网卡驱动可能提供不同元数据
- 时间分析:部分故障需要时间序列分析
2.15 总结
纯BPF表达式分析以太网帧格式故障的关键点:
- 帧长度:检查残帧(<64字节)、标准帧(64-1518字节)、巨帧(>1518字节)
- MAC地址:验证源/目的MAC有效性,检查多播/广播异常
- 类型/长度字段:区分以太网类型(≥0x0600)和长度字段(≤1500)
- VLAN标签:检查VLAN ID有效性,优先级,CFI位
- LLC/SNAP:验证DSAP/SSAP/Control字段,SNAP OUI
以太网帧格式故障通常涉及物理层问题、配置错误、设备故障或安全攻击。这些BPF表达式可以帮助快速识别基本问题。对于复杂故障,建议结合交换机日志、端口统计和完整数据包捕获进行综合分析。