tcpdump指南:从基础抓包到 BPF 高级过滤与生产实战

📌 本文亮点:覆盖 tcpdump 全部核心知识点------常用选项速查、BPF 过滤语法从入门到字节偏移高级用法、TCP 标志位精准抓包、生产环境抓包策略与性能优化,附速查表一键收藏!

前言

网络排障时,你是否遇到过这些问题:服务明明收到了请求却返回 RST?DNS 解析偶尔超时却不知道查询是否发出?线上疑似 SYN 洪水却无从确认?tcpdump 是解决这些问题的第一利器,但很多人只会 tcpdump -i eth0,面对高流量环境手足无措,过滤表达式写不对、抓包丢包、pcap 文件撑爆磁盘。

本文从零基础 出发,系统梳理 tcpdump 的完整知识体系,重点攻克 BPF 过滤语法这一核心技能,最终给出生产环境可直接复用的命令模板。


一、基础概念与安装

1.1 tcpdump 是什么

tcpdump 是基于 libpcap 的命令行网络数据包抓取工具,能够捕获流经网络接口的原始数据包,打印到终端或写入 .pcap 文件,是网络诊断、安全分析和协议调试的必备工具。

💡 核心优势 :BPF 过滤器在内核层面生效,只有匹配的数据包才会到达用户空间,高流量环境下过滤极为高效。

1.2 安装方式

bash 复制代码
# Debian/Ubuntu
sudo apt install tcpdump

# RHEL/CentOS
sudo yum install tcpdump

# macOS(通常已预装)
brew install tcpdump

# Alpine
apk add tcpdump

二、基本语法与常用选项

2.1 语法结构

bash 复制代码
tcpdump [选项] [BPF 过滤表达式]

2.2 接口选择

接口相关选项:

选项 说明 示例
-i <接口> 指定监听接口 tcpdump -i eth0
-i any 监听所有接口 tcpdump -i any
-D 列出可用接口 tcpdump -D

⚠️ -i any 是 Linux 的伪接口,不支持混杂模式。如需看到所有流量(不仅是单播到本机的),请指定具体物理接口。

2.3 抓包控制

抓包行为控制选项:

选项 说明 示例
-c <数量> 抓取 N 个包后停止 tcpdump -c 100
-s <字节数> 每包抓取长度(snaplen) tcpdump -s 0(全量)
-w <文件> 写入 pcap 文件 tcpdump -w capture.pcap
-r <文件> 读取 pcap 文件 tcpdump -r capture.pcap
-C <MB> 文件大小限制,自动轮转 tcpdump -C 100 -w capture.pcap
-W <数量> 轮转文件最大数量 tcpdump -C 100 -W 10 -w capture.pcap
-G <秒> 按时间轮转文件 tcpdump -G 3600 -w cap_%Y%m%d.pcap

2.4 输出格式

输出显示控制选项:

选项 说明 示例
-n 不解析主机名 tcpdump -n
-nn 不解析主机名和端口名 tcpdump -nn
-v / -vv / -vvv 递增详细度 tcpdump -vvv
-q 简洁输出 tcpdump -q
-t 不打印时间戳 tcpdump -t
-tttt 可读日期格式 tcpdump -tttt
-e 显示以太网头(MAC) tcpdump -e
-X 十六进制 + ASCII tcpdump -X
-XX 包含以太网头的十六进制 tcpdump -XX
-A ASCII 输出(适合 HTTP) tcpdump -A
-S 绝对 TCP 序列号 tcpdump -S
-l 行缓冲(可管道) tcpdump -l
-U 包缓冲(实时刷新) tcpdump -U

💡 黄金法则 :生产环境永远加 -nn,禁止 DNS 反解,避免卡顿和额外流量。


三、BPF 过滤语法(核心技能)

3.1 过滤原语一览

BPF(Berkeley Packet Filter)是 tcpdump 过滤的引擎,由原语组合而成:

原语 说明 示例
host 按主机 IP host 192.168.1.1
src host 源主机 src host 10.0.0.5
dst host 目的主机 dst host 10.0.0.5
net 按网段 net 192.168.0.0/24
port 按端口 port 80
src port 源端口 src port 443
dst port 目的端口 dst port 53
portrange 端口范围 portrange 8000-8100
ether host 按 MAC 地址 ether host aa:bb:cc:dd:ee:ff

3.2 协议快捷过滤

