tcpdump 网络抓包实战指南(持续更新)
前言
tcpdump 是什么?
想象一下:你要调查一封信是怎么从发送方到接收方的。中途经过哪些邮局、每站停留多久、有没有丢失。
tcpdump 就是网络的"快递追踪器",它能截获并显示经过网卡的每一个数据包,让你看清网络通信的每一个细节。
tcpdump 是 Linux/Unix 系统下最强大的网络抓包工具,是网络故障排查和安全分析的必备技能。作为运维工程师,我们用它来诊断网络问题、分析攻击、调试协议。
本文档会告诉你:
- tcpdump 核心概念
- 基础抓包命令
- 过滤表达式详解
- 高级过滤技巧
- 常用抓包场景
- 分析工具使用
目录
核心概念详解
1. TCP/IP 协议基础
数据包是什么?
想象一下:你寄一封信,信封上有收件人/发件人地址,内容在信纸里。
网络数据包也是这样:
- IP 头 = 信封上的地址
- TCP/UDP 头 = 邮戳(端口信息)
- 数据 = 信的内容
协议层次:
| 层次 | 协议 | 通俗解释 |
|---|---|---|
| 应用层 | HTTP, DNS, SSH | 信的内容 |
| 传输层 | TCP, UDP | 邮戳(端口) |
| 网络层 | IP | 收件人地址 |
| 链路层 | Ethernet | 街道地址 |
2. TCP 三次握手
三次握手是什么?
想象一下:打电话时,双方要确认:
- 你好,我能听到你吗?(SYN)
- 能听到,你也能听到我吗?(SYN-ACK)
- 能,开始通话!(ACK)
TCP 连接建立就是这样,需要三次确认。
👀 TCP 三次握手:
客户端 服务端
│ │
│ ────── SYN (seq=100) ──────▶│ 第一次:客户端发送 SYN
│ │
│ ◀──── SYN-ACK (seq=300,ack=101) ───│ 第二次:服务端返回 SYN-ACK
│ │
│ ────── ACK (ack=301) ──────▶│ 第三次:客户端发送 ACK
│ │
│ 建立连接! │
3. TCP 标志位
| 标志位 | 全称 | 通俗解释 |
|---|---|---|
| SYN | Synchronize | “你好,我想连接” |
| ACK | Acknowledge | “我收到了” |
| FIN | Finish | “我要关闭连接了” |
| RST | Reset | “出问题了,重置” |
| PSH | Push | “数据很急,马上处理” |
| URG | Urgent | “这是紧急数据” |
4. 端口作用
| 端口 | 服务 | 通俗解释 |
|---|---|---|
| 22 | SSH | 远程服务器的"大门" |
| 80 | HTTP | 普通网页的"入口" |
| 443 | HTTPS | 安全网页的"入口" |
| 3306 | MySQL | 数据库的"专用通道" |
| 6379 | Redis | 缓存的"专用通道" |
| 53 | DNS | 域名查询的"问讯处" |
基础命令
安装与基本使用
# 👀 检查是否安装
which tcpdump
# 👀 安装(Ubuntu/Debian)
sudo apt install tcpdump
# 👀 安装(CentOS/RHEL)
sudo yum install tcpdump
# 👀 查看版本
tcpdump --version
基础抓包命令
# 👀 抓取所有数据包(按 Ctrl+C 停止)
sudo tcpdump
# 👀 抓取指定数量包后停止
sudo tcpdump -c 10
# 👀 抓取并保存到文件
sudo tcpdump -w capture.pcap
# 👀 读取保存的抓包文件
tcpdump -r capture.pcap
# 👀 抓取时显示详细信息
sudo tcpdump -v
# 👀 抓取时显示更详细信息
sudo tcpdump -vv
# 👀 不解析域名(加快抓包速度)
sudo tcpdump -n
# 👀 不解析域名和端口
sudo tcpdump -nn
指定网卡
# 👀 查看所有网卡
tcpdump -D
# 输出示例:
# 0.eth0 [Up, Running, Connected]
# 1.lo [Up, Running, Connected]
# 2.any [Pseudo-device that captures on all interfaces]
# 3.docker0 [Up, Running, Connected]
# 👀 抓取指定网卡
sudo tcpdump -i eth0
# 👀 抓取任意网卡(用于多网卡服务器)
sudo tcpdump -i any
# 👀 抓取 Docker 容器网卡
sudo tcpdump -i docker0
过滤表达式
主机过滤
# 👀 抓取来自特定主机的数据包
sudo tcpdump -i eth0 src host 192.168.1.10
# 👀 抓取发往特定主机的数据包
sudo tcpdump -i eth0 dst host 192.168.1.10
# 👀 抓取特定主机(双向)
sudo tcpdump -i eth0 host 192.168.1.10
# 👀 抓取来自或发往 IP 段
sudo tcpdump -i eth0 net 192.168.1.0/24
端口过滤
# 👀 抓取特定端口(双向)
sudo tcpdump -i eth0 port 80
# 👀 抓取源端口
sudo tcpdump -i eth0 src port 80
# 👀 抓取目标端口
sudo tcpdump -i eth0 dst port 80
# 👀 抓取多个端口
sudo tcpdump -i eth0 port 80 or port 443
# 👀 抓取非标准端口(排除 22)
sudo tcpdump -i eth0 port not 22
协议过滤
# 👀 抓取 TCP 包
sudo tcpdump -i eth0 tcp
# 👀 抓取 UDP 包
sudo tcpdump -i eth0 udp
# 👀 抓取 ICMP 包(ping)
sudo tcpdump -i eth0 icmp
# 👀 抓取 ARP 包
sudo tcpdump -i eth0 arp
# 👀 抓取 DNS 包(DNS 用 UDP/TCP 53)
sudo tcpdump -i eth0 "port 53"
组合过滤
# 👀 AND 组合
sudo tcpdump -i eth0 tcp and port 80
# 👀 OR 组合
sudo tcpdump -i eth0 host 192.168.1.10 or host 192.168.1.20
# 👀 NOT 排除
sudo tcpdump -i eth0 tcp and not port 22
# 👀 复杂组合
sudo tcpdump -i eth0 "tcp and (port 80 or port 443) and src host 192.168.1.10"
高级技巧
抓取 HTTP 请求
# 👀 抓取 HTTP 请求内容
sudo tcpdump -i eth0 -A "tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)"
# 👀 简化版
sudo tcpdump -i eth0 -A port 80 | grep -i "GET\|POST\|HTTP"
# 👀 抓取完整 HTTP 请求和响应
sudo tcpdump -i eth0 -A -s 0 "tcp port 80 and tcp[((tcp[12:1] & 0xf0) >> 2)] = 0x"
抓取特定内容
# 👀 抓取包含特定字符串的包
sudo tcpdump -i eth0 -A "tcp[20:]" | grep -a "password\|token\|secret"
# 👀 抓取 POST 请求中的数据
sudo tcpdump -i eth0 -A -s 0 "tcp[((tcp[12:1] & 0xf0) >> 2)] = 0x50"
# 👀 抓取 JSON 数据
sudo tcpdump -i eth0 -A -s 0 | grep -i "{"
抓取连接建立和断开
# 👀 抓取 TCP 连接建立(SYN)
sudo tcpdump -i eth0 "tcp[tcpflags] == tcp-syn"
# 👀 抓取 TCP 连接断开(FIN)
sudo tcpdump -i eth0 "tcp[tcpflags] == tcp-fin"
# 👀 抓取 TCP 重置(RST)
sudo tcpdump -i eth0 "tcp[tcpflags] == tcp-rst"
# 👀 抓取 SYN 和 FIN 都算
sudo tcpdump -i eth0 "tcp[tcpflags] & (tcp-syn|tcp-fin) != 0"
抓取特定包大小
# 👀 抓取大于指定大小的包
sudo tcpdump -i eth0 "ip[2:2] > 1000"
# 👀 抓取 TCP 头部长度
sudo tcpdump -i eth0 "tcp[((tcp[12:1] & 0xf0) >> 2)]"
常用场景
场景 1:诊断无法连接 Web 服务
# 👀 抓取与 Web 服务器的通信
sudo tcpdump -i eth0 -nn host 192.168.1.100 and port 80 -w web-debug.pcap
# 👀 分析
# 1. 看有没有 SYN 包发出
# 2. 看有没有 SYN-ACK 包返回
# 3. 如果没有 SYN-ACK,可能是防火墙或网络不通
排查思路:
👀 连接问题排查流程:
1. 发 SYN 包
│
▼
2. 收到 SYN-ACK? ──否──▶ 检查服务端防火墙
│ 检查服务端服务是否启动
是
▼
3. 发 ACK 包
│
▼
4. 连接建立成功?
│
是 → 继续排查应用层问题
否 → 检查防火墙(RST)
场景 2:分析 DNS 解析
# 👀 抓取 DNS 查询和响应
sudo tcpdump -i eth0 -nn port 53
# 👀 输出示例
# 12:34:56.789 IP 192.168.1.10.12345 > 8.8.8.8.53: 12345+ A? www.example.com.
# 12:34:56.801 IP 8.8.8.8.53 > 192.168.1.10.12345: 12345 1/0/0 A 93.184.216.34
# 👀 解释:
# 192.168.1.10.12345 > 8.8.8.8.53 客户端向 DNS 服务器发送查询
# 12345+ A? www.example.com 查询 ID=12345, 查询类型=A(IPv4)
# 93.184.216.34 DNS 返回的 IP 地址
场景 3:抓取 MySQL 慢查询
# 👀 抓取 MySQL 端口通信
sudo tcpdump -i eth0 -nn -A port 3306 | grep -i "SELECT\|INSERT\|UPDATE"
# 👀 保存完整 MySQL 流量
sudo tcpdump -i eth0 -nn port 3306 -w mysql.pcap
# 👀 后续分析
tcpdump -r mysql.pcap -A | less
场景 4:分析 HTTP 攻击
# 👀 抓取 HTTP GET 请求
sudo tcpdump -i eth0 -nn -A "tcp port 80 and tcp[((tcp[12:1] & 0xf0) >> 2)] = 0x47455420"
# 👀 47455420 是什么? = "GET " 的十六进制
# 👀 常见 HTTP 方法十六进制
# GET = 47455420 (space after GET)
# POST = 504F5354 (POST)
# PUT = 50555420
场景 5:监控 Redis 连接
# 👀 抓取 Redis 命令
sudo tcpdump -i eth0 -nn -A port 6379 | grep -i "SET\|GET\|AUTH"
# 👀 完整 Redis 流量
sudo tcpdump -i eth0 -nn port 6379 -w redis.pcap
输出分析
tcpdump 输出格式
👀 tcpdump 输出格式:
12:34:56.789123 IP 192.168.1.10.12345 > 93.184.216.34.80: Flags [S], seq 100:200, win 65535, options [mss 1460], length 100
解释:
┌────────────┬──────────┬───────┬──────────┬──────┬───────┬─────────┬─────────┬────────┐
│ 时间 │ 协议 │ 源地址 │ > │目标 │ Flags │ 序列号 │ 窗口 │ 长度 │
│ 12:34:56 │ IP │192.168│ │.80 │ [S] │ │ │ │
│ │ │ .1.10 │ │ │ SYN包 │ │ │ │
│ │ │ .12345│ │ │ │ │ │ │
└────────────┴──────────┴───────┴──────────┴──────┴───────┴─────────┴─────────┴────────┘
Flags 说明
| Flags | 含义 | 常见场景 |
|---|---|---|
[.] |
ACK | 确认包 |
[S] |
SYN | 连接建立 |
[F] |
FIN | 连接关闭 |
[R] |
RST | 重置连接 |
[P] |
PSH | 推送数据 |
[S.] |
SYN-ACK | 握手第二步 |
[P.] |
PSH-ACK | 数据包 |
[F.] |
FIN-ACK | 关闭第二步 |
分析 TCP 会话
# 👀 抓取完整 TCP 会话
sudo tcpdump -i eth0 -nn -c 100 'port 80' -w session.pcap
# 👀 分析会话
tcpdump -nn -r session.pcap | head -20
# 👀 查看会话统计
tcpdump -nn -r session.pcap | awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c
Wireshark 配合
转换为 pcap 格式
# 👀 tcpdump 抓的包直接可以用 Wireshark 打开
sudo tcpdump -i eth0 port 80 -w capture.pcap
# 👀 合并多个 pcap 文件
mergecap -w combined.pcap capture1.pcap capture2.pcap
# 👀 按时间排序
tcpdump -r capture.pcap -nn | sort > sorted.txt
常用过滤语法对比
| 场景 | tcpdump | Wireshark |
|---|---|---|
| HTTP 流量 | port 80 |
http |
| TCP SYN | tcp[tcpflags] == tcp-syn |
tcp.flags.syn == 1 |
| GET 请求 | tcp[20:] contains "GET" |
http.request.method == "GET" |
| IP 过滤 | host 192.168.1.10 |
ip.addr == 192.168.1.10 |
| 端口过滤 | port 80 |
tcp.port == 80 |
总结
黄金法则
- 先筛选再抓 - 用过滤减少数据量
- 保存到文件 - 抓包后用 Wireshark 分析
- 指定网卡 - 不要用 any(太慢)
- 减少解析 - 用 -nn 加速
- 及时停止 - 抓完按 Ctrl+C
- 保留完整 - 抓包时用 -s 0 保存完整数据
常用命令速查
# 👀 基础抓包
sudo tcpdump -i eth0 -nn port 80
# 👀 保存到文件
sudo tcpdump -i eth0 -w file.pcap
# 👀 读取文件
tcpdump -r file.pcap
# 👀 HTTP 请求
sudo tcpdump -i eth0 -A port 80 | grep "GET\|HTTP"
# 👀 SYN 包
sudo tcpdump -i eth0 "tcp[tcpflags] == tcp-syn"
# 👀 ICMP (ping)
sudo tcpdump -i eth0 icmp
持续更新中… 如有问题或建议,欢迎交流讨论!
评论区