bash 复制代码
tcpdump tcp            # 所有 TCP 流量
tcpdump udp            # 所有 UDP 流量
tcpdump icmp           # 所有 ICMP(ping)
tcpdump arp            # 所有 ARP
tcpdump ip6            # 所有 IPv6

3.3 逻辑组合(and / or / not)

bash 复制代码
# AND ------ 两个条件同时匹配
tcpdump 'host 192.168.1.1 and port 80'
tcpdump 'tcp and src port 443 and dst host 10.0.0.1'

# OR ------ 任一条件匹配
tcpdump 'port 80 or port 443'
tcpdump 'host 192.168.1.1 or host 192.168.1.2'

# NOT ------ 排除
tcpdump 'not port 22'
tcpdump 'not arp and not icmp'

# 复合表达式(用引号包裹)
tcpdump 'tcp port 5432 and not host 10.0.0.99'
tcpdump 'port 53 and (udp or tcp)'

⚠️ 含空格或特殊字符的过滤表达式必须用单引号 包裹,防止 shell 解析 &|() 等符号。


四、TCP 标志位过滤

TCP 标志位于 TCP 头部第 14 字节(偏移 13),是诊断连接问题的利器。

4.1 使用命名标志(推荐)

bash 复制代码
# SYN 包(连接建立请求)
tcpdump 'tcp[tcpflags] & tcp-syn != 0'

# ACK 包
tcpdump 'tcp[tcpflags] & tcp-ack != 0'

# RST 包(连接重置/拒绝)
tcpdump 'tcp[tcpflags] & tcp-rst != 0'

# FIN 包(连接关闭)
tcpdump 'tcp[tcpflags] & tcp-fin != 0'

# PSH 包(推送数据)
tcpdump 'tcp[tcpflags] & tcp-push != 0'

# 纯 SYN(SYN=1, ACK=0)------ 新连接请求
tcpdump 'tcp[tcpflags] & tcp-syn != 0 and not tcp[tcpflags] & tcp-ack != 0'

# SYN-ACK(服务端响应)
tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0'

# 连接状态变化包(SYN + FIN + RST)
tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) != 0'

4.2 使用位掩码(底层方式)

TCP 标志位掩码对照:

标志 位值 说明
FIN 0x01 连接关闭
SYN 0x02 连接建立
RST 0x04 连接重置
PSH 0x08 推送数据
ACK 0x10 确认
URG 0x20 紧急
bash 复制代码
tcpdump 'tcp[13] & 2 != 0'     # SYN
tcpdump 'tcp[13] & 16 != 0'    # ACK
tcpdump 'tcp[13] & 18 != 0'    # SYN-ACK
tcpdump 'tcp[13] & 1 != 0'     # FIN
tcpdump 'tcp[13] & 4 != 0'     # RST
tcpdump 'tcp[13] & 8 != 0'     # PSH

五、BPF 字节偏移高级过滤

5.1 通用语法

复制代码
proto[offset:size] operator value
  • protoipip6tcpudpicmparpether
  • offset:协议头部内的字节偏移
  • size1(字节)、2(短整型)、4(整型)
  • operator=!=<<=>>=&

5.2 IP 头部过滤

bash 复制代码
# TTL 小于 10(经过很多跳)
tcpdump 'ip[8] < 10'

# IP 协议号过滤
tcpdump 'ip[9] = 6'       # TCP(协议号 6)
tcpdump 'ip[9] = 17'      # UDP(协议号 17)
tcpdump 'ip[9] = 1'       # ICMP(协议号 1)
tcpdump 'ip[9] = 50'      # ESP/IPsec(协议号 50)

# IP 包总长度
tcpdump 'ip[2:2] > 1400'  # 大于 1400 字节
tcpdump 'ip[2:2] < 64'    # 小于 64 字节

# 带 IP 选项的包(IHL > 5)
tcpdump 'ip[0] & 0x0f > 5'

# DSCP EF(Expedited Forwarding)
tcpdump 'ip[1] >> 2 = 46'

5.3 ICMP 类型过滤

bash 复制代码
tcpdump 'icmp[0] == 8'    # Echo Request(ping 请求)
tcpdump 'icmp[0] == 0'    # Echo Reply(ping 响应)
tcpdump 'icmp[0] == 3'    # Destination Unreachable(目标不可达)
tcpdump 'icmp[0] == 11'   # Time Exceeded(路由超时/Traceroute)

5.4 包大小过滤

bash 复制代码
tcpdump 'greater 1400'    # 包长度 >= 1400
tcpdump 'less 64'         # 包长度 <= 64
tcpdump 'len > 1000'      # 包长度 > 1000

5.5 HTTP 载荷匹配

bash 复制代码
# 抓取 HTTP GET 请求("GET " = 0x47455420)
tcpdump -A 'tcp dst port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'

# 抓取 HTTP POST 请求("POST" = 0x504f5354)
tcpdump -A 'tcp dst port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354'

# 抓取 HTTP 响应("HTTP" = 0x48545420)
tcpdump -A 'tcp src port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48545420'

六、VLAN 与隧道过滤

6.1 VLAN 过滤

bash 复制代码
# 任意 VLAN 标签帧
tcpdump 'vlan'

# 指定 VLAN ID
tcpdump 'vlan 10'

# QinQ(VLAN 200 嵌套在 VLAN 100 内)
tcpdump 'vlan 100 and vlan 200'

# VLAN 内的 IPv4 流量
tcpdump 'vlan and ip'

⚠️ BPF 中 vlan 关键字会改变解码偏移 ,表达式中 vlan 应放在前面。

6.2 隧道封装过滤

bash 复制代码
# VXLAN
tcpdump 'vxlan 0x7'              # VNI 7

# Geneve
tcpdump 'geneve 0xb'             # VNI 0xb

# MPLS
tcpdump 'mpls 100000'            # MPLS 标签 100000
tcpdump 'mpls 100000 and mpls 1024'  # 两层 MPLS 标签栈

# PPPoE
tcpdump 'pppoes'                 # 任意 PPPoE 会话
tcpdump 'pppoes 0x27 and ip'    # PPPoE 会话 0x27 + IPv4

七、实战场景示例

7.1 Web 流量分析

bash 复制代码
# 抓取所有 HTTP/HTTPS 流量
tcpdump -nn -i eth0 'tcp port 80 or tcp port 443'

# 实时查看 HTTP 请求内容(ASCII)
tcpdump -nn -A -i eth0 'tcp port 80'

# 只抓 HTTP 数据包(排除纯 SYN/FIN/ACK)
tcpdump -nn -i eth0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

# 保存到文件供 Wireshark 分析
tcpdump -nn -s 0 -w http.pcap -i eth0 'tcp port 80 or tcp port 443'

7.2 DNS 排障

bash 复制代码
# 所有 DNS 查询和响应
tcpdump -nn -i any 'udp port 53'

# 指定主机的 DNS 查询
tcpdump -nn -i eth0 'udp port 53 and src host 192.168.1.50'

# TCP DNS(区域传送、大响应)
tcpdump -nn -i eth0 'tcp port 53'

# DNS 到指定服务器
tcpdump -nn -i eth0 'udp port 53 and host 8.8.8.8'

7.3 TCP 连接诊断

bash 复制代码
# 新连接请求(纯 SYN)
tcpdump -nn 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0'

# 连接重置(RST)
tcpdump -nn 'tcp[tcpflags] & tcp-rst != 0'

# 服务端拒绝的连接(RST 来自服务端口)
tcpdump -nn 'tcp[tcpflags] & tcp-rst != 0 and src port 443'

# 连接关闭(FIN)
tcpdump -nn 'tcp[tcpflags] & tcp-fin != 0'

# 完整连接生命周期
tcpdump -nn 'tcp[tcpflags] & (tcp-syn|tcp-fin|tcp-rst) != 0'

7.4 DHCP 分析

bash 复制代码
# DHCP 流量
tcpdump -nn -i eth0 'udp port 67 or udp port 68'

# DHCP 详细输出
tcpdump -nn -v -i eth0 'udp port 67 or udp port 68'

7.5 ARP 排障

bash 复制代码
# 所有 ARP 流量
tcpdump -nn -e -i eth0 'arp'

# ARP 请求(who-has)
tcpdump -nn -e -i eth0 'arp[6:2] = 0x0001'

# ARP 响应
tcpdump -nn -e -i eth0 'arp[6:2] = 0x0002'

7.6 安全与事件响应

bash 复制代码
# 排除自身 SSH 会话,减少噪声
tcpdump -nn -i eth0 'not port 22'

# SYN 洪水检测
tcpdump -nn -i eth0 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0'

# 异常 ICMP(大包可能为 ICMP 隧道)
tcpdump -nn -i eth0 'icmp and greater 100'

# ARP 欺骗检测
tcpdump -nn -e -i eth0 'arp'

八、文件保存与读取

8.1 保存到 pcap 文件

bash 复制代码
# 基本保存
tcpdump -nn -i eth0 -w capture.pcap 'port 80'

# 按文件大小轮转(每个 100MB)
tcpdump -nn -i eth0 -C 100 -w capture.pcap 'port 443'

# 按时间轮转(每小时一个文件)
tcpdump -nn -i eth0 -G 3600 -w 'capture_%H:%M:%S.pcap'

# 环形缓冲:保留最近 10 个 100MB 文件
tcpdump -nn -i eth0 -C 100 -W 10 -w capture.pcap

# 轮转后自动压缩
tcpdump -nn -i eth0 -C 100 -w capture.pcap -z gzip

8.2 读取 pcap 文件

bash 复制代码
# 基本读取
tcpdump -nn -r capture.pcap

# 读取时应用过滤
tcpdump -nn -r capture.pcap 'host 192.168.1.10 and port 443'

# 读取并查看 HTTP 内容
tcpdump -nn -A -r capture.pcap 'tcp port 80'

# 转为文本供 grep 搜索
tcpdump -nn -A -r capture.pcap > capture.txt

# 统计源 IP 分布
tcpdump -nn -r capture.pcap | awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -rn

8.3 双路输出(终端 + 文件)

bash 复制代码
# 同时写文件和输出到终端
tcpdump -nn -U -l -i eth0 -w - | tee capture.pcap | tcpdump -r -

九、时间戳格式控制

bash 复制代码
# 默认:hh:mm:ss.fraction
tcpdump -nn -i eth0

# 完整日期 + 时间
tcpdump -nn -tttt -i eth0

# Unix 时间戳
tcpdump -nn -tt -i eth0

# 与上一个包的时间差
tcpdump -nn -ttt -i eth0

# 与第一个包的时间差
tcpdump -nn -ttttt -i eth0

# 不显示时间戳
tcpdump -nn -t -i eth0

# 显示包序号
tcpdump -nn --number -i eth0

十、生产环境最佳实践

10.1 黄金法则

生产抓包四步法:

复制代码
1. 指定接口(-i any 如果不确定)
2. 加 -nn 禁止名字解析(避免卡顿)
3. 用 BPF 过滤收窄到关心的主机/端口/协议
4. 要么实时看,要么 -w 写 pcap 后用 Wireshark 分析

10.2 性能优化

性能问题与解决方案:

问题 解决方案
丢包 使用更精确的 BPF 过滤;-B 增大内核缓冲区;写入更快的磁盘
pcap 文件过大 更精确过滤;-s 限制抓包长度;-C 按大小轮转
CPU 占用高 避免 -A/-X 实时输出;用 -w 写文件不打印;内核层 BPF 过滤
磁盘写满 -C + -W 环形缓冲;监控磁盘空间
bash 复制代码
# 增大内核缓冲区到 4096 KiB(减少丢包)
tcpdump -B 4096 -nn -i eth0 -w capture.pcap

# 打开设备后降权到 nobody(安全实践)
tcpdump -Z nobody -nn -i eth0 -w capture.pcap

# timeout 配合 tcpdump,防止忘关
timeout 60 tcpdump -nn -i eth0 -w /tmp/capture.pcap

10.3 抓包策略模板

bash 复制代码
# ===== 快速排查(实时终端)=====
tcpdump -nn -c 100 -i eth0 'host 10.0.0.50 and port 443'

# ===== 事件响应(完整抓包)=====
tcpdump -nn -s 0 -i eth0 -w incident_$(date +%Y%m%d_%H%M%S).pcap \
  'host 10.0.0.50 and (port 80 or port 443)'

# ===== 长期监控(轮转 + 压缩)=====
tcpdump -nn -s 0 -i eth0 -G 3600 -W 24 \
  -w '/var/captures/hourly_%H.pcap' \
  -z gzip \
  'net 10.0.0.0/8'

# ===== 高流量抓包(大缓冲 + 写快速磁盘)=====
tcpdump -nn -s 0 -i eth0 -B 4096 -w highspeed.pcap 'tcp port 443'

# ===== 容器流量(Docker)=====
tcpdump -nn -i docker0
tcpdump -nn -i br-XXXXXXXXXXXX

10.4 常见踩坑

踩坑点 解决方案
tcpdump 无输出 -D 检查接口名;确认有 root 权限
-i any 看不到 VLAN 标签 改用具体物理接口抓包
-w 后终端无输出 这是设计行为,需要双路输出用管道方案
Shell 解析了 &、` ()`
旧版默认 snaplen 太小 始终加 -s 0 确保全量抓取
DNS 解析导致卡顿 始终加 -nn

十一、学习路线图

复制代码
┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│  入门     │───▶│  进阶     │───▶│  高级     │───▶│  实战     │───▶│  专家     │
│          │    │          │    │          │    │          │    │          │
│ 基本抓包  │    │ BPF组合   │    │ 字节偏移  │    │ 生产排障  │    │ 自动化脚本 │
│ host/port│    │ and/or/not│    │ proto[]  │    │ pcap分析  │    │ 定时+告警  │
└──────────┘    └──────────┘    └──────────┘    └──────────┘    └──────────┘

各阶段目标与练习内容:

阶段 目标 练习内容
入门 掌握基本抓包 tcpdump -i any -nn,加 host/port 过滤
进阶 BPF 逻辑组合 and/or/not 组合,TCP 标志位
高级 协议头部字段 proto[offset:size] 字节偏移过滤
实战 生产排障 保存 pcap + Wireshark 分析,轮转抓包
专家 自动化脚本 tcpdump 配合 shell 脚本,定时抓包告警

十二、速查表

bash 复制代码
# ===== 基础 =====
tcpdump -D                                    # 列出接口
tcpdump -i any -nn                            # 监听所有接口,不解析
tcpdump -i eth0 -nn -c 100                    # 抓 100 个包

# ===== 过滤 =====
tcpdump -nn host 10.0.0.1                     # 指定主机
tcpdump -nn port 80                           # 指定端口
tcpdump -nn tcp                               # 指定协议
tcpdump -nn 'host 10.0.0.1 and port 443'      # 组合

# ===== TCP 标志 =====
tcpdump -nn 'tcp[tcpflags] & tcp-syn != 0'   # SYN
tcpdump -nn 'tcp[tcpflags] & tcp-rst != 0'   # RST
tcpdump -nn 'tcp[tcpflags] & tcp-fin != 0'   # FIN

# ===== 保存/读取 =====
tcpdump -nn -w file.pcap                      # 保存
tcpdump -nn -r file.pcap                      # 读取
tcpdump -nn -r file.pcap 'port 80'            # 读取并过滤

# ===== 输出格式 =====
tcpdump -nn -A 'port 80'                      # ASCII(HTTP)
tcpdump -nn -X                                # 十六进制+ASCII
tcpdump -nn -vvv                              # 最详细
tcpdump -nn -e                                # 含 MAC 地址

总结

本文核心要点:

  1. -nn 是第一原则 :生产环境永远加 -nn,避免 DNS 反解导致卡顿
  2. BPF 过滤在内核生效:先过滤再抓包,而不是抓全量再过滤,高流量下差异巨大
  3. TCP 标志位是排障利器tcp[tcpflags] 语法精准抓取 SYN/RST/FIN,快速定位连接问题
  4. 字节偏移解锁高级场景proto[offset:size] 语法可匹配 HTTP 载荷、IP 头字段、ICMP 类型等
  5. 生产抓包写文件,离线分析-w 保存 pcap,用 Wireshark 或 tcpdump -r 事后分析

📌 官方文档


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

相关推荐
糖果店的幽灵1 小时前
软件测试接口测试从入门到精通:Postman入门到精通
软件测试·测试工具·接口测试·postman·api测试
it-10242 小时前
抖音快手短视频去水印微信小程序/一键去水印/小程序去水印接口代码
微信小程序·小程序·php
墨香幽梦客11 小时前
API集成最佳实践:Postman+MuleSoft实现ERP与OA系统无缝对接
测试工具·postman
宋拾壹13 小时前
php对接抖音验券,二维码验券
php·抖音·二维码·验券
我是唐青枫16 小时前
Php Doctrine ORM 实战详解:从实体映射到查询、关联与事务
php
juesdo17 小时前
array_search()函数的用法
web安全·php
ch3nyuyu21 小时前
socket套接字
开发语言·php
leagsoft_10031 天前
零信任选型五刀法——零信任怎么选?五个问题,五条红线
开发语言·php
yyuuuzz1 天前
云服务器软件部署的几个常见问题
运维·服务器·开发语言·网络·云计算·php·apache